feat(HomeScreen): indicate when no installations

This commit is contained in:
rushiiMachine 2024-03-04 00:45:18 -08:00
parent 52e24e742e
commit b5c6f4fb54
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
3 changed files with 193 additions and 69 deletions

View file

@ -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

View file

@ -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,
)
}
}
}
}

View file

@ -34,6 +34,7 @@
<string name="permissions_grant_title">Grant Permissions</string>
<string name="permissions_grant_body">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.</string>
<string name="installs_no_installs">No installations founds!</string>
<string name="launch_aliucord_fail">Failed to launch Aliucord</string>
<string name="settings_theme">Theme</string>