Skip to content

Commit

Permalink
feat(HomeScreen): indicate when no installations
Browse files Browse the repository at this point in the history
  • Loading branch information
rushiiMachine committed Mar 4, 2024
1 parent 52e24e7 commit b5c6f4f
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 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,
),
)
}
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

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
Expand Down
202 changes: 161 additions & 41 deletions app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -70,56 +75,171 @@ class HomeScreen : Screen {

Scaffold(
topBar = { HomeAppBar() },
) { paddingValues ->
LazyColumn(
) { padding ->
when (model.installations) {
is InstallsState.Fetching,
is InstallsState.Fetched,
-> PresentInstallsContent(
model = model,
padding = padding,
onClickInstall = onClickInstall,
)

InstallsState.None -> NoInstallsContent(
supportedVersion = model.supportedVersion,
onClickInstall = onClickInstall,
modifier = Modifier
.padding(padding.exclude(PaddingValuesSides.Bottom)),
)

InstallsState.Error -> {
// This is ugly asf but it should never happen
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.padding(padding),
) {
Text(
text = "Failed to fetch installations",
style = MaterialTheme.typography.labelMedium,
)
}
}
}
}
}
}

@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),
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = paddingValues
.exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top),
modifier = Modifier
.alpha(.1f)
.fillMaxSize()
.padding(paddingValues.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,
for (i in 0..<3) key(i) {
Surface(
content = {},
shape = MaterialTheme.shapes.medium,
tonalElevation = 2.dp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
)
}

item(key = "SUPPORTED_VERSION") {
AnimatedVersionDisplay(
version = model.supportedVersion,
modifier = Modifier.padding(bottom = 22.dp),
.height(195.dp)
.shadow(
clip = false,
elevation = 2.dp,
shape = MaterialTheme.shapes.medium,
),
)
}
}

val installations = (model.installations as? InstallsState.Fetched)?.data
?: return@LazyColumn
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),
)

items(installations, key = { it.packageName }) {
AnimatedVisibility(
enter = fadeIn() + slideInHorizontally { it * -2 },
exit = fadeOut() + slideOutHorizontally { it * 2 },
visible = model.supportedVersion !is DiscordVersion.None,
) {
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 = stringResource(R.string.installs_no_installs),
style = MaterialTheme.typography.labelMedium,
)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit b5c6f4f

Please sign in to comment.