feat(HomeScreen): better empty page layout

This commit is contained in:
rushiiMachine 2025-01-14 22:24:52 -08:00
parent af98fc6e99
commit 5eeeb4fb45
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
7 changed files with 98 additions and 47 deletions

View file

@ -149,6 +149,7 @@ dependencies {
implementation(libs.microg)
implementation(libs.smali)
implementation(libs.baksmali)
implementation(libs.compose.shimmer)
implementation(variantOf(libs.zip) { artifactType("aar") })
}

View file

@ -8,7 +8,7 @@ import com.aliucord.manager.ui.components.Theme
class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager(preferences) {
var theme by enumPreference("theme", Theme.DARK)
var dynamicColor by booleanPreference("dynamic_color", true)
var dynamicColor by booleanPreference("dynamic_color", false)
var devMode by booleanPreference("dev_mode", false)
var downloader by enumPreference<DownloaderSetting>("downloader", DownloadManagerProvider.getDefaultDownloader())
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PM)

View file

@ -15,6 +15,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.*
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@ -33,6 +34,7 @@ import com.aliucord.manager.ui.screens.plugins.PluginsScreen
import com.aliucord.manager.ui.util.DiscordVersion
import com.aliucord.manager.ui.util.paddings.PaddingValuesSides
import com.aliucord.manager.ui.util.paddings.exclude
import kotlin.math.*
class HomeScreen : Screen {
override val key = "Home"
@ -42,6 +44,7 @@ class HomeScreen : Screen {
val navigator = LocalNavigator.currentOrThrow
val model = getScreenModel<HomeModel>()
// FIXME: not refreshing after completing install?
// Refresh installations list when the screen changes or activity resumes
LifecycleResumeEffect(key1 = "INSTALLATIONS_REFRESH") {
model.fetchInstallations()
@ -76,16 +79,15 @@ class HomeScreen : Screen {
topBar = { HomeAppBar() },
) { padding ->
when (model.installations) {
is InstallsState.Fetching,
is InstallsState.Fetched,
-> PresentInstallsContent(
is InstallsState.Fetched -> PresentInstallsContent(
model = model,
padding = padding,
onClickInstall = onClickInstall,
)
InstallsState.Fetching -> LoadingInstallsContent(padding = padding)
InstallsState.None -> NoInstallsContent(
supportedVersion = model.supportedVersion,
onClickInstall = onClickInstall,
modifier = Modifier
.padding(padding.exclude(PaddingValuesSides.Bottom)),
@ -108,6 +110,19 @@ class HomeScreen : Screen {
}
}
@Composable
fun LoadingInstallsContent(padding: PaddingValues) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(padding)
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
) {
ProjectHeader()
}
}
@Composable
fun PresentInstallsContent(
model: HomeModel,
@ -134,7 +149,6 @@ fun PresentInstallsContent(
onClick = onClickInstall,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
)
}
@ -171,7 +185,6 @@ fun PresentInstallsContent(
@Composable
fun NoInstallsContent(
supportedVersion: DiscordVersion,
onClickInstall: () -> Unit,
modifier: Modifier = Modifier,
) {
@ -180,7 +193,7 @@ fun NoInstallsContent(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.fillMaxSize()
.padding(top = 16.dp, start = 16.dp, end = 16.dp),
.padding(16.dp),
) {
ProjectHeader()
@ -188,22 +201,18 @@ fun NoInstallsContent(
secondaryInstall = false,
onClick = onClickInstall,
modifier = Modifier
.padding(12.dp)
.height(height = 50.dp)
.fillMaxWidth()
.padding(top = 10.dp)
)
AnimatedVersionDisplay(
version = supportedVersion,
modifier = Modifier.padding(bottom = 30.dp),
)
Column(
verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterVertically),
verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.alpha(.7f)
.padding(bottom = 90.dp)
.fillMaxSize()
.padding(bottom = 80.dp)
) {
Text(
text = """ /ᐠﹷ ‸ ﹷ ᐟ\ノ""",
@ -214,6 +223,7 @@ fun NoInstallsContent(
Text(
text = stringResource(R.string.installs_no_installs),
style = MaterialTheme.typography.labelLarge,
modifier = Modifier.padding(start = 10.dp),
)
}
}

View file

@ -1,15 +1,49 @@
package com.aliucord.manager.ui.screens.home.components
import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.aliucord.manager.R
import com.aliucord.manager.ui.util.thenIf
import com.valentinilk.shimmer.*
private val shimmerTheme = defaultShimmerTheme.copy(
shimmerWidth = 150.dp,
animationSpec = infiniteRepeatable(
animation = shimmerSpec(
durationMillis = 2000,
easing = LinearEasing,
delayMillis = 3500,
),
repeatMode = RepeatMode.Restart,
initialStartOffset = StartOffset(1000),
),
blendMode = BlendMode.Lighten,
shaderColors = listOf(
Color.White.copy(alpha = 0.00f),
Color.White.copy(alpha = 0.50f),
Color.White.copy(alpha = 1.00f),
Color.White.copy(alpha = 0.50f),
Color.White.copy(alpha = 0.00f),
),
shaderColorStops = listOf(
0.0f,
0.25f,
0.5f,
0.75f,
1.0f,
),
)
@Composable
fun InstallButton(
@ -18,31 +52,37 @@ fun InstallButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
FilledTonalIconButton(
shape = MaterialTheme.shapes.medium,
colors = IconButtonDefaults.filledTonalIconButtonColors(
containerColor = if (secondaryInstall) {
MaterialTheme.colorScheme.secondaryContainer
} else {
MaterialTheme.colorScheme.primary
},
),
enabled = enabled,
onClick = onClick,
modifier = modifier,
CompositionLocalProvider(
LocalShimmerTheme provides shimmerTheme
) {
Row(
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalAlignment = Alignment.CenterVertically,
FilledTonalIconButton(
shape = RectangleShape,
colors = IconButtonDefaults.filledTonalIconButtonColors(
containerColor = if (secondaryInstall) {
MaterialTheme.colorScheme.secondaryContainer
} else {
MaterialTheme.colorScheme.primary
},
),
enabled = enabled,
onClick = onClick,
modifier = modifier
.clip(MaterialTheme.shapes.medium)
.thenIf(!secondaryInstall) { shimmer() }
) {
Icon(
painter = painterResource(R.drawable.ic_add),
contentDescription = null,
)
Text(
text = stringResource(R.string.action_add_install),
style = MaterialTheme.typography.labelLarge,
)
Row(
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(R.drawable.ic_add),
contentDescription = null,
)
Text(
text = stringResource(R.string.action_add_install),
style = MaterialTheme.typography.labelLarge,
)
}
}
}
}

View file

@ -8,7 +8,8 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.*
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -35,12 +36,7 @@ fun InstalledItemCard(
defaultElevation = 3.dp,
),
modifier = modifier
.width(IntrinsicSize.Max)
.shadow(
clip = false,
elevation = 2.dp,
shape = MaterialTheme.shapes.medium,
)
.width(IntrinsicSize.Max),
) {
Column(
verticalArrangement = Arrangement.spacedBy(24.dp),

View file

@ -15,7 +15,7 @@
<string name="action_dismiss">Dismiss</string>
<string name="action_install">Install</string>
<string name="action_uninstall">Uninstall</string>
<string name="action_add_install">Add Installation</string>
<string name="action_add_install">New Aliucord Installation</string>
<string name="action_update">Update</string>
<string name="action_clear">Clear</string>
<string name="action_launch">Launch</string>

View file

@ -20,6 +20,7 @@ kotlinx-immutable = "0.3.8"
kotlinx-serialization = "1.8.0"
ktor = "3.0.3"
microg = "0.3.6.244735"
shimmer = "1.3.1"
smali = "3.0.9"
voyager = "1.0.1"
zip = "2.1.1"
@ -84,6 +85,9 @@ smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
baksmali = { module = "com.android.tools.smali:smali-baksmali", version.ref = "smali" }
zip = { module = "io.github.diamondminer88:zip-android", version.ref = "zip" } # Only use the "aar" artifact
# Other
compose-shimmer = { module = "com.valentinilk.shimmer:compose-shimmer", version.ref = "shimmer" }
[bundles]
accompanist = [
"accompanist-permissions",