From 4ae22ceedf1690500c5b42f059a559ce724e1b25 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:03:48 -0800 Subject: [PATCH 01/10] feat: fix top divider --- .../manager/ui/screens/install/InstallScreen.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index 3822d169..0a660046 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -85,12 +85,17 @@ class InstallScreen : Screen { } ) { paddingValues -> Column(Modifier.padding(paddingValues)) { - if (state.value is InstallScreenState.Working) { + if (state.value == InstallScreenState.Working) { LinearProgressIndicator( modifier = Modifier .fillMaxWidth() - .height(8.dp) - .padding(bottom = 4.dp) + .height(4.dp) + ) + } else { + HorizontalDivider( + thickness = 2.dp, + modifier = Modifier + .fillMaxWidth() ) } @@ -99,6 +104,7 @@ class InstallScreen : Screen { modifier = Modifier .verticalScroll(rememberScrollState()) .fillMaxWidth() + .padding(top = 6.dp) .padding(16.dp) ) { var expandedGroup by remember { mutableStateOf(StepGroup.Prepare) } From e705f4fc40bfe971ae2dd8bed15526ecb31ce678 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:04:03 -0800 Subject: [PATCH 02/10] feat: make step group more square --- .../ui/screens/install/components/StepGroupCard.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt index 39b99fda..d61b8dd2 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt @@ -4,7 +4,6 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -16,7 +15,6 @@ import androidx.compose.ui.unit.dp import com.aliucord.manager.R import com.aliucord.manager.installer.steps.base.Step import com.aliucord.manager.installer.steps.base.StepState -import com.aliucord.manager.ui.util.thenIf import kotlinx.collections.immutable.ImmutableList @Composable @@ -49,10 +47,8 @@ fun StepGroupCard( Column( modifier = Modifier .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) - .thenIf(isExpanded) { - background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)) - } + .clip(MaterialTheme.shapes.large) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)) ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -60,7 +56,7 @@ fun StepGroupCard( modifier = Modifier .clickable(true, onClick = onExpand) .fillMaxWidth() - .padding(16.dp) + .padding(horizontal = 16.dp, vertical = 20.dp) ) { StepStateIcon(groupState, 24.dp) From c75f22beba47d31bd409bf620ddd1ab210e5700d Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Sun, 10 Mar 2024 15:55:23 -0700 Subject: [PATCH 03/10] wip --- .../MinimizationWarning.kt => TextBanner.kt} | 41 ++-- .../ui/screens/install/InstallModel.kt | 2 +- .../ui/screens/install/InstallScreen.kt | 215 +++++++++++++----- 3 files changed, 173 insertions(+), 85 deletions(-) rename app/src/main/kotlin/com/aliucord/manager/ui/{screens/install/components/MinimizationWarning.kt => TextBanner.kt} (50%) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MinimizationWarning.kt b/app/src/main/kotlin/com/aliucord/manager/ui/TextBanner.kt similarity index 50% rename from app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MinimizationWarning.kt rename to app/src/main/kotlin/com/aliucord/manager/ui/TextBanner.kt index b963d7a3..9c590911 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MinimizationWarning.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/TextBanner.kt @@ -1,45 +1,36 @@ -package com.aliucord.manager.ui.screens.install.components +package com.aliucord.manager.ui import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.material3.* 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.clip -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.unit.dp -import com.aliucord.manager.R -import com.aliucord.manager.ui.components.customColors -import com.aliucord.manager.util.isIgnoringBatteryOptimizations @Composable -fun MinimizationWarning(modifier: Modifier = Modifier) { - val context = LocalContext.current - val hide = remember(context) { context.isIgnoringBatteryOptimizations() } - - if (hide) return - +fun TextBanner( + text: String, + icon: Painter, + iconColor: Color, + outlineColor: Color, + containerColor: Color, + modifier: Modifier = Modifier, +) { Box( contentAlignment = Alignment.Center, modifier = modifier - .padding( - start = 20.dp, - end = 20.dp, - top = 20.dp, - bottom = 4.dp, - ) .border( width = 2.dp, - color = MaterialTheme.customColors.warning, + color = outlineColor, shape = MaterialTheme.shapes.medium, ) .clip(MaterialTheme.shapes.medium) - .background(MaterialTheme.customColors.warningContainer) + .background(containerColor) ) { Row( horizontalArrangement = Arrangement.spacedBy(12.dp), @@ -48,14 +39,14 @@ fun MinimizationWarning(modifier: Modifier = Modifier) { .padding(horizontal = 20.dp, vertical = 14.dp) ) { Icon( - painter = painterResource(R.drawable.ic_warning), - tint = MaterialTheme.customColors.onWarningContainer, + painter = icon, + tint = iconColor, contentDescription = null, modifier = Modifier.size(28.dp), ) Text( - text = stringResource(R.string.installer_minimization_warning), + text = text, style = MaterialTheme.typography.labelMedium, ) } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index 1287b74c..e769c009 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -151,6 +151,6 @@ class InstallModel( SOC: $soc """.trimIndent() - return header + "\n\n" + Log.getStackTraceString(stacktrace) + return header + "\n\n" + Log.getStackTraceString(stacktrace).trimEnd() } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index 012d14e1..e0187060 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -9,6 +9,7 @@ import androidx.activity.compose.BackHandler import androidx.compose.foundation.* import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.* @@ -16,6 +17,10 @@ import androidx.compose.runtime.* 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.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp @@ -23,13 +28,19 @@ 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.BuildConfig import com.aliucord.manager.R import com.aliucord.manager.installer.steps.StepGroup -import com.aliucord.manager.ui.components.Wakelock -import com.aliucord.manager.ui.components.back +import com.aliucord.manager.ui.TextBanner +import com.aliucord.manager.ui.components.* import com.aliucord.manager.ui.components.dialogs.InstallerAbortDialog -import com.aliucord.manager.ui.screens.install.components.* +import com.aliucord.manager.ui.screens.install.components.InstallAppBar +import com.aliucord.manager.ui.screens.install.components.StepGroupCard import com.aliucord.manager.ui.screens.installopts.InstallOptions +import com.aliucord.manager.ui.util.paddings.PaddingValuesSides +import com.aliucord.manager.ui.util.paddings.exclude +import com.aliucord.manager.util.isIgnoringBatteryOptimizations +import kotlinx.collections.immutable.persistentListOf import org.koin.core.parameter.parametersOf class InstallScreen(private val data: InstallOptions) : Screen { @@ -38,8 +49,11 @@ class InstallScreen(private val data: InstallOptions) : Screen { @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow + val context = LocalContext.current val model = getScreenModel { parametersOf(data) } + val state = model.state.collectAsState() + val showMinimizationWarning = remember { !context.isIgnoringBatteryOptimizations() } LaunchedEffect(state.value) { if (state.value is InstallScreenState.CloseScreen) @@ -52,6 +66,9 @@ class InstallScreen(private val data: InstallOptions) : Screen { // Exit warning dialog (dismiss itself if install process state changes, esp. for Success) var showAbortWarning by remember(model.state.collectAsState()) { mutableStateOf(false) } + // The currently expanded step group on this screen + var expandedGroup by remember { mutableStateOf(StepGroup.Prepare) } + // Only show exit warning if currently working val onTryExit: () -> Unit = remember { { @@ -63,6 +80,12 @@ class InstallScreen(private val data: InstallOptions) : Screen { } } + // Close all groups when successfully finished everything + LaunchedEffect(state.value) { + if (state.value == InstallScreenState.Success) + expandedGroup = null + } + if (showAbortWarning) { InstallerAbortDialog( onDismiss = { showAbortWarning = false }, @@ -84,43 +107,110 @@ class InstallScreen(private val data: InstallOptions) : Screen { interactionSource = remember(::MutableInteractionSource), ), ) { paddingValues -> - Column(Modifier.padding(paddingValues)) { + Column( + verticalArrangement = Arrangement.spacedBy(20.dp), + modifier = Modifier + .padding(paddingValues.exclude(PaddingValuesSides.Bottom)), + ) { if (state.value == InstallScreenState.Working) { LinearProgressIndicator( modifier = Modifier - .fillMaxWidth() .height(4.dp) + .fillMaxWidth() ) } else { HorizontalDivider( thickness = 2.dp, - modifier = Modifier - .fillMaxWidth() - ) - - MinimizationWarning( modifier = Modifier.fillMaxWidth(), ) } - Column( - verticalArrangement = Arrangement.spacedBy(12.dp), + LazyColumn( + verticalArrangement = Arrangement.spacedBy(20.dp), + contentPadding = paddingValues.exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top), modifier = Modifier - .verticalScroll(rememberScrollState()) - .fillMaxWidth() - .padding(top = 6.dp) - .padding(16.dp) + .padding(horizontal = 16.dp) + .fillMaxSize(), ) { - var expandedGroup by remember { mutableStateOf(StepGroup.Prepare) } + if (showMinimizationWarning && !state.value.isFinished) { + item(key = "MINIMIZATION_WARNING_BANNER") { + Column { + TextBanner( + text = stringResource(R.string.installer_minimization_warning), + icon = painterResource(R.drawable.ic_warning), + iconColor = MaterialTheme.customColors.onWarningContainer, + outlineColor = MaterialTheme.customColors.warning, + containerColor = MaterialTheme.customColors.warningContainer, + modifier = Modifier + .padding(bottom = 20.dp) + .fillMaxWidth() + .animateItemPlacement(), + ) + + HorizontalDivider( + thickness = (.5).dp, + modifier = Modifier.fillMaxWidth(), + ) + } + } + } + + if (state.value is InstallScreenState.Failed) { + stickyHeader(key = "FAILED_BANNER") { + val handler = LocalUriHandler.current + + Surface(Modifier.animateItemPlacement()) { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + TextBanner( + text = "Installation failed! You can either retry or click this to open the Aliucord server for help.", + icon = painterResource(R.drawable.ic_warning), + iconColor = MaterialTheme.colorScheme.error, + // outlineColor = MaterialTheme.colorScheme.error.copy(alpha = .5f), + outlineColor = MaterialTheme.colorScheme.errorContainer, + containerColor = MaterialTheme.colorScheme.errorContainer, + modifier = Modifier + .fillMaxWidth() + .clickable { handler.openUri("https://discord.gg/${BuildConfig.SUPPORT_SERVER}") } + ) - // Close all groups when successfully finished everything - LaunchedEffect(state.value) { - if (state.value == InstallScreenState.Success) - expandedGroup = null + FilledTonalIconButton( + shape = MaterialTheme.shapes.medium, + colors = IconButtonDefaults.filledTonalIconButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = model::restart, + modifier = Modifier.fillMaxWidth(), + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(R.drawable.ic_refresh), + contentDescription = null, + ) + Text( + text = "Retry installation", + style = MaterialTheme.typography.labelLarge, + ) + } + } + + HorizontalDivider( + thickness = (.5).dp, + modifier = Modifier + .padding(top = 8.dp, bottom = 10.dp) + .fillMaxWidth(), + ) + } + } + } } - model.installSteps?.let { groupedSteps -> - for ((group, steps) in groupedSteps.entries) key(group) { + for ((group, steps) in model.installSteps?.entries ?: persistentListOf()) { + item(key = System.identityHashCode(group)) { StepGroupCard( name = stringResource(group.localizedName), subSteps = steps, @@ -133,52 +223,59 @@ class InstallScreen(private val data: InstallOptions) : Screen { } } - if (state.value.isFinished) { - Row( - horizontalArrangement = Arrangement.End, - modifier = Modifier.fillMaxWidth() - ) { - FilledTonalButton(onClick = model::clearCache) { - Text(stringResource(R.string.setting_clear_cache)) - } - } - } + // if (state.value is InstallScreenState.Success) { + // item(key = "BUTTON_ROW") { + // Row( + // horizontalArrangement = Arrangement.End, + // modifier = Modifier.fillMaxWidth() + // ) { + // FilledTonalButton(onClick = model::clearCache) { + // Text(stringResource(R.string.setting_clear_cache)) + // } + // } + // } + // } if (state.value is InstallScreenState.Failed) { val failureLog = (state.value as InstallScreenState.Failed).failureLog - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End), - modifier = Modifier.fillMaxWidth() - ) { - FilledTonalButton(onClick = model::clearCache) { - Text(stringResource(R.string.setting_clear_cache)) - } + item(key = "BUTTON_ROW") { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End), + modifier = Modifier.fillMaxWidth() + ) { + FilledTonalButton(onClick = model::clearCache) { + Text(stringResource(R.string.setting_clear_cache)) + } - Spacer(Modifier.weight(1f, true)) + Spacer(Modifier.weight(1f, true)) - OutlinedButton(onClick = model::saveFailureLog) { - Text(stringResource(R.string.installer_save_file)) - } + OutlinedButton(onClick = model::saveFailureLog) { + Text(stringResource(R.string.installer_save_file)) + } - FilledTonalButton(onClick = model::copyDebugToClipboard) { - Text(stringResource(R.string.action_copy)) + FilledTonalButton(onClick = model::copyDebugToClipboard) { + Text(stringResource(R.string.action_copy)) + } } } - SelectionContainer { - Text( - text = failureLog, - style = MaterialTheme.typography.labelSmall, - fontFamily = FontFamily.Monospace, - softWrap = false, - modifier = Modifier - .clip(RoundedCornerShape(10.dp)) - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(10.dp)) - .padding(10.dp) - .horizontalScroll(rememberScrollState()) - ) - } + // item(key = "ERROR_LOG") { + // SelectionContainer { + // Text( + // text = failureLog, + // style = MaterialTheme.typography.labelSmall, + // fontFamily = FontFamily.Monospace, + // softWrap = false, + // modifier = Modifier + // .padding(top = 20.dp) + // .clip(RoundedCornerShape(10.dp)) + // .background(MaterialTheme.colorScheme.surfaceColorAtElevation(10.dp)) + // .padding(24.dp) + // .horizontalScroll(rememberScrollState()) + // ) + // } + // } } } } From 601df060cef1849a0a6add8f587eb79ea88f2b48 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:53:38 -0700 Subject: [PATCH 04/10] reorganize failed screen --- .../com/aliucord/manager/ui/TextBanner.kt | 20 +- .../ui/screens/install/InstallModel.kt | 1 + .../ui/screens/install/InstallScreen.kt | 179 +++++++++--------- .../install/components/StepGroupCard.kt | 11 +- 4 files changed, 114 insertions(+), 97 deletions(-) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/TextBanner.kt b/app/src/main/kotlin/com/aliucord/manager/ui/TextBanner.kt index 9c590911..282b67d5 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/TextBanner.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/TextBanner.kt @@ -1,7 +1,6 @@ package com.aliucord.manager.ui -import androidx.compose.foundation.background -import androidx.compose.foundation.border +import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.Composable @@ -11,26 +10,31 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.unit.dp +import com.aliucord.manager.ui.util.thenIf @Composable fun TextBanner( text: String, icon: Painter, iconColor: Color, - outlineColor: Color, + outlineColor: Color?, containerColor: Color, + onClick: (() -> Unit)? = null, modifier: Modifier = Modifier, ) { Box( contentAlignment = Alignment.Center, modifier = modifier - .border( - width = 2.dp, - color = outlineColor, - shape = MaterialTheme.shapes.medium, - ) + .thenIf(outlineColor) { color -> + border( + width = 2.dp, + color = color, + shape = MaterialTheme.shapes.medium, + ) + } .clip(MaterialTheme.shapes.medium) .background(containerColor) + .thenIf(onClick) { clickable(onClick = it) } ) { Row( horizontalArrangement = Arrangement.spacedBy(12.dp), diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index e769c009..46f80ab5 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -81,6 +81,7 @@ class InstallModel( val newInstallJob = screenModelScope.launch { val runner = KotlinInstallRunner(options) + // FIXME: restarting does not display new steps in UI installSteps = runner.steps.groupBy { it.group } .mapValues { it.value.toUnsafeImmutable() } .toUnsafeImmutable() diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index e0187060..937d5b97 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -6,23 +6,19 @@ package com.aliucord.manager.ui.screens.install import androidx.activity.compose.BackHandler -import androidx.compose.foundation.* +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.* import androidx.compose.runtime.* 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.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.koin.getScreenModel @@ -37,8 +33,7 @@ import com.aliucord.manager.ui.components.dialogs.InstallerAbortDialog import com.aliucord.manager.ui.screens.install.components.InstallAppBar import com.aliucord.manager.ui.screens.install.components.StepGroupCard import com.aliucord.manager.ui.screens.installopts.InstallOptions -import com.aliucord.manager.ui.util.paddings.PaddingValuesSides -import com.aliucord.manager.ui.util.paddings.exclude +import com.aliucord.manager.ui.util.paddings.* import com.aliucord.manager.util.isIgnoringBatteryOptimizations import kotlinx.collections.immutable.persistentListOf import org.koin.core.parameter.parametersOf @@ -127,85 +122,59 @@ class InstallScreen(private val data: InstallOptions) : Screen { LazyColumn( verticalArrangement = Arrangement.spacedBy(20.dp), - contentPadding = paddingValues.exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top), + contentPadding = paddingValues + .exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top) + .add(PaddingValues(bottom = 25.dp)), modifier = Modifier .padding(horizontal = 16.dp) .fillMaxSize(), ) { if (showMinimizationWarning && !state.value.isFinished) { item(key = "MINIMIZATION_WARNING_BANNER") { - Column { - TextBanner( - text = stringResource(R.string.installer_minimization_warning), - icon = painterResource(R.drawable.ic_warning), - iconColor = MaterialTheme.customColors.onWarningContainer, - outlineColor = MaterialTheme.customColors.warning, - containerColor = MaterialTheme.customColors.warningContainer, - modifier = Modifier - .padding(bottom = 20.dp) - .fillMaxWidth() - .animateItemPlacement(), - ) + TextBanner( + text = stringResource(R.string.installer_minimization_warning), + icon = painterResource(R.drawable.ic_warning), + iconColor = MaterialTheme.customColors.onWarningContainer, + outlineColor = MaterialTheme.customColors.warning, + containerColor = MaterialTheme.customColors.warningContainer, + modifier = Modifier + .fillMaxWidth() + .animateItemPlacement(), + ) + } - HorizontalDivider( - thickness = (.5).dp, - modifier = Modifier.fillMaxWidth(), - ) - } + item(contentType = "DIVIDER") { + HorizontalDivider( + thickness = 1.dp, + modifier = Modifier.animateItemPlacement(), + ) } } if (state.value is InstallScreenState.Failed) { - stickyHeader(key = "FAILED_BANNER") { + item(key = "FAILED_BANNER") { val handler = LocalUriHandler.current - Surface(Modifier.animateItemPlacement()) { - Column( - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { - TextBanner( - text = "Installation failed! You can either retry or click this to open the Aliucord server for help.", - icon = painterResource(R.drawable.ic_warning), - iconColor = MaterialTheme.colorScheme.error, - // outlineColor = MaterialTheme.colorScheme.error.copy(alpha = .5f), - outlineColor = MaterialTheme.colorScheme.errorContainer, - containerColor = MaterialTheme.colorScheme.errorContainer, - modifier = Modifier - .fillMaxWidth() - .clickable { handler.openUri("https://discord.gg/${BuildConfig.SUPPORT_SERVER}") } - ) - - FilledTonalIconButton( - shape = MaterialTheme.shapes.medium, - colors = IconButtonDefaults.filledTonalIconButtonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - onClick = model::restart, - modifier = Modifier.fillMaxWidth(), - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(6.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - painter = painterResource(R.drawable.ic_refresh), - contentDescription = null, - ) - Text( - text = "Retry installation", - style = MaterialTheme.typography.labelLarge, - ) - } - } + TextBanner( + text = "Installation failed! You can either retry or click this to open the Aliucord server for help.", + icon = painterResource(R.drawable.ic_warning), + iconColor = MaterialTheme.colorScheme.error, + outlineColor = null, + containerColor = MaterialTheme.colorScheme.errorContainer, + onClick = { handler.openUri("https://discord.gg/${BuildConfig.SUPPORT_SERVER}") }, + modifier = Modifier + .fillMaxWidth() + .animateItemPlacement() + ) + } - HorizontalDivider( - thickness = (.5).dp, - modifier = Modifier - .padding(top = 8.dp, bottom = 10.dp) - .fillMaxWidth(), - ) - } - } + item(contentType = "DIVIDER") { + HorizontalDivider( + thickness = 1.dp, + modifier = Modifier + .padding(vertical = 4.dp) + .animateItemPlacement(), + ) } } @@ -237,25 +206,65 @@ class InstallScreen(private val data: InstallOptions) : Screen { // } if (state.value is InstallScreenState.Failed) { - val failureLog = (state.value as InstallScreenState.Failed).failureLog + item(contentType = "DIVIDER") { + HorizontalDivider( + thickness = 1.dp, + modifier = Modifier + .padding(vertical = 4.dp) + .animateItemPlacement(), + ) + } item(key = "BUTTON_ROW") { - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End), - modifier = Modifier.fillMaxWidth() + Column( + verticalArrangement = Arrangement.spacedBy(14.dp), + modifier = Modifier + .animateItemPlacement() ) { - FilledTonalButton(onClick = model::clearCache) { - Text(stringResource(R.string.setting_clear_cache)) + FilledTonalIconButton( + shape = MaterialTheme.shapes.medium, + colors = IconButtonDefaults.filledTonalIconButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = model::restart, + modifier = Modifier + .fillMaxWidth() + .height(42.dp), + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(R.drawable.ic_refresh), + contentDescription = null, + modifier = Modifier.size(20.dp), + ) + Text( + text = "Retry installation", + style = MaterialTheme.typography.labelLarge, + textAlign = TextAlign.Center, + ) + } } - Spacer(Modifier.weight(1f, true)) + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End), + modifier = Modifier.fillMaxWidth(), + ) { + FilledTonalButton(onClick = model::clearCache) { + Text(stringResource(R.string.setting_clear_cache)) + } - OutlinedButton(onClick = model::saveFailureLog) { - Text(stringResource(R.string.installer_save_file)) - } + Spacer(Modifier.weight(1f, true)) - FilledTonalButton(onClick = model::copyDebugToClipboard) { - Text(stringResource(R.string.action_copy)) + OutlinedButton(onClick = model::saveFailureLog) { + Text(stringResource(R.string.installer_save_file)) + } + + FilledTonalButton(onClick = model::copyDebugToClipboard) { + Text(stringResource(R.string.action_copy)) + } } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt index d61b8dd2..bb9c91df 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt @@ -52,13 +52,16 @@ fun StepGroupCard( ) { Row( verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + horizontalArrangement = Arrangement.spacedBy(14.dp), modifier = Modifier .clickable(true, onClick = onExpand) .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 20.dp) + .padding(20.dp) ) { - StepStateIcon(groupState, 24.dp) + StepStateIcon( + state = groupState, + size = 24.dp, + ) Text(text = name) @@ -88,7 +91,7 @@ fun StepGroupCard( modifier = Modifier .background(MaterialTheme.colorScheme.background.copy(0.6f)) .fillMaxWidth() - .padding(16.dp) + .padding(20.dp) .padding(start = 4.dp) ) { for (step in subSteps) key(step) { From b6f8e30b1a287eed58697e12bc6619b199171b13 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Sun, 10 Mar 2024 22:57:55 -0700 Subject: [PATCH 05/10] more stuff --- app/src/main/AndroidManifest.xml | 4 +++- .../aliucord/manager/ui/screens/install/InstallModel.kt | 1 - .../aliucord/manager/ui/screens/install/InstallScreen.kt | 7 ++++++- .../manager/ui/screens/install/components/StepGroupCard.kt | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 28aec094..d5d5d2a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -44,7 +44,9 @@ android:name=".MainActivity" android:exported="true" android:launchMode="singleTask" - android:theme="@style/Theme.AliucordManager.SplashScreen"> + android:screenOrientation="portrait" + android:theme="@style/Theme.AliucordManager.SplashScreen" + tools:ignore="DiscouragedApi,LockedOrientationActivity"> diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index 46f80ab5..e769c009 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -81,7 +81,6 @@ class InstallModel( val newInstallJob = screenModelScope.launch { val runner = KotlinInstallRunner(options) - // FIXME: restarting does not display new steps in UI installSteps = runner.steps.groupBy { it.group } .mapValues { it.value.toUnsafeImmutable() } .toUnsafeImmutable() diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index 937d5b97..98bc7e6e 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -48,6 +49,7 @@ class InstallScreen(private val data: InstallOptions) : Screen { val model = getScreenModel { parametersOf(data) } val state = model.state.collectAsState() + val listState = rememberLazyListState() val showMinimizationWarning = remember { !context.isIgnoringBatteryOptimizations() } LaunchedEffect(state.value) { @@ -79,6 +81,8 @@ class InstallScreen(private val data: InstallOptions) : Screen { LaunchedEffect(state.value) { if (state.value == InstallScreenState.Success) expandedGroup = null + + listState.animateScrollToItem(0) } if (showAbortWarning) { @@ -121,6 +125,7 @@ class InstallScreen(private val data: InstallOptions) : Screen { } LazyColumn( + state = listState, verticalArrangement = Arrangement.spacedBy(20.dp), contentPadding = paddingValues .exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top) @@ -156,7 +161,7 @@ class InstallScreen(private val data: InstallOptions) : Screen { val handler = LocalUriHandler.current TextBanner( - text = "Installation failed! You can either retry or click this to open the Aliucord server for help.", + text = "Installation failed! You can either retry or click this banner to open the Aliucord server for help.", icon = painterResource(R.drawable.ic_warning), iconColor = MaterialTheme.colorScheme.error, outlineColor = null, diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt index d3b087c1..b3508918 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt @@ -24,7 +24,7 @@ fun StepGroupCard( isExpanded: Boolean, onExpand: () -> Unit, ) { - val groupState by remember { + val groupState by remember(subSteps) { derivedStateOf { when { // If all steps are pending then show pending From 9aeeeb538d511a5375665fdd231afb8b9ed3d184 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:00:29 -0700 Subject: [PATCH 06/10] more ui changes --- .../ui/screens/install/InstallModel.kt | 24 +- .../ui/screens/install/InstallScreen.kt | 249 +++++++++--------- .../ui/screens/install/InstallScreenState.kt | 11 +- .../install/components/MainActionButton.kt | 53 ++++ .../install/components/StepGroupCard.kt | 4 +- .../install/components/StepStateIcon.kt | 2 +- 6 files changed, 191 insertions(+), 152 deletions(-) create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index e769c009..2c89f0a9 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -31,7 +31,6 @@ class InstallModel( ) : StateScreenModel(InstallScreenState.Pending) { private lateinit var startTime: Date private var installJob: Job? = null - private var autocloseCancelled: Boolean = false var installSteps by mutableStateOf>?>(null) private set @@ -40,6 +39,15 @@ class InstallModel( restart() } + fun launchApp() { + screenModelScope.launch { + if (state.value !is InstallScreenState.Success) + return@launch + + // TODO: finish this + } + } + fun copyDebugToClipboard() { val content = (state.value as? InstallScreenState.Failed)?.failureLog ?: return @@ -64,13 +72,6 @@ class InstallModel( application.showToast(R.string.action_cleared_cache) } - /** - * Cancel the screen auto-close once installation was completed - */ - fun cancelAutoclose() { - autocloseCancelled = true - } - fun restart() { installJob?.cancel("Manual cancellation") installSteps = null @@ -100,13 +101,6 @@ class InstallModel( // At this point, the installation has successfully completed else { mutableState.value = InstallScreenState.Success - autocloseCancelled = false - - // Wait 5s before returning to Home if screen hasn't been clicked - delay(5000) - if (!autocloseCancelled) { - mutableState.value = InstallScreenState.CloseScreen - } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index b53e131b..55c97350 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -7,20 +7,20 @@ package com.aliucord.manager.ui.screens.install import android.os.Parcelable import androidx.activity.compose.BackHandler -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.animation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState 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.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.koin.getScreenModel @@ -32,16 +32,19 @@ import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.ui.TextBanner import com.aliucord.manager.ui.components.* import com.aliucord.manager.ui.components.dialogs.InstallerAbortDialog -import com.aliucord.manager.ui.screens.install.components.InstallAppBar -import com.aliucord.manager.ui.screens.install.components.StepGroupCard +import com.aliucord.manager.ui.screens.install.components.* import com.aliucord.manager.ui.screens.installopts.InstallOptions import com.aliucord.manager.ui.util.paddings.* +import com.aliucord.manager.ui.util.spacedByLastAtBottom import com.aliucord.manager.util.isIgnoringBatteryOptimizations import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.flow.filter import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import org.koin.core.parameter.parametersOf +private val VERTICAL_PADDING: Dp = 18.dp + @Parcelize class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { @IgnoredOnParcel @@ -53,17 +56,17 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { val context = LocalContext.current val model = getScreenModel { parametersOf(data) } - val state = model.state.collectAsState() + val state by model.state.collectAsState() val listState = rememberLazyListState() val showMinimizationWarning = remember { !context.isIgnoringBatteryOptimizations() } - LaunchedEffect(state.value) { - if (state.value is InstallScreenState.CloseScreen) + LaunchedEffect(state) { + if (state is InstallScreenState.CloseScreen) navigator.back(currentActivity = null) } // Prevent screen from turning off while working - Wakelock(active = state.value is InstallScreenState.Working) + Wakelock(active = state is InstallScreenState.Working) // Exit warning dialog (dismiss itself if install process state changes, esp. for Success) var showAbortWarning by remember(model.state.collectAsState()) { mutableStateOf(false) } @@ -74,7 +77,7 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { // Only show exit warning if currently working val onTryExit: () -> Unit = remember { { - if (state.value == InstallScreenState.Working) { + if (state == InstallScreenState.Working) { showAbortWarning = true } else { navigator.back(currentActivity = null) @@ -83,8 +86,8 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { } // Close all groups when successfully finished everything - LaunchedEffect(state.value) { - if (state.value == InstallScreenState.Success) + LaunchedEffect(state) { + if (state == InstallScreenState.Success) expandedGroup = null listState.animateScrollToItem(0) @@ -104,19 +107,13 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { Scaffold( topBar = { InstallAppBar(onTryExit) }, - modifier = Modifier - .clickable( - indication = null, - onClick = model::cancelAutoclose, - interactionSource = remember(::MutableInteractionSource), - ), ) { paddingValues -> Column( - verticalArrangement = Arrangement.spacedBy(20.dp), + verticalArrangement = Arrangement.spacedBy(VERTICAL_PADDING), modifier = Modifier .padding(paddingValues.exclude(PaddingValuesSides.Bottom)), ) { - if (state.value == InstallScreenState.Working) { + if (state == InstallScreenState.Working) { LinearProgressIndicator( modifier = Modifier .height(4.dp) @@ -131,7 +128,7 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { LazyColumn( state = listState, - verticalArrangement = Arrangement.spacedBy(20.dp), + verticalArrangement = Arrangement.spacedByLastAtBottom(0.dp), contentPadding = paddingValues .exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top) .add(PaddingValues(bottom = 25.dp)), @@ -139,8 +136,8 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { .padding(horizontal = 16.dp) .fillMaxSize(), ) { - if (showMinimizationWarning && !state.value.isFinished) { - item(key = "MINIMIZATION_WARNING_BANNER") { + item(key = "MINIMIZATION_WARNING") { + BannerSection(visible = showMinimizationWarning && !state.isFinished) { TextBanner( text = stringResource(R.string.installer_minimization_warning), icon = painterResource(R.drawable.ic_warning), @@ -148,21 +145,14 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { outlineColor = MaterialTheme.customColors.warning, containerColor = MaterialTheme.customColors.warningContainer, modifier = Modifier - .fillMaxWidth() - .animateItemPlacement(), - ) - } - - item(contentType = "DIVIDER") { - HorizontalDivider( - thickness = 1.dp, - modifier = Modifier.animateItemPlacement(), + .padding(bottom = VERTICAL_PADDING) + .fillMaxWidth(), ) } } - if (state.value is InstallScreenState.Failed) { - item(key = "FAILED_BANNER") { + item(key = "FAILED_BANNER") { + BannerSection(visible = state is InstallScreenState.Failed) { val handler = LocalUriHandler.current TextBanner( @@ -173,17 +163,8 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { containerColor = MaterialTheme.colorScheme.errorContainer, onClick = { handler.openUri("https://discord.gg/${BuildConfig.SUPPORT_SERVER}") }, modifier = Modifier - .fillMaxWidth() - .animateItemPlacement() - ) - } - - item(contentType = "DIVIDER") { - HorizontalDivider( - thickness = 1.dp, - modifier = Modifier - .padding(vertical = 4.dp) - .animateItemPlacement(), + .padding(bottom = VERTICAL_PADDING) + .fillMaxWidth(), ) } } @@ -194,110 +175,116 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { name = stringResource(group.localizedName), subSteps = steps, isExpanded = expandedGroup == group, - onExpand = { - model.cancelAutoclose() - expandedGroup = group - }, + onExpand = { expandedGroup = group }, + modifier = Modifier + .padding(bottom = VERTICAL_PADDING) + .fillMaxWidth() ) } } - // if (state.value is InstallScreenState.Success) { - // item(key = "BUTTON_ROW") { - // Row( - // horizontalArrangement = Arrangement.End, - // modifier = Modifier.fillMaxWidth() - // ) { - // FilledTonalButton(onClick = model::clearCache) { - // Text(stringResource(R.string.setting_clear_cache)) - // } - // } - // } - // } + item(key = "BUTTONS") { + val filteredState by remember { model.state.filter { it.isNewlyFinished } } + .collectAsState(initial = null) - if (state.value is InstallScreenState.Failed) { - item(contentType = "DIVIDER") { - HorizontalDivider( - thickness = 1.dp, - modifier = Modifier - .padding(vertical = 4.dp) - .animateItemPlacement(), - ) - } - - item(key = "BUTTON_ROW") { - Column( - verticalArrangement = Arrangement.spacedBy(14.dp), - modifier = Modifier - .animateItemPlacement() - ) { - FilledTonalIconButton( - shape = MaterialTheme.shapes.medium, - colors = IconButtonDefaults.filledTonalIconButtonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - onClick = model::restart, + AnimatedVisibility( + visible = filteredState != null, + enter = fadeIn() + slideInVertically(), + exit = ExitTransition.None, + ) { + Column { + HorizontalDivider( + thickness = 1.dp, modifier = Modifier - .fillMaxWidth() - .height(42.dp), - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(6.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - painter = painterResource(R.drawable.ic_refresh), - contentDescription = null, - modifier = Modifier.size(20.dp), - ) - Text( - text = "Retry installation", - style = MaterialTheme.typography.labelLarge, - textAlign = TextAlign.Center, - ) - } - } + .padding(vertical = 4.dp) + .padding(bottom = VERTICAL_PADDING) + ) - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End), - modifier = Modifier.fillMaxWidth(), - ) { - FilledTonalButton(onClick = model::clearCache) { - Text(stringResource(R.string.setting_clear_cache)) + when (filteredState) { + InstallScreenState.Success -> { + MainActionButton( + text = "Launch Aliucord", + icon = painterResource(R.drawable.ic_launch), + onClick = model::launchApp, + ) } - Spacer(Modifier.weight(1f, true)) - - OutlinedButton(onClick = model::saveFailureLog) { - Text(stringResource(R.string.installer_save_file)) + is InstallScreenState.Failed -> { + MainActionButton( + text = "Retry installation", + icon = painterResource(R.drawable.ic_refresh), + onClick = model::restart, + ) } - FilledTonalButton(onClick = model::copyDebugToClipboard) { - Text(stringResource(R.string.action_copy)) - } + else -> error("unreachable") } } } + } + + item(key = "FUN_FACT") { + val facts = arrayOf( + "Did you know that Google Play Protect is useless?", + "Did you know Discord (allegedly) fired the Android team when introducing RNA?", + "Did you know Aliucord with 150+ plugins still somehow runs better than Discord's new app?", + "i am in your walls", + ) - // item(key = "ERROR_LOG") { - // SelectionContainer { - // Text( - // text = failureLog, - // style = MaterialTheme.typography.labelSmall, - // fontFamily = FontFamily.Monospace, - // softWrap = false, - // modifier = Modifier - // .padding(top = 20.dp) - // .clip(RoundedCornerShape(10.dp)) - // .background(MaterialTheme.colorScheme.surfaceColorAtElevation(10.dp)) - // .padding(24.dp) - // .horizontalScroll(rememberScrollState()) - // ) - // } - // } + Text( + text = "FUN FACT: " + remember { facts.random() }, + style = MaterialTheme.typography.bodySmall, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(horizontal = VERTICAL_PADDING) + .padding(bottom = 25.dp) + .fillMaxWidth() + .alpha(.6f) + ) } } } } } } + +@Composable +private fun BannerSection( + visible: Boolean, + modifier: Modifier = Modifier, + content: @Composable () -> Unit, +) { + AnimatedVisibility( + visible = visible, + enter = fadeIn() + slideInVertically(), + exit = fadeOut() + slideOutVertically(), + modifier = modifier + .padding(bottom = VERTICAL_PADDING), + ) { + Column { + content() + + HorizontalDivider( + thickness = 1.dp, + modifier = Modifier.padding(vertical = 4.dp), + ) + } + } +} + +// item(key = "ERROR_LOG") { +// SelectionContainer { +// Text( +// text = failureLog, +// style = MaterialTheme.typography.labelSmall, +// fontFamily = FontFamily.Monospace, +// softWrap = false, +// modifier = Modifier +// .padding(top = VERTICAL_PADDING) +// .clip(RoundedCornerShape(10.dp)) +// .background(MaterialTheme.colorScheme.surfaceColorAtElevation(10.dp)) +// .padding(24.dp) +// .horizontalScroll(rememberScrollState()) +// ) +// } +// } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreenState.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreenState.kt index f9fab47a..c6d9d0ce 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreenState.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreenState.kt @@ -1,5 +1,7 @@ package com.aliucord.manager.ui.screens.install +import com.aliucord.manager.ui.screens.install.InstallScreenState.* + sealed interface InstallScreenState { data object Pending : InstallScreenState data object Working : InstallScreenState @@ -10,7 +12,10 @@ sealed interface InstallScreenState { ) : InstallScreenState data object CloseScreen : InstallScreenState - - val isFinished: Boolean - get() = this !is Pending && this !is Working } + +val InstallScreenState.isNewlyFinished: Boolean + inline get() = this == Success || this is Failed + +val InstallScreenState.isFinished: Boolean + inline get() = isNewlyFinished || this == CloseScreen diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt new file mode 100644 index 00000000..5e108380 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt @@ -0,0 +1,53 @@ +package com.aliucord.manager.ui.screens.install.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.material3.FilledTonalIconButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp + +@Composable +fun MainActionButton( + text: String, + icon: Painter, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + FilledTonalIconButton( + shape = MaterialTheme.shapes.medium, + colors = IconButtonDefaults.filledTonalIconButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = onClick, + modifier = modifier + .fillMaxWidth() + .height(46.dp), + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = text, + style = MaterialTheme.typography.labelLarge, + textAlign = TextAlign.Center, + ) + Icon( + painter = icon, + contentDescription = null, + modifier = Modifier.size(20.dp), + ) + } + } +} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt index b3508918..b5cce943 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepGroupCard.kt @@ -23,6 +23,7 @@ fun StepGroupCard( subSteps: ImmutableList, isExpanded: Boolean, onExpand: () -> Unit, + modifier: Modifier = Modifier, ) { val groupState by remember(subSteps) { derivedStateOf { @@ -55,8 +56,7 @@ fun StepGroupCard( } Column( - modifier = Modifier - .fillMaxWidth() + modifier = modifier .clip(MaterialTheme.shapes.large) .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)) ) { diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepStateIcon.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepStateIcon.kt index cfb21731..d71cd500 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepStateIcon.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/StepStateIcon.kt @@ -35,7 +35,7 @@ fun StepStateIcon( StepState.Pending -> Icon( painter = painterResource(R.drawable.ic_circle), contentDescription = stringResource(R.string.status_queued), - tint = MaterialTheme.colorScheme.onSurface.copy(0.4f), + tint = MaterialTheme.colorScheme.onSurface.copy(.2f), modifier = Modifier.size(size) ) From d4ce1a82a04ca1d2473e8bfeabf56ac4a91d68b3 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Fri, 17 May 2024 16:21:33 -0700 Subject: [PATCH 07/10] wip --- .../ui/screens/install/InstallModel.kt | 29 ++++++++++++++++--- .../ui/screens/install/InstallScreen.kt | 9 +----- app/src/main/res/values/strings.xml | 6 ++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index b5e652d7..2cc484c7 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -41,16 +41,24 @@ class InstallModel( var showGppWarning by mutableStateOf(false) private set + var funFact by mutableIntStateOf(0) + private set + init { restart() } fun launchApp() { - screenModelScope.launch { - if (state.value !is InstallScreenState.Success) - return@launch + if (state.value !is InstallScreenState.Success) + return - // TODO: finish this + val launchIntent = application.packageManager + .getLaunchIntentForPackage(options.packageName) + + if (launchIntent != null) { + application.startActivity(launchIntent) + } else { + application.showToast(R.string.launch_aliucord_fail) } } @@ -98,6 +106,7 @@ class InstallModel( installSteps = null startTime = Date() + funFact = FUN_FACTS.random() mutableState.value = InstallScreenState.Working val newInstallJob = screenModelScope.launch { @@ -183,4 +192,16 @@ class InstallModel( return header + "\n\n" + Log.getStackTraceString(stacktrace).trimEnd() } + + private companion object { + /** + * Random fun facts to show on the installation screen. + */ + val FUN_FACTS = arrayOf( + R.string.fun_fact_1, + R.string.fun_fact_2, + R.string.fun_fact_3, + R.string.fun_fact_4, + ) + } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index 9f32a6ab..74c76cf2 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -229,15 +229,8 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { } item(key = "FUN_FACT") { - val facts = arrayOf( - "Did you know that Google Play Protect is useless?", - "Did you know Discord (allegedly) fired the Android team when introducing RNA?", - "Did you know Aliucord with 150+ plugins still somehow runs better than Discord's new app?", - "i am in your walls", - ) - Text( - text = "FUN FACT: " + remember { facts.random() }, + text = stringResource(R.string.fun_fact_prefix, stringResource(model.funFact)), style = MaterialTheme.typography.bodySmall, textAlign = TextAlign.Center, modifier = Modifier diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 65ddb166..4ecf014e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -159,4 +159,10 @@ Google Play Protect appears to be enabled on your device. It may attempt to interfere with a new installation due to the usage of a unique signing key. You can disable it in Play Protect\'s settings.\n\nIf it does show a warning dialog, press\n\"More Details\" -> \"Install anyway\" Continue Open Play Protect + + Fun Fact: %s + Did you know that Google Play Protect is useless? + Did you know Aliucord with 150+ plugins somehow runs better than Discord\'s new app? + Did you know Aliucord has over 200 available plugins? + i am in your walls From b61493717290a0b24e9dd2e672b6fbcf051bcd01 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Fri, 17 May 2024 16:30:32 -0700 Subject: [PATCH 08/10] more wip --- .../installer/steps/KotlinInstallRunner.kt | 2 +- .../CopyDependenciesStep.kt | 5 +-- .../installer/steps/install/AlignmentStep.kt | 2 +- .../installer/steps/install/InstallStep.kt | 2 +- .../installer/steps/install/SigningStep.kt | 2 +- .../installer/steps/patch/AddAliuhookStep.kt | 1 + .../installer/steps/patch/AddInjectorStep.kt | 3 +- .../steps/patch/PatchManifestStep.kt | 1 + .../installer/steps/patch/ReplaceIconStep.kt | 1 + .../manager/installer/util/ManifestPatcher.kt | 2 +- .../ui/screens/install/InstallModel.kt | 12 ++---- .../install/components/InstalledButtonRow.kt | 43 +++++++++++++++++++ .../install/components/MainActionButton.kt | 12 +----- app/src/main/res/values/strings.xml | 1 - 14 files changed, 60 insertions(+), 29 deletions(-) rename app/src/main/kotlin/com/aliucord/manager/installer/steps/{patch => download}/CopyDependenciesStep.kt (87%) create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/KotlinInstallRunner.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/KotlinInstallRunner.kt index 2a806a94..083e7c5e 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/KotlinInstallRunner.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/KotlinInstallRunner.kt @@ -22,9 +22,9 @@ class KotlinInstallRunner(options: InstallOptions) : StepRunner() { DownloadInjectorStep(), DownloadAliuhookStep(), DownloadKotlinStep(), + CopyDependenciesStep(), // Patch - CopyDependenciesStep(), ReplaceIconStep(options), PatchManifestStep(options), AddInjectorStep(), diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/CopyDependenciesStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/download/CopyDependenciesStep.kt similarity index 87% rename from app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/CopyDependenciesStep.kt rename to app/src/main/kotlin/com/aliucord/manager/installer/steps/download/CopyDependenciesStep.kt index 309f402d..74024109 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/CopyDependenciesStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/download/CopyDependenciesStep.kt @@ -1,10 +1,9 @@ -package com.aliucord.manager.installer.steps.patch +package com.aliucord.manager.installer.steps.download import com.aliucord.manager.R import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step -import com.aliucord.manager.installer.steps.download.DownloadDiscordStep import com.aliucord.manager.manager.PathManager import org.koin.core.component.KoinComponent import org.koin.core.component.inject @@ -22,7 +21,7 @@ class CopyDependenciesStep : Step(), KoinComponent { val patchedApk: File = paths.patchingWorkingDir() .resolve("patched.apk") - override val group = StepGroup.Patch + override val group = StepGroup.Download override val localizedName = R.string.install_step_copy override suspend fun execute(container: StepRunner) { diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/AlignmentStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/AlignmentStep.kt index b4e9d758..22cc46d8 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/AlignmentStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/AlignmentStep.kt @@ -6,7 +6,7 @@ import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step import com.aliucord.manager.installer.steps.base.StepState -import com.aliucord.manager.installer.steps.patch.CopyDependenciesStep +import com.aliucord.manager.installer.steps.download.CopyDependenciesStep import com.github.diamondminer88.zip.* import org.koin.core.component.KoinComponent diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/InstallStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/InstallStep.kt index 00aa9aed..8721f90d 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/InstallStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/InstallStep.kt @@ -7,7 +7,7 @@ import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step import com.aliucord.manager.installer.steps.base.StepState -import com.aliucord.manager.installer.steps.patch.CopyDependenciesStep +import com.aliucord.manager.installer.steps.download.CopyDependenciesStep import com.aliucord.manager.installers.InstallerResult import com.aliucord.manager.manager.InstallerManager import com.aliucord.manager.manager.PreferencesManager diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/SigningStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/SigningStep.kt index bf84aced..261df703 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/SigningStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/install/SigningStep.kt @@ -4,7 +4,7 @@ import com.aliucord.manager.R import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step -import com.aliucord.manager.installer.steps.patch.CopyDependenciesStep +import com.aliucord.manager.installer.steps.download.CopyDependenciesStep import com.aliucord.manager.installer.util.Signer import org.koin.core.component.KoinComponent diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddAliuhookStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddAliuhookStep.kt index b10f997f..169ca475 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddAliuhookStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddAliuhookStep.kt @@ -5,6 +5,7 @@ import com.aliucord.manager.R import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step +import com.aliucord.manager.installer.steps.download.CopyDependenciesStep import com.aliucord.manager.installer.steps.download.DownloadAliuhookStep import com.github.diamondminer88.zip.ZipReader import com.github.diamondminer88.zip.ZipWriter diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddInjectorStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddInjectorStep.kt index e60ce32d..3318d45b 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddInjectorStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/AddInjectorStep.kt @@ -4,8 +4,7 @@ import com.aliucord.manager.R import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step -import com.aliucord.manager.installer.steps.download.DownloadInjectorStep -import com.aliucord.manager.installer.steps.download.DownloadKotlinStep +import com.aliucord.manager.installer.steps.download.* import com.github.diamondminer88.zip.ZipReader import com.github.diamondminer88.zip.ZipWriter import org.koin.core.component.KoinComponent diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/PatchManifestStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/PatchManifestStep.kt index ae7d608d..8a6ab36f 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/PatchManifestStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/PatchManifestStep.kt @@ -4,6 +4,7 @@ import com.aliucord.manager.R import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step +import com.aliucord.manager.installer.steps.download.CopyDependenciesStep import com.aliucord.manager.installer.util.ManifestPatcher import com.aliucord.manager.ui.screens.installopts.InstallOptions import com.github.diamondminer88.zip.ZipReader diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/ReplaceIconStep.kt b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/ReplaceIconStep.kt index e20f9fd8..1b961a87 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/ReplaceIconStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/steps/patch/ReplaceIconStep.kt @@ -8,6 +8,7 @@ import com.aliucord.manager.installer.steps.StepGroup import com.aliucord.manager.installer.steps.StepRunner import com.aliucord.manager.installer.steps.base.Step import com.aliucord.manager.installer.steps.base.StepState +import com.aliucord.manager.installer.steps.download.CopyDependenciesStep import com.aliucord.manager.installer.util.ArscUtil import com.aliucord.manager.installer.util.ArscUtil.addColorResource import com.aliucord.manager.installer.util.ArscUtil.addResource diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/util/ManifestPatcher.kt b/app/src/main/kotlin/com/aliucord/manager/installer/util/ManifestPatcher.kt index dc0cd493..5b5cf6a0 100644 --- a/app/src/main/kotlin/com/aliucord/manager/installer/util/ManifestPatcher.kt +++ b/app/src/main/kotlin/com/aliucord/manager/installer/util/ManifestPatcher.kt @@ -93,7 +93,7 @@ object ManifestPatcher { override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) { if (name == NETWORK_SECURITY_CONFIG) return super.attr(ns, name, resourceId, type, value) - if (name == REQUEST_LEGACY_EXTERNAL_STORAGE) addLegacyStorage = false; + if (name == REQUEST_LEGACY_EXTERNAL_STORAGE) addLegacyStorage = false if (name == DEBUGGABLE) addDebuggable = false if (name == USES_CLEARTEXT_TRAFFIC) addUseClearTextTraffic = false } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index 2cc484c7..00190ce8 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -4,6 +4,7 @@ package com.aliucord.manager.ui.screens.install import android.annotation.SuppressLint import android.app.Application +import android.content.Intent import android.os.Build import android.util.Log import androidx.compose.runtime.* @@ -52,14 +53,9 @@ class InstallModel( if (state.value !is InstallScreenState.Success) return - val launchIntent = application.packageManager - .getLaunchIntentForPackage(options.packageName) - - if (launchIntent != null) { - application.startActivity(launchIntent) - } else { - application.showToast(R.string.launch_aliucord_fail) - } + Intent(options.packageName) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .also(application::startActivity) } fun copyDebugToClipboard() { diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt new file mode 100644 index 00000000..886f399b --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt @@ -0,0 +1,43 @@ +package com.aliucord.manager.ui.screens.install.components + +import androidx.compose.foundation.layout.* +import androidx.compose.material3.FilledTonalButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.aliucord.manager.R +import com.aliucord.manager.ui.screens.install.InstallScreenState + +@Composable +fun InstalledButtonRow( + state: InstallScreenState, + onRetry: () -> Unit, + onLaunch: () -> Unit, + onClearCache: () -> Unit, + onSaveLog: () -> Unit, + onShareLog: () -> Unit, + modifier: Modifier = Modifier, +) { + Column( + verticalArrangement = Arrangement.spacedBy(14.dp), + modifier = modifier, + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End), + modifier = Modifier.fillMaxWidth(), + ) { + FilledTonalButton(onClick = onClearCache) { + Text(stringResource(R.string.setting_clear_cache)) + } + + Spacer(Modifier.weight(1f, true)) + + // OutlinedButton(onClick = onSaveLog) { + // Text(stringResource(R.string.installer_save_file)) + // } + } + } +} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt index 5e108380..f688a714 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt @@ -1,15 +1,7 @@ package com.aliucord.manager.ui.screens.install.components -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.size -import androidx.compose.material3.FilledTonalIconButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButtonDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4ecf014e..3b1b9fe8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -78,7 +78,6 @@ Unknown Failed to retrieve version - Save to file Saved to %s Failed to save %s Successfully installed Aliucord From c50e7a0b3c276ce26092e5cb660b96aa33b87f3d Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Sun, 19 May 2024 13:40:34 -0700 Subject: [PATCH 09/10] more fun facts & success banner --- .../ui/screens/install/InstallModel.kt | 20 +++++- .../ui/screens/install/InstallScreen.kt | 68 ++++++++++++++++--- .../install/components/InstalledButtonRow.kt | 43 ------------ app/src/main/res/values/strings.xml | 7 ++ 4 files changed, 83 insertions(+), 55 deletions(-) delete mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index 00190ce8..89828e36 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -7,6 +7,7 @@ import android.app.Application import android.content.Intent import android.os.Build import android.util.Log +import androidx.annotation.StringRes import androidx.compose.runtime.* import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope @@ -26,6 +27,7 @@ import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import java.text.SimpleDateFormat import java.util.Date +import kotlin.time.Duration.Companion.seconds class InstallModel( private val application: Application, @@ -42,11 +44,19 @@ class InstallModel( var showGppWarning by mutableStateOf(false) private set + @get:StringRes var funFact by mutableIntStateOf(0) private set init { restart() + + screenModelScope.launch { + while (true) { + funFact = FUN_FACTS.random() + delay(20.seconds) + } + } } fun launchApp() { @@ -79,7 +89,7 @@ class InstallModel( } fun clearCache() { - paths.clearCache() + screenModelScope.launch { paths.clearCache() } application.showToast(R.string.action_cleared_cache) } @@ -102,7 +112,6 @@ class InstallModel( installSteps = null startTime = Date() - funFact = FUN_FACTS.random() mutableState.value = InstallScreenState.Working val newInstallJob = screenModelScope.launch { @@ -198,6 +207,13 @@ class InstallModel( R.string.fun_fact_2, R.string.fun_fact_3, R.string.fun_fact_4, + R.string.fun_fact_5, + R.string.fun_fact_6, + R.string.fun_fact_7, + R.string.fun_fact_8, + R.string.fun_fact_9, + R.string.fun_fact_10, + R.string.fun_fact_11, ) } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index 74c76cf2..192c8a3f 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -8,6 +8,7 @@ package com.aliucord.manager.ui.screens.install import android.os.Parcelable import androidx.activity.compose.BackHandler import androidx.compose.animation.* +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState @@ -15,6 +16,7 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource @@ -37,6 +39,7 @@ import com.aliucord.manager.ui.screens.install.components.* import com.aliucord.manager.ui.screens.installopts.InstallOptions import com.aliucord.manager.ui.util.paddings.* import com.aliucord.manager.ui.util.spacedByLastAtBottom +import com.aliucord.manager.ui.util.thenIf import com.aliucord.manager.util.isIgnoringBatteryOptimizations import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.filter @@ -174,6 +177,21 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { } } + item(key = "INSTALLED_BANNER") { + BannerSection(visible = state is InstallScreenState.Success) { + TextBanner( + text = "Successfully installed Aliucord! Do *NOT* uninstall the manager (this app) as it is required to perform certain types of updates.", + icon = painterResource(R.drawable.ic_check_circle), + iconColor = Color(0xFF59B463), + outlineColor = MaterialTheme.colorScheme.surfaceVariant, + containerColor = MaterialTheme.colorScheme.surfaceContainerHigh, + modifier = Modifier + .padding(bottom = VERTICAL_PADDING) + .fillMaxWidth(), + ) + } + } + for ((group, steps) in model.installSteps?.entries ?: persistentListOf()) { item(key = System.identityHashCode(group)) { StepGroupCard( @@ -184,11 +202,13 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { modifier = Modifier .padding(bottom = VERTICAL_PADDING) .fillMaxWidth() + .thenIf(state is InstallScreenState.Success) { alpha(.6f) } ) } } item(key = "BUTTONS") { + var cacheCleared by remember { mutableStateOf(false) } val filteredState by remember { model.state.filter { it.isNewlyFinished } } .collectAsState(initial = null) @@ -224,21 +244,49 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { else -> error("unreachable") } + + Row( + horizontalArrangement = Arrangement.End, + modifier = Modifier + .padding(top = 8.dp) + .fillMaxWidth() + ) { + // Clear cache button + Button( + // TODO: adjust colors + onClick = { + cacheCleared = true + // model.clearCache() + }, + enabled = !cacheCleared, + ) { + Text(stringResource(R.string.setting_clear_cache)) + } + } } } } item(key = "FUN_FACT") { - Text( - text = stringResource(R.string.fun_fact_prefix, stringResource(model.funFact)), - style = MaterialTheme.typography.bodySmall, - textAlign = TextAlign.Center, - modifier = Modifier - .padding(horizontal = VERTICAL_PADDING) - .padding(bottom = 25.dp) - .fillMaxWidth() - .alpha(.6f) - ) + AnimatedContent( + targetState = model.funFact, + label = "fun fact transition", + transitionSpec = { + (fadeIn(tween(220, delayMillis = 90)) + slideInHorizontally { it * -2 }) togetherWith + (fadeOut(tween(90)) + slideOutHorizontally { it * 2 }) + } + ) { text -> + Text( + text = stringResource(R.string.fun_fact_prefix, stringResource(text)), + style = MaterialTheme.typography.bodySmall, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(horizontal = VERTICAL_PADDING) + .padding(bottom = 25.dp) + .fillMaxWidth() + .alpha(.6f) + ) + } } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt deleted file mode 100644 index 886f399b..00000000 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/InstalledButtonRow.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.aliucord.manager.ui.screens.install.components - -import androidx.compose.foundation.layout.* -import androidx.compose.material3.FilledTonalButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import com.aliucord.manager.R -import com.aliucord.manager.ui.screens.install.InstallScreenState - -@Composable -fun InstalledButtonRow( - state: InstallScreenState, - onRetry: () -> Unit, - onLaunch: () -> Unit, - onClearCache: () -> Unit, - onSaveLog: () -> Unit, - onShareLog: () -> Unit, - modifier: Modifier = Modifier, -) { - Column( - verticalArrangement = Arrangement.spacedBy(14.dp), - modifier = modifier, - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End), - modifier = Modifier.fillMaxWidth(), - ) { - FilledTonalButton(onClick = onClearCache) { - Text(stringResource(R.string.setting_clear_cache)) - } - - Spacer(Modifier.weight(1f, true)) - - // OutlinedButton(onClick = onSaveLog) { - // Text(stringResource(R.string.installer_save_file)) - // } - } - } -} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b1b9fe8..8c4f99e3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -164,4 +164,11 @@ Did you know Aliucord with 150+ plugins somehow runs better than Discord\'s new app? Did you know Aliucord has over 200 available plugins? i am in your walls + Did you know AliucordRN spawned Enmity and Vendetta? + Having issues? Visit the #support channel in our Discord! + The IWillCrashYourDiscord plugin crashes your discord. + \"@Vendicated my bad.\" + Aliucord can run on WearOS + Aliucord uses the *real* old UI, from mid-2022! + There was an attempt to make Aliucord run on iOS… From 02b28bb36d08c3020513f5a7f8f37702cb3a44bb Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Sun, 19 May 2024 14:17:25 -0700 Subject: [PATCH 10/10] adjust clear cache button --- .../ui/screens/install/InstallModel.kt | 1 + .../ui/screens/install/InstallScreen.kt | 32 ++++++++----------- .../install/components/MainActionButton.kt | 20 +++++++----- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt index 89828e36..43e539d2 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallModel.kt @@ -51,6 +51,7 @@ class InstallModel( init { restart() + // Rotate fun facts every 20s screenModelScope.launch { while (true) { funFact = FUN_FACTS.random() diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt index 192c8a3f..e67807bf 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/InstallScreen.kt @@ -245,24 +245,21 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { else -> error("unreachable") } - Row( - horizontalArrangement = Arrangement.End, + MainActionButton( + text = stringResource(R.string.setting_clear_cache), + icon = painterResource(R.drawable.ic_delete_forever), + enabled = !cacheCleared, + colors = IconButtonDefaults.filledTonalIconButtonColors( + containerColor = MaterialTheme.colorScheme.error, + ), + onClick = { + cacheCleared = true + model.clearCache() + }, modifier = Modifier - .padding(top = 8.dp) + .padding(top = 14.dp) .fillMaxWidth() - ) { - // Clear cache button - Button( - // TODO: adjust colors - onClick = { - cacheCleared = true - // model.clearCache() - }, - enabled = !cacheCleared, - ) { - Text(stringResource(R.string.setting_clear_cache)) - } - } + ) } } } @@ -281,8 +278,7 @@ class InstallScreen(private val data: InstallOptions) : Screen, Parcelable { style = MaterialTheme.typography.bodySmall, textAlign = TextAlign.Center, modifier = Modifier - .padding(horizontal = VERTICAL_PADDING) - .padding(bottom = 25.dp) + .padding(top = VERTICAL_PADDING, bottom = 25.dp, start = VERTICAL_PADDING, end = VERTICAL_PADDING) .fillMaxWidth() .alpha(.6f) ) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt index f688a714..e37e42e8 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/install/components/MainActionButton.kt @@ -14,14 +14,17 @@ fun MainActionButton( text: String, icon: Painter, onClick: () -> Unit, + enabled: Boolean = true, + colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), modifier: Modifier = Modifier, ) { FilledTonalIconButton( shape = MaterialTheme.shapes.medium, - colors = IconButtonDefaults.filledTonalIconButtonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), + colors = colors, onClick = onClick, + enabled = enabled, modifier = modifier .fillMaxWidth() .height(46.dp), @@ -30,16 +33,17 @@ fun MainActionButton( horizontalArrangement = Arrangement.spacedBy(6.dp), verticalAlignment = Alignment.CenterVertically, ) { - Text( - text = text, - style = MaterialTheme.typography.labelLarge, - textAlign = TextAlign.Center, - ) Icon( painter = icon, contentDescription = null, modifier = Modifier.size(20.dp), ) + + Text( + text = text, + style = MaterialTheme.typography.labelLarge, + textAlign = TextAlign.Center, + ) } } }