HeliBoard/app/src/main/java/helium314/keyboard/settings/screens/AdvancedScreen.kt

358 lines
16 KiB
Kotlin
Raw Normal View History

package helium314.keyboard.settings.screens
import android.content.Context
import android.os.Build
2025-02-05 20:21:16 +01:00
import android.widget.Toast
import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
2025-02-05 20:21:16 +01:00
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
2025-02-05 20:21:16 +01:00
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
2025-02-05 20:21:16 +01:00
import helium314.keyboard.keyboard.KeyboardLayoutSet
import helium314.keyboard.keyboard.internal.keyboard_parser.RawKeyboardParser
import helium314.keyboard.latin.BuildConfig
import helium314.keyboard.latin.R
import helium314.keyboard.latin.SystemBroadcastReceiver
2025-02-05 20:21:16 +01:00
import helium314.keyboard.latin.common.splitOnWhitespace
import helium314.keyboard.latin.settings.DebugSettings
import helium314.keyboard.latin.settings.Settings
2025-02-05 20:21:16 +01:00
import helium314.keyboard.latin.utils.CUSTOM_FUNCTIONAL_LAYOUT_NORMAL
import helium314.keyboard.latin.utils.CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS
import helium314.keyboard.latin.utils.CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED
import helium314.keyboard.latin.utils.CUSTOM_LAYOUT_PREFIX
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.checkLayout
import helium314.keyboard.latin.utils.getCustomLayoutFile
import helium314.keyboard.latin.utils.getCustomLayoutFiles
import helium314.keyboard.latin.utils.getLayoutDisplayName
import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.AllPrefs
import helium314.keyboard.settings.ListPreference
import helium314.keyboard.settings.NonSettingsPrefs
import helium314.keyboard.settings.PrefDef
import helium314.keyboard.settings.Preference
import helium314.keyboard.settings.PreferenceCategory
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SettingsActivity2
import helium314.keyboard.settings.SettingsDestination
import helium314.keyboard.settings.SliderPreference
import helium314.keyboard.settings.SwitchPreference
import helium314.keyboard.settings.Theme
2025-02-05 20:21:16 +01:00
import helium314.keyboard.settings.dialogs.CustomizeLayoutDialog
import helium314.keyboard.settings.dialogs.ListPickerDialog
2025-02-02 13:38:55 +01:00
import helium314.keyboard.settings.dialogs.TextInputDialog
2025-02-01 08:43:04 +01:00
import helium314.keyboard.settings.keyboardNeedsReload
2025-02-05 20:21:16 +01:00
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.File
@Composable
fun AdvancedSettingsScreen(
onClickBack: () -> Unit,
) {
val prefs = LocalContext.current.prefs()
SearchPrefScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_advanced),
) {
SettingsActivity2.allPrefs.map[Settings.PREF_ALWAYS_INCOGNITO_MODE]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_KEY_LONGPRESS_TIMEOUT]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_SPACE_HORIZONTAL_SWIPE]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_SPACE_VERTICAL_SWIPE]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_DELETE_SWIPE]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_SPACE_TO_CHANGE_LANG]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREFS_LONG_PRESS_SYMBOLS_FOR_NUMPAD]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY]!!.Preference()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
SettingsActivity2.allPrefs.map[Settings.PREF_SHOW_SETUP_WIZARD_ICON]!!.Preference()
2025-02-02 13:38:55 +01:00
SettingsActivity2.allPrefs.map[Settings.PREF_ABC_AFTER_SYMBOL_SPACE]!!.Preference() // todo: this is ugly
SettingsActivity2.allPrefs.map[Settings.PREF_ABC_AFTER_EMOJI]!!.Preference() // todo: this is ugly
SettingsActivity2.allPrefs.map[Settings.PREF_ABC_AFTER_CLIP]!!.Preference() // todo: this is ugly
SettingsActivity2.allPrefs.map[Settings.PREF_CUSTOM_CURRENCY_KEY]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_MORE_POPUP_KEYS]!!.Preference()
SettingsActivity2.allPrefs.map[NonSettingsPrefs.CUSTOM_SYMBOLS_NUMBER_LAYOUTS]!!.Preference()
SettingsActivity2.allPrefs.map[NonSettingsPrefs.CUSTOM_FUNCTIONAL_LAYOUTS]!!.Preference()
SettingsActivity2.allPrefs.map[NonSettingsPrefs.BACKUP_RESTORE]!!.Preference()
if (BuildConfig.DEBUG || prefs.getBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, false))
2025-01-29 23:34:21 +01:00
SettingsActivity2.allPrefs.map[NonSettingsPrefs.DEBUG_SETTINGS]!!.Preference() // todo: maybe move to main screen?
PreferenceCategory(
stringResource(R.string.settings_category_experimental)
) {
SettingsActivity2.allPrefs.map[Settings.PREF_EMOJI_MAX_SDK]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_URL_DETECTION]!!.Preference()
if (BuildConfig.BUILD_TYPE != "nouserlib")
SettingsActivity2.allPrefs.map[NonSettingsPrefs.LOAD_GESTURE_LIB]!!.Preference()
}
}
}
fun createAdvancedPrefs(context: Context) = listOf(
PrefDef(context, Settings.PREF_ALWAYS_INCOGNITO_MODE, R.string.incognito, R.string.prefs_force_incognito_mode_summary) {
SwitchPreference(
def = it,
default = false
)
},
PrefDef(context, Settings.PREF_KEY_LONGPRESS_TIMEOUT, R.string.prefs_key_longpress_timeout_settings) {
SliderPreference(
name = it.title,
pref = it.key,
default = 300,
range = 100f..700f,
description = { stringResource(R.string.abbreviation_unit_milliseconds, it.toString()) }
)
},
PrefDef(context, Settings.PREF_SPACE_HORIZONTAL_SWIPE, R.string.show_horizontal_space_swipe) { def ->
val items = listOf(
stringResource(R.string.space_swipe_move_cursor_entry) to "move_cursor",
stringResource(R.string.switch_language) to "switch_language",
stringResource(R.string.space_swipe_toggle_numpad_entry) to "toggle_numpad",
stringResource(R.string.action_none) to "none",
)
ListPreference(def, items, "move_cursor")
},
PrefDef(context, Settings.PREF_SPACE_VERTICAL_SWIPE, R.string.show_vertical_space_swipe) { def ->
val items = listOf(
stringResource(R.string.space_swipe_move_cursor_entry) to "move_cursor",
stringResource(R.string.switch_language) to "switch_language",
stringResource(R.string.space_swipe_toggle_numpad_entry) to "toggle_numpad",
stringResource(R.string.action_none) to "none",
)
ListPreference(def, items, "none")
},
PrefDef(context, Settings.PREF_DELETE_SWIPE, R.string.delete_swipe, R.string.delete_swipe_summary) {
SwitchPreference(
def = it,
default = true
)
},
PrefDef(context, Settings.PREF_SPACE_TO_CHANGE_LANG, R.string.prefs_long_press_keyboard_to_change_lang, R.string.prefs_long_press_keyboard_to_change_lang_summary) {
SwitchPreference(
def = it,
default = true
)
},
PrefDef(context, Settings.PREFS_LONG_PRESS_SYMBOLS_FOR_NUMPAD, R.string.prefs_long_press_symbol_for_numpad) {
SwitchPreference(
def = it,
default = false
)
},
PrefDef(context, Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY, R.string.prefs_enable_emoji_alt_physical_key, R.string.prefs_enable_emoji_alt_physical_key_summary) {
SwitchPreference(
def = it,
default = true
)
},
PrefDef(context, Settings.PREF_SHOW_SETUP_WIZARD_ICON, R.string.prefs_enable_emoji_alt_physical_key_summary) {
val ctx = LocalContext.current
SwitchPreference(
def = it,
default = true
) { SystemBroadcastReceiver.toggleAppIcon(ctx) }
},
PrefDef(context, Settings.PREF_ABC_AFTER_SYMBOL_SPACE, R.string.switch_keyboard_after, R.string.after_symbol_and_space) {
SwitchPreference(
def = it,
default = true
)
},
PrefDef(context, Settings.PREF_ABC_AFTER_EMOJI, R.string.switch_keyboard_after, R.string.after_emoji) {
SwitchPreference(
def = it,
default = false
)
},
PrefDef(context, Settings.PREF_ABC_AFTER_CLIP, R.string.switch_keyboard_after, R.string.after_clip) {
SwitchPreference(
def = it,
default = false
)
},
2025-02-05 20:21:16 +01:00
PrefDef(context, Settings.PREF_CUSTOM_CURRENCY_KEY, R.string.customize_currencies) { def ->
var showDialog by remember { mutableStateOf(false) }
Preference(
2025-02-05 20:21:16 +01:00
name = def.title,
onClick = { showDialog = true }
)
2025-02-05 20:21:16 +01:00
if (showDialog) {
val prefs = LocalContext.current.prefs()
TextInputDialog(
onDismissRequest = { showDialog = false },
textInputLabel = { Text(stringResource(R.string.customize_currencies_detail)) },
initialText = prefs.getString(def.key, "")!!,
onConfirmed = { prefs.edit().putString(def.key, it).apply(); KeyboardLayoutSet.onSystemLocaleChanged() },
title = { Text(stringResource(R.string.customize_currencies)) },
neutralButtonText = if (prefs.contains(def.key)) stringResource(R.string.button_default) else null,
onNeutral = { prefs.edit().remove(def.key).apply(); KeyboardLayoutSet.onSystemLocaleChanged() },
checkTextValid = { it.splitOnWhitespace().none { it.length > 8 } }
)
}
},
PrefDef(context, Settings.PREF_MORE_POPUP_KEYS, R.string.show_popup_keys_title) { def ->
val items = listOf(
stringResource(R.string.show_popup_keys_normal) to "normal",
stringResource(R.string.show_popup_keys_main) to "main",
stringResource(R.string.show_popup_keys_more) to "more",
stringResource(R.string.show_popup_keys_all) to "all",
)
2025-02-05 20:21:16 +01:00
ListPreference(def, items, "main") { KeyboardLayoutSet.onSystemLocaleChanged() }
},
2025-02-05 20:21:16 +01:00
PrefDef(context, NonSettingsPrefs.CUSTOM_SYMBOLS_NUMBER_LAYOUTS, R.string.customize_symbols_number_layouts) { def ->
var showDialog by remember { mutableStateOf(false) }
2025-02-05 20:21:16 +01:00
val ctx = LocalContext.current
var layout: String? by remember { mutableStateOf(null) }
Preference(
2025-02-05 20:21:16 +01:00
name = def.title,
onClick = { showDialog = true }
)
2025-02-05 20:21:16 +01:00
if (showDialog) {
ListPickerDialog(
2025-02-02 13:38:55 +01:00
onDismissRequest = { showDialog = false },
2025-02-05 20:21:16 +01:00
showRadioButtons = false,
confirmImmediately = true,
items = RawKeyboardParser.symbolAndNumberLayouts,
getItemName = { it.getStringResourceOrName("layout_", ctx) },
onItemSelected = { layout = it },
title = { Text(def.title) }
)
}
if (layout != null) {
val customLayoutName = getCustomLayoutFiles(ctx).firstOrNull { it.name.startsWith("$CUSTOM_LAYOUT_PREFIX$layout.")}?.name
val originalLayout = if (customLayoutName != null) null
else {
ctx.assets.list("layouts")?.firstOrNull { it.startsWith("$layout.") }
?.let { ctx.assets.open("layouts" + File.separator + it).reader().readText() }
}
CustomizeLayoutDialog(
layoutName = customLayoutName ?: "$CUSTOM_LAYOUT_PREFIX$layout.",
startContent = originalLayout,
displayName = layout?.getStringResourceOrName("layout_", ctx),
onDismissRequest = { layout = null}
2025-02-02 13:38:55 +01:00
)
2025-02-05 20:21:16 +01:00
}
},
2025-02-05 20:21:16 +01:00
PrefDef(context, NonSettingsPrefs.CUSTOM_FUNCTIONAL_LAYOUTS, R.string.customize_functional_key_layouts) { def ->
var showDialog by remember { mutableStateOf(false) }
2025-02-05 20:21:16 +01:00
val ctx = LocalContext.current
var layout: String? by remember { mutableStateOf(null) }
Preference(
2025-02-05 20:21:16 +01:00
name = def.title,
onClick = { showDialog = true }
)
2025-02-05 20:21:16 +01:00
if (showDialog) {
ListPickerDialog(
onDismissRequest = { showDialog = false },
showRadioButtons = false,
confirmImmediately = true,
items = listOf(CUSTOM_FUNCTIONAL_LAYOUT_NORMAL, CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS, CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED)
.map { it.substringBeforeLast(".") },
getItemName = { it.substringAfter(CUSTOM_LAYOUT_PREFIX).getStringResourceOrName("layout_", ctx) },
onItemSelected = { layout = it },
title = { Text(def.title) }
)
}
if (layout != null) {
val customLayoutName = getCustomLayoutFiles(ctx).map { it.name }
.firstOrNull { it.startsWith("$layout.") }
val originalLayout = if (customLayoutName != null) null
else {
val defaultLayoutName = if (Settings.getInstance().isTablet) "functional_keys_tablet.json" else "functional_keys.json"
ctx.assets.open("layouts" + File.separator + defaultLayoutName).reader().readText()
}
CustomizeLayoutDialog(
layoutName = customLayoutName ?: "$CUSTOM_LAYOUT_PREFIX$layout.",
startContent = originalLayout,
displayName = layout?.substringAfter(CUSTOM_LAYOUT_PREFIX)?.getStringResourceOrName("layout_", ctx),
onDismissRequest = { layout = null}
)
}
},
PrefDef(context, NonSettingsPrefs.BACKUP_RESTORE, R.string.backup_restore_title) {
var showDialog by remember { mutableStateOf(false) }
Preference(
name = it.title,
onClick = { showDialog = true }
)
2025-02-02 13:38:55 +01:00
// if (showDialog) todo: show the dialog
},
PrefDef(context, NonSettingsPrefs.DEBUG_SETTINGS, R.string.debug_settings_title) {
Preference(
name = it.title,
onClick = { SettingsDestination.navigateTo(SettingsDestination.Debug) }
) {
Icon(
painter = painterResource(R.drawable.ic_arrow_left),
modifier = Modifier.scale(-1f, 1f),
contentDescription = null
)
}
},
PrefDef(context, Settings.PREF_EMOJI_MAX_SDK, R.string.prefs_key_emoji_max_sdk) {
SliderPreference(
name = it.title,
pref = it.key,
default = Build.VERSION.SDK_INT,
range = 21f..35f,
description = {
"Android " + when(it) {
21 -> "5.0"
22 -> "5.1"
23 -> "6"
24 -> "7.0"
25 -> "7.1"
26 -> "8.0"
27 -> "8.1"
28 -> "9"
29 -> "10"
30 -> "11"
31 -> "12"
32 -> "12L"
33 -> "13"
34 -> "14"
35 -> "15"
else -> "version unknown"
}
},
2025-02-01 08:43:04 +01:00
onValueChanged = { keyboardNeedsReload = true }
)
},
PrefDef(context, Settings.PREF_URL_DETECTION, R.string.url_detection_title, R.string.url_detection_summary) {
SwitchPreference(
def = it,
default = false
)
},
PrefDef(context, NonSettingsPrefs.LOAD_GESTURE_LIB, R.string.load_gesture_library, R.string.load_gesture_library_summary) {
var showDialog by remember { mutableStateOf(false) }
Preference(
name = it.title,
onClick = { showDialog = true }
)
// if (showDialog) todo: show the dialog, or launch that thing
},
)
@Preview
@Composable
private fun Preview() {
SettingsActivity2.allPrefs = AllPrefs(LocalContext.current)
Theme(true) {
Surface {
AdvancedSettingsScreen { }
}
}
}