Make clock widget configurable from home screen
This commit is contained in:
parent
6cf8747eee
commit
b518e1713c
@ -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(),
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 -> ""
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user