diff --git a/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt b/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt index 08b6a94d..548df41a 100644 --- a/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt +++ b/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt @@ -23,6 +23,7 @@ class PreferencesManager( val firstLaunch = booleanPreference("first_launch", true) val managerAutoUpdates = booleanPreference("manager_auto_updates", false) + val showManagerUpdateDialogOnLaunch = booleanPreference("show_manager_update_dialog_on_launch", true) val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false) val disableSelectionWarning = booleanPreference("disable_selection_warning", false) diff --git a/app/src/main/java/app/revanced/manager/ui/component/AvailableUpdateDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/AvailableUpdateDialog.kt new file mode 100644 index 00000000..7059ad0d --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/AvailableUpdateDialog.kt @@ -0,0 +1,81 @@ +package app.revanced.manager.ui.component + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Update +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import app.revanced.manager.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AvailableUpdateDialog( + onDismiss: () -> Unit, + onConfirm: () -> Unit, + setShowManagerUpdateDialogOnLaunch: (Boolean) -> Unit, + newVersion: String +) { + var dontShowAgain by rememberSaveable { mutableStateOf(false) } + val dismissDialog = { + setShowManagerUpdateDialogOnLaunch(!dontShowAgain) + onDismiss() + } + + AlertDialogExtended( + onDismissRequest = dismissDialog, + confirmButton = { + TextButton( + onClick = { + dismissDialog() + onConfirm() + } + ) { + Text(stringResource(R.string.show)) + } + }, + dismissButton = { + TextButton( + onClick = dismissDialog + ) { + Text(stringResource(R.string.dismiss)) + } + }, + icon = { + Icon(imageVector = Icons.Outlined.Update, contentDescription = null) + }, + title = { + Text(stringResource(R.string.update_available)) + }, + text = { + Column( + modifier = Modifier.padding(horizontal = 8.dp), + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + Text( + modifier = Modifier.padding(horizontal = 16.dp), + text = stringResource(R.string.update_available_dialog_description, newVersion) + ) + ListItem( + modifier = Modifier.clickable { dontShowAgain = !dontShowAgain }, + headlineContent = { + Text(stringResource(R.string.never_show_again)) + }, + leadingContent = { + CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) { + Checkbox(checked = dontShowAgain, onCheckedChange = { dontShowAgain = it }) + } + } + ) + } + }, + textHorizontalPadding = PaddingValues(0.dp) + ) +} diff --git a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt index 11681824..bf310fc7 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt @@ -6,43 +6,17 @@ import android.net.Uri import android.provider.Settings import androidx.activity.compose.BackHandler import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.BatteryAlert import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.outlined.Apps -import androidx.compose.material.icons.outlined.DeleteOutline -import androidx.compose.material.icons.outlined.Refresh -import androidx.compose.material.icons.outlined.Settings -import androidx.compose.material.icons.outlined.Source -import androidx.compose.material.icons.outlined.Update -import androidx.compose.material.icons.outlined.WarningAmber -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Tab -import androidx.compose.material3.TabRow -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.surfaceColorAtElevation -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.material.icons.outlined.* +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext @@ -55,6 +29,7 @@ import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.isDefaul import app.revanced.manager.patcher.aapt.Aapt import app.revanced.manager.ui.component.AppTopBar import app.revanced.manager.ui.component.AutoUpdatesDialog +import app.revanced.manager.ui.component.AvailableUpdateDialog import app.revanced.manager.ui.component.NotificationCard import app.revanced.manager.ui.component.bundle.BundleItem import app.revanced.manager.ui.component.bundle.BundleTopBar @@ -113,6 +88,20 @@ fun DashboardScreen( ) } + var showDialog by rememberSaveable { mutableStateOf(vm.prefs.showManagerUpdateDialogOnLaunch.getBlocking()) } + val availableUpdate by remember { + derivedStateOf { vm.updatedManagerVersion.takeIf { showDialog } } + } + + availableUpdate?.let { version -> + AvailableUpdateDialog( + onDismiss = { showDialog = false }, + setShowManagerUpdateDialogOnLaunch = vm::setShowManagerUpdateDialogOnLaunch, + onConfirm = onUpdateClick, + newVersion = version + ) + } + Scaffold( topBar = { if (bundlesSelectable) { @@ -154,6 +143,23 @@ fun DashboardScreen( AppTopBar( title = stringResource(R.string.app_name), actions = { + if (!vm.updatedManagerVersion.isNullOrEmpty()) { + IconButton( + onClick = onUpdateClick, + ) { + BadgedBox( + badge = { + Badge( + // A size value above 6.dp forces the Badge icon to be closer to the center, fixing a clipping issue + modifier = Modifier.size(7.dp), + containerColor = MaterialTheme.colorScheme.primary, + ) + } + ) { + Icon(Icons.Outlined.Update, stringResource(R.string.update)) + } + } + } IconButton(onClick = onSettingsClick) { Icon(Icons.Outlined.Settings, stringResource(R.string.settings)) } @@ -230,23 +236,7 @@ fun DashboardScreen( } ) } - } else null, - vm.updatedManagerVersion?.let { - { - NotificationCard( - text = stringResource(R.string.update_available_dialog_description, it), - icon = Icons.Outlined.Update, - actions = { - TextButton(onClick = vm::dismissUpdateDialog) { - Text(stringResource(R.string.dismiss)) - } - TextButton(onClick = onUpdateClick) { - Text(stringResource(R.string.show)) - } - } - ) - } - } + } else null ) HorizontalPager( diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdatesSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdatesSettingsScreen.kt index 96aa2cd2..3772f3f4 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdatesSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdatesSettingsScreen.kt @@ -64,6 +64,12 @@ fun UpdatesSettingsScreen( headline = R.string.update_checking_manager, description = R.string.update_checking_manager_description ) + + BooleanItem( + preference = vm.showManagerUpdateDialogOnLaunch, + headline = R.string.show_manager_update_dialog_on_launch, + description = R.string.update_checking_manager_description + ) } } } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt index 9d2e1224..ce68249d 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt @@ -64,6 +64,12 @@ class DashboardViewModel( } } + fun setShowManagerUpdateDialogOnLaunch(value: Boolean) { + viewModelScope.launch { + prefs.showManagerUpdateDialogOnLaunch.update(value) + } + } + fun applyAutoUpdatePrefs(manager: Boolean, patches: Boolean) = viewModelScope.launch { prefs.firstLaunch.update(false) diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdatesSettingsViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdatesSettingsViewModel.kt index cd96e091..385aeddf 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdatesSettingsViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdatesSettingsViewModel.kt @@ -14,6 +14,7 @@ class UpdatesSettingsViewModel( private val reVancedAPI: ReVancedAPI, ) : ViewModel() { val managerAutoUpdates = prefs.managerAutoUpdates + val showManagerUpdateDialogOnLaunch = prefs.showManagerUpdateDialogOnLaunch suspend fun checkForUpdates(): Boolean { uiSafe(app, R.string.failed_to_check_updates, "Failed to check for updates") { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 277f6a50..7f520eeb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -367,4 +367,8 @@ Add patch bundle Bundle URL Auto update + Never show again + Show update message on launch + Shows a popup notification whenever there is a new update available on launch. +