Make clock widget configurable from home screen

This commit is contained in:
MM20 2023-10-12 20:28:41 +02:00
parent 6cf8747eee
commit b518e1713c
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
4 changed files with 669 additions and 115 deletions

View File

@ -482,21 +482,13 @@ fun PagerScaffold(
)
.padding(top = editModePadding)
) {
AnimatedVisibility(!isWidgetEditMode) {
Box(
modifier = Modifier
.fillMaxWidth()
.then(clockHeight?.let { Modifier.height(it) }
?: Modifier)
.padding(bottom = clockPadding),
contentAlignment = Alignment.BottomCenter
) {
ClockWidget(
modifier = Modifier.fillMaxWidth()
)
}
}
ClockWidget(
modifier = Modifier
.fillMaxWidth()
.then(clockHeight?.let { Modifier.height(it) } ?: Modifier)
.padding(bottom = clockPadding),
editMode = isWidgetEditMode,
)
WidgetColumn(
modifier = Modifier.fillMaxWidth(),

View File

@ -1,6 +1,5 @@
package de.mm20.launcher2.ui.launcher
import android.app.WallpaperManager
import android.view.HapticFeedbackConstants
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
@ -50,15 +49,12 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
@ -295,6 +291,7 @@ fun PullDownScaffold(
}
true
}
else -> false
}
}
@ -469,20 +466,14 @@ fun PullDownScaffold(
)
.padding(top = editModePadding)
) {
AnimatedVisibility(!isWidgetEditMode) {
Box(
modifier = Modifier
.fillMaxWidth()
.then(clockHeight?.let { Modifier.height(it) }
?: Modifier)
.padding(bottom = clockPadding),
contentAlignment = Alignment.BottomCenter
) {
ClockWidget(
modifier = Modifier.fillMaxWidth()
)
}
}
ClockWidget(
modifier = Modifier
.fillMaxWidth()
.then(clockHeight?.let { Modifier.height(it) } ?: Modifier)
.padding(bottom = clockPadding),
editMode = isWidgetEditMode,
)
WidgetColumn(
modifier = Modifier.fillMaxWidth(),
editMode = isWidgetEditMode,
@ -505,8 +496,14 @@ fun PullDownScaffold(
pagerState.currentPage + pagerState.currentPageOffsetFraction
transformOrigin = TransformOrigin.Center
alpha = min(progress, 1f - dragProgress * 0.1f)
scaleX = min(1f - (dragProgress * 0.05f), 1f - (1f - progress) * 0.1f)
scaleY = min(1f - (dragProgress * 0.05f),1f - (1f - progress) * 0.1f)
scaleX = min(
1f - (dragProgress * 0.05f),
1f - (1f - progress) * 0.1f
)
scaleY = min(
1f - (dragProgress * 0.05f),
1f - (1f - progress) * 0.1f
)
}
.fillMaxSize()
.padding(

View File

@ -1,5 +1,7 @@
package de.mm20.launcher2.ui.launcher.widgets.clock
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
@ -10,38 +12,82 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Alarm
import androidx.compose.material.icons.rounded.AutoAwesome
import androidx.compose.material.icons.rounded.BatteryFull
import androidx.compose.material.icons.rounded.ChevronLeft
import androidx.compose.material.icons.rounded.ChevronRight
import androidx.compose.material.icons.rounded.DarkMode
import androidx.compose.material.icons.rounded.Height
import androidx.compose.material.icons.rounded.HorizontalSplit
import androidx.compose.material.icons.rounded.LightMode
import androidx.compose.material.icons.rounded.MusicNote
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material.icons.rounded.Style
import androidx.compose.material.icons.rounded.Today
import androidx.compose.material.icons.rounded.Tune
import androidx.compose.material.icons.rounded.VerticalSplit
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.base.LocalTime
import de.mm20.launcher2.ui.component.BottomSheetDialog
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.AnalogClock
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.BinaryClock
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.DigitalClock1
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.DigitalClock2
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.OrbitClock
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.PartProvider
import de.mm20.launcher2.ui.locals.LocalDarkTheme
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreenVM
import kotlinx.coroutines.launch
@Composable
fun ClockWidget(
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
editMode: Boolean = false,
) {
val viewModel: ClockWidgetVM = viewModel()
val context = LocalContext.current
@ -50,6 +96,13 @@ fun ClockWidget(
val color by viewModel.color.collectAsState()
val time = LocalTime.current
val contentColor =
if (color == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || color == ClockWidgetColors.Dark) {
Color(0, 0, 0, 180)
} else {
Color.White
}
LaunchedEffect(time) {
viewModel.updateTime(time)
}
@ -58,95 +111,132 @@ fun ClockWidget(
emptyList()
)
Box(
modifier = Modifier
.fillMaxWidth(),
contentAlignment = Alignment.BottomCenter
) {
val contentColor =
if (color == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || color == ClockWidgetColors.Dark) {
Color(0, 0, 0, 180)
} else {
Color.White
}
CompositionLocalProvider(
LocalContentColor provides contentColor
) {
if (layout == ClockWidgetLayout.Vertical) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier.clickable(
enabled = clockStyle != ClockStyle.EmptyClock,
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
viewModel.launchClockApp(context)
}
) {
Clock(clockStyle, ClockWidgetLayout.Vertical)
}
for (part in partProviders) {
DynamicZone(
modifier = Modifier.padding(bottom = 8.dp),
layout = ClockWidgetLayout.Vertical,
provider = part,
)
}
}
}
if (layout == ClockWidgetLayout.Horizontal) {
Row(
AnimatedContent(editMode, label = "ClockWidget") {
if (it) {
var configure by remember { mutableStateOf(false) }
Column {
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(end = 8.dp, bottom = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
.padding(vertical = 8.dp),
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colorScheme.surfaceVariant,
shadowElevation = 2.dp,
tonalElevation = 2.dp,
) {
if (partProviders.size > 1) {
HorizontalPager(
state = rememberPagerState { 2 },
beyondBoundsPageCount = 1,
modifier = Modifier.weight(1f)
Row(
modifier = Modifier.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(modifier = Modifier.size(24.dp))
Text(
text = stringResource(id = R.string.preference_screen_clockwidget),
style = MaterialTheme.typography.titleMedium,
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp),
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
IconButton(onClick = {
configure = true
}) {
Icon(
imageVector = Icons.Rounded.Tune,
contentDescription = stringResource(R.string.settings)
)
}
}
}
HorizontalDivider()
if (configure) {
ConfigureClockWidgetSheet(onDismiss = { configure = false })
}
}
} else {
Box(
modifier = modifier,
contentAlignment = Alignment.BottomCenter
) {
CompositionLocalProvider(
LocalContentColor provides contentColor
) {
if (layout == ClockWidgetLayout.Vertical) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
partProviders.getOrNull(it)?.let {
Box(
modifier = Modifier.clickable(
enabled = clockStyle != ClockStyle.EmptyClock,
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
viewModel.launchClockApp(context)
}
) {
Clock(clockStyle, ClockWidgetLayout.Vertical)
}
for (part in partProviders) {
DynamicZone(
modifier = Modifier.fillMaxWidth(),
layout = ClockWidgetLayout.Horizontal,
provider = it,
modifier = Modifier.padding(bottom = 8.dp),
layout = ClockWidgetLayout.Vertical,
provider = part,
)
}
}
} else if (partProviders.isNotEmpty()) {
DynamicZone(
modifier = Modifier.weight(1f),
layout = ClockWidgetLayout.Horizontal,
provider = partProviders[0],
)
}
Box(
modifier = Modifier
.padding(horizontal = 16.dp)
.height(56.dp)
.width(2.dp)
.background(
LocalContentColor.current
),
)
Box(
modifier = Modifier.clickable(
enabled = clockStyle != ClockStyle.EmptyClock,
indication = null,
interactionSource = remember { MutableInteractionSource() }
if (layout == ClockWidgetLayout.Horizontal) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(end = 8.dp, bottom = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
viewModel.launchClockApp(context)
if (partProviders.size > 1) {
HorizontalPager(
state = rememberPagerState { 2 },
beyondBoundsPageCount = 1,
modifier = Modifier.weight(1f)
) {
partProviders.getOrNull(it)?.let {
DynamicZone(
modifier = Modifier.fillMaxWidth(),
layout = ClockWidgetLayout.Horizontal,
provider = it,
)
}
}
} else if (partProviders.isNotEmpty()) {
DynamicZone(
modifier = Modifier.weight(1f),
layout = ClockWidgetLayout.Horizontal,
provider = partProviders[0],
)
}
Box(
modifier = Modifier
.padding(horizontal = 16.dp)
.height(56.dp)
.width(2.dp)
.background(
LocalContentColor.current
),
)
Box(
modifier = Modifier.clickable(
enabled = clockStyle != ClockStyle.EmptyClock,
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
viewModel.launchClockApp(context)
}
) {
Clock(clockStyle, ClockWidgetLayout.Horizontal)
}
}
) {
Clock(clockStyle, ClockWidgetLayout.Horizontal)
}
}
}
@ -182,4 +272,203 @@ fun DynamicZone(
) {
provider?.Component(layout)
}
}
}
@Composable
fun ConfigureClockWidgetSheet(
onDismiss: () -> Unit,
) {
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
val layout by viewModel.layout.collectAsState()
val color by viewModel.color.collectAsState()
val style by viewModel.clockStyle.collectAsState()
val fillHeight by viewModel.fillHeight.collectAsState()
val date by viewModel.datePart.collectAsState()
val favorites by viewModel.favoritesPart.collectAsState()
val media by viewModel.musicPart.collectAsState()
val alarm by viewModel.alarmPart.collectAsState()
val battery by viewModel.batteryPart.collectAsState()
BottomSheetDialog(onDismissRequest = onDismiss) {
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.fillMaxWidth()
.padding(it)
) {
SingleChoiceSegmentedButtonRow(
modifier = Modifier.fillMaxWidth(),
) {
SegmentedButton(
selected = layout == ClockWidgetLayout.Vertical,
onClick = {
viewModel.setLayout(ClockWidgetLayout.Vertical)
},
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
icon = {
SegmentedButtonDefaults.Icon(
active = layout == ClockWidgetLayout.Vertical,
) {
Icon(
imageVector = Icons.Rounded.HorizontalSplit,
contentDescription = null,
modifier = Modifier.size(SegmentedButtonDefaults.IconSize)
)
}
}
) {
Text(text = stringResource(R.string.preference_clockwidget_layout_vertical))
}
SegmentedButton(
selected = layout == ClockWidgetLayout.Horizontal,
onClick = {
viewModel.setLayout(ClockWidgetLayout.Horizontal)
},
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
icon = {
SegmentedButtonDefaults.Icon(
active = layout == ClockWidgetLayout.Horizontal,
) {
Icon(
imageVector = Icons.Rounded.VerticalSplit,
contentDescription = null,
modifier = Modifier.size(SegmentedButtonDefaults.IconSize)
)
}
}
) {
Text(text = stringResource(R.string.preference_clockwidget_layout_horizontal))
}
}
if (color != null && layout != null) {
WatchFaceSelector(layout = layout!!, colors = color!!, selected = style, onSelect = {
viewModel.setClockStyle(it)
})
}
SingleChoiceSegmentedButtonRow(
modifier = Modifier.fillMaxWidth(),
) {
SegmentedButton(
selected = color == ClockWidgetColors.Auto,
onClick = {
viewModel.setColor(ClockWidgetColors.Auto)
},
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 3),
) {
Icon(
imageVector = Icons.Rounded.AutoAwesome,
contentDescription = null,
modifier = Modifier.size(SegmentedButtonDefaults.IconSize)
)
}
SegmentedButton(
selected = color == ClockWidgetColors.Dark,
onClick = {
viewModel.setColor(ClockWidgetColors.Dark)
},
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 3),
) {
Icon(
imageVector = Icons.Rounded.LightMode,
contentDescription = null,
modifier = Modifier.size(SegmentedButtonDefaults.IconSize)
)
}
SegmentedButton(
selected = color == ClockWidgetColors.Light,
onClick = {
viewModel.setColor(ClockWidgetColors.Light)
},
shape = SegmentedButtonDefaults.itemShape(index = 2, count = 3),
) {
Icon(
imageVector = Icons.Rounded.DarkMode,
contentDescription = null,
modifier = Modifier.size(SegmentedButtonDefaults.IconSize)
)
}
}
OutlinedCard(
modifier = Modifier.padding(top = 16.dp),
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
SwitchPreference(
title = stringResource(R.string.preference_clock_widget_fill_height),
icon = Icons.Rounded.Height,
value = fillHeight == true,
onValueChanged = {
viewModel.setFillHeight(it)
}
)
}
}
OutlinedCard(
modifier = Modifier.padding(top = 16.dp),
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
SwitchPreference(
title = stringResource(R.string.preference_clockwidget_date_part),
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
icon = Icons.Rounded.Today,
value = date == true,
onValueChanged = {
viewModel.setDatePart(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_clockwidget_favorites_part),
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
icon = Icons.Rounded.Star,
value = favorites == true,
onValueChanged = {
viewModel.setFavoritesPart(it)
}
)
}
}
OutlinedCard(
modifier = Modifier.padding(top = 16.dp),
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
SwitchPreference(
title = stringResource(R.string.preference_clockwidget_music_part),
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
icon = Icons.Rounded.MusicNote,
value = media == true,
onValueChanged = {
viewModel.setMusicPart(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_clockwidget_alarm_part),
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
icon = Icons.Rounded.Alarm,
value = alarm == true,
onValueChanged = {
viewModel.setAlarmPart(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_clockwidget_battery_part),
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
icon = Icons.Rounded.BatteryFull,
value = battery == true,
onValueChanged = {
viewModel.setBatteryPart(it)
}
)
}
}
}
}
}

View File

@ -0,0 +1,276 @@
package de.mm20.launcher2.ui.launcher.widgets.clock
import android.content.Context
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowDropDown
import androidx.compose.material.icons.rounded.ChevronLeft
import androidx.compose.material.icons.rounded.ChevronRight
import androidx.compose.material.icons.rounded.Style
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
import de.mm20.launcher2.ui.locals.LocalDarkTheme
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
import kotlinx.coroutines.launch
@Composable
fun WatchFaceSelector(
layout: ClockWidgetLayout,
colors: ClockWidgetColors,
selected: ClockStyle?,
onSelect: (ClockStyle) -> Unit,
) {
val context = LocalContext.current
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 32.dp),
color = if (colors == ClockWidgetColors.Dark || colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current) {
if (LocalDarkTheme.current) MaterialTheme.colorScheme.inverseSurface else MaterialTheme.colorScheme.surfaceContainer
} else {
if (LocalDarkTheme.current) MaterialTheme.colorScheme.surfaceContainer else MaterialTheme.colorScheme.inverseSurface
},
shape = MaterialTheme.shapes.medium,
) {
Column(
modifier = Modifier,
) {
val styles = remember {
sortedMapOf(
ClockStyle.DigitalClock1 to 0,
ClockStyle.DigitalClock2 to 1,
ClockStyle.AnalogClock to 2,
ClockStyle.OrbitClock to 3,
ClockStyle.BinaryClock to 4,
ClockStyle.EmptyClock to 5,
)
}
val pagerState = rememberPagerState(
initialPage = styles.getOrDefault(selected, 0)
) {
styles.values.max() + 1
}
LaunchedEffect(pagerState.currentPage) {
if (styles.getOrDefault(selected, 0) == pagerState.currentPage) {
return@LaunchedEffect
}
onSelect(styles.entries.first { it.value == pagerState.currentPage }.key)
}
val scope = rememberCoroutineScope()
Box {
androidx.compose.animation.AnimatedVisibility(
styles.entries.count { it.value == pagerState.currentPage } > 1,
modifier = Modifier
.align(Alignment.TopEnd)
.zIndex(1f),
enter = scaleIn(),
exit = scaleOut(),
) {
var showVariantDropdown by remember { mutableStateOf(false) }
IconButton(
onClick = { showVariantDropdown = true },
modifier = Modifier
.padding(4.dp)
) {
Icon(Icons.Rounded.Style, null)
}
DropdownMenu(
expanded = showVariantDropdown,
onDismissRequest = { showVariantDropdown = false }) {
for (variant in styles.filter { it.value == pagerState.currentPage }) {
DropdownMenuItem(
onClick = {
onSelect(variant.key)
showVariantDropdown = false
},
text = {
Text(
text = getVariantName(context, variant.key),
)
}
)
}
}
}
CompositionLocalProvider(
LocalContentColor provides if (colors == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || colors == ClockWidgetColors.Dark) {
Color(0, 0, 0, 180)
} else {
Color.White
},
) {
HorizontalPager(
modifier = Modifier.animateContentSize(),
state = pagerState,
verticalAlignment = Alignment.Top,
) { pageIndex ->
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp, bottom = 8.dp),
contentAlignment = Alignment.TopCenter,
) {
val currentPageStyles = remember {
styles.filter { it.value == pageIndex }
}
if (currentPageStyles.containsKey(selected)) {
Clock(selected, layout)
} else {
Clock(currentPageStyles.keys.first(), layout)
}
}
}
}
}
Row(
verticalAlignment = Alignment.CenterVertically
) {
IconButton(
enabled = pagerState.currentPage > 0,
onClick = {
scope.launch {
pagerState.animateScrollToPage(
pagerState.currentPage - 1,
)
}
}) {
Icon(Icons.Rounded.ChevronLeft, null)
}
var showStyleDropdown by remember { mutableStateOf(false) }
TextButton(
modifier = Modifier
.weight(1f)
.padding(horizontal = 16.dp),
onClick = { showStyleDropdown = true },
contentPadding = PaddingValues(
top = 8.dp,
bottom = 8.dp,
start = 16.dp,
end = 12.dp,
),
colors = ButtonDefaults.textButtonColors(
contentColor = LocalContentColor.current,
),
) {
Text(
text = getClockstyleName(
context,
styles.entries.first { (k, v) -> v == pagerState.currentPage }.key
),
textAlign = TextAlign.Center,
)
Icon(
Icons.Rounded.ArrowDropDown,
null,
modifier = Modifier
.padding(ButtonDefaults.IconSpacing)
.size(ButtonDefaults.IconSize)
)
DropdownMenu(
expanded = showStyleDropdown,
onDismissRequest = { showStyleDropdown = false }
) {
for (style in styles.entries.distinctBy { it.value }) {
DropdownMenuItem(
onClick = {
scope.launch {
pagerState.animateScrollToPage(
style.value,
)
}
showStyleDropdown = false
},
text = {
Text(
text = getClockstyleName(context, style.key),
)
}
)
}
}
}
IconButton(
enabled = pagerState.currentPage < pagerState.pageCount - 1,
onClick = {
scope.launch {
pagerState.animateScrollToPage(
pagerState.currentPage + 1,
)
}
}) {
Icon(Icons.Rounded.ChevronRight, null)
}
}
}
}
}
fun getClockstyleName(context: Context, style: ClockStyle): String {
return when (style) {
ClockStyle.DigitalClock1 -> "Bold"
ClockStyle.DigitalClock2 -> "Simple"
ClockStyle.OrbitClock -> "Orbit"
ClockStyle.BinaryClock -> "Binary"
ClockStyle.AnalogClock -> "Hands"
ClockStyle.EmptyClock -> "Empty"
ClockStyle.UNRECOGNIZED -> ""
}
}
fun getVariantName(context: Context, style: ClockStyle): String {
return when (style) {
ClockStyle.DigitalClock1,
ClockStyle.DigitalClock2,
ClockStyle.OrbitClock,
ClockStyle.BinaryClock,
ClockStyle.AnalogClock,
ClockStyle.EmptyClock -> "Standard"
ClockStyle.UNRECOGNIZED -> ""
}
}