Skip to content

Commit 9cf2bd6

Browse files
committed
feat: Add UI nudges to note about pitfalls
1 parent cd24d59 commit 9cf2bd6

File tree

6 files changed

+150
-12
lines changed

6 files changed

+150
-12
lines changed

app/src/main/java/app/revanced/manager/ui/component/settings/SettingsListItem.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
2424
import androidx.compose.runtime.setValue
2525
import androidx.compose.ui.Alignment
2626
import androidx.compose.ui.Modifier
27+
import androidx.compose.ui.graphics.Color
2728
import androidx.compose.ui.semantics.semantics
2829
import androidx.compose.ui.semantics.stateDescription
2930
import androidx.compose.ui.unit.dp
@@ -40,6 +41,7 @@ fun SettingsListItem(
4041
onLongClickLabel: String? = null,
4142
overlineContent: @Composable (() -> Unit)? = null,
4243
supportingContent: String? = null,
44+
supportingContentColor: Color = Color.Unspecified,
4345
leadingContent: @Composable (() -> Unit)? = null,
4446
trailingContent: @Composable (() -> Unit)? = null,
4547
) {
@@ -64,7 +66,14 @@ fun SettingsListItem(
6466
}
6567
}
6668
},
67-
supportingContent = supportingContent?.let { { Text(it) } },
69+
supportingContent = supportingContent?.let {
70+
{
71+
Text(
72+
text = it,
73+
color = supportingContentColor
74+
)
75+
}
76+
},
6877
verticalAlignment = Alignment.CenterVertically,
6978
) {
7079
Text(headlineContent)
@@ -81,6 +90,7 @@ fun SettingsListItem(
8190
onLongClickLabel: String? = null,
8291
overlineContent: @Composable (() -> Unit)? = null,
8392
supportingContent: String? = null,
93+
supportingContentColor: Color = Color.Unspecified,
8494
leadingContent: @Composable (() -> Unit)? = null,
8595
trailingContent: @Composable (() -> Unit)? = null,
8696
) {
@@ -99,7 +109,14 @@ fun SettingsListItem(
99109
overlineContent = overlineContent,
100110
leadingContent = leadingContent,
101111
trailingContent = trailingContent,
102-
supportingContent = supportingContent?.let { { Text(it) } },
112+
supportingContent = supportingContent?.let {
113+
{
114+
Text(
115+
text = it,
116+
color = supportingContentColor
117+
)
118+
}
119+
},
103120
content = headlineContent
104121
)
105122
}

app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,23 @@ fun DashboardScreen(
138138
val showNewDownloaderNotification by vm.newDownloadersAvailable.collectAsStateWithLifecycle(false)
139139
val managerAutoUpdates by vm.prefs.managerAutoUpdates.getAsState()
140140
val showManagerUpdateDialogOnLaunch by vm.prefs.showManagerUpdateDialogOnLaunch.getAsState()
141+
val disablePatchVersionCompatCheck by vm.prefs.disablePatchVersionCompatCheck.getAsState()
142+
val disableSelectionWarning by vm.prefs.disableSelectionWarning.getAsState()
143+
val disableUniversalPatchCheck by vm.prefs.disableUniversalPatchCheck.getAsState()
144+
val suggestedVersionSafeguard by vm.prefs.suggestedVersionSafeguard.getAsState()
145+
val safeguardsToggled by remember(
146+
disablePatchVersionCompatCheck,
147+
disableSelectionWarning,
148+
disableUniversalPatchCheck,
149+
suggestedVersionSafeguard
150+
) {
151+
derivedStateOf {
152+
disablePatchVersionCompatCheck ||
153+
disableSelectionWarning ||
154+
disableUniversalPatchCheck ||
155+
!suggestedVersionSafeguard
156+
}
157+
}
141158
val availableUpdate by vm.availableManagerUpdate.collectAsStateWithLifecycle()
142159
val androidContext = LocalContext.current
143160
val resources = LocalResources.current
@@ -442,7 +459,18 @@ fun DashboardScreen(
442459
onClick = onSettingsClick,
443460
shapes = IconButtonDefaults.shapes()
444461
) {
445-
Icon(Icons.Filled.Settings, stringResource(R.string.settings))
462+
BadgedBox(
463+
badge = {
464+
if (safeguardsToggled) {
465+
Badge(
466+
modifier = Modifier.size(6.dp),
467+
containerColor = MaterialTheme.colorScheme.error
468+
)
469+
}
470+
}
471+
) {
472+
Icon(Icons.Filled.Settings, stringResource(R.string.settings))
473+
}
446474
}
447475
},
448476
colors = TopAppBarDefaults.topAppBarColors(

app/src/main/java/app/revanced/manager/ui/screen/SelectedAppInfoScreen.kt

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ import androidx.compose.runtime.rememberCoroutineScope
3535
import androidx.compose.runtime.mutableStateOf
3636
import androidx.compose.runtime.setValue
3737
import androidx.compose.ui.Modifier
38+
import androidx.compose.ui.graphics.Color
3839
import androidx.compose.ui.input.nestedscroll.nestedScroll
39-
import androidx.compose.ui.platform.LocalContext
4040
import androidx.compose.ui.platform.LocalResources
4141
import androidx.compose.ui.res.stringResource
4242
import androidx.compose.ui.unit.dp
@@ -60,7 +60,6 @@ import app.revanced.manager.util.Options
6060
import app.revanced.manager.util.PatchSelection
6161
import app.revanced.manager.util.APK_MIMETYPE
6262
import app.revanced.manager.util.enabled
63-
import app.revanced.manager.util.toast
6463
import app.revanced.manager.util.transparentListItemColors
6564
import kotlinx.coroutines.launch
6665
import org.koin.compose.koinInject
@@ -74,7 +73,6 @@ fun SelectedAppInfoScreen(
7473
onBackClick: () -> Unit,
7574
vm: SelectedAppInfoViewModel
7675
) {
77-
val context = LocalContext.current
7876
val resources = LocalResources.current
7977
val networkInfo = koinInject<NetworkInfo>()
8078
val networkConnected = remember { networkInfo.isConnected() }
@@ -102,13 +100,40 @@ fun SelectedAppInfoScreen(
102100
)
103101
}
104102
}
103+
val strictVersionOptions by remember(bundles, patches, packageName) {
104+
derivedStateOf {
105+
buildVersionOptions(
106+
bundles = bundles,
107+
selectedPatches = patches,
108+
packageName = packageName,
109+
allowIncompatible = false
110+
)
111+
}
112+
}
105113
val selectedVersionLabel by remember(vm.selectedApp.version) {
106114
derivedStateOf {
107115
vm.selectedApp.version ?: resources.getString(R.string.selected_app_meta_any_version)
108116
}
109117
}
110118
var showVersionSelector by remember { mutableStateOf(false) }
111119
val selectedPatchCount = patches.values.sumOf { it.size }
120+
val hasModifiedPatchSelection by remember(bundles, effectiveAllowIncompatible) {
121+
derivedStateOf {
122+
vm.hasModifiedPatchSelection(bundles, effectiveAllowIncompatible)
123+
}
124+
}
125+
val showVersionCompatibilityWarning by remember(
126+
vm.selectedApp.version,
127+
allowIncompatiblePatches,
128+
strictVersionOptions
129+
) {
130+
derivedStateOf {
131+
val selectedVersion = vm.selectedApp.version ?: return@derivedStateOf false
132+
allowIncompatiblePatches &&
133+
strictVersionOptions.versions.isNotEmpty() &&
134+
selectedVersion !in strictVersionOptions.versions
135+
}
136+
}
112137

113138
LaunchedEffect(versionOptions, vm.selectedApp.version) {
114139
if (versionOptions.unrestricted) return@LaunchedEffect
@@ -258,6 +283,11 @@ fun SelectedAppInfoScreen(
258283
R.string.patch_selector_item_description,
259284
selectedPatchCount
260285
),
286+
warningDescription = if (hasModifiedPatchSelection) {
287+
stringResource(R.string.patch_selection_changed_warning)
288+
} else {
289+
null
290+
},
261291
onClick = {
262292
onPatchSelectorClick(
263293
vm.selectedApp,
@@ -272,6 +302,11 @@ fun SelectedAppInfoScreen(
272302
PageItem(
273303
R.string.version,
274304
selectedVersionLabel,
305+
warningDescription = if (showVersionCompatibilityWarning) {
306+
stringResource(R.string.version_compatibility_warning)
307+
} else {
308+
null
309+
},
275310
enabled = versionOptions.unrestricted || versionOptions.versions.isNotEmpty(),
276311
onClick = { showVersionSelector = true }
277312
)
@@ -355,6 +390,8 @@ private fun PageItem(
355390
@StringRes title: Int,
356391
description: String,
357392
enabled: Boolean = true,
393+
warningDescription: String? = null,
394+
warningColor: Color = Color.Unspecified,
358395
onClick: () -> Unit
359396
) {
360397
ListItem(
@@ -370,11 +407,25 @@ private fun PageItem(
370407
)
371408
},
372409
supportingContent = {
373-
Text(
374-
description,
375-
color = MaterialTheme.colorScheme.outline,
376-
style = MaterialTheme.typography.bodyMedium
377-
)
410+
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
411+
Text(
412+
description,
413+
color = MaterialTheme.colorScheme.outline,
414+
style = MaterialTheme.typography.bodyMedium
415+
)
416+
417+
warningDescription?.let {
418+
Text(
419+
text = "(!) $it",
420+
color = if (warningColor == Color.Unspecified) {
421+
MaterialTheme.colorScheme.tertiary
422+
} else {
423+
warningColor
424+
},
425+
style = MaterialTheme.typography.bodySmall
426+
)
427+
}
428+
}
378429
},
379430
trailingContent = {
380431
Icon(Icons.AutoMirrored.Outlined.ArrowRight, null)

app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ import androidx.compose.material3.TopAppBarDefaults
3131
import androidx.compose.runtime.Composable
3232
import androidx.compose.runtime.getValue
3333
import androidx.compose.runtime.remember
34+
import androidx.compose.runtime.derivedStateOf
3435
import androidx.compose.ui.Modifier
3536
import androidx.compose.ui.draw.clip
37+
import androidx.compose.ui.graphics.Color
3638
import androidx.compose.ui.graphics.vector.ImageVector
3739
import androidx.compose.ui.input.nestedscroll.nestedScroll
3840
import androidx.compose.ui.platform.LocalContext
@@ -62,6 +64,23 @@ private data class Section(
6264
fun SettingsScreen(onBackClick: () -> Unit, navigate: (Settings.Destination) -> Unit) {
6365
val prefs: PreferencesManager = koinInject()
6466
val showDeveloperSettings by prefs.showDeveloperSettings.getAsState()
67+
val disablePatchVersionCompatCheck by prefs.disablePatchVersionCompatCheck.getAsState()
68+
val disableSelectionWarning by prefs.disableSelectionWarning.getAsState()
69+
val disableUniversalPatchCheck by prefs.disableUniversalPatchCheck.getAsState()
70+
val suggestedVersionSafeguard by prefs.suggestedVersionSafeguard.getAsState()
71+
val safeguardsToggled by remember(
72+
disablePatchVersionCompatCheck,
73+
disableSelectionWarning,
74+
disableUniversalPatchCheck,
75+
suggestedVersionSafeguard
76+
) {
77+
derivedStateOf {
78+
disablePatchVersionCompatCheck ||
79+
disableSelectionWarning ||
80+
disableUniversalPatchCheck ||
81+
!suggestedVersionSafeguard
82+
}
83+
}
6584
val scrollState = rememberScrollState()
6685
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
6786
canScroll = {
@@ -183,9 +202,20 @@ fun SettingsScreen(onBackClick: () -> Unit, navigate: (Settings.Destination) ->
183202

184203
ListSection {
185204
advancedSections.forEach { (name, description, icon, destination) ->
205+
val hasSafeguardWarning = destination == Settings.Advanced && safeguardsToggled
206+
val supportingText = if (hasSafeguardWarning) {
207+
"Safeguards have been toggled"
208+
} else {
209+
stringResource(description)
210+
}
186211
SettingsListItem(
187212
headlineContent = stringResource(name),
188-
supportingContent = stringResource(description),
213+
supportingContent = supportingText,
214+
supportingContentColor = if (hasSafeguardWarning) {
215+
MaterialTheme.colorScheme.error
216+
} else {
217+
Color.Unspecified
218+
},
189219
leadingContent = { ExpressiveListIcon(icon = icon) },
190220
onClick = { navigate(destination) }
191221
)

app/src/main/java/app/revanced/manager/ui/viewmodel/SelectedAppInfoViewModel.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,15 @@ class SelectedAppInfoViewModel(
403403
fun getPatches(bundles: List<PatchBundleInfo.Scoped>, allowIncompatible: Boolean) =
404404
selectionState.patches(bundles, allowIncompatible)
405405

406+
fun hasModifiedPatchSelection(
407+
bundles: List<PatchBundleInfo.Scoped>,
408+
allowIncompatible: Boolean
409+
): Boolean {
410+
val selected = getPatches(bundles, allowIncompatible)
411+
val defaults = bundles.toPatchSelection(allowIncompatible) { _, patch -> patch.include }
412+
return selected != defaults
413+
}
414+
406415
fun getCustomPatches(
407416
bundles: List<PatchBundleInfo.Scoped>,
408417
allowIncompatible: Boolean

app/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ Second \"item\" text"</string>
107107
<string name="patch_item_description">Start patching the application</string>
108108
<string name="patch_selector_item">Select patches</string>
109109
<string name="patch_selector_item_description">%d patches selected</string>
110+
<string name="patch_selection_changed_warning">Selection of patches has been changed</string>
110111
<string name="no_patches_selected">No patches selected</string>
111112

112113
<string name="network_unavailable_warning">Your device is not connected to the internet. Downloading will fail later.</string>
@@ -144,6 +145,7 @@ Second \"item\" text"</string>
144145
<string name="import_export_description">Keystore, patch options and selection</string>
145146
<string name="advanced">Advanced</string>
146147
<string name="advanced_description">API URL, memory limit, debugging</string>
148+
<string name="safeguards_toggled_warning">Safeguards have been toggled</string>
147149
<string name="about">About</string>
148150
<string name="about_app_name">About %1$s</string>
149151
<string name="opensource_licenses">Open source licenses</string>
@@ -490,6 +492,7 @@ It is only compatible with the following version(s): %2$s</string>
490492
<string name="repository">Repository</string>
491493
<string name="bundle_information_by_author">By %1$s</string>
492494
<string name="version">Version</string>
495+
<string name="version_compatibility_warning">Selected version may be incompatible with selected patches</string>
493496
<string name="submit_feedback">Submit issue or feedback</string>
494497
<string name="submit_feedback_description">Help us improve this application</string>
495498
<string name="developer_options">Developer options</string>

0 commit comments

Comments
 (0)