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.
+