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.viewmodel.compose.viewModel
|
||||
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.ui.component.SearchBarLevel
|
||||
import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM
|
||||
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.SearchVM
|
||||
import de.mm20.launcher2.ui.launcher.searchbar.LauncherSearchBar
|
||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@Composable
|
||||
fun AssistantScaffold(
|
||||
@ -204,7 +202,7 @@ fun AssistantScaffold(
|
||||
showHiddenItemsButton = true,
|
||||
value = { value },
|
||||
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,
|
||||
reverse = bottomSearchBar,
|
||||
onKeyboardActionGo = if (launchOnEnter) {
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package de.mm20.launcher2.ui.base
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.IconShape
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
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.locals.LocalCardStyle
|
||||
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||
@ -19,32 +21,28 @@ import org.koin.androidx.compose.inject
|
||||
fun ProvideSettings(
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val dataStore: LauncherDataStore by inject()
|
||||
val settings: UiSettings by inject()
|
||||
val widgetRepository: WidgetRepository by inject()
|
||||
|
||||
val cardStyle by remember {
|
||||
dataStore.data.map { it.cards }.distinctUntilChanged()
|
||||
settings.cardStyle.distinctUntilChanged()
|
||||
}.collectAsState(
|
||||
Settings.CardSettings.getDefaultInstance()
|
||||
CardStyle()
|
||||
)
|
||||
val iconShape by remember {
|
||||
dataStore.data.map {
|
||||
if (it.easterEgg) Settings.IconSettings.IconShape.EasterEgg
|
||||
else it.icons.shape
|
||||
}.distinctUntilChanged()
|
||||
}.collectAsState(Settings.IconSettings.IconShape.Circle)
|
||||
settings.iconShape.distinctUntilChanged()
|
||||
}.collectAsState(IconShape.Circle)
|
||||
|
||||
val favoritesEnabled by remember {
|
||||
combine(
|
||||
widgetRepository.exists(FavoritesWidget.Type),
|
||||
dataStore.data.map { it.favorites.enabled },
|
||||
dataStore.data.map { it.clockWidget.favoritesPart },
|
||||
) { a, b, c -> a || b || c }.distinctUntilChanged()
|
||||
settings.favoritesEnabled,
|
||||
) { a, b -> a || b }.distinctUntilChanged()
|
||||
}.collectAsState(true)
|
||||
|
||||
val gridSettings by remember {
|
||||
dataStore.data.map { it.grid }.distinctUntilChanged()
|
||||
}.collectAsState(Settings.GridSettings.newBuilder().setColumnCount(5).setShowLabels(true).setIconSize(48).build())
|
||||
settings.gridSettings.distinctUntilChanged()
|
||||
}.collectAsState(GridSettings())
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalCardStyle provides cardStyle,
|
||||
|
||||
@ -4,7 +4,8 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
||||
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.data.Tag
|
||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||
@ -19,11 +20,11 @@ abstract class FavoritesVM : ViewModel(), KoinComponent {
|
||||
private val favoritesService: FavoritesService by inject()
|
||||
internal val widgetRepository: WidgetRepository 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 showEditButton = dataStore.data.map { it.favorites.editButton }
|
||||
val showEditButton = settings.showEditButton
|
||||
abstract val tagsExpanded: Flow<Boolean>
|
||||
|
||||
val pinnedTags = favoritesService.getFavorites(
|
||||
@ -36,24 +37,18 @@ abstract class FavoritesVM : ViewModel(), KoinComponent {
|
||||
|
||||
open val favorites: Flow<List<SavableSearchable>> = selectedTag.flatMapLatest { tag ->
|
||||
if (tag == null) {
|
||||
val columns = dataStore.data.map { it.grid.columnCount }
|
||||
val excludeCalendar = widgetRepository.exists(CalendarWidget.Type)
|
||||
val includeFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
||||
|
||||
combine(
|
||||
listOf(
|
||||
columns,
|
||||
excludeCalendar,
|
||||
includeFrequentlyUsed,
|
||||
frequentlyUsedRows
|
||||
)
|
||||
) { it }.transformLatest {
|
||||
excludeCalendar,
|
||||
settings,
|
||||
) { (a, b) -> a as Boolean to b as FavoritesSettingsData }
|
||||
.transformLatest {
|
||||
|
||||
val columns = it[0] as Int
|
||||
val excludeCalendar = it[1] as Boolean
|
||||
val includeFrequentlyUsed = it[2] as Boolean
|
||||
val frequentlyUsedRows = it[3] as Int
|
||||
val columns = it.second.columns
|
||||
val excludeCalendar = it.first
|
||||
val includeFrequentlyUsed = it.second.frequentlyUsed
|
||||
val frequentlyUsedRows = it.second.frequentlyUsedRows
|
||||
|
||||
val pinned = favoritesService.getFavorites(
|
||||
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
||||
|
||||
@ -5,7 +5,8 @@ import android.net.Uri
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.ThemeRepository
|
||||
import de.mm20.launcher2.themes.fromJson
|
||||
@ -17,7 +18,7 @@ import org.koin.core.component.inject
|
||||
class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val themeRepository: ThemeRepository by inject()
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
private val uiSettings: UiSettings by inject()
|
||||
|
||||
val theme = mutableStateOf<Theme?>(null)
|
||||
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)
|
||||
if (apply) {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setThemeId(theme.id.toString())
|
||||
).build()
|
||||
}
|
||||
uiSettings.setTheme(ThemeDescriptor.Custom(theme.id.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.search.SearchService
|
||||
import de.mm20.launcher2.search.toList
|
||||
@ -15,15 +14,13 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.component.KoinComponent
|
||||
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 iconService: IconService by inject()
|
||||
|
||||
@ -41,15 +38,11 @@ class SearchablePickerVM: ViewModel(), KoinComponent {
|
||||
searchQuery = query
|
||||
searchJob?.cancel()
|
||||
searchJob = viewModelScope.launch {
|
||||
val settings = dataStore.data.first()
|
||||
searchService.search(
|
||||
query = query,
|
||||
shortcuts = settings.appShortcutSearch,
|
||||
contacts = settings.contactsSearch,
|
||||
calendars = settings.calendarSearch,
|
||||
).collectLatest {
|
||||
if (searchQuery != query) return@collectLatest
|
||||
items = withContext(Dispatchers.Default) {
|
||||
items = withContext(Dispatchers.Default) {
|
||||
it.toList().filterIsInstance<SavableSearchable>().sorted()
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,9 +2,9 @@ package de.mm20.launcher2.ui.common
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
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.settings.WeatherSettings
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.first
|
||||
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.text.input.ImeAction
|
||||
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.layout.BottomReversed
|
||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||
@ -47,7 +47,7 @@ import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
modifier: Modifier = Modifier,
|
||||
style: Settings.SearchBarSettings.SearchBarStyle,
|
||||
style: SearchBarStyle,
|
||||
level: SearchBarLevel,
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
@ -78,7 +78,7 @@ fun SearchBar(
|
||||
}
|
||||
) {
|
||||
when {
|
||||
it == SearchBarLevel.Resting && style != Settings.SearchBarSettings.SearchBarStyle.Solid -> 0.dp
|
||||
it == SearchBarLevel.Resting && style != SearchBarStyle.Solid -> 0.dp
|
||||
it == SearchBarLevel.Raised -> 8.dp
|
||||
else -> 2.dp
|
||||
}
|
||||
@ -98,7 +98,7 @@ fun SearchBar(
|
||||
}) {
|
||||
when {
|
||||
it == SearchBarLevel.Active -> LocalCardStyle.current.opacity
|
||||
style != Settings.SearchBarSettings.SearchBarStyle.Transparent -> 1f
|
||||
style != SearchBarStyle.Transparent -> 1f
|
||||
it == SearchBarLevel.Resting -> 0f
|
||||
else -> 1f
|
||||
}
|
||||
@ -117,14 +117,14 @@ fun SearchBar(
|
||||
}
|
||||
}) {
|
||||
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
|
||||
else -> MaterialTheme.colorScheme.onSurface
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
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.toAndroidRect
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
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.TransparentLayer
|
||||
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.ktx.toPixels
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
@ -495,7 +493,6 @@ fun getShape(iconShape: IconShape): Shape {
|
||||
IconShape.Teardrop -> TeardropShape
|
||||
IconShape.Pebble -> PebbleShape
|
||||
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.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
|
||||
import de.mm20.launcher2.preferences.BaseLayout
|
||||
import de.mm20.launcher2.preferences.ColorScheme
|
||||
import de.mm20.launcher2.preferences.GestureAction
|
||||
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.ui.gestures.Gesture
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@ -32,7 +35,8 @@ import org.koin.core.component.inject
|
||||
|
||||
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 permissionsManager: PermissionsManager by inject()
|
||||
private val searchableRepository: SavableSearchableRepository by inject()
|
||||
@ -40,40 +44,41 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
private var isSystemInDarkMode = MutableStateFlow(false)
|
||||
|
||||
private val dimBackgroundState = combine(
|
||||
dataStore.data.map { it.appearance.dimWallpaper },
|
||||
dataStore.data.map { it.appearance.theme },
|
||||
uiSettings.dimWallpaper,
|
||||
uiSettings.colorScheme,
|
||||
isSystemInDarkMode
|
||||
) { 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 statusBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
||||
val statusBarColor = uiSettings.statusBarColor
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val navBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
||||
val navBarColor = uiSettings.navigationBarColor
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val chargingAnimation = dataStore.data.map { it.animations.charging }
|
||||
val chargingAnimation = uiSettings.chargingAnimation
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
||||
val hideNavBar = uiSettings.hideNavigationBar
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
||||
val hideStatusBar = uiSettings.hideStatusBar
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
fun setSystemInDarkMode(darkMode: Boolean) {
|
||||
isSystemInDarkMode.value = darkMode
|
||||
}
|
||||
|
||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
||||
val baseLayout = uiSettings.baseLayout
|
||||
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
||||
val bottomSearchBar = uiSettings.bottomSearchBar
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
||||
val reverseSearchResults = uiSettings.reverseSearchResults
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
||||
val fixedSearchBar = uiSettings.fixedSearchBar
|
||||
.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)
|
||||
|
||||
val isSearchOpen = mutableStateOf(false)
|
||||
@ -81,8 +86,7 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
|
||||
val searchBarFocused = mutableStateOf(false)
|
||||
|
||||
|
||||
val autoFocusSearch = dataStore.data.map { it.searchBar.autoFocus }
|
||||
val autoFocusSearch = uiSettings.openKeyboardOnSearch
|
||||
|
||||
fun setSearchbarFocus(focused: Boolean) {
|
||||
if (searchBarFocused.value != focused) searchBarFocused.value = focused
|
||||
@ -120,45 +124,43 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
isWidgetEditMode.value = editMode
|
||||
}
|
||||
|
||||
val wallpaperBlur = dataStore.data.map { it.appearance.blurWallpaper }
|
||||
val wallpaperBlur = uiSettings.blurWallpaper
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||
val wallpaperBlurRadius = dataStore.data.map { it.appearance.blurWallpaperRadius }
|
||||
val wallpaperBlurRadius = uiSettings.wallpaperBlurRadius
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
||||
|
||||
|
||||
val fillClockHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
||||
val fillClockHeight = uiSettings.clockFillScreen
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarColors.Auto)
|
||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||
val searchBarColor = uiSettings.searchBarColor
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SearchBarColors.Auto)
|
||||
val searchBarStyle = uiSettings.searchBarStyle
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SearchBarStyle.Transparent)
|
||||
|
||||
val gestureState: StateFlow<GestureState> = dataStore
|
||||
.data.map { it.gestures }
|
||||
.distinctUntilChanged()
|
||||
val gestureState: StateFlow<GestureState> = gestureSettings
|
||||
.combine(baseLayout) { settings, layout ->
|
||||
val swipeLeftAction =
|
||||
settings?.swipeLeft?.takeIf { layout != Layout.Pager } ?: GestureAction.None
|
||||
val swipeRightAction = settings?.swipeRight?.takeIf { layout != Layout.PagerReversed }
|
||||
?: GestureAction.None
|
||||
settings.swipeLeft.takeIf { layout != BaseLayout.Pager } ?: GestureAction.NoAction
|
||||
val swipeRightAction = settings.swipeRight.takeIf { layout != BaseLayout.PagerReversed }
|
||||
?: GestureAction.NoAction
|
||||
val swipeDownAction =
|
||||
settings?.swipeDown?.takeIf { layout != Layout.PullDown } ?: GestureAction.None
|
||||
val longPressAction = settings?.longPress ?: GestureAction.None
|
||||
val doubleTapAction = settings?.doubleTap ?: GestureAction.None
|
||||
val homeButtonAction = settings?.homeButton ?: GestureAction.None
|
||||
settings.swipeDown.takeIf { layout != BaseLayout.PullDown } ?: GestureAction.NoAction
|
||||
val longPressAction = settings.longPress
|
||||
val doubleTapAction = settings.doubleTap
|
||||
val homeButtonAction = settings.homeButton
|
||||
|
||||
val swipeLeftAppKey =
|
||||
if (swipeLeftAction == GestureAction.LaunchApp) settings.swipeLeftApp else null
|
||||
if (swipeLeftAction is GestureAction.Launch) swipeLeftAction.key else null
|
||||
val swipeRightAppKey =
|
||||
if (swipeRightAction == GestureAction.LaunchApp) settings.swipeRightApp else null
|
||||
if (swipeRightAction is GestureAction.Launch) swipeRightAction.key else null
|
||||
val swipeDownAppKey =
|
||||
if (swipeDownAction == GestureAction.LaunchApp) settings.swipeDownApp else null
|
||||
if (swipeDownAction is GestureAction.Launch) swipeDownAction.key else null
|
||||
val longPressAppKey =
|
||||
if (longPressAction == GestureAction.LaunchApp) settings.longPressApp else null
|
||||
if (longPressAction is GestureAction.Launch) longPressAction.key else null
|
||||
val doubleTapAppKey =
|
||||
if (doubleTapAction == GestureAction.LaunchApp) settings.doubleTapApp else null
|
||||
if (doubleTapAction is GestureAction.Launch) doubleTapAction.key else null
|
||||
val homeButtonAppKey =
|
||||
if (homeButtonAction == GestureAction.LaunchApp) settings.homeButtonApp else null
|
||||
if (homeButtonAction is GestureAction.Launch) homeButtonAction.key else null
|
||||
val apps = listOfNotNull(
|
||||
swipeLeftAppKey,
|
||||
swipeRightAppKey,
|
||||
@ -189,17 +191,17 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
val action = when (gesture) {
|
||||
Gesture.DoubleTap -> gestureState.value.doubleTapAction
|
||||
Gesture.LongPress -> gestureState.value.longPressAction
|
||||
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != Layout.PullDown }
|
||||
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != Layout.Pager }
|
||||
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != Layout.PagerReversed }
|
||||
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != BaseLayout.PullDown }
|
||||
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != BaseLayout.Pager }
|
||||
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != BaseLayout.PagerReversed }
|
||||
Gesture.HomeButton -> gestureState.value.homeButtonAction
|
||||
}
|
||||
val requiresAccessibilityService =
|
||||
action == GestureAction.OpenRecents
|
||||
|| action == GestureAction.OpenPowerDialog
|
||||
|| action == GestureAction.OpenQuickSettings
|
||||
|| action == GestureAction.OpenNotificationDrawer
|
||||
|| action == GestureAction.LockScreen
|
||||
action is GestureAction.Recents
|
||||
|| action is GestureAction.PowerMenu
|
||||
|| action is GestureAction.QuickSettings
|
||||
|| action is GestureAction.Notifications
|
||||
|| action is GestureAction.ScreenLock
|
||||
|
||||
if (action != null && requiresAccessibilityService && !permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.Accessibility
|
||||
@ -211,37 +213,37 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
|
||||
|
||||
return when (action) {
|
||||
GestureAction.OpenSearch -> {
|
||||
is GestureAction.Search -> {
|
||||
openSearch()
|
||||
true
|
||||
}
|
||||
|
||||
GestureAction.OpenNotificationDrawer -> {
|
||||
is GestureAction.Notifications -> {
|
||||
globalActionsService.openNotificationDrawer()
|
||||
true
|
||||
}
|
||||
|
||||
GestureAction.OpenQuickSettings -> {
|
||||
is GestureAction.QuickSettings -> {
|
||||
globalActionsService.openQuickSettings()
|
||||
true
|
||||
}
|
||||
|
||||
GestureAction.LockScreen -> {
|
||||
is GestureAction.ScreenLock -> {
|
||||
globalActionsService.lockScreen()
|
||||
true
|
||||
}
|
||||
|
||||
GestureAction.OpenPowerDialog -> {
|
||||
is GestureAction.PowerMenu -> {
|
||||
globalActionsService.openPowerDialog()
|
||||
true
|
||||
}
|
||||
|
||||
GestureAction.OpenRecents -> {
|
||||
is GestureAction.Recents -> {
|
||||
globalActionsService.openRecents()
|
||||
true
|
||||
}
|
||||
|
||||
GestureAction.LaunchApp -> {
|
||||
is GestureAction.Launch -> {
|
||||
val view = (context as Activity).window.decorView
|
||||
val options = ActivityOptionsCompat.makeScaleUpAnimation(
|
||||
view,
|
||||
@ -271,12 +273,12 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
data class GestureState(
|
||||
val swipeLeftAction: GestureAction = GestureAction.None,
|
||||
val swipeRightAction: GestureAction = GestureAction.None,
|
||||
val swipeDownAction: GestureAction = GestureAction.None,
|
||||
val longPressAction: GestureAction = GestureAction.None,
|
||||
val doubleTapAction: GestureAction = GestureAction.None,
|
||||
val homeButtonAction: GestureAction = GestureAction.None,
|
||||
val swipeLeftAction: GestureAction = GestureAction.NoAction,
|
||||
val swipeRightAction: GestureAction = GestureAction.NoAction,
|
||||
val swipeDownAction: GestureAction = GestureAction.NoAction,
|
||||
val longPressAction: GestureAction = GestureAction.NoAction,
|
||||
val doubleTapAction: GestureAction = GestureAction.NoAction,
|
||||
val homeButtonAction: GestureAction = GestureAction.NoAction,
|
||||
val swipeLeftApp: SavableSearchable? = null,
|
||||
val swipeRightApp: SavableSearchable? = null,
|
||||
val swipeDownApp: SavableSearchable? = null,
|
||||
|
||||
@ -86,7 +86,7 @@ import androidx.compose.ui.unit.Velocity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
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.ui.R
|
||||
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.lifecycle.viewmodel.compose.viewModel
|
||||
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.ui.R
|
||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||
@ -605,7 +605,7 @@ fun PullDownScaffold(
|
||||
showHiddenItemsButton = isSearchOpen,
|
||||
value = { value },
|
||||
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,
|
||||
reverse = bottomSearchBar,
|
||||
onKeyboardActionGo = if (launchOnEnter) {
|
||||
|
||||
@ -34,8 +34,8 @@ import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings.SystemBarColors
|
||||
import de.mm20.launcher2.preferences.BaseLayout
|
||||
import de.mm20.launcher2.preferences.SystemBarColors
|
||||
import de.mm20.launcher2.ui.assistant.AssistantScaffold
|
||||
import de.mm20.launcher2.ui.base.BaseActivity
|
||||
import de.mm20.launcher2.ui.base.ProvideCurrentTime
|
||||
@ -184,7 +184,7 @@ abstract class SharedLauncherActivity(
|
||||
}
|
||||
} else {
|
||||
when (layout) {
|
||||
Settings.LayoutSettings.Layout.PullDown -> {
|
||||
BaseLayout.PullDown -> {
|
||||
key(bottomSearchBar, reverseSearchResults) {
|
||||
PullDownScaffold(
|
||||
modifier = Modifier
|
||||
@ -205,8 +205,8 @@ abstract class SharedLauncherActivity(
|
||||
}
|
||||
}
|
||||
|
||||
Settings.LayoutSettings.Layout.Pager,
|
||||
Settings.LayoutSettings.Layout.PagerReversed -> {
|
||||
BaseLayout.Pager,
|
||||
BaseLayout.PagerReversed -> {
|
||||
key(bottomSearchBar, reverseSearchResults) {
|
||||
PagerScaffold(
|
||||
modifier = Modifier
|
||||
@ -220,7 +220,7 @@ abstract class SharedLauncherActivity(
|
||||
},
|
||||
darkStatusBarIcons = lightStatus,
|
||||
darkNavBarIcons = lightNav,
|
||||
reverse = layout == Settings.LayoutSettings.Layout.PagerReversed,
|
||||
reverse = layout == BaseLayout.PagerReversed,
|
||||
bottomSearchBar = bottomSearchBar,
|
||||
reverseSearchResults = reverseSearchResults,
|
||||
fixedSearchBar = fixedSearchBar,
|
||||
|
||||
@ -19,7 +19,7 @@ import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
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.ui.component.FakeSplashScreen
|
||||
import de.mm20.launcher2.ui.gestures.Gesture
|
||||
@ -52,7 +52,7 @@ fun LauncherGestureHandler(
|
||||
|
||||
val gestureState by viewModel.gestureState.collectAsState(GestureState())
|
||||
|
||||
val shouldDetectDoubleTapGesture = gestureState.doubleTapAction != GestureAction.None
|
||||
val shouldDetectDoubleTapGesture = gestureState.doubleTapAction !is GestureAction.NoAction
|
||||
|
||||
LaunchedEffect(shouldDetectDoubleTapGesture) {
|
||||
gestureDetector.shouldDetectDoubleTaps = shouldDetectDoubleTapGesture
|
||||
|
||||
@ -5,25 +5,30 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.Ordering
|
||||
import de.mm20.launcher2.preferences.LegacySettings.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.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.File
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.search.SearchService
|
||||
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.data.Calculator
|
||||
import de.mm20.launcher2.search.data.UnitConverter
|
||||
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||
import kotlinx.coroutines.CancellationException
|
||||
@ -32,7 +37,6 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
@ -47,10 +51,14 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
private val favoritesService: FavoritesService by inject()
|
||||
private val searchableRepository: SavableSearchableRepository 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)
|
||||
|
||||
private val searchService: SearchService by inject()
|
||||
@ -70,10 +78,10 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
val unitConverterResults = mutableStateOf<List<UnitConverter>>(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 favoritesEnabled = dataStore.data.map { it.favorites.enabled }
|
||||
val favoritesEnabled = searchUiSettings.favorites
|
||||
val hideFavorites = mutableStateOf(false)
|
||||
|
||||
private val hiddenItemKeys = searchableRepository
|
||||
@ -117,16 +125,9 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
hideFavorites.value = query.isNotEmpty()
|
||||
searchJob = viewModelScope.launch {
|
||||
dataStore.data.collectLatest { settings ->
|
||||
searchUiSettings.resultOrder.collectLatest { resultOrder ->
|
||||
searchService.search(
|
||||
query,
|
||||
calculator = settings.calculatorSearch,
|
||||
unitConverter = settings.unitConverterSearch,
|
||||
calendars = settings.calendarSearch,
|
||||
contacts = settings.contactsSearch,
|
||||
shortcuts = settings.appShortcutSearch,
|
||||
websites = settings.websiteSearch,
|
||||
wikipedia = settings.wikipediaSearch,
|
||||
query
|
||||
).collectLatest { results ->
|
||||
var resultsList = withContext(Dispatchers.Default) {
|
||||
listOfNotNull(
|
||||
@ -151,13 +152,13 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
emptyList()
|
||||
} else {
|
||||
val keys = resultsList.mapNotNull { (it as? SavableSearchable)?.key }
|
||||
when (settings.resultOrdering.ordering) {
|
||||
when (resultOrder) {
|
||||
|
||||
Ordering.LaunchCount -> searchableRepository.sortByRelevance(
|
||||
SearchResultOrder.LaunchCount -> searchableRepository.sortByRelevance(
|
||||
keys
|
||||
).first()
|
||||
|
||||
Ordering.Weighted -> searchableRepository.sortByWeight(
|
||||
SearchResultOrder.Weighted -> searchableRepository.sortByWeight(
|
||||
keys
|
||||
).first()
|
||||
|
||||
@ -256,7 +257,7 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
|
||||
val missingCalendarPermission = combine(
|
||||
permissionsManager.hasPermission(PermissionGroup.Calendar),
|
||||
dataStore.data.map { it.calendarSearch.enabled }.distinctUntilChanged()
|
||||
calendarSearchSettings.enabled,
|
||||
) { perm, enabled -> !perm && enabled }
|
||||
|
||||
fun requestCalendarPermission(context: AppCompatActivity) {
|
||||
@ -264,18 +265,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun disableCalendarSearch() {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setCalendarSearch(it.calendarSearch.toBuilder().setEnabled(false))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
calendarSearchSettings.setEnabled(false)
|
||||
}
|
||||
|
||||
val missingContactsPermission = combine(
|
||||
permissionsManager.hasPermission(PermissionGroup.Contacts),
|
||||
dataStore.data.map { it.contactsSearch.enabled }.distinctUntilChanged()
|
||||
contactSearchSettings.enabled
|
||||
) { perm, enabled -> !perm && enabled }
|
||||
|
||||
fun requestContactsPermission(context: AppCompatActivity) {
|
||||
@ -283,18 +278,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun disableContactsSearch() {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setContactsSearch(it.contactsSearch.toBuilder().setEnabled(false))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
contactSearchSettings.setEnabled(false)
|
||||
}
|
||||
|
||||
val missingFilesPermission = combine(
|
||||
permissionsManager.hasPermission(PermissionGroup.ExternalStorage),
|
||||
fileSearchSettings.localFiles.distinctUntilChanged()
|
||||
fileSearchSettings.localFiles
|
||||
) { perm, enabled -> !perm && enabled }
|
||||
|
||||
fun requestFilesPermission(context: AppCompatActivity) {
|
||||
@ -302,18 +291,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun disableFilesSearch() {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setFileSearch(it.fileSearch.toBuilder().setLocalFiles(false))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
fileSearchSettings.setLocalFiles(false)
|
||||
}
|
||||
|
||||
val missingAppShortcutPermission = combine(
|
||||
permissionsManager.hasPermission(PermissionGroup.AppShortcuts),
|
||||
dataStore.data.map { it.appShortcutSearch.enabled }.distinctUntilChanged()
|
||||
shortcutSearchSettings.enabled,
|
||||
) { perm, enabled -> !perm && enabled }
|
||||
|
||||
fun requestAppShortcutPermission(context: AppCompatActivity) {
|
||||
@ -321,12 +304,6 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun disableAppShortcutSearch() {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppShortcutSearch(it.appShortcutSearch.toBuilder().setEnabled(false))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
shortcutSearchSettings.setEnabled(false)
|
||||
}
|
||||
}
|
||||
@ -1,29 +1,23 @@
|
||||
package de.mm20.launcher2.ui.launcher.search.favorites
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.ui.UiState
|
||||
import de.mm20.launcher2.ui.common.FavoritesVM
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.inject
|
||||
|
||||
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)
|
||||
|
||||
override fun setTagsExpanded(expanded: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setUi(
|
||||
it.ui.toBuilder()
|
||||
.setSearchTagsMultiline(expanded)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiState.setFavoritesTagsExpanded(expanded)
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,7 +19,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
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.ui.component.SearchBar
|
||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||
@ -29,7 +29,7 @@ import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
|
||||
@Composable
|
||||
fun LauncherSearchBar(
|
||||
modifier: Modifier = Modifier,
|
||||
style: Settings.SearchBarSettings.SearchBarStyle,
|
||||
style: SearchBarStyle,
|
||||
level: () -> SearchBarLevel,
|
||||
value: () -> String,
|
||||
onValueChange: (String) -> Unit,
|
||||
|
||||
@ -17,9 +17,9 @@ import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.ktx.normalize
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.appshortcuts.AppShortcut
|
||||
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||
import de.mm20.launcher2.search.Searchable
|
||||
import de.mm20.launcher2.search.data.Tag
|
||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||
@ -41,7 +41,7 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
||||
private val badgeService: BadgeService by inject()
|
||||
private val customAttributesRepository: CustomAttributesRepository 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())
|
||||
|
||||
@ -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)
|
||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setFavorites(
|
||||
it.favorites
|
||||
.toBuilder()
|
||||
.setFrequentlyUsed(frequentlyUsed)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
favoritesSettings.setFrequentlyUsed(frequentlyUsed)
|
||||
}
|
||||
|
||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
||||
val frequentlyUsedRows = favoritesSettings.frequentlyUsedRows
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setFavorites(
|
||||
it.favorites
|
||||
.toBuilder()
|
||||
.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
favoritesSettings.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||
}
|
||||
|
||||
fun pinTag(tag: Tag) {
|
||||
|
||||
@ -14,7 +14,8 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
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.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
@ -29,12 +30,12 @@ fun FailedGestureSheet(
|
||||
val viewModel: FailedGestureSheetVM = viewModel()
|
||||
|
||||
val actionName = stringResource(when(failedGesture.action) {
|
||||
Settings.GestureSettings.GestureAction.OpenSearch -> R.string.gesture_action_open_search
|
||||
Settings.GestureSettings.GestureAction.OpenNotificationDrawer -> R.string.gesture_action_notifications
|
||||
Settings.GestureSettings.GestureAction.LockScreen -> R.string.gesture_action_lock_screen
|
||||
Settings.GestureSettings.GestureAction.OpenQuickSettings -> R.string.gesture_action_quick_settings
|
||||
Settings.GestureSettings.GestureAction.OpenRecents -> R.string.gesture_action_recents
|
||||
Settings.GestureSettings.GestureAction.OpenPowerDialog -> R.string.gesture_action_power_menu
|
||||
is GestureAction.Search -> R.string.gesture_action_open_search
|
||||
is GestureAction.Notifications -> R.string.gesture_action_notifications
|
||||
is GestureAction.ScreenLock -> R.string.gesture_action_lock_screen
|
||||
is GestureAction.QuickSettings -> R.string.gesture_action_quick_settings
|
||||
is GestureAction.Recents -> R.string.gesture_action_recents
|
||||
is GestureAction.PowerMenu -> R.string.gesture_action_power_menu
|
||||
else -> R.string.gesture_action_none
|
||||
})
|
||||
val gestureName = stringResource(when(failedGesture.gesture) {
|
||||
|
||||
@ -5,8 +5,8 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
||||
import de.mm20.launcher2.preferences.GestureAction
|
||||
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||
import de.mm20.launcher2.ui.gestures.Gesture
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
@ -14,28 +14,20 @@ import org.koin.core.component.inject
|
||||
|
||||
class FailedGestureSheetVM : ViewModel(), KoinComponent {
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
private val gestureSettings: GestureSettings by inject()
|
||||
|
||||
fun requestPermission(context: AppCompatActivity) {
|
||||
permissionsManager.requestPermission(context, PermissionGroup.Accessibility)
|
||||
}
|
||||
|
||||
fun disableGesture(gesture: Gesture) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setGestures(
|
||||
it.gestures.toBuilder().apply {
|
||||
when (gesture) {
|
||||
Gesture.SwipeDown -> swipeDown = GestureAction.None
|
||||
Gesture.SwipeLeft -> swipeLeft = GestureAction.None
|
||||
Gesture.SwipeRight -> swipeRight = GestureAction.None
|
||||
Gesture.DoubleTap -> doubleTap = GestureAction.None
|
||||
Gesture.LongPress -> longPress = GestureAction.None
|
||||
Gesture.HomeButton -> homeButton = GestureAction.None
|
||||
}
|
||||
}.build()
|
||||
).build()
|
||||
}
|
||||
when(gesture) {
|
||||
Gesture.DoubleTap -> gestureSettings.setDoubleTap(GestureAction.NoAction)
|
||||
Gesture.LongPress -> gestureSettings.setLongPress(GestureAction.NoAction)
|
||||
Gesture.SwipeDown -> gestureSettings.setSwipeDown(GestureAction.NoAction)
|
||||
Gesture.SwipeLeft -> gestureSettings.setSwipeLeft(GestureAction.NoAction)
|
||||
Gesture.SwipeRight -> gestureSettings.setSwipeRight(GestureAction.NoAction)
|
||||
Gesture.HomeButton -> gestureSettings.setHomeButton(GestureAction.NoAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.WidgetRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
@ -15,9 +14,9 @@ import org.koin.core.component.inject
|
||||
class WidgetsVM : ViewModel(), KoinComponent {
|
||||
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)
|
||||
|
||||
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.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
@ -64,10 +62,9 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetAlignment
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
||||
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.base.LocalTime
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
@ -89,7 +86,7 @@ fun ClockWidget(
|
||||
) {
|
||||
val viewModel: ClockWidgetVM = viewModel()
|
||||
val context = LocalContext.current
|
||||
val layout by viewModel.layout.collectAsState()
|
||||
val compact by viewModel.compactLayout.collectAsState()
|
||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
||||
val color by viewModel.color.collectAsState()
|
||||
val alignment by viewModel.alignment.collectAsState()
|
||||
@ -106,7 +103,9 @@ fun ClockWidget(
|
||||
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") {
|
||||
if (it) {
|
||||
@ -165,32 +164,32 @@ fun ClockWidget(
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides contentColor
|
||||
) {
|
||||
if (layout == ClockWidgetLayout.Vertical) {
|
||||
if (compact == false) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.clickable(
|
||||
enabled = clockStyle != ClockStyle.EmptyClock,
|
||||
enabled = clockStyle !is ClockWidgetStyle.Empty,
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) {
|
||||
viewModel.launchClockApp(context)
|
||||
}
|
||||
) {
|
||||
Clock(clockStyle, ClockWidgetLayout.Vertical)
|
||||
Clock(clockStyle, false)
|
||||
}
|
||||
|
||||
if (partProvider != null) {
|
||||
DynamicZone(
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
layout = ClockWidgetLayout.Vertical,
|
||||
compact = false,
|
||||
provider = partProvider,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layout == ClockWidgetLayout.Horizontal) {
|
||||
if (compact == true) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -201,7 +200,7 @@ fun ClockWidget(
|
||||
if (partProvider != null) {
|
||||
DynamicZone(
|
||||
modifier = Modifier.weight(1f),
|
||||
layout = ClockWidgetLayout.Horizontal,
|
||||
compact = true,
|
||||
provider = partProvider,
|
||||
)
|
||||
}
|
||||
@ -216,14 +215,14 @@ fun ClockWidget(
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier.clickable(
|
||||
enabled = clockStyle != ClockStyle.EmptyClock,
|
||||
enabled = clockStyle !is ClockWidgetStyle.Empty,
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) {
|
||||
viewModel.launchClockApp(context)
|
||||
}
|
||||
) {
|
||||
Clock(clockStyle, ClockWidgetLayout.Horizontal)
|
||||
Clock(clockStyle, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -236,7 +235,7 @@ fun ClockWidget(
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp)
|
||||
) {
|
||||
dockProvider?.Component(ClockWidgetLayout.Vertical)
|
||||
dockProvider?.Component(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -246,21 +245,18 @@ fun ClockWidget(
|
||||
|
||||
@Composable
|
||||
fun Clock(
|
||||
style: ClockStyle?,
|
||||
layout: ClockWidgetLayout
|
||||
style: ClockWidgetStyle?,
|
||||
compact: Boolean,
|
||||
) {
|
||||
val time = LocalTime.current
|
||||
when (style) {
|
||||
ClockStyle.DigitalClock1,
|
||||
ClockStyle.DigitalClock1_Outlined,
|
||||
ClockStyle.DigitalClock1_MDY,
|
||||
ClockStyle.DigitalClock1_OnePlus -> DigitalClock1(time, layout, style)
|
||||
is ClockWidgetStyle.Digital1 -> DigitalClock1(time, compact, style)
|
||||
|
||||
ClockStyle.DigitalClock2 -> DigitalClock2(time, layout)
|
||||
ClockStyle.BinaryClock -> BinaryClock(time, layout)
|
||||
ClockStyle.AnalogClock -> AnalogClock(time, layout)
|
||||
ClockStyle.OrbitClock -> OrbitClock(time, layout)
|
||||
ClockStyle.EmptyClock -> {}
|
||||
is ClockWidgetStyle.Digital2 -> DigitalClock2(time, compact)
|
||||
is ClockWidgetStyle.Binary -> BinaryClock(time, compact)
|
||||
is ClockWidgetStyle.Analog -> AnalogClock(time, compact)
|
||||
is ClockWidgetStyle.Orbit -> OrbitClock(time, compact)
|
||||
is ClockWidgetStyle.Empty -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -268,13 +264,13 @@ fun Clock(
|
||||
@Composable
|
||||
fun DynamicZone(
|
||||
modifier: Modifier = Modifier,
|
||||
layout: ClockWidgetLayout,
|
||||
compact: Boolean,
|
||||
provider: PartProvider?,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
provider?.Component(layout)
|
||||
provider?.Component(compact)
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,18 +279,13 @@ fun ConfigureClockWidgetSheet(
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
|
||||
val layout by viewModel.layout.collectAsState()
|
||||
val compact by viewModel.compact.collectAsState()
|
||||
val color by viewModel.color.collectAsState()
|
||||
val style by viewModel.clockStyle.collectAsState()
|
||||
val fillHeight by viewModel.fillHeight.collectAsState()
|
||||
val alignment by viewModel.alignment.collectAsState()
|
||||
|
||||
val date by viewModel.datePart.collectAsState()
|
||||
val favorites by viewModel.favoritesPart.collectAsState()
|
||||
val media by viewModel.musicPart.collectAsState()
|
||||
val alarm by viewModel.alarmPart.collectAsState()
|
||||
val battery by viewModel.batteryPart.collectAsState()
|
||||
|
||||
val dock by viewModel.dock.collectAsState()
|
||||
val parts by viewModel.parts.collectAsState()
|
||||
|
||||
BottomSheetDialog(onDismissRequest = onDismiss) {
|
||||
Column(
|
||||
@ -307,14 +298,14 @@ fun ConfigureClockWidgetSheet(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
SegmentedButton(
|
||||
selected = layout == ClockWidgetLayout.Vertical,
|
||||
selected = compact == false,
|
||||
onClick = {
|
||||
viewModel.setLayout(ClockWidgetLayout.Vertical)
|
||||
viewModel.setCompact(false)
|
||||
},
|
||||
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
|
||||
icon = {
|
||||
SegmentedButtonDefaults.Icon(
|
||||
active = layout == ClockWidgetLayout.Vertical,
|
||||
active = compact == false,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.HorizontalSplit,
|
||||
@ -327,14 +318,14 @@ fun ConfigureClockWidgetSheet(
|
||||
Text(text = stringResource(R.string.preference_clockwidget_layout_vertical))
|
||||
}
|
||||
SegmentedButton(
|
||||
selected = layout == ClockWidgetLayout.Horizontal,
|
||||
selected = compact == true,
|
||||
onClick = {
|
||||
viewModel.setLayout(ClockWidgetLayout.Horizontal)
|
||||
viewModel.setCompact(true)
|
||||
},
|
||||
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
|
||||
icon = {
|
||||
SegmentedButtonDefaults.Icon(
|
||||
active = layout == ClockWidgetLayout.Horizontal,
|
||||
active = compact == true,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.VerticalSplit,
|
||||
@ -348,9 +339,9 @@ fun ConfigureClockWidgetSheet(
|
||||
}
|
||||
}
|
||||
|
||||
if (color != null && layout != null) {
|
||||
if (color != null && compact != null) {
|
||||
WatchFaceSelector(
|
||||
layout = layout!!,
|
||||
compact = compact!!,
|
||||
colors = color!!,
|
||||
selected = style,
|
||||
onSelect = {
|
||||
@ -487,7 +478,7 @@ fun ConfigureClockWidgetSheet(
|
||||
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
||||
icon = Icons.Rounded.Star,
|
||||
value = favorites == true,
|
||||
value = dock == true,
|
||||
onValueChanged = {
|
||||
viewModel.setFavoritesPart(it)
|
||||
}
|
||||
@ -510,7 +501,7 @@ fun ConfigureClockWidgetSheet(
|
||||
title = stringResource(R.string.preference_clockwidget_date_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
||||
icon = Icons.Rounded.Today,
|
||||
value = date == true,
|
||||
value = parts?.date == true,
|
||||
onValueChanged = {
|
||||
viewModel.setDatePart(it)
|
||||
}
|
||||
@ -519,7 +510,7 @@ fun ConfigureClockWidgetSheet(
|
||||
title = stringResource(R.string.preference_clockwidget_music_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
||||
icon = Icons.Rounded.MusicNote,
|
||||
value = media == true,
|
||||
value = parts?.music == true,
|
||||
onValueChanged = {
|
||||
viewModel.setMusicPart(it)
|
||||
}
|
||||
@ -528,7 +519,7 @@ fun ConfigureClockWidgetSheet(
|
||||
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
||||
icon = Icons.Rounded.Alarm,
|
||||
value = alarm == true,
|
||||
value = parts?.alarm == true,
|
||||
onValueChanged = {
|
||||
viewModel.setAlarmPart(it)
|
||||
}
|
||||
@ -537,7 +528,7 @@ fun ConfigureClockWidgetSheet(
|
||||
title = stringResource(R.string.preference_clockwidget_battery_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
||||
icon = Icons.Rounded.BatteryFull,
|
||||
value = battery == true,
|
||||
value = parts?.battery == true,
|
||||
onValueChanged = {
|
||||
viewModel.setBatteryPart(it)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import android.provider.AlarmClock
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
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.BatteryPartProvider
|
||||
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.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
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>()
|
||||
if (it.datePart) providers += DatePartProvider()
|
||||
if (it.musicPart) providers += MusicPartProvider()
|
||||
if (it.batteryPart) providers += BatteryPartProvider()
|
||||
if (it.alarmPart) providers += AlarmPartProvider()
|
||||
if (it.date) providers += DatePartProvider()
|
||||
if (it.music) providers += MusicPartProvider()
|
||||
if (it.battery) providers += BatteryPartProvider()
|
||||
if (it.alarm) providers += AlarmPartProvider()
|
||||
providers
|
||||
}.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)
|
||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
||||
val clockStyle = settings.clockStyle
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val color = dataStore.data.map { it.clockWidget.color }
|
||||
val color = settings.color
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val alignment = dataStore.data.map { it.clockWidget.alignment }
|
||||
val alignment = settings.alignment
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val dockProvider = dataStore.data
|
||||
.map { if (it.clockWidget.favoritesPart) FavoritesPartProvider() else null }
|
||||
val dockProvider = settings.dock
|
||||
.map { if (it) FavoritesPartProvider() else null }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
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.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun WatchFaceSelector(
|
||||
layout: ClockWidgetLayout,
|
||||
compact: Boolean,
|
||||
colors: ClockWidgetColors,
|
||||
selected: ClockStyle?,
|
||||
onSelect: (ClockStyle) -> Unit,
|
||||
selected: ClockWidgetStyle?,
|
||||
onSelect: (ClockWidgetStyle) -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Surface(
|
||||
@ -73,7 +72,7 @@ fun WatchFaceSelector(
|
||||
modifier = Modifier,
|
||||
) {
|
||||
val styles = remember {
|
||||
sortedMapOf(
|
||||
mapOf(
|
||||
ClockStyle.DigitalClock1 to 0,
|
||||
ClockStyle.DigitalClock1_Outlined to 0,
|
||||
ClockStyle.DigitalClock1_MDY to 0,
|
||||
@ -159,9 +158,9 @@ fun WatchFaceSelector(
|
||||
styles.filter { it.value == pageIndex }
|
||||
}
|
||||
if (currentPageStyles.containsKey(selected)) {
|
||||
Clock(selected, layout)
|
||||
Clock(selected, compact)
|
||||
} 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) {
|
||||
ClockStyle.DigitalClock1,
|
||||
ClockStyle.DigitalClock1_Outlined,
|
||||
@ -264,11 +263,11 @@ fun getClockstyleName(context: Context, style: ClockStyle): String {
|
||||
ClockStyle.BinaryClock -> "Binary"
|
||||
ClockStyle.AnalogClock -> "Hands"
|
||||
ClockStyle.EmptyClock -> "Empty"
|
||||
ClockStyle.UNRECOGNIZED -> ""
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
fun getVariantName(context: Context, style: ClockStyle): String {
|
||||
fun getVariantName(context: Context, style: ClockWidgetStyle): String {
|
||||
return when (style) {
|
||||
ClockStyle.DigitalClock1,
|
||||
ClockStyle.DigitalClock2,
|
||||
@ -279,7 +278,20 @@ fun getVariantName(context: Context, style: ClockStyle): String {
|
||||
ClockStyle.DigitalClock1_Outlined -> "Outlined"
|
||||
ClockStyle.DigitalClock1_MDY -> "Material You"
|
||||
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.rotate
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
fun AnalogClock(
|
||||
time: Long,
|
||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
compact: Boolean,
|
||||
) {
|
||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
||||
val verticalLayout = !compact
|
||||
val date = Calendar.getInstance()
|
||||
date.timeInMillis = time
|
||||
val minute = date[Calendar.MINUTE]
|
||||
|
||||
@ -7,15 +7,14 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
fun BinaryClock(
|
||||
time: Long,
|
||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
compact: Boolean,
|
||||
) {
|
||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
||||
val verticalLayout = !compact
|
||||
val date = Calendar.getInstance()
|
||||
date.timeInMillis = time
|
||||
val minute = date[Calendar.MINUTE]
|
||||
|
||||
@ -8,7 +8,6 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
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.Stroke
|
||||
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.em
|
||||
import androidx.compose.ui.unit.sp
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||
import de.mm20.launcher2.ui.ktx.toPixels
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import java.text.SimpleDateFormat
|
||||
@ -30,10 +28,10 @@ import java.util.*
|
||||
@Composable
|
||||
fun DigitalClock1(
|
||||
time: Long,
|
||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout,
|
||||
variant: ClockStyle = ClockStyle.DigitalClock1,
|
||||
compact: Boolean,
|
||||
style: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
|
||||
) {
|
||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
||||
val verticalLayout = !compact
|
||||
val format = SimpleDateFormat(
|
||||
if (verticalLayout) {
|
||||
if (DateFormat.is24HourFormat(LocalContext.current)) "HH\nmm" else "hh\nmm"
|
||||
@ -50,8 +48,8 @@ fun DigitalClock1(
|
||||
fontWeight = FontWeight.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
lineHeight = 0.8.em,
|
||||
drawStyle = if (variant == ClockStyle.DigitalClock1_Outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
||||
color = if (variant == ClockStyle.DigitalClock1_MDY) {
|
||||
drawStyle = if (style.outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
||||
color = if (style.variant == ClockWidgetStyle.Digital1.Variant.MDY) {
|
||||
if (LocalContentColor.current == Color.White) {
|
||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||
else MaterialTheme.colorScheme.primaryContainer
|
||||
@ -64,7 +62,7 @@ fun DigitalClock1(
|
||||
|
||||
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)
|
||||
Text(
|
||||
modifier = modifier,
|
||||
|
||||
@ -6,13 +6,12 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
|
||||
|
||||
@Composable
|
||||
fun DigitalClock2(
|
||||
time: Long,
|
||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
compact: Boolean,
|
||||
) {
|
||||
Text(
|
||||
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.toOffset
|
||||
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.ZoneId
|
||||
import java.time.ZonedDateTime
|
||||
@ -46,9 +46,9 @@ private val currentTime
|
||||
@Composable
|
||||
fun OrbitClock(
|
||||
_time: Long,
|
||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
compact: Boolean,
|
||||
) {
|
||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
||||
val verticalLayout = !compact
|
||||
|
||||
val timeState = remember { mutableStateOf<ZonedDateTime>(currentTime) }
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.getSystemService
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.flow.*
|
||||
@ -71,7 +70,7 @@ class AlarmPartProvider : PartProvider {
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Component(layout: ClockWidgetLayout) {
|
||||
override fun Component(compactLayout: Boolean) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val alarmTime by nextAlarmTime
|
||||
@ -79,7 +78,7 @@ class AlarmPartProvider : PartProvider {
|
||||
|
||||
alarmTime?.let {
|
||||
|
||||
if (layout == ClockWidgetLayout.Vertical) {
|
||||
if (!compactLayout) {
|
||||
|
||||
TextButton(
|
||||
onClick = {
|
||||
|
||||
@ -20,14 +20,12 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.getSystemService
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.icons.*
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
@ -54,13 +52,13 @@ class BatteryPartProvider : PartProvider {
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Component(layout: Settings.ClockWidgetSettings.ClockWidgetLayout) {
|
||||
override fun Component(compactLayout: Boolean) {
|
||||
|
||||
val batteryInfo by this.batteryInfo.collectAsState(null)
|
||||
|
||||
batteryInfo?.let {
|
||||
|
||||
if (layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical) {
|
||||
if (!compactLayout) {
|
||||
Row(
|
||||
Modifier.padding(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
@ -86,7 +84,7 @@ class BatteryPartProvider : PartProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Horizontal) {
|
||||
if (compactLayout) {
|
||||
Row(
|
||||
Modifier.padding(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
|
||||
@ -12,7 +12,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.em
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.ui.base.LocalTime
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
@ -25,9 +24,9 @@ class DatePartProvider : PartProvider {
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Component(layout: Settings.ClockWidgetSettings.ClockWidgetLayout) {
|
||||
override fun Component(compactLayout: Boolean) {
|
||||
val time = LocalTime.current
|
||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
||||
val verticalLayout = !compactLayout
|
||||
val context = LocalContext.current
|
||||
TextButton(
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
|
||||
@ -3,16 +3,13 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
||||
import de.mm20.launcher2.widgets.CalendarWidget
|
||||
@ -27,25 +24,24 @@ class FavoritesPartProvider : PartProvider, KoinComponent {
|
||||
|
||||
private val favoritesService: FavoritesService 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 {
|
||||
emit(Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Component(layout: ClockWidgetLayout) {
|
||||
val columns by remember(layout) {
|
||||
dataStore.data.map {
|
||||
val c = it.grid.columnCount
|
||||
if (layout == ClockWidgetLayout.Horizontal) c - 2 else c
|
||||
override fun Component(compactLayout: Boolean) {
|
||||
val columns by remember {
|
||||
uiSettings.gridSettings.map {
|
||||
it.columnCount
|
||||
}
|
||||
}.collectAsState(0)
|
||||
val excludeCalendar by remember { widgetRepository.exists(CalendarWidget.Type) }.collectAsState(
|
||||
true
|
||||
)
|
||||
|
||||
val favorites by remember(columns, excludeCalendar, layout) {
|
||||
val favorites by remember(columns, excludeCalendar) {
|
||||
favoritesService.getFavorites(
|
||||
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
||||
manuallySorted = true,
|
||||
|
||||
@ -28,7 +28,6 @@ import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.music.MusicService
|
||||
import de.mm20.launcher2.music.PlaybackState
|
||||
import de.mm20.launcher2.music.SupportedActions
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import de.mm20.launcher2.ui.R
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
@ -48,7 +47,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Component(layout: ClockWidgetLayout) {
|
||||
override fun Component(compactLayout: Boolean) {
|
||||
val context = LocalContext.current
|
||||
|
||||
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)
|
||||
|
||||
if (layout === ClockWidgetLayout.Horizontal) {
|
||||
if (compactLayout) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
@ -113,7 +112,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layout === ClockWidgetLayout.Vertical) {
|
||||
if (!compactLayout) {
|
||||
Column(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
|
||||
@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface PartProvider {
|
||||
@ -12,5 +11,5 @@ interface PartProvider {
|
||||
fun setTime(time: Long) {}
|
||||
|
||||
@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.Tag
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
@ -30,6 +31,10 @@ fun FavoritesWidget(widget: FavoritesWidget) {
|
||||
|
||||
val tagsExpanded by viewModel.tagsExpanded.collectAsState(false)
|
||||
|
||||
LaunchedEffect(widget) {
|
||||
viewModel.updateWidget(widget)
|
||||
}
|
||||
|
||||
Column {
|
||||
if (favorites.isNotEmpty()) {
|
||||
SearchResultGrid(favorites)
|
||||
|
||||
@ -1,32 +1,34 @@
|
||||
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 androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import de.mm20.launcher2.ui.common.FavoritesVM
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import de.mm20.launcher2.widgets.FavoritesWidget
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
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
|
||||
|
||||
class FavoritesWidgetVM : FavoritesVM() {
|
||||
|
||||
private val widgetsService: WidgetsService by inject()
|
||||
|
||||
override val tagsExpanded: Flow<Boolean> = dataStore.data.map { it.ui.widgetTagsMultiline }
|
||||
.shareIn(viewModelScope, SharingStarted.Lazily)
|
||||
private val uiSettings: UiSettings by inject()
|
||||
|
||||
override val tagsExpanded: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
private val widget = MutableStateFlow<FavoritesWidget?>(null)
|
||||
|
||||
private val isTopWidget = widgetsService.isFavoritesWidgetFirst()
|
||||
private val clockWidgetFavSlots = dataStore.data.combine(isTopWidget) { data, isTop ->
|
||||
if (!isTop || !data.clockWidget.favoritesPart) 0
|
||||
else {
|
||||
if (data.clockWidget.layout == ClockWidgetLayout.Horizontal) data.grid.columnCount - 2
|
||||
else data.grid.columnCount
|
||||
private val clockWidgetFavSlots =
|
||||
combine(uiSettings.dock, isTopWidget, uiSettings.gridSettings) { (dock, isTop, grid) ->
|
||||
dock as Boolean
|
||||
isTop as Boolean
|
||||
grid as GridSettings
|
||||
if (!isTop || !dock) 0
|
||||
else {
|
||||
grid.columnCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val favorites = super.favorites.combine(clockWidgetFavSlots) { favs, slots ->
|
||||
if (selectedTag.value == null) {
|
||||
@ -38,17 +40,16 @@ class FavoritesWidgetVM : FavoritesVM() {
|
||||
}
|
||||
|
||||
override fun setTagsExpanded(expanded: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setUi(
|
||||
it.ui.toBuilder()
|
||||
.setWidgetTagsMultiline(expanded)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
val widget = this.widget.value ?: return
|
||||
widgetsService.updateWidget(
|
||||
widget.copy(
|
||||
config = widget.config.copy(tagsMultiline = expanded)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun updateWidget(widget: FavoritesWidget) {
|
||||
tagsExpanded.value = widget.config.tagsMultiline
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,11 +5,10 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.*
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
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.Forecast
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
@ -26,8 +25,6 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
/**
|
||||
* Index of the currently selected day in [dailyForecasts]
|
||||
*/
|
||||
@ -111,7 +108,8 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
val autoLocation = weatherSettings.autoLocation
|
||||
.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) {
|
||||
selectedDayIndex = min(index, forecasts.lastIndex)
|
||||
|
||||
@ -5,8 +5,8 @@ import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.navigation.NavController
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.GridSettings
|
||||
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||
import de.mm20.launcher2.ui.theme.WallpaperColors
|
||||
|
||||
val LocalWindowSize = compositionLocalOf { Size(0f, 0f) }
|
||||
@ -15,11 +15,11 @@ val LocalAppWidgetHost = compositionLocalOf<AppWidgetHost?>(defaultFactory = { n
|
||||
|
||||
val LocalNavController = compositionLocalOf<NavController?> { null }
|
||||
|
||||
val LocalCardStyle = compositionLocalOf<Settings.CardSettings> { Settings.CardSettings.getDefaultInstance() }
|
||||
val LocalCardStyle = compositionLocalOf { CardStyle() }
|
||||
|
||||
val LocalFavoritesEnabled = compositionLocalOf { true }
|
||||
|
||||
val LocalGridSettings = compositionLocalOf { GridSettings.newBuilder().setColumnCount(5).setShowLabels(true).setIconSize(48).build() }
|
||||
val LocalGridSettings = compositionLocalOf { GridSettings() }
|
||||
|
||||
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.buildinfo.BuildInfoSettingsScreen
|
||||
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.ThemesSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.crashreporter.CrashReportScreen
|
||||
@ -170,9 +169,6 @@ class SettingsActivity : BaseActivity() {
|
||||
composable(ROUTE_MEDIA_INTEGRATION) {
|
||||
MediaIntegrationSettingsScreen()
|
||||
}
|
||||
composable("settings/homescreen/clock") {
|
||||
ClockWidgetSettingsScreen()
|
||||
}
|
||||
composable("settings/favorites") {
|
||||
FavoritesSettingsScreen()
|
||||
}
|
||||
|
||||
@ -9,9 +9,8 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
||||
import de.mm20.launcher2.preferences.ColorScheme
|
||||
import de.mm20.launcher2.preferences.Font
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
@ -26,22 +25,22 @@ fun AppearanceSettingsScreen() {
|
||||
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
||||
val context = LocalContext.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)) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val theme by viewModel.theme.collectAsState()
|
||||
val theme by viewModel.colorScheme.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(id = R.string.preference_theme),
|
||||
items = listOf(
|
||||
stringResource(id = R.string.preference_theme_system) to Theme.System,
|
||||
stringResource(id = R.string.preference_theme_light) to Theme.Light,
|
||||
stringResource(id = R.string.preference_theme_dark) to Theme.Dark,
|
||||
stringResource(id = R.string.preference_theme_system) to ColorScheme.System,
|
||||
stringResource(id = R.string.preference_theme_light) to ColorScheme.Light,
|
||||
stringResource(id = R.string.preference_theme_dark) to ColorScheme.Dark,
|
||||
),
|
||||
value = theme,
|
||||
onValueChanged = { newValue ->
|
||||
if (newValue == null) return@ListPreference
|
||||
viewModel.setTheme(newValue)
|
||||
viewModel.setColorScheme(newValue)
|
||||
}
|
||||
)
|
||||
Preference(
|
||||
@ -55,8 +54,8 @@ fun AppearanceSettingsScreen() {
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_font),
|
||||
items = listOf(
|
||||
"Outfit" to AppearanceSettings.Font.Outfit,
|
||||
stringResource(R.string.preference_font_system) to AppearanceSettings.Font.SystemDefault,
|
||||
"Outfit" to Font.Outfit,
|
||||
stringResource(R.string.preference_font_system) to Font.System,
|
||||
),
|
||||
value = font,
|
||||
onValueChanged = {
|
||||
|
||||
@ -3,44 +3,30 @@ package de.mm20.launcher2.ui.settings.appearance
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Font
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
||||
import de.mm20.launcher2.preferences.ColorScheme
|
||||
import de.mm20.launcher2.preferences.Font
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
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.inject
|
||||
import java.util.UUID
|
||||
|
||||
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()
|
||||
|
||||
val theme = dataStore.data.map { it.appearance.theme }
|
||||
val colorScheme = uiSettings.colorScheme
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setTheme(theme: Theme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(it.appearance.toBuilder().setTheme(theme))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
fun setColorScheme(colorScheme: ColorScheme) {
|
||||
uiSettings.setColorScheme(colorScheme)
|
||||
}
|
||||
|
||||
val colorSchemeName = dataStore.data.map {
|
||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
||||
UUID.fromString(it)
|
||||
}
|
||||
}
|
||||
.flatMapLatest {
|
||||
val themeName = uiSettings.theme.flatMapLatest {
|
||||
themeRepository.getThemeOrDefault(it)
|
||||
}.map {
|
||||
it.name
|
||||
@ -48,16 +34,10 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
|
||||
val font = dataStore.data.map { it.appearance.font }
|
||||
val font = uiSettings.font
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setFont(font: Font) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(it.appearance.toBuilder().setFont(font))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setFont(font)
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.settings.buildinfo
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.accounts.AccountType
|
||||
import de.mm20.launcher2.accounts.AccountsRepository
|
||||
import de.mm20.launcher2.preferences.Settings.WeatherSettings.WeatherProvider
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import kotlinx.coroutines.flow.map
|
||||
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.unit.dp
|
||||
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.component.LauncherCard
|
||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||
@ -26,6 +28,9 @@ import de.mm20.launcher2.ui.component.preferences.SliderPreference
|
||||
@Composable
|
||||
fun CardsSettingsScreen() {
|
||||
val viewModel: CardsSettingsScreenVM = viewModel()
|
||||
|
||||
val cardStyle by viewModel.cardStyle.collectAsState(CardStyle())
|
||||
|
||||
PreferenceScreen(title = stringResource(R.string.preference_cards)) {
|
||||
item {
|
||||
Box(
|
||||
@ -43,23 +48,21 @@ fun CardsSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val shape by viewModel.shape.collectAsState()
|
||||
ListPreference(
|
||||
icon = Icons.Rounded.Rectangle,
|
||||
title = stringResource(R.string.preference_cards_shape),
|
||||
items = listOf(
|
||||
stringResource(R.string.preference_cards_shape_rounded) to Settings.CardSettings.Shape.Rounded,
|
||||
stringResource(R.string.preference_cards_shape_cut) to Settings.CardSettings.Shape.Cut,
|
||||
stringResource(R.string.preference_cards_shape_rounded) to SurfaceShape.Rounded,
|
||||
stringResource(R.string.preference_cards_shape_cut) to SurfaceShape.Cut,
|
||||
),
|
||||
value = shape,
|
||||
value = cardStyle.shape,
|
||||
onValueChanged = {
|
||||
if (it != null) viewModel.setShape(it)
|
||||
viewModel.setShape(it)
|
||||
})
|
||||
val radius by viewModel.radius.collectAsState()
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_corner_radius),
|
||||
icon = Icons.Rounded.RoundedCorner,
|
||||
value = radius,
|
||||
value = cardStyle.cornerRadius,
|
||||
min = 0,
|
||||
max = 24,
|
||||
step = 1,
|
||||
@ -67,22 +70,20 @@ fun CardsSettingsScreen() {
|
||||
viewModel.setRadius(it)
|
||||
}
|
||||
)
|
||||
val opacity by viewModel.opacity.collectAsState()
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_opacity),
|
||||
icon = Icons.Rounded.Opacity,
|
||||
value = opacity,
|
||||
value = cardStyle.opacity,
|
||||
min = 0f,
|
||||
max = 1f,
|
||||
onValueChanged = {
|
||||
viewModel.setOpacity(it)
|
||||
}
|
||||
)
|
||||
val borderWidth by viewModel.borderWidth.collectAsState()
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_stroke_width),
|
||||
icon = Icons.Rounded.LineWeight,
|
||||
value = borderWidth,
|
||||
value = cardStyle.borderWidth,
|
||||
min = 0,
|
||||
max = 8,
|
||||
step = 1,
|
||||
|
||||
@ -1,70 +1,29 @@
|
||||
package de.mm20.launcher2.ui.settings.cards
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
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 de.mm20.launcher2.preferences.SurfaceShape
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class CardsSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
class CardsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
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) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setCards(it.cards.toBuilder()
|
||||
.setOpacity(opacity)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
uiSettings.setCardOpacity(opacity)
|
||||
}
|
||||
|
||||
val radius = dataStore.data.map { it.cards.radius }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||
|
||||
fun setRadius(radius: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setCards(it.cards.toBuilder()
|
||||
.setRadius(radius)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
uiSettings.setCardRadius(radius)
|
||||
}
|
||||
|
||||
val borderWidth = dataStore.data.map { it.cards.borderWidth }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||
fun setBorderWidth(borderWidth: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setCards(it.cards.toBuilder()
|
||||
.setBorderWidth(borderWidth)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
uiSettings.setCardBorderWidth(borderWidth)
|
||||
}
|
||||
|
||||
val shape = dataStore.data.map { it.cards.shape }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setShape(shape: Settings.CardSettings.Shape) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setCards(it.cards.toBuilder()
|
||||
.setShape(shape)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
fun setShape(shape: SurfaceShape) {
|
||||
uiSettings.setCardShape(shape)
|
||||
}
|
||||
}
|
||||
@ -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.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
||||
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@ -13,146 +14,62 @@ import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
val layout = dataStore.data.map { it.clockWidget.layout }
|
||||
private val settings: ClockWidgetSettings by inject()
|
||||
val compact = settings.compact
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLayout(layout: ClockWidgetSettings.ClockWidgetLayout) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setLayout(layout)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
fun setCompact(compact: Boolean) {
|
||||
settings.setCompact(compact)
|
||||
}
|
||||
|
||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
||||
val clockStyle = settings.clockStyle
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setClockStyle(clockStyle: ClockWidgetSettings.ClockStyle) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setClockStyle(clockStyle)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
fun setClockStyle(clockStyle: ClockWidgetStyle) {
|
||||
settings.setClockStyle(clockStyle)
|
||||
}
|
||||
|
||||
val color = dataStore.data.map { it.clockWidget.color }
|
||||
val color = settings.color
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setColor(color: ClockWidgetColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setColor(color)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
settings.setColor(color)
|
||||
}
|
||||
|
||||
val fillHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
||||
val fillHeight = settings.fillHeight
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFillHeight(fillHeight: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setFillHeight(fillHeight)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
settings.setFillHeight(fillHeight)
|
||||
}
|
||||
|
||||
val datePart = dataStore.data.map { it.clockWidget.datePart }
|
||||
val dock = settings.dock
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val parts = settings.parts
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setDatePart(datePart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setDatePart(datePart)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
settings.setDatePart(datePart)
|
||||
}
|
||||
|
||||
val favoritesPart = dataStore.data.map { it.clockWidget.favoritesPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFavoritesPart(favoritesPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setFavoritesPart(favoritesPart)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
settings.setDock(favoritesPart)
|
||||
}
|
||||
|
||||
val batteryPart = dataStore.data.map { it.clockWidget.batteryPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setBatteryPart(batteryPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setBatteryPart(batteryPart)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
settings.setBatteryPart(batteryPart)
|
||||
}
|
||||
|
||||
val musicPart = dataStore.data.map { it.clockWidget.musicPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setMusicPart(musicPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setMusicPart(musicPart)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
settings.setMusicPart(musicPart)
|
||||
}
|
||||
|
||||
val alarmPart = dataStore.data.map { it.clockWidget.alarmPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setAlarmPart(alarmPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setAlarmPart(alarmPart)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
settings.setAlarmPart(alarmPart)
|
||||
}
|
||||
|
||||
val alignment = dataStore.data.map { it.clockWidget.alignment }
|
||||
val alignment = settings.alignment
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setAlignment(alignment: ClockWidgetSettings.ClockWidgetAlignment) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setClockWidget(
|
||||
it.clockWidget.toBuilder()
|
||||
.setAlignment(alignment)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
fun setAlignment(alignment: ClockWidgetAlignment) {
|
||||
settings.setAlignment(alignment)
|
||||
}
|
||||
}
|
||||
@ -2,24 +2,20 @@ package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.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.Theme
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.themes.fromJson
|
||||
import de.mm20.launcher2.themes.toJson
|
||||
import de.mm20.launcher2.ui.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -31,12 +27,14 @@ import java.util.UUID
|
||||
class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
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 {
|
||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
||||
UUID.fromString(it)
|
||||
} ?: DefaultThemeId
|
||||
val selectedTheme = uiSettings.theme.map {
|
||||
when(it) {
|
||||
ThemeDescriptor.Default -> DefaultThemeId
|
||||
ThemeDescriptor.BlackAndWhite -> BlackAndWhiteThemeId
|
||||
is ThemeDescriptor.Custom -> UUID.fromString(it.id)
|
||||
}
|
||||
}
|
||||
val themes: Flow<List<Theme>> = themeRepository.getThemes()
|
||||
|
||||
@ -49,15 +47,10 @@ class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun selectTheme(theme: Theme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setThemeId(theme.id.toString())
|
||||
)
|
||||
.build()
|
||||
}
|
||||
when(theme.id) {
|
||||
DefaultThemeId -> ThemeDescriptor.Default
|
||||
BlackAndWhiteThemeId -> ThemeDescriptor.BlackAndWhite
|
||||
else -> ThemeDescriptor.Custom(theme.id.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,24 +2,20 @@ package de.mm20.launcher2.ui.settings.easteregg
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
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)
|
||||
fun setEasterEgg(easterEgg: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setEasterEgg(easterEgg).build()
|
||||
}
|
||||
}
|
||||
settings.setIconShape(if (easterEgg) IconShape.EasterEgg else IconShape.PlatformDefault)
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.component.preferences.ListPreference
|
||||
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.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
||||
import de.mm20.launcher2.preferences.WeightFactor
|
||||
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||
import de.mm20.launcher2.preferences.search.RankingSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@ -12,65 +13,30 @@ import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
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)
|
||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setFavorites(
|
||||
it.favorites.toBuilder()
|
||||
.setFrequentlyUsed(frequentlyUsed)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
favoritesSettings.setFrequentlyUsed(frequentlyUsed)
|
||||
}
|
||||
|
||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
||||
val frequentlyUsedRows = favoritesSettings.frequentlyUsedRows
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
|
||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setFavorites(
|
||||
it.favorites.toBuilder()
|
||||
.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
favoritesSettings.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||
}
|
||||
|
||||
val editButton = dataStore.data.map { it.favorites.editButton }
|
||||
val editButton = favoritesSettings.showEditButton
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setEditButton(editButton: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setFavorites(
|
||||
it.favorites.toBuilder()
|
||||
.setEditButton(editButton)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
favoritesSettings.setShowEditButton(editButton)
|
||||
}
|
||||
|
||||
val searchResultWeightFactor = dataStore.data.map { it.resultOrdering.weightFactor }
|
||||
val searchResultWeightFactor = rankingSettings.weightFactor
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), WeightFactor.Default)
|
||||
fun setSearchResultWeightFactor(searchResultWeightFactor: WeightFactor) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setResultOrdering(
|
||||
it.resultOrdering.toBuilder()
|
||||
.setWeightFactor(searchResultWeightFactor)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
rankingSettings.setWeightFactor(searchResultWeightFactor)
|
||||
}
|
||||
}
|
||||
@ -7,11 +7,11 @@ import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.accounts.Account
|
||||
import de.mm20.launcher2.accounts.AccountType
|
||||
import de.mm20.launcher2.accounts.AccountsRepository
|
||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.plugin.PluginType
|
||||
import de.mm20.launcher2.plugins.PluginService
|
||||
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@ -27,8 +27,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
|
||||
import de.mm20.launcher2.preferences.BaseLayout
|
||||
import de.mm20.launcher2.preferences.GestureAction
|
||||
import de.mm20.launcher2.preferences.LegacySettings.LayoutSettings.Layout
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.common.SearchablePicker
|
||||
@ -47,14 +48,14 @@ fun GestureSettingsScreen() {
|
||||
val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null)
|
||||
|
||||
val options = buildList {
|
||||
add(stringResource(R.string.gesture_action_none) to GestureAction.None)
|
||||
add(stringResource(R.string.gesture_action_notifications) to GestureAction.OpenNotificationDrawer)
|
||||
add(stringResource(R.string.gesture_action_quick_settings) to GestureAction.OpenQuickSettings)
|
||||
if (isAtLeastApiLevel(28)) add(stringResource(R.string.gesture_action_lock_screen) to GestureAction.LockScreen)
|
||||
add(stringResource(R.string.gesture_action_recents) to GestureAction.OpenRecents)
|
||||
add(stringResource(R.string.gesture_action_power_menu) to GestureAction.OpenPowerDialog)
|
||||
add(stringResource(R.string.gesture_action_open_search) to GestureAction.OpenSearch)
|
||||
add(stringResource(R.string.gesture_action_launch_app) to GestureAction.LaunchApp)
|
||||
add(stringResource(R.string.gesture_action_none) to GestureAction.NoAction)
|
||||
add(stringResource(R.string.gesture_action_notifications) to GestureAction.Notifications)
|
||||
add(stringResource(R.string.gesture_action_quick_settings) to GestureAction.QuickSettings)
|
||||
if (isAtLeastApiLevel(28)) add(stringResource(R.string.gesture_action_lock_screen) to GestureAction.ScreenLock)
|
||||
add(stringResource(R.string.gesture_action_recents) to GestureAction.Recents)
|
||||
add(stringResource(R.string.gesture_action_power_menu) to GestureAction.PowerMenu)
|
||||
add(stringResource(R.string.gesture_action_open_search) to GestureAction.Search)
|
||||
add(stringResource(R.string.gesture_action_launch_app) to GestureAction.Launch(null))
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
@ -64,9 +65,9 @@ fun GestureSettingsScreen() {
|
||||
val baseLayout by viewModel.baseLayout.collectAsStateWithLifecycle(null)
|
||||
ListPreference(title = stringResource(R.string.preference_layout_open_search),
|
||||
items = listOf(
|
||||
stringResource(R.string.open_search_pull_down) to Layout.PullDown,
|
||||
stringResource(R.string.open_search_swipe_left) to Layout.Pager,
|
||||
stringResource(R.string.open_search_swipe_right) to Layout.PagerReversed,
|
||||
stringResource(R.string.open_search_pull_down) to BaseLayout.PullDown,
|
||||
stringResource(R.string.open_search_swipe_left) to BaseLayout.Pager,
|
||||
stringResource(R.string.open_search_swipe_right) to BaseLayout.PagerReversed,
|
||||
),
|
||||
value = baseLayout,
|
||||
onValueChanged = {
|
||||
@ -125,7 +126,7 @@ fun GestureSettingsScreen() {
|
||||
)
|
||||
|
||||
val swipeDown by viewModel.swipeDown.collectAsStateWithLifecycle(null)
|
||||
val swipeDownIsSearch = layout == Layout.PullDown
|
||||
val swipeDownIsSearch = layout == BaseLayout.PullDown
|
||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeDown) && !swipeDownIsSearch) {
|
||||
MissingPermissionBanner(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
@ -149,7 +150,7 @@ fun GestureSettingsScreen() {
|
||||
)
|
||||
|
||||
val swipeLeft by viewModel.swipeLeft.collectAsStateWithLifecycle(null)
|
||||
val swipeLeftIsSearch = layout == Layout.Pager
|
||||
val swipeLeftIsSearch = layout == BaseLayout.Pager
|
||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeLeft) && !swipeLeftIsSearch) {
|
||||
MissingPermissionBanner(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
@ -173,7 +174,7 @@ fun GestureSettingsScreen() {
|
||||
)
|
||||
|
||||
val swipeRight by viewModel.swipeRight.collectAsStateWithLifecycle(null)
|
||||
val swipeRightIsSearch = layout == Layout.PagerReversed
|
||||
val swipeRightIsSearch = layout == BaseLayout.PagerReversed
|
||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeRight) && !swipeRightIsSearch) {
|
||||
MissingPermissionBanner(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
@ -225,11 +226,11 @@ fun GestureSettingsScreen() {
|
||||
|
||||
fun requiresAccessibilityService(action: GestureAction?): Boolean {
|
||||
return when (action) {
|
||||
GestureAction.OpenNotificationDrawer,
|
||||
GestureAction.LockScreen,
|
||||
GestureAction.OpenQuickSettings,
|
||||
GestureAction.OpenRecents,
|
||||
GestureAction.OpenPowerDialog -> true
|
||||
is GestureAction.Notifications,
|
||||
is GestureAction.ScreenLock,
|
||||
is GestureAction.QuickSettings,
|
||||
is GestureAction.Recents,
|
||||
is GestureAction.PowerMenu -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@ -256,12 +257,12 @@ fun GesturePreference(
|
||||
title = title,
|
||||
enabled = !isOpenSearch,
|
||||
items = options,
|
||||
value = if (isOpenSearch) GestureAction.OpenSearch else value,
|
||||
value = if (isOpenSearch) GestureAction.Search else value,
|
||||
onValueChanged = { if (it != null) onValueChanged(it) }
|
||||
)
|
||||
}
|
||||
|
||||
if (value == GestureAction.LaunchApp && !isOpenSearch) {
|
||||
if (value is GestureAction.Launch && !isOpenSearch) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.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(
|
||||
title = { Text(title) },
|
||||
onDismissRequest = {
|
||||
showAppPicker = false
|
||||
if (app == null) onValueChanged(GestureAction.None)
|
||||
if (app == null) onValueChanged(GestureAction.NoAction)
|
||||
},
|
||||
value = app,
|
||||
onValueChanged = {
|
||||
|
||||
@ -3,15 +3,16 @@ package de.mm20.launcher2.ui.settings.gestures
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
||||
import de.mm20.launcher2.preferences.BaseLayout
|
||||
import de.mm20.launcher2.preferences.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.searchable.SavableSearchableRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
@ -22,7 +23,8 @@ import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
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 searchableRepository: SavableSearchableRepository by inject()
|
||||
private val iconService: IconService by inject()
|
||||
@ -30,208 +32,124 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
||||
val baseLayout = uiSettings.baseLayout
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setBaseLayout(baseLayout: Settings.LayoutSettings.Layout) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setLayout(it.layout.toBuilder().setBaseLayout(baseLayout))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
fun setBaseLayout(baseLayout: BaseLayout) {
|
||||
uiSettings.setBaseLayout(baseLayout)
|
||||
}
|
||||
|
||||
val swipeDown = dataStore.data.map { it.gestures.swipeDown }
|
||||
|
||||
val swipeDown = gestureSettings.swipeDown
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val swipeLeft = dataStore.data.map { it.gestures.swipeLeft }
|
||||
val swipeLeft = gestureSettings.swipeLeft
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val swipeRight = dataStore.data.map { it.gestures.swipeRight }
|
||||
val swipeRight = gestureSettings.swipeRight
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val doubleTap = dataStore.data.map { it.gestures.doubleTap }
|
||||
val doubleTap = gestureSettings.doubleTap
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val longPress = dataStore.data.map { it.gestures.longPress }
|
||||
val longPress = gestureSettings.longPress
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val homeButton = dataStore.data.map { it.gestures.homeButton }
|
||||
val homeButton = gestureSettings.homeButton
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setSwipeDown(action: GestureAction) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeDown(action).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
gestureSettings.setSwipeDown(action)
|
||||
}
|
||||
|
||||
fun setSwipeLeft(action: GestureAction) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeLeft(action).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
gestureSettings.setSwipeLeft(action)
|
||||
}
|
||||
|
||||
fun setSwipeRight(action: GestureAction) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeRight(action).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
gestureSettings.setSwipeRight(action)
|
||||
}
|
||||
|
||||
fun setDoubleTap(action: GestureAction) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setGestures(it.gestures.toBuilder().setDoubleTap(action).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
gestureSettings.setDoubleTap(action)
|
||||
}
|
||||
|
||||
fun setLongPress(action: GestureAction) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setGestures(it.gestures.toBuilder().setLongPress(action).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
gestureSettings.setLongPress(action)
|
||||
}
|
||||
|
||||
fun setHomeButton(action: GestureAction) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setGestures(it.gestures.toBuilder().setHomeButton(action).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
gestureSettings.setHomeButton(action)
|
||||
}
|
||||
|
||||
val swipeLeftApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeLeftApp }
|
||||
val swipeLeftApp: Flow<SavableSearchable?> = swipeLeft
|
||||
.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)
|
||||
|
||||
fun setSwipeLeftApp(searchable: SavableSearchable?) {
|
||||
viewModelScope.launch {
|
||||
searchable?.let { searchableRepository.insert(it) }
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGestures(it.gestures.toBuilder()
|
||||
.setSwipeLeftApp(searchable?.key ?: "")
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||
setSwipeLeft(GestureAction.Launch(searchable.key))
|
||||
}
|
||||
|
||||
val swipeRightApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeRightApp }
|
||||
val swipeRightApp: Flow<SavableSearchable?> = swipeRight
|
||||
.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)
|
||||
|
||||
fun setSwipeRightApp(searchable: SavableSearchable?) {
|
||||
viewModelScope.launch {
|
||||
searchable?.let { searchableRepository.insert(it) }
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGestures(it.gestures.toBuilder()
|
||||
.setSwipeRightApp(searchable?.key ?: "")
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||
setSwipeRight(GestureAction.Launch(searchable.key))
|
||||
}
|
||||
|
||||
val swipeDownApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeDownApp }
|
||||
val swipeDownApp: Flow<SavableSearchable?> = swipeDown
|
||||
.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)
|
||||
|
||||
fun setSwipeDownApp(searchable: SavableSearchable?) {
|
||||
viewModelScope.launch {
|
||||
searchable?.let { searchableRepository.insert(it) }
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGestures(it.gestures.toBuilder()
|
||||
.setSwipeDownApp(searchable?.key ?: "")
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||
setSwipeDown(GestureAction.Launch(searchable.key))
|
||||
}
|
||||
|
||||
val longPressApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.longPressApp }
|
||||
val longPressApp: Flow<SavableSearchable?> = longPress
|
||||
.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)
|
||||
|
||||
fun setLongPressApp(searchable: SavableSearchable?) {
|
||||
viewModelScope.launch {
|
||||
searchable?.let { searchableRepository.insert(it) }
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGestures(it.gestures.toBuilder()
|
||||
.setLongPressApp(searchable?.key ?: "")
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||
setLongPress(GestureAction.Launch(searchable.key))
|
||||
}
|
||||
|
||||
val doubleTapApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.doubleTapApp }
|
||||
val doubleTapApp: Flow<SavableSearchable?> = doubleTap
|
||||
.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)
|
||||
|
||||
fun setDoubleTapApp(searchable: SavableSearchable?) {
|
||||
viewModelScope.launch {
|
||||
searchable?.let { searchableRepository.insert(it) }
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGestures(it.gestures.toBuilder()
|
||||
.setDoubleTapApp(searchable?.key ?: "")
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||
setDoubleTap(GestureAction.Launch(searchable.key))
|
||||
}
|
||||
|
||||
val homeButtonApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.homeButtonApp }
|
||||
val homeButtonApp: Flow<SavableSearchable?> = homeButton
|
||||
.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)
|
||||
|
||||
fun setHomeButtonApp(searchable: SavableSearchable?) {
|
||||
viewModelScope.launch {
|
||||
searchable?.let { searchableRepository.insert(it) }
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGestures(it.gestures.toBuilder()
|
||||
.setHomeButtonApp(searchable?.key ?: "")
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||
setHomeButton(GestureAction.Launch(searchable.key))
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun requestPermission(context: AppCompatActivity) {
|
||||
permissionsManager.requestPermission(context, PermissionGroup.Accessibility)
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
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.Application
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -29,7 +29,7 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val appRepository: AppRepository by inject()
|
||||
private val searchableRepository: SavableSearchableRepository 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 {
|
||||
withContext(Dispatchers.Default) { it.sorted() }
|
||||
@ -68,16 +68,10 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
app.openAppDetails(context)
|
||||
}
|
||||
|
||||
val hiddenItemsButton = dataStore.data.map { it.searchBar.hiddenItemsButton }
|
||||
val hiddenItemsButton = searchUiSettings.hiddenItemsButton
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
fun setHiddenItemsButton(hidden: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setSearchBar(it.searchBar.toBuilder().setHiddenItemsButton(hidden)).build()
|
||||
|
||||
}
|
||||
}
|
||||
searchUiSettings.setHiddenItemsButton(hidden)
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,10 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
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.component.SearchBar
|
||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||
@ -109,14 +112,14 @@ fun HomescreenSettingsScreen() {
|
||||
viewModel.setSearchBarStyle(it)
|
||||
}
|
||||
)
|
||||
AnimatedVisibility(searchBarStyle == Settings.SearchBarSettings.SearchBarStyle.Transparent) {
|
||||
AnimatedVisibility(searchBarStyle == SearchBarStyle.Transparent) {
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_search_bar_color),
|
||||
value = searchBarColor,
|
||||
items = listOf(
|
||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SearchBarSettings.SearchBarColors.Auto,
|
||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SearchBarSettings.SearchBarColors.Light,
|
||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SearchBarSettings.SearchBarColors.Dark,
|
||||
stringResource(R.string.preference_system_bar_icons_auto) to SearchBarColors.Auto,
|
||||
stringResource(R.string.preference_system_bar_icons_light) to SearchBarColors.Light,
|
||||
stringResource(R.string.preference_system_bar_icons_dark) to SearchBarColors.Dark,
|
||||
),
|
||||
onValueChanged = {
|
||||
if (it != null) viewModel.setSearchBarColor(it)
|
||||
@ -208,9 +211,9 @@ fun HomescreenSettingsScreen() {
|
||||
title = stringResource(R.string.preference_status_bar_icons),
|
||||
value = lightStatusBar,
|
||||
items = listOf(
|
||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
|
||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
|
||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
|
||||
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
|
||||
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
|
||||
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
|
||||
),
|
||||
onValueChanged = {
|
||||
if (it != null) viewModel.setLightStatusBar(it)
|
||||
@ -220,9 +223,9 @@ fun HomescreenSettingsScreen() {
|
||||
title = stringResource(R.string.preference_nav_bar_icons),
|
||||
value = lightNavBar,
|
||||
items = listOf(
|
||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
|
||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
|
||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
|
||||
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
|
||||
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
|
||||
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
|
||||
),
|
||||
onValueChanged = {
|
||||
if (it != null) viewModel.setLightNavBar(it)
|
||||
@ -255,15 +258,14 @@ fun HomescreenSettingsScreen() {
|
||||
fun SearchBarStylePreference(
|
||||
title: String,
|
||||
summary: String? = null,
|
||||
value: Settings.SearchBarSettings.SearchBarStyle?,
|
||||
onValueChanged: (Settings.SearchBarSettings.SearchBarStyle) -> Unit
|
||||
value: SearchBarStyle?,
|
||||
onValueChanged: (SearchBarStyle) -> Unit
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
||||
if (showDialog && value != null) {
|
||||
val styles = remember {
|
||||
Settings.SearchBarSettings.SearchBarStyle.values()
|
||||
.filter { it != Settings.SearchBarSettings.SearchBarStyle.UNRECOGNIZED }
|
||||
SearchBarStyle.entries
|
||||
}
|
||||
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.viewModelFactory
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
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.SystemBarColors
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@ -23,52 +27,31 @@ import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
class HomescreenSettingsScreenVM(
|
||||
private val dataStore: LauncherDataStore,
|
||||
private val uiSettings: UiSettings,
|
||||
) : ViewModel() {
|
||||
|
||||
var showClockWidgetSheet by mutableStateOf(false)
|
||||
|
||||
|
||||
val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }
|
||||
val dimWallpaper = uiSettings.dimWallpaper
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
fun setDimWallpaper(dimWallpaper: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setDimWallpaper(dimWallpaper)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
uiSettings.setDimWallpaper(dimWallpaper)
|
||||
}
|
||||
|
||||
val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper }
|
||||
val blurWallpaper = uiSettings.blurWallpaper
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
fun setBlurWallpaper(blurWallpaper: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setBlurWallpaper(blurWallpaper)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
uiSettings.setBlurWallpaper(blurWallpaper)
|
||||
}
|
||||
|
||||
val blurWallpaperRadius = dataStore.data.map { it.appearance.blurWallpaperRadius }
|
||||
val blurWallpaperRadius = uiSettings.wallpaperBlurRadius
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
||||
|
||||
fun setBlurWallpaperRadius(blurWallpaperRadius: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setBlurWallpaperRadius(blurWallpaperRadius)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
uiSettings.setWallpaperBlurRadius(blurWallpaperRadius)
|
||||
}
|
||||
|
||||
fun openWallpaperChooser(context: AppCompatActivity) {
|
||||
@ -80,168 +63,88 @@ class HomescreenSettingsScreenVM(
|
||||
return context.getSystemService<WindowManager>()?.isCrossWindowBlurEnabled == true
|
||||
}
|
||||
|
||||
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }
|
||||
val statusBarIcons = uiSettings.statusBarColor
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLightStatusBar(statusBarColor: Settings.SystemBarsSettings.SystemBarColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setSystemBars(
|
||||
it.systemBars.toBuilder()
|
||||
.setStatusBarColor(statusBarColor)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
fun setLightStatusBar(statusBarColor: SystemBarColors) {
|
||||
uiSettings.setStatusBarColor(statusBarColor)
|
||||
}
|
||||
|
||||
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }
|
||||
val navBarIcons = uiSettings.navigationBarColor
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLightNavBar(navBarColors: Settings.SystemBarsSettings.SystemBarColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setSystemBars(
|
||||
it.systemBars.toBuilder()
|
||||
.setNavBarColor(navBarColors)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
fun setLightNavBar(navBarColors: SystemBarColors) {
|
||||
uiSettings.setNavigationBarColor(navBarColors)
|
||||
}
|
||||
|
||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
||||
val hideStatusBar = uiSettings.hideStatusBar
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setHideStatusBar(hideStatusBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setSystemBars(
|
||||
it.systemBars.toBuilder()
|
||||
.setHideStatusBar(hideStatusBar)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setHideStatusBar(hideStatusBar)
|
||||
}
|
||||
|
||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
||||
val hideNavBar = uiSettings.hideNavigationBar
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setHideNavBar(hideNavBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setSystemBars(
|
||||
it.systemBars.toBuilder()
|
||||
.setHideNavBar(hideNavBar)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setHideNavigationBar(hideNavBar)
|
||||
}
|
||||
|
||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
||||
val searchBarColor = uiSettings.searchBarColor
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setSearchBarColor(color: Settings.SearchBarSettings.SearchBarColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setSearchBar(
|
||||
it.searchBar.toBuilder()
|
||||
.setColor(color)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
fun setSearchBarColor(color: SearchBarColors) {
|
||||
uiSettings.setSearchBarColor(color)
|
||||
}
|
||||
|
||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
||||
val searchBarStyle = uiSettings.searchBarStyle
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setSearchBarStyle(searchBarStyle: Settings.SearchBarSettings.SearchBarStyle) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setSearchBar(
|
||||
it.searchBar.toBuilder()
|
||||
.setSearchBarStyle(searchBarStyle)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
fun setSearchBarStyle(searchBarStyle: SearchBarStyle) {
|
||||
uiSettings.setSearchBarStyle(searchBarStyle)
|
||||
}
|
||||
|
||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
||||
val fixedSearchBar = uiSettings.fixedSearchBar
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setFixedSearchBar(fixedSearchBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setLayout(it.layout.toBuilder().setFixedSearchBar(fixedSearchBar))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setFixedSearchBar(fixedSearchBar)
|
||||
}
|
||||
|
||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
||||
val bottomSearchBar = uiSettings.bottomSearchBar
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setBottomSearchBar(bottomSearchBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setLayout(it.layout.toBuilder().setBottomSearchBar(bottomSearchBar))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setBottomSearchBar(bottomSearchBar)
|
||||
}
|
||||
|
||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
|
||||
val fixedRotation = uiSettings.orientation.map { it != ScreenOrientation.Auto }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setFixedRotation(fixedRotation: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setLayout(it.layout.toBuilder().setFixedRotation(fixedRotation))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setOrientation(if (fixedRotation) ScreenOrientation.Portrait else ScreenOrientation.Auto)
|
||||
}
|
||||
|
||||
val widgetEditButton = dataStore.data.map { it.widgets.editButton }
|
||||
val widgetEditButton = uiSettings.widgetEditButton
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setWidgetEditButton(editButton: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setWidgets(
|
||||
it.widgets.toBuilder()
|
||||
.setEditButton(editButton)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setWidgetEditButton(editButton)
|
||||
}
|
||||
|
||||
val chargingAnimation = dataStore.data.map { it.animations.charging }
|
||||
val chargingAnimation = uiSettings.chargingAnimation
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setChargingAnimation(chargingAnimation: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAnimations(
|
||||
it.animations.toBuilder()
|
||||
.setCharging(chargingAnimation)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setChargingAnimation(chargingAnimation)
|
||||
}
|
||||
|
||||
companion object : KoinComponent {
|
||||
val Factory = viewModelFactory {
|
||||
initializer {
|
||||
HomescreenSettingsScreenVM(
|
||||
dataStore = get()
|
||||
uiSettings = get()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ import androidx.compose.material3.FilledIconToggleButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.PlainTooltipBox
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
@ -50,7 +49,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.icons.StaticIconLayer
|
||||
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.component.MissingPermissionBanner
|
||||
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.label
|
||||
import de.mm20.launcher2.ui.component.preferences.value
|
||||
import de.mm20.launcher2.ui.ktx.toPixels
|
||||
|
||||
@Composable
|
||||
fun IconsSettingsScreen() {
|
||||
val viewModel: IconsSettingsScreenVM = viewModel(factory = IconsSettingsScreenVM.Factory)
|
||||
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 showLabels by viewModel.showLabels.collectAsStateWithLifecycle(null)
|
||||
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 iconShape by viewModel.iconShape.collectAsStateWithLifecycle(IconShape.PlatformDefault)
|
||||
|
||||
val iconPackPackage by viewModel.iconPack.collectAsStateWithLifecycle(null)
|
||||
val iconPackThemed by viewModel.iconPackThemed.collectAsState(true)
|
||||
val installedIconPacks by viewModel.installedIconPacks.collectAsState(emptyList())
|
||||
val forceThemedIcons by viewModel.forceThemedIcons.collectAsStateWithLifecycle(null)
|
||||
|
||||
val hasNotificationsPermission by viewModel.hasNotificationsPermission.collectAsStateWithLifecycle(null)
|
||||
|
||||
@ -91,8 +86,8 @@ fun IconsSettingsScreen() {
|
||||
val shortcutBadges by viewModel.shortcutBadges.collectAsStateWithLifecycle(null)
|
||||
val pluginBadges by viewModel.pluginBadges.collectAsStateWithLifecycle(null)
|
||||
|
||||
val previewIcons by remember(iconSize) {
|
||||
viewModel.getPreviewIcons(with(density) { iconSize.dp.toPx() }.toInt())
|
||||
val previewIcons by remember(grid?.iconSize) {
|
||||
viewModel.getPreviewIcons(with(density) { grid.iconSize.dp.toPx() }.toInt())
|
||||
}.collectAsState(
|
||||
emptyList()
|
||||
)
|
||||
@ -102,7 +97,7 @@ fun IconsSettingsScreen() {
|
||||
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_grid_icon_size),
|
||||
value = iconSize,
|
||||
value = grid.iconSize,
|
||||
step = 8,
|
||||
min = 32,
|
||||
max = 64,
|
||||
@ -113,14 +108,14 @@ fun IconsSettingsScreen() {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_grid_labels),
|
||||
summary = stringResource(R.string.preference_grid_labels_summary),
|
||||
value = showLabels == true,
|
||||
value = grid.showLabels,
|
||||
onValueChanged = {
|
||||
viewModel.setShowLabels(it)
|
||||
}
|
||||
)
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_grid_column_count),
|
||||
value = columnCount,
|
||||
value = grid.columnCount,
|
||||
min = 3,
|
||||
max = 12,
|
||||
onValueChanged = {
|
||||
@ -148,7 +143,7 @@ fun IconsSettingsScreen() {
|
||||
modifier = Modifier.weight(1f),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
ShapedLauncherIcon(size = iconSize.dp, icon = { icon })
|
||||
ShapedLauncherIcon(size = grid.iconSize.dp, icon = { icon })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,7 +160,7 @@ fun IconsSettingsScreen() {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_enforce_icon_shape),
|
||||
summary = stringResource(R.string.preference_enforce_icon_shape_summary),
|
||||
value = adaptifyLegacyIcons == true,
|
||||
value = icons?.adaptify == true,
|
||||
onValueChanged = {
|
||||
viewModel.setAdaptifyLegacyIcons(it)
|
||||
}
|
||||
@ -173,7 +168,7 @@ fun IconsSettingsScreen() {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_themed_icons),
|
||||
summary = stringResource(R.string.preference_themed_icons_summary),
|
||||
value = themedIcons == true,
|
||||
value = icons?.themedIcons == true,
|
||||
onValueChanged = {
|
||||
viewModel.setThemedIcons(it)
|
||||
}
|
||||
@ -181,14 +176,14 @@ fun IconsSettingsScreen() {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_force_themed_icons),
|
||||
summary = stringResource(R.string.preference_force_themed_icons_summary),
|
||||
value = forceThemedIcons == true,
|
||||
enabled = themedIcons == true,
|
||||
value = icons?.forceThemed == true,
|
||||
enabled = icons?.themedIcons == true,
|
||||
onValueChanged = {
|
||||
viewModel.setForceThemedIcons(it)
|
||||
}
|
||||
)
|
||||
val iconPack by remember {
|
||||
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == iconPackPackage } }
|
||||
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == icons?.iconPack } }
|
||||
}
|
||||
val items = installedIconPacks.map {
|
||||
it.name to it
|
||||
@ -265,7 +260,7 @@ fun IconsSettingsScreen() {
|
||||
PlainTooltipBox(tooltip = { Text(stringResource(R.string.icon_pack_dynamic_colors)) }) {
|
||||
FilledIconToggleButton(
|
||||
modifier = Modifier.tooltipTrigger(),
|
||||
checked = iconPackThemed,
|
||||
checked = icons?.iconPackThemed == true,
|
||||
onCheckedChange = {
|
||||
viewModel.setIconPackThemed(it)
|
||||
}) {
|
||||
@ -347,16 +342,16 @@ fun IconsSettingsScreen() {
|
||||
fun IconShapePreference(
|
||||
title: String,
|
||||
summary: String? = null,
|
||||
value: Settings.IconSettings.IconShape?,
|
||||
onValueChanged: (Settings.IconSettings.IconShape) -> Unit
|
||||
value: IconShape?,
|
||||
onValueChanged: (IconShape) -> Unit
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
||||
|
||||
if (showDialog && value != null) {
|
||||
val shapes = remember {
|
||||
Settings.IconSettings.IconShape.values()
|
||||
.filter { it != Settings.IconSettings.IconShape.UNRECOGNIZED && it != Settings.IconSettings.IconShape.EasterEgg }
|
||||
IconShape.entries
|
||||
.filter { it != IconShape.EasterEgg }
|
||||
}
|
||||
Dialog(onDismissRequest = { showDialog = false }) {
|
||||
Surface(
|
||||
@ -431,19 +426,19 @@ fun IconShapePreference(
|
||||
|
||||
|
||||
@Composable
|
||||
private fun getShapeName(shape: Settings.IconSettings.IconShape?): String? {
|
||||
private fun getShapeName(shape: IconShape?): String? {
|
||||
return stringResource(
|
||||
when (shape) {
|
||||
Settings.IconSettings.IconShape.Triangle -> R.string.preference_icon_shape_triangle
|
||||
Settings.IconSettings.IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
|
||||
Settings.IconSettings.IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
|
||||
Settings.IconSettings.IconShape.Squircle -> R.string.preference_icon_shape_squircle
|
||||
Settings.IconSettings.IconShape.Square -> R.string.preference_icon_shape_square
|
||||
Settings.IconSettings.IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
|
||||
Settings.IconSettings.IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
|
||||
Settings.IconSettings.IconShape.Circle -> R.string.preference_icon_shape_circle
|
||||
Settings.IconSettings.IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
|
||||
Settings.IconSettings.IconShape.Pebble -> R.string.preference_icon_shape_pebble
|
||||
IconShape.Triangle -> R.string.preference_icon_shape_triangle
|
||||
IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
|
||||
IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
|
||||
IconShape.Squircle -> R.string.preference_icon_shape_squircle
|
||||
IconShape.Square -> R.string.preference_icon_shape_square
|
||||
IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
|
||||
IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
|
||||
IconShape.Circle -> R.string.preference_icon_shape_circle
|
||||
IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
|
||||
IconShape.Pebble -> R.string.preference_icon_shape_pebble
|
||||
else -> return null
|
||||
}
|
||||
)
|
||||
|
||||
@ -2,124 +2,64 @@ package de.mm20.launcher2.ui.settings.icons
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import de.mm20.launcher2.badges.settings.BadgeSettings
|
||||
import de.mm20.launcher2.icons.IconPack
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.search.Application
|
||||
import de.mm20.launcher2.preferences.IconShape
|
||||
import de.mm20.launcher2.preferences.ui.BadgeSettings
|
||||
import de.mm20.launcher2.preferences.ui.IconSettings
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
class IconsSettingsScreenVM(
|
||||
private val dataStore: LauncherDataStore,
|
||||
private val uiSettings: UiSettings,
|
||||
private val iconSettings: IconSettings,
|
||||
private val badgeSettings: BadgeSettings,
|
||||
private val iconService: IconService,
|
||||
private val favoritesService: FavoritesService,
|
||||
private val permissionsManager: PermissionsManager,
|
||||
) : ViewModel() {
|
||||
|
||||
val grid = uiSettings.gridSettings
|
||||
|
||||
val columnCount = dataStore.data.map { it.grid.columnCount }
|
||||
fun setColumnCount(columnCount: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGrid(it.grid.toBuilder().setColumnCount(columnCount))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setGridColumnCount(columnCount)
|
||||
}
|
||||
|
||||
val iconSize = dataStore.data.map { it.grid.iconSize }
|
||||
fun setIconSize(iconSize: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGrid(it.grid.toBuilder().setIconSize(iconSize))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setGridIconSize(iconSize)
|
||||
}
|
||||
|
||||
|
||||
val showLabels = dataStore.data.map { it.grid.showLabels }
|
||||
fun setShowLabels(showLabels: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setGrid(it.grid.toBuilder().setShowLabels(showLabels))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
uiSettings.setGridShowLabels(showLabels)
|
||||
}
|
||||
|
||||
val iconShape = dataStore.data.map { it.icons.shape }
|
||||
fun setIconShape(iconShape: Settings.IconSettings.IconShape) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setIcons(
|
||||
it.icons.toBuilder()
|
||||
.setShape(iconShape)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
val iconShape = uiSettings.iconShape
|
||||
fun setIconShape(iconShape: IconShape) {
|
||||
uiSettings.setIconShape(iconShape)
|
||||
}
|
||||
|
||||
val adaptifyLegacyIcons = dataStore.data.map { it.icons.adaptify }
|
||||
val icons = iconSettings
|
||||
fun setAdaptifyLegacyIcons(adaptify: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setIcons(
|
||||
it.icons.toBuilder()
|
||||
.setAdaptify(adaptify)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
iconSettings.setAdaptifyLegacyIcons(adaptify)
|
||||
}
|
||||
|
||||
val themedIcons = dataStore.data.map { it.icons.themedIcons }
|
||||
fun setThemedIcons(themedIcons: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setIcons(
|
||||
it.icons.toBuilder()
|
||||
.setThemedIcons(themedIcons)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
iconSettings.setThemedIcons(themedIcons)
|
||||
}
|
||||
|
||||
val forceThemedIcons = dataStore.data.map { it.icons.forceThemed }
|
||||
fun setForceThemedIcons(forceThemedIcons: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setIcons(
|
||||
it.icons.toBuilder()
|
||||
.setForceThemed(forceThemedIcons)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
iconSettings.setForceThemedIcons(forceThemedIcons)
|
||||
}
|
||||
|
||||
val installedIconPacks: Flow<List<IconPack>> = iconService.getInstalledIconPacks().map {
|
||||
@ -132,33 +72,12 @@ class IconsSettingsScreenVM(
|
||||
) + it
|
||||
}
|
||||
|
||||
val iconPackThemed = dataStore.data.map { it.icons.iconPackThemed }
|
||||
fun setIconPackThemed(iconPackThemed: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setIcons(
|
||||
it.icons
|
||||
.toBuilder()
|
||||
.setIconPackThemed(iconPackThemed)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
iconSettings.setIconPackThemed(iconPackThemed)
|
||||
}
|
||||
|
||||
val iconPack = dataStore.data.map { it.icons.iconPack }
|
||||
fun setIconPack(iconPack: String) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setIcons(
|
||||
it.icons.toBuilder()
|
||||
.setIconPack(iconPack)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
fun setIconPack(iconPack: String?) {
|
||||
iconSettings.setIconPack(iconPack?.takeIf { it.isNotBlank() })
|
||||
}
|
||||
|
||||
val hasNotificationsPermission = permissionsManager.hasPermission(PermissionGroup.Notifications)
|
||||
@ -193,10 +112,10 @@ class IconsSettingsScreenVM(
|
||||
}
|
||||
|
||||
fun getPreviewIcons(size: Int): Flow<List<LauncherIcon?>> {
|
||||
return columnCount.flatMapLatest { cols ->
|
||||
return grid.flatMapLatest { grid ->
|
||||
favoritesService.getFavorites(
|
||||
includeTypes = listOf("app"),
|
||||
limit = cols,
|
||||
limit = grid.columnCount,
|
||||
manuallySorted = true,
|
||||
automaticallySorted = true,
|
||||
frequentlyUsed = true,
|
||||
@ -214,11 +133,12 @@ class IconsSettingsScreenVM(
|
||||
val Factory = viewModelFactory {
|
||||
initializer {
|
||||
IconsSettingsScreenVM(
|
||||
dataStore = get(),
|
||||
uiSettings = get(),
|
||||
iconService = get(),
|
||||
permissionsManager = get(),
|
||||
favoritesService = 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.permissions.PermissionGroup
|
||||
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 kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
@ -29,7 +28,9 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val musicService: MusicService by inject()
|
||||
private val appRepository: AppRepository by inject()
|
||||
private val iconService: IconService by inject()
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
private val mediaSettings: MediaSettings by inject()
|
||||
|
||||
val hasPermission =
|
||||
permissionsManager.hasPermission(PermissionGroup.Notifications)
|
||||
|
||||
@ -52,9 +53,9 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
val musicApps = musicService.getInstalledPlayerPackages()
|
||||
val allApps = appRepository.findMany().first().filter { it.profile == AppProfile.Personal }
|
||||
.distinctBy { it.componentName.packageName }
|
||||
val settings = dataStore.data.map { it.musicWidget }.first()
|
||||
val allowList = settings.allowListList
|
||||
val denyList = settings.denyListList
|
||||
val settings = mediaSettings.first()
|
||||
val allowList = settings.allowList
|
||||
val denyList = settings.denyList
|
||||
|
||||
appList.value = allApps.map {
|
||||
AppListItem(
|
||||
@ -92,19 +93,7 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
denyList.add(app.packageName)
|
||||
}
|
||||
}
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setMusicWidget(
|
||||
it.musicWidget.toBuilder()
|
||||
.clearAllowList()
|
||||
.addAllAllowList(allowList)
|
||||
.clearDenyList()
|
||||
.addAllDenyList(denyList)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
mediaSettings.setLists(allowList.toSet(), denyList.toSet())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,14 +7,14 @@ import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.plugin.PluginPackage
|
||||
import de.mm20.launcher2.plugin.PluginState
|
||||
import de.mm20.launcher2.plugin.PluginType
|
||||
import de.mm20.launcher2.plugins.PluginService
|
||||
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.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
@ -111,6 +111,6 @@ class PluginSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
val weatherProvider = weatherSettings.providerId
|
||||
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.lifecycle.compose.collectAsStateWithLifecycle
|
||||
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.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.component.preferences.*
|
||||
@ -232,8 +233,8 @@ fun SearchSettingsScreen() {
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_search_result_ordering),
|
||||
items = listOf(
|
||||
stringResource(R.string.preference_search_result_ordering_alphabetic) to Settings.SearchResultOrderingSettings.Ordering.Alphabetic,
|
||||
stringResource(R.string.preference_search_result_ordering_weighted) to Settings.SearchResultOrderingSettings.Ordering.Weighted
|
||||
stringResource(R.string.preference_search_result_ordering_alphabetic) to SearchResultOrder.Alphabetical,
|
||||
stringResource(R.string.preference_search_result_ordering_weighted) to SearchResultOrder.Weighted
|
||||
),
|
||||
value = searchResultOrdering,
|
||||
onValueChanged = {
|
||||
|
||||
@ -5,10 +5,16 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||
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.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
@ -16,35 +22,32 @@ import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
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()
|
||||
|
||||
val favorites = dataStore.data.map { it.favorites.enabled }
|
||||
val favorites = searchUiSettings.favorites
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setFavorites(favorites: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setFavorites(
|
||||
it.favorites.toBuilder().setEnabled(favorites)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
searchUiSettings.setFavorites(favorites)
|
||||
}
|
||||
|
||||
|
||||
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val contacts = dataStore.data.map { it.contactsSearch.enabled }
|
||||
val contacts = contactSearchSettings.enabled
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setContacts(contacts: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setContactsSearch(
|
||||
it.contactsSearch.toBuilder().setEnabled(contacts)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
contactSearchSettings.setEnabled(contacts)
|
||||
}
|
||||
|
||||
fun requestContactsPermission(activity: AppCompatActivity) {
|
||||
@ -53,133 +56,81 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val calendar = dataStore.data.map { it.calendarSearch.enabled }
|
||||
val calendar = calendarSearchSettings.enabled
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setCalendar(calendar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setCalendarSearch(
|
||||
it.calendarSearch.toBuilder().setEnabled(calendar)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
calendarSearchSettings.setEnabled(calendar)
|
||||
}
|
||||
|
||||
fun requestCalendarPermission(activity: AppCompatActivity) {
|
||||
permissionsManager.requestPermission(activity, PermissionGroup.Calendar)
|
||||
}
|
||||
|
||||
val calculator = dataStore.data.map { it.calculatorSearch.enabled }
|
||||
val calculator = calculatorSearchSettings.enabled
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setCalculator(calculator: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setCalculatorSearch(
|
||||
it.calculatorSearch.toBuilder().setEnabled(calculator)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
calculatorSearchSettings.setEnabled(calculator)
|
||||
}
|
||||
|
||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
|
||||
val unitConverter = unitConverterSettings.enabled
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setUnitConverter(unitConverter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setUnitConverterSearch(
|
||||
it.unitConverterSearch.toBuilder().setEnabled(unitConverter)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
unitConverterSettings.setEnabled(unitConverter)
|
||||
}
|
||||
|
||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
|
||||
val wikipedia = wikipediaSearchSettings.enabled
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setWikipedia(wikipedia: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setWikipediaSearch(
|
||||
it.wikipediaSearch.toBuilder().setEnabled(wikipedia)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
wikipediaSearchSettings.setEnabled(wikipedia)
|
||||
}
|
||||
|
||||
val websites = dataStore.data.map { it.websiteSearch.enabled }
|
||||
val websites = websiteSearchSettings.enabled
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setWebsites(websites: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setWebsiteSearch(
|
||||
it.websiteSearch.toBuilder().setEnabled(websites)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
websiteSearchSettings.setEnabled(websites)
|
||||
}
|
||||
|
||||
val autoFocus = dataStore.data.map { it.searchBar.autoFocus }
|
||||
val autoFocus = searchUiSettings.openKeyboard
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setAutoFocus(autoFocus: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setSearchBar(
|
||||
it.searchBar.toBuilder().setAutoFocus(autoFocus)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
searchUiSettings.setOpenKeyboard(autoFocus)
|
||||
}
|
||||
|
||||
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
|
||||
val launchOnEnter = searchUiSettings.launchOnEnter
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setLaunchOnEnter(launchOnEnter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setSearchBar(
|
||||
it.searchBar.toBuilder().setLaunchOnEnter(launchOnEnter)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
searchUiSettings.setLaunchOnEnter(launchOnEnter)
|
||||
}
|
||||
|
||||
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled }
|
||||
val appShortcuts = shortcutSearchSettings.enabled
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setAppShortcuts(appShortcuts: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setAppShortcutSearch(
|
||||
it.appShortcutSearch.toBuilder().setEnabled(appShortcuts)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
shortcutSearchSettings.setEnabled(appShortcuts)
|
||||
}
|
||||
|
||||
val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering }
|
||||
val searchResultOrdering = searchUiSettings.resultOrder
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setSearchResultOrdering(searchResultOrdering: Settings.SearchResultOrderingSettings.Ordering) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setResultOrdering(
|
||||
it.resultOrdering.toBuilder().setOrdering(searchResultOrdering)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
|
||||
fun setSearchResultOrdering(searchResultOrdering: SearchResultOrder) {
|
||||
searchUiSettings.setResultOrder(searchResultOrdering)
|
||||
}
|
||||
|
||||
|
||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
||||
val reverseSearchResults = searchUiSettings.reversedResults
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setReverseSearchResults(reverseSearchResults: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setLayout(it.layout.toBuilder().setReverseSearchResults(reverseSearchResults))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
searchUiSettings.setReversedResults(reverseSearchResults)
|
||||
}
|
||||
|
||||
fun requestAppShortcutsPermission(activity: AppCompatActivity) {
|
||||
|
||||
@ -2,7 +2,7 @@ package de.mm20.launcher2.ui.settings.unitconverter
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@ -12,35 +12,17 @@ import org.koin.core.component.inject
|
||||
|
||||
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)
|
||||
fun setUnitConverter(unitConverter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setUnitConverterSearch(
|
||||
it.unitConverterSearch.toBuilder()
|
||||
.setEnabled(unitConverter)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
settings.setEnabled(unitConverter)
|
||||
}
|
||||
|
||||
val currencyConverter = dataStore.data.map { it.unitConverterSearch.currencies }
|
||||
val currencyConverter = settings.currencies
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setCurrencyConverter(currencyConverter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setUnitConverterSearch(
|
||||
it.unitConverterSearch.toBuilder()
|
||||
.setCurrencies(currencyConverter)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
settings.setCurrencies(currencyConverter)
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,6 @@ import de.mm20.launcher2.ui.common.WeatherLocationSearchDialog
|
||||
import de.mm20.launcher2.ui.component.Banner
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.component.preferences.*
|
||||
import de.mm20.launcher2.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
||||
|
||||
@Composable
|
||||
|
||||
@ -1,26 +1,18 @@
|
||||
package de.mm20.launcher2.ui.settings.weather
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.plugins.PluginService
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
||||
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
||||
import kotlinx.coroutines.*
|
||||
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.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -30,29 +22,22 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val weatherSettings: WeatherSettings by inject()
|
||||
private val pluginService: PluginService by inject()
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val availableProviders = repository.getProviders()
|
||||
|
||||
val weatherProvider = weatherSettings.providerId
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setWeatherProvider(provider: String) {
|
||||
weatherSettings.setProviderId(provider)
|
||||
weatherSettings.setProvider(provider)
|
||||
}
|
||||
|
||||
val weatherProviderPluginState = weatherProvider.flatMapLatest {
|
||||
it?.let { pluginService.getPluginWithState(it) } ?: flowOf(null)
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
||||
val imperialUnits = weatherSettings.imperialUnits
|
||||
fun setImperialUnits(imperialUnits: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setWeather(it.weather.toBuilder().setImperialUnits(imperialUnits))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
weatherSettings.setImperialUnits(imperialUnits)
|
||||
}
|
||||
|
||||
val autoLocation = weatherSettings.autoLocation
|
||||
|
||||
@ -24,20 +24,10 @@ fun WikipediaSettingsScreen() {
|
||||
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()
|
||||
TextPreference(
|
||||
title = stringResource(R.string.preference_wikipedia_customurl),
|
||||
value = customUrl,
|
||||
value = customUrl ?: "",
|
||||
placeholder = stringResource(id = R.string.wikipedia_url),
|
||||
summary = customUrl.takeIf { !it.isNullOrBlank() }
|
||||
?: stringResource(id = R.string.wikipedia_url),
|
||||
|
||||
@ -2,7 +2,7 @@ package de.mm20.launcher2.ui.settings.wikipedia
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@ -11,50 +11,17 @@ import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
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)
|
||||
fun setWikipedia(wikipedia: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setWikipediaSearch(
|
||||
it.wikipediaSearch.toBuilder()
|
||||
.setEnabled(wikipedia)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
wikipediaSearchSettings.setEnabled(wikipedia)
|
||||
}
|
||||
|
||||
val images = dataStore.data.map { it.wikipediaSearch.images }
|
||||
.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 }
|
||||
val customUrl = wikipediaSearchSettings.customUrl
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
|
||||
fun setCustomUrl(customUrl: String) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setWikipediaSearch(
|
||||
it.wikipediaSearch.toBuilder()
|
||||
.setCustomUrl(customUrl)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
wikipediaSearchSettings.setCustomUrl(customUrl)
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,18 @@
|
||||
package de.mm20.launcher2.ui.theme
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.foundation.shape.CutCornerShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.coerceAtMost
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import de.mm20.launcher2.themes.DefaultThemeId
|
||||
import de.mm20.launcher2.themes.Theme
|
||||
import de.mm20.launcher2.preferences.Font
|
||||
import de.mm20.launcher2.preferences.SurfaceShape
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
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.map
|
||||
import org.koin.androidx.compose.inject
|
||||
import java.util.UUID
|
||||
import de.mm20.launcher2.preferences.ColorScheme as ColorSchemePref
|
||||
|
||||
|
||||
@Composable
|
||||
@ -35,33 +30,31 @@ fun LauncherTheme(
|
||||
) {
|
||||
|
||||
val context = LocalContext.current
|
||||
val dataStore: LauncherDataStore by inject()
|
||||
val uiSettings: UiSettings by inject()
|
||||
val themeRepository: ThemeRepository by inject()
|
||||
|
||||
val theme by remember {
|
||||
dataStore.data.map {
|
||||
it.appearance.themeId.takeIf { it.isNotEmpty() }?.let {
|
||||
UUID.fromString(it)
|
||||
}
|
||||
}.flatMapLatest {
|
||||
uiSettings.theme.flatMapLatest {
|
||||
themeRepository.getThemeOrDefault(it)
|
||||
}
|
||||
}.collectAsState(themeRepository.getDefaultTheme())
|
||||
|
||||
val themePreference by remember { dataStore.data.map { it.appearance.theme } }.collectAsState(
|
||||
AppearanceSettings.Theme.System
|
||||
val colorSchemePref by remember { uiSettings.colorScheme }.collectAsState(
|
||||
ColorSchemePref.System
|
||||
)
|
||||
val darkTheme =
|
||||
themePreference == AppearanceSettings.Theme.Dark || themePreference == AppearanceSettings.Theme.System && isSystemInDarkTheme()
|
||||
colorSchemePref == ColorSchemePref.Dark || colorSchemePref == ColorSchemePref.System && isSystemInDarkTheme()
|
||||
|
||||
val cornerRadius by remember {
|
||||
dataStore.data.map { it.cards.radius.dp }
|
||||
uiSettings.cardStyle.map {
|
||||
it.cornerRadius.dp
|
||||
}
|
||||
}.collectAsState(8.dp)
|
||||
|
||||
val baseShape by remember {
|
||||
dataStore.data.map {
|
||||
when (it.cards.shape) {
|
||||
Settings.CardSettings.Shape.Cut -> CutCornerShape(0f)
|
||||
uiSettings.cardStyle.map {
|
||||
when (it.shape) {
|
||||
SurfaceShape.Cut -> CutCornerShape(0f)
|
||||
else -> RoundedCornerShape(0f)
|
||||
}
|
||||
}
|
||||
@ -73,8 +66,8 @@ fun LauncherTheme(
|
||||
lightColorSchemeOf(theme)
|
||||
}
|
||||
|
||||
val font by remember { dataStore.data.map { it.appearance.font } }.collectAsState(
|
||||
AppearanceSettings.Font.Outfit
|
||||
val font by remember { uiSettings.font }.collectAsState(
|
||||
Font.Outfit
|
||||
)
|
||||
|
||||
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) {
|
||||
AppearanceSettings.Font.SystemDefault -> getDeviceDefaultTypography(context)
|
||||
Font.System -> getDeviceDefaultTypography(context)
|
||||
else -> DefaultTypography
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.DefaultDarkColorScheme
|
||||
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(
|
||||
primary = Color(colors.primary),
|
||||
onPrimary = Color(colors.onPrimary),
|
||||
|
||||
@ -4,6 +4,7 @@ plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.protobuf)
|
||||
alias(libs.plugins.kotlin.plugin.serialization)
|
||||
}
|
||||
|
||||
android {
|
||||
@ -57,6 +58,7 @@ protobuf {
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlin.stdlib)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.androidx.core)
|
||||
implementation(libs.androidx.appcompat)
|
||||
api(libs.androidx.datastore)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
-keepclassmembers class de.mm20.launcher2.preferences.Settings {
|
||||
-keepclassmembers class de.mm20.launcher2.preferences.LegacySettings {
|
||||
<fields>;
|
||||
}
|
||||
|
||||
-keepclassmembers class de.mm20.launcher2.preferences.Settings$* {
|
||||
-keepclassmembers class de.mm20.launcher2.preferences.LegacySettings$* {
|
||||
<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 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 scheme.Scheme
|
||||
import java.util.UUID
|
||||
|
||||
fun createFactorySettings(context: Context): Settings {
|
||||
return Settings.newBuilder()
|
||||
fun createFactorySettings(context: Context): LegacySettings {
|
||||
return LegacySettings.newBuilder()
|
||||
.setAppearance(
|
||||
Settings.AppearanceSettings
|
||||
LegacySettings.AppearanceSettings
|
||||
.newBuilder()
|
||||
.setTheme(Settings.AppearanceSettings.Theme.System)
|
||||
.setTheme(LegacySettings.AppearanceSettings.Theme.System)
|
||||
.setDimWallpaper(false)
|
||||
.setBlurWallpaper(true)
|
||||
.setBlurWallpaperRadius(32)
|
||||
.setThemeId(UUID(0L, 0L).toString())
|
||||
.setFont(Settings.AppearanceSettings.Font.Outfit)
|
||||
.setFont(LegacySettings.AppearanceSettings.Font.Outfit)
|
||||
.build()
|
||||
)
|
||||
.setWeather(
|
||||
Settings.WeatherSettings
|
||||
LegacySettings.WeatherSettings
|
||||
.newBuilder()
|
||||
.setProvider(Settings.WeatherSettings.WeatherProvider.MetNo)
|
||||
.setProvider(LegacySettings.WeatherSettings.WeatherProvider.MetNo)
|
||||
.setImperialUnits(context.resources.getBoolean(R.bool.default_imperialUnits))
|
||||
.build()
|
||||
)
|
||||
.setMusicWidget(
|
||||
Settings.MusicWidgetSettings
|
||||
LegacySettings.MusicWidgetSettings
|
||||
.newBuilder()
|
||||
.build()
|
||||
)
|
||||
.setCalendarWidget(
|
||||
Settings.CalendarWidgetSettings
|
||||
LegacySettings.CalendarWidgetSettings
|
||||
.newBuilder()
|
||||
.setHideAlldayEvents(false)
|
||||
)
|
||||
.setClockWidget(
|
||||
Settings.ClockWidgetSettings
|
||||
LegacySettings.ClockWidgetSettings
|
||||
.newBuilder()
|
||||
.setLayout(Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical)
|
||||
.setClockStyle(Settings.ClockWidgetSettings.ClockStyle.DigitalClock1)
|
||||
.setColor(Settings.ClockWidgetSettings.ClockWidgetColors.Auto)
|
||||
.setLayout(LegacySettings.ClockWidgetSettings.ClockWidgetLayout.Vertical)
|
||||
.setClockStyle(LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1)
|
||||
.setColor(LegacySettings.ClockWidgetSettings.ClockWidgetColors.Auto)
|
||||
.setAlarmPart(true)
|
||||
.setBatteryPart(true)
|
||||
.setMusicPart(true)
|
||||
.setDatePart(true)
|
||||
.setFavoritesPart(false)
|
||||
.setFillHeight(true)
|
||||
.setAlignment(Settings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
||||
.setAlignment(LegacySettings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
||||
.build()
|
||||
)
|
||||
.setFavorites(
|
||||
Settings.FavoritesSettings
|
||||
LegacySettings.FavoritesSettings
|
||||
.newBuilder()
|
||||
.setEnabled(true)
|
||||
.setFrequentlyUsed(true)
|
||||
@ -61,7 +61,7 @@ fun createFactorySettings(context: Context): Settings {
|
||||
.setEditButton(true)
|
||||
)
|
||||
.setFileSearch(
|
||||
Settings.FilesSearchSettings
|
||||
LegacySettings.FilesSearchSettings
|
||||
.newBuilder()
|
||||
.setLocalFiles(true)
|
||||
.setNextcloud(false)
|
||||
@ -70,50 +70,50 @@ fun createFactorySettings(context: Context): Settings {
|
||||
.setNextcloud(false)
|
||||
)
|
||||
.setContactsSearch(
|
||||
Settings.ContactsSearchSettings
|
||||
LegacySettings.ContactsSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(true)
|
||||
)
|
||||
.setCalendarSearch(
|
||||
Settings.CalendarSearchSettings
|
||||
LegacySettings.CalendarSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(true)
|
||||
)
|
||||
.setAppShortcutSearch(
|
||||
Settings.AppShortcutSearchSettings
|
||||
LegacySettings.AppShortcutSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(true)
|
||||
)
|
||||
.setCalculatorSearch(
|
||||
Settings.CalculatorSearchSettings
|
||||
LegacySettings.CalculatorSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(true)
|
||||
)
|
||||
.setUnitConverterSearch(
|
||||
Settings.UnitConverterSearchSettings
|
||||
LegacySettings.UnitConverterSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(true)
|
||||
.setCurrencies(true)
|
||||
)
|
||||
.setWikipediaSearch(
|
||||
Settings.WikipediaSearchSettings
|
||||
LegacySettings.WikipediaSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(false)
|
||||
.setImages(false)
|
||||
.setCustomUrl("")
|
||||
)
|
||||
.setWebsiteSearch(
|
||||
Settings.WebsiteSearchSettings
|
||||
LegacySettings.WebsiteSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(false)
|
||||
)
|
||||
.setWebSearch(
|
||||
Settings.WebSearchSettings
|
||||
LegacySettings.WebSearchSettings
|
||||
.newBuilder()
|
||||
.setEnabled(true)
|
||||
)
|
||||
.setBadges(
|
||||
Settings.BadgeSettings
|
||||
LegacySettings.BadgeSettings
|
||||
.newBuilder()
|
||||
.setNotifications(true)
|
||||
.setCloudFiles(true)
|
||||
@ -121,15 +121,15 @@ fun createFactorySettings(context: Context): Settings {
|
||||
.setSuspendedApps(true)
|
||||
)
|
||||
.setGrid(
|
||||
Settings.GridSettings.newBuilder()
|
||||
LegacySettings.GridSettings.newBuilder()
|
||||
.setColumnCount(context.resources.getInteger(R.integer.config_columnCount))
|
||||
.setIconSize(48)
|
||||
.setShowLabels(true)
|
||||
.build()
|
||||
)
|
||||
.setSearchBar(
|
||||
Settings.SearchBarSettings.newBuilder()
|
||||
.setSearchBarStyle(Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||
LegacySettings.SearchBarSettings.newBuilder()
|
||||
.setSearchBarStyle(LegacySettings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||
.setAutoFocus(true)
|
||||
.setLaunchOnEnter(true)
|
||||
.setColor(SearchBarColors.Auto)
|
||||
@ -137,67 +137,67 @@ fun createFactorySettings(context: Context): Settings {
|
||||
.build()
|
||||
)
|
||||
.setIcons(
|
||||
Settings.IconSettings.newBuilder()
|
||||
LegacySettings.IconSettings.newBuilder()
|
||||
.setAdaptify(true)
|
||||
.setShape(Settings.IconSettings.IconShape.PlatformDefault)
|
||||
.setShape(LegacySettings.IconSettings.IconShape.PlatformDefault)
|
||||
.setThemedIcons(false)
|
||||
.setIconPack("")
|
||||
.setIconPackThemed(true)
|
||||
)
|
||||
.setEasterEgg(false)
|
||||
.setSystemBars(
|
||||
Settings.SystemBarsSettings.newBuilder()
|
||||
.setNavBarColor(Settings.SystemBarsSettings.SystemBarColors.Auto)
|
||||
.setStatusBarColor(Settings.SystemBarsSettings.SystemBarColors.Auto)
|
||||
LegacySettings.SystemBarsSettings.newBuilder()
|
||||
.setNavBarColor(LegacySettings.SystemBarsSettings.SystemBarColors.Auto)
|
||||
.setStatusBarColor(LegacySettings.SystemBarsSettings.SystemBarColors.Auto)
|
||||
.setHideStatusBar(false)
|
||||
.setHideNavBar(false)
|
||||
)
|
||||
.setCards(
|
||||
Settings.CardSettings.newBuilder()
|
||||
LegacySettings.CardSettings.newBuilder()
|
||||
.setBorderWidth(0)
|
||||
.setRadius(12)
|
||||
.setOpacity(1f)
|
||||
)
|
||||
.setWidgets(
|
||||
Settings.WidgetSettings.newBuilder()
|
||||
LegacySettings.WidgetSettings.newBuilder()
|
||||
.setEditButton(true)
|
||||
)
|
||||
.setLayout(
|
||||
Settings.LayoutSettings.newBuilder()
|
||||
.setBaseLayout(Settings.LayoutSettings.Layout.PullDown)
|
||||
LegacySettings.LayoutSettings.newBuilder()
|
||||
.setBaseLayout(LegacySettings.LayoutSettings.Layout.PullDown)
|
||||
.setBottomSearchBar(false)
|
||||
.setReverseSearchResults(false)
|
||||
.setFixedRotation(false)
|
||||
)
|
||||
.setGestures(
|
||||
Settings.GestureSettings.newBuilder()
|
||||
LegacySettings.GestureSettings.newBuilder()
|
||||
.setDoubleTap(
|
||||
if (isAtLeastApiLevel(28)) {
|
||||
Settings.GestureSettings.GestureAction.LockScreen
|
||||
LegacySettings.GestureSettings.GestureAction.LockScreen
|
||||
} else {
|
||||
Settings.GestureSettings.GestureAction.None
|
||||
LegacySettings.GestureSettings.GestureAction.None
|
||||
})
|
||||
.setLongPress(Settings.GestureSettings.GestureAction.None)
|
||||
.setSwipeDown(Settings.GestureSettings.GestureAction.OpenNotificationDrawer)
|
||||
.setSwipeLeft(Settings.GestureSettings.GestureAction.None)
|
||||
.setSwipeRight(Settings.GestureSettings.GestureAction.None)
|
||||
.setLongPress(LegacySettings.GestureSettings.GestureAction.None)
|
||||
.setSwipeDown(LegacySettings.GestureSettings.GestureAction.OpenNotificationDrawer)
|
||||
.setSwipeLeft(LegacySettings.GestureSettings.GestureAction.None)
|
||||
.setSwipeRight(LegacySettings.GestureSettings.GestureAction.None)
|
||||
)
|
||||
.setResultOrdering(
|
||||
Settings.SearchResultOrderingSettings.newBuilder()
|
||||
.setOrdering(Settings.SearchResultOrderingSettings.Ordering.Weighted)
|
||||
.setWeightFactor(Settings.SearchResultOrderingSettings.WeightFactor.Default)
|
||||
LegacySettings.SearchResultOrderingSettings.newBuilder()
|
||||
.setOrdering(LegacySettings.SearchResultOrderingSettings.Ordering.Weighted)
|
||||
.setWeightFactor(LegacySettings.SearchResultOrderingSettings.WeightFactor.Default)
|
||||
)
|
||||
.setAnimations(
|
||||
Settings.AnimationSettings.newBuilder()
|
||||
LegacySettings.AnimationSettings.newBuilder()
|
||||
.setCharging(true)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
internal val DefaultCustomColorsBase: Settings.AppearanceSettings.CustomColors.BaseColors
|
||||
internal val DefaultCustomColorsBase: LegacySettings.AppearanceSettings.CustomColors.BaseColors
|
||||
get() {
|
||||
val scheme = Scheme.light(0xFFACE330.toInt())
|
||||
return Settings.AppearanceSettings.CustomColors.BaseColors.newBuilder()
|
||||
return LegacySettings.AppearanceSettings.CustomColors.BaseColors.newBuilder()
|
||||
.setAccent1(scheme.primary)
|
||||
.setAccent2(scheme.secondary)
|
||||
.setAccent3(scheme.tertiary)
|
||||
@ -207,13 +207,13 @@ internal val DefaultCustomColorsBase: Settings.AppearanceSettings.CustomColors.B
|
||||
.build()
|
||||
}
|
||||
|
||||
internal val DefaultLightCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme
|
||||
internal val DefaultLightCustomColorScheme: LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||
get() {
|
||||
val scheme = Scheme.light(0xFFACE330.toInt())
|
||||
return scheme.toSettingsColorsScheme()
|
||||
}
|
||||
|
||||
internal val DefaultDarkCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme
|
||||
internal val DefaultDarkCustomColorScheme: LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||
get() {
|
||||
val scheme = Scheme.dark(0xFFACE330.toInt())
|
||||
return scheme.toSettingsColorsScheme()
|
||||
|
||||
@ -14,7 +14,7 @@ import java.io.File
|
||||
|
||||
internal class LauncherStoreBackupComponent(
|
||||
private val context: Context,
|
||||
private val dataStore: LauncherDataStore
|
||||
private val dataStore: LegacyDataStore
|
||||
): Backupable {
|
||||
override suspend fun backup(toDir: File) {
|
||||
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 backupDataStore = DataStoreFactory.create(
|
||||
serializer = SettingsSerializer,
|
||||
serializer = LegacySettingsSerializer,
|
||||
produceFile = {
|
||||
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 backupDataStore = DataStoreFactory.create(
|
||||
serializer = SettingsSerializer,
|
||||
serializer = LegacySettingsSerializer,
|
||||
migrations = getMigrations(context),
|
||||
corruptionHandler = ReplaceFileCorruptionHandler {
|
||||
CrashReporter.logException(it)
|
||||
Settings.getDefaultInstance()
|
||||
LegacySettings.getDefaultInstance()
|
||||
},
|
||||
produceFile = {
|
||||
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.Serializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
@ -11,27 +10,17 @@ import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
@Serializable
|
||||
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 object LauncherSettingsDataSerializer : Serializer<LauncherSettingsData> {
|
||||
|
||||
internal val json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
encodeDefaults = true
|
||||
}
|
||||
|
||||
override val defaultValue: FileSearchSettingsData
|
||||
get() = FileSearchSettingsData(schemaVersion = 0)
|
||||
override val defaultValue: LauncherSettingsData
|
||||
get() = LauncherSettingsData(schemaVersion = 0)
|
||||
|
||||
override suspend fun readFrom(input: InputStream): FileSearchSettingsData {
|
||||
override suspend fun readFrom(input: InputStream): LauncherSettingsData {
|
||||
try {
|
||||
return json.decodeFromStream(input)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
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.core.qualifier.named
|
||||
import org.koin.dsl.module
|
||||
|
||||
val preferencesModule = module {
|
||||
single { androidContext().dataStore }
|
||||
factory<Backupable>(named<LauncherDataStore>()) { LauncherStoreBackupComponent(androidContext(), get()) }
|
||||
single { androidContext().legacyDataStore }
|
||||
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
|
||||
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
import scheme.Scheme
|
||||
|
||||
fun Scheme.toSettingsColorsScheme(): Settings.AppearanceSettings.CustomColors.Scheme {
|
||||
fun Scheme.toSettingsColorsScheme(): LegacySettings.AppearanceSettings.CustomColors.Scheme {
|
||||
val scheme = this
|
||||
return Settings.AppearanceSettings.CustomColors.Scheme.newBuilder()
|
||||
return LegacySettings.AppearanceSettings.CustomColors.Scheme.newBuilder()
|
||||
.setPrimary(scheme.primary)
|
||||
.setSurfaceTint(scheme.primary)
|
||||
.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 androidx.datastore.core.DataMigration
|
||||
import de.mm20.launcher2.preferences.SchemaVersion
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
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 migrate(currentData: Settings): Settings {
|
||||
override suspend fun migrate(currentData: LegacySettings): LegacySettings {
|
||||
Log.d("MM20", "Initializing user settings…")
|
||||
Log.d("MM20", "Done")
|
||||
val defaults = createFactorySettings(context)
|
||||
return defaults.toBuilder().setVersion(SchemaVersion).build()
|
||||
}
|
||||
|
||||
override suspend fun shouldMigrate(currentData: Settings): Boolean {
|
||||
override suspend fun shouldMigrate(currentData: LegacySettings): Boolean {
|
||||
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
|
||||
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
|
||||
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(
|
||||
builder.appearance.toBuilder()
|
||||
.setCustomColors(
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
package de.mm20.launcher2.preferences.migrations
|
||||
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.GestureSettings
|
||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
import de.mm20.launcher2.preferences.LegacySettings.GestureSettings
|
||||
import de.mm20.launcher2.preferences.LegacySettings.LayoutSettings
|
||||
|
||||
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
|
||||
when(oldLayout) {
|
||||
LayoutSettings.Layout.Pager -> {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package de.mm20.launcher2.preferences.migrations
|
||||
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
import de.mm20.launcher2.preferences.LegacySettings.SearchResultOrderingSettings.WeightFactor
|
||||
|
||||
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
|
||||
.setClockWidget(
|
||||
builder.clockWidget.toBuilder()
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder
|
||||
.setIcons(
|
||||
builder.icons.toBuilder()
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setSearchBar(
|
||||
builder.searchBar.toBuilder()
|
||||
.setHiddenItemsButton(true)
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package de.mm20.launcher2.preferences.migrations
|
||||
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.CustomColors.Scheme
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
import de.mm20.launcher2.preferences.LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||
import palettes.TonalPalette
|
||||
|
||||
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(
|
||||
builder.appearance.toBuilder()
|
||||
.setCustomColors(
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
package de.mm20.launcher2.preferences.migrations
|
||||
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.LegacySettings
|
||||
import java.util.UUID
|
||||
|
||||
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(
|
||||
builder.appearance.toBuilder()
|
||||
.setThemeId(
|
||||
when(builder.appearance.colorScheme) {
|
||||
Settings.AppearanceSettings.ColorScheme.BlackAndWhite -> UUID(0L, 1L)
|
||||
Settings.AppearanceSettings.ColorScheme.Custom -> UUID(1L, 1L)
|
||||
LegacySettings.AppearanceSettings.ColorScheme.BlackAndWhite -> UUID(0L, 1L)
|
||||
LegacySettings.AppearanceSettings.ColorScheme.Custom -> UUID(1L, 1L)
|
||||
else -> UUID(0L, 0L)
|
||||
}.toString()
|
||||
)
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder
|
||||
.setAppearance(builder.appearance.toBuilder()
|
||||
.setBlurWallpaperRadius(32)
|
||||
)
|
||||
.setClockWidget(builder.clockWidget.toBuilder()
|
||||
.setAlignment(Settings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
||||
.setAlignment(LegacySettings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
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) {
|
||||
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setSystemBars(
|
||||
builder.systemBars.toBuilder()
|
||||
.setHideNavBar(false)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setClockWidget(
|
||||
builder.clockWidget.toBuilder()
|
||||
.setAlarmPart(true)
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setAppShortcutSearch(
|
||||
Settings.AppShortcutSearchSettings.newBuilder()
|
||||
LegacySettings.AppShortcutSearchSettings.newBuilder()
|
||||
.setEnabled(true)
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setGrid(
|
||||
builder.grid.toBuilder()
|
||||
.setIconSize(48)
|
||||
|
||||
@ -3,13 +3,14 @@ package de.mm20.launcher2.preferences.migrations
|
||||
import de.mm20.launcher2.preferences.DefaultCustomColorsBase
|
||||
import de.mm20.launcher2.preferences.DefaultDarkCustomColorScheme
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setAppearance(
|
||||
builder.appearance.toBuilder()
|
||||
.setCustomColors(Settings.AppearanceSettings.CustomColors.newBuilder()
|
||||
.setCustomColors(
|
||||
LegacySettings.AppearanceSettings.CustomColors.newBuilder()
|
||||
.setAdvancedMode(false)
|
||||
.setBaseColors(DefaultCustomColorsBase)
|
||||
.setLightScheme(DefaultLightCustomColorScheme)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setIcons(
|
||||
builder.icons.toBuilder()
|
||||
.setAdaptify(true)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder.setAppearance(
|
||||
builder.appearance.toBuilder()
|
||||
.setBlurWallpaper(true)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
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) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
override suspend fun applyMigrations(builder: LegacySettings.Builder): LegacySettings.Builder {
|
||||
return builder
|
||||
.setClockWidget(
|
||||
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