Skip to content

Commit 5153e5e

Browse files
Axelen123oSumAtrIX
authored andcommitted
feat(Compose): hide developer settings (#2551)
1 parent a1f5dd3 commit 5153e5e

File tree

6 files changed

+142
-44
lines changed

6 files changed

+142
-44
lines changed

app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package app.revanced.manager.domain.manager
33
import android.content.Context
44
import app.revanced.manager.domain.manager.base.BasePreferencesManager
55
import app.revanced.manager.ui.theme.Theme
6+
import app.revanced.manager.util.isDebuggable
67

78
class PreferencesManager(
89
context: Context
@@ -28,4 +29,6 @@ class PreferencesManager(
2829
val suggestedVersionSafeguard = booleanPreference("suggested_version_safeguard", true)
2930

3031
val acknowledgedDownloaderPlugins = stringSetPreference("acknowledged_downloader_plugins", emptySet())
32+
33+
val showDeveloperSettings = booleanPreference("show_developer_settings", context.isDebuggable)
3134
}

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

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,86 @@
11
package app.revanced.manager.ui.screen
22

3+
import androidx.annotation.StringRes
34
import androidx.compose.foundation.clickable
45
import androidx.compose.foundation.layout.fillMaxSize
56
import androidx.compose.foundation.layout.padding
67
import androidx.compose.material.icons.Icons
78
import androidx.compose.material.icons.outlined.*
89
import androidx.compose.material3.*
910
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.getValue
12+
import androidx.compose.runtime.remember
1013
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.graphics.vector.ImageVector
1115
import androidx.compose.ui.res.stringResource
1216
import app.revanced.manager.R
17+
import app.revanced.manager.domain.manager.PreferencesManager
1318
import app.revanced.manager.ui.component.AppTopBar
1419
import app.revanced.manager.ui.component.ColumnWithScrollbar
1520
import app.revanced.manager.ui.component.settings.SettingsListItem
1621
import app.revanced.manager.ui.model.navigation.Settings
22+
import org.koin.compose.koinInject
1723

18-
private val settingsSections = listOf(
19-
Triple(
20-
R.string.general,
21-
R.string.general_description,
22-
Icons.Outlined.Settings
23-
) to Settings.General,
24-
Triple(
25-
R.string.updates,
26-
R.string.updates_description,
27-
Icons.Outlined.Update
28-
) to Settings.Updates,
29-
Triple(
30-
R.string.downloads,
31-
R.string.downloads_description,
32-
Icons.Outlined.Download
33-
) to Settings.Downloads,
34-
Triple(
35-
R.string.import_export,
36-
R.string.import_export_description,
37-
Icons.Outlined.SwapVert
38-
) to Settings.ImportExport,
39-
Triple(
40-
R.string.advanced,
41-
R.string.advanced_description,
42-
Icons.Outlined.Tune
43-
) to Settings.Advanced,
44-
Triple(
45-
R.string.developer_options,
46-
R.string.developer_options_description,
47-
Icons.Outlined.Code
48-
) to Settings.Developer,
49-
Triple(
50-
R.string.about,
51-
R.string.app_name,
52-
Icons.Outlined.Info
53-
) to Settings.About,
24+
private data class Section(
25+
@StringRes val name: Int,
26+
@StringRes val description: Int,
27+
val image: ImageVector,
28+
val destination: Settings.Destination,
5429
)
5530

5631
@OptIn(ExperimentalMaterial3Api::class)
5732
@Composable
5833
fun SettingsScreen(onBackClick: () -> Unit, navigate: (Settings.Destination) -> Unit) {
34+
val prefs: PreferencesManager = koinInject()
35+
val showDeveloperSettings by prefs.showDeveloperSettings.getAsState()
36+
37+
val settingsSections = remember(showDeveloperSettings) {
38+
listOfNotNull(
39+
Section(
40+
R.string.general,
41+
R.string.general_description,
42+
Icons.Outlined.Settings,
43+
Settings.General
44+
),
45+
Section(
46+
R.string.updates,
47+
R.string.updates_description,
48+
Icons.Outlined.Update,
49+
Settings.Updates
50+
),
51+
Section(
52+
R.string.downloads,
53+
R.string.downloads_description,
54+
Icons.Outlined.Download,
55+
Settings.Downloads
56+
),
57+
Section(
58+
R.string.import_export,
59+
R.string.import_export_description,
60+
Icons.Outlined.SwapVert,
61+
Settings.ImportExport
62+
),
63+
Section(
64+
R.string.advanced,
65+
R.string.advanced_description,
66+
Icons.Outlined.Tune,
67+
Settings.Advanced
68+
),
69+
Section(
70+
R.string.about,
71+
R.string.app_name,
72+
Icons.Outlined.Info,
73+
Settings.About
74+
),
75+
Section(
76+
R.string.developer_options,
77+
R.string.developer_options_description,
78+
Icons.Outlined.Code,
79+
Settings.Developer
80+
).takeIf { showDeveloperSettings }
81+
)
82+
}
83+
5984
Scaffold(
6085
topBar = {
6186
AppTopBar(
@@ -69,12 +94,12 @@ fun SettingsScreen(onBackClick: () -> Unit, navigate: (Settings.Destination) ->
6994
.padding(paddingValues)
7095
.fillMaxSize()
7196
) {
72-
settingsSections.forEach { (titleDescIcon, destination) ->
97+
settingsSections.forEach { (name, description, icon, destination) ->
7398
SettingsListItem(
7499
modifier = Modifier.clickable { navigate(destination) },
75-
headlineContent = stringResource(titleDescIcon.first),
76-
supportingContent = stringResource(titleDescIcon.second),
77-
leadingContent = { Icon(titleDescIcon.third, null) }
100+
headlineContent = stringResource(name),
101+
supportingContent = stringResource(description),
102+
leadingContent = { Icon(icon, null) }
78103
)
79104
}
80105
}

app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,26 @@ import androidx.compose.material3.IconButton
2323
import androidx.compose.material3.MaterialTheme
2424
import androidx.compose.material3.OutlinedCard
2525
import androidx.compose.material3.Scaffold
26+
import androidx.compose.material3.SnackbarDuration
27+
import androidx.compose.material3.SnackbarHost
28+
import androidx.compose.material3.SnackbarHostState
2629
import androidx.compose.material3.Text
2730
import androidx.compose.material3.TopAppBarDefaults
2831
import androidx.compose.material3.rememberTopAppBarState
2932
import androidx.compose.runtime.Composable
33+
import androidx.compose.runtime.LaunchedEffect
34+
import androidx.compose.runtime.getValue
35+
import androidx.compose.runtime.mutableIntStateOf
3036
import androidx.compose.runtime.remember
37+
import androidx.compose.runtime.saveable.rememberSaveable
38+
import androidx.compose.runtime.setValue
3139
import androidx.compose.ui.Alignment
3240
import androidx.compose.ui.Modifier
3341
import androidx.compose.ui.input.nestedscroll.nestedScroll
3442
import androidx.compose.ui.platform.LocalContext
3543
import androidx.compose.ui.res.stringResource
44+
import androidx.compose.ui.semantics.hideFromAccessibility
45+
import androidx.compose.ui.semantics.semantics
3646
import androidx.compose.ui.unit.dp
3747
import app.revanced.manager.BuildConfig
3848
import app.revanced.manager.R
@@ -42,6 +52,7 @@ import app.revanced.manager.ui.component.ColumnWithScrollbar
4252
import app.revanced.manager.ui.component.settings.SettingsListItem
4353
import app.revanced.manager.ui.model.navigation.Settings
4454
import app.revanced.manager.ui.viewmodel.AboutViewModel
55+
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.DEVELOPER_OPTIONS_TAPS
4556
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.getSocialIcon
4657
import app.revanced.manager.util.openUrl
4758
import app.revanced.manager.util.toast
@@ -109,7 +120,8 @@ fun AboutSettingsScreen(
109120
}
110121

111122
val listItems = listOfNotNull(
112-
Triple(stringResource(R.string.submit_feedback),
123+
Triple(
124+
stringResource(R.string.submit_feedback),
113125
stringResource(R.string.submit_feedback_description),
114126
third = {
115127
context.openUrl("https://github.com/ReVanced/revanced-manager/issues/new/choose")
@@ -134,6 +146,35 @@ fun AboutSettingsScreen(
134146
)
135147

136148
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
149+
val snackbarHostState = remember { SnackbarHostState() }
150+
151+
val showDeveloperSettings by viewModel.showDeveloperSettings.getAsState()
152+
var developerTaps by rememberSaveable { mutableIntStateOf(0) }
153+
LaunchedEffect(developerTaps) {
154+
if (developerTaps == 0) return@LaunchedEffect
155+
if (showDeveloperSettings) {
156+
snackbarHostState.showSnackbar(context.getString(R.string.developer_options_already_enabled))
157+
developerTaps = 0
158+
return@LaunchedEffect
159+
}
160+
161+
val remaining = DEVELOPER_OPTIONS_TAPS - developerTaps
162+
if (remaining > 0) {
163+
snackbarHostState.showSnackbar(
164+
context.getString(
165+
R.string.developer_options_taps,
166+
remaining
167+
),
168+
duration = SnackbarDuration.Long
169+
)
170+
} else if (remaining == 0) {
171+
viewModel.showDeveloperSettings.update(true)
172+
snackbarHostState.showSnackbar(context.getString(R.string.developer_options_enabled))
173+
}
174+
175+
// Reset the counter
176+
developerTaps = 0
177+
}
137178

138179
Scaffold(
139180
topBar = {
@@ -143,6 +184,9 @@ fun AboutSettingsScreen(
143184
onBackClick = onBackClick
144185
)
145186
},
187+
snackbarHost = {
188+
SnackbarHost(hostState = snackbarHostState)
189+
},
146190
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
147191
) { paddingValues ->
148192
ColumnWithScrollbar(
@@ -153,17 +197,23 @@ fun AboutSettingsScreen(
153197
verticalArrangement = Arrangement.spacedBy(16.dp)
154198
) {
155199
Image(
156-
modifier = Modifier.padding(top = 16.dp),
200+
modifier = Modifier
201+
.padding(top = 16.dp)
202+
.clickable { developerTaps += 1 },
157203
painter = icon,
158-
contentDescription = null
204+
contentDescription = stringResource(R.string.app_name)
159205
)
160206
Column(
161207
horizontalAlignment = Alignment.CenterHorizontally,
162208
verticalArrangement = Arrangement.spacedBy(4.dp)
163209
) {
164210
Text(
165211
stringResource(R.string.app_name),
166-
style = MaterialTheme.typography.headlineSmall
212+
style = MaterialTheme.typography.headlineSmall,
213+
modifier = Modifier.semantics {
214+
// Icon already has this information for the purpose of being clickable.
215+
hideFromAccessibility()
216+
}
167217
)
168218
Text(
169219
text = stringResource(R.string.version) + " " + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")",

app/src/main/java/app/revanced/manager/ui/screen/settings/DeveloperSettingsScreen.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ import androidx.compose.ui.Modifier
1212
import androidx.compose.ui.input.nestedscroll.nestedScroll
1313
import androidx.compose.ui.res.stringResource
1414
import app.revanced.manager.R
15+
import app.revanced.manager.domain.manager.PreferencesManager
1516
import app.revanced.manager.ui.component.AppTopBar
1617
import app.revanced.manager.ui.component.GroupHeader
18+
import app.revanced.manager.ui.component.settings.BooleanItem
1719
import app.revanced.manager.ui.component.settings.SettingsListItem
1820
import app.revanced.manager.ui.viewmodel.DeveloperOptionsViewModel
1921
import org.koin.androidx.compose.koinViewModel
22+
import org.koin.compose.koinInject
2023

2124
@OptIn(ExperimentalMaterial3Api::class)
2225
@Composable
@@ -25,6 +28,7 @@ fun DeveloperSettingsScreen(
2528
vm: DeveloperOptionsViewModel = koinViewModel()
2629
) {
2730
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
31+
val prefs: PreferencesManager = koinInject()
2832

2933
Scaffold(
3034
topBar = {
@@ -37,6 +41,13 @@ fun DeveloperSettingsScreen(
3741
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
3842
) { paddingValues ->
3943
Column(modifier = Modifier.padding(paddingValues)) {
44+
GroupHeader(stringResource(R.string.manager))
45+
BooleanItem(
46+
preference = prefs.showDeveloperSettings,
47+
headline = R.string.developer_options,
48+
description = R.string.developer_options_description,
49+
)
50+
4051
GroupHeader(stringResource(R.string.patch_bundles_section))
4152
SettingsListItem(
4253
headlineContent = stringResource(R.string.patch_bundles_force_download),

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import androidx.compose.runtime.setValue
88
import androidx.lifecycle.ViewModel
99
import androidx.lifecycle.viewModelScope
1010
import app.revanced.manager.data.platform.NetworkInfo
11+
import app.revanced.manager.domain.manager.PreferencesManager
1112
import app.revanced.manager.network.api.ReVancedAPI
1213
import app.revanced.manager.network.dto.ReVancedDonationLink
1314
import app.revanced.manager.network.dto.ReVancedSocial
@@ -27,6 +28,7 @@ import kotlinx.coroutines.withContext
2728
class AboutViewModel(
2829
private val reVancedAPI: ReVancedAPI,
2930
private val network: NetworkInfo,
31+
prefs: PreferencesManager,
3032
) : ViewModel() {
3133
var socials by mutableStateOf(emptyList<ReVancedSocial>())
3234
private set
@@ -37,6 +39,8 @@ class AboutViewModel(
3739
val isConnected: Boolean
3840
get() = network.isConnected()
3941

42+
val showDeveloperSettings = prefs.showDeveloperSettings
43+
4044
init {
4145
viewModelScope.launch {
4246
if (!isConnected) {
@@ -53,6 +57,8 @@ class AboutViewModel(
5357
}
5458

5559
companion object {
60+
const val DEVELOPER_OPTIONS_TAPS = 5
61+
5662
private val socialIcons = mapOf(
5763
"Discord" to FontAwesomeIcons.Brands.Discord,
5864
"GitHub" to FontAwesomeIcons.Brands.Github,

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@
348348

349349
<string name="about_revanced_manager">About ReVanced Manager</string>
350350
<string name="revanced_manager_description">ReVanced Manager is an application designed to work with ReVanced Patcher, which allows for long-lasting patches to be created for Android apps. The patching system is designed to automatically work with new versions of apps with minimal maintenance.</string>
351+
<string name="developer_options_taps">%d taps remaining</string>
352+
<string name="developer_options_enabled">Developer options enabled</string>
353+
<string name="developer_options_already_enabled">Developer options are already enabled</string>
351354
<string name="update_available">An update is available</string>
352355
<string name="current_version">Current version: %s</string>
353356
<string name="new_version">New version: %s</string>

0 commit comments

Comments
 (0)