diff --git a/app/src/main/java/com/aliernfrog/pftool/Constant.kt b/app/src/main/java/com/aliernfrog/pftool/Constant.kt index ff3c8bff..c99dd650 100644 --- a/app/src/main/java/com/aliernfrog/pftool/Constant.kt +++ b/app/src/main/java/com/aliernfrog/pftool/Constant.kt @@ -20,39 +20,15 @@ val supportsPerAppLanguagePreferences = Build.VERSION.SDK_INT >= Build.VERSION_C val folderPickerSupportsInitialUri = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O val hasAndroidDataRestrictions = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -object ConfigKey { - const val PREF_NAME = "APP_CONFIG" - const val KEY_APP_LANGUAGE = "appLanguage" - const val KEY_APP_THEME = "appTheme" - const val KEY_APP_MATERIAL_YOU = "materialYou" - const val KEY_APP_AUTO_UPDATES = "autoUpdates" - const val KEY_APP_UPDATES_URL = "updatesUrl" - const val KEY_SHOW_CHOSEN_MAP_THUMBNAIL = "showChosenMapThumbnail" - const val KEY_SHOW_MAP_THUMBNAILS_LIST = "showMapThumbnailsList" - const val KEY_MAPS_DIR = "mapsDir" - const val KEY_EXPORTED_MAPS_DIR = "mapsExportDir" - const val DEFAULT_UPDATES_URL = "https://aliernfrog.github.io/pftool/latest.json" - val RECOMMENDED_MAPS_DIR = "${Environment.getExternalStorageDirectory()}/Android/data/com.MA.Polyfield/files/editor" - val RECOMMENDED_EXPORTED_MAPS_DIR = "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)}/PFTool/exported" -} - object SettingsConstant { val folders = listOf( PrefEditItem( - labelResourceId = R.string.settings_storage_folders_maps, - getValue = { it.pfMapsDir }, - setValue = { newValue, prefs -> - prefs.pfMapsDir = newValue - }, - default = ConfigKey.RECOMMENDED_MAPS_DIR + preference = { it.pfMapsDir }, + label = { R.string.settings_storage_folders_maps } ), PrefEditItem( - labelResourceId = R.string.settings_storage_folders_exportedMaps, - getValue = { it.exportedMapsDir }, - setValue = { newValue, prefs -> - prefs.exportedMapsDir = newValue - }, - default = ConfigKey.RECOMMENDED_EXPORTED_MAPS_DIR + preference = { it.exportedMapsDir }, + label = { R.string.settings_storage_folders_exportedMaps } ) ) @@ -110,18 +86,6 @@ object SettingsConstant { link = "https://github.com/ReVanced/revanced-manager" ) ) - - val experimentalPrefOptions = listOf( - PrefEditItem( - labelResourceId = R.string.settings_experimental_updatesURL, - getValue = { it.updatesURL }, - setValue = { newValue, prefs -> - prefs.updatesURL = newValue - }, - default = ConfigKey.DEFAULT_UPDATES_URL - ), - *folders.toTypedArray() - ) } val languages = BuildConfig.LANGUAGES.sorted().map { langCode -> diff --git a/app/src/main/java/com/aliernfrog/pftool/data/PermissionData.kt b/app/src/main/java/com/aliernfrog/pftool/data/PermissionData.kt index a307bb43..ad6e3f28 100644 --- a/app/src/main/java/com/aliernfrog/pftool/data/PermissionData.kt +++ b/app/src/main/java/com/aliernfrog/pftool/data/PermissionData.kt @@ -1,17 +1,22 @@ package com.aliernfrog.pftool.data -import android.net.Uri +import android.os.Environment import androidx.annotation.StringRes import androidx.compose.runtime.Composable +import com.aliernfrog.pftool.util.manager.base.BasePreferenceManager data class PermissionData( @StringRes val title: Int, - val recommendedPath: String?, + val pref: BasePreferenceManager.Preference, + val recommendedPath: String? = pref.defaultValue, @StringRes val recommendedPathDescription: Int?, @StringRes val recommendedPathWarning: Int? = null, @StringRes val useUnrecommendedAnywayDescription: Int? = null, val forceRecommendedPath: Boolean = true, - val getUri: () -> String, - val onUriUpdate: (Uri) -> Unit, val content: @Composable () -> Unit -) \ No newline at end of file +) + +val PermissionData.requiresAndroidData: Boolean + get() = forceRecommendedPath && recommendedPath?.startsWith( + "${Environment.getExternalStorageDirectory()}/Android/data" + ) == true \ No newline at end of file diff --git a/app/src/main/java/com/aliernfrog/pftool/data/PrefEditItem.kt b/app/src/main/java/com/aliernfrog/pftool/data/PrefEditItem.kt index 0d164551..105f1d59 100644 --- a/app/src/main/java/com/aliernfrog/pftool/data/PrefEditItem.kt +++ b/app/src/main/java/com/aliernfrog/pftool/data/PrefEditItem.kt @@ -1,10 +1,9 @@ package com.aliernfrog.pftool.data import com.aliernfrog.pftool.util.manager.PreferenceManager +import com.aliernfrog.pftool.util.manager.base.BasePreferenceManager -data class PrefEditItem( - val labelResourceId: Int, - val getValue: (prefs: PreferenceManager) -> String, - val setValue: (newValue: String, prefs: PreferenceManager) -> Unit, - val default: String = "" -) +data class PrefEditItem( + val preference: (PreferenceManager) -> BasePreferenceManager.Preference, + val label: (PreferenceManager) -> Any = { preference(it).key } +) \ No newline at end of file diff --git a/app/src/main/java/com/aliernfrog/pftool/enum/StorageAccessType.kt b/app/src/main/java/com/aliernfrog/pftool/enum/StorageAccessType.kt index 3dde3b5b..863d0d15 100644 --- a/app/src/main/java/com/aliernfrog/pftool/enum/StorageAccessType.kt +++ b/app/src/main/java/com/aliernfrog/pftool/enum/StorageAccessType.kt @@ -17,9 +17,9 @@ enum class StorageAccessType( label = R.string.settings_storage_storageAccessType_saf, description = R.string.settings_storage_storageAccessType_saf_description, enable = { - it.storageAccessType = SAF.ordinal - it.pfMapsDir = FileUtil.getTreeUriForPath(it.pfMapsDir).toString() - it.exportedMapsDir = FileUtil.getTreeUriForPath(it.exportedMapsDir).toString() + it.storageAccessType.value = SAF.ordinal + it.pfMapsDir.value = FileUtil.getTreeUriForPath(it.pfMapsDir.value).toString() + it.exportedMapsDir.value = FileUtil.getTreeUriForPath(it.exportedMapsDir.value).toString() } ), @@ -28,9 +28,9 @@ enum class StorageAccessType( description = R.string.settings_storage_storageAccessType_shizuku_description, minSDK = Build.VERSION_CODES.M, enable = { - it.storageAccessType = SHIZUKU.ordinal - it.pfMapsDir = FileUtil.getFilePath(it.pfMapsDir) - it.exportedMapsDir = FileUtil.getFilePath(it.exportedMapsDir) + it.storageAccessType.value = SHIZUKU.ordinal + it.pfMapsDir.value = FileUtil.getFilePath(it.pfMapsDir.value) + it.exportedMapsDir.value = FileUtil.getFilePath(it.exportedMapsDir.value) } ), @@ -39,9 +39,9 @@ enum class StorageAccessType( description = R.string.settings_storage_storageAccessType_allFiles_description, maxSDK = Build.VERSION_CODES.N_MR1, enable = { - it.storageAccessType = ALL_FILES.ordinal - it.pfMapsDir = FileUtil.getFilePath(it.pfMapsDir) - it.exportedMapsDir = FileUtil.getFilePath(it.exportedMapsDir) + it.storageAccessType.value = ALL_FILES.ordinal + it.pfMapsDir.value = FileUtil.getFilePath(it.pfMapsDir.value) + it.exportedMapsDir.value = FileUtil.getFilePath(it.exportedMapsDir.value) } ) } diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/activity/MainActivity.kt b/app/src/main/java/com/aliernfrog/pftool/ui/activity/MainActivity.kt index a90074ca..751408a2 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/activity/MainActivity.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/activity/MainActivity.kt @@ -44,14 +44,14 @@ class MainActivity : AppCompatActivity() { val context = LocalContext.current val view = LocalView.current val scope = rememberCoroutineScope() - val useDarkTheme = shouldUseDarkTheme(mainViewModel.prefs.theme) + val useDarkTheme = shouldUseDarkTheme(mainViewModel.prefs.theme.value) @Composable fun AppTheme(content: @Composable () -> Unit) { PFToolTheme( darkTheme = useDarkTheme, - dynamicColors = mainViewModel.prefs.materialYou, - pitchBlack = mainViewModel.prefs.pitchBlack, + dynamicColors = mainViewModel.prefs.materialYou.value, + pitchBlack = mainViewModel.prefs.pitchBlack.value, content = content ) } @@ -69,7 +69,7 @@ class MainActivity : AppCompatActivity() { mainViewModel.topToastState.setComposeView(view) mainViewModel.topToastState.setAppTheme { AppTheme(it) } - if (mainViewModel.prefs.autoCheckUpdates) mainViewModel.checkUpdates() + if (mainViewModel.prefs.autoCheckUpdates.value) mainViewModel.checkUpdates() this@MainActivity.intent?.let { mainViewModel.handleIntent(it, context = context) diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsListScreen.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsListScreen.kt index 755512bb..2f79f10c 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsListScreen.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsListScreen.kt @@ -269,7 +269,7 @@ fun MapsListScreen( MapButton( map = map, - showMapThumbnail = mapsListViewModel.prefs.showMapThumbnailsInList, + showMapThumbnail = mapsListViewModel.prefs.showMapThumbnailsInList.value, modifier = Modifier.animateItem(), trailingComponent = { if (isMultiSelecting) Checkbox( diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsPermissionsScreen.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsPermissionsScreen.kt index e31318c9..81c4d4cf 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsPermissionsScreen.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsPermissionsScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import com.aliernfrog.pftool.ConfigKey import com.aliernfrog.pftool.R import com.aliernfrog.pftool.data.PermissionData import com.aliernfrog.pftool.ui.dialog.CustomMessageDialog @@ -27,27 +26,19 @@ fun MapsPermissionsScreen( val permissions = remember { arrayOf( PermissionData( title = R.string.permissions_maps, - recommendedPath = ConfigKey.RECOMMENDED_MAPS_DIR, + pref = mapsViewModel.prefs.pfMapsDir, recommendedPathDescription = R.string.permissions_maps_recommended, recommendedPathWarning = R.string.permissions_maps_openPFToCreate, useUnrecommendedAnywayDescription = R.string.permissions_maps_useUnrecommendedAnyway, - getUri = { mapsViewModel.prefs.pfMapsDir }, - onUriUpdate = { - mapsViewModel.prefs.pfMapsDir = it.toString() - }, content = { Text(stringResource(R.string.permissions_maps_description)) } ), PermissionData( title = R.string.permissions_exportedMaps, - recommendedPath = ConfigKey.RECOMMENDED_EXPORTED_MAPS_DIR, + pref = mapsViewModel.prefs.exportedMapsDir, recommendedPathDescription = R.string.permissions_exportedMaps_recommended, forceRecommendedPath = false, - getUri = { mapsViewModel.prefs.exportedMapsDir }, - onUriUpdate = { - mapsViewModel.prefs.exportedMapsDir = it.toString() - }, content = { Text(stringResource(R.string.permissions_exportedMaps_description)) } diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsScreen.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsScreen.kt index d4679c66..b9d7bde5 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsScreen.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/maps/MapsScreen.kt @@ -79,7 +79,7 @@ fun MapsScreen( Column(Modifier.fillMaxSize().verticalScroll(mapsViewModel.scrollState)) { PickMapButton( chosenMap = mapsViewModel.chosenMap, - showMapThumbnail = mapsViewModel.prefs.showChosenMapThumbnail + showMapThumbnail = mapsViewModel.prefs.showChosenMapThumbnail.value ) { mapsViewModel.mapListShown = true } @@ -114,9 +114,9 @@ private fun Actions( .clip(AppComponentShape) ) - FadeVisibility(visible = mapsViewModel.prefs.showMapNameFieldGuide) { + FadeVisibility(visible = mapsViewModel.prefs.showMapNameFieldGuide.value) { OutlinedCard( - onClick = { mapsViewModel.prefs.showMapNameFieldGuide = false }, + onClick = { mapsViewModel.prefs.showMapNameFieldGuide.value = false }, shape = AppComponentShape, modifier = Modifier.padding( horizontal = 8.dp, diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/PermissionsScreen.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/PermissionsScreen.kt index b22a0491..e41fcfb7 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/PermissionsScreen.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/PermissionsScreen.kt @@ -56,7 +56,7 @@ fun PermissionsScreen( } AnimatedContent( - StorageAccessType.entries[permissionsViewModel.prefs.storageAccessType] + StorageAccessType.entries[permissionsViewModel.prefs.storageAccessType.value] ) { method -> AnimatedContent(permissionsGranted) { showContent -> if (showContent) content() diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/SAFPermissionsScreen.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/SAFPermissionsScreen.kt index 0bfa2c06..55ce5fe9 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/SAFPermissionsScreen.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/permissions/SAFPermissionsScreen.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.aliernfrog.pftool.R import com.aliernfrog.pftool.data.PermissionData +import com.aliernfrog.pftool.data.requiresAndroidData import com.aliernfrog.pftool.enum.StorageAccessType import com.aliernfrog.pftool.enum.isCompatible import com.aliernfrog.pftool.ui.component.CardWithActions @@ -41,7 +42,6 @@ import com.aliernfrog.pftool.ui.component.form.FormSection import com.aliernfrog.pftool.ui.dialog.ChooseFolderIntroDialog import com.aliernfrog.pftool.ui.dialog.UnrecommendedFolderDialog import com.aliernfrog.pftool.ui.viewmodel.PermissionsViewModel -import com.aliernfrog.pftool.util.extension.requiresAndroidData import com.aliernfrog.pftool.util.extension.toPath import com.aliernfrog.pftool.util.extension.takePersistablePermissions import com.aliernfrog.pftool.util.staticutil.FileUtil @@ -119,7 +119,7 @@ private fun SAFPermissionsList( fun takePersistableUriPermissions(uri: Uri) { uri.takePersistablePermissions(context) - activePermissionData?.onUriUpdate?.invoke(uri) + activePermissionData?.pref?.value = uri.toString() onUpdateState() } diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AboutPage.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AboutPage.kt index 5f27e80a..2a147984 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AboutPage.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AboutPage.kt @@ -156,10 +156,10 @@ fun AboutPage( SwitchRow( title = stringResource(R.string.settings_about_autoCheckUpdates), description = stringResource(R.string.settings_about_autoCheckUpdates_description), - checked = settingsViewModel.prefs.autoCheckUpdates, + checked = settingsViewModel.prefs.autoCheckUpdates.value, modifier = Modifier.padding(top = 8.dp) ) { - settingsViewModel.prefs.autoCheckUpdates = it + settingsViewModel.prefs.autoCheckUpdates.value = it } FormSection( diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AppearancePage.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AppearancePage.kt index d5477192..71fb16e9 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AppearancePage.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/AppearancePage.kt @@ -33,12 +33,12 @@ fun AppearancePage( ) { SegmentedButtons( options = Theme.entries.map { stringResource(it.label) }, - selectedIndex = settingsViewModel.prefs.theme, + selectedIndex = settingsViewModel.prefs.theme.value, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp) ) { - settingsViewModel.prefs.theme = it + settingsViewModel.prefs.theme.value = it } } FormSection( @@ -52,18 +52,18 @@ fun AppearancePage( else R.string.settings_appearance_materialYou_unavailable ), painter = rememberVectorPainter(Icons.Outlined.Brush), - checked = settingsViewModel.prefs.materialYou, + checked = settingsViewModel.prefs.materialYou.value, enabled = supportsMaterialYou ) { - settingsViewModel.prefs.materialYou = it + settingsViewModel.prefs.materialYou.value = it } SwitchRow( title = stringResource(R.string.settings_appearance_pitchBlack), description = stringResource(R.string.settings_appearance_pitchBlack_description), painter = rememberVectorPainter(Icons.Outlined.Contrast), - checked = settingsViewModel.prefs.pitchBlack + checked = settingsViewModel.prefs.pitchBlack.value ) { - settingsViewModel.prefs.pitchBlack = it + settingsViewModel.prefs.pitchBlack.value = it } } } diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/ExperimentalPage.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/ExperimentalPage.kt index 5dc66495..396598ef 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/ExperimentalPage.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/ExperimentalPage.kt @@ -1,30 +1,40 @@ package com.aliernfrog.pftool.ui.screen.settings +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Restore import androidx.compose.material.icons.rounded.Done import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import com.aliernfrog.pftool.R -import com.aliernfrog.pftool.SettingsConstant import com.aliernfrog.pftool.ui.component.form.ButtonRow import com.aliernfrog.pftool.ui.component.form.FormSection import com.aliernfrog.pftool.ui.component.form.SwitchRow import com.aliernfrog.pftool.ui.theme.AppComponentShape import com.aliernfrog.pftool.ui.viewmodel.MainViewModel +import com.aliernfrog.pftool.util.manager.base.BasePreferenceManager import com.aliernfrog.pftool.util.staticutil.GeneralUtil import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel +@Suppress("UNCHECKED_CAST") @OptIn(ExperimentalMaterial3Api::class) @Composable fun ExperimentalPage( @@ -34,6 +44,18 @@ fun ExperimentalPage( val context = LocalContext.current val scope = rememberCoroutineScope() + val sortedExperimentalOptions = remember { + mainViewModel.prefs.experimentalPrefs.sortedBy { + when (it.defaultValue) { + is Boolean -> 0 + is String -> 1 + is Int -> 2 + is Long -> 3 + else -> 99 + } + } + } + SettingsPageContainer( title = stringResource(R.string.settings_experimental), onNavigateBackRequest = onNavigateBackRequest @@ -41,13 +63,13 @@ fun ExperimentalPage( SwitchRow( title = stringResource(R.string.settings_experimental), description = stringResource(R.string.settings_experimental_description), - checked = mainViewModel.prefs.experimentalOptionsEnabled, + checked = mainViewModel.prefs.experimentalOptionsEnabled.value, shape = AppComponentShape, containerColor = MaterialTheme.colorScheme.primaryContainer, contentColor = MaterialTheme.colorScheme.onPrimaryContainer, modifier = Modifier.padding(16.dp) ) { - mainViewModel.prefs.experimentalOptionsEnabled = it + mainViewModel.prefs.experimentalOptionsEnabled.value = it } FormSection(title = "Updates") { @@ -73,41 +95,86 @@ fun ExperimentalPage( } FormSection(title = "Prefs", bottomDivider = false) { - SwitchRow( - title = "Show map name field guide", - checked = mainViewModel.prefs.showMapNameFieldGuide, - onCheckedChange = { - mainViewModel.prefs.showMapNameFieldGuide = it + sortedExperimentalOptions.forEach { pref -> + @Composable + fun TextField( + onValueChange: (String) -> Unit, + isNumberOnly: Boolean = false + ) { + OutlinedTextField( + value = pref.value.toString(), + onValueChange = onValueChange, + label = { Text(pref.key) }, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = if (isNumberOnly) KeyboardType.Number else KeyboardType.Unspecified + ), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + ) } - ) - SettingsConstant.experimentalPrefOptions.forEach { prefEdit -> - OutlinedTextField( - value = prefEdit.getValue(mainViewModel.prefs), - onValueChange = { - prefEdit.setValue(it, mainViewModel.prefs) - }, - label = { - Text(stringResource(prefEdit.labelResourceId)) - }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 8.dp) - ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + IconButton( + onClick = { pref.resetValue() }, + modifier = Modifier.padding(start = 8.dp) + ) { + Icon( + imageVector = Icons.Default.Restore, + contentDescription = "Reset" + ) + } + when (pref.defaultValue) { + is Boolean -> { + pref as BasePreferenceManager.Preference + SwitchRow( + title = pref.key, + checked = pref.value + ) { + pref.value = it + } + } + is String -> { + pref as BasePreferenceManager.Preference + TextField( + onValueChange = { pref.value = it }, + ) + } + is Int -> { + pref as BasePreferenceManager.Preference + TextField( + onValueChange = { pref.value = it.toIntOrNull() ?: pref.defaultValue }, + isNumberOnly = true + ) + } + is Long -> { + pref as BasePreferenceManager.Preference + TextField( + onValueChange = { pref.value = it.toLongOrNull() ?: pref.defaultValue }, + isNumberOnly = true + ) + } + } + } } ButtonRow( title = "Reset experimental prefs", contentColor = MaterialTheme.colorScheme.error ) { - SettingsConstant.experimentalPrefOptions.forEach { - it.setValue(it.default, mainViewModel.prefs) + scope.launch { + sortedExperimentalOptions.forEach { + it.resetValue() + } + mainViewModel.topToastState.showAndroidToast( + text = "Restored default values for experimental prefs", + icon = Icons.Rounded.Done + ) + GeneralUtil.restartApp(context) } - mainViewModel.topToastState.showAndroidToast( - text = "Restored default values for experimental prefs", - icon = Icons.Rounded.Done - ) - GeneralUtil.restartApp(context) } } } diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/LanguagePage.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/LanguagePage.kt index 059b3328..519443eb 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/LanguagePage.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/LanguagePage.kt @@ -48,7 +48,7 @@ fun LanguagePage( mainViewModel: MainViewModel = koinViewModel(), onNavigateBackRequest: () -> Unit ) { - val currentLanguage = mainViewModel.prefs.language + val currentLanguage = mainViewModel.prefs.language.value val availableDeviceLanguage = mainViewModel.deviceLanguage.getAvailableLanguage() @Composable diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/MapsPage.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/MapsPage.kt index 301be7e4..8a980b4c 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/MapsPage.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/MapsPage.kt @@ -19,16 +19,16 @@ fun MapsPage( SwitchRow( title = stringResource(R.string.settings_maps_showChosenMapThumbnail), description = stringResource(R.string.settings_maps_showChosenMapThumbnail_description), - checked = settingsViewModel.prefs.showChosenMapThumbnail + checked = settingsViewModel.prefs.showChosenMapThumbnail.value ) { - settingsViewModel.prefs.showChosenMapThumbnail = it + settingsViewModel.prefs.showChosenMapThumbnail.value = it } SwitchRow( title = stringResource(R.string.settings_maps_showMapThumbnailsInList), description = stringResource(R.string.settings_maps_showMapThumbnailsInList_description), - checked = settingsViewModel.prefs.showMapThumbnailsInList + checked = settingsViewModel.prefs.showMapThumbnailsInList.value ) { - settingsViewModel.prefs.showMapThumbnailsInList = it + settingsViewModel.prefs.showMapThumbnailsInList.value = it } } } \ No newline at end of file diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/SettingsScreen.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/SettingsScreen.kt index 15ffa42d..f10944a7 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/SettingsScreen.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/SettingsScreen.kt @@ -117,7 +117,7 @@ private fun SettingsRootPage( SettingsPage.entries .filter { - it.showInSettingsHome && !(it == SettingsPage.EXPERIMENTAL && !mainViewModel.prefs.experimentalOptionsEnabled) + it.showInSettingsHome && !(it == SettingsPage.EXPERIMENTAL && !mainViewModel.prefs.experimentalOptionsEnabled.value) } .forEach { page -> ButtonRow( diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/StoragePage.kt b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/StoragePage.kt index 369e5b36..5f6c339a 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/StoragePage.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/screen/settings/StoragePage.kt @@ -55,9 +55,11 @@ import com.aliernfrog.pftool.ui.component.form.FormSection import com.aliernfrog.pftool.ui.theme.AppComponentShape import com.aliernfrog.pftool.ui.viewmodel.SettingsViewModel import com.aliernfrog.pftool.util.extension.horizontalFadingEdge +import com.aliernfrog.pftool.util.extension.resolveString import com.aliernfrog.pftool.util.extension.takePersistablePermissions import com.aliernfrog.pftool.util.extension.toPath import com.aliernfrog.pftool.util.manager.PreferenceManager +import com.aliernfrog.pftool.util.manager.base.BasePreferenceManager import com.aliernfrog.pftool.util.staticutil.FileUtil import org.koin.androidx.compose.koinViewModel import org.koin.compose.koinInject @@ -71,7 +73,7 @@ fun StoragePage( mutableStateOf(false) } - val selectedStorageAccessType = StorageAccessType.entries[settingsViewModel.prefs.storageAccessType] + val selectedStorageAccessType = StorageAccessType.entries[settingsViewModel.prefs.storageAccessType.value] SettingsPageContainer( title = stringResource(R.string.settings_storage), @@ -85,7 +87,7 @@ fun StoragePage( onClickHeader = { storageAccessTypesExpanded = !storageAccessTypesExpanded } ) { StorageAccessType.entries.filter { it.isCompatible() }.forEach { type -> - val selected = settingsViewModel.prefs.storageAccessType == type.ordinal + val selected = settingsViewModel.prefs.storageAccessType.value == type.ordinal fun onSelect() { if (!selected) type.enable(settingsViewModel.prefs) } @@ -126,32 +128,32 @@ private fun FolderConfiguration( useRawPathInputs: Boolean ) { val context = LocalContext.current - var activePref: PrefEditItem? = remember { null } + var activePref: PrefEditItem? = remember { null } val openFolderLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.OpenDocumentTree(), onResult = { if (it == null) return@rememberLauncherForActivityResult val pref = activePref ?: return@rememberLauncherForActivityResult it.takePersistablePermissions(context) - pref.setValue(it.toString(), prefs) + pref.preference(prefs).value = it.toString() }) AnimatedContent(useRawPathInputs) { rawPathInput -> Column { - SettingsConstant.folders.forEach { pref -> + SettingsConstant.folders.forEach { prefEditItem -> + val pref = prefEditItem.preference(prefs) + val label = prefEditItem.label(prefs).resolveString() if (rawPathInput) RawPathInput( + label = label, pref = pref, - prefs = prefs, onPickFolderRequest = { openFolderLauncher.launch(null) } ) else FolderCard( + label = label, pref = pref, - path = getFolderDescription( - folder = pref, - prefs = prefs - ), + path = getFolderDescription(pref.value), onPickFolderRequest = { uri -> - activePref = pref + activePref = prefEditItem openFolderLauncher.launch(uri) } ) @@ -162,24 +164,24 @@ private fun FolderConfiguration( @Composable fun RawPathInput( - pref: PrefEditItem, - prefs: PreferenceManager, + label: String, + pref: BasePreferenceManager.Preference, onPickFolderRequest: () -> Unit ) { - val currentPath = pref.getValue(prefs) - val isDefault = pref.default == currentPath + val currentPath = pref.value + val isDefault = pref.defaultValue == currentPath OutlinedTextField( value = currentPath, onValueChange = { - pref.setValue(it, prefs) + pref.value = it }, label = { - Text(stringResource(pref.labelResourceId)) + Text(label) }, supportingText = { FadeVisibility(!isDefault) { Text( - stringResource(R.string.settings_storage_folders_default).replace("%s", pref.default) + stringResource(R.string.settings_storage_folders_default).replace("%s", pref.defaultValue) ) } }, @@ -187,7 +189,7 @@ fun RawPathInput( Row { Crossfade(!isDefault) { enabled -> IconButton( - onClick = { pref.setValue(pref.default, prefs) }, + onClick = { pref.value = pref.defaultValue }, enabled = enabled ) { Icon( @@ -215,12 +217,13 @@ fun RawPathInput( @Composable fun FolderCard( - pref: PrefEditItem, + label: String, + pref: BasePreferenceManager.Preference, path: String, onPickFolderRequest: (Uri?) -> Unit ) { val buttonsScrollState = rememberScrollState() - val recommendedPath = remember { pref.default.removePrefix(externalStorageRoot) } + val recommendedPath = remember { pref.defaultValue.removePrefix(externalStorageRoot) } val dataFolderPath = remember { externalStorageRoot+"Android/data" } val usingRecommendedPath = path.equals(recommendedPath, ignoreCase = true) Card( @@ -237,7 +240,7 @@ fun FolderCard( modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp) ) { Text( - text = stringResource(pref.labelResourceId), + text = label, style = MaterialTheme.typography.titleMedium ) Text(path) @@ -263,7 +266,7 @@ fun FolderCard( ) { if (folderPickerSupportsInitialUri) AssistChip( onClick = { - onPickFolderRequest(FileUtil.getUriForPath(pref.default)) + onPickFolderRequest(FileUtil.getUriForPath(pref.defaultValue)) }, label = { Text(stringResource(R.string.settings_storage_folders_openRecommended)) @@ -291,11 +294,8 @@ fun FolderCard( } @Composable -private fun getFolderDescription( - folder: PrefEditItem, - prefs: PreferenceManager -): String { - var text = folder.getValue(prefs) +private fun getFolderDescription(path: String): String { + var text = path if (text.isNotEmpty()) try { text = Uri.parse(text).toPath().removePrefix(externalStorageRoot) } catch (_: Exception) {} diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MainViewModel.kt b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MainViewModel.kt index af15e8a2..2c276901 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MainViewModel.kt @@ -23,7 +23,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aliernfrog.pftool.BuildConfig import com.aliernfrog.pftool.R -import com.aliernfrog.pftool.SettingsConstant import com.aliernfrog.pftool.TAG import com.aliernfrog.pftool.data.Language import com.aliernfrog.pftool.data.ReleaseInfo @@ -39,7 +38,6 @@ import com.aliernfrog.pftool.util.extension.cacheFile import com.aliernfrog.pftool.util.extension.getAvailableLanguage import com.aliernfrog.pftool.util.extension.showErrorToast import com.aliernfrog.pftool.util.extension.toLanguage -import com.aliernfrog.pftool.util.manager.ContextUtils import com.aliernfrog.pftool.util.manager.PreferenceManager import com.aliernfrog.pftool.util.staticutil.GeneralUtil import com.aliernfrog.toptoast.enum.TopToastColor @@ -59,8 +57,7 @@ class MainViewModel( context: Context, val prefs: PreferenceManager, val topToastState: TopToastState, - val progressState: ProgressState, - private val contextUtils: ContextUtils + val progressState: ProgressState ) : ViewModel() { lateinit var scope: CoroutineScope val updateSheetState = SheetState(skipPartiallyExpanded = false, Density(context)) @@ -86,7 +83,7 @@ class MainViewModel( var appLanguage: Language? get() = _appLanguage ?: deviceLanguage.getAvailableLanguage() ?: defaultLanguage set(language) { - prefs.language = language?.fullCode ?: "" + prefs.language.value = language?.fullCode ?: "" val localeListCompat = if (language == null) LocaleListCompat.getEmptyLocaleList() else LocaleListCompat.forLanguageTags(language.languageCode) AppCompatDelegate.setApplicationLocales(localeListCompat) @@ -109,15 +106,14 @@ class MainViewModel( get() = arrayOf( "PF Tool $applicationVersionLabel", "Android API ${Build.VERSION.SDK_INT}", - "Storage access type ${prefs.storageAccessType}", - SettingsConstant.experimentalPrefOptions.joinToString("\n") { - "${contextUtils.getString(it.labelResourceId)}: ${it.getValue(prefs)}" + prefs.debugInfoPrefs.joinToString("\n") { + "${it.key}: ${it.value}" } ).joinToString("\n") init { - if (!supportsPerAppLanguagePreferences && prefs.language.isNotBlank()) runBlocking { - appLanguage = GeneralUtil.getLanguageFromCode(prefs.language)?.getAvailableLanguage() + if (!supportsPerAppLanguagePreferences && prefs.language.value.isNotBlank()) runBlocking { + appLanguage = GeneralUtil.getLanguageFromCode(prefs.language.value)?.getAvailableLanguage() } } @@ -127,7 +123,7 @@ class MainViewModel( ) { withContext(Dispatchers.IO) { try { - val updatesURL = prefs.updatesURL + val updatesURL = prefs.updatesURL.value val responseJson = JSONObject(URL(updatesURL).readText()) val json = responseJson.getJSONObject( if (applicationIsPreRelease && responseJson.has("preRelease")) "preRelease" else "stable" diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MapsViewModel.kt b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MapsViewModel.kt index 156cc5f6..70f29bb3 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MapsViewModel.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/MapsViewModel.kt @@ -45,15 +45,15 @@ class MapsViewModel( val scrollState = ScrollState(0) val mapsDir: String - get() = prefs.pfMapsDir + get() = prefs.pfMapsDir.value val exportedMapsDir: String - get() = prefs.exportedMapsDir + get() = prefs.exportedMapsDir.value lateinit var mapsFile: Any private set lateinit var exportedMapsFile: Any private set - private var lastKnownStorageAccessType = prefs.storageAccessType + private var lastKnownStorageAccessType = prefs.storageAccessType.value var isLoadingMaps by mutableStateOf(true) var importedMaps by mutableStateOf(emptyList()) @@ -159,7 +159,7 @@ class MapsViewModel( */ private fun getMapsFile(context: Context): Any { val isUpToDate = if (!::mapsFile.isInitialized) false - else if (lastKnownStorageAccessType != prefs.storageAccessType) false + else if (lastKnownStorageAccessType != prefs.storageAccessType.value) false else { val existingPath = when (val file = mapsFile) { is File -> file.absolutePath @@ -170,7 +170,7 @@ class MapsViewModel( mapsDir == existingPath } if (isUpToDate) return mapsFile - val storageAccessType = prefs.storageAccessType + val storageAccessType = prefs.storageAccessType.value lastKnownStorageAccessType = storageAccessType mapsFile = when (StorageAccessType.entries[storageAccessType]) { StorageAccessType.SAF -> { @@ -199,7 +199,7 @@ class MapsViewModel( */ private fun getExportedMapsFile(context: Context): Any { val isUpToDate = if (!::exportedMapsFile.isInitialized) false - else if (lastKnownStorageAccessType != prefs.storageAccessType) false + else if (lastKnownStorageAccessType != prefs.storageAccessType.value) false else { val existingPath = when (val file = exportedMapsFile) { is File -> file.absolutePath @@ -210,7 +210,7 @@ class MapsViewModel( exportedMapsDir == existingPath } if (isUpToDate) return exportedMapsFile - val storageAccessType = prefs.storageAccessType + val storageAccessType = prefs.storageAccessType.value lastKnownStorageAccessType = storageAccessType exportedMapsFile = when (StorageAccessType.entries[storageAccessType]) { StorageAccessType.SAF -> { diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/PermissionsViewModel.kt b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/PermissionsViewModel.kt index f42bc4c5..e1cee037 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/PermissionsViewModel.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/PermissionsViewModel.kt @@ -19,7 +19,7 @@ class PermissionsViewModel( val prefs: PreferenceManager ) : ViewModel() { private var storageAccessType: StorageAccessType - get() = StorageAccessType.entries[prefs.storageAccessType] + get() = StorageAccessType.entries[prefs.storageAccessType.value] set(value) { value.enable(prefs) } var showShizukuIntroDialog by mutableStateOf(false) @@ -47,7 +47,7 @@ class PermissionsViewModel( context: Context ): List { return permissionsData.filter { - !Uri.parse(it.getUri()).appHasPermissions(context) + !Uri.parse(it.pref.value).appHasPermissions(context) } } } \ No newline at end of file diff --git a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/SettingsViewModel.kt b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/SettingsViewModel.kt index caa5ed8c..71b15722 100644 --- a/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/com/aliernfrog/pftool/ui/viewmodel/SettingsViewModel.kt @@ -25,11 +25,11 @@ class SettingsViewModel( val libraries = Libs.Builder().withContext(context).build().libraries fun onAboutClick() { - if (prefs.experimentalOptionsEnabled) return + if (prefs.experimentalOptionsEnabled.value) return aboutClickCount++ if (aboutClickCount == experimentalSettingsRequiredClicks) { aboutClickCount = 0 - prefs.experimentalOptionsEnabled = true + prefs.experimentalOptionsEnabled.value = true topToastState.showToast( text = R.string.settings_experimental_enabled, icon = Icons.Rounded.Build, diff --git a/app/src/main/java/com/aliernfrog/pftool/util/extension/PermissionData.kt b/app/src/main/java/com/aliernfrog/pftool/util/extension/PermissionData.kt deleted file mode 100644 index d3c21639..00000000 --- a/app/src/main/java/com/aliernfrog/pftool/util/extension/PermissionData.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.aliernfrog.pftool.util.extension - -import android.os.Environment -import com.aliernfrog.pftool.data.PermissionData - -val PermissionData.requiresAndroidData: Boolean - get() = forceRecommendedPath && recommendedPath?.startsWith( - "${Environment.getExternalStorageDirectory()}/Android/data" - ) == true \ No newline at end of file diff --git a/app/src/main/java/com/aliernfrog/pftool/util/extension/Uri.kt b/app/src/main/java/com/aliernfrog/pftool/util/extension/Uri.kt index 7edcaba0..39f26c73 100644 --- a/app/src/main/java/com/aliernfrog/pftool/util/extension/Uri.kt +++ b/app/src/main/java/com/aliernfrog/pftool/util/extension/Uri.kt @@ -32,6 +32,7 @@ fun Uri.cacheFile(context: Context): File? { } fun Uri.toPath(): String { + if (!toString().contains(":")) return toString() val pathSplit = pathSegments.last().split(":", limit = 2) val root = pathSplit.first() val filePath = pathSplit.last() diff --git a/app/src/main/java/com/aliernfrog/pftool/util/manager/PreferenceManager.kt b/app/src/main/java/com/aliernfrog/pftool/util/manager/PreferenceManager.kt index c3bd10c9..ffb29e4b 100644 --- a/app/src/main/java/com/aliernfrog/pftool/util/manager/PreferenceManager.kt +++ b/app/src/main/java/com/aliernfrog/pftool/util/manager/PreferenceManager.kt @@ -1,32 +1,33 @@ package com.aliernfrog.pftool.util.manager import android.content.Context -import com.aliernfrog.pftool.ConfigKey +import android.os.Environment import com.aliernfrog.pftool.enum.StorageAccessType +import com.aliernfrog.pftool.externalStorageRoot import com.aliernfrog.pftool.ui.theme.Theme import com.aliernfrog.pftool.util.manager.base.BasePreferenceManager class PreferenceManager(context: Context) : BasePreferenceManager( - prefs = context.getSharedPreferences(ConfigKey.PREF_NAME, Context.MODE_PRIVATE) + prefs = context.getSharedPreferences("APP_CONFIG", Context.MODE_PRIVATE) ) { // Appearance options - var theme by intPreference(ConfigKey.KEY_APP_THEME, Theme.SYSTEM.ordinal) - var materialYou by booleanPreference(ConfigKey.KEY_APP_MATERIAL_YOU, true) - var pitchBlack by booleanPreference("pitchBlack", false) + val theme = intPreference("appTheme", Theme.SYSTEM.ordinal) + val materialYou = booleanPreference("materialYou", true) + val pitchBlack = booleanPreference("pitchBlack", false) // General options - var showChosenMapThumbnail by booleanPreference(ConfigKey.KEY_SHOW_CHOSEN_MAP_THUMBNAIL, true) - var showMapThumbnailsInList by booleanPreference(ConfigKey.KEY_SHOW_MAP_THUMBNAILS_LIST, true) - var language by stringPreference(ConfigKey.KEY_APP_LANGUAGE, "") // follow system if blank + val showChosenMapThumbnail = booleanPreference("showChosenMapThumbnail", true) + val showMapThumbnailsInList = booleanPreference("showMapThumbnailsList", true) + val language = stringPreference("appLanguage", "") // follow system if blank + val autoCheckUpdates = booleanPreference("autoUpdates", true) // Storage options - var pfMapsDir by stringPreference(ConfigKey.KEY_MAPS_DIR, ConfigKey.RECOMMENDED_MAPS_DIR) - var exportedMapsDir by stringPreference(ConfigKey.KEY_EXPORTED_MAPS_DIR, ConfigKey.RECOMMENDED_EXPORTED_MAPS_DIR) - var storageAccessType by intPreference("storageAccessType", StorageAccessType.SAF.ordinal) + val pfMapsDir = stringPreference("mapsDir", "${externalStorageRoot}Android/data/com.MA.Polyfield/files/editor", experimental = true) + val exportedMapsDir = stringPreference("mapsExportDir", "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)}/PFTool/exported", experimental = true) + val storageAccessType = intPreference("storageAccessType", StorageAccessType.SAF.ordinal, includeInDebugInfo = true) // Experimental (developer) options - var experimentalOptionsEnabled by booleanPreference("experimentalOptionsEnabled", false) - var showMapNameFieldGuide by booleanPreference("showMapNameFieldGuide", true) - var autoCheckUpdates by booleanPreference(ConfigKey.KEY_APP_AUTO_UPDATES, true) - var updatesURL by stringPreference(ConfigKey.KEY_APP_UPDATES_URL, ConfigKey.DEFAULT_UPDATES_URL) + var experimentalOptionsEnabled = booleanPreference("experimentalOptionsEnabled", false) + var showMapNameFieldGuide = booleanPreference("showMapNameFieldGuide", true, experimental = true, includeInDebugInfo = false) + var updatesURL = stringPreference("updatesUrl", "https://aliernfrog.github.io/pftool/latest.json", experimental = true, includeInDebugInfo = false) } \ No newline at end of file diff --git a/app/src/main/java/com/aliernfrog/pftool/util/manager/base/BasePreferenceManager.kt b/app/src/main/java/com/aliernfrog/pftool/util/manager/base/BasePreferenceManager.kt index 8fb938d7..ceaad158 100644 --- a/app/src/main/java/com/aliernfrog/pftool/util/manager/base/BasePreferenceManager.kt +++ b/app/src/main/java/com/aliernfrog/pftool/util/manager/base/BasePreferenceManager.kt @@ -7,63 +7,93 @@ import androidx.compose.runtime.setValue import androidx.core.content.edit import kotlin.reflect.KProperty -@Suppress("SameParameterValue") abstract class BasePreferenceManager( private val prefs: SharedPreferences ) { - fun getString(key: String, defaultValue: String?) = prefs.getString(key, defaultValue)!! + private fun getString(key: String, defaultValue: String?) = prefs.getString(key, defaultValue)!! private fun getBoolean(key: String, defaultValue: Boolean) = prefs.getBoolean(key, defaultValue) private fun getInt(key: String, defaultValue: Int) = prefs.getInt(key, defaultValue) - fun putString(key: String, value: String?) = prefs.edit { putString(key, value) } + private fun putString(key: String, value: String?) = prefs.edit { putString(key, value) } private fun putBoolean(key: String, value: Boolean) = prefs.edit { putBoolean(key, value) } private fun putInt(key: String, value: Int) = prefs.edit { putInt(key, value) } + val experimentalPrefs = mutableListOf>() + val debugInfoPrefs = mutableListOf>() - protected class Preference( - private val key: String, - defaultValue: T, + class Preference( + val key: String, + val defaultValue: T, getter: (key: String, defaultValue: T) -> T, private val setter: (key: String, newValue: T) -> Unit ) { - var value by mutableStateOf(getter(key, defaultValue)) - private set + private var mutableValue by mutableStateOf(getter(key, defaultValue)) + var value: T + get() = mutableValue + set(value) { + mutableValue = value + setter(key, value) + } operator fun getValue(thisRef: Any?, property: KProperty<*>) = value operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) { value = newValue setter(key, newValue) } + fun resetValue() { + value = defaultValue + } } protected fun stringPreference( key: String, - defaultValue: String = "" - ) = Preference( - key = key, - defaultValue = defaultValue, - getter = ::getString, - setter = ::putString - ) + defaultValue: String = "", + experimental: Boolean = false, + includeInDebugInfo: Boolean = experimental + ): Preference { + val pref = Preference( + key = key, + defaultValue = defaultValue, + getter = ::getString, + setter = ::putString + ) + if (experimental) experimentalPrefs.add(pref) + if (includeInDebugInfo) debugInfoPrefs.add(pref) + return pref + } protected fun booleanPreference( key: String, - defaultValue: Boolean - ) = Preference( - key = key, - defaultValue = defaultValue, - getter = ::getBoolean, - setter = ::putBoolean - ) + defaultValue: Boolean, + experimental: Boolean = false, + includeInDebugInfo: Boolean = experimental + ): Preference { + val pref = Preference( + key = key, + defaultValue = defaultValue, + getter = ::getBoolean, + setter = ::putBoolean + ) + if (experimental) experimentalPrefs.add(pref) + if (includeInDebugInfo) debugInfoPrefs.add(pref) + return pref + } protected fun intPreference( key: String, - defaultValue: Int - ) = Preference( - key = key, - defaultValue = defaultValue, - getter = ::getInt, - setter = ::putInt - ) + defaultValue: Int, + experimental: Boolean = false, + includeInDebugInfo: Boolean = experimental + ): Preference { + val pref = Preference( + key = key, + defaultValue = defaultValue, + getter = ::getInt, + setter = ::putInt + ) + if (experimental) experimentalPrefs.add(pref) + if (includeInDebugInfo) debugInfoPrefs.add(pref) + return pref + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5d5ffbd0..b706f757 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -185,7 +185,6 @@ Experimental settings Experimental settings enabled! Not intended for normal usage, might break the app when misused - Updates URL PF Tool update available! Click for more details No updates available Something went wrong while checking for updates