diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt index 0e38bfd0..6270b499 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt @@ -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(), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt index 110d5f5c..251ded4d 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt index 6a71622a..c8ebb82f 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt @@ -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) } -} \ No newline at end of file +} + +@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) + } + ) + } + } + } + } +} diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt new file mode 100644 index 00000000..4292369e --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt @@ -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 -> "" + } +} \ No newline at end of file