From b65d00e1428e8cb692c331f4c62d738c7be2a65a Mon Sep 17 00:00:00 2001 From: Helium314 Date: Thu, 27 Feb 2025 19:35:07 +0100 Subject: [PATCH] improve color picker: better landscape layout and survive orientation change --- .../keyboard_parser/floris/TextKeyData.kt | 2 - .../settings/dialogs/ColorPickerDialog.kt | 142 ++++++++++-------- .../keyboard/settings/screens/ColorsScreen.kt | 17 +-- 3 files changed, 91 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt index 0d1a365cf..eff715490 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt @@ -301,8 +301,6 @@ sealed interface KeyData : AbstractKeyData { // idea: directly create PopupKeySpec, but need to deal with needsToUpcase and popupKeysColumnAndFlags fun getPopupLabel(params: KeyboardParams): String { val newLabel = processLabel(params) - if (newLabel == "!") - Log.w("test", "code $code, newCode ${processCode()}") if (code == KeyCode.UNSPECIFIED) { if (newLabel == label) return label val newCode = processCode() diff --git a/app/src/main/java/helium314/keyboard/settings/dialogs/ColorPickerDialog.kt b/app/src/main/java/helium314/keyboard/settings/dialogs/ColorPickerDialog.kt index d17a8bab9..b05dde1b8 100644 --- a/app/src/main/java/helium314/keyboard/settings/dialogs/ColorPickerDialog.kt +++ b/app/src/main/java/helium314/keyboard/settings/dialogs/ColorPickerDialog.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -15,22 +16,24 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Paint import androidx.compose.ui.graphics.PaintingStyle import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalConfiguration 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.unit.dp +import androidx.compose.ui.window.DialogProperties import com.github.skydoves.colorpicker.compose.AlphaSlider import com.github.skydoves.colorpicker.compose.BrightnessSlider import com.github.skydoves.colorpicker.compose.HsvColorPicker import com.github.skydoves.colorpicker.compose.rememberColorPickerController -// todo: needs different layout in landscape (bars on the side or something like that) @Composable fun ColorPickerDialog( onDismissRequest: () -> Unit, @@ -50,70 +53,91 @@ fun ColorPickerDialog( val initialString = initialColor.toUInt().toString(16) var textValue by remember { mutableStateOf(TextFieldValue(initialString, TextRange(initialString.length))) } var currentColor by remember { mutableStateOf(Color(initialColor)) } + val width = LocalConfiguration.current.screenWidthDp + val height = LocalConfiguration.current.screenHeightDp + val useWideLayout = height < 500 && width > height + @Composable fun topBar() { + Row { + Surface( + color = Color(initialColor), + modifier = Modifier.fillMaxWidth(0.5f) + .padding(start = 10.dp) + .height(barHeight)) + { } + Surface( + color = currentColor, + modifier = Modifier.fillMaxWidth() + .padding(end = 10.dp) + .height(barHeight)) + { } + } + } + @Composable fun picker() { + HsvColorPicker( + modifier = Modifier + .size(300.dp) + .padding(10.dp), + controller = controller, + onColorChanged = { + if (it.fromUser) + textValue = TextFieldValue(it.hexCode, selection = TextRange(it.hexCode.length)) + currentColor = it.color + }, + initialColor = Color(initialColor), + ) + } + @Composable fun slidersAndTextField() { + AlphaSlider( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + .height(barHeight), + controller = controller, + initialColor = Color(initialColor), + wheelPaint = wheelPaint + ) + BrightnessSlider( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + .height(barHeight), + controller = controller, + initialColor = Color(initialColor), + wheelPaint = wheelPaint + ) + TextField( + value = textValue, + // todo: KeyboardType.Password is a crappy way of avoiding suggestions... is there really no way in compose? + keyboardOptions = KeyboardOptions(autoCorrectEnabled = false, keyboardType = KeyboardType.Password), + onValueChange = { + textValue = it + val androidColor = runCatching { android.graphics.Color.parseColor("#${it.text}") }.getOrNull() + if (androidColor != null) + controller.selectByColor(Color(androidColor), false) + } + ) + } ThreeButtonAlertDialog( onDismissRequest = onDismissRequest, onConfirmed = { onConfirmed(controller.selectedColor.value.toArgb()) }, title = { Text(title) }, content = { - Column { - Row { - Surface( - color = Color(initialColor), - modifier = Modifier.fillMaxWidth(0.5f) - .padding(start = 10.dp) - .height(barHeight)) - { } - Surface( - color = currentColor, - modifier = Modifier.fillMaxWidth() - .padding(end = 10.dp) - .height(barHeight)) - { } - } - HsvColorPicker( - modifier = Modifier - .fillMaxWidth() - .height(300.dp) - .padding(10.dp), - controller = controller, - onColorChanged = { - if (it.fromUser) - textValue = TextFieldValue(it.hexCode, selection = TextRange(it.hexCode.length)) - currentColor = it.color - }, - initialColor = Color(initialColor), - ) - AlphaSlider( - modifier = Modifier - .fillMaxWidth() - .padding(10.dp) - .height(barHeight), - controller = controller, - initialColor = Color(initialColor), - wheelPaint = wheelPaint - ) - BrightnessSlider( - modifier = Modifier - .fillMaxWidth() - .padding(10.dp) - .height(barHeight), - controller = controller, - initialColor = Color(initialColor), - wheelPaint = wheelPaint - ) - TextField( - value = textValue, - // KeyboardType.Password is a crappy way of avoiding suggestions... is there really no way in compose? - keyboardOptions = KeyboardOptions(autoCorrectEnabled = false, keyboardType = KeyboardType.Password), - onValueChange = { - textValue = it - val androidColor = kotlin.runCatching { android.graphics.Color.parseColor("#${it.text}") }.getOrNull() - if (androidColor != null) - controller.selectByColor(Color(androidColor), false) + if (useWideLayout) + Row(verticalAlignment = Alignment.CenterVertically) { + picker() + Column { + topBar() + slidersAndTextField() } - ) - } - } + } + else + Column { + topBar() + picker() + slidersAndTextField() + } + }, + properties = DialogProperties(usePlatformDefaultWidth = !useWideLayout) ) } diff --git a/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt index eaccc4e5d..0db490666 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt @@ -31,7 +31,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -116,7 +115,8 @@ fun ColorsScreen( else color ?: KeyboardTheme.determineUserColor(userColors, ctx, name, isNight) var newThemeName by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(themeName)) } - var chosenColor: ColorSetting? by remember { mutableStateOf(null) } + var chosenColorString: String by rememberSaveable { mutableStateOf("") } + val chosenColor = runCatching { Json.decodeFromString(chosenColorString) }.getOrNull() val saveLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult val uri = it.data?.data ?: return@rememberLauncherForActivityResult @@ -174,7 +174,7 @@ fun ColorsScreen( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .padding(horizontal = 16.dp, vertical = 8.dp) - .clickable { chosenColor = colorSetting } + .clickable { chosenColorString = Json.encodeToString(colorSetting) } ) { Spacer( modifier = Modifier @@ -204,19 +204,18 @@ fun ColorsScreen( } ) if (chosenColor != null) { - val color = chosenColor!! ColorPickerDialog( - onDismissRequest = { chosenColor = null }, - initialColor = color.displayColor(), - title = color.displayName, + onDismissRequest = { chosenColorString = "" }, + initialColor = chosenColor.displayColor(), + title = chosenColor.displayName, ) { if (moreColors == 2) { val oldColors = KeyboardTheme.readUserAllColors(prefs, themeName) - oldColors[ColorType.valueOf(color.name)] = it + oldColors[ColorType.valueOf(chosenColor.name)] = it KeyboardTheme.writeUserAllColors(prefs, themeName, oldColors) } else { val oldUserColors = KeyboardTheme.readUserColors(prefs, themeName) - val newUserColors = (oldUserColors + ColorSetting(color.name, false, it)) + val newUserColors = (oldUserColors + ColorSetting(chosenColor.name, false, it)) .reversed().distinctBy { it.displayName } KeyboardTheme.writeUserColors(prefs, themeName, newUserColors) }