Bring back the option to disable the clock widget's date part
This commit is contained in:
parent
e82fd23619
commit
d54b904c0a
@ -16,13 +16,13 @@ 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.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
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.base.LocalTime
|
import de.mm20.launcher2.ui.base.LocalTime
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.*
|
import de.mm20.launcher2.ui.launcher.widgets.clock.clocks.*
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.FavoritesPartProvider
|
|
||||||
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.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
|
|
||||||
@ -41,8 +41,7 @@ fun ClockWidget(
|
|||||||
viewModel.updateTime(time)
|
viewModel.updateTime(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
val partProvider by remember { viewModel.getActivePart(context) }.collectAsState(null)
|
val partProviders by remember { viewModel.getActiveParts(context) }.collectAsStateWithLifecycle(emptyList())
|
||||||
val withFavoriteBar by viewModel.withFavorites.observeAsState()
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -76,21 +75,11 @@ fun ClockWidget(
|
|||||||
Clock(clockStyle, ClockWidgetLayout.Vertical)
|
Clock(clockStyle, ClockWidgetLayout.Vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (part in partProviders) {
|
||||||
DynamicZone(
|
DynamicZone(
|
||||||
modifier = if (true == withFavoriteBar) {
|
modifier = Modifier.padding(bottom = 8.dp),
|
||||||
Modifier.padding(bottom = 8.dp, top = 8.dp)
|
|
||||||
} else {
|
|
||||||
Modifier.padding(bottom = 16.dp)
|
|
||||||
},
|
|
||||||
layout = ClockWidgetLayout.Vertical,
|
layout = ClockWidgetLayout.Vertical,
|
||||||
provider = partProvider,
|
provider = part,
|
||||||
)
|
|
||||||
|
|
||||||
if (true == withFavoriteBar) {
|
|
||||||
DynamicZone(
|
|
||||||
modifier = Modifier.padding(bottom = 16.dp),
|
|
||||||
layout = ClockWidgetLayout.Vertical,
|
|
||||||
provider = viewModel.favoritesPartProvider,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,7 +99,7 @@ fun ClockWidget(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
if (true == withFavoriteBar) {
|
if (partProviders.size > 1) {
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
pageCount = 2,
|
pageCount = 2,
|
||||||
beyondBoundsPageCount = 1,
|
beyondBoundsPageCount = 1,
|
||||||
@ -119,17 +108,14 @@ fun ClockWidget(
|
|||||||
DynamicZone(
|
DynamicZone(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
layout = ClockWidgetLayout.Horizontal,
|
layout = ClockWidgetLayout.Horizontal,
|
||||||
provider = when (it) {
|
provider = partProviders[it],
|
||||||
0 -> viewModel.favoritesPartProvider
|
|
||||||
else -> partProvider
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else if (partProviders.isNotEmpty()) {
|
||||||
DynamicZone(
|
DynamicZone(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
layout = ClockWidgetLayout.Horizontal,
|
layout = ClockWidgetLayout.Horizontal,
|
||||||
provider = partProvider
|
provider = partProviders[0],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Box(
|
Box(
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.clock
|
package de.mm20.launcher2.ui.launcher.widgets.clock
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.provider.AlarmClock
|
import android.provider.AlarmClock
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@ -11,55 +9,47 @@ import androidx.lifecycle.asLiveData
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.*
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.AlarmPartProvider
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.BatteryPartProvider
|
||||||
import kotlinx.coroutines.channels.trySendBlocking
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.DatePartProvider
|
||||||
import kotlinx.coroutines.flow.*
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.FavoritesPartProvider
|
||||||
import kotlinx.coroutines.launch
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.MusicPartProvider
|
||||||
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.PartProvider
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class ClockWidgetVM : ViewModel(), KoinComponent {
|
class ClockWidgetVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
private val partProviders = MutableStateFlow<List<PartProvider>>(emptyList())
|
private val partProviders = dataStore.data.map { it.clockWidget }.distinctUntilChanged().map {
|
||||||
|
val providers = mutableListOf<PartProvider>()
|
||||||
init {
|
if (it.datePart) providers += DatePartProvider()
|
||||||
viewModelScope.launch {
|
if (it.favoritesPart) providers += FavoritesPartProvider()
|
||||||
dataStore.data.map { it.clockWidget }.distinctUntilChanged().collectLatest {
|
|
||||||
val providers = mutableListOf<PartProvider>(
|
|
||||||
DatePartProvider()
|
|
||||||
)
|
|
||||||
if (it.musicPart) providers += MusicPartProvider()
|
if (it.musicPart) providers += MusicPartProvider()
|
||||||
if (it.batteryPart) providers += BatteryPartProvider()
|
if (it.batteryPart) providers += BatteryPartProvider()
|
||||||
if (it.alarmPart) providers += AlarmPartProvider()
|
if (it.alarmPart) providers += AlarmPartProvider()
|
||||||
partProviders.value = providers
|
providers
|
||||||
}
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val withFavorites = dataStore.data.map { it.clockWidget.favoritesPart }.asLiveData()
|
fun getActiveParts(context: Context): Flow<List<PartProvider>> = channelFlow {
|
||||||
val favoritesPartProvider = FavoritesPartProvider()
|
|
||||||
|
|
||||||
val time = MutableStateFlow(System.currentTimeMillis())
|
|
||||||
|
|
||||||
fun getActivePart(context: Context): Flow<PartProvider?> = channelFlow {
|
|
||||||
partProviders.collectLatest { providers ->
|
partProviders.collectLatest { providers ->
|
||||||
if (providers.isEmpty()) {
|
if (providers.isEmpty()) {
|
||||||
send(null)
|
send(emptyList())
|
||||||
return@collectLatest
|
return@collectLatest
|
||||||
}
|
}
|
||||||
val rankings = providers.map { it.getRanking(context) }
|
val rankings = providers.map { it.getRanking(context).map { r -> r to it } }
|
||||||
combine(rankings) { r ->
|
combine(rankings) { r ->
|
||||||
var prov = providers[0]
|
val sorted = r.sortedBy { it.first }
|
||||||
var ranking = r[0]
|
sorted.takeLast(if (sorted.last().second is FavoritesPartProvider) 2 else 1)
|
||||||
for (i in 1 until providers.size) {
|
.map { it.second }
|
||||||
if (ranking < r[i]) {
|
|
||||||
prov = providers[i]
|
|
||||||
ranking = r[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return@combine prov
|
|
||||||
}.collectLatest {
|
}.collectLatest {
|
||||||
send(it)
|
send(it)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class FavoritesPartProvider : PartProvider, KoinComponent {
|
|||||||
private val dataStore: LauncherDataStore by inject()
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
override fun getRanking(context: Context): Flow<Int> = flow {
|
override fun getRanking(context: Context): Flow<Int> = flow {
|
||||||
emit(2)
|
emit(Int.MAX_VALUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@ -75,6 +75,20 @@ fun ClockWidgetSettingsScreen() {
|
|||||||
value = fillHeight == true,
|
value = fillHeight == true,
|
||||||
onValueChanged = { viewModel.setFillHeight(it) }
|
onValueChanged = { viewModel.setFillHeight(it) }
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
PreferenceCategory {
|
||||||
|
val datePart by viewModel.datePart.observeAsState()
|
||||||
|
SwitchPreference(
|
||||||
|
title = stringResource(R.string.preference_clockwidget_date_part),
|
||||||
|
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
||||||
|
icon = Icons.Rounded.Today,
|
||||||
|
value = datePart == true,
|
||||||
|
onValueChanged = {
|
||||||
|
viewModel.setDatePart(it)
|
||||||
|
},
|
||||||
|
)
|
||||||
val favoritesPart by viewModel.favoritesPart.observeAsState()
|
val favoritesPart by viewModel.favoritesPart.observeAsState()
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
||||||
|
|||||||
@ -66,6 +66,19 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val datePart = dataStore.data.map { it.clockWidget.datePart }.asLiveData()
|
||||||
|
fun setDatePart(datePart: Boolean) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
dataStore.updateData {
|
||||||
|
it.toBuilder()
|
||||||
|
.setClockWidget(
|
||||||
|
it.clockWidget.toBuilder()
|
||||||
|
.setDatePart(datePart)
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val favoritesPart = dataStore.data.map { it.clockWidget.favoritesPart }.asLiveData()
|
val favoritesPart = dataStore.data.map { it.clockWidget.favoritesPart }.asLiveData()
|
||||||
fun setFavoritesPart(favoritesPart: Boolean) {
|
fun setFavoritesPart(favoritesPart: Boolean) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ internal val Context.dataStore: LauncherDataStore by dataStore(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
internal const val SchemaVersion = 12
|
internal const val SchemaVersion = 13
|
||||||
|
|
||||||
internal fun getMigrations(context: Context): List<DataMigration<Settings>> {
|
internal fun getMigrations(context: Context): List<DataMigration<Settings>> {
|
||||||
return listOf(
|
return listOf(
|
||||||
@ -38,5 +38,6 @@ internal fun getMigrations(context: Context): List<DataMigration<Settings>> {
|
|||||||
Migration_9_10(),
|
Migration_9_10(),
|
||||||
Migration_10_11(),
|
Migration_10_11(),
|
||||||
Migration_11_12(),
|
Migration_11_12(),
|
||||||
|
Migration_12_13(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -51,6 +51,7 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setAlarmPart(true)
|
.setAlarmPart(true)
|
||||||
.setBatteryPart(true)
|
.setBatteryPart(true)
|
||||||
.setMusicPart(true)
|
.setMusicPart(true)
|
||||||
|
.setDatePart(true)
|
||||||
.setFavoritesPart(false)
|
.setFavoritesPart(false)
|
||||||
.setFillHeight(true)
|
.setFillHeight(true)
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
|
import de.mm20.launcher2.preferences.Settings
|
||||||
|
|
||||||
|
class Migration_12_13: VersionedMigration(12, 13) {
|
||||||
|
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||||
|
return builder
|
||||||
|
.setClockWidget(
|
||||||
|
builder.clockWidget.toBuilder()
|
||||||
|
.setDatePart(true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -116,7 +116,7 @@ message Settings {
|
|||||||
EmptyClock = 4;
|
EmptyClock = 4;
|
||||||
}
|
}
|
||||||
ClockStyle clock_style = 2;
|
ClockStyle clock_style = 2;
|
||||||
reserved 3;
|
bool date_part = 3;
|
||||||
bool music_part = 4;
|
bool music_part = 4;
|
||||||
bool battery_part = 5;
|
bool battery_part = 5;
|
||||||
bool alarm_part = 6;
|
bool alarm_part = 6;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user