improve color picker: better landscape layout and survive orientation change

This commit is contained in:
Helium314 2025-02-27 19:35:07 +01:00
parent 1c955a34b2
commit b65d00e142
3 changed files with 91 additions and 70 deletions

View file

@ -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()

View file

@ -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)
)
}

View file

@ -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<ColorSetting?>(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)
}