mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Use a slider for several settings
This commit is contained in:
parent
645c7d6e49
commit
5c9bada7ae
@ -15,6 +15,9 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.LazyListScope
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
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.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
@ -22,24 +25,41 @@ import androidx.compose.material.icons.filled.ArrowForward
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.RadioButton
|
import androidx.compose.material3.RadioButton
|
||||||
|
import androidx.compose.material3.Slider
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.drawscope.translate
|
import androidx.compose.ui.graphics.drawscope.translate
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.TextRange
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
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
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||||
|
import org.futo.inputmethod.latin.uix.getSetting
|
||||||
import org.futo.inputmethod.latin.uix.theme.Typography
|
import org.futo.inputmethod.latin.uix.theme.Typography
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ScreenTitle(title: String, showBack: Boolean = false, navController: NavHostController = rememberNavController()) {
|
fun ScreenTitle(title: String, showBack: Boolean = false, navController: NavHostController = rememberNavController()) {
|
||||||
@ -243,6 +263,111 @@ fun<T> SettingRadio(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun<T: Number> SettingSlider(
|
||||||
|
title: String,
|
||||||
|
setting: SettingsKey<T>,
|
||||||
|
range: ClosedFloatingPointRange<Float>,
|
||||||
|
transform: (Float) -> T,
|
||||||
|
indicator: (T) -> String = { it.toString() },
|
||||||
|
hardRange: ClosedFloatingPointRange<Float> = range,
|
||||||
|
power: Float = 1.0f,
|
||||||
|
subtitle: String? = null
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
val (value, setValue) = useDataStore(key = setting.key, default = setting.default)
|
||||||
|
var virtualValue by remember { mutableFloatStateOf((runBlocking { context.getSetting(setting) }).toFloat().let {
|
||||||
|
if(it == Float.POSITIVE_INFINITY || it == Float.NEGATIVE_INFINITY) {
|
||||||
|
it
|
||||||
|
} else {
|
||||||
|
it.pow(1.0f / power)
|
||||||
|
}
|
||||||
|
}) }
|
||||||
|
var isTextFieldVisible by remember { mutableStateOf(false) }
|
||||||
|
var hasTextFieldFocusedYet by remember { mutableStateOf(false) }
|
||||||
|
var textFieldValue by remember(value) {
|
||||||
|
val s = value.toString()
|
||||||
|
mutableStateOf(TextFieldValue(
|
||||||
|
s,
|
||||||
|
selection = TextRange(0, s.length)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
|
LaunchedEffect(isTextFieldVisible) {
|
||||||
|
if(isTextFieldVisible) focusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenTitle(title, showBack = false)
|
||||||
|
if(subtitle != null) {
|
||||||
|
Text(subtitle, style = Typography.bodyMedium, modifier = Modifier.padding(12.dp, 0.dp))
|
||||||
|
}
|
||||||
|
Row(modifier = Modifier.padding(16.dp, 0.dp)) {
|
||||||
|
if (isTextFieldVisible) {
|
||||||
|
val apply = {
|
||||||
|
if(isTextFieldVisible) {
|
||||||
|
val number = textFieldValue.text.trim().toFloatOrNull()
|
||||||
|
val newValue = if (number != null) {
|
||||||
|
transform(number.coerceIn(hardRange))
|
||||||
|
} else {
|
||||||
|
setting.default
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(newValue)
|
||||||
|
virtualValue = newValue.toFloat().pow(1.0f / power)
|
||||||
|
|
||||||
|
isTextFieldVisible = false
|
||||||
|
textFieldValue = TextFieldValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BasicTextField(
|
||||||
|
value = textFieldValue,
|
||||||
|
onValueChange = { textFieldValue = it },
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(0.33f)
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
|
.focusRequester(focusRequester)
|
||||||
|
.onFocusChanged {
|
||||||
|
if(it.isFocused) hasTextFieldFocusedYet = true
|
||||||
|
else if(!it.isFocused && hasTextFieldFocusedYet) apply()
|
||||||
|
},
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onDone = {
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
singleLine = true,
|
||||||
|
textStyle = Typography.labelMedium
|
||||||
|
)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Text(
|
||||||
|
text = indicator(value),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(0.33f)
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
|
.clickable {
|
||||||
|
hasTextFieldFocusedYet = false
|
||||||
|
isTextFieldVisible = true
|
||||||
|
},
|
||||||
|
style = Typography.labelMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Slider(
|
||||||
|
value = virtualValue,
|
||||||
|
onValueChange = {
|
||||||
|
virtualValue = it
|
||||||
|
setValue(transform(it.pow(power))) },
|
||||||
|
valueRange = range.start.pow(1.0f / power) .. range.endInclusive.pow(1.0f / power),
|
||||||
|
enabled = !isTextFieldVisible,
|
||||||
|
modifier = Modifier.weight(1.0f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ScrollableList(content: @Composable () -> Unit) {
|
fun ScrollableList(content: @Composable () -> Unit) {
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
@ -1,20 +1,13 @@
|
|||||||
package org.futo.inputmethod.latin.uix.settings.pages
|
package org.futo.inputmethod.latin.uix.settings.pages
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import org.futo.inputmethod.latin.uix.THEME_KEY
|
|
||||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
||||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||||
import org.futo.inputmethod.latin.uix.settings.SettingRadio
|
import org.futo.inputmethod.latin.uix.settings.SettingSlider
|
||||||
import org.futo.inputmethod.latin.uix.settings.Tip
|
import org.futo.inputmethod.latin.uix.settings.Tip
|
||||||
import org.futo.inputmethod.latin.uix.settings.useDataStore
|
|
||||||
import org.futo.inputmethod.latin.uix.theme.selector.ThemePicker
|
|
||||||
import org.futo.inputmethod.latin.xlm.AutocorrectThresholdSetting
|
import org.futo.inputmethod.latin.xlm.AutocorrectThresholdSetting
|
||||||
import org.futo.inputmethod.latin.xlm.BinaryDictTransformerWeightSetting
|
import org.futo.inputmethod.latin.xlm.BinaryDictTransformerWeightSetting
|
||||||
|
|
||||||
@ -24,50 +17,55 @@ fun AdvancedParametersScreen(navController: NavHostController = rememberNavContr
|
|||||||
ScrollableList {
|
ScrollableList {
|
||||||
ScreenTitle("Advanced Parameters", showBack = true, navController)
|
ScreenTitle("Advanced Parameters", showBack = true, navController)
|
||||||
|
|
||||||
val optionsWeight = mapOf(
|
Tip("Options below are experimental and may be removed or changed in the future as internal workings of the app change. Changing these values may have an adverse impact on your experience.")
|
||||||
Float.NEGATIVE_INFINITY to "always BinaryDictionary, except if blank",
|
|
||||||
0.0001f to "significantly favor BinaryDictionary, except if BinaryDictionary score < 0",
|
SettingSlider(
|
||||||
0.01f to "favor BinaryDictionary",
|
title = "Transformer LM strength",
|
||||||
0.1f to "favor BinaryDictionary",
|
subtitle = "Lower value will make autocorrect behave more similarly to standard AOSP keyboard, while higher value will make it more dependent on the neural network\nDefault is ${BinaryDictTransformerWeightSetting.default}",
|
||||||
0.2f to "favor BinaryDictionary",
|
setting = BinaryDictTransformerWeightSetting,
|
||||||
0.3f to "favor BinaryDictionary",
|
range = 0.0f .. 100.0f,
|
||||||
0.4f to "favor BinaryDictionary",
|
transform = {
|
||||||
0.5f to "favor BinaryDictionary",
|
if(it > 99.9f) {
|
||||||
1.0f to "normal",
|
Float.POSITIVE_INFINITY
|
||||||
2.0f to "favor TransformerLM",
|
} else if(it < 0.0001f) {
|
||||||
4.0f to "significantly favor TransformerLM",
|
Float.NEGATIVE_INFINITY
|
||||||
Float.POSITIVE_INFINITY to "always TransformerLM"
|
} else {
|
||||||
)
|
it
|
||||||
val namesWeight = optionsWeight.map { "a = ${it.key} (${it.value})" }
|
}
|
||||||
SettingRadio(
|
},
|
||||||
title = "Weight of Transformer LM suggestions with respect to BinaryDictionary",
|
indicator = {
|
||||||
options = optionsWeight.keys.toList(),
|
when {
|
||||||
optionNames = namesWeight,
|
it == Float.POSITIVE_INFINITY -> {
|
||||||
setting = BinaryDictTransformerWeightSetting
|
"always Transformer LM"
|
||||||
|
}
|
||||||
|
it == Float.NEGATIVE_INFINITY -> {
|
||||||
|
"always Binary Dictionary"
|
||||||
|
}
|
||||||
|
(it > 0.1f) -> {
|
||||||
|
"a = ${String.format("%.1f", it)}"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
"a = $it"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
power = 2.5f
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SettingSlider(
|
||||||
Tip("Adjust the autocorrect threshold below. A lower threshold will autocorrect more often (and miscorrect more often), while a higher threshold will autocorrect less often (and miscorrect less often)" )
|
|
||||||
val options = mapOf(
|
|
||||||
0.0f to "none (94.6% : 5.4%)",
|
|
||||||
1.0f to "very low (93.4% : 4.3%)",
|
|
||||||
2.0f to "very low (91.2% : 2.4%)",
|
|
||||||
4.0f to "low (87.3% : 1.4%)",
|
|
||||||
6.0f to "low (no data)",
|
|
||||||
8.0f to "medium (82.3% : 0.9%)",
|
|
||||||
10.0f to "medium (80.1% : 0.8%)",
|
|
||||||
14.0f to "medium (no data)",
|
|
||||||
18.0f to "high (74.8% : 0.5%)",
|
|
||||||
25.0f to "high (71.6% : 0.4%)",
|
|
||||||
50.0f to "very high (63.5% : 0.3%)",
|
|
||||||
100.0f to "very high (54.7% : 0.2%)"
|
|
||||||
)
|
|
||||||
val names = options.map { "T = ${it.key}" }
|
|
||||||
SettingRadio(
|
|
||||||
title = "Autocorrect Threshold",
|
title = "Autocorrect Threshold",
|
||||||
options = options.keys.toList(),
|
subtitle = "A lower threshold will autocorrect more often (and miscorrect more often), while a higher threshold will autocorrect less often (and miscorrect less often).\nDefault is ${AutocorrectThresholdSetting.default}",
|
||||||
optionNames = names,
|
setting = AutocorrectThresholdSetting,
|
||||||
setting = AutocorrectThresholdSetting
|
range = 0.0f .. 25.0f,
|
||||||
|
hardRange = 0.0f .. 25.0f,
|
||||||
|
transform = {
|
||||||
|
it
|
||||||
|
},
|
||||||
|
indicator = {
|
||||||
|
"T = ${String.format("%.1f", it)}"
|
||||||
|
},
|
||||||
|
power = 2.5f
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,6 @@ package org.futo.inputmethod.latin.uix.settings.pages
|
|||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.booleanResource
|
import androidx.compose.ui.res.booleanResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -13,7 +12,6 @@ import androidx.datastore.preferences.core.intPreferencesKey
|
|||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.futo.inputmethod.latin.R
|
import org.futo.inputmethod.latin.R
|
||||||
import org.futo.inputmethod.latin.settings.Settings
|
import org.futo.inputmethod.latin.settings.Settings
|
||||||
@ -22,11 +20,11 @@ import org.futo.inputmethod.latin.uix.SHOW_EMOJI_SUGGESTIONS
|
|||||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
||||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||||
import org.futo.inputmethod.latin.uix.settings.SettingRadio
|
import org.futo.inputmethod.latin.uix.settings.SettingSlider
|
||||||
import org.futo.inputmethod.latin.uix.settings.SettingToggleDataStore
|
import org.futo.inputmethod.latin.uix.settings.SettingToggleDataStore
|
||||||
import org.futo.inputmethod.latin.uix.settings.SettingToggleSharedPrefs
|
import org.futo.inputmethod.latin.uix.settings.SettingToggleSharedPrefs
|
||||||
import org.futo.inputmethod.latin.uix.settings.useDataStore
|
import org.futo.inputmethod.latin.uix.settings.useDataStore
|
||||||
import org.futo.inputmethod.latin.uix.settings.useSharedPrefsBool
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
val vibrationDurationSetting = SettingsKey(
|
val vibrationDurationSetting = SettingsKey(
|
||||||
intPreferencesKey("vibration_duration"),
|
intPreferencesKey("vibration_duration"),
|
||||||
@ -90,6 +88,19 @@ fun TypingScreen(navController: NavHostController = rememberNavController()) {
|
|||||||
default = booleanResource(R.bool.config_default_key_preview_popup)
|
default = booleanResource(R.bool.config_default_key_preview_popup)
|
||||||
)
|
)
|
||||||
|
|
||||||
SettingRadio(title = "Vibration Duration", options = listOf(-1, 5, 10, 20, 40), optionNames = listOf("Default", "Low", "Medium", "High", "Higher"), setting = vibrationDurationSetting)
|
SettingSlider(
|
||||||
|
title = "Vibration",
|
||||||
|
setting = vibrationDurationSetting,
|
||||||
|
range = -1.0f .. 100.0f,
|
||||||
|
hardRange = -1.0f .. 2000.0f,
|
||||||
|
transform = { it.roundToInt() },
|
||||||
|
indicator = {
|
||||||
|
if(it == -1) {
|
||||||
|
"Default"
|
||||||
|
} else {
|
||||||
|
"$it ms"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user