Refactor preferences module
This commit is contained in:
parent
94aee6baba
commit
92ddc75060
@ -19,19 +19,17 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM
|
import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM
|
||||||
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
|
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
|
||||||
import de.mm20.launcher2.ui.launcher.helper.WallpaperBlur
|
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchColumn
|
import de.mm20.launcher2.ui.launcher.search.SearchColumn
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
||||||
import de.mm20.launcher2.ui.launcher.searchbar.LauncherSearchBar
|
import de.mm20.launcher2.ui.launcher.searchbar.LauncherSearchBar
|
||||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AssistantScaffold(
|
fun AssistantScaffold(
|
||||||
@ -204,7 +202,7 @@ fun AssistantScaffold(
|
|||||||
showHiddenItemsButton = true,
|
showHiddenItemsButton = true,
|
||||||
value = { value },
|
value = { value },
|
||||||
onValueChange = { searchVM.search(it) },
|
onValueChange = { searchVM.search(it) },
|
||||||
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == Settings.SearchBarSettings.SearchBarColors.Auto || searchBarColor == Settings.SearchBarSettings.SearchBarColors.Dark,
|
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == SearchBarColors.Auto || searchBarColor == SearchBarColors.Dark,
|
||||||
style = searchBarStyle,
|
style = searchBarStyle,
|
||||||
reverse = bottomSearchBar,
|
reverse = bottomSearchBar,
|
||||||
onKeyboardActionGo = if (launchOnEnter) {
|
onKeyboardActionGo = if (launchOnEnter) {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package de.mm20.launcher2.ui.base
|
package de.mm20.launcher2.ui.base
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.unit.dp
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||||
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.ui.component.ProvideIconShape
|
import de.mm20.launcher2.ui.component.ProvideIconShape
|
||||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||||
@ -19,32 +21,28 @@ import org.koin.androidx.compose.inject
|
|||||||
fun ProvideSettings(
|
fun ProvideSettings(
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val dataStore: LauncherDataStore by inject()
|
val settings: UiSettings by inject()
|
||||||
val widgetRepository: WidgetRepository by inject()
|
val widgetRepository: WidgetRepository by inject()
|
||||||
|
|
||||||
val cardStyle by remember {
|
val cardStyle by remember {
|
||||||
dataStore.data.map { it.cards }.distinctUntilChanged()
|
settings.cardStyle.distinctUntilChanged()
|
||||||
}.collectAsState(
|
}.collectAsState(
|
||||||
Settings.CardSettings.getDefaultInstance()
|
CardStyle()
|
||||||
)
|
)
|
||||||
val iconShape by remember {
|
val iconShape by remember {
|
||||||
dataStore.data.map {
|
settings.iconShape.distinctUntilChanged()
|
||||||
if (it.easterEgg) Settings.IconSettings.IconShape.EasterEgg
|
}.collectAsState(IconShape.Circle)
|
||||||
else it.icons.shape
|
|
||||||
}.distinctUntilChanged()
|
|
||||||
}.collectAsState(Settings.IconSettings.IconShape.Circle)
|
|
||||||
|
|
||||||
val favoritesEnabled by remember {
|
val favoritesEnabled by remember {
|
||||||
combine(
|
combine(
|
||||||
widgetRepository.exists(FavoritesWidget.Type),
|
widgetRepository.exists(FavoritesWidget.Type),
|
||||||
dataStore.data.map { it.favorites.enabled },
|
settings.favoritesEnabled,
|
||||||
dataStore.data.map { it.clockWidget.favoritesPart },
|
) { a, b -> a || b }.distinctUntilChanged()
|
||||||
) { a, b, c -> a || b || c }.distinctUntilChanged()
|
|
||||||
}.collectAsState(true)
|
}.collectAsState(true)
|
||||||
|
|
||||||
val gridSettings by remember {
|
val gridSettings by remember {
|
||||||
dataStore.data.map { it.grid }.distinctUntilChanged()
|
settings.gridSettings.distinctUntilChanged()
|
||||||
}.collectAsState(Settings.GridSettings.newBuilder().setColumnCount(5).setShowLabels(true).setIconSize(48).build())
|
}.collectAsState(GridSettings())
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalCardStyle provides cardStyle,
|
LocalCardStyle provides cardStyle,
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
||||||
import de.mm20.launcher2.data.customattrs.utils.withCustomLabels
|
import de.mm20.launcher2.data.customattrs.utils.withCustomLabels
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettingsData
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.data.Tag
|
import de.mm20.launcher2.search.data.Tag
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
@ -19,11 +20,11 @@ abstract class FavoritesVM : ViewModel(), KoinComponent {
|
|||||||
private val favoritesService: FavoritesService by inject()
|
private val favoritesService: FavoritesService by inject()
|
||||||
internal val widgetRepository: WidgetRepository by inject()
|
internal val widgetRepository: WidgetRepository by inject()
|
||||||
private val customAttributesRepository: CustomAttributesRepository by inject()
|
private val customAttributesRepository: CustomAttributesRepository by inject()
|
||||||
internal val dataStore: LauncherDataStore by inject()
|
internal val settings: FavoritesSettings by inject()
|
||||||
|
|
||||||
val selectedTag = MutableStateFlow<String?>(null)
|
val selectedTag = MutableStateFlow<String?>(null)
|
||||||
|
|
||||||
val showEditButton = dataStore.data.map { it.favorites.editButton }
|
val showEditButton = settings.showEditButton
|
||||||
abstract val tagsExpanded: Flow<Boolean>
|
abstract val tagsExpanded: Flow<Boolean>
|
||||||
|
|
||||||
val pinnedTags = favoritesService.getFavorites(
|
val pinnedTags = favoritesService.getFavorites(
|
||||||
@ -36,24 +37,18 @@ abstract class FavoritesVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
open val favorites: Flow<List<SavableSearchable>> = selectedTag.flatMapLatest { tag ->
|
open val favorites: Flow<List<SavableSearchable>> = selectedTag.flatMapLatest { tag ->
|
||||||
if (tag == null) {
|
if (tag == null) {
|
||||||
val columns = dataStore.data.map { it.grid.columnCount }
|
|
||||||
val excludeCalendar = widgetRepository.exists(CalendarWidget.Type)
|
val excludeCalendar = widgetRepository.exists(CalendarWidget.Type)
|
||||||
val includeFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
|
||||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
|
||||||
|
|
||||||
combine(
|
combine(
|
||||||
listOf(
|
|
||||||
columns,
|
|
||||||
excludeCalendar,
|
excludeCalendar,
|
||||||
includeFrequentlyUsed,
|
settings,
|
||||||
frequentlyUsedRows
|
) { (a, b) -> a as Boolean to b as FavoritesSettingsData }
|
||||||
)
|
.transformLatest {
|
||||||
) { it }.transformLatest {
|
|
||||||
|
|
||||||
val columns = it[0] as Int
|
val columns = it.second.columns
|
||||||
val excludeCalendar = it[1] as Boolean
|
val excludeCalendar = it.first
|
||||||
val includeFrequentlyUsed = it[2] as Boolean
|
val includeFrequentlyUsed = it.second.frequentlyUsed
|
||||||
val frequentlyUsedRows = it[3] as Int
|
val frequentlyUsedRows = it.second.frequentlyUsedRows
|
||||||
|
|
||||||
val pinned = favoritesService.getFavorites(
|
val pinned = favoritesService.getFavorites(
|
||||||
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import android.net.Uri
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ThemeDescriptor
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.themes.Theme
|
import de.mm20.launcher2.themes.Theme
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import de.mm20.launcher2.themes.fromJson
|
import de.mm20.launcher2.themes.fromJson
|
||||||
@ -17,7 +18,7 @@ import org.koin.core.component.inject
|
|||||||
class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val themeRepository: ThemeRepository by inject()
|
private val themeRepository: ThemeRepository by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
val theme = mutableStateOf<Theme?>(null)
|
val theme = mutableStateOf<Theme?>(null)
|
||||||
val error = mutableStateOf<Boolean>(false)
|
val error = mutableStateOf<Boolean>(false)
|
||||||
@ -56,16 +57,10 @@ class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun importTheme(theme: Theme, apply: Boolean) {
|
private fun importTheme(theme: Theme, apply: Boolean) {
|
||||||
themeRepository.createTheme(theme)
|
themeRepository.createTheme(theme)
|
||||||
if (apply) {
|
if (apply) {
|
||||||
dataStore.updateData {
|
uiSettings.setTheme(ThemeDescriptor.Custom(theme.id.toString()))
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setThemeId(theme.id.toString())
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.SearchService
|
import de.mm20.launcher2.search.SearchService
|
||||||
import de.mm20.launcher2.search.toList
|
import de.mm20.launcher2.search.toList
|
||||||
@ -15,7 +14,6 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@ -23,7 +21,6 @@ import org.koin.core.component.inject
|
|||||||
|
|
||||||
class SearchablePickerVM : ViewModel(), KoinComponent {
|
class SearchablePickerVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
private val searchService: SearchService by inject()
|
private val searchService: SearchService by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
|
|
||||||
@ -41,12 +38,8 @@ class SearchablePickerVM: ViewModel(), KoinComponent {
|
|||||||
searchQuery = query
|
searchQuery = query
|
||||||
searchJob?.cancel()
|
searchJob?.cancel()
|
||||||
searchJob = viewModelScope.launch {
|
searchJob = viewModelScope.launch {
|
||||||
val settings = dataStore.data.first()
|
|
||||||
searchService.search(
|
searchService.search(
|
||||||
query = query,
|
query = query,
|
||||||
shortcuts = settings.appShortcutSearch,
|
|
||||||
contacts = settings.contactsSearch,
|
|
||||||
calendars = settings.calendarSearch,
|
|
||||||
).collectLatest {
|
).collectLatest {
|
||||||
if (searchQuery != query) return@collectLatest
|
if (searchQuery != query) return@collectLatest
|
||||||
items = withContext(Dispatchers.Default) {
|
items = withContext(Dispatchers.Default) {
|
||||||
|
|||||||
@ -2,9 +2,9 @@ package de.mm20.launcher2.ui.common
|
|||||||
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import de.mm20.launcher2.weather.WeatherLocation
|
import de.mm20.launcher2.preferences.weather.WeatherLocation
|
||||||
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import androidx.compose.ui.graphics.SolidColor
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.layout.BottomReversed
|
import de.mm20.launcher2.ui.layout.BottomReversed
|
||||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
@ -47,7 +47,7 @@ import de.mm20.launcher2.ui.locals.LocalCardStyle
|
|||||||
@Composable
|
@Composable
|
||||||
fun SearchBar(
|
fun SearchBar(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
style: Settings.SearchBarSettings.SearchBarStyle,
|
style: SearchBarStyle,
|
||||||
level: SearchBarLevel,
|
level: SearchBarLevel,
|
||||||
value: String,
|
value: String,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
@ -78,7 +78,7 @@ fun SearchBar(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
it == SearchBarLevel.Resting && style != Settings.SearchBarSettings.SearchBarStyle.Solid -> 0.dp
|
it == SearchBarLevel.Resting && style != SearchBarStyle.Solid -> 0.dp
|
||||||
it == SearchBarLevel.Raised -> 8.dp
|
it == SearchBarLevel.Raised -> 8.dp
|
||||||
else -> 2.dp
|
else -> 2.dp
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ fun SearchBar(
|
|||||||
}) {
|
}) {
|
||||||
when {
|
when {
|
||||||
it == SearchBarLevel.Active -> LocalCardStyle.current.opacity
|
it == SearchBarLevel.Active -> LocalCardStyle.current.opacity
|
||||||
style != Settings.SearchBarSettings.SearchBarStyle.Transparent -> 1f
|
style != SearchBarStyle.Transparent -> 1f
|
||||||
it == SearchBarLevel.Resting -> 0f
|
it == SearchBarLevel.Resting -> 0f
|
||||||
else -> 1f
|
else -> 1f
|
||||||
}
|
}
|
||||||
@ -117,14 +117,14 @@ fun SearchBar(
|
|||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
when {
|
when {
|
||||||
style != Settings.SearchBarSettings.SearchBarStyle.Transparent -> MaterialTheme.colorScheme.onSurface
|
style != SearchBarStyle.Transparent -> MaterialTheme.colorScheme.onSurface
|
||||||
it == SearchBarLevel.Resting -> if (darkColors) Color(0, 0, 0, 180) else Color.White
|
it == SearchBarLevel.Resting -> if (darkColors) Color(0, 0, 0, 180) else Color.White
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val opacity by transition.animateFloat(label = "opacity") {
|
val opacity by transition.animateFloat(label = "opacity") {
|
||||||
if (style == Settings.SearchBarSettings.SearchBarStyle.Hidden && it == SearchBarLevel.Resting) 0f
|
if (style == SearchBarStyle.Hidden && it == SearchBarLevel.Resting) 0f
|
||||||
else 1f
|
else 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import androidx.compose.animation.core.tween
|
|||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@ -57,7 +56,6 @@ import androidx.compose.ui.graphics.drawscope.withTransform
|
|||||||
import androidx.compose.ui.graphics.nativeCanvas
|
import androidx.compose.ui.graphics.nativeCanvas
|
||||||
import androidx.compose.ui.graphics.toAndroidRect
|
import androidx.compose.ui.graphics.toAndroidRect
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.Density
|
import androidx.compose.ui.unit.Density
|
||||||
@ -80,7 +78,7 @@ import de.mm20.launcher2.icons.TintedClockLayer
|
|||||||
import de.mm20.launcher2.icons.TintedIconLayer
|
import de.mm20.launcher2.icons.TintedIconLayer
|
||||||
import de.mm20.launcher2.icons.TransparentLayer
|
import de.mm20.launcher2.icons.TransparentLayer
|
||||||
import de.mm20.launcher2.ktx.drawWithColorFilter
|
import de.mm20.launcher2.ktx.drawWithColorFilter
|
||||||
import de.mm20.launcher2.preferences.Settings.IconSettings.IconShape
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
import de.mm20.launcher2.ui.base.LocalTime
|
import de.mm20.launcher2.ui.base.LocalTime
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
import de.mm20.launcher2.ui.ktx.toPixels
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
@ -495,7 +493,6 @@ fun getShape(iconShape: IconShape): Shape {
|
|||||||
IconShape.Teardrop -> TeardropShape
|
IconShape.Teardrop -> TeardropShape
|
||||||
IconShape.Pebble -> PebbleShape
|
IconShape.Pebble -> PebbleShape
|
||||||
IconShape.EasterEgg -> EasterEggShape
|
IconShape.EasterEgg -> EasterEggShape
|
||||||
IconShape.UNRECOGNIZED -> CircleShape
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,17 +12,20 @@ import de.mm20.launcher2.searchable.SavableSearchableRepository
|
|||||||
import de.mm20.launcher2.globalactions.GlobalActionsService
|
import de.mm20.launcher2.globalactions.GlobalActionsService
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ColorScheme
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
|
import de.mm20.launcher2.preferences.ScreenOrientation
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.ui.gestures.Gesture
|
import de.mm20.launcher2.ui.gestures.Gesture
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -32,7 +35,8 @@ import org.koin.core.component.inject
|
|||||||
|
|
||||||
class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
private val gestureSettings: GestureSettings by inject()
|
||||||
private val globalActionsService: GlobalActionsService by inject()
|
private val globalActionsService: GlobalActionsService by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
@ -40,40 +44,41 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
private var isSystemInDarkMode = MutableStateFlow(false)
|
private var isSystemInDarkMode = MutableStateFlow(false)
|
||||||
|
|
||||||
private val dimBackgroundState = combine(
|
private val dimBackgroundState = combine(
|
||||||
dataStore.data.map { it.appearance.dimWallpaper },
|
uiSettings.dimWallpaper,
|
||||||
dataStore.data.map { it.appearance.theme },
|
uiSettings.colorScheme,
|
||||||
isSystemInDarkMode
|
isSystemInDarkMode
|
||||||
) { dim, theme, systemDarkMode ->
|
) { dim, theme, systemDarkMode ->
|
||||||
dim && (theme == Settings.AppearanceSettings.Theme.Dark || theme == Settings.AppearanceSettings.Theme.System && systemDarkMode)
|
dim && (theme == ColorScheme.Dark || theme == ColorScheme.System && systemDarkMode)
|
||||||
}
|
}
|
||||||
val dimBackground = dimBackgroundState.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
val dimBackground = dimBackgroundState.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
val statusBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
val statusBarColor = uiSettings.statusBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val navBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
val navBarColor = uiSettings.navigationBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val chargingAnimation = dataStore.data.map { it.animations.charging }
|
val chargingAnimation = uiSettings.chargingAnimation
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
val hideNavBar = uiSettings.hideNavigationBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
val hideStatusBar = uiSettings.hideStatusBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setSystemInDarkMode(darkMode: Boolean) {
|
fun setSystemInDarkMode(darkMode: Boolean) {
|
||||||
isSystemInDarkMode.value = darkMode
|
isSystemInDarkMode.value = darkMode
|
||||||
}
|
}
|
||||||
|
|
||||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
val baseLayout = uiSettings.baseLayout
|
||||||
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
val bottomSearchBar = uiSettings.bottomSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
val reverseSearchResults = uiSettings.reverseSearchResults
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
val fixedSearchBar = uiSettings.fixedSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
|
val fixedRotation = uiSettings.orientation
|
||||||
|
.map { it != ScreenOrientation.Auto }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
val isSearchOpen = mutableStateOf(false)
|
val isSearchOpen = mutableStateOf(false)
|
||||||
@ -81,8 +86,7 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val searchBarFocused = mutableStateOf(false)
|
val searchBarFocused = mutableStateOf(false)
|
||||||
|
|
||||||
|
val autoFocusSearch = uiSettings.openKeyboardOnSearch
|
||||||
val autoFocusSearch = dataStore.data.map { it.searchBar.autoFocus }
|
|
||||||
|
|
||||||
fun setSearchbarFocus(focused: Boolean) {
|
fun setSearchbarFocus(focused: Boolean) {
|
||||||
if (searchBarFocused.value != focused) searchBarFocused.value = focused
|
if (searchBarFocused.value != focused) searchBarFocused.value = focused
|
||||||
@ -120,45 +124,43 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
isWidgetEditMode.value = editMode
|
isWidgetEditMode.value = editMode
|
||||||
}
|
}
|
||||||
|
|
||||||
val wallpaperBlur = dataStore.data.map { it.appearance.blurWallpaper }
|
val wallpaperBlur = uiSettings.blurWallpaper
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||||
val wallpaperBlurRadius = dataStore.data.map { it.appearance.blurWallpaperRadius }
|
val wallpaperBlurRadius = uiSettings.wallpaperBlurRadius
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
||||||
|
|
||||||
|
|
||||||
val fillClockHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
val fillClockHeight = uiSettings.clockFillScreen
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
val searchBarColor = uiSettings.searchBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarColors.Auto)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SearchBarColors.Auto)
|
||||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
val searchBarStyle = uiSettings.searchBarStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SearchBarStyle.Transparent)
|
||||||
|
|
||||||
val gestureState: StateFlow<GestureState> = dataStore
|
val gestureState: StateFlow<GestureState> = gestureSettings
|
||||||
.data.map { it.gestures }
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.combine(baseLayout) { settings, layout ->
|
.combine(baseLayout) { settings, layout ->
|
||||||
val swipeLeftAction =
|
val swipeLeftAction =
|
||||||
settings?.swipeLeft?.takeIf { layout != Layout.Pager } ?: GestureAction.None
|
settings.swipeLeft.takeIf { layout != BaseLayout.Pager } ?: GestureAction.NoAction
|
||||||
val swipeRightAction = settings?.swipeRight?.takeIf { layout != Layout.PagerReversed }
|
val swipeRightAction = settings.swipeRight.takeIf { layout != BaseLayout.PagerReversed }
|
||||||
?: GestureAction.None
|
?: GestureAction.NoAction
|
||||||
val swipeDownAction =
|
val swipeDownAction =
|
||||||
settings?.swipeDown?.takeIf { layout != Layout.PullDown } ?: GestureAction.None
|
settings.swipeDown.takeIf { layout != BaseLayout.PullDown } ?: GestureAction.NoAction
|
||||||
val longPressAction = settings?.longPress ?: GestureAction.None
|
val longPressAction = settings.longPress
|
||||||
val doubleTapAction = settings?.doubleTap ?: GestureAction.None
|
val doubleTapAction = settings.doubleTap
|
||||||
val homeButtonAction = settings?.homeButton ?: GestureAction.None
|
val homeButtonAction = settings.homeButton
|
||||||
|
|
||||||
val swipeLeftAppKey =
|
val swipeLeftAppKey =
|
||||||
if (swipeLeftAction == GestureAction.LaunchApp) settings.swipeLeftApp else null
|
if (swipeLeftAction is GestureAction.Launch) swipeLeftAction.key else null
|
||||||
val swipeRightAppKey =
|
val swipeRightAppKey =
|
||||||
if (swipeRightAction == GestureAction.LaunchApp) settings.swipeRightApp else null
|
if (swipeRightAction is GestureAction.Launch) swipeRightAction.key else null
|
||||||
val swipeDownAppKey =
|
val swipeDownAppKey =
|
||||||
if (swipeDownAction == GestureAction.LaunchApp) settings.swipeDownApp else null
|
if (swipeDownAction is GestureAction.Launch) swipeDownAction.key else null
|
||||||
val longPressAppKey =
|
val longPressAppKey =
|
||||||
if (longPressAction == GestureAction.LaunchApp) settings.longPressApp else null
|
if (longPressAction is GestureAction.Launch) longPressAction.key else null
|
||||||
val doubleTapAppKey =
|
val doubleTapAppKey =
|
||||||
if (doubleTapAction == GestureAction.LaunchApp) settings.doubleTapApp else null
|
if (doubleTapAction is GestureAction.Launch) doubleTapAction.key else null
|
||||||
val homeButtonAppKey =
|
val homeButtonAppKey =
|
||||||
if (homeButtonAction == GestureAction.LaunchApp) settings.homeButtonApp else null
|
if (homeButtonAction is GestureAction.Launch) homeButtonAction.key else null
|
||||||
val apps = listOfNotNull(
|
val apps = listOfNotNull(
|
||||||
swipeLeftAppKey,
|
swipeLeftAppKey,
|
||||||
swipeRightAppKey,
|
swipeRightAppKey,
|
||||||
@ -189,17 +191,17 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
val action = when (gesture) {
|
val action = when (gesture) {
|
||||||
Gesture.DoubleTap -> gestureState.value.doubleTapAction
|
Gesture.DoubleTap -> gestureState.value.doubleTapAction
|
||||||
Gesture.LongPress -> gestureState.value.longPressAction
|
Gesture.LongPress -> gestureState.value.longPressAction
|
||||||
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != Layout.PullDown }
|
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != BaseLayout.PullDown }
|
||||||
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != Layout.Pager }
|
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != BaseLayout.Pager }
|
||||||
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != Layout.PagerReversed }
|
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != BaseLayout.PagerReversed }
|
||||||
Gesture.HomeButton -> gestureState.value.homeButtonAction
|
Gesture.HomeButton -> gestureState.value.homeButtonAction
|
||||||
}
|
}
|
||||||
val requiresAccessibilityService =
|
val requiresAccessibilityService =
|
||||||
action == GestureAction.OpenRecents
|
action is GestureAction.Recents
|
||||||
|| action == GestureAction.OpenPowerDialog
|
|| action is GestureAction.PowerMenu
|
||||||
|| action == GestureAction.OpenQuickSettings
|
|| action is GestureAction.QuickSettings
|
||||||
|| action == GestureAction.OpenNotificationDrawer
|
|| action is GestureAction.Notifications
|
||||||
|| action == GestureAction.LockScreen
|
|| action is GestureAction.ScreenLock
|
||||||
|
|
||||||
if (action != null && requiresAccessibilityService && !permissionsManager.checkPermissionOnce(
|
if (action != null && requiresAccessibilityService && !permissionsManager.checkPermissionOnce(
|
||||||
PermissionGroup.Accessibility
|
PermissionGroup.Accessibility
|
||||||
@ -211,37 +213,37 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
|
|
||||||
return when (action) {
|
return when (action) {
|
||||||
GestureAction.OpenSearch -> {
|
is GestureAction.Search -> {
|
||||||
openSearch()
|
openSearch()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenNotificationDrawer -> {
|
is GestureAction.Notifications -> {
|
||||||
globalActionsService.openNotificationDrawer()
|
globalActionsService.openNotificationDrawer()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenQuickSettings -> {
|
is GestureAction.QuickSettings -> {
|
||||||
globalActionsService.openQuickSettings()
|
globalActionsService.openQuickSettings()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.LockScreen -> {
|
is GestureAction.ScreenLock -> {
|
||||||
globalActionsService.lockScreen()
|
globalActionsService.lockScreen()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenPowerDialog -> {
|
is GestureAction.PowerMenu -> {
|
||||||
globalActionsService.openPowerDialog()
|
globalActionsService.openPowerDialog()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenRecents -> {
|
is GestureAction.Recents -> {
|
||||||
globalActionsService.openRecents()
|
globalActionsService.openRecents()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.LaunchApp -> {
|
is GestureAction.Launch -> {
|
||||||
val view = (context as Activity).window.decorView
|
val view = (context as Activity).window.decorView
|
||||||
val options = ActivityOptionsCompat.makeScaleUpAnimation(
|
val options = ActivityOptionsCompat.makeScaleUpAnimation(
|
||||||
view,
|
view,
|
||||||
@ -271,12 +273,12 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class GestureState(
|
data class GestureState(
|
||||||
val swipeLeftAction: GestureAction = GestureAction.None,
|
val swipeLeftAction: GestureAction = GestureAction.NoAction,
|
||||||
val swipeRightAction: GestureAction = GestureAction.None,
|
val swipeRightAction: GestureAction = GestureAction.NoAction,
|
||||||
val swipeDownAction: GestureAction = GestureAction.None,
|
val swipeDownAction: GestureAction = GestureAction.NoAction,
|
||||||
val longPressAction: GestureAction = GestureAction.None,
|
val longPressAction: GestureAction = GestureAction.NoAction,
|
||||||
val doubleTapAction: GestureAction = GestureAction.None,
|
val doubleTapAction: GestureAction = GestureAction.NoAction,
|
||||||
val homeButtonAction: GestureAction = GestureAction.None,
|
val homeButtonAction: GestureAction = GestureAction.NoAction,
|
||||||
val swipeLeftApp: SavableSearchable? = null,
|
val swipeLeftApp: SavableSearchable? = null,
|
||||||
val swipeRightApp: SavableSearchable? = null,
|
val swipeRightApp: SavableSearchable? = null,
|
||||||
val swipeDownApp: SavableSearchable? = null,
|
val swipeDownApp: SavableSearchable? = null,
|
||||||
|
|||||||
@ -86,7 +86,7 @@ import androidx.compose.ui.unit.Velocity
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
|
|||||||
@ -68,7 +68,7 @@ import androidx.compose.ui.unit.Velocity
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
@ -605,7 +605,7 @@ fun PullDownScaffold(
|
|||||||
showHiddenItemsButton = isSearchOpen,
|
showHiddenItemsButton = isSearchOpen,
|
||||||
value = { value },
|
value = { value },
|
||||||
onValueChange = { searchVM.search(it) },
|
onValueChange = { searchVM.search(it) },
|
||||||
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == Settings.SearchBarSettings.SearchBarColors.Auto || searchBarColor == Settings.SearchBarSettings.SearchBarColors.Dark,
|
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == SearchBarColors.Auto || searchBarColor == SearchBarColors.Dark,
|
||||||
style = searchBarStyle,
|
style = searchBarStyle,
|
||||||
reverse = bottomSearchBar,
|
reverse = bottomSearchBar,
|
||||||
onKeyboardActionGo = if (launchOnEnter) {
|
onKeyboardActionGo = if (launchOnEnter) {
|
||||||
|
|||||||
@ -34,8 +34,8 @@ import androidx.core.view.WindowInsetsControllerCompat
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.flowWithLifecycle
|
import androidx.lifecycle.flowWithLifecycle
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings.SystemBarColors
|
import de.mm20.launcher2.preferences.SystemBarColors
|
||||||
import de.mm20.launcher2.ui.assistant.AssistantScaffold
|
import de.mm20.launcher2.ui.assistant.AssistantScaffold
|
||||||
import de.mm20.launcher2.ui.base.BaseActivity
|
import de.mm20.launcher2.ui.base.BaseActivity
|
||||||
import de.mm20.launcher2.ui.base.ProvideCurrentTime
|
import de.mm20.launcher2.ui.base.ProvideCurrentTime
|
||||||
@ -184,7 +184,7 @@ abstract class SharedLauncherActivity(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
when (layout) {
|
when (layout) {
|
||||||
Settings.LayoutSettings.Layout.PullDown -> {
|
BaseLayout.PullDown -> {
|
||||||
key(bottomSearchBar, reverseSearchResults) {
|
key(bottomSearchBar, reverseSearchResults) {
|
||||||
PullDownScaffold(
|
PullDownScaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -205,8 +205,8 @@ abstract class SharedLauncherActivity(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings.LayoutSettings.Layout.Pager,
|
BaseLayout.Pager,
|
||||||
Settings.LayoutSettings.Layout.PagerReversed -> {
|
BaseLayout.PagerReversed -> {
|
||||||
key(bottomSearchBar, reverseSearchResults) {
|
key(bottomSearchBar, reverseSearchResults) {
|
||||||
PagerScaffold(
|
PagerScaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -220,7 +220,7 @@ abstract class SharedLauncherActivity(
|
|||||||
},
|
},
|
||||||
darkStatusBarIcons = lightStatus,
|
darkStatusBarIcons = lightStatus,
|
||||||
darkNavBarIcons = lightNav,
|
darkNavBarIcons = lightNav,
|
||||||
reverse = layout == Settings.LayoutSettings.Layout.PagerReversed,
|
reverse = layout == BaseLayout.PagerReversed,
|
||||||
bottomSearchBar = bottomSearchBar,
|
bottomSearchBar = bottomSearchBar,
|
||||||
reverseSearchResults = reverseSearchResults,
|
reverseSearchResults = reverseSearchResults,
|
||||||
fixedSearchBar = fixedSearchBar,
|
fixedSearchBar = fixedSearchBar,
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import androidx.compose.ui.platform.LocalView
|
|||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.ui.component.FakeSplashScreen
|
import de.mm20.launcher2.ui.component.FakeSplashScreen
|
||||||
import de.mm20.launcher2.ui.gestures.Gesture
|
import de.mm20.launcher2.ui.gestures.Gesture
|
||||||
@ -52,7 +52,7 @@ fun LauncherGestureHandler(
|
|||||||
|
|
||||||
val gestureState by viewModel.gestureState.collectAsState(GestureState())
|
val gestureState by viewModel.gestureState.collectAsState(GestureState())
|
||||||
|
|
||||||
val shouldDetectDoubleTapGesture = gestureState.doubleTapAction != GestureAction.None
|
val shouldDetectDoubleTapGesture = gestureState.doubleTapAction !is GestureAction.NoAction
|
||||||
|
|
||||||
LaunchedEffect(shouldDetectDoubleTapGesture) {
|
LaunchedEffect(shouldDetectDoubleTapGesture) {
|
||||||
gestureDetector.shouldDetectDoubleTaps = shouldDetectDoubleTapGesture
|
gestureDetector.shouldDetectDoubleTaps = shouldDetectDoubleTapGesture
|
||||||
|
|||||||
@ -5,25 +5,30 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
|
||||||
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LegacySettings.SearchResultOrderingSettings.Ordering
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.Ordering
|
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||||
|
import de.mm20.launcher2.preferences.search.CalendarSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
import de.mm20.launcher2.search.AppProfile
|
import de.mm20.launcher2.search.AppProfile
|
||||||
|
import de.mm20.launcher2.search.AppShortcut
|
||||||
|
import de.mm20.launcher2.search.Application
|
||||||
|
import de.mm20.launcher2.search.Article
|
||||||
|
import de.mm20.launcher2.search.CalendarEvent
|
||||||
import de.mm20.launcher2.search.Contact
|
import de.mm20.launcher2.search.Contact
|
||||||
import de.mm20.launcher2.search.File
|
import de.mm20.launcher2.search.File
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.SearchService
|
import de.mm20.launcher2.search.SearchService
|
||||||
import de.mm20.launcher2.search.Searchable
|
import de.mm20.launcher2.search.Searchable
|
||||||
import de.mm20.launcher2.search.AppShortcut
|
|
||||||
import de.mm20.launcher2.search.Application
|
|
||||||
import de.mm20.launcher2.search.Article
|
|
||||||
import de.mm20.launcher2.search.CalendarEvent
|
|
||||||
import de.mm20.launcher2.search.Website
|
import de.mm20.launcher2.search.Website
|
||||||
import de.mm20.launcher2.search.data.Calculator
|
import de.mm20.launcher2.search.data.Calculator
|
||||||
import de.mm20.launcher2.search.data.UnitConverter
|
import de.mm20.launcher2.search.data.UnitConverter
|
||||||
|
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
@ -32,7 +37,6 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
@ -47,10 +51,14 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
private val favoritesService: FavoritesService by inject()
|
private val favoritesService: FavoritesService by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
private val fileSearchSettings: FileSearchSettings by inject()
|
|
||||||
|
|
||||||
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
|
private val fileSearchSettings: FileSearchSettings by inject()
|
||||||
|
private val contactSearchSettings: ContactSearchSettings by inject()
|
||||||
|
private val calendarSearchSettings: CalendarSearchSettings by inject()
|
||||||
|
private val shortcutSearchSettings: ShortcutSearchSettings by inject()
|
||||||
|
private val searchUiSettings: SearchUiSettings by inject()
|
||||||
|
|
||||||
|
val launchOnEnter = searchUiSettings.launchOnEnter
|
||||||
.stateIn(viewModelScope, SharingStarted.Eagerly, false)
|
.stateIn(viewModelScope, SharingStarted.Eagerly, false)
|
||||||
|
|
||||||
private val searchService: SearchService by inject()
|
private val searchService: SearchService by inject()
|
||||||
@ -70,10 +78,10 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
val unitConverterResults = mutableStateOf<List<UnitConverter>>(emptyList())
|
val unitConverterResults = mutableStateOf<List<UnitConverter>>(emptyList())
|
||||||
val searchActionResults = mutableStateOf<List<SearchAction>>(emptyList())
|
val searchActionResults = mutableStateOf<List<SearchAction>>(emptyList())
|
||||||
|
|
||||||
val hiddenResultsButton = dataStore.data.map { it.searchBar.hiddenItemsButton }
|
val hiddenResultsButton = searchUiSettings.hiddenItemsButton
|
||||||
val hiddenResults = mutableStateOf<List<SavableSearchable>>(emptyList())
|
val hiddenResults = mutableStateOf<List<SavableSearchable>>(emptyList())
|
||||||
|
|
||||||
val favoritesEnabled = dataStore.data.map { it.favorites.enabled }
|
val favoritesEnabled = searchUiSettings.favorites
|
||||||
val hideFavorites = mutableStateOf(false)
|
val hideFavorites = mutableStateOf(false)
|
||||||
|
|
||||||
private val hiddenItemKeys = searchableRepository
|
private val hiddenItemKeys = searchableRepository
|
||||||
@ -117,16 +125,9 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
hideFavorites.value = query.isNotEmpty()
|
hideFavorites.value = query.isNotEmpty()
|
||||||
searchJob = viewModelScope.launch {
|
searchJob = viewModelScope.launch {
|
||||||
dataStore.data.collectLatest { settings ->
|
searchUiSettings.resultOrder.collectLatest { resultOrder ->
|
||||||
searchService.search(
|
searchService.search(
|
||||||
query,
|
query
|
||||||
calculator = settings.calculatorSearch,
|
|
||||||
unitConverter = settings.unitConverterSearch,
|
|
||||||
calendars = settings.calendarSearch,
|
|
||||||
contacts = settings.contactsSearch,
|
|
||||||
shortcuts = settings.appShortcutSearch,
|
|
||||||
websites = settings.websiteSearch,
|
|
||||||
wikipedia = settings.wikipediaSearch,
|
|
||||||
).collectLatest { results ->
|
).collectLatest { results ->
|
||||||
var resultsList = withContext(Dispatchers.Default) {
|
var resultsList = withContext(Dispatchers.Default) {
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
@ -151,13 +152,13 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
emptyList()
|
emptyList()
|
||||||
} else {
|
} else {
|
||||||
val keys = resultsList.mapNotNull { (it as? SavableSearchable)?.key }
|
val keys = resultsList.mapNotNull { (it as? SavableSearchable)?.key }
|
||||||
when (settings.resultOrdering.ordering) {
|
when (resultOrder) {
|
||||||
|
|
||||||
Ordering.LaunchCount -> searchableRepository.sortByRelevance(
|
SearchResultOrder.LaunchCount -> searchableRepository.sortByRelevance(
|
||||||
keys
|
keys
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
Ordering.Weighted -> searchableRepository.sortByWeight(
|
SearchResultOrder.Weighted -> searchableRepository.sortByWeight(
|
||||||
keys
|
keys
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
@ -256,7 +257,7 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val missingCalendarPermission = combine(
|
val missingCalendarPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.Calendar),
|
permissionsManager.hasPermission(PermissionGroup.Calendar),
|
||||||
dataStore.data.map { it.calendarSearch.enabled }.distinctUntilChanged()
|
calendarSearchSettings.enabled,
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestCalendarPermission(context: AppCompatActivity) {
|
fun requestCalendarPermission(context: AppCompatActivity) {
|
||||||
@ -264,18 +265,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableCalendarSearch() {
|
fun disableCalendarSearch() {
|
||||||
viewModelScope.launch {
|
calendarSearchSettings.setEnabled(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCalendarSearch(it.calendarSearch.toBuilder().setEnabled(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val missingContactsPermission = combine(
|
val missingContactsPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.Contacts),
|
permissionsManager.hasPermission(PermissionGroup.Contacts),
|
||||||
dataStore.data.map { it.contactsSearch.enabled }.distinctUntilChanged()
|
contactSearchSettings.enabled
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestContactsPermission(context: AppCompatActivity) {
|
fun requestContactsPermission(context: AppCompatActivity) {
|
||||||
@ -283,18 +278,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableContactsSearch() {
|
fun disableContactsSearch() {
|
||||||
viewModelScope.launch {
|
contactSearchSettings.setEnabled(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setContactsSearch(it.contactsSearch.toBuilder().setEnabled(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val missingFilesPermission = combine(
|
val missingFilesPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.ExternalStorage),
|
permissionsManager.hasPermission(PermissionGroup.ExternalStorage),
|
||||||
fileSearchSettings.localFiles.distinctUntilChanged()
|
fileSearchSettings.localFiles
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestFilesPermission(context: AppCompatActivity) {
|
fun requestFilesPermission(context: AppCompatActivity) {
|
||||||
@ -302,18 +291,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableFilesSearch() {
|
fun disableFilesSearch() {
|
||||||
viewModelScope.launch {
|
fileSearchSettings.setLocalFiles(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFileSearch(it.fileSearch.toBuilder().setLocalFiles(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val missingAppShortcutPermission = combine(
|
val missingAppShortcutPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.AppShortcuts),
|
permissionsManager.hasPermission(PermissionGroup.AppShortcuts),
|
||||||
dataStore.data.map { it.appShortcutSearch.enabled }.distinctUntilChanged()
|
shortcutSearchSettings.enabled,
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestAppShortcutPermission(context: AppCompatActivity) {
|
fun requestAppShortcutPermission(context: AppCompatActivity) {
|
||||||
@ -321,12 +304,6 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableAppShortcutSearch() {
|
fun disableAppShortcutSearch() {
|
||||||
viewModelScope.launch {
|
shortcutSearchSettings.setEnabled(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppShortcutSearch(it.appShortcutSearch.toBuilder().setEnabled(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,29 +1,23 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.search.favorites
|
package de.mm20.launcher2.ui.launcher.search.favorites
|
||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiState
|
||||||
import de.mm20.launcher2.ui.common.FavoritesVM
|
import de.mm20.launcher2.ui.common.FavoritesVM
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class SearchFavoritesVM : FavoritesVM() {
|
class SearchFavoritesVM : FavoritesVM() {
|
||||||
override val tagsExpanded: Flow<Boolean> = dataStore.data.map { it.ui.searchTagsMultiline }
|
private val uiState: UiState by inject()
|
||||||
|
|
||||||
|
override val tagsExpanded: Flow<Boolean> = uiState.favoritesTagsExpanded
|
||||||
.shareIn(viewModelScope, SharingStarted.Lazily)
|
.shareIn(viewModelScope, SharingStarted.Lazily)
|
||||||
|
|
||||||
override fun setTagsExpanded(expanded: Boolean) {
|
override fun setTagsExpanded(expanded: Boolean) {
|
||||||
viewModelScope.launch {
|
uiState.setFavoritesTagsExpanded(expanded)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setUi(
|
|
||||||
it.ui.toBuilder()
|
|
||||||
.setSearchTagsMultiline(expanded)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.component.SearchBar
|
import de.mm20.launcher2.ui.component.SearchBar
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
@ -29,7 +29,7 @@ import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
|
|||||||
@Composable
|
@Composable
|
||||||
fun LauncherSearchBar(
|
fun LauncherSearchBar(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
style: Settings.SearchBarSettings.SearchBarStyle,
|
style: SearchBarStyle,
|
||||||
level: () -> SearchBarLevel,
|
level: () -> SearchBarLevel,
|
||||||
value: () -> String,
|
value: () -> String,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
|
|||||||
@ -17,9 +17,9 @@ import de.mm20.launcher2.icons.LauncherIcon
|
|||||||
import de.mm20.launcher2.ktx.normalize
|
import de.mm20.launcher2.ktx.normalize
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.appshortcuts.AppShortcut
|
import de.mm20.launcher2.appshortcuts.AppShortcut
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
import de.mm20.launcher2.search.Searchable
|
import de.mm20.launcher2.search.Searchable
|
||||||
import de.mm20.launcher2.search.data.Tag
|
import de.mm20.launcher2.search.data.Tag
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
@ -41,7 +41,7 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
|||||||
private val badgeService: BadgeService by inject()
|
private val badgeService: BadgeService by inject()
|
||||||
private val customAttributesRepository: CustomAttributesRepository by inject()
|
private val customAttributesRepository: CustomAttributesRepository by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val favoritesSettings: FavoritesSettings by inject()
|
||||||
|
|
||||||
val gridItems = mutableStateOf<List<FavoritesSheetGridItem>>(emptyList())
|
val gridItems = mutableStateOf<List<FavoritesSheetGridItem>>(emptyList())
|
||||||
|
|
||||||
@ -245,36 +245,16 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val enableFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
val enableFrequentlyUsed = favoritesSettings.frequentlyUsed
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsed(frequentlyUsed)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites
|
|
||||||
.toBuilder()
|
|
||||||
.setFrequentlyUsed(frequentlyUsed)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
val frequentlyUsedRows = favoritesSettings.frequentlyUsedRows
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites
|
|
||||||
.toBuilder()
|
|
||||||
.setFrequentlyUsedRows(frequentlyUsedRows)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pinTag(tag: Tag) {
|
fun pinTag(tag: Tag) {
|
||||||
|
|||||||
@ -14,7 +14,8 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
@ -29,12 +30,12 @@ fun FailedGestureSheet(
|
|||||||
val viewModel: FailedGestureSheetVM = viewModel()
|
val viewModel: FailedGestureSheetVM = viewModel()
|
||||||
|
|
||||||
val actionName = stringResource(when(failedGesture.action) {
|
val actionName = stringResource(when(failedGesture.action) {
|
||||||
Settings.GestureSettings.GestureAction.OpenSearch -> R.string.gesture_action_open_search
|
is GestureAction.Search -> R.string.gesture_action_open_search
|
||||||
Settings.GestureSettings.GestureAction.OpenNotificationDrawer -> R.string.gesture_action_notifications
|
is GestureAction.Notifications -> R.string.gesture_action_notifications
|
||||||
Settings.GestureSettings.GestureAction.LockScreen -> R.string.gesture_action_lock_screen
|
is GestureAction.ScreenLock -> R.string.gesture_action_lock_screen
|
||||||
Settings.GestureSettings.GestureAction.OpenQuickSettings -> R.string.gesture_action_quick_settings
|
is GestureAction.QuickSettings -> R.string.gesture_action_quick_settings
|
||||||
Settings.GestureSettings.GestureAction.OpenRecents -> R.string.gesture_action_recents
|
is GestureAction.Recents -> R.string.gesture_action_recents
|
||||||
Settings.GestureSettings.GestureAction.OpenPowerDialog -> R.string.gesture_action_power_menu
|
is GestureAction.PowerMenu -> R.string.gesture_action_power_menu
|
||||||
else -> R.string.gesture_action_none
|
else -> R.string.gesture_action_none
|
||||||
})
|
})
|
||||||
val gestureName = stringResource(when(failedGesture.gesture) {
|
val gestureName = stringResource(when(failedGesture.gesture) {
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
import de.mm20.launcher2.ui.gestures.Gesture
|
import de.mm20.launcher2.ui.gestures.Gesture
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@ -14,28 +14,20 @@ import org.koin.core.component.inject
|
|||||||
|
|
||||||
class FailedGestureSheetVM : ViewModel(), KoinComponent {
|
class FailedGestureSheetVM : ViewModel(), KoinComponent {
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val gestureSettings: GestureSettings by inject()
|
||||||
|
|
||||||
fun requestPermission(context: AppCompatActivity) {
|
fun requestPermission(context: AppCompatActivity) {
|
||||||
permissionsManager.requestPermission(context, PermissionGroup.Accessibility)
|
permissionsManager.requestPermission(context, PermissionGroup.Accessibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableGesture(gesture: Gesture) {
|
fun disableGesture(gesture: Gesture) {
|
||||||
viewModelScope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(
|
|
||||||
it.gestures.toBuilder().apply {
|
|
||||||
when(gesture) {
|
when(gesture) {
|
||||||
Gesture.SwipeDown -> swipeDown = GestureAction.None
|
Gesture.DoubleTap -> gestureSettings.setDoubleTap(GestureAction.NoAction)
|
||||||
Gesture.SwipeLeft -> swipeLeft = GestureAction.None
|
Gesture.LongPress -> gestureSettings.setLongPress(GestureAction.NoAction)
|
||||||
Gesture.SwipeRight -> swipeRight = GestureAction.None
|
Gesture.SwipeDown -> gestureSettings.setSwipeDown(GestureAction.NoAction)
|
||||||
Gesture.DoubleTap -> doubleTap = GestureAction.None
|
Gesture.SwipeLeft -> gestureSettings.setSwipeLeft(GestureAction.NoAction)
|
||||||
Gesture.LongPress -> longPress = GestureAction.None
|
Gesture.SwipeRight -> gestureSettings.setSwipeRight(GestureAction.NoAction)
|
||||||
Gesture.HomeButton -> homeButton = GestureAction.None
|
Gesture.HomeButton -> gestureSettings.setHomeButton(GestureAction.NoAction)
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,9 +1,8 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets
|
package de.mm20.launcher2.ui.launcher.widgets
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.widgets.Widget
|
import de.mm20.launcher2.widgets.Widget
|
||||||
import de.mm20.launcher2.widgets.WidgetRepository
|
import de.mm20.launcher2.widgets.WidgetRepository
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
@ -15,9 +14,9 @@ import org.koin.core.component.inject
|
|||||||
class WidgetsVM : ViewModel(), KoinComponent {
|
class WidgetsVM : ViewModel(), KoinComponent {
|
||||||
private val widgetRepository: WidgetRepository by inject()
|
private val widgetRepository: WidgetRepository by inject()
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
val editButton = dataStore.data.map { it.widgets.editButton }
|
val editButton = uiSettings.widgetEditButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val widgets = widgetRepository.get()
|
val widgets = widgetRepository.get()
|
||||||
|
|||||||
@ -14,8 +14,6 @@ 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.size
|
||||||
import androidx.compose.foundation.layout.width
|
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.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@ -64,10 +62,9 @@ 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.ClockWidgetAlignment
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetAlignment
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.R
|
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.BottomSheetDialog
|
||||||
@ -89,7 +86,7 @@ fun ClockWidget(
|
|||||||
) {
|
) {
|
||||||
val viewModel: ClockWidgetVM = viewModel()
|
val viewModel: ClockWidgetVM = viewModel()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val layout by viewModel.layout.collectAsState()
|
val compact by viewModel.compactLayout.collectAsState()
|
||||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
val clockStyle by viewModel.clockStyle.collectAsState()
|
||||||
val color by viewModel.color.collectAsState()
|
val color by viewModel.color.collectAsState()
|
||||||
val alignment by viewModel.alignment.collectAsState()
|
val alignment by viewModel.alignment.collectAsState()
|
||||||
@ -106,7 +103,9 @@ fun ClockWidget(
|
|||||||
viewModel.updateTime(time)
|
viewModel.updateTime(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
val partProvider by remember { viewModel.getActivePart(context) }.collectAsStateWithLifecycle(null)
|
val partProvider by remember { viewModel.getActivePart(context) }.collectAsStateWithLifecycle(
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
AnimatedContent(editMode, label = "ClockWidget") {
|
AnimatedContent(editMode, label = "ClockWidget") {
|
||||||
if (it) {
|
if (it) {
|
||||||
@ -165,32 +164,32 @@ fun ClockWidget(
|
|||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalContentColor provides contentColor
|
LocalContentColor provides contentColor
|
||||||
) {
|
) {
|
||||||
if (layout == ClockWidgetLayout.Vertical) {
|
if (compact == false) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
enabled = clockStyle != ClockStyle.EmptyClock,
|
enabled = clockStyle !is ClockWidgetStyle.Empty,
|
||||||
indication = null,
|
indication = null,
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() }
|
||||||
) {
|
) {
|
||||||
viewModel.launchClockApp(context)
|
viewModel.launchClockApp(context)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Clock(clockStyle, ClockWidgetLayout.Vertical)
|
Clock(clockStyle, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partProvider != null) {
|
if (partProvider != null) {
|
||||||
DynamicZone(
|
DynamicZone(
|
||||||
modifier = Modifier.padding(bottom = 8.dp),
|
modifier = Modifier.padding(bottom = 8.dp),
|
||||||
layout = ClockWidgetLayout.Vertical,
|
compact = false,
|
||||||
provider = partProvider,
|
provider = partProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layout == ClockWidgetLayout.Horizontal) {
|
if (compact == true) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@ -201,7 +200,7 @@ fun ClockWidget(
|
|||||||
if (partProvider != null) {
|
if (partProvider != null) {
|
||||||
DynamicZone(
|
DynamicZone(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
layout = ClockWidgetLayout.Horizontal,
|
compact = true,
|
||||||
provider = partProvider,
|
provider = partProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -216,14 +215,14 @@ fun ClockWidget(
|
|||||||
)
|
)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
enabled = clockStyle != ClockStyle.EmptyClock,
|
enabled = clockStyle !is ClockWidgetStyle.Empty,
|
||||||
indication = null,
|
indication = null,
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() }
|
||||||
) {
|
) {
|
||||||
viewModel.launchClockApp(context)
|
viewModel.launchClockApp(context)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Clock(clockStyle, ClockWidgetLayout.Horizontal)
|
Clock(clockStyle, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +235,7 @@ fun ClockWidget(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(bottom = 16.dp)
|
.padding(bottom = 16.dp)
|
||||||
) {
|
) {
|
||||||
dockProvider?.Component(ClockWidgetLayout.Vertical)
|
dockProvider?.Component(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,21 +245,18 @@ fun ClockWidget(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Clock(
|
fun Clock(
|
||||||
style: ClockStyle?,
|
style: ClockWidgetStyle?,
|
||||||
layout: ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val time = LocalTime.current
|
val time = LocalTime.current
|
||||||
when (style) {
|
when (style) {
|
||||||
ClockStyle.DigitalClock1,
|
is ClockWidgetStyle.Digital1 -> DigitalClock1(time, compact, style)
|
||||||
ClockStyle.DigitalClock1_Outlined,
|
|
||||||
ClockStyle.DigitalClock1_MDY,
|
|
||||||
ClockStyle.DigitalClock1_OnePlus -> DigitalClock1(time, layout, style)
|
|
||||||
|
|
||||||
ClockStyle.DigitalClock2 -> DigitalClock2(time, layout)
|
is ClockWidgetStyle.Digital2 -> DigitalClock2(time, compact)
|
||||||
ClockStyle.BinaryClock -> BinaryClock(time, layout)
|
is ClockWidgetStyle.Binary -> BinaryClock(time, compact)
|
||||||
ClockStyle.AnalogClock -> AnalogClock(time, layout)
|
is ClockWidgetStyle.Analog -> AnalogClock(time, compact)
|
||||||
ClockStyle.OrbitClock -> OrbitClock(time, layout)
|
is ClockWidgetStyle.Orbit -> OrbitClock(time, compact)
|
||||||
ClockStyle.EmptyClock -> {}
|
is ClockWidgetStyle.Empty -> {}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,13 +264,13 @@ fun Clock(
|
|||||||
@Composable
|
@Composable
|
||||||
fun DynamicZone(
|
fun DynamicZone(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
layout: ClockWidgetLayout,
|
compact: Boolean,
|
||||||
provider: PartProvider?,
|
provider: PartProvider?,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
) {
|
) {
|
||||||
provider?.Component(layout)
|
provider?.Component(compact)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,18 +279,13 @@ fun ConfigureClockWidgetSheet(
|
|||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
|
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
|
||||||
val layout by viewModel.layout.collectAsState()
|
val compact by viewModel.compact.collectAsState()
|
||||||
val color by viewModel.color.collectAsState()
|
val color by viewModel.color.collectAsState()
|
||||||
val style by viewModel.clockStyle.collectAsState()
|
val style by viewModel.clockStyle.collectAsState()
|
||||||
val fillHeight by viewModel.fillHeight.collectAsState()
|
val fillHeight by viewModel.fillHeight.collectAsState()
|
||||||
val alignment by viewModel.alignment.collectAsState()
|
val alignment by viewModel.alignment.collectAsState()
|
||||||
|
val dock by viewModel.dock.collectAsState()
|
||||||
val date by viewModel.datePart.collectAsState()
|
val parts by viewModel.parts.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) {
|
BottomSheetDialog(onDismissRequest = onDismiss) {
|
||||||
Column(
|
Column(
|
||||||
@ -307,14 +298,14 @@ fun ConfigureClockWidgetSheet(
|
|||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
SegmentedButton(
|
SegmentedButton(
|
||||||
selected = layout == ClockWidgetLayout.Vertical,
|
selected = compact == false,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setLayout(ClockWidgetLayout.Vertical)
|
viewModel.setCompact(false)
|
||||||
},
|
},
|
||||||
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
|
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
|
||||||
icon = {
|
icon = {
|
||||||
SegmentedButtonDefaults.Icon(
|
SegmentedButtonDefaults.Icon(
|
||||||
active = layout == ClockWidgetLayout.Vertical,
|
active = compact == false,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Rounded.HorizontalSplit,
|
imageVector = Icons.Rounded.HorizontalSplit,
|
||||||
@ -327,14 +318,14 @@ fun ConfigureClockWidgetSheet(
|
|||||||
Text(text = stringResource(R.string.preference_clockwidget_layout_vertical))
|
Text(text = stringResource(R.string.preference_clockwidget_layout_vertical))
|
||||||
}
|
}
|
||||||
SegmentedButton(
|
SegmentedButton(
|
||||||
selected = layout == ClockWidgetLayout.Horizontal,
|
selected = compact == true,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setLayout(ClockWidgetLayout.Horizontal)
|
viewModel.setCompact(true)
|
||||||
},
|
},
|
||||||
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
|
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
|
||||||
icon = {
|
icon = {
|
||||||
SegmentedButtonDefaults.Icon(
|
SegmentedButtonDefaults.Icon(
|
||||||
active = layout == ClockWidgetLayout.Horizontal,
|
active = compact == true,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Rounded.VerticalSplit,
|
imageVector = Icons.Rounded.VerticalSplit,
|
||||||
@ -348,9 +339,9 @@ fun ConfigureClockWidgetSheet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color != null && layout != null) {
|
if (color != null && compact != null) {
|
||||||
WatchFaceSelector(
|
WatchFaceSelector(
|
||||||
layout = layout!!,
|
compact = compact!!,
|
||||||
colors = color!!,
|
colors = color!!,
|
||||||
selected = style,
|
selected = style,
|
||||||
onSelect = {
|
onSelect = {
|
||||||
@ -487,7 +478,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
||||||
icon = Icons.Rounded.Star,
|
icon = Icons.Rounded.Star,
|
||||||
value = favorites == true,
|
value = dock == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setFavoritesPart(it)
|
viewModel.setFavoritesPart(it)
|
||||||
}
|
}
|
||||||
@ -510,7 +501,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_date_part),
|
title = stringResource(R.string.preference_clockwidget_date_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
||||||
icon = Icons.Rounded.Today,
|
icon = Icons.Rounded.Today,
|
||||||
value = date == true,
|
value = parts?.date == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setDatePart(it)
|
viewModel.setDatePart(it)
|
||||||
}
|
}
|
||||||
@ -519,7 +510,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_music_part),
|
title = stringResource(R.string.preference_clockwidget_music_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
||||||
icon = Icons.Rounded.MusicNote,
|
icon = Icons.Rounded.MusicNote,
|
||||||
value = media == true,
|
value = parts?.music == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setMusicPart(it)
|
viewModel.setMusicPart(it)
|
||||||
}
|
}
|
||||||
@ -528,7 +519,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
||||||
icon = Icons.Rounded.Alarm,
|
icon = Icons.Rounded.Alarm,
|
||||||
value = alarm == true,
|
value = parts?.alarm == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setAlarmPart(it)
|
viewModel.setAlarmPart(it)
|
||||||
}
|
}
|
||||||
@ -537,7 +528,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_battery_part),
|
title = stringResource(R.string.preference_clockwidget_battery_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
||||||
icon = Icons.Rounded.BatteryFull,
|
icon = Icons.Rounded.BatteryFull,
|
||||||
value = battery == true,
|
value = parts?.battery == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setBatteryPart(it)
|
viewModel.setBatteryPart(it)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import android.provider.AlarmClock
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
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.ui.ClockWidgetSettings
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.AlarmPartProvider
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.AlarmPartProvider
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.BatteryPartProvider
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.BatteryPartProvider
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.DatePartProvider
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.DatePartProvider
|
||||||
@ -18,21 +18,20 @@ import kotlinx.coroutines.flow.SharingStarted
|
|||||||
import kotlinx.coroutines.flow.channelFlow
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
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 settings: ClockWidgetSettings by inject()
|
||||||
|
|
||||||
private val partProviders = dataStore.data.map { it.clockWidget }.distinctUntilChanged().map {
|
private val partProviders = settings.parts.map {
|
||||||
val providers = mutableListOf<PartProvider>()
|
val providers = mutableListOf<PartProvider>()
|
||||||
if (it.datePart) providers += DatePartProvider()
|
if (it.date) providers += DatePartProvider()
|
||||||
if (it.musicPart) providers += MusicPartProvider()
|
if (it.music) providers += MusicPartProvider()
|
||||||
if (it.batteryPart) providers += BatteryPartProvider()
|
if (it.battery) providers += BatteryPartProvider()
|
||||||
if (it.alarmPart) providers += AlarmPartProvider()
|
if (it.alarm) providers += AlarmPartProvider()
|
||||||
providers
|
providers
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||||
|
|
||||||
@ -51,19 +50,19 @@ class ClockWidgetVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val layout = dataStore.data.map { it.clockWidget.layout }
|
val compactLayout = settings.compact
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
val clockStyle = settings.clockStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val color = dataStore.data.map { it.clockWidget.color }
|
val color = settings.color
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val alignment = dataStore.data.map { it.clockWidget.alignment }
|
val alignment = settings.alignment
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val dockProvider = dataStore.data
|
val dockProvider = settings.dock
|
||||||
.map { if (it.clockWidget.favoritesPart) FavoritesPartProvider() else null }
|
.map { if (it) FavoritesPartProvider() else null }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun updateTime(time: Long) {
|
fun updateTime(time: Long) {
|
||||||
|
|||||||
@ -43,19 +43,18 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WatchFaceSelector(
|
fun WatchFaceSelector(
|
||||||
layout: ClockWidgetLayout,
|
compact: Boolean,
|
||||||
colors: ClockWidgetColors,
|
colors: ClockWidgetColors,
|
||||||
selected: ClockStyle?,
|
selected: ClockWidgetStyle?,
|
||||||
onSelect: (ClockStyle) -> Unit,
|
onSelect: (ClockWidgetStyle) -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Surface(
|
Surface(
|
||||||
@ -73,7 +72,7 @@ fun WatchFaceSelector(
|
|||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val styles = remember {
|
val styles = remember {
|
||||||
sortedMapOf(
|
mapOf(
|
||||||
ClockStyle.DigitalClock1 to 0,
|
ClockStyle.DigitalClock1 to 0,
|
||||||
ClockStyle.DigitalClock1_Outlined to 0,
|
ClockStyle.DigitalClock1_Outlined to 0,
|
||||||
ClockStyle.DigitalClock1_MDY to 0,
|
ClockStyle.DigitalClock1_MDY to 0,
|
||||||
@ -159,9 +158,9 @@ fun WatchFaceSelector(
|
|||||||
styles.filter { it.value == pageIndex }
|
styles.filter { it.value == pageIndex }
|
||||||
}
|
}
|
||||||
if (currentPageStyles.containsKey(selected)) {
|
if (currentPageStyles.containsKey(selected)) {
|
||||||
Clock(selected, layout)
|
Clock(selected, compact)
|
||||||
} else {
|
} else {
|
||||||
Clock(currentPageStyles.keys.first(), layout)
|
Clock(currentPageStyles.keys.first(), compact)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,7 +252,7 @@ fun WatchFaceSelector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getClockstyleName(context: Context, style: ClockStyle): String {
|
fun getClockstyleName(context: Context, style: ClockWidgetStyle): String {
|
||||||
return when (style) {
|
return when (style) {
|
||||||
ClockStyle.DigitalClock1,
|
ClockStyle.DigitalClock1,
|
||||||
ClockStyle.DigitalClock1_Outlined,
|
ClockStyle.DigitalClock1_Outlined,
|
||||||
@ -264,11 +263,11 @@ fun getClockstyleName(context: Context, style: ClockStyle): String {
|
|||||||
ClockStyle.BinaryClock -> "Binary"
|
ClockStyle.BinaryClock -> "Binary"
|
||||||
ClockStyle.AnalogClock -> "Hands"
|
ClockStyle.AnalogClock -> "Hands"
|
||||||
ClockStyle.EmptyClock -> "Empty"
|
ClockStyle.EmptyClock -> "Empty"
|
||||||
ClockStyle.UNRECOGNIZED -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getVariantName(context: Context, style: ClockStyle): String {
|
fun getVariantName(context: Context, style: ClockWidgetStyle): String {
|
||||||
return when (style) {
|
return when (style) {
|
||||||
ClockStyle.DigitalClock1,
|
ClockStyle.DigitalClock1,
|
||||||
ClockStyle.DigitalClock2,
|
ClockStyle.DigitalClock2,
|
||||||
@ -279,7 +278,20 @@ fun getVariantName(context: Context, style: ClockStyle): String {
|
|||||||
ClockStyle.DigitalClock1_Outlined -> "Outlined"
|
ClockStyle.DigitalClock1_Outlined -> "Outlined"
|
||||||
ClockStyle.DigitalClock1_MDY -> "Material You"
|
ClockStyle.DigitalClock1_MDY -> "Material You"
|
||||||
ClockStyle.DigitalClock1_OnePlus -> "OnePlus"
|
ClockStyle.DigitalClock1_OnePlus -> "OnePlus"
|
||||||
|
else -> ""
|
||||||
|
|
||||||
ClockStyle.UNRECOGNIZED -> ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compat for old enum names, TODO refactor this screen
|
||||||
|
object ClockStyle {
|
||||||
|
val DigitalClock1 = ClockWidgetStyle.Digital1()
|
||||||
|
val DigitalClock1_Outlined = ClockWidgetStyle.Digital1(outlined = true)
|
||||||
|
val DigitalClock1_MDY = ClockWidgetStyle.Digital1(variant = ClockWidgetStyle.Digital1.Variant.MDY)
|
||||||
|
val DigitalClock1_OnePlus = ClockWidgetStyle.Digital1(variant = ClockWidgetStyle.Digital1.Variant.OnePlus)
|
||||||
|
val DigitalClock2 = ClockWidgetStyle.Digital2
|
||||||
|
val OrbitClock = ClockWidgetStyle.Orbit
|
||||||
|
val AnalogClock = ClockWidgetStyle.Analog
|
||||||
|
val BinaryClock = ClockWidgetStyle.Binary
|
||||||
|
val EmptyClock = ClockWidgetStyle.Empty
|
||||||
|
}
|
||||||
@ -11,15 +11,15 @@ import androidx.compose.ui.graphics.StrokeCap
|
|||||||
import androidx.compose.ui.graphics.drawscope.Fill
|
import androidx.compose.ui.graphics.drawscope.Fill
|
||||||
import androidx.compose.ui.graphics.drawscope.rotate
|
import androidx.compose.ui.graphics.drawscope.rotate
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnalogClock(
|
fun AnalogClock(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
date.timeInMillis = time
|
date.timeInMillis = time
|
||||||
val minute = date[Calendar.MINUTE]
|
val minute = date[Calendar.MINUTE]
|
||||||
|
|||||||
@ -7,15 +7,14 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BinaryClock(
|
fun BinaryClock(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
date.timeInMillis = time
|
date.timeInMillis = time
|
||||||
val minute = date[Calendar.MINUTE]
|
val minute = date[Calendar.MINUTE]
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
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.graphics.drawscope.DrawStyle
|
|
||||||
import androidx.compose.ui.graphics.drawscope.Fill
|
import androidx.compose.ui.graphics.drawscope.Fill
|
||||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@ -20,8 +19,7 @@ import androidx.compose.ui.text.withStyle
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.em
|
import androidx.compose.ui.unit.em
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
import de.mm20.launcher2.ui.ktx.toPixels
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -30,10 +28,10 @@ import java.util.*
|
|||||||
@Composable
|
@Composable
|
||||||
fun DigitalClock1(
|
fun DigitalClock1(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout,
|
compact: Boolean,
|
||||||
variant: ClockStyle = ClockStyle.DigitalClock1,
|
style: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
val format = SimpleDateFormat(
|
val format = SimpleDateFormat(
|
||||||
if (verticalLayout) {
|
if (verticalLayout) {
|
||||||
if (DateFormat.is24HourFormat(LocalContext.current)) "HH\nmm" else "hh\nmm"
|
if (DateFormat.is24HourFormat(LocalContext.current)) "HH\nmm" else "hh\nmm"
|
||||||
@ -50,8 +48,8 @@ fun DigitalClock1(
|
|||||||
fontWeight = FontWeight.Black,
|
fontWeight = FontWeight.Black,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
lineHeight = 0.8.em,
|
lineHeight = 0.8.em,
|
||||||
drawStyle = if (variant == ClockStyle.DigitalClock1_Outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
drawStyle = if (style.outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
||||||
color = if (variant == ClockStyle.DigitalClock1_MDY) {
|
color = if (style.variant == ClockWidgetStyle.Digital1.Variant.MDY) {
|
||||||
if (LocalContentColor.current == Color.White) {
|
if (LocalContentColor.current == Color.White) {
|
||||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
else MaterialTheme.colorScheme.primaryContainer
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
@ -64,7 +62,7 @@ fun DigitalClock1(
|
|||||||
|
|
||||||
val modifier = Modifier.offset(0.dp, if (verticalLayout) 16.dp else 0.dp)
|
val modifier = Modifier.offset(0.dp, if (verticalLayout) 16.dp else 0.dp)
|
||||||
|
|
||||||
if (variant == ClockStyle.DigitalClock1_OnePlus) {
|
if (style.variant == ClockWidgetStyle.Digital1.Variant.OnePlus) {
|
||||||
val hour = formattedString.substring(0, 2)
|
val hour = formattedString.substring(0, 2)
|
||||||
Text(
|
Text(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|||||||
@ -6,13 +6,12 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DigitalClock2(
|
fun DigitalClock2(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = DateUtils.formatDateTime(LocalContext.current, time, DateUtils.FORMAT_SHOW_TIME),
|
text = DateUtils.formatDateTime(LocalContext.current, time, DateUtils.FORMAT_SHOW_TIME),
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import androidx.compose.ui.unit.center
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.toOffset
|
import androidx.compose.ui.unit.toOffset
|
||||||
import de.mm20.launcher2.ktx.TWO_PI
|
import de.mm20.launcher2.ktx.TWO_PI
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
@ -46,9 +46,9 @@ private val currentTime
|
|||||||
@Composable
|
@Composable
|
||||||
fun OrbitClock(
|
fun OrbitClock(
|
||||||
_time: Long,
|
_time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
|
|
||||||
val timeState = remember { mutableStateOf<ZonedDateTime>(currentTime) }
|
val timeState = remember { mutableStateOf<ZonedDateTime>(currentTime) }
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.channels.trySendBlocking
|
import kotlinx.coroutines.channels.trySendBlocking
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@ -71,7 +70,7 @@ class AlarmPartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val alarmTime by nextAlarmTime
|
val alarmTime by nextAlarmTime
|
||||||
@ -79,7 +78,7 @@ class AlarmPartProvider : PartProvider {
|
|||||||
|
|
||||||
alarmTime?.let {
|
alarmTime?.let {
|
||||||
|
|
||||||
if (layout == ClockWidgetLayout.Vertical) {
|
if (!compactLayout) {
|
||||||
|
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|||||||
@ -20,14 +20,12 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.icons.*
|
import de.mm20.launcher2.ui.icons.*
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
@ -54,13 +52,13 @@ class BatteryPartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: Settings.ClockWidgetSettings.ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
|
|
||||||
val batteryInfo by this.batteryInfo.collectAsState(null)
|
val batteryInfo by this.batteryInfo.collectAsState(null)
|
||||||
|
|
||||||
batteryInfo?.let {
|
batteryInfo?.let {
|
||||||
|
|
||||||
if (layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical) {
|
if (!compactLayout) {
|
||||||
Row(
|
Row(
|
||||||
Modifier.padding(8.dp),
|
Modifier.padding(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
@ -86,7 +84,7 @@ class BatteryPartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Horizontal) {
|
if (compactLayout) {
|
||||||
Row(
|
Row(
|
||||||
Modifier.padding(8.dp),
|
Modifier.padding(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.em
|
import androidx.compose.ui.unit.em
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import de.mm20.launcher2.ui.base.LocalTime
|
import de.mm20.launcher2.ui.base.LocalTime
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
@ -25,9 +24,9 @@ class DatePartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: Settings.ClockWidgetSettings.ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val time = LocalTime.current
|
val time = LocalTime.current
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compactLayout
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
TextButton(
|
TextButton(
|
||||||
colors = ButtonDefaults.textButtonColors(
|
colors = ButtonDefaults.textButtonColors(
|
||||||
|
|||||||
@ -3,16 +3,13 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
||||||
import de.mm20.launcher2.widgets.CalendarWidget
|
import de.mm20.launcher2.widgets.CalendarWidget
|
||||||
@ -27,25 +24,24 @@ class FavoritesPartProvider : PartProvider, KoinComponent {
|
|||||||
|
|
||||||
private val favoritesService: FavoritesService by inject()
|
private val favoritesService: FavoritesService by inject()
|
||||||
private val widgetRepository: WidgetRepository by inject()
|
private val widgetRepository: WidgetRepository by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
override fun getRanking(context: Context): Flow<Int> = flow {
|
override fun getRanking(context: Context): Flow<Int> = flow {
|
||||||
emit(Int.MAX_VALUE)
|
emit(Int.MAX_VALUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val columns by remember(layout) {
|
val columns by remember {
|
||||||
dataStore.data.map {
|
uiSettings.gridSettings.map {
|
||||||
val c = it.grid.columnCount
|
it.columnCount
|
||||||
if (layout == ClockWidgetLayout.Horizontal) c - 2 else c
|
|
||||||
}
|
}
|
||||||
}.collectAsState(0)
|
}.collectAsState(0)
|
||||||
val excludeCalendar by remember { widgetRepository.exists(CalendarWidget.Type) }.collectAsState(
|
val excludeCalendar by remember { widgetRepository.exists(CalendarWidget.Type) }.collectAsState(
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
val favorites by remember(columns, excludeCalendar, layout) {
|
val favorites by remember(columns, excludeCalendar) {
|
||||||
favoritesService.getFavorites(
|
favoritesService.getFavorites(
|
||||||
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
||||||
manuallySorted = true,
|
manuallySorted = true,
|
||||||
|
|||||||
@ -28,7 +28,6 @@ import androidx.compose.ui.unit.dp
|
|||||||
import de.mm20.launcher2.music.MusicService
|
import de.mm20.launcher2.music.MusicService
|
||||||
import de.mm20.launcher2.music.PlaybackState
|
import de.mm20.launcher2.music.PlaybackState
|
||||||
import de.mm20.launcher2.music.SupportedActions
|
import de.mm20.launcher2.music.SupportedActions
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.channelFlow
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
@ -48,7 +47,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val title by musicService.title.collectAsState(null)
|
val title by musicService.title.collectAsState(null)
|
||||||
@ -58,7 +57,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
|||||||
|
|
||||||
val playIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_play_pause)
|
val playIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_play_pause)
|
||||||
|
|
||||||
if (layout === ClockWidgetLayout.Horizontal) {
|
if (compactLayout) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@ -113,7 +112,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layout === ClockWidgetLayout.Vertical) {
|
if (!compactLayout) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(8.dp),
|
modifier = Modifier.padding(8.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface PartProvider {
|
interface PartProvider {
|
||||||
@ -12,5 +11,5 @@ interface PartProvider {
|
|||||||
fun setTime(time: Long) {}
|
fun setTime(time: Long) {}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Component(layout: ClockWidgetLayout)
|
fun Component(compactLayout: Boolean)
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.rounded.Star
|
import androidx.compose.material.icons.rounded.Star
|
||||||
import androidx.compose.material.icons.rounded.Tag
|
import androidx.compose.material.icons.rounded.Tag
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
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.remember
|
import androidx.compose.runtime.remember
|
||||||
@ -30,6 +31,10 @@ fun FavoritesWidget(widget: FavoritesWidget) {
|
|||||||
|
|
||||||
val tagsExpanded by viewModel.tagsExpanded.collectAsState(false)
|
val tagsExpanded by viewModel.tagsExpanded.collectAsState(false)
|
||||||
|
|
||||||
|
LaunchedEffect(widget) {
|
||||||
|
viewModel.updateWidget(widget)
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
if (favorites.isNotEmpty()) {
|
if (favorites.isNotEmpty()) {
|
||||||
SearchResultGrid(favorites)
|
SearchResultGrid(favorites)
|
||||||
|
|||||||
@ -1,30 +1,32 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.favorites
|
package de.mm20.launcher2.ui.launcher.widgets.favorites
|
||||||
|
|
||||||
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.services.widgets.WidgetsService
|
import de.mm20.launcher2.services.widgets.WidgetsService
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.common.FavoritesVM
|
import de.mm20.launcher2.ui.common.FavoritesVM
|
||||||
import kotlinx.coroutines.flow.Flow
|
import de.mm20.launcher2.widgets.FavoritesWidget
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.shareIn
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class FavoritesWidgetVM : FavoritesVM() {
|
class FavoritesWidgetVM : FavoritesVM() {
|
||||||
|
|
||||||
private val widgetsService: WidgetsService by inject()
|
private val widgetsService: WidgetsService by inject()
|
||||||
|
|
||||||
override val tagsExpanded: Flow<Boolean> = dataStore.data.map { it.ui.widgetTagsMultiline }
|
private val uiSettings: UiSettings by inject()
|
||||||
.shareIn(viewModelScope, SharingStarted.Lazily)
|
|
||||||
|
override val tagsExpanded: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||||
|
private val widget = MutableStateFlow<FavoritesWidget?>(null)
|
||||||
|
|
||||||
private val isTopWidget = widgetsService.isFavoritesWidgetFirst()
|
private val isTopWidget = widgetsService.isFavoritesWidgetFirst()
|
||||||
private val clockWidgetFavSlots = dataStore.data.combine(isTopWidget) { data, isTop ->
|
private val clockWidgetFavSlots =
|
||||||
if (!isTop || !data.clockWidget.favoritesPart) 0
|
combine(uiSettings.dock, isTopWidget, uiSettings.gridSettings) { (dock, isTop, grid) ->
|
||||||
|
dock as Boolean
|
||||||
|
isTop as Boolean
|
||||||
|
grid as GridSettings
|
||||||
|
if (!isTop || !dock) 0
|
||||||
else {
|
else {
|
||||||
if (data.clockWidget.layout == ClockWidgetLayout.Horizontal) data.grid.columnCount - 2
|
grid.columnCount
|
||||||
else data.grid.columnCount
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,17 +40,16 @@ class FavoritesWidgetVM : FavoritesVM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setTagsExpanded(expanded: Boolean) {
|
override fun setTagsExpanded(expanded: Boolean) {
|
||||||
viewModelScope.launch {
|
val widget = this.widget.value ?: return
|
||||||
dataStore.updateData {
|
widgetsService.updateWidget(
|
||||||
it.toBuilder()
|
widget.copy(
|
||||||
.setUi(
|
config = widget.config.copy(tagsMultiline = expanded)
|
||||||
it.ui.toBuilder()
|
)
|
||||||
.setWidgetTagsMultiline(expanded)
|
|
||||||
.build()
|
|
||||||
)
|
)
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateWidget(widget: FavoritesWidget) {
|
||||||
|
tagsExpanded.value = widget.config.tagsMultiline
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -5,11 +5,10 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import de.mm20.launcher2.weather.DailyForecast
|
import de.mm20.launcher2.weather.DailyForecast
|
||||||
import de.mm20.launcher2.weather.Forecast
|
import de.mm20.launcher2.weather.Forecast
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@ -26,8 +25,6 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index of the currently selected day in [dailyForecasts]
|
* Index of the currently selected day in [dailyForecasts]
|
||||||
*/
|
*/
|
||||||
@ -111,7 +108,8 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
|||||||
val autoLocation = weatherSettings.autoLocation
|
val autoLocation = weatherSettings.autoLocation
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
val imperialUnits = weatherSettings.imperialUnits
|
||||||
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun selectDay(index: Int) {
|
fun selectDay(index: Int) {
|
||||||
selectedDayIndex = min(index, forecasts.lastIndex)
|
selectedDayIndex = min(index, forecasts.lastIndex)
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import androidx.compose.material3.SnackbarHostState
|
|||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.ui.geometry.Size
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.GridSettings
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
import de.mm20.launcher2.ui.theme.WallpaperColors
|
import de.mm20.launcher2.ui.theme.WallpaperColors
|
||||||
|
|
||||||
val LocalWindowSize = compositionLocalOf { Size(0f, 0f) }
|
val LocalWindowSize = compositionLocalOf { Size(0f, 0f) }
|
||||||
@ -15,11 +15,11 @@ val LocalAppWidgetHost = compositionLocalOf<AppWidgetHost?>(defaultFactory = { n
|
|||||||
|
|
||||||
val LocalNavController = compositionLocalOf<NavController?> { null }
|
val LocalNavController = compositionLocalOf<NavController?> { null }
|
||||||
|
|
||||||
val LocalCardStyle = compositionLocalOf<Settings.CardSettings> { Settings.CardSettings.getDefaultInstance() }
|
val LocalCardStyle = compositionLocalOf { CardStyle() }
|
||||||
|
|
||||||
val LocalFavoritesEnabled = compositionLocalOf { true }
|
val LocalFavoritesEnabled = compositionLocalOf { true }
|
||||||
|
|
||||||
val LocalGridSettings = compositionLocalOf { GridSettings.newBuilder().setColumnCount(5).setShowLabels(true).setIconSize(48).build() }
|
val LocalGridSettings = compositionLocalOf { GridSettings() }
|
||||||
|
|
||||||
val LocalSnackbarHostState = compositionLocalOf { SnackbarHostState() }
|
val LocalSnackbarHostState = compositionLocalOf { SnackbarHostState() }
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,6 @@ import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
|
|||||||
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
|
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
|
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreen
|
|
||||||
import de.mm20.launcher2.ui.settings.colorscheme.ThemeSettingsScreen
|
import de.mm20.launcher2.ui.settings.colorscheme.ThemeSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.colorscheme.ThemesSettingsScreen
|
import de.mm20.launcher2.ui.settings.colorscheme.ThemesSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.crashreporter.CrashReportScreen
|
import de.mm20.launcher2.ui.settings.crashreporter.CrashReportScreen
|
||||||
@ -170,9 +169,6 @@ class SettingsActivity : BaseActivity() {
|
|||||||
composable(ROUTE_MEDIA_INTEGRATION) {
|
composable(ROUTE_MEDIA_INTEGRATION) {
|
||||||
MediaIntegrationSettingsScreen()
|
MediaIntegrationSettingsScreen()
|
||||||
}
|
}
|
||||||
composable("settings/homescreen/clock") {
|
|
||||||
ClockWidgetSettingsScreen()
|
|
||||||
}
|
|
||||||
composable("settings/favorites") {
|
composable("settings/favorites") {
|
||||||
FavoritesSettingsScreen()
|
FavoritesSettingsScreen()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,9 +9,8 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
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.AppearanceSettings
|
import de.mm20.launcher2.preferences.ColorScheme
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
|
import de.mm20.launcher2.preferences.Font
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||||
@ -26,22 +25,22 @@ fun AppearanceSettingsScreen() {
|
|||||||
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val themeName by viewModel.colorSchemeName.collectAsStateWithLifecycle(null)
|
val themeName by viewModel.themeName.collectAsStateWithLifecycle(null)
|
||||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
||||||
item {
|
item {
|
||||||
PreferenceCategory {
|
PreferenceCategory {
|
||||||
val theme by viewModel.theme.collectAsState()
|
val theme by viewModel.colorScheme.collectAsState()
|
||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(id = R.string.preference_theme),
|
title = stringResource(id = R.string.preference_theme),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(id = R.string.preference_theme_system) to Theme.System,
|
stringResource(id = R.string.preference_theme_system) to ColorScheme.System,
|
||||||
stringResource(id = R.string.preference_theme_light) to Theme.Light,
|
stringResource(id = R.string.preference_theme_light) to ColorScheme.Light,
|
||||||
stringResource(id = R.string.preference_theme_dark) to Theme.Dark,
|
stringResource(id = R.string.preference_theme_dark) to ColorScheme.Dark,
|
||||||
),
|
),
|
||||||
value = theme,
|
value = theme,
|
||||||
onValueChanged = { newValue ->
|
onValueChanged = { newValue ->
|
||||||
if (newValue == null) return@ListPreference
|
if (newValue == null) return@ListPreference
|
||||||
viewModel.setTheme(newValue)
|
viewModel.setColorScheme(newValue)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Preference(
|
Preference(
|
||||||
@ -55,8 +54,8 @@ fun AppearanceSettingsScreen() {
|
|||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(R.string.preference_font),
|
title = stringResource(R.string.preference_font),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
"Outfit" to AppearanceSettings.Font.Outfit,
|
"Outfit" to Font.Outfit,
|
||||||
stringResource(R.string.preference_font_system) to AppearanceSettings.Font.SystemDefault,
|
stringResource(R.string.preference_font_system) to Font.System,
|
||||||
),
|
),
|
||||||
value = font,
|
value = font,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
|||||||
@ -3,44 +3,30 @@ package de.mm20.launcher2.ui.settings.appearance
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ColorScheme
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Font
|
import de.mm20.launcher2.preferences.Font
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
private val iconService: IconService by inject()
|
|
||||||
private val themeRepository: ThemeRepository by inject()
|
private val themeRepository: ThemeRepository by inject()
|
||||||
|
|
||||||
val theme = dataStore.data.map { it.appearance.theme }
|
val colorScheme = uiSettings.colorScheme
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setTheme(theme: Theme) {
|
fun setColorScheme(colorScheme: ColorScheme) {
|
||||||
viewModelScope.launch {
|
uiSettings.setColorScheme(colorScheme)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(it.appearance.toBuilder().setTheme(theme))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val colorSchemeName = dataStore.data.map {
|
val themeName = uiSettings.theme.flatMapLatest {
|
||||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
|
||||||
UUID.fromString(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.flatMapLatest {
|
|
||||||
themeRepository.getThemeOrDefault(it)
|
themeRepository.getThemeOrDefault(it)
|
||||||
}.map {
|
}.map {
|
||||||
it.name
|
it.name
|
||||||
@ -48,16 +34,10 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
|
|
||||||
val font = dataStore.data.map { it.appearance.font }
|
val font = uiSettings.font
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFont(font: Font) {
|
fun setFont(font: Font) {
|
||||||
viewModelScope.launch {
|
uiSettings.setFont(font)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(it.appearance.toBuilder().setFont(font))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.settings.buildinfo
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import de.mm20.launcher2.accounts.AccountType
|
import de.mm20.launcher2.accounts.AccountType
|
||||||
import de.mm20.launcher2.accounts.AccountsRepository
|
import de.mm20.launcher2.accounts.AccountsRepository
|
||||||
import de.mm20.launcher2.preferences.Settings.WeatherSettings.WeatherProvider
|
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
|
|||||||
@ -15,7 +15,9 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.SurfaceShape
|
||||||
|
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.LauncherCard
|
import de.mm20.launcher2.ui.component.LauncherCard
|
||||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||||
@ -26,6 +28,9 @@ import de.mm20.launcher2.ui.component.preferences.SliderPreference
|
|||||||
@Composable
|
@Composable
|
||||||
fun CardsSettingsScreen() {
|
fun CardsSettingsScreen() {
|
||||||
val viewModel: CardsSettingsScreenVM = viewModel()
|
val viewModel: CardsSettingsScreenVM = viewModel()
|
||||||
|
|
||||||
|
val cardStyle by viewModel.cardStyle.collectAsState(CardStyle())
|
||||||
|
|
||||||
PreferenceScreen(title = stringResource(R.string.preference_cards)) {
|
PreferenceScreen(title = stringResource(R.string.preference_cards)) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
@ -43,23 +48,21 @@ fun CardsSettingsScreen() {
|
|||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceCategory {
|
PreferenceCategory {
|
||||||
val shape by viewModel.shape.collectAsState()
|
|
||||||
ListPreference(
|
ListPreference(
|
||||||
icon = Icons.Rounded.Rectangle,
|
icon = Icons.Rounded.Rectangle,
|
||||||
title = stringResource(R.string.preference_cards_shape),
|
title = stringResource(R.string.preference_cards_shape),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_cards_shape_rounded) to Settings.CardSettings.Shape.Rounded,
|
stringResource(R.string.preference_cards_shape_rounded) to SurfaceShape.Rounded,
|
||||||
stringResource(R.string.preference_cards_shape_cut) to Settings.CardSettings.Shape.Cut,
|
stringResource(R.string.preference_cards_shape_cut) to SurfaceShape.Cut,
|
||||||
),
|
),
|
||||||
value = shape,
|
value = cardStyle.shape,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setShape(it)
|
viewModel.setShape(it)
|
||||||
})
|
})
|
||||||
val radius by viewModel.radius.collectAsState()
|
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_cards_corner_radius),
|
title = stringResource(R.string.preference_cards_corner_radius),
|
||||||
icon = Icons.Rounded.RoundedCorner,
|
icon = Icons.Rounded.RoundedCorner,
|
||||||
value = radius,
|
value = cardStyle.cornerRadius,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 24,
|
max = 24,
|
||||||
step = 1,
|
step = 1,
|
||||||
@ -67,22 +70,20 @@ fun CardsSettingsScreen() {
|
|||||||
viewModel.setRadius(it)
|
viewModel.setRadius(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val opacity by viewModel.opacity.collectAsState()
|
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_cards_opacity),
|
title = stringResource(R.string.preference_cards_opacity),
|
||||||
icon = Icons.Rounded.Opacity,
|
icon = Icons.Rounded.Opacity,
|
||||||
value = opacity,
|
value = cardStyle.opacity,
|
||||||
min = 0f,
|
min = 0f,
|
||||||
max = 1f,
|
max = 1f,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setOpacity(it)
|
viewModel.setOpacity(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val borderWidth by viewModel.borderWidth.collectAsState()
|
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_cards_stroke_width),
|
title = stringResource(R.string.preference_cards_stroke_width),
|
||||||
icon = Icons.Rounded.LineWeight,
|
icon = Icons.Rounded.LineWeight,
|
||||||
value = borderWidth,
|
value = cardStyle.borderWidth,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 8,
|
max = 8,
|
||||||
step = 1,
|
step = 1,
|
||||||
|
|||||||
@ -1,70 +1,29 @@
|
|||||||
package de.mm20.launcher2.ui.settings.cards
|
package de.mm20.launcher2.ui.settings.cards
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import de.mm20.launcher2.preferences.SurfaceShape
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
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 CardsSettingsScreenVM : ViewModel(), KoinComponent {
|
class CardsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
|
val cardStyle = uiSettings.cardStyle
|
||||||
|
|
||||||
val opacity = dataStore.data.map { it.cards.opacity }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0f)
|
|
||||||
fun setOpacity(opacity: Float) {
|
fun setOpacity(opacity: Float) {
|
||||||
viewModelScope.launch {
|
uiSettings.setCardOpacity(opacity)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setOpacity(opacity)
|
|
||||||
).build()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val radius = dataStore.data.map { it.cards.radius }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
|
||||||
|
|
||||||
fun setRadius(radius: Int) {
|
fun setRadius(radius: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setCardRadius(radius)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setRadius(radius)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val borderWidth = dataStore.data.map { it.cards.borderWidth }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
|
||||||
fun setBorderWidth(borderWidth: Int) {
|
fun setBorderWidth(borderWidth: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setCardBorderWidth(borderWidth)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setBorderWidth(borderWidth)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val shape = dataStore.data.map { it.cards.shape }
|
fun setShape(shape: SurfaceShape) {
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
uiSettings.setCardShape(shape)
|
||||||
|
|
||||||
fun setShape(shape: Settings.CardSettings.Shape) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setShape(shape)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,204 +0,0 @@
|
|||||||
package de.mm20.launcher2.ui.settings.clockwidget
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.*
|
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import com.google.accompanist.pager.HorizontalPagerIndicator
|
|
||||||
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.launcher.widgets.clock.Clock
|
|
||||||
import de.mm20.launcher2.ui.R
|
|
||||||
import de.mm20.launcher2.ui.component.preferences.*
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClockWidgetSettingsScreen() {
|
|
||||||
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
|
|
||||||
PreferenceScreen(
|
|
||||||
title = stringResource(R.string.preference_screen_clockwidget),
|
|
||||||
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/widgets/clock"
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val layout by viewModel.layout.collectAsState()
|
|
||||||
ListPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_layout),
|
|
||||||
value = layout,
|
|
||||||
items = listOf(
|
|
||||||
stringResource(R.string.preference_clockwidget_layout_vertical) to ClockWidgetLayout.Vertical,
|
|
||||||
stringResource(R.string.preference_clockwidget_layout_horizontal) to ClockWidgetLayout.Horizontal,
|
|
||||||
),
|
|
||||||
onValueChanged = {
|
|
||||||
if (it != null) viewModel.setLayout(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
|
||||||
ClockStylePreference(
|
|
||||||
layout = layout ?: ClockWidgetLayout.Vertical,
|
|
||||||
value = clockStyle,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setClockStyle(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val color by viewModel.color.collectAsState()
|
|
||||||
ListPreference(
|
|
||||||
title = stringResource(R.string.preference_clock_widget_color),
|
|
||||||
value = color,
|
|
||||||
items = listOf(
|
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to ClockWidgetColors.Auto,
|
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to ClockWidgetColors.Light,
|
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to ClockWidgetColors.Dark,
|
|
||||||
),
|
|
||||||
onValueChanged = {
|
|
||||||
if (it != null) viewModel.setColor(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val fillHeight by viewModel.fillHeight.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clock_widget_fill_height),
|
|
||||||
summary = stringResource(R.string.preference_clock_widget_fill_height_summary),
|
|
||||||
value = fillHeight == true,
|
|
||||||
onValueChanged = { viewModel.setFillHeight(it) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val datePart by viewModel.datePart.collectAsState()
|
|
||||||
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.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
|
||||||
icon = Icons.Rounded.Star,
|
|
||||||
value = favoritesPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setFavoritesPart(it)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val musicPart by viewModel.musicPart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_music_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
|
||||||
icon = Icons.Rounded.MusicNote,
|
|
||||||
value = musicPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setMusicPart(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val alarmPart by viewModel.alarmPart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
|
||||||
icon = Icons.Rounded.Alarm,
|
|
||||||
value = alarmPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setAlarmPart(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val batteryPart by viewModel.batteryPart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_battery_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
|
||||||
icon = Icons.Rounded.BatteryFull,
|
|
||||||
value = batteryPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setBatteryPart(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClockStylePreference(
|
|
||||||
layout: ClockWidgetLayout,
|
|
||||||
value: ClockStyle?,
|
|
||||||
onValueChanged: (ClockStyle) -> Unit
|
|
||||||
) {
|
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
|
||||||
Preference(
|
|
||||||
title = stringResource(R.string.preference_clock_widget_style),
|
|
||||||
summary = stringResource(R.string.preference_clock_widget_style_summary),
|
|
||||||
onClick = {
|
|
||||||
showDialog = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (showDialog && value != null) {
|
|
||||||
val styles = remember {
|
|
||||||
ClockStyle.values().filter { it != ClockStyle.UNRECOGNIZED }
|
|
||||||
}
|
|
||||||
val pagerState = rememberPagerState(styles.indexOf(value)) { styles.size }
|
|
||||||
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = { showDialog = false },
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(onClick = {
|
|
||||||
showDialog = false
|
|
||||||
onValueChanged(styles[pagerState.currentPage])
|
|
||||||
}) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(android.R.string.ok),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(onClick = { showDialog = false }) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(android.R.string.cancel),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
text = {
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
HorizontalPager(
|
|
||||||
state = pagerState,
|
|
||||||
modifier = Modifier.height(300.dp).fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Clock(
|
|
||||||
style = styles[it],
|
|
||||||
layout = layout
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HorizontalPagerIndicator(pagerState = pagerState, pageCount = styles.size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,9 +2,10 @@ package de.mm20.launcher2.ui.settings.clockwidget
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -13,146 +14,62 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val settings: ClockWidgetSettings by inject()
|
||||||
val layout = dataStore.data.map { it.clockWidget.layout }
|
val compact = settings.compact
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setLayout(layout: ClockWidgetSettings.ClockWidgetLayout) {
|
fun setCompact(compact: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setCompact(compact)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setLayout(layout)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
val clockStyle = settings.clockStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setClockStyle(clockStyle: ClockWidgetSettings.ClockStyle) {
|
fun setClockStyle(clockStyle: ClockWidgetStyle) {
|
||||||
viewModelScope.launch {
|
settings.setClockStyle(clockStyle)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setClockStyle(clockStyle)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val color = dataStore.data.map { it.clockWidget.color }
|
val color = settings.color
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setColor(color: ClockWidgetColors) {
|
fun setColor(color: ClockWidgetColors) {
|
||||||
viewModelScope.launch {
|
settings.setColor(color)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setColor(color)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val fillHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
val fillHeight = settings.fillHeight
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setFillHeight(fillHeight: Boolean) {
|
fun setFillHeight(fillHeight: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setFillHeight(fillHeight)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setFillHeight(fillHeight)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val datePart = dataStore.data.map { it.clockWidget.datePart }
|
val dock = settings.dock
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
|
val parts = settings.parts
|
||||||
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setDatePart(datePart: Boolean) {
|
fun setDatePart(datePart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setDatePart(datePart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setDatePart(datePart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val favoritesPart = dataStore.data.map { it.clockWidget.favoritesPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setFavoritesPart(favoritesPart: Boolean) {
|
fun setFavoritesPart(favoritesPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setDock(favoritesPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setFavoritesPart(favoritesPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val batteryPart = dataStore.data.map { it.clockWidget.batteryPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setBatteryPart(batteryPart: Boolean) {
|
fun setBatteryPart(batteryPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setBatteryPart(batteryPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setBatteryPart(batteryPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val musicPart = dataStore.data.map { it.clockWidget.musicPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setMusicPart(musicPart: Boolean) {
|
fun setMusicPart(musicPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setMusicPart(musicPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setMusicPart(musicPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val alarmPart = dataStore.data.map { it.clockWidget.alarmPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setAlarmPart(alarmPart: Boolean) {
|
fun setAlarmPart(alarmPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setAlarmPart(alarmPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setAlarmPart(alarmPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val alignment = dataStore.data.map { it.clockWidget.alignment }
|
val alignment = settings.alignment
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setAlignment(alignment: ClockWidgetSettings.ClockWidgetAlignment) {
|
fun setAlignment(alignment: ClockWidgetAlignment) {
|
||||||
viewModelScope.launch {
|
settings.setAlignment(alignment)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setAlignment(alignment)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,24 +2,20 @@ package de.mm20.launcher2.ui.settings.colorscheme
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.google.protobuf.ByteString
|
|
||||||
import de.mm20.launcher2.ktx.toBytes
|
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ThemeDescriptor
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
|
import de.mm20.launcher2.themes.BlackAndWhiteThemeId
|
||||||
import de.mm20.launcher2.themes.DefaultThemeId
|
import de.mm20.launcher2.themes.DefaultThemeId
|
||||||
import de.mm20.launcher2.themes.Theme
|
import de.mm20.launcher2.themes.Theme
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import de.mm20.launcher2.themes.fromJson
|
|
||||||
import de.mm20.launcher2.themes.toJson
|
import de.mm20.launcher2.themes.toJson
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -31,12 +27,14 @@ import java.util.UUID
|
|||||||
class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val themeRepository: ThemeRepository by inject()
|
private val themeRepository: ThemeRepository by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
val selectedTheme: Flow<UUID?> = dataStore.data.map {
|
val selectedTheme = uiSettings.theme.map {
|
||||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
when(it) {
|
||||||
UUID.fromString(it)
|
ThemeDescriptor.Default -> DefaultThemeId
|
||||||
} ?: DefaultThemeId
|
ThemeDescriptor.BlackAndWhite -> BlackAndWhiteThemeId
|
||||||
|
is ThemeDescriptor.Custom -> UUID.fromString(it.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val themes: Flow<List<Theme>> = themeRepository.getThemes()
|
val themes: Flow<List<Theme>> = themeRepository.getThemes()
|
||||||
|
|
||||||
@ -49,15 +47,10 @@ class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun selectTheme(theme: Theme) {
|
fun selectTheme(theme: Theme) {
|
||||||
viewModelScope.launch {
|
when(theme.id) {
|
||||||
dataStore.updateData {
|
DefaultThemeId -> ThemeDescriptor.Default
|
||||||
it.toBuilder()
|
BlackAndWhiteThemeId -> ThemeDescriptor.BlackAndWhite
|
||||||
.setAppearance(
|
else -> ThemeDescriptor.Custom(theme.id.toString())
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setThemeId(theme.id.toString())
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,24 +2,20 @@ package de.mm20.launcher2.ui.settings.easteregg
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
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 EasterEggSettingsScreenVM: ViewModel(), KoinComponent {
|
class EasterEggSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val settings: UiSettings by inject()
|
||||||
|
|
||||||
val easterEgg = dataStore.data.map { it.easterEgg }
|
val easterEgg = settings.iconShape.map { it == IconShape.EasterEgg }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
fun setEasterEgg(easterEgg: Boolean) {
|
fun setEasterEgg(easterEgg: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setIconShape(if (easterEgg) IconShape.EasterEgg else IconShape.PlatformDefault)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setEasterEgg(easterEgg).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
import de.mm20.launcher2.preferences.WeightFactor
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||||
|
|||||||
@ -2,8 +2,9 @@ package de.mm20.launcher2.ui.settings.favorites
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.WeightFactor
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.RankingSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -12,65 +13,30 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val favoritesSettings: FavoritesSettings by inject()
|
||||||
|
private val rankingSettings: RankingSettings by inject()
|
||||||
|
|
||||||
val frequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
val frequentlyUsed = favoritesSettings.frequentlyUsed
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsed(frequentlyUsed)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites.toBuilder()
|
|
||||||
.setFrequentlyUsed(frequentlyUsed)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
val frequentlyUsedRows = favoritesSettings.frequentlyUsedRows
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
|
||||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites.toBuilder()
|
|
||||||
.setFrequentlyUsedRows(frequentlyUsedRows)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val editButton = dataStore.data.map { it.favorites.editButton }
|
val editButton = favoritesSettings.showEditButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setEditButton(editButton: Boolean) {
|
fun setEditButton(editButton: Boolean) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setShowEditButton(editButton)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites.toBuilder()
|
|
||||||
.setEditButton(editButton)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchResultWeightFactor = dataStore.data.map { it.resultOrdering.weightFactor }
|
val searchResultWeightFactor = rankingSettings.weightFactor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), WeightFactor.Default)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), WeightFactor.Default)
|
||||||
fun setSearchResultWeightFactor(searchResultWeightFactor: WeightFactor) {
|
fun setSearchResultWeightFactor(searchResultWeightFactor: WeightFactor) {
|
||||||
viewModelScope.launch {
|
rankingSettings.setWeightFactor(searchResultWeightFactor)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setResultOrdering(
|
|
||||||
it.resultOrdering.toBuilder()
|
|
||||||
.setWeightFactor(searchResultWeightFactor)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,11 +7,11 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import de.mm20.launcher2.accounts.Account
|
import de.mm20.launcher2.accounts.Account
|
||||||
import de.mm20.launcher2.accounts.AccountType
|
import de.mm20.launcher2.accounts.AccountType
|
||||||
import de.mm20.launcher2.accounts.AccountsRepository
|
import de.mm20.launcher2.accounts.AccountsRepository
|
||||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.plugin.PluginType
|
import de.mm20.launcher2.plugin.PluginType
|
||||||
import de.mm20.launcher2.plugins.PluginService
|
import de.mm20.launcher2.plugins.PluginService
|
||||||
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|||||||
@ -27,8 +27,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
|
import de.mm20.launcher2.preferences.LegacySettings.LayoutSettings.Layout
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.common.SearchablePicker
|
import de.mm20.launcher2.ui.common.SearchablePicker
|
||||||
@ -47,14 +48,14 @@ fun GestureSettingsScreen() {
|
|||||||
val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null)
|
val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null)
|
||||||
|
|
||||||
val options = buildList {
|
val options = buildList {
|
||||||
add(stringResource(R.string.gesture_action_none) to GestureAction.None)
|
add(stringResource(R.string.gesture_action_none) to GestureAction.NoAction)
|
||||||
add(stringResource(R.string.gesture_action_notifications) to GestureAction.OpenNotificationDrawer)
|
add(stringResource(R.string.gesture_action_notifications) to GestureAction.Notifications)
|
||||||
add(stringResource(R.string.gesture_action_quick_settings) to GestureAction.OpenQuickSettings)
|
add(stringResource(R.string.gesture_action_quick_settings) to GestureAction.QuickSettings)
|
||||||
if (isAtLeastApiLevel(28)) add(stringResource(R.string.gesture_action_lock_screen) to GestureAction.LockScreen)
|
if (isAtLeastApiLevel(28)) add(stringResource(R.string.gesture_action_lock_screen) to GestureAction.ScreenLock)
|
||||||
add(stringResource(R.string.gesture_action_recents) to GestureAction.OpenRecents)
|
add(stringResource(R.string.gesture_action_recents) to GestureAction.Recents)
|
||||||
add(stringResource(R.string.gesture_action_power_menu) to GestureAction.OpenPowerDialog)
|
add(stringResource(R.string.gesture_action_power_menu) to GestureAction.PowerMenu)
|
||||||
add(stringResource(R.string.gesture_action_open_search) to GestureAction.OpenSearch)
|
add(stringResource(R.string.gesture_action_open_search) to GestureAction.Search)
|
||||||
add(stringResource(R.string.gesture_action_launch_app) to GestureAction.LaunchApp)
|
add(stringResource(R.string.gesture_action_launch_app) to GestureAction.Launch(null))
|
||||||
}
|
}
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@ -64,9 +65,9 @@ fun GestureSettingsScreen() {
|
|||||||
val baseLayout by viewModel.baseLayout.collectAsStateWithLifecycle(null)
|
val baseLayout by viewModel.baseLayout.collectAsStateWithLifecycle(null)
|
||||||
ListPreference(title = stringResource(R.string.preference_layout_open_search),
|
ListPreference(title = stringResource(R.string.preference_layout_open_search),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.open_search_pull_down) to Layout.PullDown,
|
stringResource(R.string.open_search_pull_down) to BaseLayout.PullDown,
|
||||||
stringResource(R.string.open_search_swipe_left) to Layout.Pager,
|
stringResource(R.string.open_search_swipe_left) to BaseLayout.Pager,
|
||||||
stringResource(R.string.open_search_swipe_right) to Layout.PagerReversed,
|
stringResource(R.string.open_search_swipe_right) to BaseLayout.PagerReversed,
|
||||||
),
|
),
|
||||||
value = baseLayout,
|
value = baseLayout,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
@ -125,7 +126,7 @@ fun GestureSettingsScreen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val swipeDown by viewModel.swipeDown.collectAsStateWithLifecycle(null)
|
val swipeDown by viewModel.swipeDown.collectAsStateWithLifecycle(null)
|
||||||
val swipeDownIsSearch = layout == Layout.PullDown
|
val swipeDownIsSearch = layout == BaseLayout.PullDown
|
||||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeDown) && !swipeDownIsSearch) {
|
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeDown) && !swipeDownIsSearch) {
|
||||||
MissingPermissionBanner(
|
MissingPermissionBanner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
@ -149,7 +150,7 @@ fun GestureSettingsScreen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val swipeLeft by viewModel.swipeLeft.collectAsStateWithLifecycle(null)
|
val swipeLeft by viewModel.swipeLeft.collectAsStateWithLifecycle(null)
|
||||||
val swipeLeftIsSearch = layout == Layout.Pager
|
val swipeLeftIsSearch = layout == BaseLayout.Pager
|
||||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeLeft) && !swipeLeftIsSearch) {
|
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeLeft) && !swipeLeftIsSearch) {
|
||||||
MissingPermissionBanner(
|
MissingPermissionBanner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
@ -173,7 +174,7 @@ fun GestureSettingsScreen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val swipeRight by viewModel.swipeRight.collectAsStateWithLifecycle(null)
|
val swipeRight by viewModel.swipeRight.collectAsStateWithLifecycle(null)
|
||||||
val swipeRightIsSearch = layout == Layout.PagerReversed
|
val swipeRightIsSearch = layout == BaseLayout.PagerReversed
|
||||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeRight) && !swipeRightIsSearch) {
|
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeRight) && !swipeRightIsSearch) {
|
||||||
MissingPermissionBanner(
|
MissingPermissionBanner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
@ -225,11 +226,11 @@ fun GestureSettingsScreen() {
|
|||||||
|
|
||||||
fun requiresAccessibilityService(action: GestureAction?): Boolean {
|
fun requiresAccessibilityService(action: GestureAction?): Boolean {
|
||||||
return when (action) {
|
return when (action) {
|
||||||
GestureAction.OpenNotificationDrawer,
|
is GestureAction.Notifications,
|
||||||
GestureAction.LockScreen,
|
is GestureAction.ScreenLock,
|
||||||
GestureAction.OpenQuickSettings,
|
is GestureAction.QuickSettings,
|
||||||
GestureAction.OpenRecents,
|
is GestureAction.Recents,
|
||||||
GestureAction.OpenPowerDialog -> true
|
is GestureAction.PowerMenu -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,12 +257,12 @@ fun GesturePreference(
|
|||||||
title = title,
|
title = title,
|
||||||
enabled = !isOpenSearch,
|
enabled = !isOpenSearch,
|
||||||
items = options,
|
items = options,
|
||||||
value = if (isOpenSearch) GestureAction.OpenSearch else value,
|
value = if (isOpenSearch) GestureAction.Search else value,
|
||||||
onValueChanged = { if (it != null) onValueChanged(it) }
|
onValueChanged = { if (it != null) onValueChanged(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value == GestureAction.LaunchApp && !isOpenSearch) {
|
if (value is GestureAction.Launch && !isOpenSearch) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(36.dp)
|
.height(36.dp)
|
||||||
@ -277,12 +278,12 @@ fun GesturePreference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOpenSearch && value == GestureAction.LaunchApp && (showAppPicker || app == null)) {
|
if (!isOpenSearch && value is GestureAction.Launch && (showAppPicker || app == null)) {
|
||||||
SearchablePicker(
|
SearchablePicker(
|
||||||
title = { Text(title) },
|
title = { Text(title) },
|
||||||
onDismissRequest = {
|
onDismissRequest = {
|
||||||
showAppPicker = false
|
showAppPicker = false
|
||||||
if (app == null) onValueChanged(GestureAction.None)
|
if (app == null) onValueChanged(GestureAction.NoAction)
|
||||||
},
|
},
|
||||||
value = app,
|
value = app,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
|||||||
@ -3,15 +3,16 @@ package de.mm20.launcher2.ui.settings.gestures
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
|
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
@ -22,7 +23,8 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val gestureSettings: GestureSettings by inject()
|
||||||
|
private val uiSettings: UiSettings by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
@ -30,206 +32,122 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
|
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
val baseLayout = uiSettings.baseLayout
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setBaseLayout(baseLayout: Settings.LayoutSettings.Layout) {
|
fun setBaseLayout(baseLayout: BaseLayout) {
|
||||||
viewModelScope.launch {
|
uiSettings.setBaseLayout(baseLayout)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setBaseLayout(baseLayout))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeDown = dataStore.data.map { it.gestures.swipeDown }
|
|
||||||
|
val swipeDown = gestureSettings.swipeDown
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val swipeLeft = dataStore.data.map { it.gestures.swipeLeft }
|
val swipeLeft = gestureSettings.swipeLeft
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val swipeRight = dataStore.data.map { it.gestures.swipeRight }
|
val swipeRight = gestureSettings.swipeRight
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val doubleTap = dataStore.data.map { it.gestures.doubleTap }
|
val doubleTap = gestureSettings.doubleTap
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val longPress = dataStore.data.map { it.gestures.longPress }
|
val longPress = gestureSettings.longPress
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val homeButton = dataStore.data.map { it.gestures.homeButton }
|
val homeButton = gestureSettings.homeButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setSwipeDown(action: GestureAction) {
|
fun setSwipeDown(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setSwipeDown(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeDown(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSwipeLeft(action: GestureAction) {
|
fun setSwipeLeft(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setSwipeLeft(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeLeft(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSwipeRight(action: GestureAction) {
|
fun setSwipeRight(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setSwipeRight(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeRight(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDoubleTap(action: GestureAction) {
|
fun setDoubleTap(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setDoubleTap(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setDoubleTap(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setLongPress(action: GestureAction) {
|
fun setLongPress(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setLongPress(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setLongPress(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setHomeButton(action: GestureAction) {
|
fun setHomeButton(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setHomeButton(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setHomeButton(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeLeftApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeLeftApp }
|
val swipeLeftApp: Flow<SavableSearchable?> = swipeLeft
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setSwipeLeftApp(searchable: SavableSearchable?) {
|
fun setSwipeLeftApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setSwipeLeft(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setSwipeLeftApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeRightApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeRightApp }
|
val swipeRightApp: Flow<SavableSearchable?> = swipeRight
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setSwipeRightApp(searchable: SavableSearchable?) {
|
fun setSwipeRightApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setSwipeRight(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setSwipeRightApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeDownApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeDownApp }
|
val swipeDownApp: Flow<SavableSearchable?> = swipeDown
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setSwipeDownApp(searchable: SavableSearchable?) {
|
fun setSwipeDownApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setSwipeDown(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setSwipeDownApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val longPressApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.longPressApp }
|
val longPressApp: Flow<SavableSearchable?> = longPress
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setLongPressApp(searchable: SavableSearchable?) {
|
fun setLongPressApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setLongPress(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setLongPressApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val doubleTapApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.doubleTapApp }
|
val doubleTapApp: Flow<SavableSearchable?> = doubleTap
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setDoubleTapApp(searchable: SavableSearchable?) {
|
fun setDoubleTapApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setDoubleTap(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setDoubleTapApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val homeButtonApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.homeButtonApp }
|
val homeButtonApp: Flow<SavableSearchable?> = homeButton
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setHomeButtonApp(searchable: SavableSearchable?) {
|
fun setHomeButtonApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setHomeButton(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setHomeButtonApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun requestPermission(context: AppCompatActivity) {
|
fun requestPermission(context: AppCompatActivity) {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import de.mm20.launcher2.searchable.SavableSearchableRepository
|
|||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.Application
|
import de.mm20.launcher2.search.Application
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -29,7 +29,7 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
private val appRepository: AppRepository by inject()
|
private val appRepository: AppRepository by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val searchUiSettings: SearchUiSettings by inject()
|
||||||
|
|
||||||
val allApps = appRepository.findMany().map {
|
val allApps = appRepository.findMany().map {
|
||||||
withContext(Dispatchers.Default) { it.sorted() }
|
withContext(Dispatchers.Default) { it.sorted() }
|
||||||
@ -68,16 +68,10 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
app.openAppDetails(context)
|
app.openAppDetails(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
val hiddenItemsButton = dataStore.data.map { it.searchBar.hiddenItemsButton }
|
val hiddenItemsButton = searchUiSettings.hiddenItemsButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setHiddenItemsButton(hidden: Boolean) {
|
fun setHiddenItemsButton(hidden: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setHiddenItemsButton(hidden)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setSearchBar(it.searchBar.toBuilder().setHiddenItemsButton(hidden)).build()
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,7 +26,10 @@ 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 com.google.accompanist.pager.HorizontalPagerIndicator
|
import com.google.accompanist.pager.HorizontalPagerIndicator
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
|
import de.mm20.launcher2.preferences.SystemBarColors
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.SearchBar
|
import de.mm20.launcher2.ui.component.SearchBar
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
@ -109,14 +112,14 @@ fun HomescreenSettingsScreen() {
|
|||||||
viewModel.setSearchBarStyle(it)
|
viewModel.setSearchBarStyle(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
AnimatedVisibility(searchBarStyle == Settings.SearchBarSettings.SearchBarStyle.Transparent) {
|
AnimatedVisibility(searchBarStyle == SearchBarStyle.Transparent) {
|
||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(R.string.preference_search_bar_color),
|
title = stringResource(R.string.preference_search_bar_color),
|
||||||
value = searchBarColor,
|
value = searchBarColor,
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SearchBarSettings.SearchBarColors.Auto,
|
stringResource(R.string.preference_system_bar_icons_auto) to SearchBarColors.Auto,
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SearchBarSettings.SearchBarColors.Light,
|
stringResource(R.string.preference_system_bar_icons_light) to SearchBarColors.Light,
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SearchBarSettings.SearchBarColors.Dark,
|
stringResource(R.string.preference_system_bar_icons_dark) to SearchBarColors.Dark,
|
||||||
),
|
),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setSearchBarColor(it)
|
if (it != null) viewModel.setSearchBarColor(it)
|
||||||
@ -208,9 +211,9 @@ fun HomescreenSettingsScreen() {
|
|||||||
title = stringResource(R.string.preference_status_bar_icons),
|
title = stringResource(R.string.preference_status_bar_icons),
|
||||||
value = lightStatusBar,
|
value = lightStatusBar,
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
|
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
|
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
|
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
|
||||||
),
|
),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setLightStatusBar(it)
|
if (it != null) viewModel.setLightStatusBar(it)
|
||||||
@ -220,9 +223,9 @@ fun HomescreenSettingsScreen() {
|
|||||||
title = stringResource(R.string.preference_nav_bar_icons),
|
title = stringResource(R.string.preference_nav_bar_icons),
|
||||||
value = lightNavBar,
|
value = lightNavBar,
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
|
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
|
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
|
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
|
||||||
),
|
),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setLightNavBar(it)
|
if (it != null) viewModel.setLightNavBar(it)
|
||||||
@ -255,15 +258,14 @@ fun HomescreenSettingsScreen() {
|
|||||||
fun SearchBarStylePreference(
|
fun SearchBarStylePreference(
|
||||||
title: String,
|
title: String,
|
||||||
summary: String? = null,
|
summary: String? = null,
|
||||||
value: Settings.SearchBarSettings.SearchBarStyle?,
|
value: SearchBarStyle?,
|
||||||
onValueChanged: (Settings.SearchBarSettings.SearchBarStyle) -> Unit
|
onValueChanged: (SearchBarStyle) -> Unit
|
||||||
) {
|
) {
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
||||||
if (showDialog && value != null) {
|
if (showDialog && value != null) {
|
||||||
val styles = remember {
|
val styles = remember {
|
||||||
Settings.SearchBarSettings.SearchBarStyle.values()
|
SearchBarStyle.entries
|
||||||
.filter { it != Settings.SearchBarSettings.SearchBarStyle.UNRECOGNIZED }
|
|
||||||
}
|
}
|
||||||
val pagerState = rememberPagerState(initialPage = styles.indexOf(value)) { styles.size }
|
val pagerState = rememberPagerState(initialPage = styles.indexOf(value)) { styles.size }
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,12 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ScreenOrientation
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
|
import de.mm20.launcher2.preferences.SystemBarColors
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -23,52 +27,31 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.get
|
import org.koin.core.component.get
|
||||||
|
|
||||||
class HomescreenSettingsScreenVM(
|
class HomescreenSettingsScreenVM(
|
||||||
private val dataStore: LauncherDataStore,
|
private val uiSettings: UiSettings,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
var showClockWidgetSheet by mutableStateOf(false)
|
var showClockWidgetSheet by mutableStateOf(false)
|
||||||
|
|
||||||
|
|
||||||
val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }
|
val dimWallpaper = uiSettings.dimWallpaper
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setDimWallpaper(dimWallpaper: Boolean) {
|
fun setDimWallpaper(dimWallpaper: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setDimWallpaper(dimWallpaper)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setDimWallpaper(dimWallpaper)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper }
|
val blurWallpaper = uiSettings.blurWallpaper
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setBlurWallpaper(blurWallpaper: Boolean) {
|
fun setBlurWallpaper(blurWallpaper: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setBlurWallpaper(blurWallpaper)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setBlurWallpaper(blurWallpaper)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val blurWallpaperRadius = dataStore.data.map { it.appearance.blurWallpaperRadius }
|
val blurWallpaperRadius = uiSettings.wallpaperBlurRadius
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
||||||
|
|
||||||
fun setBlurWallpaperRadius(blurWallpaperRadius: Int) {
|
fun setBlurWallpaperRadius(blurWallpaperRadius: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setWallpaperBlurRadius(blurWallpaperRadius)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setBlurWallpaperRadius(blurWallpaperRadius)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openWallpaperChooser(context: AppCompatActivity) {
|
fun openWallpaperChooser(context: AppCompatActivity) {
|
||||||
@ -80,168 +63,88 @@ class HomescreenSettingsScreenVM(
|
|||||||
return context.getSystemService<WindowManager>()?.isCrossWindowBlurEnabled == true
|
return context.getSystemService<WindowManager>()?.isCrossWindowBlurEnabled == true
|
||||||
}
|
}
|
||||||
|
|
||||||
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }
|
val statusBarIcons = uiSettings.statusBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setLightStatusBar(statusBarColor: Settings.SystemBarsSettings.SystemBarColors) {
|
|
||||||
viewModelScope.launch {
|
fun setLightStatusBar(statusBarColor: SystemBarColors) {
|
||||||
dataStore.updateData {
|
uiSettings.setStatusBarColor(statusBarColor)
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setStatusBarColor(statusBarColor)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }
|
val navBarIcons = uiSettings.navigationBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setLightNavBar(navBarColors: Settings.SystemBarsSettings.SystemBarColors) {
|
|
||||||
viewModelScope.launch {
|
fun setLightNavBar(navBarColors: SystemBarColors) {
|
||||||
dataStore.updateData {
|
uiSettings.setNavigationBarColor(navBarColors)
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setNavBarColor(navBarColors)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
val hideStatusBar = uiSettings.hideStatusBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setHideStatusBar(hideStatusBar: Boolean) {
|
fun setHideStatusBar(hideStatusBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setHideStatusBar(hideStatusBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setHideStatusBar(hideStatusBar)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
val hideNavBar = uiSettings.hideNavigationBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setHideNavBar(hideNavBar: Boolean) {
|
fun setHideNavBar(hideNavBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setHideNavigationBar(hideNavBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setHideNavBar(hideNavBar)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
val searchBarColor = uiSettings.searchBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setSearchBarColor(color: Settings.SearchBarSettings.SearchBarColors) {
|
|
||||||
viewModelScope.launch {
|
fun setSearchBarColor(color: SearchBarColors) {
|
||||||
dataStore.updateData {
|
uiSettings.setSearchBarColor(color)
|
||||||
it.toBuilder()
|
|
||||||
.setSearchBar(
|
|
||||||
it.searchBar.toBuilder()
|
|
||||||
.setColor(color)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
val searchBarStyle = uiSettings.searchBarStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setSearchBarStyle(searchBarStyle: Settings.SearchBarSettings.SearchBarStyle) {
|
|
||||||
viewModelScope.launch {
|
fun setSearchBarStyle(searchBarStyle: SearchBarStyle) {
|
||||||
dataStore.updateData {
|
uiSettings.setSearchBarStyle(searchBarStyle)
|
||||||
it.toBuilder()
|
|
||||||
.setSearchBar(
|
|
||||||
it.searchBar.toBuilder()
|
|
||||||
.setSearchBarStyle(searchBarStyle)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
val fixedSearchBar = uiSettings.fixedSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFixedSearchBar(fixedSearchBar: Boolean) {
|
fun setFixedSearchBar(fixedSearchBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setFixedSearchBar(fixedSearchBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setFixedSearchBar(fixedSearchBar))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
val bottomSearchBar = uiSettings.bottomSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setBottomSearchBar(bottomSearchBar: Boolean) {
|
fun setBottomSearchBar(bottomSearchBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setBottomSearchBar(bottomSearchBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setBottomSearchBar(bottomSearchBar))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
|
val fixedRotation = uiSettings.orientation.map { it != ScreenOrientation.Auto }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFixedRotation(fixedRotation: Boolean) {
|
fun setFixedRotation(fixedRotation: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setOrientation(if (fixedRotation) ScreenOrientation.Portrait else ScreenOrientation.Auto)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setFixedRotation(fixedRotation))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val widgetEditButton = dataStore.data.map { it.widgets.editButton }
|
val widgetEditButton = uiSettings.widgetEditButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setWidgetEditButton(editButton: Boolean) {
|
fun setWidgetEditButton(editButton: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setWidgetEditButton(editButton)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWidgets(
|
|
||||||
it.widgets.toBuilder()
|
|
||||||
.setEditButton(editButton)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val chargingAnimation = dataStore.data.map { it.animations.charging }
|
val chargingAnimation = uiSettings.chargingAnimation
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setChargingAnimation(chargingAnimation: Boolean) {
|
fun setChargingAnimation(chargingAnimation: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setChargingAnimation(chargingAnimation)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAnimations(
|
|
||||||
it.animations.toBuilder()
|
|
||||||
.setCharging(chargingAnimation)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : KoinComponent {
|
companion object : KoinComponent {
|
||||||
val Factory = viewModelFactory {
|
val Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
HomescreenSettingsScreenVM(
|
HomescreenSettingsScreenVM(
|
||||||
dataStore = get()
|
uiSettings = get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import androidx.compose.material3.FilledIconToggleButton
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedCard
|
|
||||||
import androidx.compose.material3.PlainTooltipBox
|
import androidx.compose.material3.PlainTooltipBox
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@ -50,7 +49,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.icons.StaticIconLayer
|
import de.mm20.launcher2.icons.StaticIconLayer
|
||||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.IconSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.IconSettingsData
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||||
@ -63,25 +65,18 @@ import de.mm20.launcher2.ui.component.preferences.SliderPreference
|
|||||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||||
import de.mm20.launcher2.ui.component.preferences.label
|
import de.mm20.launcher2.ui.component.preferences.label
|
||||||
import de.mm20.launcher2.ui.component.preferences.value
|
import de.mm20.launcher2.ui.component.preferences.value
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun IconsSettingsScreen() {
|
fun IconsSettingsScreen() {
|
||||||
val viewModel: IconsSettingsScreenVM = viewModel(factory = IconsSettingsScreenVM.Factory)
|
val viewModel: IconsSettingsScreenVM = viewModel(factory = IconsSettingsScreenVM.Factory)
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val iconSize by viewModel.iconSize.collectAsStateWithLifecycle(48)
|
val grid by viewModel.grid.collectAsStateWithLifecycle(GridSettings())
|
||||||
|
val icons by viewModel.icons.collectAsStateWithLifecycle(null)
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val showLabels by viewModel.showLabels.collectAsStateWithLifecycle(null)
|
val iconShape by viewModel.iconShape.collectAsStateWithLifecycle(IconShape.PlatformDefault)
|
||||||
val columnCount by viewModel.columnCount.collectAsStateWithLifecycle(5)
|
|
||||||
val iconShape by viewModel.iconShape.collectAsStateWithLifecycle(Settings.IconSettings.IconShape.PlatformDefault)
|
|
||||||
val adaptifyLegacyIcons by viewModel.adaptifyLegacyIcons.collectAsStateWithLifecycle(null)
|
|
||||||
val themedIcons by viewModel.themedIcons.collectAsStateWithLifecycle(null)
|
|
||||||
|
|
||||||
val iconPackPackage by viewModel.iconPack.collectAsStateWithLifecycle(null)
|
|
||||||
val iconPackThemed by viewModel.iconPackThemed.collectAsState(true)
|
|
||||||
val installedIconPacks by viewModel.installedIconPacks.collectAsState(emptyList())
|
val installedIconPacks by viewModel.installedIconPacks.collectAsState(emptyList())
|
||||||
val forceThemedIcons by viewModel.forceThemedIcons.collectAsStateWithLifecycle(null)
|
|
||||||
|
|
||||||
val hasNotificationsPermission by viewModel.hasNotificationsPermission.collectAsStateWithLifecycle(null)
|
val hasNotificationsPermission by viewModel.hasNotificationsPermission.collectAsStateWithLifecycle(null)
|
||||||
|
|
||||||
@ -91,8 +86,8 @@ fun IconsSettingsScreen() {
|
|||||||
val shortcutBadges by viewModel.shortcutBadges.collectAsStateWithLifecycle(null)
|
val shortcutBadges by viewModel.shortcutBadges.collectAsStateWithLifecycle(null)
|
||||||
val pluginBadges by viewModel.pluginBadges.collectAsStateWithLifecycle(null)
|
val pluginBadges by viewModel.pluginBadges.collectAsStateWithLifecycle(null)
|
||||||
|
|
||||||
val previewIcons by remember(iconSize) {
|
val previewIcons by remember(grid?.iconSize) {
|
||||||
viewModel.getPreviewIcons(with(density) { iconSize.dp.toPx() }.toInt())
|
viewModel.getPreviewIcons(with(density) { grid.iconSize.dp.toPx() }.toInt())
|
||||||
}.collectAsState(
|
}.collectAsState(
|
||||||
emptyList()
|
emptyList()
|
||||||
)
|
)
|
||||||
@ -102,7 +97,7 @@ fun IconsSettingsScreen() {
|
|||||||
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
|
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_grid_icon_size),
|
title = stringResource(R.string.preference_grid_icon_size),
|
||||||
value = iconSize,
|
value = grid.iconSize,
|
||||||
step = 8,
|
step = 8,
|
||||||
min = 32,
|
min = 32,
|
||||||
max = 64,
|
max = 64,
|
||||||
@ -113,14 +108,14 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_grid_labels),
|
title = stringResource(R.string.preference_grid_labels),
|
||||||
summary = stringResource(R.string.preference_grid_labels_summary),
|
summary = stringResource(R.string.preference_grid_labels_summary),
|
||||||
value = showLabels == true,
|
value = grid.showLabels,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setShowLabels(it)
|
viewModel.setShowLabels(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_grid_column_count),
|
title = stringResource(R.string.preference_grid_column_count),
|
||||||
value = columnCount,
|
value = grid.columnCount,
|
||||||
min = 3,
|
min = 3,
|
||||||
max = 12,
|
max = 12,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
@ -148,7 +143,7 @@ fun IconsSettingsScreen() {
|
|||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
ShapedLauncherIcon(size = iconSize.dp, icon = { icon })
|
ShapedLauncherIcon(size = grid.iconSize.dp, icon = { icon })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,7 +160,7 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_enforce_icon_shape),
|
title = stringResource(R.string.preference_enforce_icon_shape),
|
||||||
summary = stringResource(R.string.preference_enforce_icon_shape_summary),
|
summary = stringResource(R.string.preference_enforce_icon_shape_summary),
|
||||||
value = adaptifyLegacyIcons == true,
|
value = icons?.adaptify == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setAdaptifyLegacyIcons(it)
|
viewModel.setAdaptifyLegacyIcons(it)
|
||||||
}
|
}
|
||||||
@ -173,7 +168,7 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_themed_icons),
|
title = stringResource(R.string.preference_themed_icons),
|
||||||
summary = stringResource(R.string.preference_themed_icons_summary),
|
summary = stringResource(R.string.preference_themed_icons_summary),
|
||||||
value = themedIcons == true,
|
value = icons?.themedIcons == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setThemedIcons(it)
|
viewModel.setThemedIcons(it)
|
||||||
}
|
}
|
||||||
@ -181,14 +176,14 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_force_themed_icons),
|
title = stringResource(R.string.preference_force_themed_icons),
|
||||||
summary = stringResource(R.string.preference_force_themed_icons_summary),
|
summary = stringResource(R.string.preference_force_themed_icons_summary),
|
||||||
value = forceThemedIcons == true,
|
value = icons?.forceThemed == true,
|
||||||
enabled = themedIcons == true,
|
enabled = icons?.themedIcons == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setForceThemedIcons(it)
|
viewModel.setForceThemedIcons(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val iconPack by remember {
|
val iconPack by remember {
|
||||||
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == iconPackPackage } }
|
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == icons?.iconPack } }
|
||||||
}
|
}
|
||||||
val items = installedIconPacks.map {
|
val items = installedIconPacks.map {
|
||||||
it.name to it
|
it.name to it
|
||||||
@ -265,7 +260,7 @@ fun IconsSettingsScreen() {
|
|||||||
PlainTooltipBox(tooltip = { Text(stringResource(R.string.icon_pack_dynamic_colors)) }) {
|
PlainTooltipBox(tooltip = { Text(stringResource(R.string.icon_pack_dynamic_colors)) }) {
|
||||||
FilledIconToggleButton(
|
FilledIconToggleButton(
|
||||||
modifier = Modifier.tooltipTrigger(),
|
modifier = Modifier.tooltipTrigger(),
|
||||||
checked = iconPackThemed,
|
checked = icons?.iconPackThemed == true,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
viewModel.setIconPackThemed(it)
|
viewModel.setIconPackThemed(it)
|
||||||
}) {
|
}) {
|
||||||
@ -347,16 +342,16 @@ fun IconsSettingsScreen() {
|
|||||||
fun IconShapePreference(
|
fun IconShapePreference(
|
||||||
title: String,
|
title: String,
|
||||||
summary: String? = null,
|
summary: String? = null,
|
||||||
value: Settings.IconSettings.IconShape?,
|
value: IconShape?,
|
||||||
onValueChanged: (Settings.IconSettings.IconShape) -> Unit
|
onValueChanged: (IconShape) -> Unit
|
||||||
) {
|
) {
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
||||||
|
|
||||||
if (showDialog && value != null) {
|
if (showDialog && value != null) {
|
||||||
val shapes = remember {
|
val shapes = remember {
|
||||||
Settings.IconSettings.IconShape.values()
|
IconShape.entries
|
||||||
.filter { it != Settings.IconSettings.IconShape.UNRECOGNIZED && it != Settings.IconSettings.IconShape.EasterEgg }
|
.filter { it != IconShape.EasterEgg }
|
||||||
}
|
}
|
||||||
Dialog(onDismissRequest = { showDialog = false }) {
|
Dialog(onDismissRequest = { showDialog = false }) {
|
||||||
Surface(
|
Surface(
|
||||||
@ -431,19 +426,19 @@ fun IconShapePreference(
|
|||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getShapeName(shape: Settings.IconSettings.IconShape?): String? {
|
private fun getShapeName(shape: IconShape?): String? {
|
||||||
return stringResource(
|
return stringResource(
|
||||||
when (shape) {
|
when (shape) {
|
||||||
Settings.IconSettings.IconShape.Triangle -> R.string.preference_icon_shape_triangle
|
IconShape.Triangle -> R.string.preference_icon_shape_triangle
|
||||||
Settings.IconSettings.IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
|
IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
|
||||||
Settings.IconSettings.IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
|
IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
|
||||||
Settings.IconSettings.IconShape.Squircle -> R.string.preference_icon_shape_squircle
|
IconShape.Squircle -> R.string.preference_icon_shape_squircle
|
||||||
Settings.IconSettings.IconShape.Square -> R.string.preference_icon_shape_square
|
IconShape.Square -> R.string.preference_icon_shape_square
|
||||||
Settings.IconSettings.IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
|
IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
|
||||||
Settings.IconSettings.IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
|
IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
|
||||||
Settings.IconSettings.IconShape.Circle -> R.string.preference_icon_shape_circle
|
IconShape.Circle -> R.string.preference_icon_shape_circle
|
||||||
Settings.IconSettings.IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
|
IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
|
||||||
Settings.IconSettings.IconShape.Pebble -> R.string.preference_icon_shape_pebble
|
IconShape.Pebble -> R.string.preference_icon_shape_pebble
|
||||||
else -> return null
|
else -> return null
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,124 +2,64 @@ package de.mm20.launcher2.ui.settings.icons
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import de.mm20.launcher2.badges.settings.BadgeSettings
|
|
||||||
import de.mm20.launcher2.icons.IconPack
|
import de.mm20.launcher2.icons.IconPack
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ui.BadgeSettings
|
||||||
import de.mm20.launcher2.search.Application
|
import de.mm20.launcher2.preferences.ui.IconSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.get
|
import org.koin.core.component.get
|
||||||
|
|
||||||
class IconsSettingsScreenVM(
|
class IconsSettingsScreenVM(
|
||||||
private val dataStore: LauncherDataStore,
|
private val uiSettings: UiSettings,
|
||||||
|
private val iconSettings: IconSettings,
|
||||||
private val badgeSettings: BadgeSettings,
|
private val badgeSettings: BadgeSettings,
|
||||||
private val iconService: IconService,
|
private val iconService: IconService,
|
||||||
private val favoritesService: FavoritesService,
|
private val favoritesService: FavoritesService,
|
||||||
private val permissionsManager: PermissionsManager,
|
private val permissionsManager: PermissionsManager,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
|
val grid = uiSettings.gridSettings
|
||||||
|
|
||||||
val columnCount = dataStore.data.map { it.grid.columnCount }
|
|
||||||
fun setColumnCount(columnCount: Int) {
|
fun setColumnCount(columnCount: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setGridColumnCount(columnCount)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGrid(it.grid.toBuilder().setColumnCount(columnCount))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconSize = dataStore.data.map { it.grid.iconSize }
|
|
||||||
fun setIconSize(iconSize: Int) {
|
fun setIconSize(iconSize: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setGridIconSize(iconSize)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGrid(it.grid.toBuilder().setIconSize(iconSize))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val showLabels = dataStore.data.map { it.grid.showLabels }
|
|
||||||
fun setShowLabels(showLabels: Boolean) {
|
fun setShowLabels(showLabels: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setGridShowLabels(showLabels)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGrid(it.grid.toBuilder().setShowLabels(showLabels))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconShape = dataStore.data.map { it.icons.shape }
|
val iconShape = uiSettings.iconShape
|
||||||
fun setIconShape(iconShape: Settings.IconSettings.IconShape) {
|
fun setIconShape(iconShape: IconShape) {
|
||||||
viewModelScope.launch {
|
uiSettings.setIconShape(iconShape)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setShape(iconShape)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val adaptifyLegacyIcons = dataStore.data.map { it.icons.adaptify }
|
val icons = iconSettings
|
||||||
fun setAdaptifyLegacyIcons(adaptify: Boolean) {
|
fun setAdaptifyLegacyIcons(adaptify: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setAdaptifyLegacyIcons(adaptify)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setAdaptify(adaptify)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val themedIcons = dataStore.data.map { it.icons.themedIcons }
|
|
||||||
fun setThemedIcons(themedIcons: Boolean) {
|
fun setThemedIcons(themedIcons: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setThemedIcons(themedIcons)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setThemedIcons(themedIcons)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val forceThemedIcons = dataStore.data.map { it.icons.forceThemed }
|
|
||||||
fun setForceThemedIcons(forceThemedIcons: Boolean) {
|
fun setForceThemedIcons(forceThemedIcons: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setForceThemedIcons(forceThemedIcons)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setForceThemed(forceThemedIcons)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val installedIconPacks: Flow<List<IconPack>> = iconService.getInstalledIconPacks().map {
|
val installedIconPacks: Flow<List<IconPack>> = iconService.getInstalledIconPacks().map {
|
||||||
@ -132,33 +72,12 @@ class IconsSettingsScreenVM(
|
|||||||
) + it
|
) + it
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconPackThemed = dataStore.data.map { it.icons.iconPackThemed }
|
|
||||||
fun setIconPackThemed(iconPackThemed: Boolean) {
|
fun setIconPackThemed(iconPackThemed: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setIconPackThemed(iconPackThemed)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons
|
|
||||||
.toBuilder()
|
|
||||||
.setIconPackThemed(iconPackThemed)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconPack = dataStore.data.map { it.icons.iconPack }
|
fun setIconPack(iconPack: String?) {
|
||||||
fun setIconPack(iconPack: String) {
|
iconSettings.setIconPack(iconPack?.takeIf { it.isNotBlank() })
|
||||||
viewModelScope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setIconPack(iconPack)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasNotificationsPermission = permissionsManager.hasPermission(PermissionGroup.Notifications)
|
val hasNotificationsPermission = permissionsManager.hasPermission(PermissionGroup.Notifications)
|
||||||
@ -193,10 +112,10 @@ class IconsSettingsScreenVM(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getPreviewIcons(size: Int): Flow<List<LauncherIcon?>> {
|
fun getPreviewIcons(size: Int): Flow<List<LauncherIcon?>> {
|
||||||
return columnCount.flatMapLatest { cols ->
|
return grid.flatMapLatest { grid ->
|
||||||
favoritesService.getFavorites(
|
favoritesService.getFavorites(
|
||||||
includeTypes = listOf("app"),
|
includeTypes = listOf("app"),
|
||||||
limit = cols,
|
limit = grid.columnCount,
|
||||||
manuallySorted = true,
|
manuallySorted = true,
|
||||||
automaticallySorted = true,
|
automaticallySorted = true,
|
||||||
frequentlyUsed = true,
|
frequentlyUsed = true,
|
||||||
@ -214,11 +133,12 @@ class IconsSettingsScreenVM(
|
|||||||
val Factory = viewModelFactory {
|
val Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
IconsSettingsScreenVM(
|
IconsSettingsScreenVM(
|
||||||
dataStore = get(),
|
uiSettings = get(),
|
||||||
iconService = get(),
|
iconService = get(),
|
||||||
permissionsManager = get(),
|
permissionsManager = get(),
|
||||||
favoritesService = get(),
|
favoritesService = get(),
|
||||||
badgeSettings = get(),
|
badgeSettings = get(),
|
||||||
|
iconSettings = get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,13 +11,12 @@ import de.mm20.launcher2.ktx.normalize
|
|||||||
import de.mm20.launcher2.music.MusicService
|
import de.mm20.launcher2.music.MusicService
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.media.MediaSettings
|
||||||
import de.mm20.launcher2.search.AppProfile
|
import de.mm20.launcher2.search.AppProfile
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@ -29,7 +28,9 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
private val musicService: MusicService by inject()
|
private val musicService: MusicService by inject()
|
||||||
private val appRepository: AppRepository by inject()
|
private val appRepository: AppRepository by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
|
private val mediaSettings: MediaSettings by inject()
|
||||||
|
|
||||||
val hasPermission =
|
val hasPermission =
|
||||||
permissionsManager.hasPermission(PermissionGroup.Notifications)
|
permissionsManager.hasPermission(PermissionGroup.Notifications)
|
||||||
|
|
||||||
@ -52,9 +53,9 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
val musicApps = musicService.getInstalledPlayerPackages()
|
val musicApps = musicService.getInstalledPlayerPackages()
|
||||||
val allApps = appRepository.findMany().first().filter { it.profile == AppProfile.Personal }
|
val allApps = appRepository.findMany().first().filter { it.profile == AppProfile.Personal }
|
||||||
.distinctBy { it.componentName.packageName }
|
.distinctBy { it.componentName.packageName }
|
||||||
val settings = dataStore.data.map { it.musicWidget }.first()
|
val settings = mediaSettings.first()
|
||||||
val allowList = settings.allowListList
|
val allowList = settings.allowList
|
||||||
val denyList = settings.denyListList
|
val denyList = settings.denyList
|
||||||
|
|
||||||
appList.value = allApps.map {
|
appList.value = allApps.map {
|
||||||
AppListItem(
|
AppListItem(
|
||||||
@ -92,19 +93,7 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
denyList.add(app.packageName)
|
denyList.add(app.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewModelScope.launch {
|
mediaSettings.setLists(allowList.toSet(), denyList.toSet())
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setMusicWidget(
|
|
||||||
it.musicWidget.toBuilder()
|
|
||||||
.clearAllowList()
|
|
||||||
.addAllAllowList(allowList)
|
|
||||||
.clearDenyList()
|
|
||||||
.addAllDenyList(denyList)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,14 +7,14 @@ import android.net.Uri
|
|||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.plugin.PluginPackage
|
import de.mm20.launcher2.plugin.PluginPackage
|
||||||
import de.mm20.launcher2.plugin.PluginState
|
import de.mm20.launcher2.plugin.PluginState
|
||||||
import de.mm20.launcher2.plugin.PluginType
|
import de.mm20.launcher2.plugin.PluginType
|
||||||
import de.mm20.launcher2.plugins.PluginService
|
import de.mm20.launcher2.plugins.PluginService
|
||||||
import de.mm20.launcher2.plugins.PluginWithState
|
import de.mm20.launcher2.plugins.PluginWithState
|
||||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
@ -111,6 +111,6 @@ class PluginSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val weatherProvider = weatherSettings.providerId
|
val weatherProvider = weatherSettings.providerId
|
||||||
fun setWeatherProvider(providerId: String) {
|
fun setWeatherProvider(providerId: String) {
|
||||||
weatherSettings.setProviderId(providerId)
|
weatherSettings.setProvider(providerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,7 +13,8 @@ import androidx.compose.ui.res.stringResource
|
|||||||
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
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
import de.mm20.launcher2.ui.component.preferences.*
|
import de.mm20.launcher2.ui.component.preferences.*
|
||||||
@ -232,8 +233,8 @@ fun SearchSettingsScreen() {
|
|||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(R.string.preference_search_result_ordering),
|
title = stringResource(R.string.preference_search_result_ordering),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_search_result_ordering_alphabetic) to Settings.SearchResultOrderingSettings.Ordering.Alphabetic,
|
stringResource(R.string.preference_search_result_ordering_alphabetic) to SearchResultOrder.Alphabetical,
|
||||||
stringResource(R.string.preference_search_result_ordering_weighted) to Settings.SearchResultOrderingSettings.Ordering.Weighted
|
stringResource(R.string.preference_search_result_ordering_weighted) to SearchResultOrder.Weighted
|
||||||
),
|
),
|
||||||
value = searchResultOrdering,
|
value = searchResultOrdering,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
|||||||
@ -5,10 +5,16 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.search.CalculatorSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.CalendarSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.UnitConverterSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WebsiteSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WikipediaSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -16,35 +22,32 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val searchUiSettings: SearchUiSettings by inject()
|
||||||
|
private val contactSearchSettings: ContactSearchSettings by inject()
|
||||||
|
private val calendarSearchSettings: CalendarSearchSettings by inject()
|
||||||
|
private val shortcutSearchSettings: ShortcutSearchSettings by inject()
|
||||||
|
private val wikipediaSearchSettings: WikipediaSearchSettings by inject()
|
||||||
|
private val websiteSearchSettings: WebsiteSearchSettings by inject()
|
||||||
|
private val unitConverterSettings: UnitConverterSettings by inject()
|
||||||
|
private val calculatorSearchSettings: CalculatorSearchSettings by inject()
|
||||||
|
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
|
|
||||||
val favorites = dataStore.data.map { it.favorites.enabled }
|
val favorites = searchUiSettings.favorites
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFavorites(favorites: Boolean) {
|
fun setFavorites(favorites: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setFavorites(favorites)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setFavorites(
|
|
||||||
it.favorites.toBuilder().setEnabled(favorites)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val contacts = dataStore.data.map { it.contactsSearch.enabled }
|
val contacts = contactSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setContacts(contacts: Boolean) {
|
fun setContacts(contacts: Boolean) {
|
||||||
viewModelScope.launch {
|
contactSearchSettings.setEnabled(contacts)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setContactsSearch(
|
|
||||||
it.contactsSearch.toBuilder().setEnabled(contacts)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestContactsPermission(activity: AppCompatActivity) {
|
fun requestContactsPermission(activity: AppCompatActivity) {
|
||||||
@ -53,133 +56,81 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val calendar = dataStore.data.map { it.calendarSearch.enabled }
|
val calendar = calendarSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setCalendar(calendar: Boolean) {
|
fun setCalendar(calendar: Boolean) {
|
||||||
viewModelScope.launch {
|
calendarSearchSettings.setEnabled(calendar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setCalendarSearch(
|
|
||||||
it.calendarSearch.toBuilder().setEnabled(calendar)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestCalendarPermission(activity: AppCompatActivity) {
|
fun requestCalendarPermission(activity: AppCompatActivity) {
|
||||||
permissionsManager.requestPermission(activity, PermissionGroup.Calendar)
|
permissionsManager.requestPermission(activity, PermissionGroup.Calendar)
|
||||||
}
|
}
|
||||||
|
|
||||||
val calculator = dataStore.data.map { it.calculatorSearch.enabled }
|
val calculator = calculatorSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setCalculator(calculator: Boolean) {
|
fun setCalculator(calculator: Boolean) {
|
||||||
viewModelScope.launch {
|
calculatorSearchSettings.setEnabled(calculator)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setCalculatorSearch(
|
|
||||||
it.calculatorSearch.toBuilder().setEnabled(calculator)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
|
val unitConverter = unitConverterSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setUnitConverter(unitConverter: Boolean) {
|
fun setUnitConverter(unitConverter: Boolean) {
|
||||||
viewModelScope.launch {
|
unitConverterSettings.setEnabled(unitConverter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setUnitConverterSearch(
|
|
||||||
it.unitConverterSearch.toBuilder().setEnabled(unitConverter)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
|
val wikipedia = wikipediaSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setWikipedia(wikipedia: Boolean) {
|
fun setWikipedia(wikipedia: Boolean) {
|
||||||
viewModelScope.launch {
|
wikipediaSearchSettings.setEnabled(wikipedia)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder().setEnabled(wikipedia)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val websites = dataStore.data.map { it.websiteSearch.enabled }
|
val websites = websiteSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setWebsites(websites: Boolean) {
|
fun setWebsites(websites: Boolean) {
|
||||||
viewModelScope.launch {
|
websiteSearchSettings.setEnabled(websites)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setWebsiteSearch(
|
|
||||||
it.websiteSearch.toBuilder().setEnabled(websites)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val autoFocus = dataStore.data.map { it.searchBar.autoFocus }
|
val autoFocus = searchUiSettings.openKeyboard
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setAutoFocus(autoFocus: Boolean) {
|
fun setAutoFocus(autoFocus: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setOpenKeyboard(autoFocus)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setSearchBar(
|
|
||||||
it.searchBar.toBuilder().setAutoFocus(autoFocus)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
|
val launchOnEnter = searchUiSettings.launchOnEnter
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setLaunchOnEnter(launchOnEnter: Boolean) {
|
fun setLaunchOnEnter(launchOnEnter: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setLaunchOnEnter(launchOnEnter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setSearchBar(
|
|
||||||
it.searchBar.toBuilder().setLaunchOnEnter(launchOnEnter)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
|
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled }
|
val appShortcuts = shortcutSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setAppShortcuts(appShortcuts: Boolean) {
|
fun setAppShortcuts(appShortcuts: Boolean) {
|
||||||
viewModelScope.launch {
|
shortcutSearchSettings.setEnabled(appShortcuts)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setAppShortcutSearch(
|
|
||||||
it.appShortcutSearch.toBuilder().setEnabled(appShortcuts)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering }
|
val searchResultOrdering = searchUiSettings.resultOrder
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setSearchResultOrdering(searchResultOrdering: Settings.SearchResultOrderingSettings.Ordering) {
|
|
||||||
viewModelScope.launch {
|
fun setSearchResultOrdering(searchResultOrdering: SearchResultOrder) {
|
||||||
dataStore.updateData {
|
searchUiSettings.setResultOrder(searchResultOrdering)
|
||||||
it.toBuilder().setResultOrdering(
|
|
||||||
it.resultOrdering.toBuilder().setOrdering(searchResultOrdering)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
val reverseSearchResults = searchUiSettings.reversedResults
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setReverseSearchResults(reverseSearchResults: Boolean) {
|
fun setReverseSearchResults(reverseSearchResults: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setReversedResults(reverseSearchResults)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setReverseSearchResults(reverseSearchResults))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestAppShortcutsPermission(activity: AppCompatActivity) {
|
fun requestAppShortcutsPermission(activity: AppCompatActivity) {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package de.mm20.launcher2.ui.settings.unitconverter
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.search.UnitConverterSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -12,35 +12,17 @@ import org.koin.core.component.inject
|
|||||||
|
|
||||||
class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
|
class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val settings: UnitConverterSettings by inject()
|
||||||
|
|
||||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
|
val unitConverter = settings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setUnitConverter(unitConverter: Boolean) {
|
fun setUnitConverter(unitConverter: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setEnabled(unitConverter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setUnitConverterSearch(
|
|
||||||
it.unitConverterSearch.toBuilder()
|
|
||||||
.setEnabled(unitConverter)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val currencyConverter = dataStore.data.map { it.unitConverterSearch.currencies }
|
val currencyConverter = settings.currencies
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setCurrencyConverter(currencyConverter: Boolean) {
|
fun setCurrencyConverter(currencyConverter: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setCurrencies(currencyConverter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setUnitConverterSearch(
|
|
||||||
it.unitConverterSearch.toBuilder()
|
|
||||||
.setCurrencies(currencyConverter)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,7 +24,6 @@ import de.mm20.launcher2.ui.common.WeatherLocationSearchDialog
|
|||||||
import de.mm20.launcher2.ui.component.Banner
|
import de.mm20.launcher2.ui.component.Banner
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
import de.mm20.launcher2.ui.component.preferences.*
|
import de.mm20.launcher2.ui.component.preferences.*
|
||||||
import de.mm20.launcher2.weather.WeatherLocation
|
|
||||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
import de.mm20.launcher2.weather.WeatherProviderInfo
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@ -1,26 +1,18 @@
|
|||||||
package de.mm20.launcher2.ui.settings.weather
|
package de.mm20.launcher2.ui.settings.weather
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.plugins.PluginService
|
import de.mm20.launcher2.plugins.PluginService
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import de.mm20.launcher2.weather.WeatherLocation
|
|
||||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.flatMap
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
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
|
||||||
@ -30,29 +22,22 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
private val weatherSettings: WeatherSettings by inject()
|
private val weatherSettings: WeatherSettings by inject()
|
||||||
private val pluginService: PluginService by inject()
|
private val pluginService: PluginService by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
|
|
||||||
val availableProviders = repository.getProviders()
|
val availableProviders = repository.getProviders()
|
||||||
|
|
||||||
val weatherProvider = weatherSettings.providerId
|
val weatherProvider = weatherSettings.providerId
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setWeatherProvider(provider: String) {
|
fun setWeatherProvider(provider: String) {
|
||||||
weatherSettings.setProviderId(provider)
|
weatherSettings.setProvider(provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
val weatherProviderPluginState = weatherProvider.flatMapLatest {
|
val weatherProviderPluginState = weatherProvider.flatMapLatest {
|
||||||
it?.let { pluginService.getPluginWithState(it) } ?: flowOf(null)
|
it?.let { pluginService.getPluginWithState(it) } ?: flowOf(null)
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
val imperialUnits = weatherSettings.imperialUnits
|
||||||
fun setImperialUnits(imperialUnits: Boolean) {
|
fun setImperialUnits(imperialUnits: Boolean) {
|
||||||
viewModelScope.launch {
|
weatherSettings.setImperialUnits(imperialUnits)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWeather(it.weather.toBuilder().setImperialUnits(imperialUnits))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val autoLocation = weatherSettings.autoLocation
|
val autoLocation = weatherSettings.autoLocation
|
||||||
|
|||||||
@ -24,20 +24,10 @@ fun WikipediaSettingsScreen() {
|
|||||||
viewModel.setWikipedia(it)
|
viewModel.setWikipedia(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val images by viewModel.images.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_search_wikipedia_pictures),
|
|
||||||
summary = stringResource(R.string.preference_search_wikipedia_pictures_summary),
|
|
||||||
enabled = wikipedia == true,
|
|
||||||
value = images == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setImages(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val customUrl by viewModel.customUrl.collectAsState()
|
val customUrl by viewModel.customUrl.collectAsState()
|
||||||
TextPreference(
|
TextPreference(
|
||||||
title = stringResource(R.string.preference_wikipedia_customurl),
|
title = stringResource(R.string.preference_wikipedia_customurl),
|
||||||
value = customUrl,
|
value = customUrl ?: "",
|
||||||
placeholder = stringResource(id = R.string.wikipedia_url),
|
placeholder = stringResource(id = R.string.wikipedia_url),
|
||||||
summary = customUrl.takeIf { !it.isNullOrBlank() }
|
summary = customUrl.takeIf { !it.isNullOrBlank() }
|
||||||
?: stringResource(id = R.string.wikipedia_url),
|
?: stringResource(id = R.string.wikipedia_url),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package de.mm20.launcher2.ui.settings.wikipedia
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.search.WikipediaSearchSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -11,50 +11,17 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
|
class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val wikipediaSearchSettings: WikipediaSearchSettings by inject()
|
||||||
|
|
||||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
|
val wikipedia = wikipediaSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setWikipedia(wikipedia: Boolean) {
|
fun setWikipedia(wikipedia: Boolean) {
|
||||||
viewModelScope.launch {
|
wikipediaSearchSettings.setEnabled(wikipedia)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder()
|
|
||||||
.setEnabled(wikipedia)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val images = dataStore.data.map { it.wikipediaSearch.images }
|
val customUrl = wikipediaSearchSettings.customUrl
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setImages(images: Boolean) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder()
|
|
||||||
.setImages(images)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val customUrl = dataStore.data.map { it.wikipediaSearch.customUrl }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
|
||||||
fun setCustomUrl(customUrl: String) {
|
fun setCustomUrl(customUrl: String) {
|
||||||
viewModelScope.launch {
|
wikipediaSearchSettings.setCustomUrl(customUrl)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder()
|
|
||||||
.setCustomUrl(customUrl)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,23 +1,18 @@
|
|||||||
package de.mm20.launcher2.ui.theme
|
package de.mm20.launcher2.ui.theme
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.shape.CornerSize
|
import androidx.compose.foundation.shape.CornerSize
|
||||||
import androidx.compose.foundation.shape.CutCornerShape
|
import androidx.compose.foundation.shape.CutCornerShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.coerceAtMost
|
import androidx.compose.ui.unit.coerceAtMost
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.Font
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SurfaceShape
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.themes.DefaultThemeId
|
|
||||||
import de.mm20.launcher2.themes.Theme
|
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import de.mm20.launcher2.ui.theme.colorscheme.*
|
import de.mm20.launcher2.ui.theme.colorscheme.*
|
||||||
@ -26,7 +21,7 @@ import de.mm20.launcher2.ui.theme.typography.getDeviceDefaultTypography
|
|||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.koin.androidx.compose.inject
|
import org.koin.androidx.compose.inject
|
||||||
import java.util.UUID
|
import de.mm20.launcher2.preferences.ColorScheme as ColorSchemePref
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -35,33 +30,31 @@ fun LauncherTheme(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val dataStore: LauncherDataStore by inject()
|
val uiSettings: UiSettings by inject()
|
||||||
val themeRepository: ThemeRepository by inject()
|
val themeRepository: ThemeRepository by inject()
|
||||||
|
|
||||||
val theme by remember {
|
val theme by remember {
|
||||||
dataStore.data.map {
|
uiSettings.theme.flatMapLatest {
|
||||||
it.appearance.themeId.takeIf { it.isNotEmpty() }?.let {
|
|
||||||
UUID.fromString(it)
|
|
||||||
}
|
|
||||||
}.flatMapLatest {
|
|
||||||
themeRepository.getThemeOrDefault(it)
|
themeRepository.getThemeOrDefault(it)
|
||||||
}
|
}
|
||||||
}.collectAsState(themeRepository.getDefaultTheme())
|
}.collectAsState(themeRepository.getDefaultTheme())
|
||||||
|
|
||||||
val themePreference by remember { dataStore.data.map { it.appearance.theme } }.collectAsState(
|
val colorSchemePref by remember { uiSettings.colorScheme }.collectAsState(
|
||||||
AppearanceSettings.Theme.System
|
ColorSchemePref.System
|
||||||
)
|
)
|
||||||
val darkTheme =
|
val darkTheme =
|
||||||
themePreference == AppearanceSettings.Theme.Dark || themePreference == AppearanceSettings.Theme.System && isSystemInDarkTheme()
|
colorSchemePref == ColorSchemePref.Dark || colorSchemePref == ColorSchemePref.System && isSystemInDarkTheme()
|
||||||
|
|
||||||
val cornerRadius by remember {
|
val cornerRadius by remember {
|
||||||
dataStore.data.map { it.cards.radius.dp }
|
uiSettings.cardStyle.map {
|
||||||
|
it.cornerRadius.dp
|
||||||
|
}
|
||||||
}.collectAsState(8.dp)
|
}.collectAsState(8.dp)
|
||||||
|
|
||||||
val baseShape by remember {
|
val baseShape by remember {
|
||||||
dataStore.data.map {
|
uiSettings.cardStyle.map {
|
||||||
when (it.cards.shape) {
|
when (it.shape) {
|
||||||
Settings.CardSettings.Shape.Cut -> CutCornerShape(0f)
|
SurfaceShape.Cut -> CutCornerShape(0f)
|
||||||
else -> RoundedCornerShape(0f)
|
else -> RoundedCornerShape(0f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,8 +66,8 @@ fun LauncherTheme(
|
|||||||
lightColorSchemeOf(theme)
|
lightColorSchemeOf(theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
val font by remember { dataStore.data.map { it.appearance.font } }.collectAsState(
|
val font by remember { uiSettings.font }.collectAsState(
|
||||||
AppearanceSettings.Font.Outfit
|
Font.Outfit
|
||||||
)
|
)
|
||||||
|
|
||||||
val typography = remember(font) {
|
val typography = remember(font) {
|
||||||
@ -99,9 +92,9 @@ fun LauncherTheme(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTypography(context: Context, font: AppearanceSettings.Font?): Typography {
|
fun getTypography(context: Context, font: Font?): Typography {
|
||||||
return when (font) {
|
return when (font) {
|
||||||
AppearanceSettings.Font.SystemDefault -> getDeviceDefaultTypography(context)
|
Font.System -> getDeviceDefaultTypography(context)
|
||||||
else -> DefaultTypography
|
else -> DefaultTypography
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,7 +8,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.themes.CorePalette
|
import de.mm20.launcher2.themes.CorePalette
|
||||||
import de.mm20.launcher2.themes.DefaultDarkColorScheme
|
import de.mm20.launcher2.themes.DefaultDarkColorScheme
|
||||||
import de.mm20.launcher2.themes.DefaultLightColorScheme
|
import de.mm20.launcher2.themes.DefaultLightColorScheme
|
||||||
@ -102,7 +102,7 @@ fun systemCorePalette(): CorePalette<Int> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CustomColorScheme(colors: Settings.AppearanceSettings.CustomColors.Scheme): ColorScheme {
|
fun CustomColorScheme(colors: LegacySettings.AppearanceSettings.CustomColors.Scheme): ColorScheme {
|
||||||
return ColorScheme(
|
return ColorScheme(
|
||||||
primary = Color(colors.primary),
|
primary = Color(colors.primary),
|
||||||
onPrimary = Color(colors.onPrimary),
|
onPrimary = Color(colors.onPrimary),
|
||||||
|
|||||||
@ -4,6 +4,7 @@ plugins {
|
|||||||
alias(libs.plugins.android.library)
|
alias(libs.plugins.android.library)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.protobuf)
|
alias(libs.plugins.protobuf)
|
||||||
|
alias(libs.plugins.kotlin.plugin.serialization)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -57,6 +58,7 @@ protobuf {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.kotlin.stdlib)
|
implementation(libs.kotlin.stdlib)
|
||||||
|
implementation(libs.kotlinx.serialization.json)
|
||||||
implementation(libs.androidx.core)
|
implementation(libs.androidx.core)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
api(libs.androidx.datastore)
|
api(libs.androidx.datastore)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
-keepclassmembers class de.mm20.launcher2.preferences.Settings {
|
-keepclassmembers class de.mm20.launcher2.preferences.LegacySettings {
|
||||||
<fields>;
|
<fields>;
|
||||||
}
|
}
|
||||||
|
|
||||||
-keepclassmembers class de.mm20.launcher2.preferences.Settings$* {
|
-keepclassmembers class de.mm20.launcher2.preferences.LegacySettings$* {
|
||||||
<fields>;
|
<fields>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,48 +0,0 @@
|
|||||||
package de.mm20.launcher2.preferences
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.datastore.core.DataMigration
|
|
||||||
import androidx.datastore.core.DataStore
|
|
||||||
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
|
||||||
import androidx.datastore.dataStore
|
|
||||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
|
||||||
import de.mm20.launcher2.preferences.migrations.*
|
|
||||||
|
|
||||||
typealias LauncherDataStore = DataStore<Settings>
|
|
||||||
|
|
||||||
internal val Context.dataStore: LauncherDataStore by dataStore(
|
|
||||||
fileName = "settings.pb",
|
|
||||||
serializer = SettingsSerializer,
|
|
||||||
produceMigrations = {
|
|
||||||
getMigrations(it)
|
|
||||||
},
|
|
||||||
corruptionHandler = ReplaceFileCorruptionHandler {
|
|
||||||
CrashReporter.logException(it)
|
|
||||||
Settings.getDefaultInstance()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
internal const val SchemaVersion = 18
|
|
||||||
|
|
||||||
internal fun getMigrations(context: Context): List<DataMigration<Settings>> {
|
|
||||||
return listOf(
|
|
||||||
FactorySettingsMigration(context),
|
|
||||||
Migration_1_2(),
|
|
||||||
Migration_2_3(),
|
|
||||||
Migration_3_4(),
|
|
||||||
Migration_4_5(),
|
|
||||||
Migration_5_6(),
|
|
||||||
Migration_6_7(),
|
|
||||||
Migration_7_8(),
|
|
||||||
Migration_8_9(),
|
|
||||||
Migration_9_10(),
|
|
||||||
Migration_10_11(),
|
|
||||||
Migration_11_12(),
|
|
||||||
Migration_12_13(),
|
|
||||||
Migration_13_14(),
|
|
||||||
Migration_14_15(),
|
|
||||||
Migration_15_16(),
|
|
||||||
Migration_16_17(),
|
|
||||||
Migration_17_18(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -2,58 +2,58 @@ package de.mm20.launcher2.preferences
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
|
import de.mm20.launcher2.preferences.LegacySettings.SearchBarSettings.SearchBarColors
|
||||||
import de.mm20.launcher2.preferences.ktx.toSettingsColorsScheme
|
import de.mm20.launcher2.preferences.ktx.toSettingsColorsScheme
|
||||||
import scheme.Scheme
|
import scheme.Scheme
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
fun createFactorySettings(context: Context): Settings {
|
fun createFactorySettings(context: Context): LegacySettings {
|
||||||
return Settings.newBuilder()
|
return LegacySettings.newBuilder()
|
||||||
.setAppearance(
|
.setAppearance(
|
||||||
Settings.AppearanceSettings
|
LegacySettings.AppearanceSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setTheme(Settings.AppearanceSettings.Theme.System)
|
.setTheme(LegacySettings.AppearanceSettings.Theme.System)
|
||||||
.setDimWallpaper(false)
|
.setDimWallpaper(false)
|
||||||
.setBlurWallpaper(true)
|
.setBlurWallpaper(true)
|
||||||
.setBlurWallpaperRadius(32)
|
.setBlurWallpaperRadius(32)
|
||||||
.setThemeId(UUID(0L, 0L).toString())
|
.setThemeId(UUID(0L, 0L).toString())
|
||||||
.setFont(Settings.AppearanceSettings.Font.Outfit)
|
.setFont(LegacySettings.AppearanceSettings.Font.Outfit)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setWeather(
|
.setWeather(
|
||||||
Settings.WeatherSettings
|
LegacySettings.WeatherSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setProvider(Settings.WeatherSettings.WeatherProvider.MetNo)
|
.setProvider(LegacySettings.WeatherSettings.WeatherProvider.MetNo)
|
||||||
.setImperialUnits(context.resources.getBoolean(R.bool.default_imperialUnits))
|
.setImperialUnits(context.resources.getBoolean(R.bool.default_imperialUnits))
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setMusicWidget(
|
.setMusicWidget(
|
||||||
Settings.MusicWidgetSettings
|
LegacySettings.MusicWidgetSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setCalendarWidget(
|
.setCalendarWidget(
|
||||||
Settings.CalendarWidgetSettings
|
LegacySettings.CalendarWidgetSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setHideAlldayEvents(false)
|
.setHideAlldayEvents(false)
|
||||||
)
|
)
|
||||||
.setClockWidget(
|
.setClockWidget(
|
||||||
Settings.ClockWidgetSettings
|
LegacySettings.ClockWidgetSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setLayout(Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical)
|
.setLayout(LegacySettings.ClockWidgetSettings.ClockWidgetLayout.Vertical)
|
||||||
.setClockStyle(Settings.ClockWidgetSettings.ClockStyle.DigitalClock1)
|
.setClockStyle(LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1)
|
||||||
.setColor(Settings.ClockWidgetSettings.ClockWidgetColors.Auto)
|
.setColor(LegacySettings.ClockWidgetSettings.ClockWidgetColors.Auto)
|
||||||
.setAlarmPart(true)
|
.setAlarmPart(true)
|
||||||
.setBatteryPart(true)
|
.setBatteryPart(true)
|
||||||
.setMusicPart(true)
|
.setMusicPart(true)
|
||||||
.setDatePart(true)
|
.setDatePart(true)
|
||||||
.setFavoritesPart(false)
|
.setFavoritesPart(false)
|
||||||
.setFillHeight(true)
|
.setFillHeight(true)
|
||||||
.setAlignment(Settings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
.setAlignment(LegacySettings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setFavorites(
|
.setFavorites(
|
||||||
Settings.FavoritesSettings
|
LegacySettings.FavoritesSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
.setFrequentlyUsed(true)
|
.setFrequentlyUsed(true)
|
||||||
@ -61,7 +61,7 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setEditButton(true)
|
.setEditButton(true)
|
||||||
)
|
)
|
||||||
.setFileSearch(
|
.setFileSearch(
|
||||||
Settings.FilesSearchSettings
|
LegacySettings.FilesSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setLocalFiles(true)
|
.setLocalFiles(true)
|
||||||
.setNextcloud(false)
|
.setNextcloud(false)
|
||||||
@ -70,50 +70,50 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setNextcloud(false)
|
.setNextcloud(false)
|
||||||
)
|
)
|
||||||
.setContactsSearch(
|
.setContactsSearch(
|
||||||
Settings.ContactsSearchSettings
|
LegacySettings.ContactsSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setCalendarSearch(
|
.setCalendarSearch(
|
||||||
Settings.CalendarSearchSettings
|
LegacySettings.CalendarSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setAppShortcutSearch(
|
.setAppShortcutSearch(
|
||||||
Settings.AppShortcutSearchSettings
|
LegacySettings.AppShortcutSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setCalculatorSearch(
|
.setCalculatorSearch(
|
||||||
Settings.CalculatorSearchSettings
|
LegacySettings.CalculatorSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setUnitConverterSearch(
|
.setUnitConverterSearch(
|
||||||
Settings.UnitConverterSearchSettings
|
LegacySettings.UnitConverterSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
.setCurrencies(true)
|
.setCurrencies(true)
|
||||||
)
|
)
|
||||||
.setWikipediaSearch(
|
.setWikipediaSearch(
|
||||||
Settings.WikipediaSearchSettings
|
LegacySettings.WikipediaSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(false)
|
.setEnabled(false)
|
||||||
.setImages(false)
|
.setImages(false)
|
||||||
.setCustomUrl("")
|
.setCustomUrl("")
|
||||||
)
|
)
|
||||||
.setWebsiteSearch(
|
.setWebsiteSearch(
|
||||||
Settings.WebsiteSearchSettings
|
LegacySettings.WebsiteSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(false)
|
.setEnabled(false)
|
||||||
)
|
)
|
||||||
.setWebSearch(
|
.setWebSearch(
|
||||||
Settings.WebSearchSettings
|
LegacySettings.WebSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setBadges(
|
.setBadges(
|
||||||
Settings.BadgeSettings
|
LegacySettings.BadgeSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setNotifications(true)
|
.setNotifications(true)
|
||||||
.setCloudFiles(true)
|
.setCloudFiles(true)
|
||||||
@ -121,15 +121,15 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setSuspendedApps(true)
|
.setSuspendedApps(true)
|
||||||
)
|
)
|
||||||
.setGrid(
|
.setGrid(
|
||||||
Settings.GridSettings.newBuilder()
|
LegacySettings.GridSettings.newBuilder()
|
||||||
.setColumnCount(context.resources.getInteger(R.integer.config_columnCount))
|
.setColumnCount(context.resources.getInteger(R.integer.config_columnCount))
|
||||||
.setIconSize(48)
|
.setIconSize(48)
|
||||||
.setShowLabels(true)
|
.setShowLabels(true)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setSearchBar(
|
.setSearchBar(
|
||||||
Settings.SearchBarSettings.newBuilder()
|
LegacySettings.SearchBarSettings.newBuilder()
|
||||||
.setSearchBarStyle(Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
.setSearchBarStyle(LegacySettings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||||
.setAutoFocus(true)
|
.setAutoFocus(true)
|
||||||
.setLaunchOnEnter(true)
|
.setLaunchOnEnter(true)
|
||||||
.setColor(SearchBarColors.Auto)
|
.setColor(SearchBarColors.Auto)
|
||||||
@ -137,67 +137,67 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setIcons(
|
.setIcons(
|
||||||
Settings.IconSettings.newBuilder()
|
LegacySettings.IconSettings.newBuilder()
|
||||||
.setAdaptify(true)
|
.setAdaptify(true)
|
||||||
.setShape(Settings.IconSettings.IconShape.PlatformDefault)
|
.setShape(LegacySettings.IconSettings.IconShape.PlatformDefault)
|
||||||
.setThemedIcons(false)
|
.setThemedIcons(false)
|
||||||
.setIconPack("")
|
.setIconPack("")
|
||||||
.setIconPackThemed(true)
|
.setIconPackThemed(true)
|
||||||
)
|
)
|
||||||
.setEasterEgg(false)
|
.setEasterEgg(false)
|
||||||
.setSystemBars(
|
.setSystemBars(
|
||||||
Settings.SystemBarsSettings.newBuilder()
|
LegacySettings.SystemBarsSettings.newBuilder()
|
||||||
.setNavBarColor(Settings.SystemBarsSettings.SystemBarColors.Auto)
|
.setNavBarColor(LegacySettings.SystemBarsSettings.SystemBarColors.Auto)
|
||||||
.setStatusBarColor(Settings.SystemBarsSettings.SystemBarColors.Auto)
|
.setStatusBarColor(LegacySettings.SystemBarsSettings.SystemBarColors.Auto)
|
||||||
.setHideStatusBar(false)
|
.setHideStatusBar(false)
|
||||||
.setHideNavBar(false)
|
.setHideNavBar(false)
|
||||||
)
|
)
|
||||||
.setCards(
|
.setCards(
|
||||||
Settings.CardSettings.newBuilder()
|
LegacySettings.CardSettings.newBuilder()
|
||||||
.setBorderWidth(0)
|
.setBorderWidth(0)
|
||||||
.setRadius(12)
|
.setRadius(12)
|
||||||
.setOpacity(1f)
|
.setOpacity(1f)
|
||||||
)
|
)
|
||||||
.setWidgets(
|
.setWidgets(
|
||||||
Settings.WidgetSettings.newBuilder()
|
LegacySettings.WidgetSettings.newBuilder()
|
||||||
.setEditButton(true)
|
.setEditButton(true)
|
||||||
)
|
)
|
||||||
.setLayout(
|
.setLayout(
|
||||||
Settings.LayoutSettings.newBuilder()
|
LegacySettings.LayoutSettings.newBuilder()
|
||||||
.setBaseLayout(Settings.LayoutSettings.Layout.PullDown)
|
.setBaseLayout(LegacySettings.LayoutSettings.Layout.PullDown)
|
||||||
.setBottomSearchBar(false)
|
.setBottomSearchBar(false)
|
||||||
.setReverseSearchResults(false)
|
.setReverseSearchResults(false)
|
||||||
.setFixedRotation(false)
|
.setFixedRotation(false)
|
||||||
)
|
)
|
||||||
.setGestures(
|
.setGestures(
|
||||||
Settings.GestureSettings.newBuilder()
|
LegacySettings.GestureSettings.newBuilder()
|
||||||
.setDoubleTap(
|
.setDoubleTap(
|
||||||
if (isAtLeastApiLevel(28)) {
|
if (isAtLeastApiLevel(28)) {
|
||||||
Settings.GestureSettings.GestureAction.LockScreen
|
LegacySettings.GestureSettings.GestureAction.LockScreen
|
||||||
} else {
|
} else {
|
||||||
Settings.GestureSettings.GestureAction.None
|
LegacySettings.GestureSettings.GestureAction.None
|
||||||
})
|
})
|
||||||
.setLongPress(Settings.GestureSettings.GestureAction.None)
|
.setLongPress(LegacySettings.GestureSettings.GestureAction.None)
|
||||||
.setSwipeDown(Settings.GestureSettings.GestureAction.OpenNotificationDrawer)
|
.setSwipeDown(LegacySettings.GestureSettings.GestureAction.OpenNotificationDrawer)
|
||||||
.setSwipeLeft(Settings.GestureSettings.GestureAction.None)
|
.setSwipeLeft(LegacySettings.GestureSettings.GestureAction.None)
|
||||||
.setSwipeRight(Settings.GestureSettings.GestureAction.None)
|
.setSwipeRight(LegacySettings.GestureSettings.GestureAction.None)
|
||||||
)
|
)
|
||||||
.setResultOrdering(
|
.setResultOrdering(
|
||||||
Settings.SearchResultOrderingSettings.newBuilder()
|
LegacySettings.SearchResultOrderingSettings.newBuilder()
|
||||||
.setOrdering(Settings.SearchResultOrderingSettings.Ordering.Weighted)
|
.setOrdering(LegacySettings.SearchResultOrderingSettings.Ordering.Weighted)
|
||||||
.setWeightFactor(Settings.SearchResultOrderingSettings.WeightFactor.Default)
|
.setWeightFactor(LegacySettings.SearchResultOrderingSettings.WeightFactor.Default)
|
||||||
)
|
)
|
||||||
.setAnimations(
|
.setAnimations(
|
||||||
Settings.AnimationSettings.newBuilder()
|
LegacySettings.AnimationSettings.newBuilder()
|
||||||
.setCharging(true)
|
.setCharging(true)
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DefaultCustomColorsBase: Settings.AppearanceSettings.CustomColors.BaseColors
|
internal val DefaultCustomColorsBase: LegacySettings.AppearanceSettings.CustomColors.BaseColors
|
||||||
get() {
|
get() {
|
||||||
val scheme = Scheme.light(0xFFACE330.toInt())
|
val scheme = Scheme.light(0xFFACE330.toInt())
|
||||||
return Settings.AppearanceSettings.CustomColors.BaseColors.newBuilder()
|
return LegacySettings.AppearanceSettings.CustomColors.BaseColors.newBuilder()
|
||||||
.setAccent1(scheme.primary)
|
.setAccent1(scheme.primary)
|
||||||
.setAccent2(scheme.secondary)
|
.setAccent2(scheme.secondary)
|
||||||
.setAccent3(scheme.tertiary)
|
.setAccent3(scheme.tertiary)
|
||||||
@ -207,13 +207,13 @@ internal val DefaultCustomColorsBase: Settings.AppearanceSettings.CustomColors.B
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DefaultLightCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme
|
internal val DefaultLightCustomColorScheme: LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||||
get() {
|
get() {
|
||||||
val scheme = Scheme.light(0xFFACE330.toInt())
|
val scheme = Scheme.light(0xFFACE330.toInt())
|
||||||
return scheme.toSettingsColorsScheme()
|
return scheme.toSettingsColorsScheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DefaultDarkCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme
|
internal val DefaultDarkCustomColorScheme: LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||||
get() {
|
get() {
|
||||||
val scheme = Scheme.dark(0xFFACE330.toInt())
|
val scheme = Scheme.dark(0xFFACE330.toInt())
|
||||||
return scheme.toSettingsColorsScheme()
|
return scheme.toSettingsColorsScheme()
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import java.io.File
|
|||||||
|
|
||||||
internal class LauncherStoreBackupComponent(
|
internal class LauncherStoreBackupComponent(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val dataStore: LauncherDataStore
|
private val dataStore: LegacyDataStore
|
||||||
): Backupable {
|
): Backupable {
|
||||||
override suspend fun backup(toDir: File) {
|
override suspend fun backup(toDir: File) {
|
||||||
dataStore.export(toDir)
|
dataStore.export(toDir)
|
||||||
@ -25,10 +25,10 @@ internal class LauncherStoreBackupComponent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun LauncherDataStore.export(toDir: File) {
|
suspend fun LegacyDataStore.export(toDir: File) {
|
||||||
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
val backupDataStore = DataStoreFactory.create(
|
val backupDataStore = DataStoreFactory.create(
|
||||||
serializer = SettingsSerializer,
|
serializer = LegacySettingsSerializer,
|
||||||
produceFile = {
|
produceFile = {
|
||||||
File(toDir, "settings")
|
File(toDir, "settings")
|
||||||
},
|
},
|
||||||
@ -42,14 +42,14 @@ suspend fun LauncherDataStore.export(toDir: File) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
suspend fun LauncherDataStore.import(context: Context, fromDir: File) {
|
suspend fun LegacyDataStore.import(context: Context, fromDir: File) {
|
||||||
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
val backupDataStore = DataStoreFactory.create(
|
val backupDataStore = DataStoreFactory.create(
|
||||||
serializer = SettingsSerializer,
|
serializer = LegacySettingsSerializer,
|
||||||
migrations = getMigrations(context),
|
migrations = getMigrations(context),
|
||||||
corruptionHandler = ReplaceFileCorruptionHandler {
|
corruptionHandler = ReplaceFileCorruptionHandler {
|
||||||
CrashReporter.logException(it)
|
CrashReporter.logException(it)
|
||||||
Settings.getDefaultInstance()
|
LegacySettings.getDefaultInstance()
|
||||||
},
|
},
|
||||||
produceFile = {
|
produceFile = {
|
||||||
File(fromDir, "settings")
|
File(fromDir, "settings")
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import de.mm20.launcher2.preferences.migrations.Migration1
|
||||||
|
import de.mm20.launcher2.settings.BaseSettings
|
||||||
|
|
||||||
|
internal class LauncherDataStore(
|
||||||
|
private val context: Context,
|
||||||
|
legacyDataStore: LegacyDataStore,
|
||||||
|
): BaseSettings<LauncherSettingsData>(
|
||||||
|
context,
|
||||||
|
fileName = "settings.json",
|
||||||
|
serializer = LauncherSettingsDataSerializer,
|
||||||
|
migrations = listOf(Migration1(legacyDataStore)),
|
||||||
|
) {
|
||||||
|
|
||||||
|
val data
|
||||||
|
get() = context.dataStore.data
|
||||||
|
|
||||||
|
fun update(block: (LauncherSettingsData) -> LauncherSettingsData) {
|
||||||
|
updateData(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,332 @@
|
|||||||
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LauncherSettingsData(
|
||||||
|
val schemaVersion: Int = 1,
|
||||||
|
|
||||||
|
val uiColorScheme: ColorScheme = ColorScheme.System,
|
||||||
|
val uiTheme: ThemeDescriptor = ThemeDescriptor.Default,
|
||||||
|
val uiFont: Font = Font.Outfit,
|
||||||
|
val uiBaseLayout: BaseLayout = BaseLayout.PullDown,
|
||||||
|
val uiOrientation: ScreenOrientation = ScreenOrientation.Auto,
|
||||||
|
|
||||||
|
val wallpaperDim: Boolean = false,
|
||||||
|
val wallpaperBlur: Boolean = true,
|
||||||
|
val wallpaperBlurRadius: Int = 32,
|
||||||
|
|
||||||
|
val mediaAllowList: Set<String> = emptySet(),
|
||||||
|
val mediaDenyList: Set<String> = emptySet(),
|
||||||
|
|
||||||
|
val clockWidgetCompact: Boolean = false,
|
||||||
|
val clockWidgetStyle: ClockWidgetStyle = ClockWidgetStyle.Digital1(),
|
||||||
|
val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto,
|
||||||
|
val clockWidgetAlarmPart: Boolean = true,
|
||||||
|
val clockWidgetBatteryPart: Boolean = true,
|
||||||
|
val clockWidgetMusicPart: Boolean = true,
|
||||||
|
val clockWidgetDatePart: Boolean = true,
|
||||||
|
val clockWidgetFillHeight: Boolean = true,
|
||||||
|
val clockWidgetAlignment: ClockWidgetAlignment = ClockWidgetAlignment.Bottom,
|
||||||
|
|
||||||
|
val homeScreenDock: Boolean = false,
|
||||||
|
|
||||||
|
val favoritesEnabled: Boolean = true,
|
||||||
|
val favoritesFrequentlyUsed: Boolean = true,
|
||||||
|
val favoritesFrequentlyUsedRows: Int = 1,
|
||||||
|
val favoritesEditButton: Boolean = true,
|
||||||
|
|
||||||
|
val fileSearchProviders: Set<String> = setOf("local"),
|
||||||
|
|
||||||
|
val contactSearchEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val calendarSearchEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val shortcutSearchEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val calculatorEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val unitConverterEnabled: Boolean = true,
|
||||||
|
val unitConverterCurrencies: Boolean = true,
|
||||||
|
|
||||||
|
val wikipediaSearchEnabled: Boolean = false,
|
||||||
|
val wikipediaSearchImages: Boolean = false,
|
||||||
|
val wikipediaCustomUrl: String? = null,
|
||||||
|
|
||||||
|
val websiteSearchEnabled: Boolean = false,
|
||||||
|
|
||||||
|
val badgesNotifications: Boolean = true,
|
||||||
|
val badgesSuspendedApps: Boolean = true,
|
||||||
|
val badgesCloudFiles: Boolean = true,
|
||||||
|
val badgesShortcuts: Boolean = true,
|
||||||
|
val badgesPlugins: Boolean = true,
|
||||||
|
|
||||||
|
val gridColumnCount: Int = 5,
|
||||||
|
val gridIconSize: Int = 48,
|
||||||
|
val gridLabels: Boolean = true,
|
||||||
|
|
||||||
|
val searchBarStyle: SearchBarStyle = SearchBarStyle.Transparent,
|
||||||
|
val searchBarColors: SearchBarColors = SearchBarColors.Auto,
|
||||||
|
val searchBarKeyboard: Boolean = true,
|
||||||
|
val searchLaunchOnEnter: Boolean = true,
|
||||||
|
val searchBarBottom: Boolean = false,
|
||||||
|
val searchBarFixed: Boolean = false,
|
||||||
|
|
||||||
|
val searchResultsReversed: Boolean = false,
|
||||||
|
val searchResultOrder: SearchResultOrder = SearchResultOrder.Weighted,
|
||||||
|
|
||||||
|
val rankingWeightFactor: WeightFactor = WeightFactor.Default,
|
||||||
|
|
||||||
|
val hiddenItemsShowButton: Boolean = true,
|
||||||
|
|
||||||
|
val iconsShape: IconShape = IconShape.PlatformDefault,
|
||||||
|
val iconsAdaptify: Boolean = false,
|
||||||
|
val iconsThemed: Boolean = false,
|
||||||
|
val iconsForceThemed: Boolean = false,
|
||||||
|
val iconsPack: String? = null,
|
||||||
|
val iconsPackThemed: Boolean = false,
|
||||||
|
|
||||||
|
val easterEgg: Boolean = false,
|
||||||
|
|
||||||
|
val systemBarsHideStatus: Boolean = false,
|
||||||
|
val systemBarsHideNav: Boolean = false,
|
||||||
|
val systemBarsStatusColors: SystemBarColors = SystemBarColors.Auto,
|
||||||
|
val systemBarsNavColors: SystemBarColors = SystemBarColors.Auto,
|
||||||
|
|
||||||
|
val surfacesOpacity: Float = 1f,
|
||||||
|
val surfacesRadius: Int = 24,
|
||||||
|
val surfacesBorderWidth: Int = 0,
|
||||||
|
val surfacesShape: SurfaceShape = SurfaceShape.Rounded,
|
||||||
|
|
||||||
|
val widgetsEditButton: Boolean = true,
|
||||||
|
|
||||||
|
val gesturesSwipeDown: GestureAction = GestureAction.Notifications,
|
||||||
|
val gesturesSwipeLeft: GestureAction = GestureAction.NoAction,
|
||||||
|
val gesturesSwipeRight: GestureAction = GestureAction.NoAction,
|
||||||
|
val gesturesDoubleTap: GestureAction = GestureAction.ScreenLock,
|
||||||
|
val gesturesLongPress: GestureAction = GestureAction.NoAction,
|
||||||
|
val gesturesHomeButton: GestureAction = GestureAction.NoAction,
|
||||||
|
|
||||||
|
val animationsCharging: Boolean = true,
|
||||||
|
|
||||||
|
val stateTagsMultiline: Boolean = false,
|
||||||
|
|
||||||
|
val weatherProvider: String = "metno",
|
||||||
|
val weatherAutoLocation: Boolean = true,
|
||||||
|
val weatherLocation: LatLon? = null,
|
||||||
|
val weatherLocationName: String? = null,
|
||||||
|
val weatherLastLocation: LatLon? = null,
|
||||||
|
val weatherLastUpdate: Long = 0L,
|
||||||
|
val weatherProviderSettings: Map<String, ProviderSettings> = emptyMap(),
|
||||||
|
val weatherImperialUnits: Boolean = false,
|
||||||
|
|
||||||
|
) {
|
||||||
|
constructor(
|
||||||
|
context: Context,
|
||||||
|
) : this(
|
||||||
|
weatherImperialUnits = context.resources.getBoolean(R.bool.default_imperialUnits),
|
||||||
|
gridColumnCount = context.resources.getInteger(R.integer.config_columnCount),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ColorScheme {
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class Font {
|
||||||
|
Outfit,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface ThemeDescriptor {
|
||||||
|
@Serializable
|
||||||
|
@SerialName("default")
|
||||||
|
data object Default : ThemeDescriptor
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("bw")
|
||||||
|
data object BlackAndWhite : ThemeDescriptor
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("custom")
|
||||||
|
data class Custom(
|
||||||
|
val id: String,
|
||||||
|
) : ThemeDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface ClockWidgetStyle {
|
||||||
|
@Serializable
|
||||||
|
@SerialName("digital1")
|
||||||
|
data class Digital1(
|
||||||
|
val outlined: Boolean = false,
|
||||||
|
val variant: Variant = Variant.Default,
|
||||||
|
) : ClockWidgetStyle {
|
||||||
|
@Serializable
|
||||||
|
enum class Variant {
|
||||||
|
Default,
|
||||||
|
MDY,
|
||||||
|
OnePlus,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("digital2")
|
||||||
|
data object Digital2 : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("orbit")
|
||||||
|
data object Orbit : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("analog")
|
||||||
|
data object Analog : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("binary")
|
||||||
|
data object Binary : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("empty")
|
||||||
|
data object Empty : ClockWidgetStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ClockWidgetColors {
|
||||||
|
Auto,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ClockWidgetAlignment {
|
||||||
|
Top,
|
||||||
|
Center,
|
||||||
|
Bottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SearchBarStyle {
|
||||||
|
Transparent,
|
||||||
|
Solid,
|
||||||
|
Hidden,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SearchBarColors {
|
||||||
|
Auto,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class IconShape {
|
||||||
|
PlatformDefault,
|
||||||
|
Circle,
|
||||||
|
Square,
|
||||||
|
RoundedSquare,
|
||||||
|
Triangle,
|
||||||
|
Squircle,
|
||||||
|
Hexagon,
|
||||||
|
Pentagon,
|
||||||
|
Teardrop,
|
||||||
|
Pebble,
|
||||||
|
EasterEgg,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SystemBarColors {
|
||||||
|
Auto,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SurfaceShape {
|
||||||
|
Rounded,
|
||||||
|
Cut,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class BaseLayout {
|
||||||
|
PullDown,
|
||||||
|
Pager,
|
||||||
|
PagerReversed,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ScreenOrientation {
|
||||||
|
Auto,
|
||||||
|
Portrait,
|
||||||
|
Landscape,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface GestureAction {
|
||||||
|
@Serializable
|
||||||
|
@SerialName("no_action")
|
||||||
|
data object NoAction : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("notifications")
|
||||||
|
data object Notifications : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("quick_settings")
|
||||||
|
data object QuickSettings : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("screen_lock")
|
||||||
|
data object ScreenLock : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("search")
|
||||||
|
data object Search : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("power_menu")
|
||||||
|
data object PowerMenu : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("recents")
|
||||||
|
data object Recents : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("launch_searchable")
|
||||||
|
data class Launch(val key: String?) : GestureAction
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SearchResultOrder {
|
||||||
|
Weighted,
|
||||||
|
Alphabetical,
|
||||||
|
LaunchCount,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class WeightFactor {
|
||||||
|
Default,
|
||||||
|
Low,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LatLon(
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ProviderSettings(
|
||||||
|
val locationId: String? = null,
|
||||||
|
val locationName: String? = null,
|
||||||
|
)
|
||||||
@ -1,8 +1,7 @@
|
|||||||
package de.mm20.launcher2.files.settings
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
import androidx.datastore.core.CorruptionException
|
import androidx.datastore.core.CorruptionException
|
||||||
import androidx.datastore.core.Serializer
|
import androidx.datastore.core.Serializer
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
import kotlinx.serialization.json.decodeFromStream
|
||||||
@ -11,27 +10,17 @@ import java.io.IOException
|
|||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@Serializable
|
internal object LauncherSettingsDataSerializer : Serializer<LauncherSettingsData> {
|
||||||
data class FileSearchSettingsData(
|
|
||||||
val localFiles: Boolean = true,
|
|
||||||
val gdriveFiles: Boolean = false,
|
|
||||||
val nextcloudFiles: Boolean = false,
|
|
||||||
val owncloudFiles: Boolean = false,
|
|
||||||
val plugins: Set<String> = emptySet(),
|
|
||||||
val schemaVersion: Int = 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
internal object FileSearchSettingsDataSerializer : Serializer<FileSearchSettingsData> {
|
|
||||||
|
|
||||||
internal val json = Json {
|
internal val json = Json {
|
||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
encodeDefaults = true
|
encodeDefaults = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override val defaultValue: FileSearchSettingsData
|
override val defaultValue: LauncherSettingsData
|
||||||
get() = FileSearchSettingsData(schemaVersion = 0)
|
get() = LauncherSettingsData(schemaVersion = 0)
|
||||||
|
|
||||||
override suspend fun readFrom(input: InputStream): FileSearchSettingsData {
|
override suspend fun readFrom(input: InputStream): LauncherSettingsData {
|
||||||
try {
|
try {
|
||||||
return json.decodeFromStream(input)
|
return json.decodeFromStream(input)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
@ -43,7 +32,7 @@ internal object FileSearchSettingsDataSerializer : Serializer<FileSearchSettings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun writeTo(t: FileSearchSettingsData, output: OutputStream) {
|
override suspend fun writeTo(t: LauncherSettingsData, output: OutputStream) {
|
||||||
json.encodeToStream(t, output)
|
json.encodeToStream(t, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.CorruptionException
|
||||||
|
import androidx.datastore.core.DataMigration
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.core.Serializer
|
||||||
|
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
||||||
|
import androidx.datastore.dataStore
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException
|
||||||
|
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||||
|
import de.mm20.launcher2.preferences.migrations.*
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
internal typealias LegacyDataStore = DataStore<LegacySettings>
|
||||||
|
|
||||||
|
internal val Context.legacyDataStore: LegacyDataStore by dataStore(
|
||||||
|
fileName = "settings.pb",
|
||||||
|
serializer = LegacySettingsSerializer,
|
||||||
|
produceMigrations = {
|
||||||
|
getMigrations(it)
|
||||||
|
},
|
||||||
|
corruptionHandler = ReplaceFileCorruptionHandler {
|
||||||
|
CrashReporter.logException(it)
|
||||||
|
LegacySettings.getDefaultInstance()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
internal const val SchemaVersion = 18
|
||||||
|
|
||||||
|
internal fun getMigrations(context: Context): List<DataMigration<LegacySettings>> {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
object LegacySettingsSerializer : Serializer<LegacySettings> {
|
||||||
|
override val defaultValue: LegacySettings = LegacySettings.getDefaultInstance()
|
||||||
|
|
||||||
|
override suspend fun readFrom(input: InputStream): LegacySettings {
|
||||||
|
try {
|
||||||
|
return LegacySettings.parseFrom(input)
|
||||||
|
} catch (e: InvalidProtocolBufferException) {
|
||||||
|
throw CorruptionException("Cannot read proto.", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun writeTo(t: LegacySettings, output: OutputStream) {
|
||||||
|
t.writeTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,51 @@
|
|||||||
package de.mm20.launcher2.preferences
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
import de.mm20.launcher2.backup.Backupable
|
import de.mm20.launcher2.backup.Backupable
|
||||||
|
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.media.MediaSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.CalculatorSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.CalendarSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.RankingSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.UnitConverterSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WebsiteSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WikipediaSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.BadgeSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.IconSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiState
|
||||||
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.core.qualifier.named
|
import org.koin.core.qualifier.named
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val preferencesModule = module {
|
val preferencesModule = module {
|
||||||
single { androidContext().dataStore }
|
single { androidContext().legacyDataStore }
|
||||||
factory<Backupable>(named<LauncherDataStore>()) { LauncherStoreBackupComponent(androidContext(), get()) }
|
factory<Backupable>(named<LegacyDataStore>()) { LauncherStoreBackupComponent(androidContext(), get()) }
|
||||||
|
single { LauncherDataStore(androidContext(), get()) }
|
||||||
|
factory<Backupable>(named<LauncherDataStore>()) { get<LauncherDataStore>() }
|
||||||
|
factory { MediaSettings(get()) }
|
||||||
|
factory { ContactSearchSettings(get()) }
|
||||||
|
factory { FileSearchSettings(get()) }
|
||||||
|
factory { UnitConverterSettings(get()) }
|
||||||
|
factory { BadgeSettings(get()) }
|
||||||
|
factory { UiSettings(get()) }
|
||||||
|
factory { ShortcutSearchSettings(get()) }
|
||||||
|
factory { FavoritesSettings(get()) }
|
||||||
|
factory { WikipediaSearchSettings(get()) }
|
||||||
|
factory { IconSettings(get()) }
|
||||||
|
factory { RankingSettings(get()) }
|
||||||
|
factory { CalendarSearchSettings(get()) }
|
||||||
|
factory { WebsiteSearchSettings(get()) }
|
||||||
|
factory { UiState(get()) }
|
||||||
|
factory { SearchUiSettings(get()) }
|
||||||
|
factory { WeatherSettings(get()) }
|
||||||
|
factory { GestureSettings(get()) }
|
||||||
|
factory { CalculatorSearchSettings(get()) }
|
||||||
|
factory { ClockWidgetSettings(get()) }
|
||||||
}
|
}
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package de.mm20.launcher2.preferences
|
|
||||||
|
|
||||||
import androidx.datastore.core.CorruptionException
|
|
||||||
import androidx.datastore.core.Serializer
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
|
|
||||||
|
|
||||||
object SettingsSerializer : Serializer<Settings> {
|
|
||||||
override val defaultValue: Settings = Settings.getDefaultInstance()
|
|
||||||
|
|
||||||
override suspend fun readFrom(input: InputStream): Settings {
|
|
||||||
try {
|
|
||||||
return Settings.parseFrom(input)
|
|
||||||
} catch (e: InvalidProtocolBufferException) {
|
|
||||||
throw CorruptionException("Cannot read proto.", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun writeTo(t: Settings, output: OutputStream) {
|
|
||||||
t.writeTo(output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,11 @@
|
|||||||
package de.mm20.launcher2.preferences.ktx
|
package de.mm20.launcher2.preferences.ktx
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import scheme.Scheme
|
import scheme.Scheme
|
||||||
|
|
||||||
fun Scheme.toSettingsColorsScheme(): Settings.AppearanceSettings.CustomColors.Scheme {
|
fun Scheme.toSettingsColorsScheme(): LegacySettings.AppearanceSettings.CustomColors.Scheme {
|
||||||
val scheme = this
|
val scheme = this
|
||||||
return Settings.AppearanceSettings.CustomColors.Scheme.newBuilder()
|
return LegacySettings.AppearanceSettings.CustomColors.Scheme.newBuilder()
|
||||||
.setPrimary(scheme.primary)
|
.setPrimary(scheme.primary)
|
||||||
.setSurfaceTint(scheme.primary)
|
.setSurfaceTint(scheme.primary)
|
||||||
.setOnPrimary(scheme.onPrimary)
|
.setOnPrimary(scheme.onPrimary)
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
package de.mm20.launcher2.preferences.media
|
||||||
|
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
data class MediaSettingsData(
|
||||||
|
val allowList: Set<String>,
|
||||||
|
val denyList: Set<String>,
|
||||||
|
)
|
||||||
|
|
||||||
|
class MediaSettings internal constructor(
|
||||||
|
private val launcherDataStore: LauncherDataStore
|
||||||
|
) : Flow<MediaSettingsData> by (launcherDataStore.data.map {
|
||||||
|
MediaSettingsData(
|
||||||
|
it.mediaAllowList,
|
||||||
|
it.mediaDenyList
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
val allowList
|
||||||
|
get() = launcherDataStore.data.map { it.mediaAllowList }
|
||||||
|
|
||||||
|
fun setLists(allowList: Set<String>, denyList: Set<String>) {
|
||||||
|
launcherDataStore.update {
|
||||||
|
it.copy(mediaAllowList = allowList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val denyList
|
||||||
|
get() = launcherDataStore.data.map { it.mediaDenyList }
|
||||||
|
}
|
||||||
@ -4,22 +4,22 @@ import android.content.Context
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.datastore.core.DataMigration
|
import androidx.datastore.core.DataMigration
|
||||||
import de.mm20.launcher2.preferences.SchemaVersion
|
import de.mm20.launcher2.preferences.SchemaVersion
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.createFactorySettings
|
import de.mm20.launcher2.preferences.createFactorySettings
|
||||||
|
|
||||||
class FactorySettingsMigration(private val context: Context): DataMigration<Settings> {
|
class FactorySettingsMigration(private val context: Context): DataMigration<LegacySettings> {
|
||||||
override suspend fun cleanUp() {
|
override suspend fun cleanUp() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun migrate(currentData: Settings): Settings {
|
override suspend fun migrate(currentData: LegacySettings): LegacySettings {
|
||||||
Log.d("MM20", "Initializing user settings…")
|
Log.d("MM20", "Initializing user settings…")
|
||||||
Log.d("MM20", "Done")
|
Log.d("MM20", "Done")
|
||||||
val defaults = createFactorySettings(context)
|
val defaults = createFactorySettings(context)
|
||||||
return defaults.toBuilder().setVersion(SchemaVersion).build()
|
return defaults.toBuilder().setVersion(SchemaVersion).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun shouldMigrate(currentData: Settings): Boolean {
|
override suspend fun shouldMigrate(currentData: LegacySettings): Boolean {
|
||||||
return currentData.version == 0
|
return currentData.version == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,254 @@
|
|||||||
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
|
import androidx.datastore.core.DataMigration
|
||||||
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
|
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
||||||
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
|
import de.mm20.launcher2.preferences.ColorScheme
|
||||||
|
import de.mm20.launcher2.preferences.Font
|
||||||
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
|
import de.mm20.launcher2.preferences.LauncherSettingsData
|
||||||
|
import de.mm20.launcher2.preferences.LegacyDataStore
|
||||||
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.ScreenOrientation
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
|
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||||
|
import de.mm20.launcher2.preferences.SurfaceShape
|
||||||
|
import de.mm20.launcher2.preferences.SystemBarColors
|
||||||
|
import de.mm20.launcher2.preferences.ThemeDescriptor
|
||||||
|
import de.mm20.launcher2.preferences.WeightFactor
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
class Migration1(
|
||||||
|
private val legacyDataStore: LegacyDataStore,
|
||||||
|
) : DataMigration<LauncherSettingsData> {
|
||||||
|
override suspend fun cleanUp() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun shouldMigrate(currentData: LauncherSettingsData): Boolean {
|
||||||
|
return legacyDataStore.data.first().version > 0 && currentData.schemaVersion < 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun migrate(currentData: LauncherSettingsData): LauncherSettingsData {
|
||||||
|
val legacyData = legacyDataStore.data.first()
|
||||||
|
return currentData.copy(
|
||||||
|
schemaVersion = 1,
|
||||||
|
uiBaseLayout = when (legacyData.layout.baseLayout) {
|
||||||
|
LegacySettings.LayoutSettings.Layout.Pager -> BaseLayout.PullDown
|
||||||
|
LegacySettings.LayoutSettings.Layout.PagerReversed -> BaseLayout.PagerReversed
|
||||||
|
else -> BaseLayout.PullDown
|
||||||
|
},
|
||||||
|
gridColumnCount = legacyData.grid.columnCount,
|
||||||
|
animationsCharging = legacyData.animations.charging,
|
||||||
|
badgesCloudFiles = legacyData.badges.cloudFiles,
|
||||||
|
badgesNotifications = legacyData.badges.notifications,
|
||||||
|
badgesShortcuts = legacyData.badges.shortcuts,
|
||||||
|
badgesSuspendedApps = legacyData.badges.suspendedApps,
|
||||||
|
calculatorEnabled = legacyData.calculatorSearch.enabled,
|
||||||
|
calendarSearchEnabled = legacyData.calendarSearch.enabled,
|
||||||
|
clockWidgetAlarmPart = legacyData.clockWidget.alarmPart,
|
||||||
|
clockWidgetBatteryPart = legacyData.clockWidget.batteryPart,
|
||||||
|
clockWidgetDatePart = legacyData.clockWidget.datePart,
|
||||||
|
clockWidgetColors = when (legacyData.clockWidget.color) {
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockWidgetColors.Light -> ClockWidgetColors.Light
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockWidgetColors.Dark -> ClockWidgetColors.Dark
|
||||||
|
else -> ClockWidgetColors.Auto
|
||||||
|
},
|
||||||
|
clockWidgetAlignment = when (legacyData.clockWidget.alignment) {
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockWidgetAlignment.Top -> ClockWidgetAlignment.Top
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockWidgetAlignment.Center -> ClockWidgetAlignment.Center
|
||||||
|
else -> ClockWidgetAlignment.Bottom
|
||||||
|
},
|
||||||
|
homeScreenDock = legacyData.clockWidget.favoritesPart,
|
||||||
|
clockWidgetFillHeight = legacyData.clockWidget.fillHeight,
|
||||||
|
clockWidgetCompact = legacyData.clockWidget.layout == LegacySettings.ClockWidgetSettings.ClockWidgetLayout.Horizontal,
|
||||||
|
clockWidgetMusicPart = legacyData.clockWidget.musicPart,
|
||||||
|
clockWidgetStyle = when (legacyData.clockWidget.clockStyle) {
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1 -> ClockWidgetStyle.Digital1()
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock2 -> ClockWidgetStyle.Digital2
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.OrbitClock -> ClockWidgetStyle.Orbit
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.BinaryClock -> ClockWidgetStyle.Binary
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.AnalogClock -> ClockWidgetStyle.Analog
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.EmptyClock -> ClockWidgetStyle.Empty
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1_MDY -> ClockWidgetStyle.Digital1(
|
||||||
|
variant = ClockWidgetStyle.Digital1.Variant.MDY
|
||||||
|
)
|
||||||
|
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1_Outlined -> ClockWidgetStyle.Digital1(
|
||||||
|
outlined = true
|
||||||
|
)
|
||||||
|
|
||||||
|
LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1_OnePlus -> ClockWidgetStyle.Digital1(
|
||||||
|
variant = ClockWidgetStyle.Digital1.Variant.OnePlus
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> ClockWidgetStyle.Digital1()
|
||||||
|
},
|
||||||
|
contactSearchEnabled = legacyData.contactsSearch.enabled,
|
||||||
|
easterEgg = legacyData.easterEgg,
|
||||||
|
favoritesEditButton = legacyData.favorites.editButton,
|
||||||
|
favoritesEnabled = legacyData.favorites.enabled,
|
||||||
|
favoritesFrequentlyUsed = legacyData.favorites.frequentlyUsed,
|
||||||
|
favoritesFrequentlyUsedRows = legacyData.favorites.frequentlyUsedRows,
|
||||||
|
rankingWeightFactor = when (legacyData.resultOrdering.weightFactor) {
|
||||||
|
LegacySettings.SearchResultOrderingSettings.WeightFactor.Low -> WeightFactor.Low
|
||||||
|
LegacySettings.SearchResultOrderingSettings.WeightFactor.High -> WeightFactor.High
|
||||||
|
else -> WeightFactor.Default
|
||||||
|
},
|
||||||
|
fileSearchProviders = buildSet {
|
||||||
|
if (legacyData.fileSearch.localFiles) add("local")
|
||||||
|
if (legacyData.fileSearch.nextcloud) add("nextcloud")
|
||||||
|
if (legacyData.fileSearch.gdrive) add("gdrive")
|
||||||
|
if (legacyData.fileSearch.onedrive) add("onedrive")
|
||||||
|
},
|
||||||
|
gesturesDoubleTap = makeGestureSettings(
|
||||||
|
legacyData.gestures.doubleTap,
|
||||||
|
legacyData.gestures.doubleTapApp
|
||||||
|
),
|
||||||
|
gesturesSwipeDown = makeGestureSettings(
|
||||||
|
legacyData.gestures.swipeDown,
|
||||||
|
legacyData.gestures.swipeDownApp
|
||||||
|
),
|
||||||
|
gesturesSwipeLeft = makeGestureSettings(
|
||||||
|
legacyData.gestures.swipeLeft,
|
||||||
|
legacyData.gestures.swipeLeftApp
|
||||||
|
),
|
||||||
|
gesturesSwipeRight = makeGestureSettings(
|
||||||
|
legacyData.gestures.swipeRight,
|
||||||
|
legacyData.gestures.swipeRightApp
|
||||||
|
),
|
||||||
|
gesturesLongPress = makeGestureSettings(
|
||||||
|
legacyData.gestures.longPress,
|
||||||
|
legacyData.gestures.longPressApp
|
||||||
|
),
|
||||||
|
gesturesHomeButton = makeGestureSettings(
|
||||||
|
legacyData.gestures.homeButton,
|
||||||
|
legacyData.gestures.homeButtonApp
|
||||||
|
),
|
||||||
|
gridIconSize = legacyData.grid.iconSize,
|
||||||
|
gridLabels = legacyData.grid.showLabels,
|
||||||
|
mediaAllowList = legacyData.musicWidget.allowListList.toSet(),
|
||||||
|
mediaDenyList = legacyData.musicWidget.denyListList.toSet(),
|
||||||
|
hiddenItemsShowButton = legacyData.searchBar.hiddenItemsButton,
|
||||||
|
iconsAdaptify = legacyData.icons.adaptify,
|
||||||
|
iconsForceThemed = legacyData.icons.forceThemed,
|
||||||
|
iconsPack = legacyData.icons.iconPack.takeIf { it.isNotBlank() },
|
||||||
|
iconsPackThemed = legacyData.icons.iconPackThemed,
|
||||||
|
iconsShape = when (legacyData.icons.shape) {
|
||||||
|
LegacySettings.IconSettings.IconShape.Circle -> IconShape.Circle
|
||||||
|
LegacySettings.IconSettings.IconShape.Square -> IconShape.Square
|
||||||
|
LegacySettings.IconSettings.IconShape.Squircle -> IconShape.Squircle
|
||||||
|
LegacySettings.IconSettings.IconShape.RoundedSquare -> IconShape.RoundedSquare
|
||||||
|
LegacySettings.IconSettings.IconShape.EasterEgg -> IconShape.EasterEgg
|
||||||
|
LegacySettings.IconSettings.IconShape.Hexagon -> IconShape.Hexagon
|
||||||
|
LegacySettings.IconSettings.IconShape.Triangle -> IconShape.Triangle
|
||||||
|
LegacySettings.IconSettings.IconShape.Pentagon -> IconShape.Pentagon
|
||||||
|
LegacySettings.IconSettings.IconShape.Teardrop -> IconShape.Teardrop
|
||||||
|
LegacySettings.IconSettings.IconShape.Pebble -> IconShape.Pebble
|
||||||
|
else -> IconShape.PlatformDefault
|
||||||
|
},
|
||||||
|
iconsThemed = legacyData.icons.themedIcons,
|
||||||
|
searchBarBottom = legacyData.layout.bottomSearchBar,
|
||||||
|
searchBarColors = when (legacyData.systemBars.statusBarColor) {
|
||||||
|
LegacySettings.SystemBarsSettings.SystemBarColors.Light -> SearchBarColors.Light
|
||||||
|
LegacySettings.SystemBarsSettings.SystemBarColors.Dark -> SearchBarColors.Dark
|
||||||
|
else -> SearchBarColors.Auto
|
||||||
|
},
|
||||||
|
searchBarFixed = legacyData.layout.bottomSearchBar,
|
||||||
|
searchBarKeyboard = legacyData.searchBar.autoFocus,
|
||||||
|
searchBarStyle = when (legacyData.searchBar.searchBarStyle) {
|
||||||
|
LegacySettings.SearchBarSettings.SearchBarStyle.Hidden -> SearchBarStyle.Hidden
|
||||||
|
LegacySettings.SearchBarSettings.SearchBarStyle.Solid -> SearchBarStyle.Solid
|
||||||
|
else -> SearchBarStyle.Transparent
|
||||||
|
},
|
||||||
|
searchLaunchOnEnter = legacyData.searchBar.launchOnEnter,
|
||||||
|
searchResultOrder = when (legacyData.resultOrdering.ordering) {
|
||||||
|
LegacySettings.SearchResultOrderingSettings.Ordering.Alphabetic -> SearchResultOrder.Alphabetical
|
||||||
|
LegacySettings.SearchResultOrderingSettings.Ordering.LaunchCount -> SearchResultOrder.LaunchCount
|
||||||
|
else -> SearchResultOrder.Weighted
|
||||||
|
},
|
||||||
|
searchResultsReversed = legacyData.layout.reverseSearchResults,
|
||||||
|
shortcutSearchEnabled = legacyData.appShortcutSearch.enabled,
|
||||||
|
stateTagsMultiline = legacyData.ui.searchTagsMultiline,
|
||||||
|
surfacesBorderWidth = legacyData.cards.borderWidth,
|
||||||
|
surfacesOpacity = legacyData.cards.opacity,
|
||||||
|
surfacesRadius = legacyData.cards.radius,
|
||||||
|
surfacesShape = when (legacyData.cards.shape) {
|
||||||
|
LegacySettings.CardSettings.Shape.Cut -> SurfaceShape.Cut
|
||||||
|
else -> SurfaceShape.Rounded
|
||||||
|
},
|
||||||
|
systemBarsHideNav = legacyData.systemBars.hideNavBar,
|
||||||
|
systemBarsHideStatus = legacyData.systemBars.hideStatusBar,
|
||||||
|
systemBarsNavColors = when (legacyData.systemBars.navBarColor) {
|
||||||
|
LegacySettings.SystemBarsSettings.SystemBarColors.Light -> SystemBarColors.Light
|
||||||
|
LegacySettings.SystemBarsSettings.SystemBarColors.Dark -> SystemBarColors.Dark
|
||||||
|
else -> SystemBarColors.Auto
|
||||||
|
},
|
||||||
|
systemBarsStatusColors = when (legacyData.systemBars.statusBarColor) {
|
||||||
|
LegacySettings.SystemBarsSettings.SystemBarColors.Light -> SystemBarColors.Light
|
||||||
|
LegacySettings.SystemBarsSettings.SystemBarColors.Dark -> SystemBarColors.Dark
|
||||||
|
else -> SystemBarColors.Auto
|
||||||
|
},
|
||||||
|
uiColorScheme = when (legacyData.appearance.theme) {
|
||||||
|
LegacySettings.AppearanceSettings.Theme.Light -> ColorScheme.Light
|
||||||
|
LegacySettings.AppearanceSettings.Theme.Dark -> ColorScheme.Dark
|
||||||
|
else -> ColorScheme.System
|
||||||
|
},
|
||||||
|
uiFont = when (legacyData.appearance.font) {
|
||||||
|
LegacySettings.AppearanceSettings.Font.SystemDefault -> Font.System
|
||||||
|
else -> Font.Outfit
|
||||||
|
},
|
||||||
|
uiOrientation = when (legacyData.layout.fixedRotation) {
|
||||||
|
true -> ScreenOrientation.Portrait
|
||||||
|
else -> ScreenOrientation.Auto
|
||||||
|
},
|
||||||
|
uiTheme = when (legacyData.appearance.themeId) {
|
||||||
|
UUID(0L, 0L).toString() -> ThemeDescriptor.Default
|
||||||
|
UUID(0L, 1L).toString() -> ThemeDescriptor.BlackAndWhite
|
||||||
|
else -> ThemeDescriptor.Custom(legacyData.appearance.themeId)
|
||||||
|
},
|
||||||
|
unitConverterCurrencies = legacyData.unitConverterSearch.currencies,
|
||||||
|
unitConverterEnabled = legacyData.unitConverterSearch.enabled,
|
||||||
|
wallpaperBlur = legacyData.appearance.blurWallpaper,
|
||||||
|
weatherImperialUnits = legacyData.weather.imperialUnits,
|
||||||
|
wallpaperBlurRadius = legacyData.appearance.blurWallpaperRadius,
|
||||||
|
wallpaperDim = legacyData.appearance.dimWallpaper,
|
||||||
|
weatherProvider = when (legacyData.weather.provider) {
|
||||||
|
LegacySettings.WeatherSettings.WeatherProvider.MetNo -> "metno"
|
||||||
|
LegacySettings.WeatherSettings.WeatherProvider.OpenWeatherMap -> "owm"
|
||||||
|
LegacySettings.WeatherSettings.WeatherProvider.Here -> "here"
|
||||||
|
LegacySettings.WeatherSettings.WeatherProvider.BrightSky -> "dwd"
|
||||||
|
else -> "metno"
|
||||||
|
},
|
||||||
|
websiteSearchEnabled = legacyData.websiteSearch.enabled,
|
||||||
|
widgetsEditButton = legacyData.widgets.editButton,
|
||||||
|
wikipediaCustomUrl = legacyData.wikipediaSearch.customUrl.takeIf { it.isNotBlank() },
|
||||||
|
wikipediaSearchEnabled = legacyData.wikipediaSearch.enabled,
|
||||||
|
wikipediaSearchImages = legacyData.wikipediaSearch.images,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeGestureSettings(
|
||||||
|
gesture: LegacySettings.GestureSettings.GestureAction,
|
||||||
|
key: String
|
||||||
|
): GestureAction {
|
||||||
|
return when (gesture) {
|
||||||
|
LegacySettings.GestureSettings.GestureAction.OpenSearch -> GestureAction.Search
|
||||||
|
LegacySettings.GestureSettings.GestureAction.OpenNotificationDrawer -> GestureAction.Notifications
|
||||||
|
LegacySettings.GestureSettings.GestureAction.LockScreen -> GestureAction.ScreenLock
|
||||||
|
LegacySettings.GestureSettings.GestureAction.OpenQuickSettings -> GestureAction.QuickSettings
|
||||||
|
LegacySettings.GestureSettings.GestureAction.OpenRecents -> GestureAction.Recents
|
||||||
|
LegacySettings.GestureSettings.GestureAction.OpenPowerDialog -> GestureAction.PowerMenu
|
||||||
|
LegacySettings.GestureSettings.GestureAction.LaunchApp -> GestureAction.Launch(
|
||||||
|
key
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> GestureAction.NoAction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_10_11: VersionedMigration(10, 11) {
|
class Migration_10_11: VersionedMigration(10, 11) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setAppearance(
|
return builder.setAppearance(
|
||||||
builder.appearance.toBuilder()
|
builder.appearance.toBuilder()
|
||||||
.setCustomColors(
|
.setCustomColors(
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings
|
import de.mm20.launcher2.preferences.LegacySettings.GestureSettings
|
||||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings
|
import de.mm20.launcher2.preferences.LegacySettings.LayoutSettings
|
||||||
|
|
||||||
class Migration_11_12: VersionedMigration(11, 12) {
|
class Migration_11_12: VersionedMigration(11, 12) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
val oldLayout = builder.appearance.layout
|
val oldLayout = builder.appearance.layout
|
||||||
when(oldLayout) {
|
when(oldLayout) {
|
||||||
LayoutSettings.Layout.Pager -> {
|
LayoutSettings.Layout.Pager -> {
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
import de.mm20.launcher2.preferences.LegacySettings.SearchResultOrderingSettings.WeightFactor
|
||||||
|
|
||||||
class Migration_12_13: VersionedMigration(12, 13) {
|
class Migration_12_13: VersionedMigration(12, 13) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder
|
return builder
|
||||||
.setClockWidget(
|
.setClockWidget(
|
||||||
builder.clockWidget.toBuilder()
|
builder.clockWidget.toBuilder()
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_13_14 : VersionedMigration(13, 14) {
|
class Migration_13_14 : VersionedMigration(13, 14) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder
|
return builder
|
||||||
.setIcons(
|
.setIcons(
|
||||||
builder.icons.toBuilder()
|
builder.icons.toBuilder()
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_14_15: VersionedMigration(14, 15) {
|
class Migration_14_15: VersionedMigration(14, 15) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setSearchBar(
|
return builder.setSearchBar(
|
||||||
builder.searchBar.toBuilder()
|
builder.searchBar.toBuilder()
|
||||||
.setHiddenItemsButton(true)
|
.setHiddenItemsButton(true)
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.CustomColors.Scheme
|
import de.mm20.launcher2.preferences.LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||||
import palettes.TonalPalette
|
import palettes.TonalPalette
|
||||||
|
|
||||||
class Migration_15_16 : VersionedMigration(15, 16) {
|
class Migration_15_16 : VersionedMigration(15, 16) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setAppearance(
|
return builder.setAppearance(
|
||||||
builder.appearance.toBuilder()
|
builder.appearance.toBuilder()
|
||||||
.setCustomColors(
|
.setCustomColors(
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class Migration_16_17: VersionedMigration(16, 17) {
|
class Migration_16_17: VersionedMigration(16, 17) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setAppearance(
|
return builder.setAppearance(
|
||||||
builder.appearance.toBuilder()
|
builder.appearance.toBuilder()
|
||||||
.setThemeId(
|
.setThemeId(
|
||||||
when(builder.appearance.colorScheme) {
|
when(builder.appearance.colorScheme) {
|
||||||
Settings.AppearanceSettings.ColorScheme.BlackAndWhite -> UUID(0L, 1L)
|
LegacySettings.AppearanceSettings.ColorScheme.BlackAndWhite -> UUID(0L, 1L)
|
||||||
Settings.AppearanceSettings.ColorScheme.Custom -> UUID(1L, 1L)
|
LegacySettings.AppearanceSettings.ColorScheme.Custom -> UUID(1L, 1L)
|
||||||
else -> UUID(0L, 0L)
|
else -> UUID(0L, 0L)
|
||||||
}.toString()
|
}.toString()
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_17_18 : VersionedMigration(17, 18) {
|
class Migration_17_18 : VersionedMigration(17, 18) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder
|
return builder
|
||||||
.setAppearance(builder.appearance.toBuilder()
|
.setAppearance(builder.appearance.toBuilder()
|
||||||
.setBlurWallpaperRadius(32)
|
.setBlurWallpaperRadius(32)
|
||||||
)
|
)
|
||||||
.setClockWidget(builder.clockWidget.toBuilder()
|
.setClockWidget(builder.clockWidget.toBuilder()
|
||||||
.setAlignment(Settings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
.setAlignment(LegacySettings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_1_2: VersionedMigration(1, 2) {
|
class Migration_1_2: VersionedMigration(1, 2) {
|
||||||
|
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setSystemBars(
|
return builder.setSystemBars(
|
||||||
builder.systemBars.toBuilder()
|
builder.systemBars.toBuilder()
|
||||||
.setHideNavBar(false)
|
.setHideNavBar(false)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_2_3: VersionedMigration(2, 3) {
|
class Migration_2_3: VersionedMigration(2, 3) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setClockWidget(
|
return builder.setClockWidget(
|
||||||
builder.clockWidget.toBuilder()
|
builder.clockWidget.toBuilder()
|
||||||
.setAlarmPart(true)
|
.setAlarmPart(true)
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_3_4: VersionedMigration(3, 4) {
|
class Migration_3_4: VersionedMigration(3, 4) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setAppShortcutSearch(
|
return builder.setAppShortcutSearch(
|
||||||
Settings.AppShortcutSearchSettings.newBuilder()
|
LegacySettings.AppShortcutSearchSettings.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_4_5: VersionedMigration(4, 5) {
|
class Migration_4_5: VersionedMigration(4, 5) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setGrid(
|
return builder.setGrid(
|
||||||
builder.grid.toBuilder()
|
builder.grid.toBuilder()
|
||||||
.setIconSize(48)
|
.setIconSize(48)
|
||||||
|
|||||||
@ -3,13 +3,14 @@ package de.mm20.launcher2.preferences.migrations
|
|||||||
import de.mm20.launcher2.preferences.DefaultCustomColorsBase
|
import de.mm20.launcher2.preferences.DefaultCustomColorsBase
|
||||||
import de.mm20.launcher2.preferences.DefaultDarkCustomColorScheme
|
import de.mm20.launcher2.preferences.DefaultDarkCustomColorScheme
|
||||||
import de.mm20.launcher2.preferences.DefaultLightCustomColorScheme
|
import de.mm20.launcher2.preferences.DefaultLightCustomColorScheme
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_5_6: VersionedMigration(5, 6) {
|
class Migration_5_6: VersionedMigration(5, 6) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setAppearance(
|
return builder.setAppearance(
|
||||||
builder.appearance.toBuilder()
|
builder.appearance.toBuilder()
|
||||||
.setCustomColors(Settings.AppearanceSettings.CustomColors.newBuilder()
|
.setCustomColors(
|
||||||
|
LegacySettings.AppearanceSettings.CustomColors.newBuilder()
|
||||||
.setAdvancedMode(false)
|
.setAdvancedMode(false)
|
||||||
.setBaseColors(DefaultCustomColorsBase)
|
.setBaseColors(DefaultCustomColorsBase)
|
||||||
.setLightScheme(DefaultLightCustomColorScheme)
|
.setLightScheme(DefaultLightCustomColorScheme)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_6_7 : VersionedMigration(6, 7) {
|
class Migration_6_7 : VersionedMigration(6, 7) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setIcons(
|
return builder.setIcons(
|
||||||
builder.icons.toBuilder()
|
builder.icons.toBuilder()
|
||||||
.setAdaptify(true)
|
.setAdaptify(true)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_7_8: VersionedMigration(7, 8) {
|
class Migration_7_8: VersionedMigration(7, 8) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder.setAppearance(
|
return builder.setAppearance(
|
||||||
builder.appearance.toBuilder()
|
builder.appearance.toBuilder()
|
||||||
.setBlurWallpaper(true)
|
.setBlurWallpaper(true)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.preferences.migrations
|
package de.mm20.launcher2.preferences.migrations
|
||||||
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
|
||||||
class Migration_8_9: VersionedMigration(8, 9) {
|
class Migration_8_9: VersionedMigration(8, 9) {
|
||||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||||
return builder
|
return builder
|
||||||
.setClockWidget(
|
.setClockWidget(
|
||||||
builder.clockWidget.toBuilder()
|
builder.clockWidget.toBuilder()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user