mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Add slider for long press duration
This commit is contained in:
parent
abda1a3d08
commit
49cbcabf5e
@ -23,7 +23,6 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.ArrowForward
|
import androidx.compose.material.icons.filled.ArrowForward
|
||||||
import androidx.compose.material.icons.filled.Send
|
import androidx.compose.material.icons.filled.Send
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
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
|
||||||
@ -48,6 +47,7 @@ import androidx.compose.ui.focus.focusRequester
|
|||||||
import androidx.compose.ui.focus.onFocusChanged
|
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.SolidColor
|
||||||
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.platform.LocalContext
|
||||||
@ -58,9 +58,7 @@ 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.getSettingBlocking
|
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||||
import org.futo.inputmethod.latin.uix.theme.Typography
|
import org.futo.inputmethod.latin.uix.theme.Typography
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -268,20 +266,22 @@ fun<T> SettingRadio(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun<T: Number> SettingSlider(
|
private fun<T: Number> SettingSliderForDataStoreItem(
|
||||||
title: String,
|
title: String,
|
||||||
setting: SettingsKey<T>,
|
item: DataStoreItem<T>,
|
||||||
|
default: T,
|
||||||
range: ClosedFloatingPointRange<Float>,
|
range: ClosedFloatingPointRange<Float>,
|
||||||
transform: (Float) -> T,
|
transform: (Float) -> T,
|
||||||
indicator: (T) -> String = { it.toString() },
|
indicator: (T) -> String = { it.toString() },
|
||||||
hardRange: ClosedFloatingPointRange<Float> = range,
|
hardRange: ClosedFloatingPointRange<Float> = range,
|
||||||
power: Float = 1.0f,
|
power: Float = 1.0f,
|
||||||
subtitle: String? = null
|
subtitle: String? = null,
|
||||||
|
steps: Int = 0,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val (value, setValue) = useDataStore(key = setting.key, default = setting.default)
|
val (value, setValue) = item
|
||||||
var virtualValue by remember { mutableFloatStateOf((runBlocking { context.getSetting(setting) }).toFloat().let {
|
var virtualValue by remember { mutableFloatStateOf(value.toFloat().let {
|
||||||
if(it == Float.POSITIVE_INFINITY || it == Float.NEGATIVE_INFINITY) {
|
if(it == Float.POSITIVE_INFINITY || it == Float.NEGATIVE_INFINITY) {
|
||||||
it
|
it
|
||||||
} else {
|
} else {
|
||||||
@ -317,7 +317,7 @@ fun<T: Number> SettingSlider(
|
|||||||
val newValue = if (number != null) {
|
val newValue = if (number != null) {
|
||||||
transform(number.coerceIn(hardRange))
|
transform(number.coerceIn(hardRange))
|
||||||
} else {
|
} else {
|
||||||
setting.default
|
default
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(newValue)
|
setValue(newValue)
|
||||||
@ -327,12 +327,13 @@ fun<T: Number> SettingSlider(
|
|||||||
textFieldValue = TextFieldValue()
|
textFieldValue = TextFieldValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = textFieldValue,
|
value = textFieldValue,
|
||||||
onValueChange = { textFieldValue = it },
|
onValueChange = { textFieldValue = it },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(0.33f)
|
.weight(0.33f)
|
||||||
.align(Alignment.CenterVertically)
|
.align(CenterVertically)
|
||||||
.focusRequester(focusRequester)
|
.focusRequester(focusRequester)
|
||||||
.onFocusChanged {
|
.onFocusChanged {
|
||||||
if (it.isFocused) hasTextFieldFocusedYet = true
|
if (it.isFocused) hasTextFieldFocusedYet = true
|
||||||
@ -345,9 +346,9 @@ fun<T: Number> SettingSlider(
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
textStyle = Typography.labelMedium
|
textStyle = Typography.labelMedium.copy(color = MaterialTheme.colorScheme.onBackground),
|
||||||
|
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary)
|
||||||
)
|
)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
text = indicator(value),
|
text = indicator(value),
|
||||||
@ -368,12 +369,68 @@ fun<T: Number> SettingSlider(
|
|||||||
setValue(transform(it.pow(power))) },
|
setValue(transform(it.pow(power))) },
|
||||||
valueRange = range.start.pow(1.0f / power) .. range.endInclusive.pow(1.0f / power),
|
valueRange = range.start.pow(1.0f / power) .. range.endInclusive.pow(1.0f / power),
|
||||||
enabled = !isTextFieldVisible,
|
enabled = !isTextFieldVisible,
|
||||||
modifier = Modifier.weight(1.0f)
|
modifier = Modifier.weight(1.0f),
|
||||||
|
steps = steps
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@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,
|
||||||
|
steps: Int = 0
|
||||||
|
) {
|
||||||
|
SettingSliderForDataStoreItem(
|
||||||
|
title = title,
|
||||||
|
item = useDataStore(setting),
|
||||||
|
default = setting.default,
|
||||||
|
range = range,
|
||||||
|
transform = transform,
|
||||||
|
indicator = indicator,
|
||||||
|
hardRange = hardRange,
|
||||||
|
power = power,
|
||||||
|
subtitle = subtitle,
|
||||||
|
steps = steps
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingSliderSharedPrefsInt(
|
||||||
|
title: String,
|
||||||
|
key: String,
|
||||||
|
default: Int,
|
||||||
|
range: ClosedFloatingPointRange<Float>,
|
||||||
|
transform: (Float) -> Int,
|
||||||
|
indicator: (Int) -> String = { it.toString() },
|
||||||
|
hardRange: ClosedFloatingPointRange<Float> = range,
|
||||||
|
power: Float = 1.0f,
|
||||||
|
subtitle: String? = null,
|
||||||
|
steps: Int = 0
|
||||||
|
) {
|
||||||
|
SettingSliderForDataStoreItem(
|
||||||
|
title = title,
|
||||||
|
item = useSharedPrefsInt(key, default),
|
||||||
|
default = default,
|
||||||
|
range = range,
|
||||||
|
transform = transform,
|
||||||
|
indicator = indicator,
|
||||||
|
hardRange = hardRange,
|
||||||
|
power = power,
|
||||||
|
subtitle = subtitle,
|
||||||
|
steps = steps
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ScrollableList(content: @Composable () -> Unit) {
|
fun ScrollableList(content: @Composable () -> Unit) {
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
@ -4,6 +4,7 @@ import android.content.SharedPreferences
|
|||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@ -80,19 +81,19 @@ fun <T> useDataStore(key: SettingsKey<T>): DataStoreItem<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun useSharedPrefsBool(key: String, default: Boolean): DataStoreItem<Boolean> {
|
fun<T> useSharedPrefsGeneric(key: String, default: T, get: (SharedPreferences, String, T) -> T, put: (SharedPreferences, String, T) -> Unit): DataStoreItem<T> {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val sharedPrefs = remember { PreferenceManager.getDefaultSharedPreferences(context) }
|
val sharedPrefs = remember { PreferenceManager.getDefaultSharedPreferences(context) }
|
||||||
|
|
||||||
val value = remember { mutableStateOf(sharedPrefs.getBoolean(key, default)) }
|
val value = remember { mutableStateOf(get(sharedPrefs, key, default)) }
|
||||||
|
|
||||||
// This is not the most efficient way to do this... but it works for a settings menu
|
// This is not the most efficient way to do this... but it works for a settings menu
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
val listener =
|
val listener =
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, changedKey ->
|
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, changedKey ->
|
||||||
if (key == changedKey) {
|
if (key == changedKey) {
|
||||||
value.value = sharedPreferences.getBoolean(key, value.value)
|
value.value = get(sharedPreferences, key, value.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,15 +104,63 @@ fun useSharedPrefsBool(key: String, default: Boolean): DataStoreItem<Boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val setValue = { newValue: Boolean ->
|
val setValue = { newValue: T ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
sharedPrefs.edit {
|
put(sharedPrefs, key, newValue)
|
||||||
putBoolean(key, newValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return DataStoreItem(value.value, setValue)
|
return DataStoreItem(value.value, setValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun useSharedPrefsBool(key: String, default: Boolean): DataStoreItem<Boolean> {
|
||||||
|
return useSharedPrefsGeneric(key, default,
|
||||||
|
get = { sharedPreferences, k, d ->
|
||||||
|
sharedPreferences.getBoolean(k, d)
|
||||||
|
},
|
||||||
|
put = { sharedPreferences, k, v ->
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putBoolean(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun useSharedPrefsInt(key: String, default: Int): DataStoreItem<Int> {
|
||||||
|
return useSharedPrefsGeneric(key, default,
|
||||||
|
get = { sharedPreferences, k, d ->
|
||||||
|
sharedPreferences.getInt(k, d)
|
||||||
|
},
|
||||||
|
put = { sharedPreferences, k, v ->
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putInt(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun<T> SyncDataStoreToPreferences(key: SettingsKey<T>, update: (newValue: T, editor: SharedPreferences.Editor) -> Unit) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val sharedPrefs = remember { PreferenceManager.getDefaultSharedPreferences(context) }
|
||||||
|
val value = useDataStoreValueBlocking(key)
|
||||||
|
|
||||||
|
LaunchedEffect(value) {
|
||||||
|
val edit = sharedPrefs.edit {
|
||||||
|
update(value, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SyncDataStoreToPreferencesInt(key: SettingsKey<Int>, sharedPreference: String) {
|
||||||
|
SyncDataStoreToPreferences(key) { value, editor ->
|
||||||
|
editor.putInt(sharedPreference, value)
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,6 +21,7 @@ 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.SettingSlider
|
import org.futo.inputmethod.latin.uix.settings.SettingSlider
|
||||||
|
import org.futo.inputmethod.latin.uix.settings.SettingSliderSharedPrefsInt
|
||||||
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
|
||||||
@ -107,5 +108,16 @@ fun TypingScreen(navController: NavHostController = rememberNavController()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SettingSliderSharedPrefsInt(
|
||||||
|
title = "Long Press Duration",
|
||||||
|
key = Settings.PREF_KEY_LONGPRESS_TIMEOUT,
|
||||||
|
default = 300,
|
||||||
|
range = 100.0f .. 700.0f,
|
||||||
|
hardRange = 25.0f .. 1200.0f,
|
||||||
|
transform = { it.roundToInt() },
|
||||||
|
indicator = { "$it ms" },
|
||||||
|
steps = 23
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user