feat: 自定义主题色支持直接输入颜色的十六进制
This commit is contained in:
parent
b18571c1e5
commit
fe0c667af5
|
|
@ -1,6 +1,8 @@
|
|||
package com.huanchengfly.tieba.post.ui.page.settings.theme
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
|
|
@ -15,17 +17,24 @@ 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.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Checkbox
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.OutlinedTextField
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.BorderColor
|
||||
import androidx.compose.material.icons.rounded.Check
|
||||
import androidx.compose.material.icons.rounded.ColorLens
|
||||
import androidx.compose.material.icons.rounded.Colorize
|
||||
|
|
@ -34,6 +43,7 @@ import androidx.compose.material.icons.rounded.PhotoSizeSelectActual
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -47,7 +57,9 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.stringArrayResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import com.github.panpf.sketch.compose.AsyncImage
|
||||
import com.github.panpf.sketch.fetch.newFileUri
|
||||
|
|
@ -74,6 +86,7 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.TitleCentredToolbar
|
|||
import com.huanchengfly.tieba.post.ui.widgets.compose.rememberDialogState
|
||||
import com.huanchengfly.tieba.post.utils.ThemeUtil
|
||||
import com.huanchengfly.tieba.post.utils.appPreferences
|
||||
import com.huanchengfly.tieba.post.utils.extension.toHexString
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
|
||||
|
|
@ -119,22 +132,96 @@ fun AppThemePage(
|
|||
dialogState = customPrimaryColorDialogState,
|
||||
title = { Text(text = stringResource(id = R.string.title_custom_theme)) },
|
||||
content = {
|
||||
var useInput by remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = useInput,
|
||||
label = "",
|
||||
modifier = Modifier
|
||||
.wrapContentHeight()
|
||||
.animateContentSize()
|
||||
) { input ->
|
||||
if (input) {
|
||||
var inputHexColor by remember { mutableStateOf(customPrimaryColor.toHexString()) }
|
||||
val lastValidColor by produceState(
|
||||
initialValue = customPrimaryColor,
|
||||
inputHexColor
|
||||
) {
|
||||
if ("^#([0-9a-fA-F]{6})$".toRegex().matches(inputHexColor)) {
|
||||
value = Color(inputHexColor.toColorInt())
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clip(CircleShape)
|
||||
.background(lastValidColor)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = inputHexColor,
|
||||
onValueChange = {
|
||||
if ("^#([0-9a-fA-F]{0,6})$".toRegex().matches(it)) {
|
||||
inputHexColor = it
|
||||
}
|
||||
},
|
||||
maxLines = 1,
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = TextFieldDefaults.outlinedTextFieldColors(
|
||||
cursorColor = ExtendedTheme.colors.primary,
|
||||
focusedBorderColor = ExtendedTheme.colors.primary,
|
||||
focusedLabelColor = ExtendedTheme.colors.primary
|
||||
)
|
||||
)
|
||||
IconButton(
|
||||
onClick = {
|
||||
customPrimaryColor = Color(inputHexColor.toColorInt())
|
||||
useInput = false
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Check,
|
||||
contentDescription = stringResource(id = R.string.button_sure_default)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Box {
|
||||
HarmonyColorPicker(
|
||||
harmonyMode = ColorHarmonyMode.ANALOGOUS,
|
||||
color = HsvColor.from(customPrimaryColor),
|
||||
onColorChanged = {
|
||||
customPrimaryColor = it.toColor()
|
||||
},
|
||||
modifier = Modifier.size(350.dp)
|
||||
modifier = Modifier.sizeIn(maxWidth = 320.dp, maxHeight = 320.dp)
|
||||
)
|
||||
|
||||
IconButton(
|
||||
onClick = { useInput = true },
|
||||
modifier = Modifier.align(Alignment.TopEnd)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.BorderColor,
|
||||
contentDescription = stringResource(id = R.string.desc_input_color)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.huanchengfly.tieba.post.ui.widgets.compose
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
|
@ -8,6 +9,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
|
|
@ -29,7 +31,6 @@ import androidx.compose.runtime.saveable.listSaver
|
|||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
|
|
@ -39,6 +40,9 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import androidx.constraintlayout.compose.Visibility
|
||||
import com.huanchengfly.tieba.post.R
|
||||
import com.huanchengfly.tieba.post.arch.BaseComposeActivity.Companion.LocalWindowSizeClass
|
||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||
|
|
@ -239,7 +243,6 @@ fun ConfirmDialog(
|
|||
*
|
||||
* @param onValueChange 输入框内容变化时的回调,返回true表示允许变化,false表示不允许变化
|
||||
*/
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun PromptDialog(
|
||||
onConfirm: (String) -> Unit,
|
||||
|
|
@ -361,8 +364,11 @@ fun Dialog(
|
|||
dismissOnClickOutside = cancelableOnTouchOutside
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
ProvideContentColor(color = ExtendedTheme.colors.text) {
|
||||
ConstraintLayout(
|
||||
modifier = modifier
|
||||
.wrapContentHeight()
|
||||
.animateContentSize()
|
||||
.fillMaxWidth(
|
||||
fraction = if (windowWidthSizeClass == WindowWidthSizeClass.Compact) {
|
||||
1f
|
||||
|
|
@ -376,9 +382,22 @@ fun Dialog(
|
|||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
.padding(vertical = 24.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
ProvideContentColor(color = ExtendedTheme.colors.text) {
|
||||
val (titleRef, contentRef, buttonsRef) = createRefs()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.constrainAs(titleRef) {
|
||||
top.linkTo(parent.top)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
width = Dimension.fillToConstraints
|
||||
visibility = if (title == null) {
|
||||
Visibility.Gone
|
||||
} else {
|
||||
Visibility.Visible
|
||||
}
|
||||
}
|
||||
) {
|
||||
if (title != null) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
|
@ -390,11 +409,27 @@ fun Dialog(
|
|||
}
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.constrainAs(contentRef) {
|
||||
top.linkTo(titleRef.bottom, margin = 16.dp, goneMargin = 0.dp)
|
||||
bottom.linkTo(buttonsRef.top, margin = 16.dp, goneMargin = 0.dp)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
height = Dimension.preferredWrapContent
|
||||
}
|
||||
) {
|
||||
dialogScope.content()
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.constrainAs(buttonsRef) {
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
bottom.linkTo(parent.bottom)
|
||||
width = Dimension.fillToConstraints
|
||||
}
|
||||
.padding(horizontal = 24.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package com.huanchengfly.tieba.post.utils.extension
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
|
||||
fun Color.toHexString(): String {
|
||||
return "#${Integer.toHexString(toArgb()).substring(2)}"
|
||||
}
|
||||
|
|
@ -517,4 +517,5 @@
|
|||
<string name="desc_show">显示</string>
|
||||
<string name="title_settings_status_bar_darker">状态栏遮罩</string>
|
||||
<string name="summary_settings_status_bar_darker">开启后非白色主题状态栏将略微变暗</string>
|
||||
<string name="desc_input_color">手动输入颜色</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue