From b5c6f4fb5417e360499b0909560a9c66adb516c3 Mon Sep 17 00:00:00 2001
From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com>
Date: Mon, 4 Mar 2024 00:45:18 -0800
Subject: [PATCH] feat(HomeScreen): indicate when no installations
---
.../manager/ui/screens/home/HomeModel.kt | 51 +++--
.../manager/ui/screens/home/HomeScreen.kt | 210 ++++++++++++++----
app/src/main/res/values/strings.xml | 1 +
3 files changed, 193 insertions(+), 69 deletions(-)
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt
index e3c9e2e..bb60afd 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt
@@ -108,33 +108,36 @@ class HomeModel(
isAliucordPkg || hasAliucordMeta
}
- val aliucordInstallations = aliucordPackages
- .map {
- // `longVersionCode` is unnecessary since Discord doesn't use `versionCodeMajor`
- @Suppress("DEPRECATION")
- val versionCode = it.versionCode
+ val aliucordInstallations = aliucordPackages.map {
+ // `longVersionCode` is unnecessary since Discord doesn't use `versionCodeMajor`
+ @Suppress("DEPRECATION")
+ val versionCode = it.versionCode
- val baseVersion = it.applicationInfo.metaData?.getInt("aliucordBaseVersion")
- val isBaseUpdated = /* TODO: remote data json instead */ baseVersion == 0
+ val baseVersion = it.applicationInfo.metaData?.getInt("aliucordBaseVersion")
+ val isBaseUpdated = /* TODO: remote data json instead */ baseVersion == 0
- InstallData(
- name = packageManager.getApplicationLabel(it.applicationInfo).toString(),
- packageName = it.packageName,
- baseUpdated = isBaseUpdated,
- icon = packageManager
- .getApplicationIcon(it.applicationInfo)
- .toBitmap()
- .asImageBitmap()
- .let(::BitmapPainter),
- version = DiscordVersion.Existing(
- type = DiscordVersion.parseVersionType(versionCode),
- name = it.versionName.split("-")[0].trim(),
- code = versionCode,
- ),
- )
- }
+ InstallData(
+ name = packageManager.getApplicationLabel(it.applicationInfo).toString(),
+ packageName = it.packageName,
+ baseUpdated = isBaseUpdated,
+ icon = packageManager
+ .getApplicationIcon(it.applicationInfo)
+ .toBitmap()
+ .asImageBitmap()
+ .let(::BitmapPainter),
+ version = DiscordVersion.Existing(
+ type = DiscordVersion.parseVersionType(versionCode),
+ name = it.versionName.split("-")[0].trim(),
+ code = versionCode,
+ ),
+ )
+ }.toImmutableList()
- installations = InstallsState.Fetched(data = aliucordInstallations.toImmutableList())
+ installations = if (aliucordInstallations.isNotEmpty()) {
+ InstallsState.Fetched(data = aliucordInstallations)
+ } else {
+ InstallsState.None
+ }
} catch (t: Throwable) {
Log.e(BuildConfig.TAG, "Failed to query Aliucord installations", t)
installations = InstallsState.Error
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt
index 0a2a22c..3ab9d3f 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt
@@ -10,16 +10,21 @@ import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
-import androidx.compose.material3.Scaffold
+import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.LifecycleResumeEffect
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.koin.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
+import com.aliucord.manager.R
import com.aliucord.manager.ui.components.AnimatedVersionDisplay
import com.aliucord.manager.ui.components.ProjectHeader
import com.aliucord.manager.ui.components.dialogs.NetworkWarningDialog
@@ -70,53 +75,32 @@ class HomeScreen : Screen {
Scaffold(
topBar = { HomeAppBar() },
- ) { paddingValues ->
- LazyColumn(
- verticalArrangement = Arrangement.spacedBy(6.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- contentPadding = paddingValues
- .exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top),
- modifier = Modifier
- .fillMaxSize()
- .padding(paddingValues.exclude(PaddingValuesSides.Bottom))
- .padding(top = 16.dp, start = 16.dp, end = 16.dp),
- ) {
- item(key = "PROJECT_HEADER") {
- ProjectHeader()
- }
+ ) { padding ->
+ when (model.installations) {
+ is InstallsState.Fetching,
+ is InstallsState.Fetched,
+ -> PresentInstallsContent(
+ model = model,
+ padding = padding,
+ onClickInstall = onClickInstall,
+ )
- item(key = "ADD_INSTALL_BUTTON") {
- InstallButton(
- onClick = onClickInstall,
- modifier = Modifier
- .fillMaxWidth()
- .padding(top = 10.dp)
- )
- }
+ InstallsState.None -> NoInstallsContent(
+ supportedVersion = model.supportedVersion,
+ onClickInstall = onClickInstall,
+ modifier = Modifier
+ .padding(padding.exclude(PaddingValuesSides.Bottom)),
+ )
- item(key = "SUPPORTED_VERSION") {
- AnimatedVersionDisplay(
- version = model.supportedVersion,
- modifier = Modifier.padding(bottom = 22.dp),
- )
- }
-
- val installations = (model.installations as? InstallsState.Fetched)?.data
- ?: return@LazyColumn
-
- items(installations, key = { it.packageName }) {
- AnimatedVisibility(
- enter = fadeIn() + slideInHorizontally { it * -2 },
- exit = fadeOut() + slideOutHorizontally { it * 2 },
- visible = model.supportedVersion !is DiscordVersion.None,
+ InstallsState.Error -> {
+ // This is ugly asf but it should never happen
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = Modifier.padding(padding),
) {
- InstalledItemCard(
- data = it,
- onUpdate = ::TODO, // TODO: prefilled install options screen
- onOpenApp = { model.launchApp(it.packageName) },
- onOpenInfo = { model.openAppInfo(it.packageName) },
- onOpenPlugins = { navigator.push(PluginsScreen()) }, // TODO: install-specific plugins
- modifier = Modifier.fillMaxWidth()
+ Text(
+ text = "Failed to fetch installations",
+ style = MaterialTheme.typography.labelMedium,
)
}
}
@@ -124,3 +108,139 @@ class HomeScreen : Screen {
}
}
}
+
+@Composable
+fun PresentInstallsContent(
+ model: HomeModel,
+ padding: PaddingValues,
+ onClickInstall: () -> Unit,
+) {
+ LazyColumn(
+ verticalArrangement = Arrangement.spacedBy(6.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ contentPadding = padding
+ .exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top),
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(padding.exclude(PaddingValuesSides.Bottom))
+ .padding(top = 16.dp, start = 16.dp, end = 16.dp),
+ ) {
+ item(key = "PROJECT_HEADER") {
+ ProjectHeader()
+ }
+
+ item(key = "ADD_INSTALL_BUTTON") {
+ InstallButton(
+ onClick = onClickInstall,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 10.dp)
+ )
+ }
+
+ item(key = "SUPPORTED_VERSION") {
+ AnimatedVersionDisplay(
+ version = model.supportedVersion,
+ modifier = Modifier.padding(bottom = 22.dp),
+ )
+ }
+
+ val installations = (model.installations as? InstallsState.Fetched)?.data
+ ?: return@LazyColumn
+
+ items(installations, key = { it.packageName }) {
+ AnimatedVisibility(
+ enter = fadeIn() + slideInHorizontally { it * -2 },
+ exit = fadeOut() + slideOutHorizontally { it * 2 },
+ visible = model.supportedVersion !is DiscordVersion.None,
+ ) {
+ val navigator = LocalNavigator.currentOrThrow
+
+ InstalledItemCard(
+ data = it,
+ onUpdate = ::TODO, // TODO: prefilled install options screen
+ onOpenApp = { model.launchApp(it.packageName) },
+ onOpenInfo = { model.openAppInfo(it.packageName) },
+ onOpenPlugins = { navigator.push(PluginsScreen()) }, // TODO: install-specific plugins
+ modifier = Modifier.fillMaxWidth()
+ )
+ }
+ }
+ }
+}
+
+@Composable
+fun NoInstallsContent(
+ supportedVersion: DiscordVersion,
+ onClickInstall: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(6.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = modifier
+ .fillMaxSize()
+ .padding(top = 16.dp, start = 16.dp, end = 16.dp),
+ ) {
+ ProjectHeader()
+
+ InstallButton(
+ onClick = onClickInstall,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 10.dp)
+ )
+
+ AnimatedVersionDisplay(
+ version = supportedVersion,
+ modifier = Modifier.padding(bottom = 22.dp),
+ )
+
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ ) {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(6.dp),
+ modifier = Modifier
+ .alpha(.1f)
+ .fillMaxSize()
+ ) {
+ for (i in 0..<3) key(i) {
+ Surface(
+ content = {},
+ shape = MaterialTheme.shapes.medium,
+ tonalElevation = 2.dp,
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(195.dp)
+ .shadow(
+ clip = false,
+ elevation = 2.dp,
+ shape = MaterialTheme.shapes.medium,
+ ),
+ )
+ }
+ }
+
+ Column(
+ verticalArrangement = Arrangement.spacedBy(14.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier
+ .alpha(.8f)
+ .align(Alignment.Center)
+ .padding(bottom = 80.dp),
+ ) {
+ Text(
+ text = """ /ᐠﹷ ‸ ﹷ ᐟ\ノ""",
+ style = MaterialTheme.typography.labelLarge
+ .copy(fontSize = 38.sp),
+ )
+
+ Text(
+ text = stringResource(R.string.installs_no_installs),
+ style = MaterialTheme.typography.labelMedium,
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8da966f..3ed961e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -34,6 +34,7 @@
Grant Permissions
In order for Aliucord Manager to function, file permissions are required. Since shared data is stored in ~/Aliucord, permissions are required in order to access it.
+ No installations founds!
Failed to launch Aliucord
Theme