wip: icon options screen basic setup

This commit is contained in:
rushiiMachine 2025-03-29 15:15:41 -07:00
parent b329e1bad6
commit 9cd713ef70
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
12 changed files with 196 additions and 65 deletions

View file

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

View file

@ -22,6 +22,7 @@ import com.aliucord.manager.manager.PreferencesManager
import com.aliucord.manager.ui.components.*
import com.aliucord.manager.ui.components.dialogs.StoragePermissionsDialog
import com.aliucord.manager.ui.screens.home.HomeScreen
import com.aliucord.manager.ui.screens.iconopts.IconOptionsScreen
import com.aliucord.manager.ui.screens.patching.PatchingScreen
import com.aliucord.manager.ui.screens.patchopts.PatchOptionsScreen
import com.aliucord.manager.ui.widgets.updater.UpdaterDialog
@ -77,6 +78,12 @@ class MainActivity : ComponentActivity() {
// Going from InstallOptions -> Install
initialState is PatchOptionsScreen && targetState is PatchingScreen ->
slideInHorizontally { it * 2 } + fadeIn togetherWith fadeOut
// Going from PatchOptions -> IconOptions
initialState is PatchOptionsScreen && targetState is IconOptionsScreen ->
slideInHorizontally { it * 2 } + fadeIn togetherWith fadeOut
// Going from IconOptions -> PatchOptions
initialState is IconOptionsScreen && targetState is PatchOptionsScreen ->
fadeIn togetherWith slideOutHorizontally { it * 2 } + fadeOut
// Going from Install -> InstallOptions
initialState is PatchingScreen && targetState is PatchOptionsScreen ->
fadeIn togetherWith slideOutHorizontally { it * 2 } + fadeOut

View file

@ -21,8 +21,7 @@ private fun PatchOptionsScreenPreview(
isDevMode = parameters.isDevMode,
debuggable = parameters.debuggable,
setDebuggable = {},
replaceIcon = parameters.replaceIcon,
setReplaceIcon = {},
onOpenIconOptions = {},
appName = parameters.appName,
appNameIsError = parameters.appNameIsError,
setAppName = {},
@ -39,7 +38,6 @@ private data class PatchOptionsParameters(
val isUpdate: Boolean,
val isDevMode: Boolean,
val debuggable: Boolean,
val replaceIcon: Boolean,
val appName: String,
val appNameIsError: Boolean,
val packageName: String,
@ -54,7 +52,6 @@ private class PatchOptionsParametersProvider : PreviewParameterProvider<PatchOpt
isUpdate = false,
isDevMode = false,
debuggable = false,
replaceIcon = true,
appName = PatchOptions.Default.appName,
appNameIsError = false,
packageName = PatchOptions.Default.packageName,
@ -65,7 +62,6 @@ private class PatchOptionsParametersProvider : PreviewParameterProvider<PatchOpt
isUpdate = true,
isDevMode = false,
debuggable = false,
replaceIcon = true,
appName = "an invalid app name.",
appNameIsError = true,
packageName = "a b",
@ -76,7 +72,6 @@ private class PatchOptionsParametersProvider : PreviewParameterProvider<PatchOpt
isUpdate = false,
isDevMode = true,
debuggable = true,
replaceIcon = false,
appName = PatchOptions.Default.appName,
appNameIsError = false,
packageName = PatchOptions.Default.packageName,

View file

@ -0,0 +1,57 @@
package com.aliucord.manager.ui.screens.iconopts
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen
import com.aliucord.manager.ui.screens.iconopts.components.IconOptionsAppBar
import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
import dev.zt64.compose.pipette.CircularColorPicker
class IconOptionsScreen(
private val prefilledOptions: IconReplacement,
) : Screen {
override val key = "IconOptions"
@Composable
override fun Content() {
var (color, setColor) = remember { mutableStateOf(IconReplacement.Aliucord.color) }
IconOptionsScreenContent(
selectedColor = color,
setSelectedColor = setColor,
)
}
}
@Composable
fun IconOptionsScreenContent(
selectedColor: Color,
setSelectedColor: (Color) -> Unit,
) {
Scaffold(
topBar = { IconOptionsAppBar() },
) { paddingValues ->
Column(
verticalArrangement = Arrangement.spacedBy(20.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(paddingValues)
.padding(horizontal = 20.dp, vertical = 20.dp)
) {
CircularColorPicker(
color = selectedColor,
onColorChange = setSelectedColor,
modifier = Modifier.size(250.dp)
)
}
}
}

View file

@ -0,0 +1,29 @@
package com.aliucord.manager.ui.screens.iconopts.components
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import com.aliucord.manager.R
import com.aliucord.manager.ui.components.BackButton
import com.aliucord.manager.ui.screens.settings.SettingsScreen
@Composable
fun IconOptionsAppBar() {
TopAppBar(
navigationIcon = { BackButton() },
title = { Text(stringResource(R.string.iconopts_screen_title)) },
actions = {
val navigator = LocalNavigator.currentOrThrow
IconButton(onClick = { navigator.push(SettingsScreen()) }) {
Icon(
painter = painterResource(R.drawable.ic_settings),
contentDescription = stringResource(R.string.navigation_settings)
)
}
}
)
}

View file

@ -59,7 +59,7 @@ class PatchingScreen(private val data: PatchOptions) : Screen, Parcelable {
val state by model.state.collectAsState()
val listState = rememberLazyListState()
val showMinimizationWarning = remember { !context.isIgnoringBatteryOptimizations() }
val showMinimizationWarning = rememberSaveable { !context.isIgnoringBatteryOptimizations() }
// Exit warning dialog (dismiss itself if install process state changes, esp. for Success)
var showAbortWarning by rememberSaveable(model.state.collectAsState().value) { mutableStateOf(false) }

View file

@ -41,14 +41,6 @@ class PatchOptionsModel(
appNameIsError = newAppName.length !in (1..150)
}
// ---------- Icon patching state ----------
var replaceIcon by mutableStateOf(prefilledOptions.iconReplacement == PatchOptions.IconReplacement.Aliucord)
private set
fun changeReplaceIcon(value: Boolean) {
replaceIcon = value
}
// ---------- Debuggable state ----------
var debuggable by mutableStateOf(prefilledOptions.debuggable)
private set
@ -75,7 +67,7 @@ class PatchOptionsModel(
packageName = packageName,
debuggable = debuggable,
// TODO: advanced icon options
iconReplacement = if (replaceIcon) PatchOptions.IconReplacement.Aliucord else PatchOptions.IconReplacement.Original,
iconReplacement = PatchOptions.IconReplacement.Aliucord,
)
}

View file

@ -1,16 +1,18 @@
package com.aliucord.manager.ui.screens.patchopts
import android.os.Parcelable
import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen
@ -21,12 +23,13 @@ import com.aliucord.manager.R
import com.aliucord.manager.ui.components.TextDivider
import com.aliucord.manager.ui.components.dialogs.NetworkWarningDialog
import com.aliucord.manager.ui.components.dialogs.UnknownSourcesPermissionDialog
import com.aliucord.manager.ui.screens.iconopts.IconOptionsScreen
import com.aliucord.manager.ui.screens.patching.PatchingScreen
import com.aliucord.manager.ui.screens.patchopts.components.PackageNameStateLabel
import com.aliucord.manager.ui.screens.patchopts.components.PatchOptionsAppBar
import com.aliucord.manager.ui.screens.patchopts.components.options.SwitchPatchOption
import com.aliucord.manager.ui.screens.patchopts.components.options.TextPatchOption
import com.aliucord.manager.ui.util.*
import com.aliucord.manager.ui.screens.patchopts.components.options.*
import com.aliucord.manager.ui.util.InstallNotifications
import com.aliucord.manager.ui.util.spacedByLastAtBottom
import com.aliucord.manager.util.isIgnoringBatteryOptimizations
import com.aliucord.manager.util.requestNoBatteryOptimizations
import kotlinx.coroutines.delay
@ -58,7 +61,7 @@ class PatchOptionsScreen(
context.requestNoBatteryOptimizations()
}
var showNetworkWarningDialog by remember { mutableStateOf(model.isNetworkDangerous()) }
var showNetworkWarningDialog by rememberSaveable { mutableStateOf(model.isNetworkDangerous()) }
if (showNetworkWarningDialog) {
NetworkWarningDialog(
onConfirm = { showNetworkWarningDialog = false },
@ -78,8 +81,8 @@ class PatchOptionsScreen(
debuggable = model.debuggable,
setDebuggable = model::changeDebuggable,
replaceIcon = model.replaceIcon,
setReplaceIcon = model::changeReplaceIcon,
// TODO: actual filled in options
onOpenIconOptions = { navigator.push(IconOptionsScreen(PatchOptions.Default.iconReplacement)) },
appName = model.appName,
appNameIsError = model.appNameIsError,
@ -103,8 +106,7 @@ fun PatchOptionsScreenContent(
debuggable: Boolean,
setDebuggable: (Boolean) -> Unit,
replaceIcon: Boolean,
setReplaceIcon: (Boolean) -> Unit,
onOpenIconOptions: () -> Unit,
appName: String,
appNameIsError: Boolean,
@ -137,14 +139,29 @@ fun PatchOptionsScreenContent(
TextDivider(text = stringResource(R.string.patchopts_divider_basic))
SwitchPatchOption(
IconPatchOption(
icon = painterResource(R.drawable.ic_app_shortcut),
name = stringResource(R.string.patchopts_icon_title),
description = stringResource(R.string.patchopts_icon_desc),
value = replaceIcon,
onValueChange = setReplaceIcon,
modifier = Modifier.padding(bottom = 8.dp)
)
modifier = Modifier
.fillMaxWidth()
.clickable(
interactionSource = remember(::MutableInteractionSource),
onClick = onOpenIconOptions,
indication = null,
role = Role.Switch,
)
.padding(bottom = 8.dp),
) {
// TODO: selected icon options preview
// Icon(
// painter = painterResource(R.drawable.ic_discord),
// contentDescription = null,
// modifier = Modifier
// .padding(start = 4.dp, end = 14.dp)
// .size(26.dp),
// )
}
val appNameIsDefault by remember {
derivedStateOf {

View file

@ -0,0 +1,50 @@
package com.aliucord.manager.ui.screens.patchopts.components.options
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.dp
@Composable
fun IconPatchOption(
icon: Painter,
name: String,
description: String,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = modifier,
) {
Icon(
painter = icon,
contentDescription = null,
modifier = Modifier.size(26.dp),
)
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.weight(1f)
) {
Text(
text = name,
style = MaterialTheme.typography.titleMedium,
)
Text(
text = description,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier
.alpha(.7f)
)
}
content()
}
}

View file

@ -2,13 +2,12 @@ package com.aliucord.manager.ui.screens.patchopts.components.options
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
@ -26,9 +25,10 @@ fun SwitchPatchOption(
val interactionSource = remember(::MutableInteractionSource)
val onClick = remember(value) { { onValueChange(!value) } }
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
IconPatchOption(
icon = icon,
name = name,
description = description,
modifier = modifier
.fillMaxWidth()
.clickable(
@ -39,29 +39,6 @@ fun SwitchPatchOption(
role = Role.Switch,
),
) {
Icon(
painter = icon,
contentDescription = null,
modifier = Modifier.size(26.dp),
)
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.weight(1f)
) {
Text(
text = name,
style = MaterialTheme.typography.titleMedium,
)
Text(
text = description,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier
.alpha(.7f)
)
}
Switch(
checked = value,
enabled = enabled,

View file

@ -16,8 +16,8 @@
<string name="action_dismiss">Dismiss</string>
<string name="action_install">Install</string>
<string name="action_uninstall">Uninstall</string>
<string name="action_add_install">New install</string>
<string name="action_update_install">Update install</string>
<string name="action_add_install">New Install</string>
<string name="action_update_install">Update Install</string>
<string name="action_update">Update</string>
<string name="action_clear">Clear</string>
<string name="action_launch">Launch</string>
@ -160,10 +160,12 @@
<string name="patchopts_debuggable_title">Debuggable</string>
<string name="patchopts_debuggable_desc">Enable the debuggable manifest flag. Only use this if you know what you are doing!</string>
<string name="patchopts_icon_title">Replace app icon</string>
<string name="patchopts_icon_desc">Changes the app\'s icon to use Aliucord branding instead of Discord\'s own.</string>
<string name="patchopts_icon_desc">Change the app\'s icon to Aliucord\'s icon (or a custom one) instead of Discord\'s.</string>
<string name="patchopts_divider_basic">Basic</string>
<string name="patchopts_divider_advanced">Advanced</string>
<string name="iconopts_screen_title">Icon Replacement</string>
<string name="notif_group_install_title">Active installation</string>
<string name="notif_group_install_desc">Progress notifications sent during a minimized installation</string>
<string name="notif_install_ready_title">Aliucord installation ready!</string>

View file

@ -13,6 +13,7 @@ coil = "3.1.0"
compose = "1.7.7"
compose-tracing = "1.7.7"
compose-material3 = "1.3.1"
compose-pipette = "1.0.0-beta01"
#diff = "4.12"
koin = "4.0.2"
kotlin = "2.1.10"
@ -53,6 +54,10 @@ compose-material3 = { module = "androidx.compose.material3:material3", version.r
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
compose-runtime-tracing = { module = "androidx.compose.runtime:runtime-tracing", version.ref = "compose-tracing" }
# Extra compose libs
compose-pipette = { module = "dev.zt64.compose.pipette:compose-pipette", version.ref = "compose-pipette" }
compose-shimmer = { module = "com.valentinilk.shimmer:compose-shimmer", version.ref = "shimmer" }
# Koin
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
koin-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" }
@ -86,7 +91,6 @@ zip = { module = "io.github.diamondminer88:zip-android", version.ref = "zip" } #
# Other
microg = { module = "org.microg.gms:play-services-safetynet", version.ref = "microg" }
compose-shimmer = { module = "com.valentinilk.shimmer:compose-shimmer", version.ref = "shimmer" }
[bundles]
accompanist = [