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) .padding(top = editModePadding)
) { ) {
ClockWidget(
AnimatedVisibility(!isWidgetEditMode) {
Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.then(clockHeight?.let { Modifier.height(it) } .then(clockHeight?.let { Modifier.height(it) } ?: Modifier)
?: Modifier)
.padding(bottom = clockPadding), .padding(bottom = clockPadding),
contentAlignment = Alignment.BottomCenter editMode = isWidgetEditMode,
) {
ClockWidget(
modifier = Modifier.fillMaxWidth()
) )
}
}
WidgetColumn( WidgetColumn(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),

View File

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

View File

@ -1,5 +1,7 @@
package de.mm20.launcher2.ui.launcher.widgets.clock 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.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource 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.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState 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.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.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext 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.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout 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.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.AnalogClock
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.BinaryClock 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.DigitalClock1
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.DigitalClock2 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.clocks.OrbitClock
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.PartProvider 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.locals.LocalPreferDarkContentOverWallpaper
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreenVM
import kotlinx.coroutines.launch
@Composable @Composable
fun ClockWidget( fun ClockWidget(
modifier: Modifier = Modifier modifier: Modifier = Modifier,
editMode: Boolean = false,
) { ) {
val viewModel: ClockWidgetVM = viewModel() val viewModel: ClockWidgetVM = viewModel()
val context = LocalContext.current val context = LocalContext.current
@ -50,6 +96,13 @@ fun ClockWidget(
val color by viewModel.color.collectAsState() val color by viewModel.color.collectAsState()
val time = LocalTime.current 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) { LaunchedEffect(time) {
viewModel.updateTime(time) viewModel.updateTime(time)
} }
@ -58,19 +111,54 @@ fun ClockWidget(
emptyList() emptyList()
) )
Box( AnimatedContent(editMode, label = "ClockWidget") {
if (it) {
var configure by remember { mutableStateOf(false) }
Column {
Surface(
modifier = Modifier modifier = Modifier
.fillMaxWidth(), .fillMaxWidth()
.padding(vertical = 8.dp),
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colorScheme.surfaceVariant,
shadowElevation = 2.dp,
tonalElevation = 2.dp,
) {
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 contentAlignment = Alignment.BottomCenter
) { ) {
val contentColor =
if (color == ClockWidgetColors.Auto && LocalPreferDarkContentOverWallpaper.current || color == ClockWidgetColors.Dark) {
Color(0, 0, 0, 180)
} else {
Color.White
}
CompositionLocalProvider( CompositionLocalProvider(
LocalContentColor provides contentColor LocalContentColor provides contentColor
) { ) {
@ -153,6 +241,8 @@ fun ClockWidget(
} }
} }
} }
}
}
@Composable @Composable
fun Clock( fun Clock(
@ -183,3 +273,202 @@ fun DynamicZone(
provider?.Component(layout) 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 -> ""
}
}