gatekeep developer settings

This commit is contained in:
Chloe committed 2025-09-14 20:03:29 -07:00
1 parent 13191dc66f
commit a75d68e5e0
3 files changed
+86 -38

No files matched your search

@@ -25,23 +25,23 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -236,6 +236,31 @@ fun onOpenDeveloperOptions(context: Context) {
context.startActivity(launchIntent) context.startActivity(launchIntent)
} }
@Composable
fun DeveloperModeDialog(onDismiss: () -> Unit, onEnable: () -> Unit) {
AlertDialog(
icon = {
Icon(
Icons.Filled.Warning,
contentDescription = null,
)
},
title = { Text(stringResource(R.string.preference_developer_options_dialog_title)) },
text = { Text(stringResource(R.string.preference_developer_mode_about)) },
dismissButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.message_box_cancel))
}
},
confirmButton = {
TextButton(onClick = onEnable) {
Text(stringResource(R.string.message_box_accept))
}
},
onDismissRequest = onDismiss
)
}
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SettingsScreen( fun SettingsScreen(
@@ -426,6 +451,8 @@ fun SettingsScreen(
} }
} }
val developerModeEnabled by PreferenceUtils.useBooleanPreference(PreferenceUtils.Key.DEVELOPER_MODE)
OptionsGroup(stringResource(R.string.preference_category_developer)) { OptionsGroup(stringResource(R.string.preference_category_developer)) {
OptionsButton( OptionsButton(
title = stringResource(R.string.preferences_view_logs), title = stringResource(R.string.preferences_view_logs),
@@ -434,13 +461,17 @@ fun SettingsScreen(
}, },
onClick = { onOpenLogs(context) } onClick = { onOpenLogs(context) }
) )
OptionsButton(
title = stringResource(R.string.preference_open_developer_options), if (developerModeEnabled) {
icon = { OptionsButton(
Icon(painterResource(R.drawable.icon_data_object), contentDescription = null) title = stringResource(R.string.preference_open_developer_options),
}, icon = {
onClick = { onOpenDeveloperOptions(context) } Icon(painterResource(R.drawable.icon_data_object), contentDescription = null)
) },
onClick = { onOpenDeveloperOptions(context) }
)
}
OptionsButton( OptionsButton(
title = context.getString(R.string.preferences_copy_external_button), title = context.getString(R.string.preferences_copy_external_button),
description = LaunchUtils.getBaseDirectory(context).path, description = LaunchUtils.getBaseDirectory(context).path,
@@ -449,29 +480,40 @@ fun SettingsScreen(
} }
OptionsGroup(stringResource(R.string.preference_category_about)) { OptionsGroup(stringResource(R.string.preference_category_about)) {
val clipboard = LocalClipboardManager.current var launcherButtonTapped by remember { mutableIntStateOf(0) }
var showDeveloperDialog by remember { mutableStateOf(false) }
OptionsButton( OptionsButton(
stringResource(R.string.preference_launcher_version_name), stringResource(R.string.preference_launcher_version_name),
stringResource(R.string.preference_launcher_version_description, BuildConfig.VERSION_NAME), stringResource(R.string.preference_launcher_version_description, BuildConfig.VERSION_NAME),
displayInline = true displayInline = true
) { ) {
clipboard.setText(AnnotatedString(context.getString( launcherButtonTapped += 1
R.string.preference_launcher_version,
BuildConfig.VERSION_NAME if (launcherButtonTapped >= 7 && !developerModeEnabled) {
))) showDeveloperDialog = true
launcherButtonTapped = 0
}
} }
OptionsButton( val context = LocalContext.current
if (showDeveloperDialog) {
DeveloperModeDialog(
onDismiss = {
showDeveloperDialog = false
},
onEnable = {
PreferenceUtils.get(context).setBoolean(PreferenceUtils.Key.DEVELOPER_MODE, true)
showDeveloperDialog = false
}
)
}
OptionsLabel(
stringResource(R.string.preference_loader_version_name), stringResource(R.string.preference_loader_version_name),
stringResource(R.string.preference_loader_version_description, currentRelease ?: "unknown"), stringResource(R.string.preference_loader_version_description, currentRelease ?: "unknown"),
displayInline = true displayInline = true
) { )
clipboard.setText(AnnotatedString(context.getString(
R.string.preference_loader_version,
currentRelease ?: "unknown"
)))
}
val gameInstalled = remember { val gameInstalled = remember {
GamePackageUtils.isGameInstalled(context.packageManager) GamePackageUtils.isGameInstalled(context.packageManager)
@@ -490,29 +532,17 @@ fun SettingsScreen(
}) })
} }
OptionsButton( OptionsLabel(
stringResource(R.string.preference_game_version_name), stringResource(R.string.preference_game_version_name),
stringResource(R.string.preference_game_version_description, gameVersion, gameSource), stringResource(R.string.preference_game_version_description, gameVersion, gameSource),
displayInline = true displayInline = true
) { )
clipboard.setText(AnnotatedString(context.getString(
R.string.preference_game_version,
gameVersion,
gameSource
)))
}
OptionsButton( OptionsLabel(
stringResource(R.string.preference_architecture_name), stringResource(R.string.preference_architecture_name),
stringResource(R.string.preference_architecture_description, Build.MODEL, LaunchUtils.applicationArchitecture), stringResource(R.string.preference_architecture_description, Build.MODEL, LaunchUtils.applicationArchitecture),
displayInline = true displayInline = true
) { )
clipboard.setText(AnnotatedString(context.getString(
R.string.preference_architecture,
Build.MODEL,
LaunchUtils.applicationArchitecture
)))
}
} }
} }
} }
@@ -52,7 +52,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@@ -886,6 +885,24 @@ fun OptionsButton(title: String, description: String? = null, icon: (@Composable
} }
} }
@Composable
fun OptionsLabel(title: String, description: String? = null, icon: (@Composable () -> Unit)? = null, displayInline: Boolean = false) {
OptionsCard(
title = {
OptionsTitle(
title = title,
description = description.takeIf { !displayInline },
icon = icon
)
},
wrapContent = true
) {
if (displayInline && description != null) {
Text(description, textAlign = TextAlign.End)
}
}
}
@Composable @Composable
fun SettingsCard(title: String, description: String? = null, icon: (@Composable () -> Unit)? = null, asCard: Boolean = true, preferenceKey: PreferenceUtils.Key) { fun SettingsCard(title: String, description: String? = null, icon: (@Composable () -> Unit)? = null, asCard: Boolean = true, preferenceKey: PreferenceUtils.Key) {
val context = LocalContext.current val context = LocalContext.current
+1
View File
@@ -219,6 +219,7 @@
<string name="preference_text_clear">Clear</string> <string name="preference_text_clear">Clear</string>
<string name="preference_open_developer_options">Open developer options</string> <string name="preference_open_developer_options">Open developer options</string>
<string name="preference_developer_options_dialog_title">Enable developer options?</string>
<string name="preference_profiles">Profiles</string> <string name="preference_profiles">Profiles</string>
<string name="preference_profiles_create">Create profile</string> <string name="preference_profiles_create">Create profile</string>