refactor more bottom sheets
This commit is contained in:
@@ -1,16 +1,22 @@
|
|||||||
package de.mm20.launcher2.ui.common
|
package de.mm20.launcher2.ui.common
|
||||||
|
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.requiredWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.DockedSearchBar
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.SearchBarDefaults
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -18,6 +24,8 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawBehind
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@@ -32,81 +40,122 @@ import de.mm20.launcher2.ui.ktx.toPixels
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SearchablePicker(
|
fun SearchablePicker(
|
||||||
|
expanded: Boolean,
|
||||||
value: SavableSearchable?,
|
value: SavableSearchable?,
|
||||||
onValueChanged: (SavableSearchable?) -> Unit,
|
onValueChanged: (SavableSearchable?) -> Unit,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val viewModel: SearchablePickerVM = viewModel()
|
DismissableBottomSheet(expanded = expanded, onDismissRequest = onDismissRequest) {
|
||||||
|
val viewModel: SearchablePickerVM = viewModel()
|
||||||
|
|
||||||
DismissableBottomSheet(onDismissRequest = onDismissRequest) {
|
val colorSurface = MaterialTheme.colorScheme.surfaceContainerLow
|
||||||
Column(
|
|
||||||
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize(),
|
||||||
.padding(it)
|
contentPadding = PaddingValues(
|
||||||
) {
|
start = 16.dp,
|
||||||
OutlinedTextField(
|
end = 16.dp,
|
||||||
modifier = Modifier
|
bottom = 16.dp + WindowInsets.navigationBars.asPaddingValues()
|
||||||
.fillMaxWidth()
|
.calculateBottomPadding(),
|
||||||
.padding(bottom = 12.dp),
|
top = 16.dp,
|
||||||
value = viewModel.searchQuery,
|
|
||||||
onValueChange = { viewModel.onSearchQueryChanged(it) },
|
|
||||||
leadingIcon = {
|
|
||||||
Icon(painterResource(R.drawable.search_24px), null)
|
|
||||||
},
|
|
||||||
placeholder = {
|
|
||||||
Text(stringResource(R.string.search_bar_placeholder))
|
|
||||||
},
|
|
||||||
singleLine = true,
|
|
||||||
)
|
)
|
||||||
LazyColumn(
|
) {
|
||||||
modifier = Modifier
|
stickyHeader {
|
||||||
.weight(1f)
|
DockedSearchBar(
|
||||||
.fillMaxWidth(),
|
modifier = Modifier
|
||||||
) {
|
.fillMaxWidth()
|
||||||
items(viewModel.items) {
|
.drawBehind {
|
||||||
val iconSize = 32.dp.toPixels()
|
drawRect(
|
||||||
val icon by remember(it.key) {
|
brush = Brush.verticalGradient(
|
||||||
viewModel.getIcon(
|
0.5f to colorSurface,
|
||||||
it,
|
0.5f to colorSurface.copy(alpha = 0f),
|
||||||
iconSize.toInt()
|
|
||||||
)
|
|
||||||
}.collectAsStateWithLifecycle(null)
|
|
||||||
val selected = it.key == value?.key
|
|
||||||
Surface(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 4.dp),
|
|
||||||
shape = MaterialTheme.shapes.small,
|
|
||||||
border = BorderStroke(1.dp, if (selected) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.outline),
|
|
||||||
color = if (selected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface,
|
|
||||||
onClick = { onValueChanged(it) }) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
ShapedLauncherIcon(
|
|
||||||
icon = { icon },
|
|
||||||
size = 32.dp,
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = it.label,
|
|
||||||
modifier = Modifier.weight(1f).padding(horizontal = 16.dp),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
if (selected) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.check_circle_24px_filled),
|
|
||||||
contentDescription = null,
|
|
||||||
tint = MaterialTheme.colorScheme.secondary,
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
.padding(bottom = 16.dp),
|
||||||
|
expanded = false,
|
||||||
|
onExpandedChange = {},
|
||||||
|
inputField = {
|
||||||
|
SearchBarDefaults.InputField(
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.search_24px),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
if (viewModel.searchQuery.isNotEmpty()) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
viewModel.onSearchQueryChanged("")
|
||||||
|
}) {
|
||||||
|
Icon(painterResource(R.drawable.close_24px), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSearch = {},
|
||||||
|
expanded = false,
|
||||||
|
onExpandedChange = {},
|
||||||
|
query = viewModel.searchQuery,
|
||||||
|
onQueryChange = {
|
||||||
|
viewModel.onSearchQueryChanged(it)
|
||||||
|
},
|
||||||
|
placeholder = {
|
||||||
|
Text(stringResource(R.string.search_bar_placeholder))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items(viewModel.items) {
|
||||||
|
val iconSize = 32.dp.toPixels()
|
||||||
|
val icon by remember(it.key) {
|
||||||
|
viewModel.getIcon(
|
||||||
|
it,
|
||||||
|
iconSize.toInt()
|
||||||
|
)
|
||||||
|
}.collectAsStateWithLifecycle(null)
|
||||||
|
val selected = it.key == value?.key
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 4.dp),
|
||||||
|
shape = MaterialTheme.shapes.small,
|
||||||
|
border = BorderStroke(
|
||||||
|
1.dp,
|
||||||
|
if (selected) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.outline
|
||||||
|
),
|
||||||
|
color = if (selected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface,
|
||||||
|
onClick = { onValueChanged(it) }) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
ShapedLauncherIcon(
|
||||||
|
icon = { icon },
|
||||||
|
size = 32.dp,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = it.label,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
if (selected) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.check_circle_24px_filled),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.secondary,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ import kotlinx.coroutines.CancellationException
|
|||||||
fun DismissableBottomSheet(
|
fun DismissableBottomSheet(
|
||||||
expanded: Boolean = true,
|
expanded: Boolean = true,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
content: @Composable (contentPadding: PaddingValues) -> Unit,
|
content: @Composable (contentPadding: PaddingValues) -> Unit,
|
||||||
) {
|
) {
|
||||||
DismissableBottomSheet(
|
DismissableBottomSheet(
|
||||||
state = expanded,
|
state = expanded,
|
||||||
|
|||||||
@@ -272,19 +272,18 @@ fun CustomizeSearchableSheet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pickIcon) {
|
DismissableBottomSheet(
|
||||||
DismissableBottomSheet(
|
expanded = pickIcon,
|
||||||
onDismissRequest = { viewModel.closeIconPicker() },
|
onDismissRequest = { viewModel.closeIconPicker() },
|
||||||
) {
|
) {
|
||||||
IconPicker(
|
IconPicker(
|
||||||
searchable = searchable,
|
searchable = searchable,
|
||||||
onSelect = {
|
onSelect = {
|
||||||
viewModel.pickIcon(it)
|
viewModel.pickIcon(it)
|
||||||
viewModel.closeIconPicker()
|
viewModel.closeIconPicker()
|
||||||
},
|
},
|
||||||
contentPadding = it,
|
contentPadding = it,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.heightIn
|
import androidx.compose.foundation.layout.heightIn
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
@@ -123,19 +124,18 @@ fun NotesWidget(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if (showConflictResolveSheet) {
|
NoteWidgetConflictResolveSheet(
|
||||||
NoteWidgetConflictResolveSheet(
|
expanded = showConflictResolveSheet,
|
||||||
localContent = widget.config.storedText,
|
localContent = widget.config.storedText,
|
||||||
fileContent = text.text,
|
fileContent = text.text,
|
||||||
onResolve = {
|
onResolve = {
|
||||||
viewModel.resolveFileContentConflict(context, it)
|
viewModel.resolveFileContentConflict(context, it)
|
||||||
showConflictResolveSheet = false
|
showConflictResolveSheet = false
|
||||||
},
|
},
|
||||||
onDismissRequest = {
|
onDismissRequest = {
|
||||||
showConflictResolveSheet = false
|
showConflictResolveSheet = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Column {
|
Column {
|
||||||
@@ -374,44 +374,44 @@ fun NotesWidget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readWriteErrorSheetText != null) {
|
NoteReadWriteErrorSheet(
|
||||||
NoteReadWriteErrorSheet(
|
message = readWriteErrorSheetText,
|
||||||
message = readWriteErrorSheetText!!,
|
onDismiss = { readWriteErrorSheetText = null },
|
||||||
onDismiss = { readWriteErrorSheetText = null },
|
onRelink = {
|
||||||
onRelink = {
|
linkFileLauncher.launch(
|
||||||
linkFileLauncher.launch(
|
context.getString(
|
||||||
context.getString(
|
R.string.notes_widget_export_filename,
|
||||||
R.string.notes_widget_export_filename,
|
ZonedDateTime.now().format(
|
||||||
ZonedDateTime.now().format(
|
DateTimeFormatter.ISO_INSTANT
|
||||||
DateTimeFormatter.ISO_INSTANT
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
)
|
||||||
onUnlink = {
|
},
|
||||||
viewModel.unlinkFile(context)
|
onUnlink = {
|
||||||
}
|
viewModel.unlinkFile(context)
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NoteWidgetConflictResolveSheet(
|
fun NoteWidgetConflictResolveSheet(
|
||||||
|
expanded: Boolean,
|
||||||
localContent: String,
|
localContent: String,
|
||||||
fileContent: String,
|
fileContent: String,
|
||||||
onResolve: (LinkedFileConflictStrategy) -> Unit,
|
onResolve: (LinkedFileConflictStrategy) -> Unit,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
) {
|
) {
|
||||||
var selectedStrategy by remember { mutableStateOf<LinkedFileConflictStrategy?>(null) }
|
|
||||||
DismissableBottomSheet(
|
DismissableBottomSheet(
|
||||||
|
expanded = expanded,
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
|
|
||||||
) {
|
) {
|
||||||
|
var selectedStrategy by remember { mutableStateOf<LinkedFileConflictStrategy?>(null) }
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(it),
|
.padding(16.dp)
|
||||||
|
.navigationBarsPadding(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
@@ -538,19 +538,24 @@ fun SelectableNoteContent(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NoteReadWriteErrorSheet(
|
fun NoteReadWriteErrorSheet(
|
||||||
message: String,
|
message: String?,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onRelink: () -> Unit,
|
onRelink: () -> Unit,
|
||||||
onUnlink: () -> Unit,
|
onUnlink: () -> Unit,
|
||||||
) {
|
) {
|
||||||
DismissableBottomSheet(
|
DismissableBottomSheet(
|
||||||
|
state = message,
|
||||||
|
expanded = { it != null },
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
) {
|
) { message ->
|
||||||
|
message ?: return@DismissableBottomSheet
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(it)
|
.padding(16.dp)
|
||||||
|
.navigationBarsPadding()
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = message,
|
text = message,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.compose.foundation.clickable
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
@@ -51,7 +52,8 @@ fun CorePaletteColorPreference(
|
|||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier.fillMaxWidth()
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.clip(MaterialTheme.shapes.extraSmall)
|
.clip(MaterialTheme.shapes.extraSmall)
|
||||||
.clickable(
|
.clickable(
|
||||||
onClick = { showDialog = true },
|
onClick = { showDialog = true },
|
||||||
@@ -62,7 +64,9 @@ fun CorePaletteColorPreference(
|
|||||||
) {
|
) {
|
||||||
ColorSwatch(
|
ColorSwatch(
|
||||||
color = Color(value ?: defaultValue),
|
color = Color(value ?: defaultValue),
|
||||||
modifier = Modifier.padding(end = 20.dp).size(48.dp),
|
modifier = Modifier
|
||||||
|
.padding(end = 20.dp)
|
||||||
|
.size(48.dp),
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
@@ -74,78 +78,79 @@ fun CorePaletteColorPreference(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showDialog) {
|
var currentValue by remember { mutableStateOf(value) }
|
||||||
var currentValue by remember { mutableStateOf(value) }
|
DismissableBottomSheet(
|
||||||
DismissableBottomSheet(onDismissRequest = {
|
expanded = showDialog,
|
||||||
|
onDismissRequest = {
|
||||||
onValueChange(currentValue)
|
onValueChange(currentValue)
|
||||||
showDialog = false
|
showDialog = false
|
||||||
}) {
|
}) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(it)
|
.padding(16.dp)
|
||||||
) {
|
.navigationBarsPadding()
|
||||||
SwitchPreference(
|
) {
|
||||||
icon = R.drawable.rule_settings_24px,
|
SwitchPreference(
|
||||||
title = stringResource(R.string.theme_color_scheme_system_default),
|
icon = R.drawable.rule_settings_24px,
|
||||||
value = currentValue == null,
|
title = stringResource(R.string.theme_color_scheme_system_default),
|
||||||
onValueChanged = {
|
value = currentValue == null,
|
||||||
currentValue = if (it) null else defaultValue
|
onValueChanged = {
|
||||||
},
|
currentValue = if (it) null else defaultValue
|
||||||
containerColor = Color.Transparent,
|
},
|
||||||
|
containerColor = Color.Transparent,
|
||||||
|
)
|
||||||
|
AnimatedVisibility(
|
||||||
|
currentValue != null,
|
||||||
|
enter = expandVertically(
|
||||||
|
expandFrom = Alignment.Top,
|
||||||
|
),
|
||||||
|
exit = shrinkVertically(
|
||||||
|
shrinkTowards = Alignment.Top,
|
||||||
)
|
)
|
||||||
AnimatedVisibility(
|
) {
|
||||||
currentValue != null,
|
Column {
|
||||||
enter = expandVertically(
|
HorizontalDivider(
|
||||||
expandFrom = Alignment.Top,
|
modifier = Modifier.padding(bottom = 24.dp)
|
||||||
),
|
|
||||||
exit = shrinkVertically(
|
|
||||||
shrinkTowards = Alignment.Top,
|
|
||||||
)
|
)
|
||||||
) {
|
val colorPickerState = rememberHctColorPickerState(
|
||||||
Column {
|
initialColor = Color(value ?: defaultValue),
|
||||||
|
onColorChanged = {
|
||||||
|
currentValue = it.toArgb()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
HctColorPicker(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.align(Alignment.CenterHorizontally),
|
||||||
|
state = colorPickerState,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (autoGenerate != null) {
|
||||||
HorizontalDivider(
|
HorizontalDivider(
|
||||||
modifier = Modifier.padding(bottom = 24.dp)
|
modifier = Modifier.padding(top = 16.dp)
|
||||||
)
|
)
|
||||||
val colorPickerState = rememberHctColorPickerState(
|
|
||||||
initialColor = Color(value ?: defaultValue),
|
TextButton(
|
||||||
onColorChanged = {
|
|
||||||
currentValue = it.toArgb()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
HctColorPicker(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.padding(top = 8.dp)
|
||||||
.align(Alignment.CenterHorizontally),
|
.align(Alignment.End),
|
||||||
state = colorPickerState,
|
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
||||||
)
|
onClick = {
|
||||||
|
val autoGenerated = autoGenerate()
|
||||||
if (autoGenerate != null) {
|
currentValue = autoGenerated
|
||||||
HorizontalDivider(
|
if (autoGenerated != null) {
|
||||||
modifier = Modifier.padding(top = 16.dp)
|
colorPickerState.setColor(Color(autoGenerated))
|
||||||
)
|
|
||||||
|
|
||||||
TextButton(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 8.dp)
|
|
||||||
.align(Alignment.End),
|
|
||||||
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
|
||||||
onClick = {
|
|
||||||
val autoGenerated = autoGenerate()
|
|
||||||
currentValue = autoGenerated
|
|
||||||
if (autoGenerated != null) {
|
|
||||||
colorPickerState.setColor(Color(autoGenerated))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.wand_stars_20px), null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(ButtonDefaults.IconSpacing)
|
|
||||||
.size(ButtonDefaults.IconSize)
|
|
||||||
)
|
|
||||||
Text(stringResource(R.string.theme_color_scheme_autogenerate))
|
|
||||||
}
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.wand_stars_20px), null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(ButtonDefaults.IconSpacing)
|
||||||
|
.size(ButtonDefaults.IconSize)
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.theme_color_scheme_autogenerate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Row
|
|||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
@@ -74,7 +75,8 @@ fun ThemeColorPreference(
|
|||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier.fillMaxWidth()
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.clip(MaterialTheme.shapes.extraSmall)
|
.clip(MaterialTheme.shapes.extraSmall)
|
||||||
.clickable(
|
.clickable(
|
||||||
onClick = { showDialog = true },
|
onClick = { showDialog = true },
|
||||||
@@ -85,7 +87,9 @@ fun ThemeColorPreference(
|
|||||||
) {
|
) {
|
||||||
ColorSwatch(
|
ColorSwatch(
|
||||||
color = Color((value ?: defaultValue).get(corePalette)),
|
color = Color((value ?: defaultValue).get(corePalette)),
|
||||||
modifier = Modifier.padding(end = 20.dp).size(48.dp),
|
modifier = Modifier
|
||||||
|
.padding(end = 20.dp)
|
||||||
|
.size(48.dp),
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
@@ -97,337 +101,338 @@ fun ThemeColorPreference(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showDialog) {
|
var currentValue by remember { mutableStateOf(value) }
|
||||||
var currentValue by remember { mutableStateOf(value) }
|
|
||||||
|
|
||||||
val actualValue = currentValue ?: defaultValue
|
DismissableBottomSheet(
|
||||||
DismissableBottomSheet(onDismissRequest = {
|
expanded = showDialog,
|
||||||
|
onDismissRequest = {
|
||||||
onValueChange(currentValue)
|
onValueChange(currentValue)
|
||||||
showDialog = false
|
showDialog = false
|
||||||
}) {
|
}) {
|
||||||
Column(
|
val actualValue = currentValue ?: defaultValue
|
||||||
modifier = Modifier
|
Column(
|
||||||
.fillMaxWidth()
|
modifier = Modifier
|
||||||
.verticalScroll(rememberScrollState())
|
.fillMaxWidth()
|
||||||
.padding(it),
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp)
|
||||||
|
.navigationBarsPadding(),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween)
|
||||||
) {
|
) {
|
||||||
Row(
|
ToggleButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.weight(1f),
|
||||||
horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween)
|
checked = actualValue is ColorRef,
|
||||||
|
onCheckedChange = {
|
||||||
|
if (actualValue is ColorRef) return@ToggleButton
|
||||||
|
currentValue = defaultValue
|
||||||
|
},
|
||||||
|
shapes = ButtonGroupDefaults.connectedLeadingButtonShapes()
|
||||||
) {
|
) {
|
||||||
ToggleButton(
|
Icon(
|
||||||
modifier = Modifier.weight(1f),
|
painterResource(
|
||||||
checked = actualValue is ColorRef,
|
if (actualValue is ColorRef) R.drawable.check_20px else R.drawable.palette_20px
|
||||||
onCheckedChange = {
|
),
|
||||||
if (actualValue is ColorRef) return@ToggleButton
|
null,
|
||||||
currentValue = defaultValue
|
modifier = Modifier
|
||||||
},
|
.padding(end = ToggleButtonDefaults.IconSpacing)
|
||||||
shapes = ButtonGroupDefaults.connectedLeadingButtonShapes()
|
.size(ToggleButtonDefaults.IconSize)
|
||||||
) {
|
)
|
||||||
Icon(
|
Text(stringResource(R.string.theme_color_scheme_palette_color))
|
||||||
painterResource(
|
|
||||||
if (actualValue is ColorRef) R.drawable.check_20px else R.drawable.palette_20px
|
|
||||||
),
|
|
||||||
null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = ToggleButtonDefaults.IconSpacing)
|
|
||||||
.size(ToggleButtonDefaults.IconSize)
|
|
||||||
)
|
|
||||||
Text(stringResource(R.string.theme_color_scheme_palette_color))
|
|
||||||
}
|
|
||||||
ToggleButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
checked = actualValue is StaticColor,
|
|
||||||
onCheckedChange = {
|
|
||||||
currentValue = StaticColor(actualValue.get(corePalette))
|
|
||||||
},
|
|
||||||
shapes = ButtonGroupDefaults.connectedTrailingButtonShapes()
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(
|
|
||||||
if (actualValue is StaticColor) R.drawable.check_20px else R.drawable.colorize_20px
|
|
||||||
),
|
|
||||||
null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = ToggleButtonDefaults.IconSpacing)
|
|
||||||
.size(ToggleButtonDefaults.IconSize)
|
|
||||||
)
|
|
||||||
Text(stringResource(R.string.theme_color_scheme_custom_color))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AnimatedContent(
|
ToggleButton(
|
||||||
actualValue,
|
modifier = Modifier.weight(1f),
|
||||||
label = "AnimatedContent",
|
checked = actualValue is StaticColor,
|
||||||
contentKey = { it is StaticColor }
|
onCheckedChange = {
|
||||||
) { themeColor ->
|
currentValue = StaticColor(actualValue.get(corePalette))
|
||||||
Column {
|
},
|
||||||
if (themeColor is StaticColor) {
|
shapes = ButtonGroupDefaults.connectedTrailingButtonShapes()
|
||||||
val colorPickerState = rememberHctColorPickerState(
|
) {
|
||||||
initialColor = Color(themeColor.color),
|
Icon(
|
||||||
onColorChanged = {
|
painterResource(
|
||||||
currentValue = StaticColor(it.toArgb())
|
if (actualValue is StaticColor) R.drawable.check_20px else R.drawable.colorize_20px
|
||||||
}
|
),
|
||||||
)
|
null,
|
||||||
HctColorPicker(
|
modifier = Modifier
|
||||||
modifier = Modifier
|
.padding(end = ToggleButtonDefaults.IconSpacing)
|
||||||
.fillMaxWidth()
|
.size(ToggleButtonDefaults.IconSize)
|
||||||
.padding(top = 24.dp)
|
)
|
||||||
.align(Alignment.CenterHorizontally),
|
Text(stringResource(R.string.theme_color_scheme_custom_color))
|
||||||
state = colorPickerState
|
}
|
||||||
)
|
}
|
||||||
} else if (themeColor is ColorRef) {
|
AnimatedContent(
|
||||||
val hct = Hct.fromInt(corePalette.get(themeColor.color))
|
actualValue,
|
||||||
val hue = hct.hue.toFloat()
|
label = "AnimatedContent",
|
||||||
val chroma = hct.chroma.toFloat()
|
contentKey = { it is StaticColor }
|
||||||
var tone by remember(value == null) { mutableStateOf(themeColor.tone.toFloat()) }
|
) { themeColor ->
|
||||||
Row(
|
Column {
|
||||||
modifier = Modifier.padding(top = 24.dp, bottom = 8.dp)
|
if (themeColor is StaticColor) {
|
||||||
) {
|
val colorPickerState = rememberHctColorPickerState(
|
||||||
ColorSwatch(
|
initialColor = Color(themeColor.color),
|
||||||
color = Color(
|
onColorChanged = {
|
||||||
corePalette
|
currentValue = StaticColor(it.toArgb())
|
||||||
.get(CorePaletteColor.Primary)
|
|
||||||
.atTone(tone.toInt())
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.size(64.dp)
|
|
||||||
.clickable {
|
|
||||||
currentValue = ColorRef(
|
|
||||||
CorePaletteColor.Primary,
|
|
||||||
tone.roundToInt()
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selected = themeColor.color == CorePaletteColor.Primary,
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
ColorSwatch(
|
|
||||||
color = Color(
|
|
||||||
corePalette
|
|
||||||
.get(CorePaletteColor.Secondary)
|
|
||||||
.atTone(tone.toInt())
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.size(64.dp)
|
|
||||||
.clickable {
|
|
||||||
currentValue = ColorRef(
|
|
||||||
CorePaletteColor.Secondary,
|
|
||||||
tone.roundToInt()
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selected = themeColor.color == CorePaletteColor.Secondary,
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
ColorSwatch(
|
|
||||||
color = Color(
|
|
||||||
corePalette
|
|
||||||
.get(CorePaletteColor.Tertiary)
|
|
||||||
.atTone(tone.toInt())
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.size(64.dp)
|
|
||||||
.clickable {
|
|
||||||
currentValue = ColorRef(
|
|
||||||
CorePaletteColor.Tertiary,
|
|
||||||
tone.roundToInt()
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selected = themeColor.color == CorePaletteColor.Tertiary,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Row(
|
)
|
||||||
modifier = Modifier.padding(bottom = 16.dp)
|
HctColorPicker(
|
||||||
) {
|
modifier = Modifier
|
||||||
ColorSwatch(
|
.fillMaxWidth()
|
||||||
color = Color(
|
.padding(top = 24.dp)
|
||||||
corePalette
|
.align(Alignment.CenterHorizontally),
|
||||||
.get(CorePaletteColor.Neutral)
|
state = colorPickerState
|
||||||
.atTone(tone.toInt())
|
)
|
||||||
),
|
} else if (themeColor is ColorRef) {
|
||||||
modifier = Modifier
|
val hct = Hct.fromInt(corePalette.get(themeColor.color))
|
||||||
.padding(8.dp)
|
val hue = hct.hue.toFloat()
|
||||||
.size(64.dp)
|
val chroma = hct.chroma.toFloat()
|
||||||
.clickable {
|
var tone by remember(value == null) { mutableStateOf(themeColor.tone.toFloat()) }
|
||||||
currentValue = ColorRef(
|
Row(
|
||||||
CorePaletteColor.Neutral,
|
modifier = Modifier.padding(top = 24.dp, bottom = 8.dp)
|
||||||
tone.roundToInt()
|
) {
|
||||||
)
|
ColorSwatch(
|
||||||
},
|
color = Color(
|
||||||
selected = themeColor.color == CorePaletteColor.Neutral,
|
corePalette
|
||||||
)
|
.get(CorePaletteColor.Primary)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
.atTone(tone.toInt())
|
||||||
ColorSwatch(
|
),
|
||||||
color = Color(
|
|
||||||
corePalette
|
|
||||||
.get(CorePaletteColor.NeutralVariant)
|
|
||||||
.atTone(tone.toInt())
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.size(64.dp)
|
|
||||||
.clickable {
|
|
||||||
currentValue = ColorRef(
|
|
||||||
CorePaletteColor.NeutralVariant,
|
|
||||||
tone.roundToInt()
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selected = themeColor.color == CorePaletteColor.NeutralVariant,
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
ColorSwatch(
|
|
||||||
color = Color(
|
|
||||||
corePalette
|
|
||||||
.get(CorePaletteColor.Error)
|
|
||||||
.atTone(tone.toInt())
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.size(64.dp)
|
|
||||||
.clickable {
|
|
||||||
currentValue = ColorRef(
|
|
||||||
CorePaletteColor.Error,
|
|
||||||
tone.roundToInt()
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selected = themeColor.color == CorePaletteColor.Error,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.padding(8.dp)
|
||||||
.padding(top = 16.dp)
|
.size(64.dp)
|
||||||
) {
|
.clickable {
|
||||||
Text(
|
currentValue = ColorRef(
|
||||||
text = "T",
|
CorePaletteColor.Primary,
|
||||||
modifier = Modifier.width(32.dp),
|
tone.roundToInt()
|
||||||
style = MaterialTheme.typography.labelMedium,
|
)
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
Slider(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
value = tone,
|
|
||||||
valueRange = 0f..100f,
|
|
||||||
onValueChange = {
|
|
||||||
tone = it
|
|
||||||
currentValue = themeColor.copy(tone = it.roundToInt())
|
|
||||||
},
|
},
|
||||||
track = {
|
selected = themeColor.color == CorePaletteColor.Primary,
|
||||||
Canvas(
|
)
|
||||||
modifier = Modifier
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
.fillMaxWidth()
|
ColorSwatch(
|
||||||
.height(20.dp)
|
color = Color(
|
||||||
) {
|
corePalette
|
||||||
drawRoundRect(
|
.get(CorePaletteColor.Secondary)
|
||||||
brush = Brush.horizontalGradient(
|
.atTone(tone.toInt())
|
||||||
colors = listOf(
|
),
|
||||||
Color.hct(
|
modifier = Modifier
|
||||||
hue,
|
.padding(8.dp)
|
||||||
chroma,
|
.size(64.dp)
|
||||||
0f
|
.clickable {
|
||||||
),
|
currentValue = ColorRef(
|
||||||
Color.hct(
|
CorePaletteColor.Secondary,
|
||||||
hue,
|
tone.roundToInt()
|
||||||
chroma,
|
)
|
||||||
10f
|
},
|
||||||
),
|
selected = themeColor.color == CorePaletteColor.Secondary,
|
||||||
Color.hct(
|
)
|
||||||
hue,
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
chroma,
|
ColorSwatch(
|
||||||
20f
|
color = Color(
|
||||||
),
|
corePalette
|
||||||
Color.hct(
|
.get(CorePaletteColor.Tertiary)
|
||||||
hue,
|
.atTone(tone.toInt())
|
||||||
chroma,
|
),
|
||||||
30f
|
modifier = Modifier
|
||||||
),
|
.padding(8.dp)
|
||||||
Color.hct(
|
.size(64.dp)
|
||||||
hue,
|
.clickable {
|
||||||
chroma,
|
currentValue = ColorRef(
|
||||||
40f
|
CorePaletteColor.Tertiary,
|
||||||
),
|
tone.roundToInt()
|
||||||
Color.hct(
|
)
|
||||||
hue,
|
},
|
||||||
chroma,
|
selected = themeColor.color == CorePaletteColor.Tertiary,
|
||||||
50f
|
)
|
||||||
),
|
}
|
||||||
Color.hct(
|
Row(
|
||||||
hue,
|
modifier = Modifier.padding(bottom = 16.dp)
|
||||||
chroma,
|
) {
|
||||||
60f
|
ColorSwatch(
|
||||||
),
|
color = Color(
|
||||||
Color.hct(
|
corePalette
|
||||||
hue,
|
.get(CorePaletteColor.Neutral)
|
||||||
chroma,
|
.atTone(tone.toInt())
|
||||||
70f
|
),
|
||||||
),
|
modifier = Modifier
|
||||||
Color.hct(
|
.padding(8.dp)
|
||||||
hue,
|
.size(64.dp)
|
||||||
chroma,
|
.clickable {
|
||||||
80f
|
currentValue = ColorRef(
|
||||||
),
|
CorePaletteColor.Neutral,
|
||||||
Color.hct(
|
tone.roundToInt()
|
||||||
hue,
|
)
|
||||||
chroma,
|
},
|
||||||
90f
|
selected = themeColor.color == CorePaletteColor.Neutral,
|
||||||
),
|
)
|
||||||
Color.hct(
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
hue,
|
ColorSwatch(
|
||||||
chroma,
|
color = Color(
|
||||||
100f
|
corePalette
|
||||||
),
|
.get(CorePaletteColor.NeutralVariant)
|
||||||
)
|
.atTone(tone.toInt())
|
||||||
),
|
),
|
||||||
style = Fill,
|
modifier = Modifier
|
||||||
cornerRadius = CornerRadius(
|
.padding(8.dp)
|
||||||
10.dp.toPx(),
|
.size(64.dp)
|
||||||
10.dp.toPx()
|
.clickable {
|
||||||
|
currentValue = ColorRef(
|
||||||
|
CorePaletteColor.NeutralVariant,
|
||||||
|
tone.roundToInt()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
selected = themeColor.color == CorePaletteColor.NeutralVariant,
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
ColorSwatch(
|
||||||
|
color = Color(
|
||||||
|
corePalette
|
||||||
|
.get(CorePaletteColor.Error)
|
||||||
|
.atTone(tone.toInt())
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.size(64.dp)
|
||||||
|
.clickable {
|
||||||
|
currentValue = ColorRef(
|
||||||
|
CorePaletteColor.Error,
|
||||||
|
tone.roundToInt()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
selected = themeColor.color == CorePaletteColor.Error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "T",
|
||||||
|
modifier = Modifier.width(32.dp),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Slider(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
value = tone,
|
||||||
|
valueRange = 0f..100f,
|
||||||
|
onValueChange = {
|
||||||
|
tone = it
|
||||||
|
currentValue = themeColor.copy(tone = it.roundToInt())
|
||||||
|
},
|
||||||
|
track = {
|
||||||
|
Canvas(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(20.dp)
|
||||||
|
) {
|
||||||
|
drawRoundRect(
|
||||||
|
brush = Brush.horizontalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
0f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
10f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
20f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
30f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
40f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
50f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
60f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
70f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
80f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
90f
|
||||||
|
),
|
||||||
|
Color.hct(
|
||||||
|
hue,
|
||||||
|
chroma,
|
||||||
|
100f
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
style = Fill,
|
||||||
|
cornerRadius = CornerRadius(
|
||||||
|
10.dp.toPx(),
|
||||||
|
10.dp.toPx()
|
||||||
)
|
)
|
||||||
}
|
|
||||||
},
|
|
||||||
thumb = {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(vertical = 2.dp, horizontal = 8.dp)
|
|
||||||
.size(16.dp)
|
|
||||||
.shadow(1.dp, CircleShape)
|
|
||||||
.clip(CircleShape)
|
|
||||||
.background(Color.White)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
},
|
||||||
Text(
|
thumb = {
|
||||||
text = tone.roundToInt().toString(),
|
Box(
|
||||||
modifier = Modifier.width(32.dp),
|
modifier = Modifier
|
||||||
style = MaterialTheme.typography.labelMedium,
|
.padding(vertical = 2.dp, horizontal = 8.dp)
|
||||||
textAlign = TextAlign.Center,
|
.size(16.dp)
|
||||||
)
|
.shadow(1.dp, CircleShape)
|
||||||
}
|
.clip(CircleShape)
|
||||||
}
|
.background(Color.White)
|
||||||
HorizontalDivider(
|
)
|
||||||
modifier = Modifier.padding(top = 16.dp)
|
}
|
||||||
)
|
)
|
||||||
|
Text(
|
||||||
TextButton(
|
text = tone.roundToInt().toString(),
|
||||||
modifier = Modifier
|
modifier = Modifier.width(32.dp),
|
||||||
.padding(top = 8.dp)
|
style = MaterialTheme.typography.labelMedium,
|
||||||
.align(Alignment.End),
|
textAlign = TextAlign.Center,
|
||||||
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
|
||||||
onClick = { currentValue = null }
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.restart_alt_20px),
|
|
||||||
null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(ButtonDefaults.IconSpacing)
|
|
||||||
.size(ButtonDefaults.IconSize)
|
|
||||||
)
|
)
|
||||||
Text(stringResource(R.string.preference_restore_default))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.padding(top = 16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 8.dp)
|
||||||
|
.align(Alignment.End),
|
||||||
|
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
||||||
|
onClick = { currentValue = null }
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.restart_alt_20px),
|
||||||
|
null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(ButtonDefaults.IconSpacing)
|
||||||
|
.size(ButtonDefaults.IconSize)
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.preference_restore_default))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,8 +285,9 @@ fun GesturePreference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value is GestureAction.Launch && (showAppPicker || app == null)) {
|
if (value is GestureAction.Launch) {
|
||||||
SearchablePicker(
|
SearchablePicker(
|
||||||
|
expanded = (showAppPicker || app == null),
|
||||||
onDismissRequest = {
|
onDismissRequest = {
|
||||||
showAppPicker = false
|
showAppPicker = false
|
||||||
if (app == null) onValueChanged(GestureAction.NoAction)
|
if (app == null) onValueChanged(GestureAction.NoAction)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Row
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
@@ -298,142 +299,141 @@ fun SearchBarStylePreference(
|
|||||||
) {
|
) {
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
||||||
if (showDialog && value != null) {
|
|
||||||
val styles = remember {
|
DismissableBottomSheet(
|
||||||
SearchBarStyle.entries
|
expanded = showDialog,
|
||||||
|
onDismissRequest = {
|
||||||
|
showDialog = false
|
||||||
}
|
}
|
||||||
|
) {
|
||||||
|
val styles = SearchBarStyle.entries
|
||||||
|
|
||||||
val darkColors =
|
val darkColors =
|
||||||
LocalPreferDarkContentOverWallpaper.current && colors == SearchBarColors.Auto || colors == SearchBarColors.Dark
|
LocalPreferDarkContentOverWallpaper.current && colors == SearchBarColors.Auto || colors == SearchBarColors.Dark
|
||||||
|
|
||||||
DismissableBottomSheet(
|
Box(
|
||||||
onDismissRequest = {
|
modifier = Modifier
|
||||||
showDialog = false
|
.verticalScroll(rememberScrollState())
|
||||||
}
|
.padding(16.dp)
|
||||||
|
.navigationBarsPadding(),
|
||||||
) {
|
) {
|
||||||
Box(
|
Column(
|
||||||
modifier = Modifier
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(it)
|
|
||||||
) {
|
) {
|
||||||
Column(
|
for (style in styles) {
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
Column {
|
||||||
) {
|
Row(
|
||||||
for (style in styles) {
|
modifier = Modifier
|
||||||
Column {
|
.padding(top = 8.dp),
|
||||||
Row(
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
) {
|
||||||
.padding(top = 8.dp),
|
Text(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
text = stringResource(
|
||||||
) {
|
when (style) {
|
||||||
Text(
|
SearchBarStyle.Transparent -> R.string.preference_search_bar_style_transparent
|
||||||
text = stringResource(
|
SearchBarStyle.Solid -> R.string.preference_search_bar_style_solid
|
||||||
when (style) {
|
SearchBarStyle.Hidden -> R.string.preference_search_bar_style_hidden
|
||||||
SearchBarStyle.Transparent -> R.string.preference_search_bar_style_transparent
|
|
||||||
SearchBarStyle.Solid -> R.string.preference_search_bar_style_solid
|
|
||||||
SearchBarStyle.Hidden -> R.string.preference_search_bar_style_hidden
|
|
||||||
}
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.titleSmall,
|
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
)
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
onStyleChanged(style)
|
|
||||||
}
|
}
|
||||||
) {
|
),
|
||||||
Icon(
|
style = MaterialTheme.typography.titleSmall,
|
||||||
painterResource(
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
if (style == value) R.drawable.check_circle_24px_filled
|
modifier = Modifier.weight(1f),
|
||||||
else R.drawable.circle_24px
|
)
|
||||||
),
|
IconButton(
|
||||||
contentDescription = null,
|
onClick = {
|
||||||
tint = if (style == value) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface,
|
onStyleChanged(style)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(
|
||||||
|
if (style == value) R.drawable.check_circle_24px_filled
|
||||||
|
else R.drawable.circle_24px
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = if (style == value) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
if (style == value) 4.dp else 2.dp,
|
||||||
|
if (style == value) MaterialTheme.colorScheme.primary else Color.Transparent,
|
||||||
|
MaterialTheme.shapes.medium,
|
||||||
|
)
|
||||||
|
.clip(MaterialTheme.shapes.medium)
|
||||||
|
.background(
|
||||||
|
when {
|
||||||
|
style != SearchBarStyle.Transparent -> MaterialTheme.colorScheme.inverseSurface
|
||||||
|
LocalDarkTheme.current != darkColors -> MaterialTheme.colorScheme.surfaceContainer
|
||||||
|
else -> MaterialTheme.colorScheme.inverseSurface
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.height(IntrinsicSize.Min)
|
||||||
|
) {
|
||||||
|
SearchBar(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp),
|
||||||
|
level = SearchBarLevel.Resting,
|
||||||
|
style = style,
|
||||||
|
value = "",
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
darkColors = darkColors,
|
||||||
|
)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.border(
|
.fillMaxSize()
|
||||||
if (style == value) 4.dp else 2.dp,
|
.clickable {
|
||||||
if (style == value) MaterialTheme.colorScheme.primary else Color.Transparent,
|
onStyleChanged(style)
|
||||||
MaterialTheme.shapes.medium,
|
}
|
||||||
)
|
)
|
||||||
.clip(MaterialTheme.shapes.medium)
|
}
|
||||||
.background(
|
if (style == SearchBarStyle.Transparent) {
|
||||||
when {
|
Row(
|
||||||
style != SearchBarStyle.Transparent -> MaterialTheme.colorScheme.inverseSurface
|
modifier = Modifier
|
||||||
LocalDarkTheme.current != darkColors -> MaterialTheme.colorScheme.surfaceContainer
|
.fillMaxWidth()
|
||||||
else -> MaterialTheme.colorScheme.inverseSurface
|
.padding(top = 16.dp),
|
||||||
}
|
horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween)
|
||||||
)
|
|
||||||
.height(IntrinsicSize.Min)
|
|
||||||
) {
|
) {
|
||||||
SearchBar(
|
ToggleButton(
|
||||||
modifier = Modifier
|
modifier = Modifier.weight(1f),
|
||||||
.padding(16.dp),
|
checked = colors == SearchBarColors.Auto,
|
||||||
level = SearchBarLevel.Resting,
|
onCheckedChange = {
|
||||||
style = style,
|
onColorsChanged(SearchBarColors.Auto)
|
||||||
value = "",
|
},
|
||||||
onValueChange = {},
|
shapes = ButtonGroupDefaults.connectedLeadingButtonShapes(),
|
||||||
readOnly = true,
|
|
||||||
darkColors = darkColors,
|
|
||||||
)
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.clickable {
|
|
||||||
onStyleChanged(style)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (style == SearchBarStyle.Transparent) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 16.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween)
|
|
||||||
) {
|
) {
|
||||||
ToggleButton(
|
Icon(
|
||||||
modifier = Modifier.weight(1f),
|
painterResource(R.drawable.auto_awesome_20dp),
|
||||||
checked = colors == SearchBarColors.Auto,
|
contentDescription = null,
|
||||||
onCheckedChange = {
|
)
|
||||||
onColorsChanged(SearchBarColors.Auto)
|
}
|
||||||
},
|
ToggleButton(
|
||||||
shapes = ButtonGroupDefaults.connectedLeadingButtonShapes(),
|
modifier = Modifier.weight(1f),
|
||||||
) {
|
checked = colors == SearchBarColors.Light,
|
||||||
Icon(
|
onCheckedChange = {
|
||||||
painterResource(R.drawable.auto_awesome_20dp),
|
onColorsChanged(SearchBarColors.Light)
|
||||||
contentDescription = null,
|
},
|
||||||
)
|
shapes = ButtonGroupDefaults.connectedMiddleButtonShapes(),
|
||||||
}
|
) {
|
||||||
ToggleButton(
|
Icon(
|
||||||
modifier = Modifier.weight(1f),
|
painterResource(R.drawable.light_mode_24px),
|
||||||
checked = colors == SearchBarColors.Light,
|
contentDescription = null,
|
||||||
onCheckedChange = {
|
)
|
||||||
onColorsChanged(SearchBarColors.Light)
|
}
|
||||||
},
|
ToggleButton(
|
||||||
shapes = ButtonGroupDefaults.connectedMiddleButtonShapes(),
|
modifier = Modifier.weight(1f),
|
||||||
) {
|
checked = colors == SearchBarColors.Dark,
|
||||||
Icon(
|
onCheckedChange = {
|
||||||
painterResource(R.drawable.light_mode_24px),
|
onColorsChanged(SearchBarColors.Dark)
|
||||||
contentDescription = null,
|
},
|
||||||
)
|
shapes = ButtonGroupDefaults.connectedTrailingButtonShapes(),
|
||||||
}
|
) {
|
||||||
ToggleButton(
|
Icon(
|
||||||
modifier = Modifier.weight(1f),
|
painterResource(R.drawable.dark_mode_24px),
|
||||||
checked = colors == SearchBarColors.Dark,
|
contentDescription = null,
|
||||||
onCheckedChange = {
|
)
|
||||||
onColorsChanged(SearchBarColors.Dark)
|
|
||||||
},
|
|
||||||
shapes = ButtonGroupDefaults.connectedTrailingButtonShapes(),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.dark_mode_24px),
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package de.mm20.launcher2.ui.settings.search
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
@@ -397,27 +398,29 @@ fun SearchSettingsScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showFilterEditor) {
|
DismissableBottomSheet(
|
||||||
|
expanded = showFilterEditor,
|
||||||
|
onDismissRequest = { showFilterEditor = false }) {
|
||||||
val filters by viewModel.searchFilters.collectAsStateWithLifecycle()
|
val filters by viewModel.searchFilters.collectAsStateWithLifecycle()
|
||||||
DismissableBottomSheet(onDismissRequest = { showFilterEditor = false }) {
|
Column(
|
||||||
Column(
|
modifier = Modifier
|
||||||
modifier = Modifier.padding(it)
|
.padding(16.dp)
|
||||||
) {
|
.navigationBarsPadding()
|
||||||
AnimatedVisibility(filters.allowNetwork) {
|
) {
|
||||||
SmallMessage(
|
AnimatedVisibility(filters.allowNetwork) {
|
||||||
modifier = Modifier.padding(bottom = 16.dp),
|
SmallMessage(
|
||||||
icon = R.drawable.warning_24px,
|
modifier = Modifier.padding(bottom = 16.dp),
|
||||||
text = stringResource(R.string.filter_settings_network_warning)
|
icon = R.drawable.warning_24px,
|
||||||
)
|
text = stringResource(R.string.filter_settings_network_warning)
|
||||||
}
|
|
||||||
SearchFilters(
|
|
||||||
filters = filters,
|
|
||||||
onFiltersChange = {
|
|
||||||
viewModel.setSearchFilters(it)
|
|
||||||
},
|
|
||||||
settings = true,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
SearchFilters(
|
||||||
|
filters = filters,
|
||||||
|
onFiltersChange = {
|
||||||
|
viewModel.setSearchFilters(it)
|
||||||
|
},
|
||||||
|
settings = true,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ import de.mm20.launcher2.themes.shapes.Shape as ThemeShape
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class ShapeSchemeSettingsRoute(
|
data class ShapeSchemeSettingsRoute(
|
||||||
@Serializable(with = UUIDSerializer::class) val id: UUID
|
@Serializable(with = UUIDSerializer::class) val id: UUID
|
||||||
): NavKey
|
) : NavKey
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ShapeSchemeSettingsScreen(themeId: UUID) {
|
fun ShapeSchemeSettingsScreen(themeId: UUID) {
|
||||||
@@ -463,20 +463,38 @@ fun ShapePreference(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showDialog) {
|
val maxRadius = (24 * factor).toInt()
|
||||||
val maxRadius = (24 * factor).toInt()
|
|
||||||
|
|
||||||
val baseTopStart = ((baseShape.radii?.get(0) ?: 12) * factor).toInt()
|
val baseTopStart = ((baseShape.radii?.get(0) ?: 12) * factor).toInt()
|
||||||
val baseTopEnd = ((baseShape.radii?.get(1) ?: 12) * factor).toInt()
|
val baseTopEnd = ((baseShape.radii?.get(1) ?: 12) * factor).toInt()
|
||||||
val baseBottomEnd = ((baseShape.radii?.get(2) ?: 12) * factor).toInt()
|
val baseBottomEnd = ((baseShape.radii?.get(2) ?: 12) * factor).toInt()
|
||||||
val baseBottomStart = ((baseShape.radii?.get(3) ?: 12) * factor).toInt()
|
val baseBottomStart = ((baseShape.radii?.get(3) ?: 12) * factor).toInt()
|
||||||
|
|
||||||
|
|
||||||
var currentCornerStyle by remember(shape) { mutableStateOf(shape?.corners) }
|
var currentCornerStyle by remember(shape) { mutableStateOf(shape?.corners) }
|
||||||
var currentTopStart by remember(shape) { mutableStateOf(shape?.radii?.get(0)) }
|
var currentTopStart by remember(shape) { mutableStateOf(shape?.radii?.get(0)) }
|
||||||
var currentTopEnd by remember(shape) { mutableStateOf(shape?.radii?.get(1)) }
|
var currentTopEnd by remember(shape) { mutableStateOf(shape?.radii?.get(1)) }
|
||||||
var currentBottomEnd by remember(shape) { mutableStateOf(shape?.radii?.get(2)) }
|
var currentBottomEnd by remember(shape) { mutableStateOf(shape?.radii?.get(2)) }
|
||||||
var currentBottomStart by remember(shape) { mutableStateOf(shape?.radii?.get(3)) }
|
var currentBottomStart by remember(shape) { mutableStateOf(shape?.radii?.get(3)) }
|
||||||
|
|
||||||
|
DismissableBottomSheet(
|
||||||
|
expanded = showDialog,
|
||||||
|
onDismissRequest = {
|
||||||
|
showDialog = false
|
||||||
|
onValueChange(
|
||||||
|
ThemeShape(
|
||||||
|
corners = currentCornerStyle,
|
||||||
|
radii = if (currentTopStart != null || currentTopEnd != null || currentBottomEnd != null || currentBottomStart != null) {
|
||||||
|
intArrayOf(
|
||||||
|
currentTopStart ?: baseTopStart,
|
||||||
|
currentTopEnd ?: baseTopEnd,
|
||||||
|
currentBottomEnd ?: baseBottomEnd,
|
||||||
|
currentBottomStart ?: baseBottomStart,
|
||||||
|
)
|
||||||
|
} else null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
|
||||||
val actualCornerStyle = currentCornerStyle ?: baseShape.corners ?: CornerStyle.Rounded
|
val actualCornerStyle = currentCornerStyle ?: baseShape.corners ?: CornerStyle.Rounded
|
||||||
val actualTopStart = currentTopStart ?: baseTopStart
|
val actualTopStart = currentTopStart ?: baseTopStart
|
||||||
@@ -484,241 +502,222 @@ fun ShapePreference(
|
|||||||
val actualBottomEnd = currentBottomEnd ?: baseBottomEnd
|
val actualBottomEnd = currentBottomEnd ?: baseBottomEnd
|
||||||
val actualBottomStart = currentBottomStart ?: baseBottomStart
|
val actualBottomStart = currentBottomStart ?: baseBottomStart
|
||||||
|
|
||||||
DismissableBottomSheet(
|
Column(
|
||||||
onDismissRequest = {
|
modifier = Modifier
|
||||||
showDialog = false
|
.verticalScroll(rememberScrollState())
|
||||||
onValueChange(
|
.padding(it)
|
||||||
ThemeShape(
|
.padding(bottom = 8.dp),
|
||||||
corners = currentCornerStyle,
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
radii = if (currentTopStart != null || currentTopEnd != null || currentBottomEnd != null || currentBottomStart != null) {
|
) {
|
||||||
intArrayOf(
|
val previewShape = if ((currentCornerStyle ?: baseShape.corners
|
||||||
currentTopStart ?: baseTopStart,
|
?: CornerStyle.Rounded) == CornerStyle.Rounded
|
||||||
currentTopEnd ?: baseTopEnd,
|
|
||||||
currentBottomEnd ?: baseBottomEnd,
|
|
||||||
currentBottomStart ?: baseBottomStart,
|
|
||||||
)
|
|
||||||
} else null
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(it)
|
|
||||||
.padding(bottom = 8.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
||||||
) {
|
) {
|
||||||
val previewShape = if ((currentCornerStyle ?: baseShape.corners
|
RoundedCornerShape(
|
||||||
?: CornerStyle.Rounded) == CornerStyle.Rounded
|
topStart = (currentTopStart ?: baseTopStart).dp,
|
||||||
) {
|
topEnd = (currentTopEnd ?: baseTopEnd).dp,
|
||||||
RoundedCornerShape(
|
bottomEnd = (currentBottomEnd ?: baseBottomEnd).dp,
|
||||||
topStart = (currentTopStart ?: baseTopStart).dp,
|
bottomStart = (currentBottomStart ?: baseBottomStart).dp
|
||||||
topEnd = (currentTopEnd ?: baseTopEnd).dp,
|
|
||||||
bottomEnd = (currentBottomEnd ?: baseBottomEnd).dp,
|
|
||||||
bottomStart = (currentBottomStart ?: baseBottomStart).dp
|
|
||||||
|
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
CutCornerShape(
|
||||||
|
topStart = (currentTopStart ?: baseTopStart).dp,
|
||||||
|
topEnd = (currentTopEnd ?: baseTopEnd).dp,
|
||||||
|
bottomEnd = (currentBottomEnd ?: baseBottomEnd).dp,
|
||||||
|
bottomStart = (currentBottomStart ?: baseBottomStart).dp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(max(96, maxRadius * 2).dp)
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceContainer, previewShape)
|
||||||
|
.border(
|
||||||
|
2.dp,
|
||||||
|
MaterialTheme.colorScheme.primary,
|
||||||
|
previewShape
|
||||||
)
|
)
|
||||||
} else {
|
)
|
||||||
CutCornerShape(
|
|
||||||
topStart = (currentTopStart ?: baseTopStart).dp,
|
Row(
|
||||||
topEnd = (currentTopEnd ?: baseTopEnd).dp,
|
modifier = Modifier
|
||||||
bottomEnd = (currentBottomEnd ?: baseBottomEnd).dp,
|
.fillMaxWidth(),
|
||||||
bottomStart = (currentBottomStart ?: baseBottomStart).dp
|
horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween),
|
||||||
|
) {
|
||||||
|
ToggleButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
checked = actualCornerStyle == CornerStyle.Rounded,
|
||||||
|
onCheckedChange = {
|
||||||
|
currentCornerStyle = CornerStyle.Rounded
|
||||||
|
},
|
||||||
|
shapes = ButtonGroupDefaults.connectedLeadingButtonShapes(),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(
|
||||||
|
if (actualCornerStyle == CornerStyle.Rounded) R.drawable.check_20px else R.drawable.rounded_corner_alt_24px
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(end = ToggleButtonDefaults.IconSpacing)
|
||||||
|
.size(ToggleButtonDefaults.IconSize)
|
||||||
)
|
)
|
||||||
|
Text(stringResource(R.string.preference_cards_shape_rounded))
|
||||||
}
|
}
|
||||||
Box(
|
ToggleButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
checked = actualCornerStyle == CornerStyle.Cut,
|
||||||
|
onCheckedChange = {
|
||||||
|
currentCornerStyle = CornerStyle.Cut
|
||||||
|
},
|
||||||
|
shapes = ButtonGroupDefaults.connectedTrailingButtonShapes(),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(
|
||||||
|
if (actualCornerStyle == CornerStyle.Cut) R.drawable.check_20px else R.drawable.cut_corner_20px
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(end = ToggleButtonDefaults.IconSpacing)
|
||||||
|
.size(ToggleButtonDefaults.IconSize)
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.preference_cards_shape_cut))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.rounded_corner_24px),
|
||||||
|
null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.padding(end = 8.dp)
|
||||||
.height(max(96, maxRadius * 2).dp)
|
.rotate(-90f)
|
||||||
.background(MaterialTheme.colorScheme.surfaceContainer, previewShape)
|
)
|
||||||
.border(
|
Slider(
|
||||||
2.dp,
|
modifier = Modifier
|
||||||
MaterialTheme.colorScheme.primary,
|
.weight(1f),
|
||||||
previewShape
|
value = actualTopStart.toFloat(),
|
||||||
)
|
onValueChange = {
|
||||||
|
currentTopStart = it.toInt()
|
||||||
|
},
|
||||||
|
valueRange = 0f..maxRadius.toFloat(),
|
||||||
|
steps = maxRadius + 1
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = actualTopStart.toString(),
|
||||||
|
modifier = Modifier.width(32.dp),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.rounded_corner_24px),
|
||||||
|
null,
|
||||||
|
modifier = Modifier.padding(end = 8.dp)
|
||||||
|
)
|
||||||
|
Slider(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f),
|
||||||
|
value = actualTopEnd.toFloat(),
|
||||||
|
onValueChange = {
|
||||||
|
currentTopEnd = it.toInt()
|
||||||
|
},
|
||||||
|
valueRange = 0f..maxRadius.toFloat(),
|
||||||
|
steps = maxRadius + 1,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = actualTopEnd.toString(),
|
||||||
|
modifier = Modifier.width(32.dp),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.rounded_corner_24px),
|
||||||
|
null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(end = 8.dp)
|
||||||
|
.rotate(90f)
|
||||||
|
)
|
||||||
|
Slider(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f),
|
||||||
|
value = actualBottomEnd.toFloat(),
|
||||||
|
onValueChange = {
|
||||||
|
currentBottomEnd = it.toInt()
|
||||||
|
},
|
||||||
|
valueRange = 0f..maxRadius.toFloat(),
|
||||||
|
steps = maxRadius + 1,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = actualBottomEnd.toString(),
|
||||||
|
modifier = Modifier.width(32.dp),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.rounded_corner_24px),
|
||||||
|
null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(end = 8.dp)
|
||||||
|
.rotate(180f)
|
||||||
|
)
|
||||||
|
Slider(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f),
|
||||||
|
value = actualBottomStart.toFloat(),
|
||||||
|
onValueChange = {
|
||||||
|
currentBottomStart = it.toInt()
|
||||||
|
},
|
||||||
|
valueRange = 0f..maxRadius.toFloat(),
|
||||||
|
steps = maxRadius + 1,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = actualBottomStart.toString(),
|
||||||
|
modifier = Modifier.width(32.dp),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(
|
}
|
||||||
|
|
||||||
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.padding(top = 16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 8.dp)
|
||||||
|
.align(Alignment.End),
|
||||||
|
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
||||||
|
onClick = {
|
||||||
|
currentTopStart = null
|
||||||
|
currentTopEnd = null
|
||||||
|
currentBottomEnd = null
|
||||||
|
currentBottomStart = null
|
||||||
|
currentCornerStyle = null
|
||||||
|
onValueChange(null)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.restart_alt_20px), null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(),
|
.padding(ButtonDefaults.IconSpacing)
|
||||||
horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween),
|
.size(ButtonDefaults.IconSize)
|
||||||
) {
|
|
||||||
ToggleButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
checked = actualCornerStyle == CornerStyle.Rounded,
|
|
||||||
onCheckedChange = {
|
|
||||||
currentCornerStyle = CornerStyle.Rounded
|
|
||||||
},
|
|
||||||
shapes = ButtonGroupDefaults.connectedLeadingButtonShapes(),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(
|
|
||||||
if (actualCornerStyle == CornerStyle.Rounded) R.drawable.check_20px else R.drawable.rounded_corner_alt_24px
|
|
||||||
),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = ToggleButtonDefaults.IconSpacing)
|
|
||||||
.size(ToggleButtonDefaults.IconSize)
|
|
||||||
)
|
|
||||||
Text(stringResource(R.string.preference_cards_shape_rounded))
|
|
||||||
}
|
|
||||||
ToggleButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
checked = actualCornerStyle == CornerStyle.Cut,
|
|
||||||
onCheckedChange = {
|
|
||||||
currentCornerStyle = CornerStyle.Cut
|
|
||||||
},
|
|
||||||
shapes = ButtonGroupDefaults.connectedTrailingButtonShapes(),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(
|
|
||||||
if (actualCornerStyle == CornerStyle.Cut) R.drawable.check_20px else R.drawable.cut_corner_20px
|
|
||||||
),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = ToggleButtonDefaults.IconSpacing)
|
|
||||||
.size(ToggleButtonDefaults.IconSize)
|
|
||||||
)
|
|
||||||
Text(stringResource(R.string.preference_cards_shape_cut))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.rounded_corner_24px),
|
|
||||||
null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = 8.dp)
|
|
||||||
.rotate(-90f)
|
|
||||||
)
|
|
||||||
Slider(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f),
|
|
||||||
value = actualTopStart.toFloat(),
|
|
||||||
onValueChange = {
|
|
||||||
currentTopStart = it.toInt()
|
|
||||||
},
|
|
||||||
valueRange = 0f..maxRadius.toFloat(),
|
|
||||||
steps = maxRadius + 1
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = actualTopStart.toString(),
|
|
||||||
modifier = Modifier.width(32.dp),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.rounded_corner_24px),
|
|
||||||
null,
|
|
||||||
modifier = Modifier.padding(end = 8.dp)
|
|
||||||
)
|
|
||||||
Slider(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f),
|
|
||||||
value = actualTopEnd.toFloat(),
|
|
||||||
onValueChange = {
|
|
||||||
currentTopEnd = it.toInt()
|
|
||||||
},
|
|
||||||
valueRange = 0f..maxRadius.toFloat(),
|
|
||||||
steps = maxRadius + 1,
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = actualTopEnd.toString(),
|
|
||||||
modifier = Modifier.width(32.dp),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.rounded_corner_24px),
|
|
||||||
null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = 8.dp)
|
|
||||||
.rotate(90f)
|
|
||||||
)
|
|
||||||
Slider(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f),
|
|
||||||
value = actualBottomEnd.toFloat(),
|
|
||||||
onValueChange = {
|
|
||||||
currentBottomEnd = it.toInt()
|
|
||||||
},
|
|
||||||
valueRange = 0f..maxRadius.toFloat(),
|
|
||||||
steps = maxRadius + 1,
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = actualBottomEnd.toString(),
|
|
||||||
modifier = Modifier.width(32.dp),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.rounded_corner_24px),
|
|
||||||
null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = 8.dp)
|
|
||||||
.rotate(180f)
|
|
||||||
)
|
|
||||||
Slider(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f),
|
|
||||||
value = actualBottomStart.toFloat(),
|
|
||||||
onValueChange = {
|
|
||||||
currentBottomStart = it.toInt()
|
|
||||||
},
|
|
||||||
valueRange = 0f..maxRadius.toFloat(),
|
|
||||||
steps = maxRadius + 1,
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = actualBottomStart.toString(),
|
|
||||||
modifier = Modifier.width(32.dp),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(top = 16.dp)
|
|
||||||
)
|
)
|
||||||
|
Text(stringResource(R.string.preference_restore_default))
|
||||||
TextButton(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 8.dp)
|
|
||||||
.align(Alignment.End),
|
|
||||||
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
|
||||||
onClick = {
|
|
||||||
currentTopStart = null
|
|
||||||
currentTopEnd = null
|
|
||||||
currentBottomEnd = null
|
|
||||||
currentBottomStart = null
|
|
||||||
currentCornerStyle = null
|
|
||||||
onValueChange(null)
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.restart_alt_20px), null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(ButtonDefaults.IconSpacing)
|
|
||||||
.size(ButtonDefaults.IconSize)
|
|
||||||
)
|
|
||||||
Text(stringResource(R.string.preference_restore_default))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,20 @@ import androidx.compose.foundation.horizontalScroll
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.heightIn
|
import androidx.compose.foundation.layout.heightIn
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
@@ -758,47 +764,54 @@ private fun FontPreference(
|
|||||||
onClick = { showDialog = true },
|
onClick = { showDialog = true },
|
||||||
)
|
)
|
||||||
|
|
||||||
if (showDialog) {
|
DismissableBottomSheet(
|
||||||
|
expanded = showDialog,
|
||||||
|
onDismissRequest = { showDialog = false },
|
||||||
|
) {
|
||||||
val fonts = remember { fontManager.getInstalledFonts() }
|
val fonts = remember { fontManager.getInstalledFonts() }
|
||||||
DismissableBottomSheet(
|
LazyColumn(
|
||||||
onDismissRequest = { showDialog = false },
|
contentPadding = PaddingValues(
|
||||||
|
start = 16.dp,
|
||||||
|
top = 16.dp,
|
||||||
|
end = 16.dp,
|
||||||
|
bottom = 16.dp + WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding(),
|
||||||
|
),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
) {
|
) {
|
||||||
LazyColumn(contentPadding = it, verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
if (fonts.builtIn.isNotEmpty()) {
|
||||||
if (fonts.builtIn.isNotEmpty()) {
|
item {
|
||||||
item {
|
FontPickerCategory(
|
||||||
FontPickerCategory(
|
preview.ExtraShort,
|
||||||
preview.ExtraShort,
|
null,
|
||||||
null,
|
fonts.builtIn,
|
||||||
fonts.builtIn,
|
onFontClick = {
|
||||||
onFontClick = {
|
onValueChange(it)
|
||||||
onValueChange(it)
|
showDialog = false
|
||||||
showDialog = false
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (fonts.deviceDefault.isNotEmpty()) {
|
}
|
||||||
item {
|
if (fonts.deviceDefault.isNotEmpty()) {
|
||||||
FontPickerCategory(
|
item {
|
||||||
preview.ExtraShort,
|
FontPickerCategory(
|
||||||
stringResource(R.string.font_category_device_default),
|
preview.ExtraShort,
|
||||||
fonts.deviceDefault,
|
stringResource(R.string.font_category_device_default),
|
||||||
onFontClick = {
|
fonts.deviceDefault,
|
||||||
onValueChange(it)
|
onFontClick = {
|
||||||
showDialog = false
|
onValueChange(it)
|
||||||
})
|
showDialog = false
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
if (fonts.generic.isNotEmpty()) {
|
}
|
||||||
item {
|
if (fonts.generic.isNotEmpty()) {
|
||||||
FontPickerCategory(
|
item {
|
||||||
preview.ExtraShort,
|
FontPickerCategory(
|
||||||
stringResource(R.string.font_category_generic),
|
preview.ExtraShort,
|
||||||
fonts.generic,
|
stringResource(R.string.font_category_generic),
|
||||||
onFontClick = {
|
fonts.generic,
|
||||||
onValueChange(it)
|
onFontClick = {
|
||||||
showDialog = false
|
onValueChange(it)
|
||||||
})
|
showDialog = false
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -951,209 +964,210 @@ private fun TextStylePreference(
|
|||||||
},
|
},
|
||||||
onClick = { showDialog = true },
|
onClick = { showDialog = true },
|
||||||
)
|
)
|
||||||
if (showDialog) {
|
var fontFamily by remember(value) {
|
||||||
var fontFamily by remember(value) {
|
mutableStateOf(value?.fontFamily)
|
||||||
mutableStateOf(value?.fontFamily)
|
}
|
||||||
}
|
var fontSize by remember(value) {
|
||||||
var fontSize by remember(value) {
|
mutableStateOf(value?.fontSize)
|
||||||
mutableStateOf(value?.fontSize)
|
}
|
||||||
}
|
var lineHeight by remember(value) {
|
||||||
var lineHeight by remember(value) {
|
mutableStateOf(value?.lineHeight)
|
||||||
mutableStateOf(value?.lineHeight)
|
}
|
||||||
}
|
var weight by remember(value) {
|
||||||
var weight by remember(value) {
|
mutableStateOf((value?.fontWeight as? ThemeFontWeight.Absolute)?.weight)
|
||||||
mutableStateOf((value?.fontWeight as? ThemeFontWeight.Absolute)?.weight)
|
}
|
||||||
}
|
var letterSpacing by remember(value) {
|
||||||
var letterSpacing by remember(value) {
|
mutableStateOf(value?.letterSpacing)
|
||||||
mutableStateOf(value?.letterSpacing)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DismissableBottomSheet(
|
DismissableBottomSheet(
|
||||||
onDismissRequest = {
|
expanded = showDialog,
|
||||||
onValueChange(
|
onDismissRequest = {
|
||||||
ThemeTextStyle(
|
onValueChange(
|
||||||
fontFamily = fontFamily,
|
ThemeTextStyle(
|
||||||
fontSize = fontSize,
|
fontFamily = fontFamily,
|
||||||
lineHeight = lineHeight,
|
fontSize = fontSize,
|
||||||
fontWeight = weight?.let { ThemeFontWeight.Absolute(it) },
|
lineHeight = lineHeight,
|
||||||
letterSpacing = letterSpacing
|
fontWeight = weight?.let { ThemeFontWeight.Absolute(it) },
|
||||||
)
|
letterSpacing = letterSpacing
|
||||||
)
|
)
|
||||||
showDialog = false
|
)
|
||||||
},
|
showDialog = false
|
||||||
) {
|
},
|
||||||
|
) {
|
||||||
|
|
||||||
|
|
||||||
val actualFontFamily = fontFamily
|
val actualFontFamily = fontFamily
|
||||||
?: parentValue?.fontFamily
|
?: parentValue?.fontFamily
|
||||||
?: defaultValue?.fontFamily
|
?: defaultValue?.fontFamily
|
||||||
?: defaultValueParent?.fontFamily!!
|
?: defaultValueParent?.fontFamily!!
|
||||||
val actualFontSize = fontSize
|
val actualFontSize = fontSize
|
||||||
?: parentValue?.fontSize
|
?: parentValue?.fontSize
|
||||||
?: defaultValue?.fontSize
|
?: defaultValue?.fontSize
|
||||||
?: defaultValueParent?.fontSize!!
|
?: defaultValueParent?.fontSize!!
|
||||||
val actualLineHeight = lineHeight
|
val actualLineHeight = lineHeight
|
||||||
?: parentValue?.lineHeight
|
?: parentValue?.lineHeight
|
||||||
?: defaultValue?.lineHeight
|
?: defaultValue?.lineHeight
|
||||||
?: defaultValueParent?.lineHeight!!
|
?: defaultValueParent?.lineHeight!!
|
||||||
val actualWeight = when {
|
val actualWeight = when {
|
||||||
weight != null -> FontWeight(weight!!)
|
weight != null -> FontWeight(weight!!)
|
||||||
parentValue?.fontWeight != null -> FontWeight(parentValue.fontWeight!!.weight)
|
parentValue?.fontWeight != null -> FontWeight(parentValue.fontWeight!!.weight)
|
||||||
defaultValue?.fontWeight is ThemeFontWeight.Absolute -> FontWeight((defaultValue.fontWeight as ThemeFontWeight.Absolute).weight)
|
defaultValue?.fontWeight is ThemeFontWeight.Absolute -> FontWeight((defaultValue.fontWeight as ThemeFontWeight.Absolute).weight)
|
||||||
defaultValue?.fontWeight is ThemeFontWeight.Relative &&
|
defaultValue?.fontWeight is ThemeFontWeight.Relative &&
|
||||||
defaultValueParent?.fontWeight is ThemeFontWeight.Absolute -> {
|
defaultValueParent?.fontWeight is ThemeFontWeight.Absolute -> {
|
||||||
FontWeight(
|
FontWeight(
|
||||||
(defaultValueParent.fontWeight as ThemeFontWeight.Absolute).weight +
|
(defaultValueParent.fontWeight as ThemeFontWeight.Absolute).weight +
|
||||||
(defaultValue.fontWeight as ThemeFontWeight.Relative).relativeWeight
|
(defaultValue.fontWeight as ThemeFontWeight.Relative).relativeWeight
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
else -> FontWeight.Normal
|
|
||||||
}
|
}
|
||||||
val actualLetterSpacing = letterSpacing
|
|
||||||
?: parentValue?.letterSpacing
|
|
||||||
?: defaultValue?.letterSpacing
|
|
||||||
?: defaultValueParent?.letterSpacing!!
|
|
||||||
|
|
||||||
Column(
|
else -> FontWeight.Normal
|
||||||
modifier = Modifier.padding(it),
|
}
|
||||||
|
val actualLetterSpacing = letterSpacing
|
||||||
|
?: parentValue?.letterSpacing
|
||||||
|
?: defaultValue?.letterSpacing
|
||||||
|
?: defaultValueParent?.letterSpacing!!
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp)
|
||||||
|
.navigationBarsPadding(),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.heightIn(min = 200.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
Box(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxWidth(),
|
||||||
.fillMaxWidth()
|
text = previewTexts.TwoLines,
|
||||||
.heightIn(min = 200.dp),
|
textAlign = TextAlign.Center,
|
||||||
contentAlignment = Alignment.Center,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
) {
|
fontFamily = fontFamilyOf(context, fonts[actualFontFamily]),
|
||||||
Text(
|
fontSize = actualFontSize.sp,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
lineHeight = actualLineHeight.em,
|
||||||
text = previewTexts.TwoLines,
|
fontWeight = actualWeight,
|
||||||
textAlign = TextAlign.Center,
|
letterSpacing = actualLetterSpacing.em,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
)
|
||||||
fontFamily = fontFamilyOf(context, fonts[actualFontFamily]),
|
}
|
||||||
fontSize = actualFontSize.sp,
|
Row(
|
||||||
lineHeight = actualLineHeight.em,
|
modifier = Modifier
|
||||||
fontWeight = actualWeight,
|
.padding(vertical = 16.dp)
|
||||||
letterSpacing = actualLetterSpacing.em,
|
.fillMaxWidth()
|
||||||
)
|
.horizontalScroll(rememberScrollState()),
|
||||||
}
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
Row(
|
) {
|
||||||
modifier = Modifier
|
for ((name, font) in fonts) {
|
||||||
.padding(vertical = 16.dp)
|
val f = remember(font) { fontFamilyOf(context, font) }
|
||||||
.fillMaxWidth()
|
Column(
|
||||||
.horizontalScroll(rememberScrollState()),
|
modifier = Modifier
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
.width(56.dp),
|
||||||
) {
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
for ((name, font) in fonts) {
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
val f = remember(font) { fontFamilyOf(context, font) }
|
) {
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(56.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
) {
|
|
||||||
|
|
||||||
OutlinedIconToggleButton(
|
OutlinedIconToggleButton(
|
||||||
modifier = Modifier.size(56.dp),
|
modifier = Modifier.size(56.dp),
|
||||||
checked = name == actualFontFamily,
|
checked = name == actualFontFamily,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
if (it) fontFamily = name
|
if (it) fontFamily = name
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Text(
|
|
||||||
text = previewTexts.ExtraShort,
|
|
||||||
fontFamily = f,
|
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
Text(
|
||||||
text = name.capitalize(LocaleList.current),
|
text = previewTexts.ExtraShort,
|
||||||
fontFamily = f,
|
fontFamily = f,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier.width(56.dp),
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.MiddleEllipsis,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Text(
|
||||||
|
text = name.capitalize(LocaleList.current),
|
||||||
|
fontFamily = f,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.width(56.dp),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.MiddleEllipsis,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SliderRow(
|
|
||||||
icon = R.drawable.format_bold_24px,
|
|
||||||
min = 100f,
|
|
||||||
max = 900f,
|
|
||||||
step = 100f,
|
|
||||||
value = actualWeight.weight.toFloat(),
|
|
||||||
onValueChange = { weight = it.toInt() },
|
|
||||||
formatValue = {
|
|
||||||
it.roundToInt().toString()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
SliderRow(
|
|
||||||
icon = R.drawable.format_size_24px,
|
|
||||||
min = floor((defaultValue?.fontSize ?: defaultValueParent?.fontSize)!! / 2f),
|
|
||||||
max = ceil((defaultValue?.fontSize ?: defaultValueParent?.fontSize)!! * 2f),
|
|
||||||
value = actualFontSize.toFloat(),
|
|
||||||
onValueChange = {
|
|
||||||
fontSize = it.roundToInt()
|
|
||||||
},
|
|
||||||
formatValue = {
|
|
||||||
it.roundToInt().toString()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
SliderRow(
|
|
||||||
icon = R.drawable.format_line_spacing_24px,
|
|
||||||
min = 0.5f,
|
|
||||||
max = 2f,
|
|
||||||
step = 0.05f,
|
|
||||||
value = actualLineHeight,
|
|
||||||
onValueChange = { lineHeight = it },
|
|
||||||
formatValue = {
|
|
||||||
(it * 100).roundToInt().toString() + "%"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
SliderRow(
|
|
||||||
icon = R.drawable.format_letter_spacing_24px,
|
|
||||||
min = -0.25f,
|
|
||||||
max = 1f,
|
|
||||||
step = 0.01f,
|
|
||||||
value = actualLetterSpacing,
|
|
||||||
onValueChange = { letterSpacing = (it * 100f).roundToInt() / 100f },
|
|
||||||
formatValue = {
|
|
||||||
(it * 100).roundToInt().toString() + "%"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(top = 16.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
TextButton(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 8.dp)
|
|
||||||
.align(Alignment.End),
|
|
||||||
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
|
||||||
onClick = {
|
|
||||||
fontFamily = null
|
|
||||||
fontSize = null
|
|
||||||
lineHeight = null
|
|
||||||
weight = null
|
|
||||||
letterSpacing = null
|
|
||||||
onValueChange(null)
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painterResource(R.drawable.restart_alt_20px), null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(ButtonDefaults.IconSpacing)
|
|
||||||
.size(ButtonDefaults.IconSize)
|
|
||||||
)
|
|
||||||
Text(stringResource(R.string.preference_restore_default))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
SliderRow(
|
||||||
|
icon = R.drawable.format_bold_24px,
|
||||||
|
min = 100f,
|
||||||
|
max = 900f,
|
||||||
|
step = 100f,
|
||||||
|
value = actualWeight.weight.toFloat(),
|
||||||
|
onValueChange = { weight = it.toInt() },
|
||||||
|
formatValue = {
|
||||||
|
it.roundToInt().toString()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
SliderRow(
|
||||||
|
icon = R.drawable.format_size_24px,
|
||||||
|
min = floor((defaultValue?.fontSize ?: defaultValueParent?.fontSize)!! / 2f),
|
||||||
|
max = ceil((defaultValue?.fontSize ?: defaultValueParent?.fontSize)!! * 2f),
|
||||||
|
value = actualFontSize.toFloat(),
|
||||||
|
onValueChange = {
|
||||||
|
fontSize = it.roundToInt()
|
||||||
|
},
|
||||||
|
formatValue = {
|
||||||
|
it.roundToInt().toString()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
SliderRow(
|
||||||
|
icon = R.drawable.format_line_spacing_24px,
|
||||||
|
min = 0.5f,
|
||||||
|
max = 2f,
|
||||||
|
step = 0.05f,
|
||||||
|
value = actualLineHeight,
|
||||||
|
onValueChange = { lineHeight = it },
|
||||||
|
formatValue = {
|
||||||
|
(it * 100).roundToInt().toString() + "%"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
SliderRow(
|
||||||
|
icon = R.drawable.format_letter_spacing_24px,
|
||||||
|
min = -0.25f,
|
||||||
|
max = 1f,
|
||||||
|
step = 0.01f,
|
||||||
|
value = actualLetterSpacing,
|
||||||
|
onValueChange = { letterSpacing = (it * 100f).roundToInt() / 100f },
|
||||||
|
formatValue = {
|
||||||
|
(it * 100).roundToInt().toString() + "%"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.padding(top = 16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 8.dp)
|
||||||
|
.align(Alignment.End),
|
||||||
|
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
||||||
|
onClick = {
|
||||||
|
fontFamily = null
|
||||||
|
fontSize = null
|
||||||
|
lineHeight = null
|
||||||
|
weight = null
|
||||||
|
letterSpacing = null
|
||||||
|
onValueChange(null)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.restart_alt_20px), null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(ButtonDefaults.IconSpacing)
|
||||||
|
.size(ButtonDefaults.IconSize)
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.preference_restore_default))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user