From eba0fbf29cb71c55b15048fa0f36ae5a753344f5 Mon Sep 17 00:00:00 2001 From: wingio Date: Fri, 24 Mar 2023 11:59:58 -0400 Subject: [PATCH] Feat: dev settings --- .../domain/manager/PreferenceManager.kt | 2 +- .../components/settings/SettingsTextField.kt | 4 +- .../manager/ui/screen/about/AboutScreen.kt | 35 +++++++++---- .../manager/ui/screen/home/HomeScreen.kt | 19 ++++--- .../manager/ui/screen/main/MainScreen.kt | 21 +++++--- .../ui/screen/settings/SettingsScreen.kt | 52 +++++++++++++++++++ .../ui/viewmodel/main/MainViewModel.kt | 2 +- .../manager/ui/widgets/about/ListItem.kt | 1 - .../manager/ui/widgets/about/UserEntry.kt | 2 +- .../ui/widgets/updater/UpdateDialog.kt | 6 +-- .../vendetta/manager/utils/NavUtils.kt | 1 - .../vendetta/manager/utils/VersionUtils.kt | 6 ++- app/src/main/res/values/strings.xml | 11 ++++ 13 files changed, 126 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt b/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt index cc84d3f..740d080 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt @@ -24,7 +24,7 @@ class PreferenceManager(private val context: Context) : var monet by booleanPreference("monet", Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) - var isDeveloper by booleanPreference("is_developer", true) + var isDeveloper by booleanPreference("is_developer", false) var theme by enumPreference("theme", Theme.SYSTEM) diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/components/settings/SettingsTextField.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/components/settings/SettingsTextField.kt index 7beeefb..7df39c4 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/components/settings/SettingsTextField.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/components/settings/SettingsTextField.kt @@ -13,6 +13,7 @@ fun SettingsTextField( disabled: Boolean = false, pref: String, error: Boolean = false, + supportingText: String? = null, onPrefChange: (String) -> Unit, ) { Box(modifier = Modifier.padding(horizontal = 18.dp, vertical = 10.dp)) { @@ -23,7 +24,8 @@ fun SettingsTextField( enabled = !disabled, label = { Text(label) }, isError = error, - singleLine = true + singleLine = true, + supportingText = if (supportingText != null) { -> Text(supportingText) } else null ) } } \ No newline at end of file diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/about/AboutScreen.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/about/AboutScreen.kt index ef03eb0..88b3741 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/about/AboutScreen.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/about/AboutScreen.kt @@ -1,9 +1,7 @@ package dev.beefers.vendetta.manager.ui.screen.about import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -16,7 +14,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.Divider import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api @@ -30,41 +27,48 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.input.nestedscroll.nestedScroll 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.unit.dp import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow -import coil.compose.AsyncImage import dev.beefers.vendetta.manager.BuildConfig import dev.beefers.vendetta.manager.R +import dev.beefers.vendetta.manager.domain.manager.PreferenceManager import dev.beefers.vendetta.manager.ui.widgets.about.LinkItem import dev.beefers.vendetta.manager.ui.widgets.about.ListItem import dev.beefers.vendetta.manager.ui.widgets.about.UserEntry import dev.beefers.vendetta.manager.utils.Constants import dev.beefers.vendetta.manager.utils.getBitmap +import dev.beefers.vendetta.manager.utils.showToast +import org.koin.androidx.compose.get -class AboutScreen: Screen { +class AboutScreen : Screen { @Composable @OptIn(ExperimentalMaterial3Api::class) override fun Content() { val uriHandler = LocalUriHandler.current + val prefs: PreferenceManager = get() val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val ctx = LocalContext.current val bitmap = remember { ctx.getBitmap(R.drawable.ic_launcher, 60).asImageBitmap() } + var tapCount by remember { + mutableStateOf(0) + } Scaffold( topBar = { TitleBar(scrollBehavior) }, @@ -100,7 +104,20 @@ class AboutScreen: Screen { text = "v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})", style = MaterialTheme.typography.labelLarge, color = LocalContentColor.current.copy(alpha = 0.5f), - modifier = Modifier.clickable { } + modifier = Modifier.clickable( + enabled = !prefs.isDeveloper + ) { + tapCount++ + when (tapCount) { + 3 -> ctx.showToast(R.string.msg_seven_left) + 5 -> ctx.showToast(R.string.msg_five_left) + 8 -> ctx.showToast(R.string.msg_two_left) + 10 -> { + ctx.showToast(R.string.msg_unlocked) + prefs.isDeveloper = true + } + } + } ) Row( @@ -153,7 +170,7 @@ class AboutScreen: Screen { uriHandler.openUri("https://github.com/${member.username}") } ) - if(i != Constants.TEAM_MEMBERS.lastIndex) { + if (i != Constants.TEAM_MEMBERS.lastIndex) { Divider( thickness = 0.5.dp, color = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f), diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt index 9f4267f..1c5f4a9 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt @@ -20,7 +20,6 @@ import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.OpenInNew import androidx.compose.material.icons.filled.Refresh -import androidx.compose.material.icons.filled.RestartAlt import androidx.compose.material.icons.outlined.Home import androidx.compose.material.icons.outlined.Info import androidx.compose.material3.Button @@ -54,7 +53,6 @@ import dev.beefers.vendetta.manager.ui.components.SegmentedButton import dev.beefers.vendetta.manager.ui.screen.about.AboutScreen import dev.beefers.vendetta.manager.ui.screen.installer.InstallerScreen import dev.beefers.vendetta.manager.ui.viewmodel.home.HomeViewModel -import dev.beefers.vendetta.manager.ui.viewmodel.main.MainViewModel import dev.beefers.vendetta.manager.ui.widgets.home.Commit import dev.beefers.vendetta.manager.utils.DiscordVersion import dev.beefers.vendetta.manager.utils.ManagerTab @@ -75,6 +73,10 @@ class HomeScreen : ManagerTab { val nav = LocalNavigator.currentOrThrow val prefs: PreferenceManager = get() val viewModel: HomeViewModel = getScreenModel() + val latestVersion = when { + prefs.discordVersion.isBlank() -> viewModel.discordVersions?.get(prefs.channel) + else -> DiscordVersion.fromVersionCode(prefs.discordVersion) + } val iconColor = when { prefs.patchIcon -> Color(0xFF3AB8BA) prefs.channel == DiscordVersion.Type.ALPHA -> Color(0xFFFBB33C) @@ -106,18 +108,18 @@ class HomeScreen : ManagerTab { horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth() ) { - AnimatedVisibility(visible = viewModel.discordVersions != null) { + AnimatedVisibility(visible = viewModel.installManager.current != null) { Text( - text = "Latest: ${viewModel.discordVersions?.get(prefs.channel)}", + text = "Current: ${viewModel.installManager.current?.versionName}", style = MaterialTheme.typography.labelLarge, color = LocalContentColor.current.copy(alpha = 0.5f), textAlign = TextAlign.Center ) } - AnimatedVisibility(visible = viewModel.installManager.current != null) { + AnimatedVisibility(visible = latestVersion != null) { Text( - text = "Current: ${viewModel.installManager.current?.versionName}", + text = "Latest: $latestVersion", style = MaterialTheme.typography.labelLarge, color = LocalContentColor.current.copy(alpha = 0.5f), textAlign = TextAlign.Center @@ -135,10 +137,7 @@ class HomeScreen : ManagerTab { ) { val label = when { viewModel.installManager.current == null -> R.string.action_install - viewModel.installManager.current?.versionName == viewModel.discordVersions?.get( - prefs.channel - ).toString() -> R.string.action_reinstall - + viewModel.installManager.current?.versionName == latestVersion.toString() -> R.string.action_reinstall else -> R.string.action_update } Text(stringResource(label)) diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/main/MainScreen.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/main/MainScreen.kt index 71d9d42..e5653b8 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/main/MainScreen.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/main/MainScreen.kt @@ -9,18 +9,21 @@ import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.koin.getScreenModel import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.rememberPagerState -import dev.beefers.vendetta.manager.BuildConfig +import dev.beefers.vendetta.manager.ui.screen.home.HomeScreen import dev.beefers.vendetta.manager.ui.viewmodel.main.MainViewModel import dev.beefers.vendetta.manager.ui.widgets.updater.UpdateDialog import dev.beefers.vendetta.manager.utils.MainTab @@ -31,6 +34,7 @@ class MainScreen : Screen { @OptIn(ExperimentalMaterial3Api::class, ExperimentalPagerApi::class) @Composable override fun Content() { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val viewModel: MainViewModel = getScreenModel() val pagerState = rememberPagerState() @@ -39,8 +43,10 @@ class MainScreen : Screen { ) { Scaffold( bottomBar = { NavBar() }, - topBar = { TitleBar() }, - modifier = Modifier.fillMaxSize() + topBar = { TitleBar(scrollBehavior) }, + modifier = Modifier + .fillMaxSize() + .nestedScroll(scrollBehavior.nestedScrollConnection) ) { pv -> if (viewModel.showUpdateDialog && viewModel.release != null) { UpdateDialog( @@ -71,18 +77,21 @@ class MainScreen : Screen { @OptIn(ExperimentalPagerApi::class, ExperimentalMaterial3Api::class) @Composable - private fun TitleBar() { + private fun TitleBar( + scrollBehavior: TopAppBarScrollBehavior + ) { val pagerState = LocalPagerState.current val tab = MainTab.values()[pagerState.currentPage].tab TopAppBar( title = { Text(tab.options.title) }, - actions = { tab.Actions() } + actions = { tab.Actions() }, + scrollBehavior = if (tab is HomeScreen) null else scrollBehavior ) } @Composable - @OptIn(ExperimentalPagerApi::class) + @OptIn(ExperimentalPagerApi::class, ExperimentalMaterial3Api::class) private fun NavBar() { val pagerState = LocalPagerState.current val scope = rememberCoroutineScope() diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt index 18a9f59..87f8fc9 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt @@ -11,6 +11,10 @@ import androidx.compose.material.icons.outlined.Settings import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -19,6 +23,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.tab.TabOptions import dev.beefers.vendetta.manager.R +import dev.beefers.vendetta.manager.domain.manager.InstallManager import dev.beefers.vendetta.manager.domain.manager.PreferenceManager import dev.beefers.vendetta.manager.ui.components.settings.SettingsButton import dev.beefers.vendetta.manager.ui.components.settings.SettingsHeader @@ -27,6 +32,7 @@ import dev.beefers.vendetta.manager.ui.components.settings.SettingsSwitch import dev.beefers.vendetta.manager.ui.components.settings.SettingsTextField import dev.beefers.vendetta.manager.ui.screen.about.AboutScreen import dev.beefers.vendetta.manager.ui.viewmodel.settings.SettingsViewModel +import dev.beefers.vendetta.manager.utils.DiscordVersion import dev.beefers.vendetta.manager.utils.ManagerTab import dev.beefers.vendetta.manager.utils.TabOptions import dev.beefers.vendetta.manager.utils.navigate @@ -44,6 +50,7 @@ class SettingsScreen : ManagerTab { override fun Content() { val viewModel: SettingsViewModel = getScreenModel() val prefs: PreferenceManager = get() + val installManager: InstallManager = get() val ctx = LocalContext.current Column( @@ -103,6 +110,51 @@ class SettingsScreen : ManagerTab { viewModel.clearCache() } ) + + if (prefs.isDeveloper) { + SettingsHeader(stringResource(R.string.settings_developer)) + SettingsTextField( + label = stringResource(R.string.settings_package_name), + pref = prefs.packageName, + onPrefChange = { + prefs.packageName = it + installManager.getInstalled() + } + ) + var version by remember { + mutableStateOf(prefs.discordVersion) + } + var versionError by remember { + mutableStateOf(false) + } + val supportingText = if (versionError) + stringResource(R.string.msg_invalid_version) + else if (version.isNotBlank()) + DiscordVersion.fromVersionCode(version).toString() + else + null + SettingsTextField( + label = stringResource(R.string.settings_version), + pref = version, + error = versionError, + supportingText = supportingText, + onPrefChange = { + version = it + if (DiscordVersion.fromVersionCode(it) == null && it.isNotBlank()) { + versionError = true + } else { + versionError = false + prefs.discordVersion = it + } + } + ) + SettingsSwitch( + label = stringResource(R.string.settings_debuggable), + secondaryLabel = stringResource(R.string.settings_debuggable_description), + pref = prefs.debuggable, + onPrefChange = { prefs.debuggable = it } + ) + } } } diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/viewmodel/main/MainViewModel.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/viewmodel/main/MainViewModel.kt index 5e39400..2d3923f 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/viewmodel/main/MainViewModel.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/viewmodel/main/MainViewModel.kt @@ -54,7 +54,7 @@ class MainViewModel( fun downloadAndInstallUpdate() { coroutineScope.launch { val update = File(cacheDir, "update.apk") - if(update.exists()) update.delete() + if (update.exists()) update.delete() isUpdating = true downloadManager.downloadUpdate(update) isUpdating = false diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/ListItem.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/ListItem.kt index e9b9b98..010d3cd 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/ListItem.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/ListItem.kt @@ -15,7 +15,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp import coil.compose.AsyncImage diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/UserEntry.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/UserEntry.kt index f2aa757..da3677b 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/UserEntry.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/about/UserEntry.kt @@ -44,7 +44,7 @@ fun UserEntry( ) { AsyncImage( modifier = Modifier - .size(if(isLarge) 70.dp else 50.dp) + .size(if (isLarge) 70.dp else 50.dp) .clip(CircleShape) .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)), model = "https://github.com/$username.png", diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/updater/UpdateDialog.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/updater/UpdateDialog.kt index b927a70..ac87c6f 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/updater/UpdateDialog.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/widgets/updater/UpdateDialog.kt @@ -1,8 +1,6 @@ package dev.beefers.vendetta.manager.ui.widgets.updater -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.SystemUpdate @@ -46,9 +44,9 @@ fun UpdateDialog( Box { Text( text = stringResource(R.string.action_start_update), - color = if(isUpdating) Color.Transparent else LocalContentColor.current + color = if (isUpdating) Color.Transparent else LocalContentColor.current ) - if(isUpdating) { + if (isUpdating) { CircularProgressIndicator( strokeWidth = 3.dp, modifier = Modifier diff --git a/app/src/main/java/dev/beefers/vendetta/manager/utils/NavUtils.kt b/app/src/main/java/dev/beefers/vendetta/manager/utils/NavUtils.kt index adf5699..bdc80af 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/utils/NavUtils.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/utils/NavUtils.kt @@ -13,7 +13,6 @@ import com.google.accompanist.pager.ExperimentalPagerApi import dev.beefers.vendetta.manager.ui.screen.home.HomeScreen import dev.beefers.vendetta.manager.ui.screen.main.LocalPagerState import dev.beefers.vendetta.manager.ui.screen.settings.SettingsScreen -import dev.beefers.vendetta.manager.ui.viewmodel.main.MainViewModel enum class MainTab(val tab: ManagerTab) { HOME(HomeScreen()), diff --git a/app/src/main/java/dev/beefers/vendetta/manager/utils/VersionUtils.kt b/app/src/main/java/dev/beefers/vendetta/manager/utils/VersionUtils.kt index 20e78b5..20b969c 100644 --- a/app/src/main/java/dev/beefers/vendetta/manager/utils/VersionUtils.kt +++ b/app/src/main/java/dev/beefers/vendetta/manager/utils/VersionUtils.kt @@ -8,7 +8,7 @@ data class DiscordVersion( val major: Int, val minor: Int, val type: Type -) : Serializable { +) : Serializable, Comparable { enum class Type(val label: String, @StringRes val labelRes: Int) { STABLE("Stable", R.string.channel_stable), @@ -16,6 +16,9 @@ data class DiscordVersion( ALPHA("Alpha", R.string.channel_alpha) } + override fun compareTo(other: DiscordVersion): Int = + toVersionCode().toInt() - other.toVersionCode().toInt() + override fun toString() = "$major.$minor - ${type.label}" fun toVersionCode() = "$major${type.ordinal}${if (minor < 10) 0 else ""}${minor}" @@ -25,6 +28,7 @@ data class DiscordVersion( fun fromVersionCode(string: String): DiscordVersion? = with(string) { if (length < 4) return@with null if (toIntOrNull() == null) return@with null + if (toInt() <= 126021) return@with null val codeReversed = toCharArray().reversed().joinToString("") val typeInt = codeReversed[2].toString().toInt() val type = Type.values().getOrNull(typeInt) ?: return@with null diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e14959..66e59f8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,6 +4,11 @@ Cache cleared successfully Failed to load commits Coming soon + Invalid Discord version + 7 more taps + 5 more taps + 2 more taps + You are now a developer Download APKs Patching @@ -71,6 +76,12 @@ Uses the Vendetta icon instead of Discord\'s Release channel + Developer only + Package name + Discord version + Debuggable + Enable debuggable flag + Vendetta Manager version %1$s is now available! Stable