Merge remote-tracking branch 'upstream/main' into feat/materialYouCompat
Signed-off-by: Guillermo Villafuerte <gvillafu@comunidad.unam.mx> # Conflicts: # app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt # app/ui/src/main/java/de/mm20/launcher2/ui/theme/colorscheme/Custom.kt # core/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt # core/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt
This commit is contained in:
commit
7d0c1829a8
@ -19,19 +19,17 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM
|
import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM
|
||||||
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
|
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
|
||||||
import de.mm20.launcher2.ui.launcher.helper.WallpaperBlur
|
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchColumn
|
import de.mm20.launcher2.ui.launcher.search.SearchColumn
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
||||||
import de.mm20.launcher2.ui.launcher.searchbar.LauncherSearchBar
|
import de.mm20.launcher2.ui.launcher.searchbar.LauncherSearchBar
|
||||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AssistantScaffold(
|
fun AssistantScaffold(
|
||||||
@ -204,7 +202,7 @@ fun AssistantScaffold(
|
|||||||
showHiddenItemsButton = true,
|
showHiddenItemsButton = true,
|
||||||
value = { value },
|
value = { value },
|
||||||
onValueChange = { searchVM.search(it) },
|
onValueChange = { searchVM.search(it) },
|
||||||
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == Settings.SearchBarSettings.SearchBarColors.Auto || searchBarColor == Settings.SearchBarSettings.SearchBarColors.Dark,
|
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == SearchBarColors.Auto || searchBarColor == SearchBarColors.Dark,
|
||||||
style = searchBarStyle,
|
style = searchBarStyle,
|
||||||
reverse = bottomSearchBar,
|
reverse = bottomSearchBar,
|
||||||
onKeyboardActionGo = if (launchOnEnter) {
|
onKeyboardActionGo = if (launchOnEnter) {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package de.mm20.launcher2.ui.base
|
package de.mm20.launcher2.ui.base
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.unit.dp
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||||
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.ui.component.ProvideIconShape
|
import de.mm20.launcher2.ui.component.ProvideIconShape
|
||||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||||
@ -19,32 +21,28 @@ import org.koin.androidx.compose.inject
|
|||||||
fun ProvideSettings(
|
fun ProvideSettings(
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val dataStore: LauncherDataStore by inject()
|
val settings: UiSettings by inject()
|
||||||
val widgetRepository: WidgetRepository by inject()
|
val widgetRepository: WidgetRepository by inject()
|
||||||
|
|
||||||
val cardStyle by remember {
|
val cardStyle by remember {
|
||||||
dataStore.data.map { it.cards }.distinctUntilChanged()
|
settings.cardStyle.distinctUntilChanged()
|
||||||
}.collectAsState(
|
}.collectAsState(
|
||||||
Settings.CardSettings.getDefaultInstance()
|
CardStyle()
|
||||||
)
|
)
|
||||||
val iconShape by remember {
|
val iconShape by remember {
|
||||||
dataStore.data.map {
|
settings.iconShape.distinctUntilChanged()
|
||||||
if (it.easterEgg) Settings.IconSettings.IconShape.EasterEgg
|
}.collectAsState(IconShape.Circle)
|
||||||
else it.icons.shape
|
|
||||||
}.distinctUntilChanged()
|
|
||||||
}.collectAsState(Settings.IconSettings.IconShape.Circle)
|
|
||||||
|
|
||||||
val favoritesEnabled by remember {
|
val favoritesEnabled by remember {
|
||||||
combine(
|
combine(
|
||||||
widgetRepository.exists(FavoritesWidget.Type),
|
widgetRepository.exists(FavoritesWidget.Type),
|
||||||
dataStore.data.map { it.favorites.enabled },
|
settings.favoritesEnabled,
|
||||||
dataStore.data.map { it.clockWidget.favoritesPart },
|
) { a, b -> a || b }.distinctUntilChanged()
|
||||||
) { a, b, c -> a || b || c }.distinctUntilChanged()
|
|
||||||
}.collectAsState(true)
|
}.collectAsState(true)
|
||||||
|
|
||||||
val gridSettings by remember {
|
val gridSettings by remember {
|
||||||
dataStore.data.map { it.grid }.distinctUntilChanged()
|
settings.gridSettings.distinctUntilChanged()
|
||||||
}.collectAsState(Settings.GridSettings.newBuilder().setColumnCount(5).setShowLabels(true).setIconSize(48).build())
|
}.collectAsState(GridSettings())
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalCardStyle provides cardStyle,
|
LocalCardStyle provides cardStyle,
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
||||||
import de.mm20.launcher2.data.customattrs.utils.withCustomLabels
|
import de.mm20.launcher2.data.customattrs.utils.withCustomLabels
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettingsData
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.data.Tag
|
import de.mm20.launcher2.search.data.Tag
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
@ -19,11 +20,11 @@ abstract class FavoritesVM : ViewModel(), KoinComponent {
|
|||||||
private val favoritesService: FavoritesService by inject()
|
private val favoritesService: FavoritesService by inject()
|
||||||
internal val widgetRepository: WidgetRepository by inject()
|
internal val widgetRepository: WidgetRepository by inject()
|
||||||
private val customAttributesRepository: CustomAttributesRepository by inject()
|
private val customAttributesRepository: CustomAttributesRepository by inject()
|
||||||
internal val dataStore: LauncherDataStore by inject()
|
internal val settings: FavoritesSettings by inject()
|
||||||
|
|
||||||
val selectedTag = MutableStateFlow<String?>(null)
|
val selectedTag = MutableStateFlow<String?>(null)
|
||||||
|
|
||||||
val showEditButton = dataStore.data.map { it.favorites.editButton }
|
val showEditButton = settings.showEditButton
|
||||||
abstract val tagsExpanded: Flow<Boolean>
|
abstract val tagsExpanded: Flow<Boolean>
|
||||||
|
|
||||||
val pinnedTags = favoritesService.getFavorites(
|
val pinnedTags = favoritesService.getFavorites(
|
||||||
@ -36,24 +37,18 @@ abstract class FavoritesVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
open val favorites: Flow<List<SavableSearchable>> = selectedTag.flatMapLatest { tag ->
|
open val favorites: Flow<List<SavableSearchable>> = selectedTag.flatMapLatest { tag ->
|
||||||
if (tag == null) {
|
if (tag == null) {
|
||||||
val columns = dataStore.data.map { it.grid.columnCount }
|
|
||||||
val excludeCalendar = widgetRepository.exists(CalendarWidget.Type)
|
val excludeCalendar = widgetRepository.exists(CalendarWidget.Type)
|
||||||
val includeFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
|
||||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
|
||||||
|
|
||||||
combine(
|
combine(
|
||||||
listOf(
|
excludeCalendar,
|
||||||
columns,
|
settings,
|
||||||
excludeCalendar,
|
) { (a, b) -> a as Boolean to b as FavoritesSettingsData }
|
||||||
includeFrequentlyUsed,
|
.transformLatest {
|
||||||
frequentlyUsedRows
|
|
||||||
)
|
|
||||||
) { it }.transformLatest {
|
|
||||||
|
|
||||||
val columns = it[0] as Int
|
val columns = it.second.columns
|
||||||
val excludeCalendar = it[1] as Boolean
|
val excludeCalendar = it.first
|
||||||
val includeFrequentlyUsed = it[2] as Boolean
|
val includeFrequentlyUsed = it.second.frequentlyUsed
|
||||||
val frequentlyUsedRows = it[3] as Int
|
val frequentlyUsedRows = it.second.frequentlyUsedRows
|
||||||
|
|
||||||
val pinned = favoritesService.getFavorites(
|
val pinned = favoritesService.getFavorites(
|
||||||
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import android.net.Uri
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ThemeDescriptor
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.themes.Theme
|
import de.mm20.launcher2.themes.Theme
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import de.mm20.launcher2.themes.fromJson
|
import de.mm20.launcher2.themes.fromJson
|
||||||
@ -17,7 +18,7 @@ import org.koin.core.component.inject
|
|||||||
class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val themeRepository: ThemeRepository by inject()
|
private val themeRepository: ThemeRepository by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
val theme = mutableStateOf<Theme?>(null)
|
val theme = mutableStateOf<Theme?>(null)
|
||||||
val error = mutableStateOf<Boolean>(false)
|
val error = mutableStateOf<Boolean>(false)
|
||||||
@ -56,16 +57,10 @@ class ImportThemeSheetVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun importTheme(theme: Theme, apply: Boolean) {
|
private fun importTheme(theme: Theme, apply: Boolean) {
|
||||||
themeRepository.createTheme(theme)
|
themeRepository.createTheme(theme)
|
||||||
if (apply) {
|
if (apply) {
|
||||||
dataStore.updateData {
|
uiSettings.setTheme(ThemeDescriptor.Custom(theme.id.toString()))
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setThemeId(theme.id.toString())
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.SearchService
|
import de.mm20.launcher2.search.SearchService
|
||||||
import de.mm20.launcher2.search.toList
|
import de.mm20.launcher2.search.toList
|
||||||
@ -15,15 +14,13 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class SearchablePickerVM: ViewModel(), KoinComponent {
|
class SearchablePickerVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
private val searchService: SearchService by inject()
|
private val searchService: SearchService by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
|
|
||||||
@ -41,15 +38,11 @@ class SearchablePickerVM: ViewModel(), KoinComponent {
|
|||||||
searchQuery = query
|
searchQuery = query
|
||||||
searchJob?.cancel()
|
searchJob?.cancel()
|
||||||
searchJob = viewModelScope.launch {
|
searchJob = viewModelScope.launch {
|
||||||
val settings = dataStore.data.first()
|
|
||||||
searchService.search(
|
searchService.search(
|
||||||
query = query,
|
query = query,
|
||||||
shortcuts = settings.appShortcutSearch,
|
|
||||||
contacts = settings.contactsSearch,
|
|
||||||
calendars = settings.calendarSearch,
|
|
||||||
).collectLatest {
|
).collectLatest {
|
||||||
if (searchQuery != query) return@collectLatest
|
if (searchQuery != query) return@collectLatest
|
||||||
items = withContext(Dispatchers.Default) {
|
items = withContext(Dispatchers.Default) {
|
||||||
it.toList().filterIsInstance<SavableSearchable>().sorted()
|
it.toList().filterIsInstance<SavableSearchable>().sorted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,9 @@ package de.mm20.launcher2.ui.common
|
|||||||
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import de.mm20.launcher2.weather.WeatherLocation
|
import de.mm20.launcher2.preferences.weather.WeatherLocation
|
||||||
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import androidx.compose.ui.graphics.SolidColor
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.layout.BottomReversed
|
import de.mm20.launcher2.ui.layout.BottomReversed
|
||||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
@ -47,7 +47,7 @@ import de.mm20.launcher2.ui.locals.LocalCardStyle
|
|||||||
@Composable
|
@Composable
|
||||||
fun SearchBar(
|
fun SearchBar(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
style: Settings.SearchBarSettings.SearchBarStyle,
|
style: SearchBarStyle,
|
||||||
level: SearchBarLevel,
|
level: SearchBarLevel,
|
||||||
value: String,
|
value: String,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
@ -78,7 +78,7 @@ fun SearchBar(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
it == SearchBarLevel.Resting && style != Settings.SearchBarSettings.SearchBarStyle.Solid -> 0.dp
|
it == SearchBarLevel.Resting && style != SearchBarStyle.Solid -> 0.dp
|
||||||
it == SearchBarLevel.Raised -> 8.dp
|
it == SearchBarLevel.Raised -> 8.dp
|
||||||
else -> 2.dp
|
else -> 2.dp
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ fun SearchBar(
|
|||||||
}) {
|
}) {
|
||||||
when {
|
when {
|
||||||
it == SearchBarLevel.Active -> LocalCardStyle.current.opacity
|
it == SearchBarLevel.Active -> LocalCardStyle.current.opacity
|
||||||
style != Settings.SearchBarSettings.SearchBarStyle.Transparent -> 1f
|
style != SearchBarStyle.Transparent -> 1f
|
||||||
it == SearchBarLevel.Resting -> 0f
|
it == SearchBarLevel.Resting -> 0f
|
||||||
else -> 1f
|
else -> 1f
|
||||||
}
|
}
|
||||||
@ -117,14 +117,14 @@ fun SearchBar(
|
|||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
when {
|
when {
|
||||||
style != Settings.SearchBarSettings.SearchBarStyle.Transparent -> MaterialTheme.colorScheme.onSurface
|
style != SearchBarStyle.Transparent -> MaterialTheme.colorScheme.onSurface
|
||||||
it == SearchBarLevel.Resting -> if (darkColors) Color(0, 0, 0, 180) else Color.White
|
it == SearchBarLevel.Resting -> if (darkColors) Color(0, 0, 0, 180) else Color.White
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val opacity by transition.animateFloat(label = "opacity") {
|
val opacity by transition.animateFloat(label = "opacity") {
|
||||||
if (style == Settings.SearchBarSettings.SearchBarStyle.Hidden && it == SearchBarLevel.Resting) 0f
|
if (style == SearchBarStyle.Hidden && it == SearchBarLevel.Resting) 0f
|
||||||
else 1f
|
else 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import androidx.compose.animation.core.tween
|
|||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@ -57,7 +56,6 @@ import androidx.compose.ui.graphics.drawscope.withTransform
|
|||||||
import androidx.compose.ui.graphics.nativeCanvas
|
import androidx.compose.ui.graphics.nativeCanvas
|
||||||
import androidx.compose.ui.graphics.toAndroidRect
|
import androidx.compose.ui.graphics.toAndroidRect
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.Density
|
import androidx.compose.ui.unit.Density
|
||||||
@ -80,7 +78,7 @@ import de.mm20.launcher2.icons.TintedClockLayer
|
|||||||
import de.mm20.launcher2.icons.TintedIconLayer
|
import de.mm20.launcher2.icons.TintedIconLayer
|
||||||
import de.mm20.launcher2.icons.TransparentLayer
|
import de.mm20.launcher2.icons.TransparentLayer
|
||||||
import de.mm20.launcher2.ktx.drawWithColorFilter
|
import de.mm20.launcher2.ktx.drawWithColorFilter
|
||||||
import de.mm20.launcher2.preferences.Settings.IconSettings.IconShape
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
import de.mm20.launcher2.ui.base.LocalTime
|
import de.mm20.launcher2.ui.base.LocalTime
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
import de.mm20.launcher2.ui.ktx.toPixels
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
@ -495,7 +493,6 @@ fun getShape(iconShape: IconShape): Shape {
|
|||||||
IconShape.Teardrop -> TeardropShape
|
IconShape.Teardrop -> TeardropShape
|
||||||
IconShape.Pebble -> PebbleShape
|
IconShape.Pebble -> PebbleShape
|
||||||
IconShape.EasterEgg -> EasterEggShape
|
IconShape.EasterEgg -> EasterEggShape
|
||||||
IconShape.UNRECOGNIZED -> CircleShape
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import androidx.compose.ui.hapticfeedback.HapticFeedback
|
|||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
|
||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import de.mm20.launcher2.ui.ktx.animateTo
|
import de.mm20.launcher2.ui.ktx.animateTo
|
||||||
@ -178,7 +177,6 @@ fun LazyVerticalDragAndDropGrid(
|
|||||||
columns,
|
columns,
|
||||||
modifier.dragAndDrop(
|
modifier.dragAndDrop(
|
||||||
state,
|
state,
|
||||||
LocalLayoutDirection.current == LayoutDirection.Rtl,
|
|
||||||
LocalHapticFeedback.current
|
LocalHapticFeedback.current
|
||||||
),
|
),
|
||||||
state.gridState,
|
state.gridState,
|
||||||
@ -208,7 +206,6 @@ fun LazyHorizontalDragAndDropGrid(
|
|||||||
rows,
|
rows,
|
||||||
modifier.dragAndDrop(
|
modifier.dragAndDrop(
|
||||||
state,
|
state,
|
||||||
LocalLayoutDirection.current == LayoutDirection.Rtl,
|
|
||||||
LocalHapticFeedback.current
|
LocalHapticFeedback.current
|
||||||
),
|
),
|
||||||
state.gridState,
|
state.gridState,
|
||||||
@ -224,7 +221,6 @@ fun LazyHorizontalDragAndDropGrid(
|
|||||||
|
|
||||||
fun Modifier.dragAndDrop(
|
fun Modifier.dragAndDrop(
|
||||||
state: LazyDragAndDropGridState,
|
state: LazyDragAndDropGridState,
|
||||||
isRtl: Boolean,
|
|
||||||
hapticFeedback: HapticFeedback
|
hapticFeedback: HapticFeedback
|
||||||
) =
|
) =
|
||||||
this then pointerInput(null) {
|
this then pointerInput(null) {
|
||||||
@ -235,10 +231,7 @@ fun Modifier.dragAndDrop(
|
|||||||
onDragStart = { offset ->
|
onDragStart = { offset ->
|
||||||
val draggedItem = state.gridState.layoutInfo.visibleItemsInfo.find {
|
val draggedItem = state.gridState.layoutInfo.visibleItemsInfo.find {
|
||||||
Rect(
|
Rect(
|
||||||
it.offset.toOffset().let {off ->
|
it.offset.toOffset(),
|
||||||
if (isRtl) off.copy(x = state.gridState.layoutInfo.viewportSize.width - off.x - it.size.width)
|
|
||||||
else off
|
|
||||||
},
|
|
||||||
it.size.toSize()
|
it.size.toSize()
|
||||||
).contains(offset)
|
).contains(offset)
|
||||||
}
|
}
|
||||||
@ -250,10 +243,7 @@ fun Modifier.dragAndDrop(
|
|||||||
val absPosition = state.draggedItemAbsolutePosition
|
val absPosition = state.draggedItemAbsolutePosition
|
||||||
val draggedItem = state.draggedItem
|
val draggedItem = state.draggedItem
|
||||||
if (absPosition != null && draggedItem != null) {
|
if (absPosition != null && draggedItem != null) {
|
||||||
state.draggedItemAbsolutePosition = absPosition + dragAmount.let {
|
state.draggedItemAbsolutePosition = absPosition + dragAmount
|
||||||
if (isRtl) it.copy(x = -it.x)
|
|
||||||
else it
|
|
||||||
}
|
|
||||||
val draggedCenter = Rect(absPosition, draggedItem.size.toSize()).center
|
val draggedCenter = Rect(absPosition, draggedItem.size.toSize()).center
|
||||||
val dragOver = state.gridState.layoutInfo.visibleItemsInfo.find {
|
val dragOver = state.gridState.layoutInfo.visibleItemsInfo.find {
|
||||||
Rect(
|
Rect(
|
||||||
@ -308,7 +298,7 @@ fun LazyGridItemScope.DraggableItem(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
.then(if (isDragged) Modifier else Modifier.animateItemPlacement())
|
.then(if (isDragged) Modifier else Modifier.animateItemPlacement())
|
||||||
.zIndex(if (isDragged) 1f else 0f)
|
.zIndex(if (isDragged) 1f else 0f)
|
||||||
.offset {
|
.absoluteOffset {
|
||||||
if (state.draggedItem?.key == key) {
|
if (state.draggedItem?.key == key) {
|
||||||
state.draggedItemOffset?.toIntOffset() ?: IntOffset.Zero
|
state.draggedItemOffset?.toIntOffset() ?: IntOffset.Zero
|
||||||
} else if (state.droppedItemKey == key) {
|
} else if (state.droppedItemKey == key) {
|
||||||
|
|||||||
@ -12,17 +12,20 @@ import de.mm20.launcher2.searchable.SavableSearchableRepository
|
|||||||
import de.mm20.launcher2.globalactions.GlobalActionsService
|
import de.mm20.launcher2.globalactions.GlobalActionsService
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ColorScheme
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
|
import de.mm20.launcher2.preferences.ScreenOrientation
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.ui.gestures.Gesture
|
import de.mm20.launcher2.ui.gestures.Gesture
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -32,7 +35,8 @@ import org.koin.core.component.inject
|
|||||||
|
|
||||||
class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
private val gestureSettings: GestureSettings by inject()
|
||||||
private val globalActionsService: GlobalActionsService by inject()
|
private val globalActionsService: GlobalActionsService by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
@ -40,40 +44,41 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
private var isSystemInDarkMode = MutableStateFlow(false)
|
private var isSystemInDarkMode = MutableStateFlow(false)
|
||||||
|
|
||||||
private val dimBackgroundState = combine(
|
private val dimBackgroundState = combine(
|
||||||
dataStore.data.map { it.appearance.dimWallpaper },
|
uiSettings.dimWallpaper,
|
||||||
dataStore.data.map { it.appearance.theme },
|
uiSettings.colorScheme,
|
||||||
isSystemInDarkMode
|
isSystemInDarkMode
|
||||||
) { dim, theme, systemDarkMode ->
|
) { dim, theme, systemDarkMode ->
|
||||||
dim && (theme == Settings.AppearanceSettings.Theme.Dark || theme == Settings.AppearanceSettings.Theme.System && systemDarkMode)
|
dim && (theme == ColorScheme.Dark || theme == ColorScheme.System && systemDarkMode)
|
||||||
}
|
}
|
||||||
val dimBackground = dimBackgroundState.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
val dimBackground = dimBackgroundState.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
val statusBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
val statusBarColor = uiSettings.statusBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val navBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
val navBarColor = uiSettings.navigationBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val chargingAnimation = dataStore.data.map { it.animations.charging }
|
val chargingAnimation = uiSettings.chargingAnimation
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
val hideNavBar = uiSettings.hideNavigationBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
val hideStatusBar = uiSettings.hideStatusBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setSystemInDarkMode(darkMode: Boolean) {
|
fun setSystemInDarkMode(darkMode: Boolean) {
|
||||||
isSystemInDarkMode.value = darkMode
|
isSystemInDarkMode.value = darkMode
|
||||||
}
|
}
|
||||||
|
|
||||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
val baseLayout = uiSettings.baseLayout
|
||||||
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
val bottomSearchBar = uiSettings.bottomSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
val reverseSearchResults = uiSettings.reverseSearchResults
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
val fixedSearchBar = uiSettings.fixedSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
|
val fixedRotation = uiSettings.orientation
|
||||||
|
.map { it != ScreenOrientation.Auto }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
val isSearchOpen = mutableStateOf(false)
|
val isSearchOpen = mutableStateOf(false)
|
||||||
@ -81,8 +86,7 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val searchBarFocused = mutableStateOf(false)
|
val searchBarFocused = mutableStateOf(false)
|
||||||
|
|
||||||
|
val autoFocusSearch = uiSettings.openKeyboardOnSearch
|
||||||
val autoFocusSearch = dataStore.data.map { it.searchBar.autoFocus }
|
|
||||||
|
|
||||||
fun setSearchbarFocus(focused: Boolean) {
|
fun setSearchbarFocus(focused: Boolean) {
|
||||||
if (searchBarFocused.value != focused) searchBarFocused.value = focused
|
if (searchBarFocused.value != focused) searchBarFocused.value = focused
|
||||||
@ -120,45 +124,43 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
isWidgetEditMode.value = editMode
|
isWidgetEditMode.value = editMode
|
||||||
}
|
}
|
||||||
|
|
||||||
val wallpaperBlur = dataStore.data.map { it.appearance.blurWallpaper }
|
val wallpaperBlur = uiSettings.blurWallpaper
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||||
val wallpaperBlurRadius = dataStore.data.map { it.appearance.blurWallpaperRadius }
|
val wallpaperBlurRadius = uiSettings.wallpaperBlurRadius
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
||||||
|
|
||||||
|
|
||||||
val fillClockHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
val fillClockHeight = uiSettings.clockFillScreen
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
val searchBarColor = uiSettings.searchBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarColors.Auto)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SearchBarColors.Auto)
|
||||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
val searchBarStyle = uiSettings.searchBarStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), SearchBarStyle.Transparent)
|
||||||
|
|
||||||
val gestureState: StateFlow<GestureState> = dataStore
|
val gestureState: StateFlow<GestureState> = gestureSettings
|
||||||
.data.map { it.gestures }
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.combine(baseLayout) { settings, layout ->
|
.combine(baseLayout) { settings, layout ->
|
||||||
val swipeLeftAction =
|
val swipeLeftAction =
|
||||||
settings?.swipeLeft?.takeIf { layout != Layout.Pager } ?: GestureAction.None
|
settings.swipeLeft.takeIf { layout != BaseLayout.Pager } ?: GestureAction.NoAction
|
||||||
val swipeRightAction = settings?.swipeRight?.takeIf { layout != Layout.PagerReversed }
|
val swipeRightAction = settings.swipeRight.takeIf { layout != BaseLayout.PagerReversed }
|
||||||
?: GestureAction.None
|
?: GestureAction.NoAction
|
||||||
val swipeDownAction =
|
val swipeDownAction =
|
||||||
settings?.swipeDown?.takeIf { layout != Layout.PullDown } ?: GestureAction.None
|
settings.swipeDown.takeIf { layout != BaseLayout.PullDown } ?: GestureAction.NoAction
|
||||||
val longPressAction = settings?.longPress ?: GestureAction.None
|
val longPressAction = settings.longPress
|
||||||
val doubleTapAction = settings?.doubleTap ?: GestureAction.None
|
val doubleTapAction = settings.doubleTap
|
||||||
val homeButtonAction = settings?.homeButton ?: GestureAction.None
|
val homeButtonAction = settings.homeButton
|
||||||
|
|
||||||
val swipeLeftAppKey =
|
val swipeLeftAppKey =
|
||||||
if (swipeLeftAction == GestureAction.LaunchApp) settings.swipeLeftApp else null
|
if (swipeLeftAction is GestureAction.Launch) swipeLeftAction.key else null
|
||||||
val swipeRightAppKey =
|
val swipeRightAppKey =
|
||||||
if (swipeRightAction == GestureAction.LaunchApp) settings.swipeRightApp else null
|
if (swipeRightAction is GestureAction.Launch) swipeRightAction.key else null
|
||||||
val swipeDownAppKey =
|
val swipeDownAppKey =
|
||||||
if (swipeDownAction == GestureAction.LaunchApp) settings.swipeDownApp else null
|
if (swipeDownAction is GestureAction.Launch) swipeDownAction.key else null
|
||||||
val longPressAppKey =
|
val longPressAppKey =
|
||||||
if (longPressAction == GestureAction.LaunchApp) settings.longPressApp else null
|
if (longPressAction is GestureAction.Launch) longPressAction.key else null
|
||||||
val doubleTapAppKey =
|
val doubleTapAppKey =
|
||||||
if (doubleTapAction == GestureAction.LaunchApp) settings.doubleTapApp else null
|
if (doubleTapAction is GestureAction.Launch) doubleTapAction.key else null
|
||||||
val homeButtonAppKey =
|
val homeButtonAppKey =
|
||||||
if (homeButtonAction == GestureAction.LaunchApp) settings.homeButtonApp else null
|
if (homeButtonAction is GestureAction.Launch) homeButtonAction.key else null
|
||||||
val apps = listOfNotNull(
|
val apps = listOfNotNull(
|
||||||
swipeLeftAppKey,
|
swipeLeftAppKey,
|
||||||
swipeRightAppKey,
|
swipeRightAppKey,
|
||||||
@ -189,17 +191,17 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
val action = when (gesture) {
|
val action = when (gesture) {
|
||||||
Gesture.DoubleTap -> gestureState.value.doubleTapAction
|
Gesture.DoubleTap -> gestureState.value.doubleTapAction
|
||||||
Gesture.LongPress -> gestureState.value.longPressAction
|
Gesture.LongPress -> gestureState.value.longPressAction
|
||||||
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != Layout.PullDown }
|
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != BaseLayout.PullDown }
|
||||||
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != Layout.Pager }
|
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != BaseLayout.Pager }
|
||||||
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != Layout.PagerReversed }
|
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != BaseLayout.PagerReversed }
|
||||||
Gesture.HomeButton -> gestureState.value.homeButtonAction
|
Gesture.HomeButton -> gestureState.value.homeButtonAction
|
||||||
}
|
}
|
||||||
val requiresAccessibilityService =
|
val requiresAccessibilityService =
|
||||||
action == GestureAction.OpenRecents
|
action is GestureAction.Recents
|
||||||
|| action == GestureAction.OpenPowerDialog
|
|| action is GestureAction.PowerMenu
|
||||||
|| action == GestureAction.OpenQuickSettings
|
|| action is GestureAction.QuickSettings
|
||||||
|| action == GestureAction.OpenNotificationDrawer
|
|| action is GestureAction.Notifications
|
||||||
|| action == GestureAction.LockScreen
|
|| action is GestureAction.ScreenLock
|
||||||
|
|
||||||
if (action != null && requiresAccessibilityService && !permissionsManager.checkPermissionOnce(
|
if (action != null && requiresAccessibilityService && !permissionsManager.checkPermissionOnce(
|
||||||
PermissionGroup.Accessibility
|
PermissionGroup.Accessibility
|
||||||
@ -211,37 +213,37 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
|
|
||||||
return when (action) {
|
return when (action) {
|
||||||
GestureAction.OpenSearch -> {
|
is GestureAction.Search -> {
|
||||||
openSearch()
|
openSearch()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenNotificationDrawer -> {
|
is GestureAction.Notifications -> {
|
||||||
globalActionsService.openNotificationDrawer()
|
globalActionsService.openNotificationDrawer()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenQuickSettings -> {
|
is GestureAction.QuickSettings -> {
|
||||||
globalActionsService.openQuickSettings()
|
globalActionsService.openQuickSettings()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.LockScreen -> {
|
is GestureAction.ScreenLock -> {
|
||||||
globalActionsService.lockScreen()
|
globalActionsService.lockScreen()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenPowerDialog -> {
|
is GestureAction.PowerMenu -> {
|
||||||
globalActionsService.openPowerDialog()
|
globalActionsService.openPowerDialog()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.OpenRecents -> {
|
is GestureAction.Recents -> {
|
||||||
globalActionsService.openRecents()
|
globalActionsService.openRecents()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction.LaunchApp -> {
|
is GestureAction.Launch -> {
|
||||||
val view = (context as Activity).window.decorView
|
val view = (context as Activity).window.decorView
|
||||||
val options = ActivityOptionsCompat.makeScaleUpAnimation(
|
val options = ActivityOptionsCompat.makeScaleUpAnimation(
|
||||||
view,
|
view,
|
||||||
@ -271,12 +273,12 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class GestureState(
|
data class GestureState(
|
||||||
val swipeLeftAction: GestureAction = GestureAction.None,
|
val swipeLeftAction: GestureAction = GestureAction.NoAction,
|
||||||
val swipeRightAction: GestureAction = GestureAction.None,
|
val swipeRightAction: GestureAction = GestureAction.NoAction,
|
||||||
val swipeDownAction: GestureAction = GestureAction.None,
|
val swipeDownAction: GestureAction = GestureAction.NoAction,
|
||||||
val longPressAction: GestureAction = GestureAction.None,
|
val longPressAction: GestureAction = GestureAction.NoAction,
|
||||||
val doubleTapAction: GestureAction = GestureAction.None,
|
val doubleTapAction: GestureAction = GestureAction.NoAction,
|
||||||
val homeButtonAction: GestureAction = GestureAction.None,
|
val homeButtonAction: GestureAction = GestureAction.NoAction,
|
||||||
val swipeLeftApp: SavableSearchable? = null,
|
val swipeLeftApp: SavableSearchable? = null,
|
||||||
val swipeRightApp: SavableSearchable? = null,
|
val swipeRightApp: SavableSearchable? = null,
|
||||||
val swipeDownApp: SavableSearchable? = null,
|
val swipeDownApp: SavableSearchable? = null,
|
||||||
|
|||||||
@ -81,11 +81,12 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|||||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.Velocity
|
import androidx.compose.ui.unit.Velocity
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
@ -398,7 +399,7 @@ fun PagerScaffold(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.nestedScroll(pagerNestedScrollConnection),
|
.nestedScroll(pagerNestedScrollConnection),
|
||||||
beyondBoundsPageCount = 1,
|
beyondBoundsPageCount = 1,
|
||||||
reverseLayout = reverse,
|
reverseLayout = reverse == (LocalLayoutDirection.current == LayoutDirection.Ltr),
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
userScrollEnabled = false,//!isWidgetEditMode,
|
userScrollEnabled = false,//!isWidgetEditMode,
|
||||||
flingBehavior = PagerDefaults.flingBehavior(
|
flingBehavior = PagerDefaults.flingBehavior(
|
||||||
@ -406,7 +407,6 @@ fun PagerScaffold(
|
|||||||
lowVelocityAnimationSpec = spring(
|
lowVelocityAnimationSpec = spring(
|
||||||
stiffness = Spring.StiffnessMediumLow,
|
stiffness = Spring.StiffnessMediumLow,
|
||||||
),
|
),
|
||||||
snapVelocityThreshold = 1000.dp,
|
|
||||||
pagerSnapDistance = remember {
|
pagerSnapDistance = remember {
|
||||||
object : PagerSnapDistance {
|
object : PagerSnapDistance {
|
||||||
override fun calculateTargetPage(
|
override fun calculateTargetPage(
|
||||||
|
|||||||
@ -68,7 +68,7 @@ import androidx.compose.ui.unit.Velocity
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
@ -605,7 +605,7 @@ fun PullDownScaffold(
|
|||||||
showHiddenItemsButton = isSearchOpen,
|
showHiddenItemsButton = isSearchOpen,
|
||||||
value = { value },
|
value = { value },
|
||||||
onValueChange = { searchVM.search(it) },
|
onValueChange = { searchVM.search(it) },
|
||||||
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == Settings.SearchBarSettings.SearchBarColors.Auto || searchBarColor == Settings.SearchBarSettings.SearchBarColors.Dark,
|
darkColors = LocalPreferDarkContentOverWallpaper.current && searchBarColor == SearchBarColors.Auto || searchBarColor == SearchBarColors.Dark,
|
||||||
style = searchBarStyle,
|
style = searchBarStyle,
|
||||||
reverse = bottomSearchBar,
|
reverse = bottomSearchBar,
|
||||||
onKeyboardActionGo = if (launchOnEnter) {
|
onKeyboardActionGo = if (launchOnEnter) {
|
||||||
|
|||||||
@ -34,8 +34,8 @@ import androidx.core.view.WindowInsetsControllerCompat
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.flowWithLifecycle
|
import androidx.lifecycle.flowWithLifecycle
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings.SystemBarColors
|
import de.mm20.launcher2.preferences.SystemBarColors
|
||||||
import de.mm20.launcher2.ui.assistant.AssistantScaffold
|
import de.mm20.launcher2.ui.assistant.AssistantScaffold
|
||||||
import de.mm20.launcher2.ui.base.BaseActivity
|
import de.mm20.launcher2.ui.base.BaseActivity
|
||||||
import de.mm20.launcher2.ui.base.ProvideCurrentTime
|
import de.mm20.launcher2.ui.base.ProvideCurrentTime
|
||||||
@ -184,7 +184,7 @@ abstract class SharedLauncherActivity(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
when (layout) {
|
when (layout) {
|
||||||
Settings.LayoutSettings.Layout.PullDown -> {
|
BaseLayout.PullDown -> {
|
||||||
key(bottomSearchBar, reverseSearchResults) {
|
key(bottomSearchBar, reverseSearchResults) {
|
||||||
PullDownScaffold(
|
PullDownScaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -205,8 +205,8 @@ abstract class SharedLauncherActivity(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings.LayoutSettings.Layout.Pager,
|
BaseLayout.Pager,
|
||||||
Settings.LayoutSettings.Layout.PagerReversed -> {
|
BaseLayout.PagerReversed -> {
|
||||||
key(bottomSearchBar, reverseSearchResults) {
|
key(bottomSearchBar, reverseSearchResults) {
|
||||||
PagerScaffold(
|
PagerScaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -220,7 +220,7 @@ abstract class SharedLauncherActivity(
|
|||||||
},
|
},
|
||||||
darkStatusBarIcons = lightStatus,
|
darkStatusBarIcons = lightStatus,
|
||||||
darkNavBarIcons = lightNav,
|
darkNavBarIcons = lightNav,
|
||||||
reverse = layout == Settings.LayoutSettings.Layout.PagerReversed,
|
reverse = layout == BaseLayout.PagerReversed,
|
||||||
bottomSearchBar = bottomSearchBar,
|
bottomSearchBar = bottomSearchBar,
|
||||||
reverseSearchResults = reverseSearchResults,
|
reverseSearchResults = reverseSearchResults,
|
||||||
fixedSearchBar = fixedSearchBar,
|
fixedSearchBar = fixedSearchBar,
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import androidx.compose.ui.platform.LocalView
|
|||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.ui.component.FakeSplashScreen
|
import de.mm20.launcher2.ui.component.FakeSplashScreen
|
||||||
import de.mm20.launcher2.ui.gestures.Gesture
|
import de.mm20.launcher2.ui.gestures.Gesture
|
||||||
@ -52,7 +52,7 @@ fun LauncherGestureHandler(
|
|||||||
|
|
||||||
val gestureState by viewModel.gestureState.collectAsState(GestureState())
|
val gestureState by viewModel.gestureState.collectAsState(GestureState())
|
||||||
|
|
||||||
val shouldDetectDoubleTapGesture = gestureState.doubleTapAction != GestureAction.None
|
val shouldDetectDoubleTapGesture = gestureState.doubleTapAction !is GestureAction.NoAction
|
||||||
|
|
||||||
LaunchedEffect(shouldDetectDoubleTapGesture) {
|
LaunchedEffect(shouldDetectDoubleTapGesture) {
|
||||||
gestureDetector.shouldDetectDoubleTaps = shouldDetectDoubleTapGesture
|
gestureDetector.shouldDetectDoubleTaps = shouldDetectDoubleTapGesture
|
||||||
|
|||||||
@ -5,25 +5,30 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
|
||||||
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LegacySettings.SearchResultOrderingSettings.Ordering
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.Ordering
|
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||||
|
import de.mm20.launcher2.preferences.search.CalendarSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
import de.mm20.launcher2.search.AppProfile
|
import de.mm20.launcher2.search.AppProfile
|
||||||
|
import de.mm20.launcher2.search.AppShortcut
|
||||||
|
import de.mm20.launcher2.search.Application
|
||||||
|
import de.mm20.launcher2.search.Article
|
||||||
|
import de.mm20.launcher2.search.CalendarEvent
|
||||||
import de.mm20.launcher2.search.Contact
|
import de.mm20.launcher2.search.Contact
|
||||||
import de.mm20.launcher2.search.File
|
import de.mm20.launcher2.search.File
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.SearchService
|
import de.mm20.launcher2.search.SearchService
|
||||||
import de.mm20.launcher2.search.Searchable
|
import de.mm20.launcher2.search.Searchable
|
||||||
import de.mm20.launcher2.search.AppShortcut
|
|
||||||
import de.mm20.launcher2.search.Application
|
|
||||||
import de.mm20.launcher2.search.Article
|
|
||||||
import de.mm20.launcher2.search.CalendarEvent
|
|
||||||
import de.mm20.launcher2.search.Website
|
import de.mm20.launcher2.search.Website
|
||||||
import de.mm20.launcher2.search.data.Calculator
|
import de.mm20.launcher2.search.data.Calculator
|
||||||
import de.mm20.launcher2.search.data.UnitConverter
|
import de.mm20.launcher2.search.data.UnitConverter
|
||||||
|
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
@ -32,7 +37,6 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
@ -47,10 +51,14 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
private val favoritesService: FavoritesService by inject()
|
private val favoritesService: FavoritesService by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
private val fileSearchSettings: FileSearchSettings by inject()
|
|
||||||
|
|
||||||
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
|
private val fileSearchSettings: FileSearchSettings by inject()
|
||||||
|
private val contactSearchSettings: ContactSearchSettings by inject()
|
||||||
|
private val calendarSearchSettings: CalendarSearchSettings by inject()
|
||||||
|
private val shortcutSearchSettings: ShortcutSearchSettings by inject()
|
||||||
|
private val searchUiSettings: SearchUiSettings by inject()
|
||||||
|
|
||||||
|
val launchOnEnter = searchUiSettings.launchOnEnter
|
||||||
.stateIn(viewModelScope, SharingStarted.Eagerly, false)
|
.stateIn(viewModelScope, SharingStarted.Eagerly, false)
|
||||||
|
|
||||||
private val searchService: SearchService by inject()
|
private val searchService: SearchService by inject()
|
||||||
@ -70,10 +78,10 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
val unitConverterResults = mutableStateOf<List<UnitConverter>>(emptyList())
|
val unitConverterResults = mutableStateOf<List<UnitConverter>>(emptyList())
|
||||||
val searchActionResults = mutableStateOf<List<SearchAction>>(emptyList())
|
val searchActionResults = mutableStateOf<List<SearchAction>>(emptyList())
|
||||||
|
|
||||||
val hiddenResultsButton = dataStore.data.map { it.searchBar.hiddenItemsButton }
|
val hiddenResultsButton = searchUiSettings.hiddenItemsButton
|
||||||
val hiddenResults = mutableStateOf<List<SavableSearchable>>(emptyList())
|
val hiddenResults = mutableStateOf<List<SavableSearchable>>(emptyList())
|
||||||
|
|
||||||
val favoritesEnabled = dataStore.data.map { it.favorites.enabled }
|
val favoritesEnabled = searchUiSettings.favorites
|
||||||
val hideFavorites = mutableStateOf(false)
|
val hideFavorites = mutableStateOf(false)
|
||||||
|
|
||||||
private val hiddenItemKeys = searchableRepository
|
private val hiddenItemKeys = searchableRepository
|
||||||
@ -117,16 +125,9 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
hideFavorites.value = query.isNotEmpty()
|
hideFavorites.value = query.isNotEmpty()
|
||||||
searchJob = viewModelScope.launch {
|
searchJob = viewModelScope.launch {
|
||||||
dataStore.data.collectLatest { settings ->
|
searchUiSettings.resultOrder.collectLatest { resultOrder ->
|
||||||
searchService.search(
|
searchService.search(
|
||||||
query,
|
query
|
||||||
calculator = settings.calculatorSearch,
|
|
||||||
unitConverter = settings.unitConverterSearch,
|
|
||||||
calendars = settings.calendarSearch,
|
|
||||||
contacts = settings.contactsSearch,
|
|
||||||
shortcuts = settings.appShortcutSearch,
|
|
||||||
websites = settings.websiteSearch,
|
|
||||||
wikipedia = settings.wikipediaSearch,
|
|
||||||
).collectLatest { results ->
|
).collectLatest { results ->
|
||||||
var resultsList = withContext(Dispatchers.Default) {
|
var resultsList = withContext(Dispatchers.Default) {
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
@ -151,13 +152,13 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
emptyList()
|
emptyList()
|
||||||
} else {
|
} else {
|
||||||
val keys = resultsList.mapNotNull { (it as? SavableSearchable)?.key }
|
val keys = resultsList.mapNotNull { (it as? SavableSearchable)?.key }
|
||||||
when (settings.resultOrdering.ordering) {
|
when (resultOrder) {
|
||||||
|
|
||||||
Ordering.LaunchCount -> searchableRepository.sortByRelevance(
|
SearchResultOrder.LaunchCount -> searchableRepository.sortByRelevance(
|
||||||
keys
|
keys
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
Ordering.Weighted -> searchableRepository.sortByWeight(
|
SearchResultOrder.Weighted -> searchableRepository.sortByWeight(
|
||||||
keys
|
keys
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
@ -256,7 +257,7 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val missingCalendarPermission = combine(
|
val missingCalendarPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.Calendar),
|
permissionsManager.hasPermission(PermissionGroup.Calendar),
|
||||||
dataStore.data.map { it.calendarSearch.enabled }.distinctUntilChanged()
|
calendarSearchSettings.enabled,
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestCalendarPermission(context: AppCompatActivity) {
|
fun requestCalendarPermission(context: AppCompatActivity) {
|
||||||
@ -264,18 +265,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableCalendarSearch() {
|
fun disableCalendarSearch() {
|
||||||
viewModelScope.launch {
|
calendarSearchSettings.setEnabled(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCalendarSearch(it.calendarSearch.toBuilder().setEnabled(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val missingContactsPermission = combine(
|
val missingContactsPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.Contacts),
|
permissionsManager.hasPermission(PermissionGroup.Contacts),
|
||||||
dataStore.data.map { it.contactsSearch.enabled }.distinctUntilChanged()
|
contactSearchSettings.enabled
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestContactsPermission(context: AppCompatActivity) {
|
fun requestContactsPermission(context: AppCompatActivity) {
|
||||||
@ -283,18 +278,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableContactsSearch() {
|
fun disableContactsSearch() {
|
||||||
viewModelScope.launch {
|
contactSearchSettings.setEnabled(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setContactsSearch(it.contactsSearch.toBuilder().setEnabled(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val missingFilesPermission = combine(
|
val missingFilesPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.ExternalStorage),
|
permissionsManager.hasPermission(PermissionGroup.ExternalStorage),
|
||||||
fileSearchSettings.localFiles.distinctUntilChanged()
|
fileSearchSettings.localFiles
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestFilesPermission(context: AppCompatActivity) {
|
fun requestFilesPermission(context: AppCompatActivity) {
|
||||||
@ -302,18 +291,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableFilesSearch() {
|
fun disableFilesSearch() {
|
||||||
viewModelScope.launch {
|
fileSearchSettings.setLocalFiles(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFileSearch(it.fileSearch.toBuilder().setLocalFiles(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val missingAppShortcutPermission = combine(
|
val missingAppShortcutPermission = combine(
|
||||||
permissionsManager.hasPermission(PermissionGroup.AppShortcuts),
|
permissionsManager.hasPermission(PermissionGroup.AppShortcuts),
|
||||||
dataStore.data.map { it.appShortcutSearch.enabled }.distinctUntilChanged()
|
shortcutSearchSettings.enabled,
|
||||||
) { perm, enabled -> !perm && enabled }
|
) { perm, enabled -> !perm && enabled }
|
||||||
|
|
||||||
fun requestAppShortcutPermission(context: AppCompatActivity) {
|
fun requestAppShortcutPermission(context: AppCompatActivity) {
|
||||||
@ -321,12 +304,6 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disableAppShortcutSearch() {
|
fun disableAppShortcutSearch() {
|
||||||
viewModelScope.launch {
|
shortcutSearchSettings.setEnabled(false)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppShortcutSearch(it.appShortcutSearch.toBuilder().setEnabled(false))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,29 +1,22 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.search.favorites
|
package de.mm20.launcher2.ui.launcher.search.favorites
|
||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiState
|
||||||
import de.mm20.launcher2.ui.common.FavoritesVM
|
import de.mm20.launcher2.ui.common.FavoritesVM
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class SearchFavoritesVM : FavoritesVM() {
|
class SearchFavoritesVM : FavoritesVM() {
|
||||||
override val tagsExpanded: Flow<Boolean> = dataStore.data.map { it.ui.searchTagsMultiline }
|
private val uiState: UiState by inject()
|
||||||
.shareIn(viewModelScope, SharingStarted.Lazily)
|
|
||||||
|
override val tagsExpanded: Flow<Boolean> = uiState.favoritesTagsExpanded
|
||||||
|
|
||||||
override fun setTagsExpanded(expanded: Boolean) {
|
override fun setTagsExpanded(expanded: Boolean) {
|
||||||
viewModelScope.launch {
|
uiState.setFavoritesTagsExpanded(expanded)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setUi(
|
|
||||||
it.ui.toBuilder()
|
|
||||||
.setSearchTagsMultiline(expanded)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||||
import de.mm20.launcher2.ui.component.SearchBar
|
import de.mm20.launcher2.ui.component.SearchBar
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
@ -29,7 +29,7 @@ import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
|
|||||||
@Composable
|
@Composable
|
||||||
fun LauncherSearchBar(
|
fun LauncherSearchBar(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
style: Settings.SearchBarSettings.SearchBarStyle,
|
style: SearchBarStyle,
|
||||||
level: () -> SearchBarLevel,
|
level: () -> SearchBarLevel,
|
||||||
value: () -> String,
|
value: () -> String,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
|
|||||||
import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.Edit
|
||||||
import androidx.compose.material.icons.rounded.HelpOutline
|
import androidx.compose.material.icons.rounded.HelpOutline
|
||||||
import androidx.compose.material.icons.rounded.Settings
|
import androidx.compose.material.icons.rounded.Settings
|
||||||
import androidx.compose.material.icons.rounded.Wallpaper
|
import androidx.compose.material.icons.rounded.Wallpaper
|
||||||
@ -20,6 +21,7 @@ import androidx.compose.material3.LocalContentColor
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@ -27,7 +29,10 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
|
import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM
|
||||||
|
import de.mm20.launcher2.ui.launcher.widgets.WidgetsVM
|
||||||
import de.mm20.launcher2.ui.settings.SettingsActivity
|
import de.mm20.launcher2.ui.settings.SettingsActivity
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -38,6 +43,8 @@ fun RowScope.SearchBarMenu(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
var showOverflowMenu by remember { mutableStateOf(false) }
|
var showOverflowMenu by remember { mutableStateOf(false) }
|
||||||
val rightIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_menu_clear)
|
val rightIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_menu_clear)
|
||||||
|
val launcherVM: LauncherScaffoldVM = viewModel()
|
||||||
|
val widgetsVM: WidgetsVM = viewModel()
|
||||||
|
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
if (searchBarValue.isNotBlank()) onSearchBarValueChange("")
|
if (searchBarValue.isNotBlank()) onSearchBarValueChange("")
|
||||||
@ -70,6 +77,22 @@ fun RowScope.SearchBarMenu(
|
|||||||
Icon(imageVector = Icons.Rounded.Wallpaper, contentDescription = null)
|
Icon(imageVector = Icons.Rounded.Wallpaper, contentDescription = null)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
val editButton by widgetsVM.editButton.collectAsState()
|
||||||
|
val searchOpen by launcherVM.isSearchOpen
|
||||||
|
if (!searchOpen && editButton == false) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
launcherVM.setWidgetEditMode(editMode = true)
|
||||||
|
showOverflowMenu = false
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(stringResource(R.string.menu_edit_widgets))
|
||||||
|
},
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(imageVector = Icons.Rounded.Edit, contentDescription = null)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
onClick = {
|
onClick = {
|
||||||
context.startActivity(Intent(context, SettingsActivity::class.java))
|
context.startActivity(Intent(context, SettingsActivity::class.java))
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.sheets
|
package de.mm20.launcher2.ui.launcher.sheets
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.LauncherApps
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.IntentSenderRequest
|
import androidx.activity.result.IntentSenderRequest
|
||||||
@ -33,7 +31,6 @@ import androidx.compose.material.icons.rounded.Delete
|
|||||||
import androidx.compose.material.icons.rounded.Settings
|
import androidx.compose.material.icons.rounded.Settings
|
||||||
import androidx.compose.material.icons.rounded.Tag
|
import androidx.compose.material.icons.rounded.Tag
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.Divider
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.FilledTonalIconButton
|
import androidx.compose.material3.FilledTonalIconButton
|
||||||
@ -65,12 +62,13 @@ import androidx.compose.ui.graphics.drawOutline
|
|||||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.Density
|
import androidx.compose.ui.unit.Density
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.toOffset
|
import androidx.compose.ui.unit.toOffset
|
||||||
import androidx.compose.ui.unit.toSize
|
import androidx.compose.ui.unit.toSize
|
||||||
@ -173,6 +171,7 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding
|
|||||||
val tagsListState = rememberLazyListState()
|
val tagsListState = rememberLazyListState()
|
||||||
val tagsTitleSize = 48.dp.toPixels()
|
val tagsTitleSize = 48.dp.toPixels()
|
||||||
val tagsSpacing = 12.dp.toPixels()
|
val tagsSpacing = 12.dp.toPixels()
|
||||||
|
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
|
||||||
val state = rememberLazyDragAndDropGridState(
|
val state = rememberLazyDragAndDropGridState(
|
||||||
gridState = gridState,
|
gridState = gridState,
|
||||||
onDragStart = {
|
onDragStart = {
|
||||||
@ -200,8 +199,11 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding
|
|||||||
&& hoveredItem.offset.y + tagsTitleSize < position.y
|
&& hoveredItem.offset.y + tagsTitleSize < position.y
|
||||||
) {
|
) {
|
||||||
val scroll = tagsListState.layoutInfo.viewportStartOffset
|
val scroll = tagsListState.layoutInfo.viewportStartOffset
|
||||||
|
val relCenter =
|
||||||
|
if (isRtl) draggedCenter.copy(x = tagsListState.layoutInfo.viewportSize.width - draggedCenter.x)
|
||||||
|
else draggedCenter
|
||||||
val tag = tagsListState.layoutInfo.visibleItemsInfo.find {
|
val tag = tagsListState.layoutInfo.visibleItemsInfo.find {
|
||||||
draggedCenter.x + scroll > it.offset && draggedCenter.x + scroll < it.offset + it.size - tagsSpacing
|
relCenter.x + scroll > it.offset && relCenter.x + scroll < it.offset + it.size - tagsSpacing
|
||||||
}
|
}
|
||||||
hoveredTag = tag?.index?.let { pinnedTags[it].tag }
|
hoveredTag = tag?.index?.let { pinnedTags[it].tag }
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -17,9 +17,9 @@ import de.mm20.launcher2.icons.LauncherIcon
|
|||||||
import de.mm20.launcher2.ktx.normalize
|
import de.mm20.launcher2.ktx.normalize
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.appshortcuts.AppShortcut
|
import de.mm20.launcher2.appshortcuts.AppShortcut
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
import de.mm20.launcher2.search.Searchable
|
import de.mm20.launcher2.search.Searchable
|
||||||
import de.mm20.launcher2.search.data.Tag
|
import de.mm20.launcher2.search.data.Tag
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
@ -41,7 +41,7 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
|||||||
private val badgeService: BadgeService by inject()
|
private val badgeService: BadgeService by inject()
|
||||||
private val customAttributesRepository: CustomAttributesRepository by inject()
|
private val customAttributesRepository: CustomAttributesRepository by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val favoritesSettings: FavoritesSettings by inject()
|
||||||
|
|
||||||
val gridItems = mutableStateOf<List<FavoritesSheetGridItem>>(emptyList())
|
val gridItems = mutableStateOf<List<FavoritesSheetGridItem>>(emptyList())
|
||||||
|
|
||||||
@ -245,36 +245,16 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val enableFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
val enableFrequentlyUsed = favoritesSettings.frequentlyUsed
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsed(frequentlyUsed)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites
|
|
||||||
.toBuilder()
|
|
||||||
.setFrequentlyUsed(frequentlyUsed)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
val frequentlyUsedRows = favoritesSettings.frequentlyUsedRows
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites
|
|
||||||
.toBuilder()
|
|
||||||
.setFrequentlyUsedRows(frequentlyUsedRows)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pinTag(tag: Tag) {
|
fun pinTag(tag: Tag) {
|
||||||
|
|||||||
@ -14,7 +14,8 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
@ -29,12 +30,12 @@ fun FailedGestureSheet(
|
|||||||
val viewModel: FailedGestureSheetVM = viewModel()
|
val viewModel: FailedGestureSheetVM = viewModel()
|
||||||
|
|
||||||
val actionName = stringResource(when(failedGesture.action) {
|
val actionName = stringResource(when(failedGesture.action) {
|
||||||
Settings.GestureSettings.GestureAction.OpenSearch -> R.string.gesture_action_open_search
|
is GestureAction.Search -> R.string.gesture_action_open_search
|
||||||
Settings.GestureSettings.GestureAction.OpenNotificationDrawer -> R.string.gesture_action_notifications
|
is GestureAction.Notifications -> R.string.gesture_action_notifications
|
||||||
Settings.GestureSettings.GestureAction.LockScreen -> R.string.gesture_action_lock_screen
|
is GestureAction.ScreenLock -> R.string.gesture_action_lock_screen
|
||||||
Settings.GestureSettings.GestureAction.OpenQuickSettings -> R.string.gesture_action_quick_settings
|
is GestureAction.QuickSettings -> R.string.gesture_action_quick_settings
|
||||||
Settings.GestureSettings.GestureAction.OpenRecents -> R.string.gesture_action_recents
|
is GestureAction.Recents -> R.string.gesture_action_recents
|
||||||
Settings.GestureSettings.GestureAction.OpenPowerDialog -> R.string.gesture_action_power_menu
|
is GestureAction.PowerMenu -> R.string.gesture_action_power_menu
|
||||||
else -> R.string.gesture_action_none
|
else -> R.string.gesture_action_none
|
||||||
})
|
})
|
||||||
val gestureName = stringResource(when(failedGesture.gesture) {
|
val gestureName = stringResource(when(failedGesture.gesture) {
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
import de.mm20.launcher2.ui.gestures.Gesture
|
import de.mm20.launcher2.ui.gestures.Gesture
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@ -14,28 +14,20 @@ import org.koin.core.component.inject
|
|||||||
|
|
||||||
class FailedGestureSheetVM : ViewModel(), KoinComponent {
|
class FailedGestureSheetVM : ViewModel(), KoinComponent {
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val gestureSettings: GestureSettings by inject()
|
||||||
|
|
||||||
fun requestPermission(context: AppCompatActivity) {
|
fun requestPermission(context: AppCompatActivity) {
|
||||||
permissionsManager.requestPermission(context, PermissionGroup.Accessibility)
|
permissionsManager.requestPermission(context, PermissionGroup.Accessibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableGesture(gesture: Gesture) {
|
fun disableGesture(gesture: Gesture) {
|
||||||
viewModelScope.launch {
|
when(gesture) {
|
||||||
dataStore.updateData {
|
Gesture.DoubleTap -> gestureSettings.setDoubleTap(GestureAction.NoAction)
|
||||||
it.toBuilder().setGestures(
|
Gesture.LongPress -> gestureSettings.setLongPress(GestureAction.NoAction)
|
||||||
it.gestures.toBuilder().apply {
|
Gesture.SwipeDown -> gestureSettings.setSwipeDown(GestureAction.NoAction)
|
||||||
when (gesture) {
|
Gesture.SwipeLeft -> gestureSettings.setSwipeLeft(GestureAction.NoAction)
|
||||||
Gesture.SwipeDown -> swipeDown = GestureAction.None
|
Gesture.SwipeRight -> gestureSettings.setSwipeRight(GestureAction.NoAction)
|
||||||
Gesture.SwipeLeft -> swipeLeft = GestureAction.None
|
Gesture.HomeButton -> gestureSettings.setHomeButton(GestureAction.NoAction)
|
||||||
Gesture.SwipeRight -> swipeRight = GestureAction.None
|
|
||||||
Gesture.DoubleTap -> doubleTap = GestureAction.None
|
|
||||||
Gesture.LongPress -> longPress = GestureAction.None
|
|
||||||
Gesture.HomeButton -> homeButton = GestureAction.None
|
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ fun WidgetColumn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val editButton by viewModel.editButton.collectAsState()
|
val editButton by viewModel.editButton.collectAsState()
|
||||||
if (editButton == true) {
|
if (editMode || editButton == true) {
|
||||||
val icon =
|
val icon =
|
||||||
AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_edit_add)
|
AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_edit_add)
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets
|
package de.mm20.launcher2.ui.launcher.widgets
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.widgets.Widget
|
import de.mm20.launcher2.widgets.Widget
|
||||||
import de.mm20.launcher2.widgets.WidgetRepository
|
import de.mm20.launcher2.widgets.WidgetRepository
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
@ -15,9 +14,9 @@ import org.koin.core.component.inject
|
|||||||
class WidgetsVM : ViewModel(), KoinComponent {
|
class WidgetsVM : ViewModel(), KoinComponent {
|
||||||
private val widgetRepository: WidgetRepository by inject()
|
private val widgetRepository: WidgetRepository by inject()
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
val editButton = dataStore.data.map { it.widgets.editButton }
|
val editButton = uiSettings.widgetEditButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val widgets = widgetRepository.get()
|
val widgets = widgetRepository.get()
|
||||||
|
|||||||
@ -14,8 +14,6 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@ -64,10 +62,9 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetAlignment
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.base.LocalTime
|
import de.mm20.launcher2.ui.base.LocalTime
|
||||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||||
@ -89,7 +86,7 @@ fun ClockWidget(
|
|||||||
) {
|
) {
|
||||||
val viewModel: ClockWidgetVM = viewModel()
|
val viewModel: ClockWidgetVM = viewModel()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val layout by viewModel.layout.collectAsState()
|
val compact by viewModel.compactLayout.collectAsState()
|
||||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
val clockStyle by viewModel.clockStyle.collectAsState()
|
||||||
val color by viewModel.color.collectAsState()
|
val color by viewModel.color.collectAsState()
|
||||||
val alignment by viewModel.alignment.collectAsState()
|
val alignment by viewModel.alignment.collectAsState()
|
||||||
@ -106,7 +103,9 @@ fun ClockWidget(
|
|||||||
viewModel.updateTime(time)
|
viewModel.updateTime(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
val partProvider by remember { viewModel.getActivePart(context) }.collectAsStateWithLifecycle(null)
|
val partProvider by remember { viewModel.getActivePart(context) }.collectAsStateWithLifecycle(
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
AnimatedContent(editMode, label = "ClockWidget") {
|
AnimatedContent(editMode, label = "ClockWidget") {
|
||||||
if (it) {
|
if (it) {
|
||||||
@ -165,32 +164,32 @@ fun ClockWidget(
|
|||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalContentColor provides contentColor
|
LocalContentColor provides contentColor
|
||||||
) {
|
) {
|
||||||
if (layout == ClockWidgetLayout.Vertical) {
|
if (compact == false) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
enabled = clockStyle != ClockStyle.EmptyClock,
|
enabled = clockStyle !is ClockWidgetStyle.Empty,
|
||||||
indication = null,
|
indication = null,
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() }
|
||||||
) {
|
) {
|
||||||
viewModel.launchClockApp(context)
|
viewModel.launchClockApp(context)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Clock(clockStyle, ClockWidgetLayout.Vertical)
|
Clock(clockStyle, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partProvider != null) {
|
if (partProvider != null) {
|
||||||
DynamicZone(
|
DynamicZone(
|
||||||
modifier = Modifier.padding(bottom = 8.dp),
|
modifier = Modifier.padding(bottom = 8.dp),
|
||||||
layout = ClockWidgetLayout.Vertical,
|
compact = false,
|
||||||
provider = partProvider,
|
provider = partProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layout == ClockWidgetLayout.Horizontal) {
|
if (compact == true) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@ -201,7 +200,7 @@ fun ClockWidget(
|
|||||||
if (partProvider != null) {
|
if (partProvider != null) {
|
||||||
DynamicZone(
|
DynamicZone(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
layout = ClockWidgetLayout.Horizontal,
|
compact = true,
|
||||||
provider = partProvider,
|
provider = partProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -216,14 +215,14 @@ fun ClockWidget(
|
|||||||
)
|
)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
enabled = clockStyle != ClockStyle.EmptyClock,
|
enabled = clockStyle !is ClockWidgetStyle.Empty,
|
||||||
indication = null,
|
indication = null,
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() }
|
||||||
) {
|
) {
|
||||||
viewModel.launchClockApp(context)
|
viewModel.launchClockApp(context)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Clock(clockStyle, ClockWidgetLayout.Horizontal)
|
Clock(clockStyle, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +235,7 @@ fun ClockWidget(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(bottom = 16.dp)
|
.padding(bottom = 16.dp)
|
||||||
) {
|
) {
|
||||||
dockProvider?.Component(ClockWidgetLayout.Vertical)
|
dockProvider?.Component(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,21 +245,18 @@ fun ClockWidget(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Clock(
|
fun Clock(
|
||||||
style: ClockStyle?,
|
style: ClockWidgetStyle?,
|
||||||
layout: ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val time = LocalTime.current
|
val time = LocalTime.current
|
||||||
when (style) {
|
when (style) {
|
||||||
ClockStyle.DigitalClock1,
|
is ClockWidgetStyle.Digital1 -> DigitalClock1(time, compact, style)
|
||||||
ClockStyle.DigitalClock1_Outlined,
|
|
||||||
ClockStyle.DigitalClock1_MDY,
|
|
||||||
ClockStyle.DigitalClock1_OnePlus -> DigitalClock1(time, layout, style)
|
|
||||||
|
|
||||||
ClockStyle.DigitalClock2 -> DigitalClock2(time, layout)
|
is ClockWidgetStyle.Digital2 -> DigitalClock2(time, compact)
|
||||||
ClockStyle.BinaryClock -> BinaryClock(time, layout)
|
is ClockWidgetStyle.Binary -> BinaryClock(time, compact)
|
||||||
ClockStyle.AnalogClock -> AnalogClock(time, layout)
|
is ClockWidgetStyle.Analog -> AnalogClock(time, compact)
|
||||||
ClockStyle.OrbitClock -> OrbitClock(time, layout)
|
is ClockWidgetStyle.Orbit -> OrbitClock(time, compact)
|
||||||
ClockStyle.EmptyClock -> {}
|
is ClockWidgetStyle.Empty -> {}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,13 +264,13 @@ fun Clock(
|
|||||||
@Composable
|
@Composable
|
||||||
fun DynamicZone(
|
fun DynamicZone(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
layout: ClockWidgetLayout,
|
compact: Boolean,
|
||||||
provider: PartProvider?,
|
provider: PartProvider?,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
) {
|
) {
|
||||||
provider?.Component(layout)
|
provider?.Component(compact)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,18 +279,13 @@ fun ConfigureClockWidgetSheet(
|
|||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
|
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
|
||||||
val layout by viewModel.layout.collectAsState()
|
val compact by viewModel.compact.collectAsState()
|
||||||
val color by viewModel.color.collectAsState()
|
val color by viewModel.color.collectAsState()
|
||||||
val style by viewModel.clockStyle.collectAsState()
|
val style by viewModel.clockStyle.collectAsState()
|
||||||
val fillHeight by viewModel.fillHeight.collectAsState()
|
val fillHeight by viewModel.fillHeight.collectAsState()
|
||||||
val alignment by viewModel.alignment.collectAsState()
|
val alignment by viewModel.alignment.collectAsState()
|
||||||
|
val dock by viewModel.dock.collectAsState()
|
||||||
val date by viewModel.datePart.collectAsState()
|
val parts by viewModel.parts.collectAsState()
|
||||||
val favorites by viewModel.favoritesPart.collectAsState()
|
|
||||||
val media by viewModel.musicPart.collectAsState()
|
|
||||||
val alarm by viewModel.alarmPart.collectAsState()
|
|
||||||
val battery by viewModel.batteryPart.collectAsState()
|
|
||||||
|
|
||||||
|
|
||||||
BottomSheetDialog(onDismissRequest = onDismiss) {
|
BottomSheetDialog(onDismissRequest = onDismiss) {
|
||||||
Column(
|
Column(
|
||||||
@ -307,14 +298,14 @@ fun ConfigureClockWidgetSheet(
|
|||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
SegmentedButton(
|
SegmentedButton(
|
||||||
selected = layout == ClockWidgetLayout.Vertical,
|
selected = compact == false,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setLayout(ClockWidgetLayout.Vertical)
|
viewModel.setCompact(false)
|
||||||
},
|
},
|
||||||
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
|
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
|
||||||
icon = {
|
icon = {
|
||||||
SegmentedButtonDefaults.Icon(
|
SegmentedButtonDefaults.Icon(
|
||||||
active = layout == ClockWidgetLayout.Vertical,
|
active = compact == false,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Rounded.HorizontalSplit,
|
imageVector = Icons.Rounded.HorizontalSplit,
|
||||||
@ -327,14 +318,14 @@ fun ConfigureClockWidgetSheet(
|
|||||||
Text(text = stringResource(R.string.preference_clockwidget_layout_vertical))
|
Text(text = stringResource(R.string.preference_clockwidget_layout_vertical))
|
||||||
}
|
}
|
||||||
SegmentedButton(
|
SegmentedButton(
|
||||||
selected = layout == ClockWidgetLayout.Horizontal,
|
selected = compact == true,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setLayout(ClockWidgetLayout.Horizontal)
|
viewModel.setCompact(true)
|
||||||
},
|
},
|
||||||
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
|
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
|
||||||
icon = {
|
icon = {
|
||||||
SegmentedButtonDefaults.Icon(
|
SegmentedButtonDefaults.Icon(
|
||||||
active = layout == ClockWidgetLayout.Horizontal,
|
active = compact == true,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Rounded.VerticalSplit,
|
imageVector = Icons.Rounded.VerticalSplit,
|
||||||
@ -348,9 +339,9 @@ fun ConfigureClockWidgetSheet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color != null && layout != null) {
|
if (color != null && compact != null) {
|
||||||
WatchFaceSelector(
|
WatchFaceSelector(
|
||||||
layout = layout!!,
|
compact = compact!!,
|
||||||
colors = color!!,
|
colors = color!!,
|
||||||
selected = style,
|
selected = style,
|
||||||
onSelect = {
|
onSelect = {
|
||||||
@ -487,7 +478,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
||||||
icon = Icons.Rounded.Star,
|
icon = Icons.Rounded.Star,
|
||||||
value = favorites == true,
|
value = dock == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setFavoritesPart(it)
|
viewModel.setFavoritesPart(it)
|
||||||
}
|
}
|
||||||
@ -510,7 +501,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_date_part),
|
title = stringResource(R.string.preference_clockwidget_date_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
||||||
icon = Icons.Rounded.Today,
|
icon = Icons.Rounded.Today,
|
||||||
value = date == true,
|
value = parts?.date == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setDatePart(it)
|
viewModel.setDatePart(it)
|
||||||
}
|
}
|
||||||
@ -519,7 +510,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_music_part),
|
title = stringResource(R.string.preference_clockwidget_music_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
||||||
icon = Icons.Rounded.MusicNote,
|
icon = Icons.Rounded.MusicNote,
|
||||||
value = media == true,
|
value = parts?.music == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setMusicPart(it)
|
viewModel.setMusicPart(it)
|
||||||
}
|
}
|
||||||
@ -528,7 +519,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
||||||
icon = Icons.Rounded.Alarm,
|
icon = Icons.Rounded.Alarm,
|
||||||
value = alarm == true,
|
value = parts?.alarm == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setAlarmPart(it)
|
viewModel.setAlarmPart(it)
|
||||||
}
|
}
|
||||||
@ -537,7 +528,7 @@ fun ConfigureClockWidgetSheet(
|
|||||||
title = stringResource(R.string.preference_clockwidget_battery_part),
|
title = stringResource(R.string.preference_clockwidget_battery_part),
|
||||||
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
||||||
icon = Icons.Rounded.BatteryFull,
|
icon = Icons.Rounded.BatteryFull,
|
||||||
value = battery == true,
|
value = parts?.battery == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setBatteryPart(it)
|
viewModel.setBatteryPart(it)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import android.provider.AlarmClock
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.AlarmPartProvider
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.AlarmPartProvider
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.BatteryPartProvider
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.BatteryPartProvider
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.DatePartProvider
|
import de.mm20.launcher2.ui.launcher.widgets.clock.parts.DatePartProvider
|
||||||
@ -18,21 +18,20 @@ import kotlinx.coroutines.flow.SharingStarted
|
|||||||
import kotlinx.coroutines.flow.channelFlow
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class ClockWidgetVM : ViewModel(), KoinComponent {
|
class ClockWidgetVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val settings: ClockWidgetSettings by inject()
|
||||||
|
|
||||||
private val partProviders = dataStore.data.map { it.clockWidget }.distinctUntilChanged().map {
|
private val partProviders = settings.parts.map {
|
||||||
val providers = mutableListOf<PartProvider>()
|
val providers = mutableListOf<PartProvider>()
|
||||||
if (it.datePart) providers += DatePartProvider()
|
if (it.date) providers += DatePartProvider()
|
||||||
if (it.musicPart) providers += MusicPartProvider()
|
if (it.music) providers += MusicPartProvider()
|
||||||
if (it.batteryPart) providers += BatteryPartProvider()
|
if (it.battery) providers += BatteryPartProvider()
|
||||||
if (it.alarmPart) providers += AlarmPartProvider()
|
if (it.alarm) providers += AlarmPartProvider()
|
||||||
providers
|
providers
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||||
|
|
||||||
@ -51,19 +50,19 @@ class ClockWidgetVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val layout = dataStore.data.map { it.clockWidget.layout }
|
val compactLayout = settings.compact
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
val clockStyle = settings.clockStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val color = dataStore.data.map { it.clockWidget.color }
|
val color = settings.color
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val alignment = dataStore.data.map { it.clockWidget.alignment }
|
val alignment = settings.alignment
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val dockProvider = dataStore.data
|
val dockProvider = settings.dock
|
||||||
.map { if (it.clockWidget.favoritesPart) FavoritesPartProvider() else null }
|
.map { if (it) FavoritesPartProvider() else null }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun updateTime(time: Long) {
|
fun updateTime(time: Long) {
|
||||||
|
|||||||
@ -43,19 +43,18 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
import de.mm20.launcher2.ui.locals.LocalPreferDarkContentOverWallpaper
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WatchFaceSelector(
|
fun WatchFaceSelector(
|
||||||
layout: ClockWidgetLayout,
|
compact: Boolean,
|
||||||
colors: ClockWidgetColors,
|
colors: ClockWidgetColors,
|
||||||
selected: ClockStyle?,
|
selected: ClockWidgetStyle?,
|
||||||
onSelect: (ClockStyle) -> Unit,
|
onSelect: (ClockWidgetStyle) -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Surface(
|
Surface(
|
||||||
@ -73,7 +72,7 @@ fun WatchFaceSelector(
|
|||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val styles = remember {
|
val styles = remember {
|
||||||
sortedMapOf(
|
mapOf(
|
||||||
ClockStyle.DigitalClock1 to 0,
|
ClockStyle.DigitalClock1 to 0,
|
||||||
ClockStyle.DigitalClock1_Outlined to 0,
|
ClockStyle.DigitalClock1_Outlined to 0,
|
||||||
ClockStyle.DigitalClock1_MDY to 0,
|
ClockStyle.DigitalClock1_MDY to 0,
|
||||||
@ -159,9 +158,9 @@ fun WatchFaceSelector(
|
|||||||
styles.filter { it.value == pageIndex }
|
styles.filter { it.value == pageIndex }
|
||||||
}
|
}
|
||||||
if (currentPageStyles.containsKey(selected)) {
|
if (currentPageStyles.containsKey(selected)) {
|
||||||
Clock(selected, layout)
|
Clock(selected, compact)
|
||||||
} else {
|
} else {
|
||||||
Clock(currentPageStyles.keys.first(), layout)
|
Clock(currentPageStyles.keys.first(), compact)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,7 +252,7 @@ fun WatchFaceSelector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getClockstyleName(context: Context, style: ClockStyle): String {
|
fun getClockstyleName(context: Context, style: ClockWidgetStyle): String {
|
||||||
return when (style) {
|
return when (style) {
|
||||||
ClockStyle.DigitalClock1,
|
ClockStyle.DigitalClock1,
|
||||||
ClockStyle.DigitalClock1_Outlined,
|
ClockStyle.DigitalClock1_Outlined,
|
||||||
@ -264,11 +263,11 @@ fun getClockstyleName(context: Context, style: ClockStyle): String {
|
|||||||
ClockStyle.BinaryClock -> "Binary"
|
ClockStyle.BinaryClock -> "Binary"
|
||||||
ClockStyle.AnalogClock -> "Hands"
|
ClockStyle.AnalogClock -> "Hands"
|
||||||
ClockStyle.EmptyClock -> "Empty"
|
ClockStyle.EmptyClock -> "Empty"
|
||||||
ClockStyle.UNRECOGNIZED -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getVariantName(context: Context, style: ClockStyle): String {
|
fun getVariantName(context: Context, style: ClockWidgetStyle): String {
|
||||||
return when (style) {
|
return when (style) {
|
||||||
ClockStyle.DigitalClock1,
|
ClockStyle.DigitalClock1,
|
||||||
ClockStyle.DigitalClock2,
|
ClockStyle.DigitalClock2,
|
||||||
@ -279,7 +278,20 @@ fun getVariantName(context: Context, style: ClockStyle): String {
|
|||||||
ClockStyle.DigitalClock1_Outlined -> "Outlined"
|
ClockStyle.DigitalClock1_Outlined -> "Outlined"
|
||||||
ClockStyle.DigitalClock1_MDY -> "Material You"
|
ClockStyle.DigitalClock1_MDY -> "Material You"
|
||||||
ClockStyle.DigitalClock1_OnePlus -> "OnePlus"
|
ClockStyle.DigitalClock1_OnePlus -> "OnePlus"
|
||||||
|
else -> ""
|
||||||
|
|
||||||
ClockStyle.UNRECOGNIZED -> ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compat for old enum names, TODO refactor this screen
|
||||||
|
object ClockStyle {
|
||||||
|
val DigitalClock1 = ClockWidgetStyle.Digital1()
|
||||||
|
val DigitalClock1_Outlined = ClockWidgetStyle.Digital1(outlined = true)
|
||||||
|
val DigitalClock1_MDY = ClockWidgetStyle.Digital1(variant = ClockWidgetStyle.Digital1.Variant.MDY)
|
||||||
|
val DigitalClock1_OnePlus = ClockWidgetStyle.Digital1(variant = ClockWidgetStyle.Digital1.Variant.OnePlus)
|
||||||
|
val DigitalClock2 = ClockWidgetStyle.Digital2
|
||||||
|
val OrbitClock = ClockWidgetStyle.Orbit
|
||||||
|
val AnalogClock = ClockWidgetStyle.Analog
|
||||||
|
val BinaryClock = ClockWidgetStyle.Binary
|
||||||
|
val EmptyClock = ClockWidgetStyle.Empty
|
||||||
|
}
|
||||||
@ -11,15 +11,15 @@ import androidx.compose.ui.graphics.StrokeCap
|
|||||||
import androidx.compose.ui.graphics.drawscope.Fill
|
import androidx.compose.ui.graphics.drawscope.Fill
|
||||||
import androidx.compose.ui.graphics.drawscope.rotate
|
import androidx.compose.ui.graphics.drawscope.rotate
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnalogClock(
|
fun AnalogClock(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
date.timeInMillis = time
|
date.timeInMillis = time
|
||||||
val minute = date[Calendar.MINUTE]
|
val minute = date[Calendar.MINUTE]
|
||||||
|
|||||||
@ -7,15 +7,14 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BinaryClock(
|
fun BinaryClock(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
date.timeInMillis = time
|
date.timeInMillis = time
|
||||||
val minute = date[Calendar.MINUTE]
|
val minute = date[Calendar.MINUTE]
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.drawscope.DrawStyle
|
|
||||||
import androidx.compose.ui.graphics.drawscope.Fill
|
import androidx.compose.ui.graphics.drawscope.Fill
|
||||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@ -20,8 +19,7 @@ import androidx.compose.ui.text.withStyle
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.em
|
import androidx.compose.ui.unit.em
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
import de.mm20.launcher2.ui.ktx.toPixels
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -30,10 +28,10 @@ import java.util.*
|
|||||||
@Composable
|
@Composable
|
||||||
fun DigitalClock1(
|
fun DigitalClock1(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout,
|
compact: Boolean,
|
||||||
variant: ClockStyle = ClockStyle.DigitalClock1,
|
style: ClockWidgetStyle.Digital1 = ClockWidgetStyle.Digital1(),
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
val format = SimpleDateFormat(
|
val format = SimpleDateFormat(
|
||||||
if (verticalLayout) {
|
if (verticalLayout) {
|
||||||
if (DateFormat.is24HourFormat(LocalContext.current)) "HH\nmm" else "hh\nmm"
|
if (DateFormat.is24HourFormat(LocalContext.current)) "HH\nmm" else "hh\nmm"
|
||||||
@ -50,8 +48,8 @@ fun DigitalClock1(
|
|||||||
fontWeight = FontWeight.Black,
|
fontWeight = FontWeight.Black,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
lineHeight = 0.8.em,
|
lineHeight = 0.8.em,
|
||||||
drawStyle = if (variant == ClockStyle.DigitalClock1_Outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
drawStyle = if (style.outlined) Stroke(width = 2.dp.toPixels()) else Fill,
|
||||||
color = if (variant == ClockStyle.DigitalClock1_MDY) {
|
color = if (style.variant == ClockWidgetStyle.Digital1.Variant.MDY) {
|
||||||
if (LocalContentColor.current == Color.White) {
|
if (LocalContentColor.current == Color.White) {
|
||||||
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
if (LocalDarkTheme.current) MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
else MaterialTheme.colorScheme.primaryContainer
|
else MaterialTheme.colorScheme.primaryContainer
|
||||||
@ -64,7 +62,7 @@ fun DigitalClock1(
|
|||||||
|
|
||||||
val modifier = Modifier.offset(0.dp, if (verticalLayout) 16.dp else 0.dp)
|
val modifier = Modifier.offset(0.dp, if (verticalLayout) 16.dp else 0.dp)
|
||||||
|
|
||||||
if (variant == ClockStyle.DigitalClock1_OnePlus) {
|
if (style.variant == ClockWidgetStyle.Digital1.Variant.OnePlus) {
|
||||||
val hour = formattedString.substring(0, 2)
|
val hour = formattedString.substring(0, 2)
|
||||||
Text(
|
Text(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|||||||
@ -6,13 +6,12 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DigitalClock2(
|
fun DigitalClock2(
|
||||||
time: Long,
|
time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = DateUtils.formatDateTime(LocalContext.current, time, DateUtils.FORMAT_SHOW_TIME),
|
text = DateUtils.formatDateTime(LocalContext.current, time, DateUtils.FORMAT_SHOW_TIME),
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import androidx.compose.ui.unit.center
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.toOffset
|
import androidx.compose.ui.unit.toOffset
|
||||||
import de.mm20.launcher2.ktx.TWO_PI
|
import de.mm20.launcher2.ktx.TWO_PI
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
@ -46,9 +46,9 @@ private val currentTime
|
|||||||
@Composable
|
@Composable
|
||||||
fun OrbitClock(
|
fun OrbitClock(
|
||||||
_time: Long,
|
_time: Long,
|
||||||
layout: Settings.ClockWidgetSettings.ClockWidgetLayout
|
compact: Boolean,
|
||||||
) {
|
) {
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compact
|
||||||
|
|
||||||
val timeState = remember { mutableStateOf<ZonedDateTime>(currentTime) }
|
val timeState = remember { mutableStateOf<ZonedDateTime>(currentTime) }
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.channels.trySendBlocking
|
import kotlinx.coroutines.channels.trySendBlocking
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@ -71,7 +70,7 @@ class AlarmPartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val alarmTime by nextAlarmTime
|
val alarmTime by nextAlarmTime
|
||||||
@ -79,7 +78,7 @@ class AlarmPartProvider : PartProvider {
|
|||||||
|
|
||||||
alarmTime?.let {
|
alarmTime?.let {
|
||||||
|
|
||||||
if (layout == ClockWidgetLayout.Vertical) {
|
if (!compactLayout) {
|
||||||
|
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|||||||
@ -20,14 +20,12 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.icons.*
|
import de.mm20.launcher2.ui.icons.*
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
@ -54,13 +52,13 @@ class BatteryPartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: Settings.ClockWidgetSettings.ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
|
|
||||||
val batteryInfo by this.batteryInfo.collectAsState(null)
|
val batteryInfo by this.batteryInfo.collectAsState(null)
|
||||||
|
|
||||||
batteryInfo?.let {
|
batteryInfo?.let {
|
||||||
|
|
||||||
if (layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical) {
|
if (!compactLayout) {
|
||||||
Row(
|
Row(
|
||||||
Modifier.padding(8.dp),
|
Modifier.padding(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
@ -86,7 +84,7 @@ class BatteryPartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Horizontal) {
|
if (compactLayout) {
|
||||||
Row(
|
Row(
|
||||||
Modifier.padding(8.dp),
|
Modifier.padding(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.em
|
import androidx.compose.ui.unit.em
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import de.mm20.launcher2.ui.base.LocalTime
|
import de.mm20.launcher2.ui.base.LocalTime
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
@ -25,9 +24,9 @@ class DatePartProvider : PartProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: Settings.ClockWidgetSettings.ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val time = LocalTime.current
|
val time = LocalTime.current
|
||||||
val verticalLayout = layout == Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical
|
val verticalLayout = !compactLayout
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
TextButton(
|
TextButton(
|
||||||
colors = ButtonDefaults.textButtonColors(
|
colors = ButtonDefaults.textButtonColors(
|
||||||
|
|||||||
@ -3,16 +3,13 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
||||||
import de.mm20.launcher2.widgets.CalendarWidget
|
import de.mm20.launcher2.widgets.CalendarWidget
|
||||||
@ -27,25 +24,24 @@ class FavoritesPartProvider : PartProvider, KoinComponent {
|
|||||||
|
|
||||||
private val favoritesService: FavoritesService by inject()
|
private val favoritesService: FavoritesService by inject()
|
||||||
private val widgetRepository: WidgetRepository by inject()
|
private val widgetRepository: WidgetRepository by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
override fun getRanking(context: Context): Flow<Int> = flow {
|
override fun getRanking(context: Context): Flow<Int> = flow {
|
||||||
emit(Int.MAX_VALUE)
|
emit(Int.MAX_VALUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val columns by remember(layout) {
|
val columns by remember {
|
||||||
dataStore.data.map {
|
uiSettings.gridSettings.map {
|
||||||
val c = it.grid.columnCount
|
it.columnCount
|
||||||
if (layout == ClockWidgetLayout.Horizontal) c - 2 else c
|
|
||||||
}
|
}
|
||||||
}.collectAsState(0)
|
}.collectAsState(0)
|
||||||
val excludeCalendar by remember { widgetRepository.exists(CalendarWidget.Type) }.collectAsState(
|
val excludeCalendar by remember { widgetRepository.exists(CalendarWidget.Type) }.collectAsState(
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
val favorites by remember(columns, excludeCalendar, layout) {
|
val favorites by remember(columns, excludeCalendar) {
|
||||||
favoritesService.getFavorites(
|
favoritesService.getFavorites(
|
||||||
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
excludeTypes = if (excludeCalendar) listOf("calendar", "tag") else listOf("tag"),
|
||||||
manuallySorted = true,
|
manuallySorted = true,
|
||||||
|
|||||||
@ -28,7 +28,6 @@ import androidx.compose.ui.unit.dp
|
|||||||
import de.mm20.launcher2.music.MusicService
|
import de.mm20.launcher2.music.MusicService
|
||||||
import de.mm20.launcher2.music.PlaybackState
|
import de.mm20.launcher2.music.PlaybackState
|
||||||
import de.mm20.launcher2.music.SupportedActions
|
import de.mm20.launcher2.music.SupportedActions
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.channelFlow
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
@ -48,7 +47,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Component(layout: ClockWidgetLayout) {
|
override fun Component(compactLayout: Boolean) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val title by musicService.title.collectAsState(null)
|
val title by musicService.title.collectAsState(null)
|
||||||
@ -58,7 +57,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
|||||||
|
|
||||||
val playIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_play_pause)
|
val playIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_play_pause)
|
||||||
|
|
||||||
if (layout === ClockWidgetLayout.Horizontal) {
|
if (compactLayout) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@ -113,7 +112,7 @@ class MusicPartProvider : PartProvider, KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layout === ClockWidgetLayout.Vertical) {
|
if (!compactLayout) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(8.dp),
|
modifier = Modifier.padding(8.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface PartProvider {
|
interface PartProvider {
|
||||||
@ -12,5 +11,5 @@ interface PartProvider {
|
|||||||
fun setTime(time: Long) {}
|
fun setTime(time: Long) {}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Component(layout: ClockWidgetLayout)
|
fun Component(compactLayout: Boolean)
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.rounded.Star
|
import androidx.compose.material.icons.rounded.Star
|
||||||
import androidx.compose.material.icons.rounded.Tag
|
import androidx.compose.material.icons.rounded.Tag
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@ -30,6 +31,10 @@ fun FavoritesWidget(widget: FavoritesWidget) {
|
|||||||
|
|
||||||
val tagsExpanded by viewModel.tagsExpanded.collectAsState(false)
|
val tagsExpanded by viewModel.tagsExpanded.collectAsState(false)
|
||||||
|
|
||||||
|
LaunchedEffect(widget) {
|
||||||
|
viewModel.updateWidget(widget)
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
if (favorites.isNotEmpty()) {
|
if (favorites.isNotEmpty()) {
|
||||||
SearchResultGrid(favorites)
|
SearchResultGrid(favorites)
|
||||||
|
|||||||
@ -1,32 +1,34 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.widgets.favorites
|
package de.mm20.launcher2.ui.launcher.widgets.favorites
|
||||||
|
|
||||||
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.services.widgets.WidgetsService
|
import de.mm20.launcher2.services.widgets.WidgetsService
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.common.FavoritesVM
|
import de.mm20.launcher2.ui.common.FavoritesVM
|
||||||
import kotlinx.coroutines.flow.Flow
|
import de.mm20.launcher2.widgets.FavoritesWidget
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.shareIn
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class FavoritesWidgetVM : FavoritesVM() {
|
class FavoritesWidgetVM : FavoritesVM() {
|
||||||
|
|
||||||
private val widgetsService: WidgetsService by inject()
|
private val widgetsService: WidgetsService by inject()
|
||||||
|
|
||||||
override val tagsExpanded: Flow<Boolean> = dataStore.data.map { it.ui.widgetTagsMultiline }
|
private val uiSettings: UiSettings by inject()
|
||||||
.shareIn(viewModelScope, SharingStarted.Lazily)
|
|
||||||
|
override val tagsExpanded: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||||
|
private val widget = MutableStateFlow<FavoritesWidget?>(null)
|
||||||
|
|
||||||
private val isTopWidget = widgetsService.isFavoritesWidgetFirst()
|
private val isTopWidget = widgetsService.isFavoritesWidgetFirst()
|
||||||
private val clockWidgetFavSlots = dataStore.data.combine(isTopWidget) { data, isTop ->
|
private val clockWidgetFavSlots =
|
||||||
if (!isTop || !data.clockWidget.favoritesPart) 0
|
combine(uiSettings.dock, isTopWidget, uiSettings.gridSettings) { (dock, isTop, grid) ->
|
||||||
else {
|
dock as Boolean
|
||||||
if (data.clockWidget.layout == ClockWidgetLayout.Horizontal) data.grid.columnCount - 2
|
isTop as Boolean
|
||||||
else data.grid.columnCount
|
grid as GridSettings
|
||||||
|
if (!isTop || !dock) 0
|
||||||
|
else {
|
||||||
|
grid.columnCount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override val favorites = super.favorites.combine(clockWidgetFavSlots) { favs, slots ->
|
override val favorites = super.favorites.combine(clockWidgetFavSlots) { favs, slots ->
|
||||||
if (selectedTag.value == null) {
|
if (selectedTag.value == null) {
|
||||||
@ -38,17 +40,17 @@ class FavoritesWidgetVM : FavoritesVM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setTagsExpanded(expanded: Boolean) {
|
override fun setTagsExpanded(expanded: Boolean) {
|
||||||
viewModelScope.launch {
|
this.tagsExpanded.value = expanded
|
||||||
dataStore.updateData {
|
val widget = this.widget.value ?: return
|
||||||
it.toBuilder()
|
widgetsService.updateWidget(
|
||||||
.setUi(
|
widget.copy(
|
||||||
it.ui.toBuilder()
|
config = widget.config.copy(tagsMultiline = expanded)
|
||||||
.setWidgetTagsMultiline(expanded)
|
)
|
||||||
.build()
|
)
|
||||||
)
|
}
|
||||||
.build()
|
|
||||||
}
|
fun updateWidget(widget: FavoritesWidget) {
|
||||||
}
|
tagsExpanded.value = widget.config.tagsMultiline
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -5,11 +5,10 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import de.mm20.launcher2.weather.DailyForecast
|
import de.mm20.launcher2.weather.DailyForecast
|
||||||
import de.mm20.launcher2.weather.Forecast
|
import de.mm20.launcher2.weather.Forecast
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@ -26,8 +25,6 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index of the currently selected day in [dailyForecasts]
|
* Index of the currently selected day in [dailyForecasts]
|
||||||
*/
|
*/
|
||||||
@ -111,7 +108,8 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
|||||||
val autoLocation = weatherSettings.autoLocation
|
val autoLocation = weatherSettings.autoLocation
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
val imperialUnits = weatherSettings.imperialUnits
|
||||||
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun selectDay(index: Int) {
|
fun selectDay(index: Int) {
|
||||||
selectedDayIndex = min(index, forecasts.lastIndex)
|
selectedDayIndex = min(index, forecasts.lastIndex)
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import androidx.compose.material3.SnackbarHostState
|
|||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.ui.geometry.Size
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||||
import de.mm20.launcher2.preferences.Settings.GridSettings
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
import de.mm20.launcher2.ui.theme.WallpaperColors
|
import de.mm20.launcher2.ui.theme.WallpaperColors
|
||||||
|
|
||||||
val LocalWindowSize = compositionLocalOf { Size(0f, 0f) }
|
val LocalWindowSize = compositionLocalOf { Size(0f, 0f) }
|
||||||
@ -15,11 +15,11 @@ val LocalAppWidgetHost = compositionLocalOf<AppWidgetHost?>(defaultFactory = { n
|
|||||||
|
|
||||||
val LocalNavController = compositionLocalOf<NavController?> { null }
|
val LocalNavController = compositionLocalOf<NavController?> { null }
|
||||||
|
|
||||||
val LocalCardStyle = compositionLocalOf<Settings.CardSettings> { Settings.CardSettings.getDefaultInstance() }
|
val LocalCardStyle = compositionLocalOf { CardStyle() }
|
||||||
|
|
||||||
val LocalFavoritesEnabled = compositionLocalOf { true }
|
val LocalFavoritesEnabled = compositionLocalOf { true }
|
||||||
|
|
||||||
val LocalGridSettings = compositionLocalOf { GridSettings.newBuilder().setColumnCount(5).setShowLabels(true).setIconSize(48).build() }
|
val LocalGridSettings = compositionLocalOf { GridSettings() }
|
||||||
|
|
||||||
val LocalSnackbarHostState = compositionLocalOf { SnackbarHostState() }
|
val LocalSnackbarHostState = compositionLocalOf { SnackbarHostState() }
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,6 @@ import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
|
|||||||
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
|
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
|
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreen
|
|
||||||
import de.mm20.launcher2.ui.settings.colorscheme.ThemeSettingsScreen
|
import de.mm20.launcher2.ui.settings.colorscheme.ThemeSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.colorscheme.ThemesSettingsScreen
|
import de.mm20.launcher2.ui.settings.colorscheme.ThemesSettingsScreen
|
||||||
import de.mm20.launcher2.ui.settings.crashreporter.CrashReportScreen
|
import de.mm20.launcher2.ui.settings.crashreporter.CrashReportScreen
|
||||||
@ -170,9 +169,6 @@ class SettingsActivity : BaseActivity() {
|
|||||||
composable(ROUTE_MEDIA_INTEGRATION) {
|
composable(ROUTE_MEDIA_INTEGRATION) {
|
||||||
MediaIntegrationSettingsScreen()
|
MediaIntegrationSettingsScreen()
|
||||||
}
|
}
|
||||||
composable("settings/homescreen/clock") {
|
|
||||||
ClockWidgetSettingsScreen()
|
|
||||||
}
|
|
||||||
composable("settings/favorites") {
|
composable("settings/favorites") {
|
||||||
FavoritesSettingsScreen()
|
FavoritesSettingsScreen()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,8 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
import de.mm20.launcher2.preferences.ColorScheme
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
|
import de.mm20.launcher2.preferences.Font
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||||
@ -28,22 +27,22 @@ fun AppearanceSettingsScreen() {
|
|||||||
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val themeName by viewModel.colorSchemeName.collectAsStateWithLifecycle(null)
|
val themeName by viewModel.themeName.collectAsStateWithLifecycle(null)
|
||||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
||||||
item {
|
item {
|
||||||
PreferenceCategory {
|
PreferenceCategory {
|
||||||
val theme by viewModel.theme.collectAsState()
|
val theme by viewModel.colorScheme.collectAsState()
|
||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(id = R.string.preference_theme),
|
title = stringResource(id = R.string.preference_theme),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(id = R.string.preference_theme_system) to Theme.System,
|
stringResource(id = R.string.preference_theme_system) to ColorScheme.System,
|
||||||
stringResource(id = R.string.preference_theme_light) to Theme.Light,
|
stringResource(id = R.string.preference_theme_light) to ColorScheme.Light,
|
||||||
stringResource(id = R.string.preference_theme_dark) to Theme.Dark,
|
stringResource(id = R.string.preference_theme_dark) to ColorScheme.Dark,
|
||||||
),
|
),
|
||||||
value = theme,
|
value = theme,
|
||||||
onValueChanged = { newValue ->
|
onValueChanged = { newValue ->
|
||||||
if (newValue == null) return@ListPreference
|
if (newValue == null) return@ListPreference
|
||||||
viewModel.setTheme(newValue)
|
viewModel.setColorScheme(newValue)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Preference(
|
Preference(
|
||||||
@ -54,13 +53,13 @@ fun AppearanceSettingsScreen() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (isAtLeastApiLevel(31)) {
|
if (isAtLeastApiLevel(31)) {
|
||||||
val compatMode by viewModel.compatMode.collectAsState()
|
val compatModeColors by viewModel.compatModeColors.collectAsState()
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(id = R.string.preference_force_compat_system_colors),
|
title = stringResource(id = R.string.preference_force_compat_system_colors),
|
||||||
summary = stringResource(id = R.string.preference_force_compat_system_colors_summary),
|
summary = stringResource(id = R.string.preference_force_compat_system_colors_summary),
|
||||||
value = compatMode,
|
value = compatModeColors,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setCompatMode(it)
|
viewModel.setCompatModeColors(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -68,8 +67,8 @@ fun AppearanceSettingsScreen() {
|
|||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(R.string.preference_font),
|
title = stringResource(R.string.preference_font),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
"Outfit" to AppearanceSettings.Font.Outfit,
|
"Outfit" to Font.Outfit,
|
||||||
stringResource(R.string.preference_font_system) to AppearanceSettings.Font.SystemDefault,
|
stringResource(R.string.preference_font_system) to Font.System,
|
||||||
),
|
),
|
||||||
value = font,
|
value = font,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
|||||||
@ -3,74 +3,47 @@ package de.mm20.launcher2.ui.settings.appearance
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ColorScheme
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Font
|
import de.mm20.launcher2.preferences.Font
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
private val iconService: IconService by inject()
|
|
||||||
private val themeRepository: ThemeRepository by inject()
|
private val themeRepository: ThemeRepository by inject()
|
||||||
|
|
||||||
val theme = dataStore.data.map { it.appearance.theme }
|
val colorScheme = uiSettings.colorScheme
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setTheme(theme: Theme) {
|
fun setColorScheme(colorScheme: ColorScheme) {
|
||||||
viewModelScope.launch {
|
uiSettings.setColorScheme(colorScheme)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(it.appearance.toBuilder().setTheme(theme))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val colorSchemeName = dataStore.data.map {
|
val themeName = uiSettings.theme.flatMapLatest {
|
||||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
|
||||||
UUID.fromString(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.flatMapLatest {
|
|
||||||
themeRepository.getThemeOrDefault(it)
|
themeRepository.getThemeOrDefault(it)
|
||||||
}.map {
|
}.map {
|
||||||
it.name
|
it.name
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val compatMode = dataStore.data.map {
|
val compatModeColors = uiSettings.compatModeColors
|
||||||
it.appearance.forceCompatModeSystemColors
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
|
||||||
|
|
||||||
fun setCompatMode(enabled: Boolean) {
|
fun setCompatModeColors(enabled: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setCompatModeColors(enabled)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(it.appearance.toBuilder().setForceCompatModeSystemColors(enabled))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val font = dataStore.data.map { it.appearance.font }
|
val font = uiSettings.font
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFont(font: Font) {
|
fun setFont(font: Font) {
|
||||||
viewModelScope.launch {
|
uiSettings.setFont(font)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(it.appearance.toBuilder().setFont(font))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.settings.buildinfo
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import de.mm20.launcher2.accounts.AccountType
|
import de.mm20.launcher2.accounts.AccountType
|
||||||
import de.mm20.launcher2.accounts.AccountsRepository
|
import de.mm20.launcher2.accounts.AccountsRepository
|
||||||
import de.mm20.launcher2.preferences.Settings.WeatherSettings.WeatherProvider
|
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
|
|||||||
@ -15,7 +15,9 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.SurfaceShape
|
||||||
|
import de.mm20.launcher2.preferences.ui.CardStyle
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.LauncherCard
|
import de.mm20.launcher2.ui.component.LauncherCard
|
||||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||||
@ -26,6 +28,9 @@ import de.mm20.launcher2.ui.component.preferences.SliderPreference
|
|||||||
@Composable
|
@Composable
|
||||||
fun CardsSettingsScreen() {
|
fun CardsSettingsScreen() {
|
||||||
val viewModel: CardsSettingsScreenVM = viewModel()
|
val viewModel: CardsSettingsScreenVM = viewModel()
|
||||||
|
|
||||||
|
val cardStyle by viewModel.cardStyle.collectAsState(CardStyle())
|
||||||
|
|
||||||
PreferenceScreen(title = stringResource(R.string.preference_cards)) {
|
PreferenceScreen(title = stringResource(R.string.preference_cards)) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
@ -43,23 +48,21 @@ fun CardsSettingsScreen() {
|
|||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceCategory {
|
PreferenceCategory {
|
||||||
val shape by viewModel.shape.collectAsState()
|
|
||||||
ListPreference(
|
ListPreference(
|
||||||
icon = Icons.Rounded.Rectangle,
|
icon = Icons.Rounded.Rectangle,
|
||||||
title = stringResource(R.string.preference_cards_shape),
|
title = stringResource(R.string.preference_cards_shape),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_cards_shape_rounded) to Settings.CardSettings.Shape.Rounded,
|
stringResource(R.string.preference_cards_shape_rounded) to SurfaceShape.Rounded,
|
||||||
stringResource(R.string.preference_cards_shape_cut) to Settings.CardSettings.Shape.Cut,
|
stringResource(R.string.preference_cards_shape_cut) to SurfaceShape.Cut,
|
||||||
),
|
),
|
||||||
value = shape,
|
value = cardStyle.shape,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setShape(it)
|
viewModel.setShape(it)
|
||||||
})
|
})
|
||||||
val radius by viewModel.radius.collectAsState()
|
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_cards_corner_radius),
|
title = stringResource(R.string.preference_cards_corner_radius),
|
||||||
icon = Icons.Rounded.RoundedCorner,
|
icon = Icons.Rounded.RoundedCorner,
|
||||||
value = radius,
|
value = cardStyle.cornerRadius,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 24,
|
max = 24,
|
||||||
step = 1,
|
step = 1,
|
||||||
@ -67,22 +70,20 @@ fun CardsSettingsScreen() {
|
|||||||
viewModel.setRadius(it)
|
viewModel.setRadius(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val opacity by viewModel.opacity.collectAsState()
|
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_cards_opacity),
|
title = stringResource(R.string.preference_cards_opacity),
|
||||||
icon = Icons.Rounded.Opacity,
|
icon = Icons.Rounded.Opacity,
|
||||||
value = opacity,
|
value = cardStyle.opacity,
|
||||||
min = 0f,
|
min = 0f,
|
||||||
max = 1f,
|
max = 1f,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setOpacity(it)
|
viewModel.setOpacity(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val borderWidth by viewModel.borderWidth.collectAsState()
|
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_cards_stroke_width),
|
title = stringResource(R.string.preference_cards_stroke_width),
|
||||||
icon = Icons.Rounded.LineWeight,
|
icon = Icons.Rounded.LineWeight,
|
||||||
value = borderWidth,
|
value = cardStyle.borderWidth,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 8,
|
max = 8,
|
||||||
step = 1,
|
step = 1,
|
||||||
|
|||||||
@ -1,70 +1,29 @@
|
|||||||
package de.mm20.launcher2.ui.settings.cards
|
package de.mm20.launcher2.ui.settings.cards
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import de.mm20.launcher2.preferences.SurfaceShape
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class CardsSettingsScreenVM: ViewModel(), KoinComponent {
|
class CardsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
|
val cardStyle = uiSettings.cardStyle
|
||||||
|
|
||||||
val opacity = dataStore.data.map { it.cards.opacity }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0f)
|
|
||||||
fun setOpacity(opacity: Float) {
|
fun setOpacity(opacity: Float) {
|
||||||
viewModelScope.launch {
|
uiSettings.setCardOpacity(opacity)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setOpacity(opacity)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val radius = dataStore.data.map { it.cards.radius }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
|
||||||
|
|
||||||
fun setRadius(radius: Int) {
|
fun setRadius(radius: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setCardRadius(radius)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setRadius(radius)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val borderWidth = dataStore.data.map { it.cards.borderWidth }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
|
||||||
fun setBorderWidth(borderWidth: Int) {
|
fun setBorderWidth(borderWidth: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setCardBorderWidth(borderWidth)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setBorderWidth(borderWidth)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val shape = dataStore.data.map { it.cards.shape }
|
fun setShape(shape: SurfaceShape) {
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
uiSettings.setCardShape(shape)
|
||||||
|
|
||||||
fun setShape(shape: Settings.CardSettings.Shape) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setCards(it.cards.toBuilder()
|
|
||||||
.setShape(shape)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,204 +0,0 @@
|
|||||||
package de.mm20.launcher2.ui.settings.clockwidget
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.*
|
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import com.google.accompanist.pager.HorizontalPagerIndicator
|
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.clock.Clock
|
|
||||||
import de.mm20.launcher2.ui.R
|
|
||||||
import de.mm20.launcher2.ui.component.preferences.*
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClockWidgetSettingsScreen() {
|
|
||||||
val viewModel: ClockWidgetSettingsScreenVM = viewModel()
|
|
||||||
PreferenceScreen(
|
|
||||||
title = stringResource(R.string.preference_screen_clockwidget),
|
|
||||||
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/widgets/clock"
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val layout by viewModel.layout.collectAsState()
|
|
||||||
ListPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_layout),
|
|
||||||
value = layout,
|
|
||||||
items = listOf(
|
|
||||||
stringResource(R.string.preference_clockwidget_layout_vertical) to ClockWidgetLayout.Vertical,
|
|
||||||
stringResource(R.string.preference_clockwidget_layout_horizontal) to ClockWidgetLayout.Horizontal,
|
|
||||||
),
|
|
||||||
onValueChanged = {
|
|
||||||
if (it != null) viewModel.setLayout(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
|
||||||
ClockStylePreference(
|
|
||||||
layout = layout ?: ClockWidgetLayout.Vertical,
|
|
||||||
value = clockStyle,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setClockStyle(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val color by viewModel.color.collectAsState()
|
|
||||||
ListPreference(
|
|
||||||
title = stringResource(R.string.preference_clock_widget_color),
|
|
||||||
value = color,
|
|
||||||
items = listOf(
|
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to ClockWidgetColors.Auto,
|
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to ClockWidgetColors.Light,
|
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to ClockWidgetColors.Dark,
|
|
||||||
),
|
|
||||||
onValueChanged = {
|
|
||||||
if (it != null) viewModel.setColor(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val fillHeight by viewModel.fillHeight.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clock_widget_fill_height),
|
|
||||||
summary = stringResource(R.string.preference_clock_widget_fill_height_summary),
|
|
||||||
value = fillHeight == true,
|
|
||||||
onValueChanged = { viewModel.setFillHeight(it) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val datePart by viewModel.datePart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_date_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
|
||||||
icon = Icons.Rounded.Today,
|
|
||||||
value = datePart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setDatePart(it)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
val favoritesPart by viewModel.favoritesPart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
|
||||||
icon = Icons.Rounded.Star,
|
|
||||||
value = favoritesPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setFavoritesPart(it)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val musicPart by viewModel.musicPart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_music_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
|
||||||
icon = Icons.Rounded.MusicNote,
|
|
||||||
value = musicPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setMusicPart(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val alarmPart by viewModel.alarmPart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
|
||||||
icon = Icons.Rounded.Alarm,
|
|
||||||
value = alarmPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setAlarmPart(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val batteryPart by viewModel.batteryPart.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_clockwidget_battery_part),
|
|
||||||
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
|
||||||
icon = Icons.Rounded.BatteryFull,
|
|
||||||
value = batteryPart == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setBatteryPart(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ClockStylePreference(
|
|
||||||
layout: ClockWidgetLayout,
|
|
||||||
value: ClockStyle?,
|
|
||||||
onValueChanged: (ClockStyle) -> Unit
|
|
||||||
) {
|
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
|
||||||
Preference(
|
|
||||||
title = stringResource(R.string.preference_clock_widget_style),
|
|
||||||
summary = stringResource(R.string.preference_clock_widget_style_summary),
|
|
||||||
onClick = {
|
|
||||||
showDialog = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (showDialog && value != null) {
|
|
||||||
val styles = remember {
|
|
||||||
ClockStyle.values().filter { it != ClockStyle.UNRECOGNIZED }
|
|
||||||
}
|
|
||||||
val pagerState = rememberPagerState(styles.indexOf(value)) { styles.size }
|
|
||||||
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = { showDialog = false },
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(onClick = {
|
|
||||||
showDialog = false
|
|
||||||
onValueChanged(styles[pagerState.currentPage])
|
|
||||||
}) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(android.R.string.ok),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(onClick = { showDialog = false }) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(android.R.string.cancel),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
text = {
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
HorizontalPager(
|
|
||||||
state = pagerState,
|
|
||||||
modifier = Modifier.height(300.dp).fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Clock(
|
|
||||||
style = styles[it],
|
|
||||||
layout = layout
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HorizontalPagerIndicator(pagerState = pagerState, pageCount = styles.size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,9 +2,10 @@ package de.mm20.launcher2.ui.settings.clockwidget
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ClockWidgetAlignment
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings
|
import de.mm20.launcher2.preferences.ClockWidgetColors
|
||||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
import de.mm20.launcher2.preferences.ClockWidgetStyle
|
||||||
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -13,146 +14,62 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val settings: ClockWidgetSettings by inject()
|
||||||
val layout = dataStore.data.map { it.clockWidget.layout }
|
val compact = settings.compact
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setLayout(layout: ClockWidgetSettings.ClockWidgetLayout) {
|
fun setCompact(compact: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setCompact(compact)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setLayout(layout)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
val clockStyle = settings.clockStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setClockStyle(clockStyle: ClockWidgetSettings.ClockStyle) {
|
fun setClockStyle(clockStyle: ClockWidgetStyle) {
|
||||||
viewModelScope.launch {
|
settings.setClockStyle(clockStyle)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setClockStyle(clockStyle)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val color = dataStore.data.map { it.clockWidget.color }
|
val color = settings.color
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setColor(color: ClockWidgetColors) {
|
fun setColor(color: ClockWidgetColors) {
|
||||||
viewModelScope.launch {
|
settings.setColor(color)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setColor(color)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val fillHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
val fillHeight = settings.fillHeight
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setFillHeight(fillHeight: Boolean) {
|
fun setFillHeight(fillHeight: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setFillHeight(fillHeight)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setFillHeight(fillHeight)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val datePart = dataStore.data.map { it.clockWidget.datePart }
|
val dock = settings.dock
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
|
val parts = settings.parts
|
||||||
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setDatePart(datePart: Boolean) {
|
fun setDatePart(datePart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setDatePart(datePart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setDatePart(datePart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val favoritesPart = dataStore.data.map { it.clockWidget.favoritesPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setFavoritesPart(favoritesPart: Boolean) {
|
fun setFavoritesPart(favoritesPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setDock(favoritesPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setFavoritesPart(favoritesPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val batteryPart = dataStore.data.map { it.clockWidget.batteryPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setBatteryPart(batteryPart: Boolean) {
|
fun setBatteryPart(batteryPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setBatteryPart(batteryPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setBatteryPart(batteryPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val musicPart = dataStore.data.map { it.clockWidget.musicPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setMusicPart(musicPart: Boolean) {
|
fun setMusicPart(musicPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setMusicPart(musicPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setMusicPart(musicPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val alarmPart = dataStore.data.map { it.clockWidget.alarmPart }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setAlarmPart(alarmPart: Boolean) {
|
fun setAlarmPart(alarmPart: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setAlarmPart(alarmPart)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setAlarmPart(alarmPart)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val alignment = dataStore.data.map { it.clockWidget.alignment }
|
val alignment = settings.alignment
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setAlignment(alignment: ClockWidgetSettings.ClockWidgetAlignment) {
|
fun setAlignment(alignment: ClockWidgetAlignment) {
|
||||||
viewModelScope.launch {
|
settings.setAlignment(alignment)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setClockWidget(
|
|
||||||
it.clockWidget.toBuilder()
|
|
||||||
.setAlignment(alignment)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,24 +2,20 @@ package de.mm20.launcher2.ui.settings.colorscheme
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.google.protobuf.ByteString
|
|
||||||
import de.mm20.launcher2.ktx.toBytes
|
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ThemeDescriptor
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
|
import de.mm20.launcher2.themes.BlackAndWhiteThemeId
|
||||||
import de.mm20.launcher2.themes.DefaultThemeId
|
import de.mm20.launcher2.themes.DefaultThemeId
|
||||||
import de.mm20.launcher2.themes.Theme
|
import de.mm20.launcher2.themes.Theme
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import de.mm20.launcher2.themes.fromJson
|
|
||||||
import de.mm20.launcher2.themes.toJson
|
import de.mm20.launcher2.themes.toJson
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -31,12 +27,14 @@ import java.util.UUID
|
|||||||
class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val themeRepository: ThemeRepository by inject()
|
private val themeRepository: ThemeRepository by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val uiSettings: UiSettings by inject()
|
||||||
|
|
||||||
val selectedTheme: Flow<UUID?> = dataStore.data.map {
|
val selectedTheme = uiSettings.theme.map {
|
||||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
when(it) {
|
||||||
UUID.fromString(it)
|
ThemeDescriptor.Default -> DefaultThemeId
|
||||||
} ?: DefaultThemeId
|
ThemeDescriptor.BlackAndWhite -> BlackAndWhiteThemeId
|
||||||
|
is ThemeDescriptor.Custom -> UUID.fromString(it.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val themes: Flow<List<Theme>> = themeRepository.getThemes()
|
val themes: Flow<List<Theme>> = themeRepository.getThemes()
|
||||||
|
|
||||||
@ -49,15 +47,10 @@ class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun selectTheme(theme: Theme) {
|
fun selectTheme(theme: Theme) {
|
||||||
viewModelScope.launch {
|
when(theme.id) {
|
||||||
dataStore.updateData {
|
DefaultThemeId -> ThemeDescriptor.Default
|
||||||
it.toBuilder()
|
BlackAndWhiteThemeId -> ThemeDescriptor.BlackAndWhite
|
||||||
.setAppearance(
|
else -> ThemeDescriptor.Custom(theme.id.toString())
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setThemeId(theme.id.toString())
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,24 +2,20 @@ package de.mm20.launcher2.ui.settings.easteregg
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class EasterEggSettingsScreenVM: ViewModel(), KoinComponent {
|
class EasterEggSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val settings: UiSettings by inject()
|
||||||
|
|
||||||
val easterEgg = dataStore.data.map { it.easterEgg }
|
val easterEgg = settings.iconShape.map { it == IconShape.EasterEgg }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
fun setEasterEgg(easterEgg: Boolean) {
|
fun setEasterEgg(easterEgg: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setIconShape(if (easterEgg) IconShape.EasterEgg else IconShape.PlatformDefault)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setEasterEgg(easterEgg).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
import de.mm20.launcher2.preferences.WeightFactor
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||||
|
|||||||
@ -2,8 +2,9 @@ package de.mm20.launcher2.ui.settings.favorites
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.WeightFactor
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.RankingSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -12,65 +13,30 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val favoritesSettings: FavoritesSettings by inject()
|
||||||
|
private val rankingSettings: RankingSettings by inject()
|
||||||
|
|
||||||
val frequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
val frequentlyUsed = favoritesSettings.frequentlyUsed
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsed(frequentlyUsed)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites.toBuilder()
|
|
||||||
.setFrequentlyUsed(frequentlyUsed)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
val frequentlyUsedRows = favoritesSettings.frequentlyUsedRows
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
|
||||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setFrequentlyUsedRows(frequentlyUsedRows)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites.toBuilder()
|
|
||||||
.setFrequentlyUsedRows(frequentlyUsedRows)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val editButton = dataStore.data.map { it.favorites.editButton }
|
val editButton = favoritesSettings.showEditButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setEditButton(editButton: Boolean) {
|
fun setEditButton(editButton: Boolean) {
|
||||||
viewModelScope.launch {
|
favoritesSettings.setShowEditButton(editButton)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setFavorites(
|
|
||||||
it.favorites.toBuilder()
|
|
||||||
.setEditButton(editButton)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchResultWeightFactor = dataStore.data.map { it.resultOrdering.weightFactor }
|
val searchResultWeightFactor = rankingSettings.weightFactor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), WeightFactor.Default)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), WeightFactor.Default)
|
||||||
fun setSearchResultWeightFactor(searchResultWeightFactor: WeightFactor) {
|
fun setSearchResultWeightFactor(searchResultWeightFactor: WeightFactor) {
|
||||||
viewModelScope.launch {
|
rankingSettings.setWeightFactor(searchResultWeightFactor)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setResultOrdering(
|
|
||||||
it.resultOrdering.toBuilder()
|
|
||||||
.setWeightFactor(searchResultWeightFactor)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,11 +7,11 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import de.mm20.launcher2.accounts.Account
|
import de.mm20.launcher2.accounts.Account
|
||||||
import de.mm20.launcher2.accounts.AccountType
|
import de.mm20.launcher2.accounts.AccountType
|
||||||
import de.mm20.launcher2.accounts.AccountsRepository
|
import de.mm20.launcher2.accounts.AccountsRepository
|
||||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.plugin.PluginType
|
import de.mm20.launcher2.plugin.PluginType
|
||||||
import de.mm20.launcher2.plugins.PluginService
|
import de.mm20.launcher2.plugins.PluginService
|
||||||
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|||||||
@ -27,8 +27,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
|
import de.mm20.launcher2.preferences.LegacySettings.LayoutSettings.Layout
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.common.SearchablePicker
|
import de.mm20.launcher2.ui.common.SearchablePicker
|
||||||
@ -47,14 +48,14 @@ fun GestureSettingsScreen() {
|
|||||||
val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null)
|
val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null)
|
||||||
|
|
||||||
val options = buildList {
|
val options = buildList {
|
||||||
add(stringResource(R.string.gesture_action_none) to GestureAction.None)
|
add(stringResource(R.string.gesture_action_none) to GestureAction.NoAction)
|
||||||
add(stringResource(R.string.gesture_action_notifications) to GestureAction.OpenNotificationDrawer)
|
add(stringResource(R.string.gesture_action_notifications) to GestureAction.Notifications)
|
||||||
add(stringResource(R.string.gesture_action_quick_settings) to GestureAction.OpenQuickSettings)
|
add(stringResource(R.string.gesture_action_quick_settings) to GestureAction.QuickSettings)
|
||||||
if (isAtLeastApiLevel(28)) add(stringResource(R.string.gesture_action_lock_screen) to GestureAction.LockScreen)
|
if (isAtLeastApiLevel(28)) add(stringResource(R.string.gesture_action_lock_screen) to GestureAction.ScreenLock)
|
||||||
add(stringResource(R.string.gesture_action_recents) to GestureAction.OpenRecents)
|
add(stringResource(R.string.gesture_action_recents) to GestureAction.Recents)
|
||||||
add(stringResource(R.string.gesture_action_power_menu) to GestureAction.OpenPowerDialog)
|
add(stringResource(R.string.gesture_action_power_menu) to GestureAction.PowerMenu)
|
||||||
add(stringResource(R.string.gesture_action_open_search) to GestureAction.OpenSearch)
|
add(stringResource(R.string.gesture_action_open_search) to GestureAction.Search)
|
||||||
add(stringResource(R.string.gesture_action_launch_app) to GestureAction.LaunchApp)
|
add(stringResource(R.string.gesture_action_launch_app) to GestureAction.Launch(null))
|
||||||
}
|
}
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@ -64,9 +65,9 @@ fun GestureSettingsScreen() {
|
|||||||
val baseLayout by viewModel.baseLayout.collectAsStateWithLifecycle(null)
|
val baseLayout by viewModel.baseLayout.collectAsStateWithLifecycle(null)
|
||||||
ListPreference(title = stringResource(R.string.preference_layout_open_search),
|
ListPreference(title = stringResource(R.string.preference_layout_open_search),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.open_search_pull_down) to Layout.PullDown,
|
stringResource(R.string.open_search_pull_down) to BaseLayout.PullDown,
|
||||||
stringResource(R.string.open_search_swipe_left) to Layout.Pager,
|
stringResource(R.string.open_search_swipe_left) to BaseLayout.Pager,
|
||||||
stringResource(R.string.open_search_swipe_right) to Layout.PagerReversed,
|
stringResource(R.string.open_search_swipe_right) to BaseLayout.PagerReversed,
|
||||||
),
|
),
|
||||||
value = baseLayout,
|
value = baseLayout,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
@ -125,7 +126,7 @@ fun GestureSettingsScreen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val swipeDown by viewModel.swipeDown.collectAsStateWithLifecycle(null)
|
val swipeDown by viewModel.swipeDown.collectAsStateWithLifecycle(null)
|
||||||
val swipeDownIsSearch = layout == Layout.PullDown
|
val swipeDownIsSearch = layout == BaseLayout.PullDown
|
||||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeDown) && !swipeDownIsSearch) {
|
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeDown) && !swipeDownIsSearch) {
|
||||||
MissingPermissionBanner(
|
MissingPermissionBanner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
@ -149,7 +150,7 @@ fun GestureSettingsScreen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val swipeLeft by viewModel.swipeLeft.collectAsStateWithLifecycle(null)
|
val swipeLeft by viewModel.swipeLeft.collectAsStateWithLifecycle(null)
|
||||||
val swipeLeftIsSearch = layout == Layout.Pager
|
val swipeLeftIsSearch = layout == BaseLayout.Pager
|
||||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeLeft) && !swipeLeftIsSearch) {
|
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeLeft) && !swipeLeftIsSearch) {
|
||||||
MissingPermissionBanner(
|
MissingPermissionBanner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
@ -173,7 +174,7 @@ fun GestureSettingsScreen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val swipeRight by viewModel.swipeRight.collectAsStateWithLifecycle(null)
|
val swipeRight by viewModel.swipeRight.collectAsStateWithLifecycle(null)
|
||||||
val swipeRightIsSearch = layout == Layout.PagerReversed
|
val swipeRightIsSearch = layout == BaseLayout.PagerReversed
|
||||||
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeRight) && !swipeRightIsSearch) {
|
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeRight) && !swipeRightIsSearch) {
|
||||||
MissingPermissionBanner(
|
MissingPermissionBanner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
@ -225,11 +226,11 @@ fun GestureSettingsScreen() {
|
|||||||
|
|
||||||
fun requiresAccessibilityService(action: GestureAction?): Boolean {
|
fun requiresAccessibilityService(action: GestureAction?): Boolean {
|
||||||
return when (action) {
|
return when (action) {
|
||||||
GestureAction.OpenNotificationDrawer,
|
is GestureAction.Notifications,
|
||||||
GestureAction.LockScreen,
|
is GestureAction.ScreenLock,
|
||||||
GestureAction.OpenQuickSettings,
|
is GestureAction.QuickSettings,
|
||||||
GestureAction.OpenRecents,
|
is GestureAction.Recents,
|
||||||
GestureAction.OpenPowerDialog -> true
|
is GestureAction.PowerMenu -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,12 +257,12 @@ fun GesturePreference(
|
|||||||
title = title,
|
title = title,
|
||||||
enabled = !isOpenSearch,
|
enabled = !isOpenSearch,
|
||||||
items = options,
|
items = options,
|
||||||
value = if (isOpenSearch) GestureAction.OpenSearch else value,
|
value = if (isOpenSearch) GestureAction.Search else value,
|
||||||
onValueChanged = { if (it != null) onValueChanged(it) }
|
onValueChanged = { if (it != null) onValueChanged(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value == GestureAction.LaunchApp && !isOpenSearch) {
|
if (value is GestureAction.Launch && !isOpenSearch) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(36.dp)
|
.height(36.dp)
|
||||||
@ -277,12 +278,12 @@ fun GesturePreference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOpenSearch && value == GestureAction.LaunchApp && (showAppPicker || app == null)) {
|
if (!isOpenSearch && value is GestureAction.Launch && (showAppPicker || app == null)) {
|
||||||
SearchablePicker(
|
SearchablePicker(
|
||||||
title = { Text(title) },
|
title = { Text(title) },
|
||||||
onDismissRequest = {
|
onDismissRequest = {
|
||||||
showAppPicker = false
|
showAppPicker = false
|
||||||
if (app == null) onValueChanged(GestureAction.None)
|
if (app == null) onValueChanged(GestureAction.NoAction)
|
||||||
},
|
},
|
||||||
value = app,
|
value = app,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
|||||||
@ -3,15 +3,16 @@ package de.mm20.launcher2.ui.settings.gestures
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.BaseLayout
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.GestureAction
|
||||||
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
|
import de.mm20.launcher2.searchable.SavableSearchableRepository
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
@ -22,7 +23,8 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val gestureSettings: GestureSettings by inject()
|
||||||
|
private val uiSettings: UiSettings by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
@ -30,208 +32,124 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
|
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
val baseLayout = uiSettings.baseLayout
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setBaseLayout(baseLayout: Settings.LayoutSettings.Layout) {
|
fun setBaseLayout(baseLayout: BaseLayout) {
|
||||||
viewModelScope.launch {
|
uiSettings.setBaseLayout(baseLayout)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setBaseLayout(baseLayout))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeDown = dataStore.data.map { it.gestures.swipeDown }
|
|
||||||
|
val swipeDown = gestureSettings.swipeDown
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val swipeLeft = dataStore.data.map { it.gestures.swipeLeft }
|
val swipeLeft = gestureSettings.swipeLeft
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val swipeRight = dataStore.data.map { it.gestures.swipeRight }
|
val swipeRight = gestureSettings.swipeRight
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val doubleTap = dataStore.data.map { it.gestures.doubleTap }
|
val doubleTap = gestureSettings.doubleTap
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val longPress = dataStore.data.map { it.gestures.longPress }
|
val longPress = gestureSettings.longPress
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val homeButton = dataStore.data.map { it.gestures.homeButton }
|
val homeButton = gestureSettings.homeButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setSwipeDown(action: GestureAction) {
|
fun setSwipeDown(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setSwipeDown(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeDown(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSwipeLeft(action: GestureAction) {
|
fun setSwipeLeft(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setSwipeLeft(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeLeft(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSwipeRight(action: GestureAction) {
|
fun setSwipeRight(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setSwipeRight(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setSwipeRight(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDoubleTap(action: GestureAction) {
|
fun setDoubleTap(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setDoubleTap(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setDoubleTap(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setLongPress(action: GestureAction) {
|
fun setLongPress(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setLongPress(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setLongPress(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setHomeButton(action: GestureAction) {
|
fun setHomeButton(action: GestureAction) {
|
||||||
viewModelScope.launch {
|
gestureSettings.setHomeButton(action)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setGestures(it.gestures.toBuilder().setHomeButton(action).build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeLeftApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeLeftApp }
|
val swipeLeftApp: Flow<SavableSearchable?> = swipeLeft
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setSwipeLeftApp(searchable: SavableSearchable?) {
|
fun setSwipeLeftApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setSwipeLeft(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setSwipeLeftApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeRightApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeRightApp }
|
val swipeRightApp: Flow<SavableSearchable?> = swipeRight
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setSwipeRightApp(searchable: SavableSearchable?) {
|
fun setSwipeRightApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setSwipeRight(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setSwipeRightApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val swipeDownApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.swipeDownApp }
|
val swipeDownApp: Flow<SavableSearchable?> = swipeDown
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setSwipeDownApp(searchable: SavableSearchable?) {
|
fun setSwipeDownApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setSwipeDown(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setSwipeDownApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val longPressApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.longPressApp }
|
val longPressApp: Flow<SavableSearchable?> = longPress
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setLongPressApp(searchable: SavableSearchable?) {
|
fun setLongPressApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setLongPress(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setLongPressApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val doubleTapApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.doubleTapApp }
|
val doubleTapApp: Flow<SavableSearchable?> = doubleTap
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setDoubleTapApp(searchable: SavableSearchable?) {
|
fun setDoubleTapApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setDoubleTap(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setDoubleTapApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val homeButtonApp: Flow<SavableSearchable?> = dataStore.data.map { it.gestures.homeButtonApp }
|
val homeButtonApp: Flow<SavableSearchable?> = homeButton
|
||||||
.map {
|
.map {
|
||||||
if (it.isEmpty()) null else searchableRepository.getByKeys(listOf(it)).firstOrNull()
|
if (it !is GestureAction.Launch || it.key == null) null
|
||||||
|
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull()
|
||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
|
||||||
|
|
||||||
fun setHomeButtonApp(searchable: SavableSearchable?) {
|
fun setHomeButtonApp(searchable: SavableSearchable?) {
|
||||||
viewModelScope.launch {
|
searchable?.let { searchableRepository.insert(it) } ?: return
|
||||||
searchable?.let { searchableRepository.insert(it) }
|
setHomeButton(GestureAction.Launch(searchable.key))
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGestures(it.gestures.toBuilder()
|
|
||||||
.setHomeButtonApp(searchable?.key ?: "")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun requestPermission(context: AppCompatActivity) {
|
fun requestPermission(context: AppCompatActivity) {
|
||||||
permissionsManager.requestPermission(context, PermissionGroup.Accessibility)
|
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.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
import de.mm20.launcher2.search.SavableSearchable
|
import de.mm20.launcher2.search.SavableSearchable
|
||||||
import de.mm20.launcher2.search.Application
|
import de.mm20.launcher2.search.Application
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -29,7 +29,7 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
private val appRepository: AppRepository by inject()
|
private val appRepository: AppRepository by inject()
|
||||||
private val searchableRepository: SavableSearchableRepository by inject()
|
private val searchableRepository: SavableSearchableRepository by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val searchUiSettings: SearchUiSettings by inject()
|
||||||
|
|
||||||
val allApps = appRepository.findMany().map {
|
val allApps = appRepository.findMany().map {
|
||||||
withContext(Dispatchers.Default) { it.sorted() }
|
withContext(Dispatchers.Default) { it.sorted() }
|
||||||
@ -68,16 +68,10 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
app.openAppDetails(context)
|
app.openAppDetails(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
val hiddenItemsButton = dataStore.data.map { it.searchBar.hiddenItemsButton }
|
val hiddenItemsButton = searchUiSettings.hiddenItemsButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setHiddenItemsButton(hidden: Boolean) {
|
fun setHiddenItemsButton(hidden: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setHiddenItemsButton(hidden)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setSearchBar(it.searchBar.toBuilder().setHiddenItemsButton(hidden)).build()
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,7 +26,10 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.pager.HorizontalPagerIndicator
|
import com.google.accompanist.pager.HorizontalPagerIndicator
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
|
import de.mm20.launcher2.preferences.SystemBarColors
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.SearchBar
|
import de.mm20.launcher2.ui.component.SearchBar
|
||||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||||
@ -109,14 +112,14 @@ fun HomescreenSettingsScreen() {
|
|||||||
viewModel.setSearchBarStyle(it)
|
viewModel.setSearchBarStyle(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
AnimatedVisibility(searchBarStyle == Settings.SearchBarSettings.SearchBarStyle.Transparent) {
|
AnimatedVisibility(searchBarStyle == SearchBarStyle.Transparent) {
|
||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(R.string.preference_search_bar_color),
|
title = stringResource(R.string.preference_search_bar_color),
|
||||||
value = searchBarColor,
|
value = searchBarColor,
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SearchBarSettings.SearchBarColors.Auto,
|
stringResource(R.string.preference_system_bar_icons_auto) to SearchBarColors.Auto,
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SearchBarSettings.SearchBarColors.Light,
|
stringResource(R.string.preference_system_bar_icons_light) to SearchBarColors.Light,
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SearchBarSettings.SearchBarColors.Dark,
|
stringResource(R.string.preference_system_bar_icons_dark) to SearchBarColors.Dark,
|
||||||
),
|
),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setSearchBarColor(it)
|
if (it != null) viewModel.setSearchBarColor(it)
|
||||||
@ -208,9 +211,9 @@ fun HomescreenSettingsScreen() {
|
|||||||
title = stringResource(R.string.preference_status_bar_icons),
|
title = stringResource(R.string.preference_status_bar_icons),
|
||||||
value = lightStatusBar,
|
value = lightStatusBar,
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
|
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
|
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
|
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
|
||||||
),
|
),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setLightStatusBar(it)
|
if (it != null) viewModel.setLightStatusBar(it)
|
||||||
@ -220,9 +223,9 @@ fun HomescreenSettingsScreen() {
|
|||||||
title = stringResource(R.string.preference_nav_bar_icons),
|
title = stringResource(R.string.preference_nav_bar_icons),
|
||||||
value = lightNavBar,
|
value = lightNavBar,
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
|
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
|
||||||
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
|
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
|
||||||
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
|
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
|
||||||
),
|
),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it != null) viewModel.setLightNavBar(it)
|
if (it != null) viewModel.setLightNavBar(it)
|
||||||
@ -255,15 +258,14 @@ fun HomescreenSettingsScreen() {
|
|||||||
fun SearchBarStylePreference(
|
fun SearchBarStylePreference(
|
||||||
title: String,
|
title: String,
|
||||||
summary: String? = null,
|
summary: String? = null,
|
||||||
value: Settings.SearchBarSettings.SearchBarStyle?,
|
value: SearchBarStyle?,
|
||||||
onValueChanged: (Settings.SearchBarSettings.SearchBarStyle) -> Unit
|
onValueChanged: (SearchBarStyle) -> Unit
|
||||||
) {
|
) {
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
||||||
if (showDialog && value != null) {
|
if (showDialog && value != null) {
|
||||||
val styles = remember {
|
val styles = remember {
|
||||||
Settings.SearchBarSettings.SearchBarStyle.values()
|
SearchBarStyle.entries
|
||||||
.filter { it != Settings.SearchBarSettings.SearchBarStyle.UNRECOGNIZED }
|
|
||||||
}
|
}
|
||||||
val pagerState = rememberPagerState(initialPage = styles.indexOf(value)) { styles.size }
|
val pagerState = rememberPagerState(initialPage = styles.indexOf(value)) { styles.size }
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,12 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ScreenOrientation
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarColors
|
||||||
|
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||||
|
import de.mm20.launcher2.preferences.SystemBarColors
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -23,52 +27,31 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.get
|
import org.koin.core.component.get
|
||||||
|
|
||||||
class HomescreenSettingsScreenVM(
|
class HomescreenSettingsScreenVM(
|
||||||
private val dataStore: LauncherDataStore,
|
private val uiSettings: UiSettings,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
var showClockWidgetSheet by mutableStateOf(false)
|
var showClockWidgetSheet by mutableStateOf(false)
|
||||||
|
|
||||||
|
|
||||||
val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }
|
val dimWallpaper = uiSettings.dimWallpaper
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setDimWallpaper(dimWallpaper: Boolean) {
|
fun setDimWallpaper(dimWallpaper: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setDimWallpaper(dimWallpaper)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setDimWallpaper(dimWallpaper)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper }
|
val blurWallpaper = uiSettings.blurWallpaper
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
fun setBlurWallpaper(blurWallpaper: Boolean) {
|
fun setBlurWallpaper(blurWallpaper: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setBlurWallpaper(blurWallpaper)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setBlurWallpaper(blurWallpaper)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val blurWallpaperRadius = dataStore.data.map { it.appearance.blurWallpaperRadius }
|
val blurWallpaperRadius = uiSettings.wallpaperBlurRadius
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 32)
|
||||||
|
|
||||||
fun setBlurWallpaperRadius(blurWallpaperRadius: Int) {
|
fun setBlurWallpaperRadius(blurWallpaperRadius: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setWallpaperBlurRadius(blurWallpaperRadius)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder()
|
|
||||||
.setBlurWallpaperRadius(blurWallpaperRadius)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openWallpaperChooser(context: AppCompatActivity) {
|
fun openWallpaperChooser(context: AppCompatActivity) {
|
||||||
@ -80,168 +63,88 @@ class HomescreenSettingsScreenVM(
|
|||||||
return context.getSystemService<WindowManager>()?.isCrossWindowBlurEnabled == true
|
return context.getSystemService<WindowManager>()?.isCrossWindowBlurEnabled == true
|
||||||
}
|
}
|
||||||
|
|
||||||
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }
|
val statusBarIcons = uiSettings.statusBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setLightStatusBar(statusBarColor: Settings.SystemBarsSettings.SystemBarColors) {
|
|
||||||
viewModelScope.launch {
|
fun setLightStatusBar(statusBarColor: SystemBarColors) {
|
||||||
dataStore.updateData {
|
uiSettings.setStatusBarColor(statusBarColor)
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setStatusBarColor(statusBarColor)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }
|
val navBarIcons = uiSettings.navigationBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setLightNavBar(navBarColors: Settings.SystemBarsSettings.SystemBarColors) {
|
|
||||||
viewModelScope.launch {
|
fun setLightNavBar(navBarColors: SystemBarColors) {
|
||||||
dataStore.updateData {
|
uiSettings.setNavigationBarColor(navBarColors)
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setNavBarColor(navBarColors)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
val hideStatusBar = uiSettings.hideStatusBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setHideStatusBar(hideStatusBar: Boolean) {
|
fun setHideStatusBar(hideStatusBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setHideStatusBar(hideStatusBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setHideStatusBar(hideStatusBar)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
val hideNavBar = uiSettings.hideNavigationBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setHideNavBar(hideNavBar: Boolean) {
|
fun setHideNavBar(hideNavBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setHideNavigationBar(hideNavBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setSystemBars(
|
|
||||||
it.systemBars.toBuilder()
|
|
||||||
.setHideNavBar(hideNavBar)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
val searchBarColor = uiSettings.searchBarColor
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setSearchBarColor(color: Settings.SearchBarSettings.SearchBarColors) {
|
|
||||||
viewModelScope.launch {
|
fun setSearchBarColor(color: SearchBarColors) {
|
||||||
dataStore.updateData {
|
uiSettings.setSearchBarColor(color)
|
||||||
it.toBuilder()
|
|
||||||
.setSearchBar(
|
|
||||||
it.searchBar.toBuilder()
|
|
||||||
.setColor(color)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
val searchBarStyle = uiSettings.searchBarStyle
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setSearchBarStyle(searchBarStyle: Settings.SearchBarSettings.SearchBarStyle) {
|
|
||||||
viewModelScope.launch {
|
fun setSearchBarStyle(searchBarStyle: SearchBarStyle) {
|
||||||
dataStore.updateData {
|
uiSettings.setSearchBarStyle(searchBarStyle)
|
||||||
it.toBuilder()
|
|
||||||
.setSearchBar(
|
|
||||||
it.searchBar.toBuilder()
|
|
||||||
.setSearchBarStyle(searchBarStyle)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
val fixedSearchBar = uiSettings.fixedSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFixedSearchBar(fixedSearchBar: Boolean) {
|
fun setFixedSearchBar(fixedSearchBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setFixedSearchBar(fixedSearchBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setFixedSearchBar(fixedSearchBar))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
val bottomSearchBar = uiSettings.bottomSearchBar
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setBottomSearchBar(bottomSearchBar: Boolean) {
|
fun setBottomSearchBar(bottomSearchBar: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setBottomSearchBar(bottomSearchBar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setBottomSearchBar(bottomSearchBar))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
|
val fixedRotation = uiSettings.orientation.map { it != ScreenOrientation.Auto }
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFixedRotation(fixedRotation: Boolean) {
|
fun setFixedRotation(fixedRotation: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setOrientation(if (fixedRotation) ScreenOrientation.Portrait else ScreenOrientation.Auto)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setFixedRotation(fixedRotation))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val widgetEditButton = dataStore.data.map { it.widgets.editButton }
|
val widgetEditButton = uiSettings.widgetEditButton
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setWidgetEditButton(editButton: Boolean) {
|
fun setWidgetEditButton(editButton: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setWidgetEditButton(editButton)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWidgets(
|
|
||||||
it.widgets.toBuilder()
|
|
||||||
.setEditButton(editButton)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val chargingAnimation = dataStore.data.map { it.animations.charging }
|
val chargingAnimation = uiSettings.chargingAnimation
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setChargingAnimation(chargingAnimation: Boolean) {
|
fun setChargingAnimation(chargingAnimation: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setChargingAnimation(chargingAnimation)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAnimations(
|
|
||||||
it.animations.toBuilder()
|
|
||||||
.setCharging(chargingAnimation)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : KoinComponent {
|
companion object : KoinComponent {
|
||||||
val Factory = viewModelFactory {
|
val Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
HomescreenSettingsScreenVM(
|
HomescreenSettingsScreenVM(
|
||||||
dataStore = get()
|
uiSettings = get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import androidx.compose.material3.FilledIconToggleButton
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedCard
|
|
||||||
import androidx.compose.material3.PlainTooltipBox
|
import androidx.compose.material3.PlainTooltipBox
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@ -50,7 +49,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.icons.StaticIconLayer
|
import de.mm20.launcher2.icons.StaticIconLayer
|
||||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
|
import de.mm20.launcher2.preferences.ui.GridSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.IconSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.IconSettingsData
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||||
@ -63,25 +65,18 @@ import de.mm20.launcher2.ui.component.preferences.SliderPreference
|
|||||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||||
import de.mm20.launcher2.ui.component.preferences.label
|
import de.mm20.launcher2.ui.component.preferences.label
|
||||||
import de.mm20.launcher2.ui.component.preferences.value
|
import de.mm20.launcher2.ui.component.preferences.value
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun IconsSettingsScreen() {
|
fun IconsSettingsScreen() {
|
||||||
val viewModel: IconsSettingsScreenVM = viewModel(factory = IconsSettingsScreenVM.Factory)
|
val viewModel: IconsSettingsScreenVM = viewModel(factory = IconsSettingsScreenVM.Factory)
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val iconSize by viewModel.iconSize.collectAsStateWithLifecycle(48)
|
val grid by viewModel.grid.collectAsStateWithLifecycle(GridSettings())
|
||||||
|
val icons by viewModel.icons.collectAsStateWithLifecycle(null)
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val showLabels by viewModel.showLabels.collectAsStateWithLifecycle(null)
|
val iconShape by viewModel.iconShape.collectAsStateWithLifecycle(IconShape.PlatformDefault)
|
||||||
val columnCount by viewModel.columnCount.collectAsStateWithLifecycle(5)
|
|
||||||
val iconShape by viewModel.iconShape.collectAsStateWithLifecycle(Settings.IconSettings.IconShape.PlatformDefault)
|
|
||||||
val adaptifyLegacyIcons by viewModel.adaptifyLegacyIcons.collectAsStateWithLifecycle(null)
|
|
||||||
val themedIcons by viewModel.themedIcons.collectAsStateWithLifecycle(null)
|
|
||||||
|
|
||||||
val iconPackPackage by viewModel.iconPack.collectAsStateWithLifecycle(null)
|
|
||||||
val iconPackThemed by viewModel.iconPackThemed.collectAsState(true)
|
|
||||||
val installedIconPacks by viewModel.installedIconPacks.collectAsState(emptyList())
|
val installedIconPacks by viewModel.installedIconPacks.collectAsState(emptyList())
|
||||||
val forceThemedIcons by viewModel.forceThemedIcons.collectAsStateWithLifecycle(null)
|
|
||||||
|
|
||||||
val hasNotificationsPermission by viewModel.hasNotificationsPermission.collectAsStateWithLifecycle(null)
|
val hasNotificationsPermission by viewModel.hasNotificationsPermission.collectAsStateWithLifecycle(null)
|
||||||
|
|
||||||
@ -91,8 +86,8 @@ fun IconsSettingsScreen() {
|
|||||||
val shortcutBadges by viewModel.shortcutBadges.collectAsStateWithLifecycle(null)
|
val shortcutBadges by viewModel.shortcutBadges.collectAsStateWithLifecycle(null)
|
||||||
val pluginBadges by viewModel.pluginBadges.collectAsStateWithLifecycle(null)
|
val pluginBadges by viewModel.pluginBadges.collectAsStateWithLifecycle(null)
|
||||||
|
|
||||||
val previewIcons by remember(iconSize) {
|
val previewIcons by remember(grid?.iconSize) {
|
||||||
viewModel.getPreviewIcons(with(density) { iconSize.dp.toPx() }.toInt())
|
viewModel.getPreviewIcons(with(density) { grid.iconSize.dp.toPx() }.toInt())
|
||||||
}.collectAsState(
|
}.collectAsState(
|
||||||
emptyList()
|
emptyList()
|
||||||
)
|
)
|
||||||
@ -102,7 +97,7 @@ fun IconsSettingsScreen() {
|
|||||||
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
|
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_grid_icon_size),
|
title = stringResource(R.string.preference_grid_icon_size),
|
||||||
value = iconSize,
|
value = grid.iconSize,
|
||||||
step = 8,
|
step = 8,
|
||||||
min = 32,
|
min = 32,
|
||||||
max = 64,
|
max = 64,
|
||||||
@ -113,14 +108,14 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_grid_labels),
|
title = stringResource(R.string.preference_grid_labels),
|
||||||
summary = stringResource(R.string.preference_grid_labels_summary),
|
summary = stringResource(R.string.preference_grid_labels_summary),
|
||||||
value = showLabels == true,
|
value = grid.showLabels,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setShowLabels(it)
|
viewModel.setShowLabels(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
SliderPreference(
|
SliderPreference(
|
||||||
title = stringResource(R.string.preference_grid_column_count),
|
title = stringResource(R.string.preference_grid_column_count),
|
||||||
value = columnCount,
|
value = grid.columnCount,
|
||||||
min = 3,
|
min = 3,
|
||||||
max = 12,
|
max = 12,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
@ -148,7 +143,7 @@ fun IconsSettingsScreen() {
|
|||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
ShapedLauncherIcon(size = iconSize.dp, icon = { icon })
|
ShapedLauncherIcon(size = grid.iconSize.dp, icon = { icon })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,7 +160,7 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_enforce_icon_shape),
|
title = stringResource(R.string.preference_enforce_icon_shape),
|
||||||
summary = stringResource(R.string.preference_enforce_icon_shape_summary),
|
summary = stringResource(R.string.preference_enforce_icon_shape_summary),
|
||||||
value = adaptifyLegacyIcons == true,
|
value = icons?.adaptify == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setAdaptifyLegacyIcons(it)
|
viewModel.setAdaptifyLegacyIcons(it)
|
||||||
}
|
}
|
||||||
@ -173,7 +168,7 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_themed_icons),
|
title = stringResource(R.string.preference_themed_icons),
|
||||||
summary = stringResource(R.string.preference_themed_icons_summary),
|
summary = stringResource(R.string.preference_themed_icons_summary),
|
||||||
value = themedIcons == true,
|
value = icons?.themedIcons == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setThemedIcons(it)
|
viewModel.setThemedIcons(it)
|
||||||
}
|
}
|
||||||
@ -181,14 +176,14 @@ fun IconsSettingsScreen() {
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
title = stringResource(R.string.preference_force_themed_icons),
|
title = stringResource(R.string.preference_force_themed_icons),
|
||||||
summary = stringResource(R.string.preference_force_themed_icons_summary),
|
summary = stringResource(R.string.preference_force_themed_icons_summary),
|
||||||
value = forceThemedIcons == true,
|
value = icons?.forceThemed == true,
|
||||||
enabled = themedIcons == true,
|
enabled = icons?.themedIcons == true,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
viewModel.setForceThemedIcons(it)
|
viewModel.setForceThemedIcons(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val iconPack by remember {
|
val iconPack by remember {
|
||||||
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == iconPackPackage } }
|
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == icons?.iconPack } }
|
||||||
}
|
}
|
||||||
val items = installedIconPacks.map {
|
val items = installedIconPacks.map {
|
||||||
it.name to it
|
it.name to it
|
||||||
@ -265,7 +260,7 @@ fun IconsSettingsScreen() {
|
|||||||
PlainTooltipBox(tooltip = { Text(stringResource(R.string.icon_pack_dynamic_colors)) }) {
|
PlainTooltipBox(tooltip = { Text(stringResource(R.string.icon_pack_dynamic_colors)) }) {
|
||||||
FilledIconToggleButton(
|
FilledIconToggleButton(
|
||||||
modifier = Modifier.tooltipTrigger(),
|
modifier = Modifier.tooltipTrigger(),
|
||||||
checked = iconPackThemed,
|
checked = icons?.iconPackThemed == true,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
viewModel.setIconPackThemed(it)
|
viewModel.setIconPackThemed(it)
|
||||||
}) {
|
}) {
|
||||||
@ -347,16 +342,16 @@ fun IconsSettingsScreen() {
|
|||||||
fun IconShapePreference(
|
fun IconShapePreference(
|
||||||
title: String,
|
title: String,
|
||||||
summary: String? = null,
|
summary: String? = null,
|
||||||
value: Settings.IconSettings.IconShape?,
|
value: IconShape?,
|
||||||
onValueChanged: (Settings.IconSettings.IconShape) -> Unit
|
onValueChanged: (IconShape) -> Unit
|
||||||
) {
|
) {
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
Preference(title = title, summary = summary, onClick = { showDialog = true })
|
||||||
|
|
||||||
if (showDialog && value != null) {
|
if (showDialog && value != null) {
|
||||||
val shapes = remember {
|
val shapes = remember {
|
||||||
Settings.IconSettings.IconShape.values()
|
IconShape.entries
|
||||||
.filter { it != Settings.IconSettings.IconShape.UNRECOGNIZED && it != Settings.IconSettings.IconShape.EasterEgg }
|
.filter { it != IconShape.EasterEgg }
|
||||||
}
|
}
|
||||||
Dialog(onDismissRequest = { showDialog = false }) {
|
Dialog(onDismissRequest = { showDialog = false }) {
|
||||||
Surface(
|
Surface(
|
||||||
@ -431,19 +426,19 @@ fun IconShapePreference(
|
|||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getShapeName(shape: Settings.IconSettings.IconShape?): String? {
|
private fun getShapeName(shape: IconShape?): String? {
|
||||||
return stringResource(
|
return stringResource(
|
||||||
when (shape) {
|
when (shape) {
|
||||||
Settings.IconSettings.IconShape.Triangle -> R.string.preference_icon_shape_triangle
|
IconShape.Triangle -> R.string.preference_icon_shape_triangle
|
||||||
Settings.IconSettings.IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
|
IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
|
||||||
Settings.IconSettings.IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
|
IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
|
||||||
Settings.IconSettings.IconShape.Squircle -> R.string.preference_icon_shape_squircle
|
IconShape.Squircle -> R.string.preference_icon_shape_squircle
|
||||||
Settings.IconSettings.IconShape.Square -> R.string.preference_icon_shape_square
|
IconShape.Square -> R.string.preference_icon_shape_square
|
||||||
Settings.IconSettings.IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
|
IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
|
||||||
Settings.IconSettings.IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
|
IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
|
||||||
Settings.IconSettings.IconShape.Circle -> R.string.preference_icon_shape_circle
|
IconShape.Circle -> R.string.preference_icon_shape_circle
|
||||||
Settings.IconSettings.IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
|
IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
|
||||||
Settings.IconSettings.IconShape.Pebble -> R.string.preference_icon_shape_pebble
|
IconShape.Pebble -> R.string.preference_icon_shape_pebble
|
||||||
else -> return null
|
else -> return null
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,124 +2,64 @@ package de.mm20.launcher2.ui.settings.icons
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import de.mm20.launcher2.badges.settings.BadgeSettings
|
|
||||||
import de.mm20.launcher2.icons.IconPack
|
import de.mm20.launcher2.icons.IconPack
|
||||||
import de.mm20.launcher2.icons.IconService
|
import de.mm20.launcher2.icons.IconService
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.IconShape
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.ui.BadgeSettings
|
||||||
import de.mm20.launcher2.search.Application
|
import de.mm20.launcher2.preferences.ui.IconSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.get
|
import org.koin.core.component.get
|
||||||
|
|
||||||
class IconsSettingsScreenVM(
|
class IconsSettingsScreenVM(
|
||||||
private val dataStore: LauncherDataStore,
|
private val uiSettings: UiSettings,
|
||||||
|
private val iconSettings: IconSettings,
|
||||||
private val badgeSettings: BadgeSettings,
|
private val badgeSettings: BadgeSettings,
|
||||||
private val iconService: IconService,
|
private val iconService: IconService,
|
||||||
private val favoritesService: FavoritesService,
|
private val favoritesService: FavoritesService,
|
||||||
private val permissionsManager: PermissionsManager,
|
private val permissionsManager: PermissionsManager,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
|
val grid = uiSettings.gridSettings
|
||||||
|
|
||||||
val columnCount = dataStore.data.map { it.grid.columnCount }
|
|
||||||
fun setColumnCount(columnCount: Int) {
|
fun setColumnCount(columnCount: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setGridColumnCount(columnCount)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGrid(it.grid.toBuilder().setColumnCount(columnCount))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconSize = dataStore.data.map { it.grid.iconSize }
|
|
||||||
fun setIconSize(iconSize: Int) {
|
fun setIconSize(iconSize: Int) {
|
||||||
viewModelScope.launch {
|
uiSettings.setGridIconSize(iconSize)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGrid(it.grid.toBuilder().setIconSize(iconSize))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val showLabels = dataStore.data.map { it.grid.showLabels }
|
|
||||||
fun setShowLabels(showLabels: Boolean) {
|
fun setShowLabels(showLabels: Boolean) {
|
||||||
viewModelScope.launch {
|
uiSettings.setGridShowLabels(showLabels)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setGrid(it.grid.toBuilder().setShowLabels(showLabels))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconShape = dataStore.data.map { it.icons.shape }
|
val iconShape = uiSettings.iconShape
|
||||||
fun setIconShape(iconShape: Settings.IconSettings.IconShape) {
|
fun setIconShape(iconShape: IconShape) {
|
||||||
viewModelScope.launch {
|
uiSettings.setIconShape(iconShape)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setShape(iconShape)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val adaptifyLegacyIcons = dataStore.data.map { it.icons.adaptify }
|
val icons = iconSettings
|
||||||
fun setAdaptifyLegacyIcons(adaptify: Boolean) {
|
fun setAdaptifyLegacyIcons(adaptify: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setAdaptifyLegacyIcons(adaptify)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setAdaptify(adaptify)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val themedIcons = dataStore.data.map { it.icons.themedIcons }
|
|
||||||
fun setThemedIcons(themedIcons: Boolean) {
|
fun setThemedIcons(themedIcons: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setThemedIcons(themedIcons)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setThemedIcons(themedIcons)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val forceThemedIcons = dataStore.data.map { it.icons.forceThemed }
|
|
||||||
fun setForceThemedIcons(forceThemedIcons: Boolean) {
|
fun setForceThemedIcons(forceThemedIcons: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setForceThemedIcons(forceThemedIcons)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setForceThemed(forceThemedIcons)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val installedIconPacks: Flow<List<IconPack>> = iconService.getInstalledIconPacks().map {
|
val installedIconPacks: Flow<List<IconPack>> = iconService.getInstalledIconPacks().map {
|
||||||
@ -132,33 +72,12 @@ class IconsSettingsScreenVM(
|
|||||||
) + it
|
) + it
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconPackThemed = dataStore.data.map { it.icons.iconPackThemed }
|
|
||||||
fun setIconPackThemed(iconPackThemed: Boolean) {
|
fun setIconPackThemed(iconPackThemed: Boolean) {
|
||||||
viewModelScope.launch {
|
iconSettings.setIconPackThemed(iconPackThemed)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons
|
|
||||||
.toBuilder()
|
|
||||||
.setIconPackThemed(iconPackThemed)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconPack = dataStore.data.map { it.icons.iconPack }
|
fun setIconPack(iconPack: String?) {
|
||||||
fun setIconPack(iconPack: String) {
|
iconSettings.setIconPack(iconPack?.takeIf { it.isNotBlank() })
|
||||||
viewModelScope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setIcons(
|
|
||||||
it.icons.toBuilder()
|
|
||||||
.setIconPack(iconPack)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasNotificationsPermission = permissionsManager.hasPermission(PermissionGroup.Notifications)
|
val hasNotificationsPermission = permissionsManager.hasPermission(PermissionGroup.Notifications)
|
||||||
@ -193,10 +112,10 @@ class IconsSettingsScreenVM(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getPreviewIcons(size: Int): Flow<List<LauncherIcon?>> {
|
fun getPreviewIcons(size: Int): Flow<List<LauncherIcon?>> {
|
||||||
return columnCount.flatMapLatest { cols ->
|
return grid.flatMapLatest { grid ->
|
||||||
favoritesService.getFavorites(
|
favoritesService.getFavorites(
|
||||||
includeTypes = listOf("app"),
|
includeTypes = listOf("app"),
|
||||||
limit = cols,
|
limit = grid.columnCount,
|
||||||
manuallySorted = true,
|
manuallySorted = true,
|
||||||
automaticallySorted = true,
|
automaticallySorted = true,
|
||||||
frequentlyUsed = true,
|
frequentlyUsed = true,
|
||||||
@ -214,11 +133,12 @@ class IconsSettingsScreenVM(
|
|||||||
val Factory = viewModelFactory {
|
val Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
IconsSettingsScreenVM(
|
IconsSettingsScreenVM(
|
||||||
dataStore = get(),
|
uiSettings = get(),
|
||||||
iconService = get(),
|
iconService = get(),
|
||||||
permissionsManager = get(),
|
permissionsManager = get(),
|
||||||
favoritesService = get(),
|
favoritesService = get(),
|
||||||
badgeSettings = get(),
|
badgeSettings = get(),
|
||||||
|
iconSettings = get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,13 +11,12 @@ import de.mm20.launcher2.ktx.normalize
|
|||||||
import de.mm20.launcher2.music.MusicService
|
import de.mm20.launcher2.music.MusicService
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.media.MediaSettings
|
||||||
import de.mm20.launcher2.search.AppProfile
|
import de.mm20.launcher2.search.AppProfile
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@ -29,7 +28,9 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
private val musicService: MusicService by inject()
|
private val musicService: MusicService by inject()
|
||||||
private val appRepository: AppRepository by inject()
|
private val appRepository: AppRepository by inject()
|
||||||
private val iconService: IconService by inject()
|
private val iconService: IconService by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
|
private val mediaSettings: MediaSettings by inject()
|
||||||
|
|
||||||
val hasPermission =
|
val hasPermission =
|
||||||
permissionsManager.hasPermission(PermissionGroup.Notifications)
|
permissionsManager.hasPermission(PermissionGroup.Notifications)
|
||||||
|
|
||||||
@ -52,9 +53,9 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
val musicApps = musicService.getInstalledPlayerPackages()
|
val musicApps = musicService.getInstalledPlayerPackages()
|
||||||
val allApps = appRepository.findMany().first().filter { it.profile == AppProfile.Personal }
|
val allApps = appRepository.findMany().first().filter { it.profile == AppProfile.Personal }
|
||||||
.distinctBy { it.componentName.packageName }
|
.distinctBy { it.componentName.packageName }
|
||||||
val settings = dataStore.data.map { it.musicWidget }.first()
|
val settings = mediaSettings.first()
|
||||||
val allowList = settings.allowListList
|
val allowList = settings.allowList
|
||||||
val denyList = settings.denyListList
|
val denyList = settings.denyList
|
||||||
|
|
||||||
appList.value = allApps.map {
|
appList.value = allApps.map {
|
||||||
AppListItem(
|
AppListItem(
|
||||||
@ -92,19 +93,7 @@ class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
denyList.add(app.packageName)
|
denyList.add(app.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewModelScope.launch {
|
mediaSettings.setLists(allowList.toSet(), denyList.toSet())
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setMusicWidget(
|
|
||||||
it.musicWidget.toBuilder()
|
|
||||||
.clearAllowList()
|
|
||||||
.addAllAllowList(allowList)
|
|
||||||
.clearDenyList()
|
|
||||||
.addAllDenyList(denyList)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||||
import androidx.compose.material.icons.automirrored.rounded.InsertDriveFile
|
import androidx.compose.material.icons.automirrored.rounded.InsertDriveFile
|
||||||
|
import androidx.compose.material.icons.automirrored.rounded.OpenInNew
|
||||||
import androidx.compose.material.icons.rounded.Delete
|
import androidx.compose.material.icons.rounded.Delete
|
||||||
import androidx.compose.material.icons.rounded.Error
|
import androidx.compose.material.icons.rounded.Error
|
||||||
import androidx.compose.material.icons.rounded.Info
|
import androidx.compose.material.icons.rounded.Info
|
||||||
@ -40,6 +41,7 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
@ -48,7 +50,9 @@ import coil.compose.AsyncImage
|
|||||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||||
import de.mm20.launcher2.plugin.PluginState
|
import de.mm20.launcher2.plugin.PluginState
|
||||||
import de.mm20.launcher2.plugin.PluginType
|
import de.mm20.launcher2.plugin.PluginType
|
||||||
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.Banner
|
import de.mm20.launcher2.ui.component.Banner
|
||||||
|
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||||
@ -76,6 +80,11 @@ fun PluginSettingsScreen(pluginId: String) {
|
|||||||
minActiveState = Lifecycle.State.RESUMED
|
minActiveState = Lifecycle.State.RESUMED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val weatherPlugins by viewModel.weatherPlugins.collectAsStateWithLifecycle(
|
||||||
|
emptyList(),
|
||||||
|
minActiveState = Lifecycle.State.RESUMED
|
||||||
|
)
|
||||||
|
|
||||||
val requestPermissionStarter =
|
val requestPermissionStarter =
|
||||||
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
@ -87,6 +96,10 @@ fun PluginSettingsScreen(pluginId: String) {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val weatherProviderId by viewModel.weatherProvider.collectAsStateWithLifecycle(
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@ -286,7 +299,7 @@ fun PluginSettingsScreen(pluginId: String) {
|
|||||||
AnimatedVisibility(pluginPackage?.enabled == true && hasPermission == true) {
|
AnimatedVisibility(pluginPackage?.enabled == true && hasPermission == true) {
|
||||||
if (filePlugins.isNotEmpty()) {
|
if (filePlugins.isNotEmpty()) {
|
||||||
PreferenceCategory(
|
PreferenceCategory(
|
||||||
"File search",
|
stringResource(R.string.plugin_type_filesearch),
|
||||||
iconPadding = false,
|
iconPadding = false,
|
||||||
) {
|
) {
|
||||||
for (plugin in filePlugins) {
|
for (plugin in filePlugins) {
|
||||||
@ -294,7 +307,7 @@ fun PluginSettingsScreen(pluginId: String) {
|
|||||||
if (state is PluginState.SetupRequired) {
|
if (state is PluginState.SetupRequired) {
|
||||||
Banner(
|
Banner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
text = state.message ?: "You need to setup this plugin first",
|
text = state.message ?: stringResource(R.string.plugin_state_setup_required),
|
||||||
icon = Icons.Rounded.Info,
|
icon = Icons.Rounded.Info,
|
||||||
primaryAction = {
|
primaryAction = {
|
||||||
TextButton(onClick = {
|
TextButton(onClick = {
|
||||||
@ -311,7 +324,7 @@ fun PluginSettingsScreen(pluginId: String) {
|
|||||||
} else if (state is PluginState.Error) {
|
} else if (state is PluginState.Error) {
|
||||||
Banner(
|
Banner(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
text = "This plugin isn't working correctly",
|
text = stringResource(R.string.plugin_state_error),
|
||||||
icon = Icons.Rounded.Error,
|
icon = Icons.Rounded.Error,
|
||||||
color = MaterialTheme.colorScheme.errorContainer,
|
color = MaterialTheme.colorScheme.errorContainer,
|
||||||
)
|
)
|
||||||
@ -334,6 +347,58 @@ fun PluginSettingsScreen(pluginId: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (weatherPlugins.isNotEmpty()) {
|
||||||
|
PreferenceCategory(
|
||||||
|
stringResource(R.string.plugin_type_weather),
|
||||||
|
iconPadding = false,
|
||||||
|
) {
|
||||||
|
for (plugin in weatherPlugins) {
|
||||||
|
val state = plugin.state
|
||||||
|
if (state is PluginState.SetupRequired) {
|
||||||
|
Banner(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
text = state.message ?: stringResource(R.string.plugin_state_setup_required),
|
||||||
|
icon = Icons.Rounded.Info,
|
||||||
|
primaryAction = {
|
||||||
|
TextButton(onClick = {
|
||||||
|
try {
|
||||||
|
state.setupActivity.send()
|
||||||
|
} catch (e: PendingIntent.CanceledException) {
|
||||||
|
CrashReporter.logException(e)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text(stringResource(R.string.plugin_action_setup))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else if (state is PluginState.Error) {
|
||||||
|
Banner(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
text = stringResource(R.string.plugin_state_error),
|
||||||
|
icon = Icons.Rounded.Error,
|
||||||
|
color = MaterialTheme.colorScheme.errorContainer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Preference(
|
||||||
|
title = plugin.plugin.label,
|
||||||
|
enabled = state is PluginState.Ready && weatherProviderId != plugin.plugin.authority,
|
||||||
|
iconPadding = false,
|
||||||
|
summary = if (weatherProviderId != plugin.plugin.authority) {
|
||||||
|
stringResource(R.string.plugin_weather_provider_enable)
|
||||||
|
} else {
|
||||||
|
stringResource(R.string.plugin_weather_provider_enabled)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Preference(
|
||||||
|
title = stringResource(R.string.widget_config_weather_integration_settings),
|
||||||
|
icon = Icons.AutoMirrored.Rounded.OpenInNew,
|
||||||
|
onClick = {
|
||||||
|
navController?.navigate("settings/integrations/weather")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,13 +7,14 @@ import android.net.Uri
|
|||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.files.settings.FileSearchSettings
|
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
import de.mm20.launcher2.plugin.PluginPackage
|
import de.mm20.launcher2.plugin.PluginPackage
|
||||||
import de.mm20.launcher2.plugin.PluginState
|
import de.mm20.launcher2.plugin.PluginState
|
||||||
import de.mm20.launcher2.plugin.PluginType
|
import de.mm20.launcher2.plugin.PluginType
|
||||||
import de.mm20.launcher2.plugins.PluginService
|
import de.mm20.launcher2.plugins.PluginService
|
||||||
import de.mm20.launcher2.plugins.PluginWithState
|
import de.mm20.launcher2.plugins.PluginWithState
|
||||||
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
@ -30,6 +31,7 @@ import org.koin.core.component.inject
|
|||||||
class PluginSettingsScreenVM : ViewModel(), KoinComponent {
|
class PluginSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val pluginService by inject<PluginService>()
|
private val pluginService by inject<PluginService>()
|
||||||
private val fileSearchSettings: FileSearchSettings by inject()
|
private val fileSearchSettings: FileSearchSettings by inject()
|
||||||
|
private val weatherSettings: WeatherSettings by inject()
|
||||||
|
|
||||||
private var pluginPackageName = MutableStateFlow<String?>(null)
|
private var pluginPackageName = MutableStateFlow<String?>(null)
|
||||||
|
|
||||||
@ -70,6 +72,11 @@ class PluginSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
it.filter { it.plugin.type == PluginType.FileSearch }
|
it.filter { it.plugin.type == PluginType.FileSearch }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val weatherPlugins = states
|
||||||
|
.map {
|
||||||
|
it.filter { it.plugin.type == PluginType.Weather }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun init(pluginId: String) {
|
fun init(pluginId: String) {
|
||||||
this.pluginPackageName.value = pluginId
|
this.pluginPackageName.value = pluginId
|
||||||
@ -101,4 +108,9 @@ class PluginSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
fun setFileSearchPluginEnabled(authority: String, enabled: Boolean) {
|
fun setFileSearchPluginEnabled(authority: String, enabled: Boolean) {
|
||||||
fileSearchSettings.setPluginEnabled(authority, enabled)
|
fileSearchSettings.setPluginEnabled(authority, enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val weatherProvider = weatherSettings.providerId
|
||||||
|
fun setWeatherProvider(providerId: String) {
|
||||||
|
weatherSettings.setProvider(providerId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -13,7 +13,8 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||||
import de.mm20.launcher2.ui.component.preferences.*
|
import de.mm20.launcher2.ui.component.preferences.*
|
||||||
@ -232,8 +233,8 @@ fun SearchSettingsScreen() {
|
|||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(R.string.preference_search_result_ordering),
|
title = stringResource(R.string.preference_search_result_ordering),
|
||||||
items = listOf(
|
items = listOf(
|
||||||
stringResource(R.string.preference_search_result_ordering_alphabetic) to Settings.SearchResultOrderingSettings.Ordering.Alphabetic,
|
stringResource(R.string.preference_search_result_ordering_alphabetic) to SearchResultOrder.Alphabetical,
|
||||||
stringResource(R.string.preference_search_result_ordering_weighted) to Settings.SearchResultOrderingSettings.Ordering.Weighted
|
stringResource(R.string.preference_search_result_ordering_weighted) to SearchResultOrder.Weighted
|
||||||
),
|
),
|
||||||
value = searchResultOrdering,
|
value = searchResultOrdering,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
|||||||
@ -5,10 +5,16 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.SearchResultOrder
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.search.CalculatorSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.CalendarSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.UnitConverterSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WebsiteSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WikipediaSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -16,35 +22,32 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val searchUiSettings: SearchUiSettings by inject()
|
||||||
|
private val contactSearchSettings: ContactSearchSettings by inject()
|
||||||
|
private val calendarSearchSettings: CalendarSearchSettings by inject()
|
||||||
|
private val shortcutSearchSettings: ShortcutSearchSettings by inject()
|
||||||
|
private val wikipediaSearchSettings: WikipediaSearchSettings by inject()
|
||||||
|
private val websiteSearchSettings: WebsiteSearchSettings by inject()
|
||||||
|
private val unitConverterSettings: UnitConverterSettings by inject()
|
||||||
|
private val calculatorSearchSettings: CalculatorSearchSettings by inject()
|
||||||
|
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
|
|
||||||
val favorites = dataStore.data.map { it.favorites.enabled }
|
val favorites = searchUiSettings.favorites
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setFavorites(favorites: Boolean) {
|
fun setFavorites(favorites: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setFavorites(favorites)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setFavorites(
|
|
||||||
it.favorites.toBuilder().setEnabled(favorites)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val contacts = dataStore.data.map { it.contactsSearch.enabled }
|
val contacts = contactSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setContacts(contacts: Boolean) {
|
fun setContacts(contacts: Boolean) {
|
||||||
viewModelScope.launch {
|
contactSearchSettings.setEnabled(contacts)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setContactsSearch(
|
|
||||||
it.contactsSearch.toBuilder().setEnabled(contacts)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestContactsPermission(activity: AppCompatActivity) {
|
fun requestContactsPermission(activity: AppCompatActivity) {
|
||||||
@ -53,133 +56,81 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val calendar = dataStore.data.map { it.calendarSearch.enabled }
|
val calendar = calendarSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setCalendar(calendar: Boolean) {
|
fun setCalendar(calendar: Boolean) {
|
||||||
viewModelScope.launch {
|
calendarSearchSettings.setEnabled(calendar)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setCalendarSearch(
|
|
||||||
it.calendarSearch.toBuilder().setEnabled(calendar)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestCalendarPermission(activity: AppCompatActivity) {
|
fun requestCalendarPermission(activity: AppCompatActivity) {
|
||||||
permissionsManager.requestPermission(activity, PermissionGroup.Calendar)
|
permissionsManager.requestPermission(activity, PermissionGroup.Calendar)
|
||||||
}
|
}
|
||||||
|
|
||||||
val calculator = dataStore.data.map { it.calculatorSearch.enabled }
|
val calculator = calculatorSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setCalculator(calculator: Boolean) {
|
fun setCalculator(calculator: Boolean) {
|
||||||
viewModelScope.launch {
|
calculatorSearchSettings.setEnabled(calculator)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setCalculatorSearch(
|
|
||||||
it.calculatorSearch.toBuilder().setEnabled(calculator)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
|
val unitConverter = unitConverterSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setUnitConverter(unitConverter: Boolean) {
|
fun setUnitConverter(unitConverter: Boolean) {
|
||||||
viewModelScope.launch {
|
unitConverterSettings.setEnabled(unitConverter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setUnitConverterSearch(
|
|
||||||
it.unitConverterSearch.toBuilder().setEnabled(unitConverter)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
|
val wikipedia = wikipediaSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setWikipedia(wikipedia: Boolean) {
|
fun setWikipedia(wikipedia: Boolean) {
|
||||||
viewModelScope.launch {
|
wikipediaSearchSettings.setEnabled(wikipedia)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder().setEnabled(wikipedia)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val websites = dataStore.data.map { it.websiteSearch.enabled }
|
val websites = websiteSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setWebsites(websites: Boolean) {
|
fun setWebsites(websites: Boolean) {
|
||||||
viewModelScope.launch {
|
websiteSearchSettings.setEnabled(websites)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setWebsiteSearch(
|
|
||||||
it.websiteSearch.toBuilder().setEnabled(websites)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val autoFocus = dataStore.data.map { it.searchBar.autoFocus }
|
val autoFocus = searchUiSettings.openKeyboard
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setAutoFocus(autoFocus: Boolean) {
|
fun setAutoFocus(autoFocus: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setOpenKeyboard(autoFocus)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setSearchBar(
|
|
||||||
it.searchBar.toBuilder().setAutoFocus(autoFocus)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
|
val launchOnEnter = searchUiSettings.launchOnEnter
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setLaunchOnEnter(launchOnEnter: Boolean) {
|
fun setLaunchOnEnter(launchOnEnter: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setLaunchOnEnter(launchOnEnter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setSearchBar(
|
|
||||||
it.searchBar.toBuilder().setLaunchOnEnter(launchOnEnter)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
|
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled }
|
val appShortcuts = shortcutSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setAppShortcuts(appShortcuts: Boolean) {
|
fun setAppShortcuts(appShortcuts: Boolean) {
|
||||||
viewModelScope.launch {
|
shortcutSearchSettings.setEnabled(appShortcuts)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setAppShortcutSearch(
|
|
||||||
it.appShortcutSearch.toBuilder().setEnabled(appShortcuts)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering }
|
val searchResultOrdering = searchUiSettings.resultOrder
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setSearchResultOrdering(searchResultOrdering: Settings.SearchResultOrderingSettings.Ordering) {
|
|
||||||
viewModelScope.launch {
|
fun setSearchResultOrdering(searchResultOrdering: SearchResultOrder) {
|
||||||
dataStore.updateData {
|
searchUiSettings.setResultOrder(searchResultOrdering)
|
||||||
it.toBuilder().setResultOrdering(
|
|
||||||
it.resultOrdering.toBuilder().setOrdering(searchResultOrdering)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
val reverseSearchResults = searchUiSettings.reversedResults
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
fun setReverseSearchResults(reverseSearchResults: Boolean) {
|
fun setReverseSearchResults(reverseSearchResults: Boolean) {
|
||||||
viewModelScope.launch {
|
searchUiSettings.setReversedResults(reverseSearchResults)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setLayout(it.layout.toBuilder().setReverseSearchResults(reverseSearchResults))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestAppShortcutsPermission(activity: AppCompatActivity) {
|
fun requestAppShortcutsPermission(activity: AppCompatActivity) {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ class EditTagSheetVM : ViewModel(), KoinComponent {
|
|||||||
viewModelScope.launch(Dispatchers.Default) {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
allTags = tagService.getAllTags().first().toSet()
|
allTags = tagService.getAllTags().first().toSet()
|
||||||
val items = if (tag != null) tagService.getTaggedItems(tag).first() else emptyList()
|
val items = if (tag != null) tagService.getTaggedItems(tag).first() else emptyList()
|
||||||
val apps = appRepository.findMany().first().sorted()
|
val apps = appRepository.findMany().first { it.isNotEmpty() }.sorted()
|
||||||
taggedItems = items
|
taggedItems = items
|
||||||
taggableApps = apps.map { app -> TaggableItem(app, items.any { app.key == it.key }) }
|
taggableApps = apps.map { app -> TaggableItem(app, items.any { app.key == it.key }) }
|
||||||
taggableOther = items.mapNotNull { item ->
|
taggableOther = items.mapNotNull { item ->
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package de.mm20.launcher2.ui.settings.unitconverter
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.search.UnitConverterSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -12,35 +12,17 @@ import org.koin.core.component.inject
|
|||||||
|
|
||||||
class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
|
class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val settings: UnitConverterSettings by inject()
|
||||||
|
|
||||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
|
val unitConverter = settings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setUnitConverter(unitConverter: Boolean) {
|
fun setUnitConverter(unitConverter: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setEnabled(unitConverter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setUnitConverterSearch(
|
|
||||||
it.unitConverterSearch.toBuilder()
|
|
||||||
.setEnabled(unitConverter)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val currencyConverter = dataStore.data.map { it.unitConverterSearch.currencies }
|
val currencyConverter = settings.currencies
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setCurrencyConverter(currencyConverter: Boolean) {
|
fun setCurrencyConverter(currencyConverter: Boolean) {
|
||||||
viewModelScope.launch {
|
settings.setCurrencies(currencyConverter)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setUnitConverterSearch(
|
|
||||||
it.unitConverterSearch.toBuilder()
|
|
||||||
.setCurrencies(currencyConverter)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,21 +1,29 @@
|
|||||||
package de.mm20.launcher2.ui.settings.weather
|
package de.mm20.launcher2.ui.settings.weather
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.Info
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||||
|
import de.mm20.launcher2.plugin.PluginState
|
||||||
import de.mm20.launcher2.ui.BuildConfig
|
import de.mm20.launcher2.ui.BuildConfig
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.common.WeatherLocationSearchDialog
|
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.MissingPermissionBanner
|
||||||
import de.mm20.launcher2.ui.component.preferences.*
|
import de.mm20.launcher2.ui.component.preferences.*
|
||||||
import de.mm20.launcher2.weather.WeatherLocation
|
|
||||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
import de.mm20.launcher2.weather.WeatherProviderInfo
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -25,12 +33,36 @@ fun WeatherIntegrationSettingsScreen() {
|
|||||||
|
|
||||||
val availableProviders by viewModel.availableProviders.collectAsState(emptyList())
|
val availableProviders by viewModel.availableProviders.collectAsState(emptyList())
|
||||||
|
|
||||||
|
val pluginState by viewModel.weatherProviderPluginState.collectAsStateWithLifecycle(
|
||||||
|
null,
|
||||||
|
minActiveState = Lifecycle.State.RESUMED
|
||||||
|
)
|
||||||
|
|
||||||
PreferenceScreen(
|
PreferenceScreen(
|
||||||
title = stringResource(R.string.preference_screen_weatherwidget),
|
title = stringResource(R.string.preference_screen_weatherwidget),
|
||||||
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/integrations/weather"
|
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/integrations/weather"
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
PreferenceCategory {
|
PreferenceCategory {
|
||||||
|
val state = pluginState?.state
|
||||||
|
if (state is PluginState.SetupRequired) {
|
||||||
|
Banner(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
text = state.message ?: stringResource(R.string.plugin_state_setup_required),
|
||||||
|
icon = Icons.Rounded.Info,
|
||||||
|
primaryAction = {
|
||||||
|
TextButton(onClick = {
|
||||||
|
try {
|
||||||
|
state.setupActivity.send()
|
||||||
|
} catch (e: PendingIntent.CanceledException) {
|
||||||
|
CrashReporter.logException(e)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text(stringResource(R.string.plugin_action_setup))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
val weatherProvider by viewModel.weatherProvider.collectAsState()
|
val weatherProvider by viewModel.weatherProvider.collectAsState()
|
||||||
ListPreference(
|
ListPreference(
|
||||||
title = stringResource(R.string.preference_weather_provider),
|
title = stringResource(R.string.preference_weather_provider),
|
||||||
|
|||||||
@ -1,20 +1,15 @@
|
|||||||
package de.mm20.launcher2.ui.settings.weather
|
package de.mm20.launcher2.ui.settings.weather
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.plugins.PluginService
|
||||||
import de.mm20.launcher2.weather.WeatherLocation
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
|
||||||
import de.mm20.launcher2.weather.WeatherRepository
|
import de.mm20.launcher2.weather.WeatherRepository
|
||||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@ -25,26 +20,24 @@ import org.koin.core.component.inject
|
|||||||
class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||||
private val repository: WeatherRepository by inject()
|
private val repository: WeatherRepository by inject()
|
||||||
private val weatherSettings: WeatherSettings by inject()
|
private val weatherSettings: WeatherSettings by inject()
|
||||||
|
private val pluginService: PluginService by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
|
||||||
|
|
||||||
val availableProviders = repository.getProviders()
|
val availableProviders = repository.getProviders()
|
||||||
|
|
||||||
val weatherProvider = weatherSettings.providerId
|
val weatherProvider = weatherSettings.providerId
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setWeatherProvider(provider: String) {
|
fun setWeatherProvider(provider: String) {
|
||||||
weatherSettings.setProviderId(provider)
|
weatherSettings.setProvider(provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
val weatherProviderPluginState = weatherProvider.flatMapLatest {
|
||||||
|
it?.let { pluginService.getPluginWithState(it) } ?: flowOf(null)
|
||||||
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
|
val imperialUnits = weatherSettings.imperialUnits
|
||||||
fun setImperialUnits(imperialUnits: Boolean) {
|
fun setImperialUnits(imperialUnits: Boolean) {
|
||||||
viewModelScope.launch {
|
weatherSettings.setImperialUnits(imperialUnits)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWeather(it.weather.toBuilder().setImperialUnits(imperialUnits))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val autoLocation = weatherSettings.autoLocation
|
val autoLocation = weatherSettings.autoLocation
|
||||||
|
|||||||
@ -24,20 +24,10 @@ fun WikipediaSettingsScreen() {
|
|||||||
viewModel.setWikipedia(it)
|
viewModel.setWikipedia(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val images by viewModel.images.collectAsState()
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_search_wikipedia_pictures),
|
|
||||||
summary = stringResource(R.string.preference_search_wikipedia_pictures_summary),
|
|
||||||
enabled = wikipedia == true,
|
|
||||||
value = images == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setImages(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val customUrl by viewModel.customUrl.collectAsState()
|
val customUrl by viewModel.customUrl.collectAsState()
|
||||||
TextPreference(
|
TextPreference(
|
||||||
title = stringResource(R.string.preference_wikipedia_customurl),
|
title = stringResource(R.string.preference_wikipedia_customurl),
|
||||||
value = customUrl,
|
value = customUrl ?: "",
|
||||||
placeholder = stringResource(id = R.string.wikipedia_url),
|
placeholder = stringResource(id = R.string.wikipedia_url),
|
||||||
summary = customUrl.takeIf { !it.isNullOrBlank() }
|
summary = customUrl.takeIf { !it.isNullOrBlank() }
|
||||||
?: stringResource(id = R.string.wikipedia_url),
|
?: stringResource(id = R.string.wikipedia_url),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package de.mm20.launcher2.ui.settings.wikipedia
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.search.WikipediaSearchSettings
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -11,50 +11,17 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
|
class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val wikipediaSearchSettings: WikipediaSearchSettings by inject()
|
||||||
|
|
||||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
|
val wikipedia = wikipediaSearchSettings.enabled
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
fun setWikipedia(wikipedia: Boolean) {
|
fun setWikipedia(wikipedia: Boolean) {
|
||||||
viewModelScope.launch {
|
wikipediaSearchSettings.setEnabled(wikipedia)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder()
|
|
||||||
.setEnabled(wikipedia)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val images = dataStore.data.map { it.wikipediaSearch.images }
|
val customUrl = wikipediaSearchSettings.customUrl
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
|
||||||
fun setImages(images: Boolean) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder()
|
|
||||||
.setImages(images)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val customUrl = dataStore.data.map { it.wikipediaSearch.customUrl }
|
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
|
||||||
fun setCustomUrl(customUrl: String) {
|
fun setCustomUrl(customUrl: String) {
|
||||||
viewModelScope.launch {
|
wikipediaSearchSettings.setCustomUrl(customUrl)
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setWikipediaSearch(
|
|
||||||
it.wikipediaSearch.toBuilder()
|
|
||||||
.setCustomUrl(customUrl)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,23 +1,18 @@
|
|||||||
package de.mm20.launcher2.ui.theme
|
package de.mm20.launcher2.ui.theme
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.shape.CornerSize
|
import androidx.compose.foundation.shape.CornerSize
|
||||||
import androidx.compose.foundation.shape.CutCornerShape
|
import androidx.compose.foundation.shape.CutCornerShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.coerceAtMost
|
import androidx.compose.ui.unit.coerceAtMost
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.Font
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.SurfaceShape
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.themes.DefaultThemeId
|
|
||||||
import de.mm20.launcher2.themes.Theme
|
|
||||||
import de.mm20.launcher2.themes.ThemeRepository
|
import de.mm20.launcher2.themes.ThemeRepository
|
||||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||||
import de.mm20.launcher2.ui.theme.colorscheme.*
|
import de.mm20.launcher2.ui.theme.colorscheme.*
|
||||||
@ -26,7 +21,7 @@ import de.mm20.launcher2.ui.theme.typography.getDeviceDefaultTypography
|
|||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.koin.androidx.compose.inject
|
import org.koin.androidx.compose.inject
|
||||||
import java.util.UUID
|
import de.mm20.launcher2.preferences.ColorScheme as ColorSchemePref
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -35,33 +30,31 @@ fun LauncherTheme(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val dataStore: LauncherDataStore by inject()
|
val uiSettings: UiSettings by inject()
|
||||||
val themeRepository: ThemeRepository by inject()
|
val themeRepository: ThemeRepository by inject()
|
||||||
|
|
||||||
val theme by remember {
|
val theme by remember {
|
||||||
dataStore.data.map {
|
uiSettings.theme.flatMapLatest {
|
||||||
it.appearance.themeId.takeIf { it.isNotEmpty() }?.let {
|
|
||||||
UUID.fromString(it)
|
|
||||||
}
|
|
||||||
}.flatMapLatest {
|
|
||||||
themeRepository.getThemeOrDefault(it)
|
themeRepository.getThemeOrDefault(it)
|
||||||
}
|
}
|
||||||
}.collectAsState(themeRepository.getDefaultTheme())
|
}.collectAsState(themeRepository.getDefaultTheme())
|
||||||
|
|
||||||
val themePreference by remember { dataStore.data.map { it.appearance.theme } }.collectAsState(
|
val colorSchemePref by remember { uiSettings.colorScheme }.collectAsState(
|
||||||
AppearanceSettings.Theme.System
|
ColorSchemePref.System
|
||||||
)
|
)
|
||||||
val darkTheme =
|
val darkTheme =
|
||||||
themePreference == AppearanceSettings.Theme.Dark || themePreference == AppearanceSettings.Theme.System && isSystemInDarkTheme()
|
colorSchemePref == ColorSchemePref.Dark || colorSchemePref == ColorSchemePref.System && isSystemInDarkTheme()
|
||||||
|
|
||||||
val cornerRadius by remember {
|
val cornerRadius by remember {
|
||||||
dataStore.data.map { it.cards.radius.dp }
|
uiSettings.cardStyle.map {
|
||||||
|
it.cornerRadius.dp
|
||||||
|
}
|
||||||
}.collectAsState(8.dp)
|
}.collectAsState(8.dp)
|
||||||
|
|
||||||
val baseShape by remember {
|
val baseShape by remember {
|
||||||
dataStore.data.map {
|
uiSettings.cardStyle.map {
|
||||||
when (it.cards.shape) {
|
when (it.shape) {
|
||||||
Settings.CardSettings.Shape.Cut -> CutCornerShape(0f)
|
SurfaceShape.Cut -> CutCornerShape(0f)
|
||||||
else -> RoundedCornerShape(0f)
|
else -> RoundedCornerShape(0f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,8 +66,8 @@ fun LauncherTheme(
|
|||||||
lightColorSchemeOf(theme)
|
lightColorSchemeOf(theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
val font by remember { dataStore.data.map { it.appearance.font } }.collectAsState(
|
val font by remember { uiSettings.font }.collectAsState(
|
||||||
AppearanceSettings.Font.Outfit
|
Font.Outfit
|
||||||
)
|
)
|
||||||
|
|
||||||
val typography = remember(font) {
|
val typography = remember(font) {
|
||||||
@ -99,9 +92,9 @@ fun LauncherTheme(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTypography(context: Context, font: AppearanceSettings.Font?): Typography {
|
fun getTypography(context: Context, font: Font?): Typography {
|
||||||
return when (font) {
|
return when (font) {
|
||||||
AppearanceSettings.Font.SystemDefault -> getDeviceDefaultTypography(context)
|
Font.System -> getDeviceDefaultTypography(context)
|
||||||
else -> DefaultTypography
|
else -> DefaultTypography
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,7 +11,8 @@ import androidx.compose.ui.graphics.toArgb
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.datastore.core.DataStore
|
import androidx.datastore.core.DataStore
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.LegacySettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
import de.mm20.launcher2.themes.CorePalette
|
import de.mm20.launcher2.themes.CorePalette
|
||||||
import de.mm20.launcher2.themes.DefaultDarkColorScheme
|
import de.mm20.launcher2.themes.DefaultDarkColorScheme
|
||||||
import de.mm20.launcher2.themes.DefaultLightColorScheme
|
import de.mm20.launcher2.themes.DefaultLightColorScheme
|
||||||
@ -23,6 +24,7 @@ import de.mm20.launcher2.themes.merge
|
|||||||
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
|
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.koin.androidx.compose.inject
|
import org.koin.androidx.compose.inject
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun lightColorSchemeOf(theme: Theme): ColorScheme {
|
fun lightColorSchemeOf(theme: Theme): ColorScheme {
|
||||||
@ -82,12 +84,12 @@ fun colorSchemeOf(colorScheme: FullColorScheme, corePalette: PartialCorePalette)
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun systemCorePalette(): CorePalette<Int> {
|
fun systemCorePalette(): CorePalette<Int> {
|
||||||
val dataStore: DataStore<Settings> by inject()
|
val uiSettings: UiSettings by inject()
|
||||||
val compatMode by remember {
|
val compatModeColors by remember {
|
||||||
dataStore.data.map { it.appearance.forceCompatModeSystemColors }
|
uiSettings.compatModeColors
|
||||||
}.collectAsState(false)
|
}.collectAsState(false)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 31 && !compatMode) {
|
if (Build.VERSION.SDK_INT >= 31 && !compatModeColors) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
return CorePalette(
|
return CorePalette(
|
||||||
primary = ContextCompat.getColor(context, android.R.color.system_accent1_500),
|
primary = ContextCompat.getColor(context, android.R.color.system_accent1_500),
|
||||||
@ -112,7 +114,7 @@ fun systemCorePalette(): CorePalette<Int> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CustomColorScheme(colors: Settings.AppearanceSettings.CustomColors.Scheme): ColorScheme {
|
fun CustomColorScheme(colors: LegacySettings.AppearanceSettings.CustomColors.Scheme): ColorScheme {
|
||||||
return ColorScheme(
|
return ColorScheme(
|
||||||
primary = Color(colors.primary),
|
primary = Color(colors.primary),
|
||||||
onPrimary = Color(colors.onPrimary),
|
onPrimary = Color(colors.onPrimary),
|
||||||
|
|||||||
@ -670,4 +670,11 @@
|
|||||||
<string name="plugin_host_not_installed">Hostitel doplňků není nainstalován</string>
|
<string name="plugin_host_not_installed">Hostitel doplňků není nainstalován</string>
|
||||||
<string name="preference_plugin_badges">Odznaky doplňků</string>
|
<string name="preference_plugin_badges">Odznaky doplňků</string>
|
||||||
<string name="preference_plugin_badges_summary">Zobrazit, který doplněk vytvořil výsledek vyhledávání</string>
|
<string name="preference_plugin_badges_summary">Zobrazit, který doplněk vytvořil výsledek vyhledávání</string>
|
||||||
|
<string name="plugin_state_setup_required">Nejprve musíte nastavit tento doplněk</string>
|
||||||
|
<string name="plugin_action_setup">Nastavit</string>
|
||||||
|
<string name="plugin_type_filesearch">Vyhledávání souborů</string>
|
||||||
|
<string name="plugin_type_weather">Poskytovatel počasí</string>
|
||||||
|
<string name="plugin_weather_provider_enable">Nastavit jako poskytovatele počasí</string>
|
||||||
|
<string name="plugin_weather_provider_enabled">Momentálně nastaven jako poskytovatel počasí</string>
|
||||||
|
<string name="plugin_state_error">Tento doplněk nefunguje tak, jak by měl</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -665,4 +665,11 @@
|
|||||||
<string name="preference_clockwidget_dynamic_zone">Dynamische Zone</string>
|
<string name="preference_clockwidget_dynamic_zone">Dynamische Zone</string>
|
||||||
<string name="preference_plugin_badges">Plugin-Plaketten</string>
|
<string name="preference_plugin_badges">Plugin-Plaketten</string>
|
||||||
<string name="preference_plugin_badges_summary">Anzeigen, von welchem Plugin ein Suchergebnis stammt</string>
|
<string name="preference_plugin_badges_summary">Anzeigen, von welchem Plugin ein Suchergebnis stammt</string>
|
||||||
|
<string name="plugin_action_setup">einrichten</string>
|
||||||
|
<string name="plugin_type_filesearch">Dateisuche</string>
|
||||||
|
<string name="plugin_type_weather">Wetterdienst</string>
|
||||||
|
<string name="plugin_weather_provider_enabled">Als Wetterdienst gesetzt</string>
|
||||||
|
<string name="plugin_state_error">Dieses Plugin funktioniert nicht wie erwartet</string>
|
||||||
|
<string name="plugin_state_setup_required">Sie müssen das Plugin zuerst einrichten</string>
|
||||||
|
<string name="plugin_weather_provider_enable">Als Wetterdienst nutzen</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="preference_search_bar_auto_focus_summary">Αυτόματη εμφάνιση του πληκτρολογίου κατά το άνοιγμα της αναζήτησης</string>
|
<string name="preference_search_bar_auto_focus_summary">Αυτόματη εμφάνιση του πληκτρολογίου κατά το άνοιγμα του μενού εφαρμογών</string>
|
||||||
<string name="menu_uninstall">Απεγκατάσταση</string>
|
<string name="menu_uninstall">Απεγκατάσταση</string>
|
||||||
<string name="menu_favorites_pin">Καρφίτσωμα στα αγαπημένα</string>
|
<string name="menu_favorites_pin">Καρφίτσωμα στα αγαπημένα</string>
|
||||||
<string name="menu_favorites_unpin">Ξεκαρφίτσωμα</string>
|
<string name="menu_favorites_unpin">Ξεκαρφίτσωμα</string>
|
||||||
@ -232,7 +232,7 @@
|
|||||||
<string name="preference_screen_clockwidget">Ρολόι</string>
|
<string name="preference_screen_clockwidget">Ρολόι</string>
|
||||||
<string name="preference_clockwidget_layout">Διάταξη</string>
|
<string name="preference_clockwidget_layout">Διάταξη</string>
|
||||||
<string name="preference_clockwidget_layout_vertical">Προεπιλογή</string>
|
<string name="preference_clockwidget_layout_vertical">Προεπιλογή</string>
|
||||||
<string name="preference_clockwidget_layout_horizontal">Συμπαγές</string>
|
<string name="preference_clockwidget_layout_horizontal">Συμπαγής</string>
|
||||||
<string name="preference_clock_widget_color">Χρώμα</string>
|
<string name="preference_clock_widget_color">Χρώμα</string>
|
||||||
<string name="preference_clock_widget_style">Στυλ</string>
|
<string name="preference_clock_widget_style">Στυλ</string>
|
||||||
<string name="preference_clock_widget_style_summary">Επιλογή ρολογιού</string>
|
<string name="preference_clock_widget_style_summary">Επιλογή ρολογιού</string>
|
||||||
@ -434,7 +434,7 @@
|
|||||||
<string name="preference_restore_summary">Εισαγωγή ενός αντιγράφου ασφαλείας που δημιουργήθηκε προηγουμένως</string>
|
<string name="preference_restore_summary">Εισαγωγή ενός αντιγράφου ασφαλείας που δημιουργήθηκε προηγουμένως</string>
|
||||||
<string name="preference_system_bar_icons_light">Φωτεινό</string>
|
<string name="preference_system_bar_icons_light">Φωτεινό</string>
|
||||||
<string name="preference_screen_weatherwidget">Καιρός</string>
|
<string name="preference_screen_weatherwidget">Καιρός</string>
|
||||||
<string name="preference_screen_search_summary">Παραμετροποίηση της αναζήτησης</string>
|
<string name="preference_screen_search_summary">Αναζήτηση, ετικέτες, κρυφά στοιχεία</string>
|
||||||
<string name="preference_hide_status_bar">Απόκρυψη γραμμής κατάστασης</string>
|
<string name="preference_hide_status_bar">Απόκρυψη γραμμής κατάστασης</string>
|
||||||
<string name="preference_clock_widget_fill_height">Γέμισμα ύψους οθόνης</string>
|
<string name="preference_clock_widget_fill_height">Γέμισμα ύψους οθόνης</string>
|
||||||
<string name="preference_search_favorites_summary">Εμφάνιση καρφιτσωμένων και συχνά χρησιμοποιούμενων στοιχείων πάνω από το πλέγμα εφαρμογών</string>
|
<string name="preference_search_favorites_summary">Εμφάνιση καρφιτσωμένων και συχνά χρησιμοποιούμενων στοιχείων πάνω από το πλέγμα εφαρμογών</string>
|
||||||
@ -459,7 +459,7 @@
|
|||||||
<string name="preference_wallpaper_summary">Επιλογή ταπετσαρίας</string>
|
<string name="preference_wallpaper_summary">Επιλογή ταπετσαρίας</string>
|
||||||
<string name="preference_clockwidget_alarm_part_summary">Εμφάνιση ξυπνητηριών που θα χτυπήσουν μέσα στα επόμενα 15 λεπτά</string>
|
<string name="preference_clockwidget_alarm_part_summary">Εμφάνιση ξυπνητηριών που θα χτυπήσουν μέσα στα επόμενα 15 λεπτά</string>
|
||||||
<string name="preference_search_contacts_summary">Αναζήτηση επαφών σε αυτή τη συσκευή</string>
|
<string name="preference_search_contacts_summary">Αναζήτηση επαφών σε αυτή τη συσκευή</string>
|
||||||
<string name="icon_picker_search_icon">Αναζήτηση εικονιδίου</string>
|
<string name="icon_picker_search_icon">Αναζήτηση σε πακέτα εικονιδίων</string>
|
||||||
<string name="shortcut_summary">Από %1$s</string>
|
<string name="shortcut_summary">Από %1$s</string>
|
||||||
<string name="preference_notification_badges_summary">Εμφάνιση σήματος για εφαρμογές με μη αναγνωσμένες ειδοποιήσεις</string>
|
<string name="preference_notification_badges_summary">Εμφάνιση σήματος για εφαρμογές με μη αναγνωσμένες ειδοποιήσεις</string>
|
||||||
<string name="preference_screen_backup_summary">Εξαγωγή και εισαγωγή δεδομένων εφαρμογής εκκίνησης</string>
|
<string name="preference_screen_backup_summary">Εξαγωγή και εισαγωγή δεδομένων εφαρμογής εκκίνησης</string>
|
||||||
@ -468,7 +468,7 @@
|
|||||||
<string name="missing_permission_appshortcuts_search_settings">Το %1$s πρέπει να οριστεί ως προεπιλεγμένη εφαρμογή αρχικής οθόνης για αναζήτηση συντομεύσεων εφαρμογών</string>
|
<string name="missing_permission_appshortcuts_search_settings">Το %1$s πρέπει να οριστεί ως προεπιλεγμένη εφαρμογή αρχικής οθόνης για αναζήτηση συντομεύσεων εφαρμογών</string>
|
||||||
<string name="preference_suspended_badges_summary">Εμφάνιση σήματος για εφαρμογές σε αναστολή</string>
|
<string name="preference_suspended_badges_summary">Εμφάνιση σήματος για εφαρμογές σε αναστολή</string>
|
||||||
<string name="preference_search_calculator">Αριθμομηχανή</string>
|
<string name="preference_search_calculator">Αριθμομηχανή</string>
|
||||||
<string name="backup_not_included">Δεν θα δημιουργηθούν αντίγραφα ασφαλείας για συνδεδεμένους λογαριασμούς και γραφικά στοιχεία τρίτων εφαρμογών.</string>
|
<string name="backup_not_included">Δε θα δημιουργηθούν αντίγραφα ασφαλείας για τους συνδεδεμένους λογαριασμούς. Τα γραφικά στοιχεία εφαρμογών τρίτων μπορούν να αποκατασταθούν μόνο σε αυτήν τη συσκευή.</string>
|
||||||
<string name="preference_cloud_badges">Σήματα αρχείων στο cloud</string>
|
<string name="preference_cloud_badges">Σήματα αρχείων στο cloud</string>
|
||||||
<string name="preference_search_currencyconverter_summary">Λήψη περιοδικών συναλλαγματικών ισοτιμιών για μετατροπή νομισμάτων</string>
|
<string name="preference_search_currencyconverter_summary">Λήψη περιοδικών συναλλαγματικών ισοτιμιών για μετατροπή νομισμάτων</string>
|
||||||
<string name="restore_invalid_file">Το επιλεγμένο αρχείο δεν φαίνεται να αποτελεί αντίγραφο ασφαλείας. Είστε σίγουροι ότι επιλέξατε το σωστό αρχείο;</string>
|
<string name="restore_invalid_file">Το επιλεγμένο αρχείο δεν φαίνεται να αποτελεί αντίγραφο ασφαλείας. Είστε σίγουροι ότι επιλέξατε το σωστό αρχείο;</string>
|
||||||
@ -492,4 +492,83 @@
|
|||||||
<string name="preference_logs_summary">Προβολή και εξαγωγή αρχείων καταγραφής</string>
|
<string name="preference_logs_summary">Προβολή και εξαγωγή αρχείων καταγραφής</string>
|
||||||
<string name="help">Βοήθεια</string>
|
<string name="help">Βοήθεια</string>
|
||||||
<string name="skip">Παράλειψη</string>
|
<string name="skip">Παράλειψη</string>
|
||||||
|
<string name="preference_hidden_items_reveal_button">Εμφάνιση κουμπιού αποκάλυψης</string>
|
||||||
|
<string name="preference_debug_dump_heap_summary">Τραβήξτε ένα στιγμιότυπο για να αναλύσετε τη χρήση μνήμης. Η εφαρμογή θα μπει σε αδράνεια μέχρι να ολοκληρωθεί αυτή η διαδικασία.</string>
|
||||||
|
<string name="preference_clock_widget_alignment_top">Πάνω</string>
|
||||||
|
<string name="preference_clock_widget_alignment_center">Κέντρο</string>
|
||||||
|
<string name="preference_clock_widget_alignment_bottom">Κάτω</string>
|
||||||
|
<string name="preference_clock_widget_alignment">Ευθυγράμμιση</string>
|
||||||
|
<string name="widget_name_notes">Ένα γραφικό στοιχείο που αποθηκεύει μία μόνο σημείωση</string>
|
||||||
|
<string name="search_action_message">Μήνυμα</string>
|
||||||
|
<string name="search_action_email">Email</string>
|
||||||
|
<string name="more_information">Περισσότερες πληροφορίες</string>
|
||||||
|
<string name="notes_widget_placeholder">Γράψε μια σημείωση…</string>
|
||||||
|
<string name="notes_widget_action_new">Νέα σημείωση</string>
|
||||||
|
<string name="notes_widget_export_filename">Σημείωση_%1$s</string>
|
||||||
|
<string name="notes_widget_action_dismiss">Απόρριψη</string>
|
||||||
|
<string name="notes_widget_action_save">Αποθήκευση</string>
|
||||||
|
<string name="preference_search_unitconverter_summary">Χρήση: 1,5 kg ή 4 cm >> σε</string>
|
||||||
|
<string name="preference_category_media_apps">Εφαρμογές πολυμέσων</string>
|
||||||
|
<string name="preference_screen_icons_summary">Πλέγμα, μέγεθος εικονιδίου, πακέτα εικονιδίων, σήματα</string>
|
||||||
|
<string name="preference_screen_search_actions">Γρήγορες ενέργειες</string>
|
||||||
|
<string name="preference_screen_clockwidget_summary">Διαμορφώστε το στυλ και τα στοιχεία του ρολογιού</string>
|
||||||
|
<string name="preference_debug_reinstall_iconpacks_summary">Εκκαθαρίστε και δημιουργήστε ξανά την προσωρινή μνήμη του πακέτου εικονιδίων</string>
|
||||||
|
<string name="preference_hidden_items_reveal_button_summary">Εμφάνιση ενός κουμπιού για την αποκάλυψη κρυφών αποτελεσμάτων αναζήτησης</string>
|
||||||
|
<string name="preference_search_search_actions_summary">Διαμορφώστε τις γρήγορες ενέργειες και τις συντομεύσεις αναζήτησης</string>
|
||||||
|
<string name="create_search_action_website_invalid_url">Ο συγκεκριμένος ιστότοπος δεν μπορεί να εισαχθεί αυτόματα ως αναζήτηση ιστού. Μπορείτε να δοκιμάσετε έναν διαφορετικό ιστότοπο ή να εισαγάγετε τα απαιτούμενα δεδομένα με μη αυτόματο τρόπο στο επόμενο βήμα.</string>
|
||||||
|
<string name="search_action_app">Εφαρμογή</string>
|
||||||
|
<string name="edit_search_action_title">Επεξεργασία γρήγορης δράσης</string>
|
||||||
|
<string name="create_search_action_website_url">Εισαγάγετε τη διεύθυνση του ιστότοπου:</string>
|
||||||
|
<string name="search_action_websearch_url_hint">Το πρότυπο URL που χρησιμοποιείται για τη δημιουργία της διεύθυνσης URL αναζήτησης ιστού. Χρησιμοποιήστε το \"${1}\" ως σύμβολο κράτησης θέσης για τον πραγματικό όρο αναζήτησης, π.χ. https://google.com/search?q=${1}.</string>
|
||||||
|
<string name="preference_plugin_badges">Σήματα προσθηκών</string>
|
||||||
|
<string name="preference_plugin_badges_summary">Υποδείξτε με ποια προσθήκη δημιουργήθηκε ένα αποτέλεσμα αναζήτησης</string>
|
||||||
|
<string name="preference_screen_tags_summary">Διαχείριση ετικετών και στοιχείων με ετικέτα</string>
|
||||||
|
<string name="backup_component_themes">Χρωματικοί συνδυασμοί</string>
|
||||||
|
<string name="edit">Επεξεργασία</string>
|
||||||
|
<string name="missing_permission_plugins">Απαιτείται άδεια προσθήκης για τη χρήση προσθηκών.</string>
|
||||||
|
<string name="widget_config_weather_compact">Συμπαγής λειτουργία</string>
|
||||||
|
<string name="preference_compact_mode_summary">Απόκρυψη ωριαίων και ημερήσιων προβλέψεων</string>
|
||||||
|
<string name="preference_debug_reinstall_iconpacks">Επανεγκατάσταση πακέτων εικονιδίων</string>
|
||||||
|
<string name="preference_screen_plugins">Πρόσθετα</string>
|
||||||
|
<string name="preference_screen_plugins_summary">Διαχείριση εγκατεστημένων επεκτάσεων</string>
|
||||||
|
<string name="no_plugins_installed">Δεν έχουν εγκατασταθεί πρόσθετα</string>
|
||||||
|
<string name="icon_pack_dynamic_colors">Δυναμικά χρώματα</string>
|
||||||
|
<string name="preference_blur_wallpaper_radius">Ακτίνα θολώματος</string>
|
||||||
|
<string name="preference_clockwidget_dynamic_zone">Μέρος του γραφικού στοιχείου ρολογιού που εμφανίζει δυναμικές πληροφορίες (ημερομηνία, αναπαραγωγήςμουσικής, μπαταρία,…)</string>
|
||||||
|
<string name="preference_screen_integrations">Ενσωματώσεις</string>
|
||||||
|
<string name="icon_picker_filter_all_packs">Όλα τα πακέτα εικονιδίων</string>
|
||||||
|
<string name="search_action_event">Προγραμματισμός εκδήλωσης</string>
|
||||||
|
<string name="create_search_action_type">Τι είδους δράση θέλετε να δημιουργήσετε;</string>
|
||||||
|
<string name="search_action_call">Κλήση</string>
|
||||||
|
<string name="preference_debug_dump_heap">Στιγμιότυπο μνήμης</string>
|
||||||
|
<string name="preference_debug_dump_heap_in_progress">Λήψη στιγμιότυπου…</string>
|
||||||
|
<string name="action_import">Εισαγωγή</string>
|
||||||
|
<string name="file_type_launchertheme">%1$s θέμα</string>
|
||||||
|
<string name="widget_name_unknown">Ετικέτα που χρησιμοποιείται για μη έγκυρα γραφικά στοιχεία εφαρμογών</string>
|
||||||
|
<string name="notes_widget_dismissed">Η σημείωση απορρίφθηκε.</string>
|
||||||
|
<string name="widget_action_replace">Αντικατάσταση</string>
|
||||||
|
<string name="widget_config_calendar_missing_calendars_hint">Δεν μπορείτε να βρείτε τα ημερολόγια σας;</string>
|
||||||
|
<string name="preference_screen_homescreen">Αρχική οθόνη</string>
|
||||||
|
<string name="preference_category_accounts">Λογαριασμοί</string>
|
||||||
|
<string name="preference_weather_integration">Καιρός</string>
|
||||||
|
<string name="preference_custom_colors_corepalette">Παλέτα χρωμάτων</string>
|
||||||
|
<string name="preference_screen_tags">Ετικέτες</string>
|
||||||
|
<string name="preference_screen_homescreen_summary">Ρολόι, γραμμή αναζήτησης, ταπετσαρία, γραμμές συστήματος</string>
|
||||||
|
<string name="preference_screen_icons">Πλέγμα και εικονίδια</string>
|
||||||
|
<string name="preference_media_integration">Έλεγχος πολυμέσων</string>
|
||||||
|
<string name="backup_component_searchactions">Γρήγορες ενέργειες</string>
|
||||||
|
<string name="icon_picker_no_packs_installed">Δεν έχουν εγκατασταθεί πακέτα εικονιδίων</string>
|
||||||
|
<string name="search_action_alarm">Βάζω ξυπνητήρι</string>
|
||||||
|
<string name="search_action_websearch">Διαδικτυακή αναζήτηση</string>
|
||||||
|
<string name="search_action_contact">Δημιουργία επαφής</string>
|
||||||
|
<string name="search_action_open_url">Προβολή ιστότοπου</string>
|
||||||
|
<string name="create_search_action_type_web">Αναζήτηση σε έναν ιστότοπο</string>
|
||||||
|
<string name="create_search_action_type_app">Αναζήτηση σε μία εφαρμογή</string>
|
||||||
|
<string name="create_search_action_type_intent">Προσαρμοσμένη πρόθεση</string>
|
||||||
|
<string name="create_search_action_title">Νέα γρήγορη δράση</string>
|
||||||
|
<string name="create_search_action_pick_app">Επιλέξτε μια εφαρμογή για αναζήτηση:</string>
|
||||||
|
<string name="search_action_label">Όνομα</string>
|
||||||
|
<string name="search_action_websearch_url">Πρότυπο URL</string>
|
||||||
|
<string name="experimental_feature">Πειραματικό</string>
|
||||||
|
<string name="create_tag_title">Νέα ετικέτα</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -261,4 +261,8 @@
|
|||||||
<item quantity="other">κοντοί τόνοι</item>
|
<item quantity="other">κοντοί τόνοι</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="unit_stone_symbol">st.</string>
|
<string name="unit_stone_symbol">st.</string>
|
||||||
|
<plurals name="unit_stone">
|
||||||
|
<item quantity="one">πέτρα</item>
|
||||||
|
<item quantity="other">πέτρες</item>
|
||||||
|
</plurals>
|
||||||
</resources>
|
</resources>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<string name="file_meta_artist">Artista: %1$s</string>
|
<string name="file_meta_artist">Artista: %1$s</string>
|
||||||
<string name="file_meta_album">Álbum: %1$s</string>
|
<string name="file_meta_album">Álbum: %1$s</string>
|
||||||
<string name="file_meta_duration">Duración: %1$s</string>
|
<string name="file_meta_duration">Duración: %1$s</string>
|
||||||
<string name="menu_share_store_link">%1$s link</string>
|
<string name="menu_share_store_link">Enlace de %1$s</string>
|
||||||
<string name="file_meta_year">Año: %1$s</string>
|
<string name="file_meta_year">Año: %1$s</string>
|
||||||
<string name="file_meta_size">Tamaño: %1$s</string>
|
<string name="file_meta_size">Tamaño: %1$s</string>
|
||||||
<string name="file_meta_path">Ruta: %1$s</string>
|
<string name="file_meta_path">Ruta: %1$s</string>
|
||||||
@ -151,7 +151,7 @@
|
|||||||
<string name="open_webpage">Abrir sitio web</string>
|
<string name="open_webpage">Abrir sitio web</string>
|
||||||
<string name="preference_screen_about_summary">Información de la aplicación y la licencia</string>
|
<string name="preference_screen_about_summary">Información de la aplicación y la licencia</string>
|
||||||
<string name="preference_weather_provider">Proveedor</string>
|
<string name="preference_weather_provider">Proveedor</string>
|
||||||
<string name="provider_here">AQUÍ</string>
|
<string name="provider_here">HERE</string>
|
||||||
<string name="preference_category_location">Ubicación</string>
|
<string name="preference_category_location">Ubicación</string>
|
||||||
<string name="preference_automatic_location">Ubicación automática</string>
|
<string name="preference_automatic_location">Ubicación automática</string>
|
||||||
<string name="preference_location">Ubicación</string>
|
<string name="preference_location">Ubicación</string>
|
||||||
@ -369,7 +369,7 @@
|
|||||||
<string name="restore_meta">Creado %1$s en %2$s con %3$s.</string>
|
<string name="restore_meta">Creado %1$s en %2$s con %3$s.</string>
|
||||||
<string name="restore_select_components">Seleccione que restaurar. ¡Los datos existentes van a ser sobrescritos!</string>
|
<string name="restore_select_components">Seleccione que restaurar. ¡Los datos existentes van a ser sobrescritos!</string>
|
||||||
<string name="icon_picker_default_icon">Por defecto</string>
|
<string name="icon_picker_default_icon">Por defecto</string>
|
||||||
<string name="icon_picker_search_icon">Buscar icono</string>
|
<string name="icon_picker_search_icon">Buscar en paquetes de iconos</string>
|
||||||
<string name="apps_profile_main">Personal</string>
|
<string name="apps_profile_main">Personal</string>
|
||||||
<string name="apps_profile_work">Trabajo</string>
|
<string name="apps_profile_work">Trabajo</string>
|
||||||
<string name="favorites_empty">Los elementos fijados y frecuentemente usados aparecerán aquí</string>
|
<string name="favorites_empty">Los elementos fijados y frecuentemente usados aparecerán aquí</string>
|
||||||
@ -406,7 +406,7 @@
|
|||||||
<item quantity="other">%1$d elementos seleccionados</item>
|
<item quantity="other">%1$d elementos seleccionados</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="preference_cloud_badges_summary">Mostrar insignia para archivos almacenados en la nube</string>
|
<string name="preference_cloud_badges_summary">Mostrar insignia para archivos almacenados en la nube</string>
|
||||||
<string name="preference_search_bar_auto_focus_summary">Mostrar el teclado automáticamente al abrir la búsqueda</string>
|
<string name="preference_search_bar_auto_focus_summary">Mostrar el teclado automáticamente al abrir la lista de aplicaciones</string>
|
||||||
<string name="preference_hidden_items_summary">Administrar aplicaciones y resultados de búsqueda ocultos</string>
|
<string name="preference_hidden_items_summary">Administrar aplicaciones y resultados de búsqueda ocultos</string>
|
||||||
<string name="preference_nextcloud">NextCloud</string>
|
<string name="preference_nextcloud">NextCloud</string>
|
||||||
<string name="preference_nextcloud_signin_summary">Registrate para buscar en tu servidor NextCloud</string>
|
<string name="preference_nextcloud_signin_summary">Registrate para buscar en tu servidor NextCloud</string>
|
||||||
@ -416,7 +416,7 @@
|
|||||||
<string name="preference_screen_debug_summary">Herramientas de solución de problemas</string>
|
<string name="preference_screen_debug_summary">Herramientas de solución de problemas</string>
|
||||||
<string name="backup_select_components">Selecciona componentes para hacer copia de seguridad:</string>
|
<string name="backup_select_components">Selecciona componentes para hacer copia de seguridad:</string>
|
||||||
<string name="preference_clockwidget_layout">Diseño</string>
|
<string name="preference_clockwidget_layout">Diseño</string>
|
||||||
<string name="backup_not_included">Las cuentas conectadas y aplicaciones de terceros no serán incluidas en la copia de seguridad.</string>
|
<string name="backup_not_included">Las cuentas conectadas no serán incluidas en la copia de seguridad. Los widgets de apps de terceros solo pueden ser restaurados en este dispositivo.</string>
|
||||||
<string name="preference_clockwidget_layout_vertical">Por defecto</string>
|
<string name="preference_clockwidget_layout_vertical">Por defecto</string>
|
||||||
<string name="restore_incompatible_file">Esta copia de seguridad se ha creado con una diferente versión de %1$s y no se puede restaurar con esta versión.</string>
|
<string name="restore_incompatible_file">Esta copia de seguridad se ha creado con una diferente versión de %1$s y no se puede restaurar con esta versión.</string>
|
||||||
<string name="preference_clock_widget_fill_height">Rellenar altura de pantalla</string>
|
<string name="preference_clock_widget_fill_height">Rellenar altura de pantalla</string>
|
||||||
@ -432,7 +432,7 @@
|
|||||||
<string name="preference_gesture_swipe_right">Deslizar hacia la derecha</string>
|
<string name="preference_gesture_swipe_right">Deslizar hacia la derecha</string>
|
||||||
<string name="preference_gesture_double_tap">Doble toque</string>
|
<string name="preference_gesture_double_tap">Doble toque</string>
|
||||||
<string name="preference_gesture_long_press">Pulsación larga</string>
|
<string name="preference_gesture_long_press">Pulsación larga</string>
|
||||||
<string name="gesture_action_none">Nada</string>
|
<string name="gesture_action_none">No hacer nada</string>
|
||||||
<string name="gesture_action_open_search">Abrir búsqueda</string>
|
<string name="gesture_action_open_search">Abrir búsqueda</string>
|
||||||
<string name="gesture_action_notifications">Abrir barra de notificaciones</string>
|
<string name="gesture_action_notifications">Abrir barra de notificaciones</string>
|
||||||
<string name="gesture_action_lock_screen">Apagar pantalla</string>
|
<string name="gesture_action_lock_screen">Apagar pantalla</string>
|
||||||
@ -608,7 +608,7 @@
|
|||||||
<string name="preference_hidden_items_reveal_button_summary">Mostrar un botón para revelar los resultados de búsqueda ocultos</string>
|
<string name="preference_hidden_items_reveal_button_summary">Mostrar un botón para revelar los resultados de búsqueda ocultos</string>
|
||||||
<string name="widget_config_calendar_no_calendars">Calendarios no encontrados</string>
|
<string name="widget_config_calendar_no_calendars">Calendarios no encontrados</string>
|
||||||
<string name="preference_search_result_ordering">Orden de resultados de búsqueda</string>
|
<string name="preference_search_result_ordering">Orden de resultados de búsqueda</string>
|
||||||
<string name="app_widget_loading_failed">El widget de la aplicación a fallado en cargar.</string>
|
<string name="app_widget_loading_failed">El widget de la aplicación ha fallado en cargar.</string>
|
||||||
<string name="note_widget_conflict_description">El archivo vinculado no está vacío y su contenido no coincide con la última versión guardada de esta nota. ¿Qué versión desea conservar\?</string>
|
<string name="note_widget_conflict_description">El archivo vinculado no está vacío y su contenido no coincide con la última versión guardada de esta nota. ¿Qué versión desea conservar\?</string>
|
||||||
<string name="note_widget_file_read_error_description">No se ha podido leer el archivo vinculado. Posiblemente, haya sido movido o borrado. Se ha restaurado una copia desde el almacenamiento interno del lanzador. Si editas la nota, posiblemente se sobrescribirá el archivo vinculado.</string>
|
<string name="note_widget_file_read_error_description">No se ha podido leer el archivo vinculado. Posiblemente, haya sido movido o borrado. Se ha restaurado una copia desde el almacenamiento interno del lanzador. Si editas la nota, posiblemente se sobrescribirá el archivo vinculado.</string>
|
||||||
<string name="preference_category_accounts">Cuentas</string>
|
<string name="preference_category_accounts">Cuentas</string>
|
||||||
@ -634,4 +634,40 @@
|
|||||||
<string name="note_widget_file_read_error">Error al leer la nota</string>
|
<string name="note_widget_file_read_error">Error al leer la nota</string>
|
||||||
<string name="note_widget_file_write_error">Error al guardar la nota</string>
|
<string name="note_widget_file_write_error">Error al guardar la nota</string>
|
||||||
<string name="note_widget_file_write_error_description">No se ha podido leer el archivo vinculado. Posiblemente, haya sido movido o borrado. Se ha restaurado una copia desde el almacenamiento interno del lanzador. Si editas la nota, posiblemente se sobrescribirá el archivo vinculado.</string>
|
<string name="note_widget_file_write_error_description">No se ha podido leer el archivo vinculado. Posiblemente, haya sido movido o borrado. Se ha restaurado una copia desde el almacenamiento interno del lanzador. Si editas la nota, posiblemente se sobrescribirá el archivo vinculado.</string>
|
||||||
|
<string name="file_type_launchertheme">Tema de %1$s</string>
|
||||||
|
<string name="preference_debug_dump_heap_summary">Captura una instantánea para analizar el uso de memoria. La app se congelará hasta que el proceso se complete.</string>
|
||||||
|
<string name="theme_color_scheme_system_default">Usar el predeterminado del sistema</string>
|
||||||
|
<string name="preference_clock_widget_alignment">Alineación</string>
|
||||||
|
<string name="preference_restore_default">Restaurar predeterminado</string>
|
||||||
|
<string name="search_action_websearch">Búsqueda web</string>
|
||||||
|
<string name="confirmation_delete_color_scheme">¿Realmente deseas eliminar el esquema de colores %1$s?</string>
|
||||||
|
<string name="import_theme_error">El archivo seleccionado no pudo ser leído. Asegúrate de que has seleccionado un archivo de tema válido (*.kvtheme), y que el archivo no esté dañado.</string>
|
||||||
|
<string name="preference_clock_widget_alignment_bottom">Inferior</string>
|
||||||
|
<string name="preference_plugin_badges">Insignias de plugin</string>
|
||||||
|
<string name="preference_plugin_badges_summary">Indica con qué plugin se creó un resultado de búsqueda</string>
|
||||||
|
<string name="preference_clock_widget_alignment_center">Centro</string>
|
||||||
|
<string name="backup_component_themes">Esquemas de color</string>
|
||||||
|
<string name="edit">Editar</string>
|
||||||
|
<string name="missing_permission_plugins">El permiso de plugin es requerido para usar plugins.</string>
|
||||||
|
<string name="preference_screen_plugins">Plugins</string>
|
||||||
|
<string name="preference_screen_plugins_summary">Administrar extensiones instaladas</string>
|
||||||
|
<string name="no_plugins_installed">Sin plugins instalados</string>
|
||||||
|
<string name="plugin_host_not_installed">Host de plugins no instalado</string>
|
||||||
|
<string name="preference_category_animations">Animaciones</string>
|
||||||
|
<string name="preference_charging_animation">Animación de carga</string>
|
||||||
|
<string name="preference_charging_animation_summary">Reproduce una animación de burbujas mientras el dispositivo está cargando</string>
|
||||||
|
<string name="preference_debug_dump_heap">Instantánea de memoria</string>
|
||||||
|
<string name="preference_debug_dump_heap_in_progress">Capturando instantánea…</string>
|
||||||
|
<string name="preference_clockwidget_dynamic_zone">Zona dinámica</string>
|
||||||
|
<string name="preference_blur_wallpaper_radius">Radio de desenfoque</string>
|
||||||
|
<string name="preference_custom_colors_corepalette">Paleta de colores</string>
|
||||||
|
<string name="theme_color_scheme_custom_color">Personalizado</string>
|
||||||
|
<string name="action_import">Importar</string>
|
||||||
|
<string name="preference_clock_widget_alignment_top">Superior</string>
|
||||||
|
<string name="new_color_scheme_name">Nuevo esquema de colores</string>
|
||||||
|
<string name="theme_color_scheme_autogenerate">A partir de color primario</string>
|
||||||
|
<string name="theme_color_scheme_palette_color">Paleta</string>
|
||||||
|
<string name="import_theme_apply">Aplicar tema</string>
|
||||||
|
<string name="shortcut_label_unavailable">No disponible</string>
|
||||||
|
<string name="shortcut_unavailable_description">Este acceso directo no está disponible porque %1$s no es el lanzador predeterminado</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -698,4 +698,13 @@
|
|||||||
<string name="preference_clockwidget_dynamic_zone">Zone dynamique</string>
|
<string name="preference_clockwidget_dynamic_zone">Zone dynamique</string>
|
||||||
<string name="plugin_host_not_installed">Hôte du plugin non installé</string>
|
<string name="plugin_host_not_installed">Hôte du plugin non installé</string>
|
||||||
<string name="preference_blur_wallpaper_radius">Rayon de flou</string>
|
<string name="preference_blur_wallpaper_radius">Rayon de flou</string>
|
||||||
|
<string name="plugin_state_setup_required">Vous devez d\'abord configurer ce plugin</string>
|
||||||
|
<string name="plugin_action_setup">Configuration</string>
|
||||||
|
<string name="plugin_type_filesearch">Recherche de fichier</string>
|
||||||
|
<string name="plugin_type_weather">Provisionneur de météo</string>
|
||||||
|
<string name="plugin_weather_provider_enable">Définir en tant que provisionneur météo</string>
|
||||||
|
<string name="plugin_weather_provider_enabled">Actuellement défini en tant que provisionneur météo</string>
|
||||||
|
<string name="plugin_state_error">Ce plugin ne fonctionne pas correctement</string>
|
||||||
|
<string name="preference_plugin_badges">Insignes de plugin</string>
|
||||||
|
<string name="preference_plugin_badges_summary">Indique par quel plugin un résultat de recherche a été créé</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -24,8 +24,8 @@
|
|||||||
<string name="menu_share_store_link">%1$s hivatkozás</string>
|
<string name="menu_share_store_link">%1$s hivatkozás</string>
|
||||||
<string name="menu_open_file">Megnyitás</string>
|
<string name="menu_open_file">Megnyitás</string>
|
||||||
<string name="menu_calendar_open_externally">Megnyitás a naptár alkalmazásban</string>
|
<string name="menu_calendar_open_externally">Megnyitás a naptár alkalmazásban</string>
|
||||||
<string name="wind_north">észak</string>
|
<string name="wind_north">Észak</string>
|
||||||
<string name="wind_north_east">északkelet</string>
|
<string name="wind_north_east">Északkelet</string>
|
||||||
<string name="wikipedia_source">Forrás: Wikipedia</string>
|
<string name="wikipedia_source">Forrás: Wikipedia</string>
|
||||||
<string name="file_meta_title">Cím: %1$s</string>
|
<string name="file_meta_title">Cím: %1$s</string>
|
||||||
<string name="file_meta_artist">Előadó: %1$s</string>
|
<string name="file_meta_artist">Előadó: %1$s</string>
|
||||||
@ -55,9 +55,9 @@
|
|||||||
<string name="file_type_ebook">E-book</string>
|
<string name="file_type_ebook">E-book</string>
|
||||||
<string name="file_type_drawing">Rajz</string>
|
<string name="file_type_drawing">Rajz</string>
|
||||||
<string name="file_type_generic">%1$s fájl</string>
|
<string name="file_type_generic">%1$s fájl</string>
|
||||||
<string name="alert_delete_file">A(z) %1$s fájl véglegesen törlve lesz. Folytassa\?</string>
|
<string name="alert_delete_file">A(z) %1$s fájl véglegesen törlve lesz. Folytatod?</string>
|
||||||
<string name="alert_delete_shortcut">A(z) %1$s parancsikon véglegesen törölve lesz. Folytassa\?</string>
|
<string name="alert_delete_shortcut">A(z) %1$s parancsikon véglegesen törölve lesz. Folytatod?</string>
|
||||||
<string name="error_activity_not_found">Nem sikerült a(z) %1$s megnyitása</string>
|
<string name="error_activity_not_found">Nem sikerült megnyitni a(z) %1$s-t</string>
|
||||||
<string name="default_websearch_1_url">https://google.com/search\?q=${1}</string>
|
<string name="default_websearch_1_url">https://google.com/search\?q=${1}</string>
|
||||||
<string name="default_websearch_3_url">https://play.google.com/store/search\?q=${1}</string>
|
<string name="default_websearch_3_url">https://play.google.com/store/search\?q=${1}</string>
|
||||||
<string name="websearch_dialog_create_title">Internetes keresés hozzáadása</string>
|
<string name="websearch_dialog_create_title">Internetes keresés hozzáadása</string>
|
||||||
@ -72,7 +72,7 @@
|
|||||||
<string name="widget_name_music">Zene</string>
|
<string name="widget_name_music">Zene</string>
|
||||||
<string name="widget_name_favorites">Kedvencek</string>
|
<string name="widget_name_favorites">Kedvencek</string>
|
||||||
<string name="widget_add_widget">Widget hozzáadása</string>
|
<string name="widget_add_widget">Widget hozzáadása</string>
|
||||||
<string name="shortcut_summary">Készítő: %1$s</string>
|
<string name="shortcut_summary">Készítette: %1$s</string>
|
||||||
<string name="installation_in_progress">Telepítés folyamatban... (%1$s)</string>
|
<string name="installation_in_progress">Telepítés folyamatban... (%1$s)</string>
|
||||||
<string name="duplicate">Másolat készítése</string>
|
<string name="duplicate">Másolat készítése</string>
|
||||||
<string name="skip">Kihagyás</string>
|
<string name="skip">Kihagyás</string>
|
||||||
@ -87,7 +87,7 @@
|
|||||||
<string name="file_type_presentation">Prezentáció</string>
|
<string name="file_type_presentation">Prezentáció</string>
|
||||||
<string name="file_type_form">Űrlap</string>
|
<string name="file_type_form">Űrlap</string>
|
||||||
<string name="file_type_launcherbackup">%1$s biztonsági mentés</string>
|
<string name="file_type_launcherbackup">%1$s biztonsági mentés</string>
|
||||||
<string name="alert_delete_directory">A(z) %1$s könyvtár és annak összes tartalma véglegesen törlődik. Folytassa\?</string>
|
<string name="alert_delete_directory">A(z) %1$s könyvtár és annak összes tartalma véglegesen törlődik. Folytatod?</string>
|
||||||
<string name="default_websearch_1_name">Google</string>
|
<string name="default_websearch_1_name">Google</string>
|
||||||
<string name="default_websearch_2_name">YouTube</string>
|
<string name="default_websearch_2_name">YouTube</string>
|
||||||
<string name="default_websearch_2_url">https://www.youtube.com/results\?search_query=${1}</string>
|
<string name="default_websearch_2_url">https://www.youtube.com/results\?search_query=${1}</string>
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<string name="websearch_dialog_import_url">Importálás URL-címről</string>
|
<string name="websearch_dialog_import_url">Importálás URL-címről</string>
|
||||||
<string name="widget_name_weather">Időjárás</string>
|
<string name="widget_name_weather">Időjárás</string>
|
||||||
<string name="widget_add_external">Továbbiak</string>
|
<string name="widget_add_external">Továbbiak</string>
|
||||||
<string name="easter_egg_1">Itt nincsenek húsvéti tojások, hacsak nem hoztál magaddal.</string>
|
<string name="easter_egg_1">Itt nincsenek Easter Egg-ek, hacsak nem hoztál magaddal.</string>
|
||||||
<string name="close">Bezárás</string>
|
<string name="close">Bezárás</string>
|
||||||
<string name="action_continue">Tovább</string>
|
<string name="action_continue">Tovább</string>
|
||||||
<string name="widget_action_settings">Beállítások</string>
|
<string name="widget_action_settings">Beállítások</string>
|
||||||
@ -124,25 +124,25 @@
|
|||||||
<string name="calendar_widget_no_events">Ma nincsenek események</string>
|
<string name="calendar_widget_no_events">Ma nincsenek események</string>
|
||||||
<string name="date_tomorrow">Holnap</string>
|
<string name="date_tomorrow">Holnap</string>
|
||||||
<string name="calendar_event_allday">egész nap</string>
|
<string name="calendar_event_allday">egész nap</string>
|
||||||
<string name="music_widget_default_title">%1$s médiát játszik</string>
|
<string name="music_widget_default_title">A(z) %1$s médiát játszik le</string>
|
||||||
<string name="weather_condition_lightsnowshowers">Könnyű hózáporok</string>
|
<string name="weather_condition_lightsnowshowers">Enyhe hó záporok</string>
|
||||||
<string name="widget_name_notes">Jegyzet</string>
|
<string name="widget_name_notes">Jegyzet</string>
|
||||||
<string name="easter_egg_2">Kérem, hagyja abba, csak az idejét vesztegeti</string>
|
<string name="easter_egg_2">Kérlek, hagyd abba, csak az idődet vesztegeted</string>
|
||||||
<string name="edit_favorites_dialog_pinned_sorted">Kitűzött - kézzel rendezett</string>
|
<string name="edit_favorites_dialog_pinned_sorted">Kitűzött - kézzel rendezett</string>
|
||||||
<string name="edit_favorites_dialog_new_tag">Címke készítése…</string>
|
<string name="edit_favorites_dialog_new_tag">Címke készítése…</string>
|
||||||
<string name="nextcloud_server_url">Nextcloud szerver URL</string>
|
<string name="nextcloud_server_url">Nextcloud szerver URL</string>
|
||||||
<string name="edit_favorites_dialog_tag_section_empty">A kitűzött címkék itt jelennek meg</string>
|
<string name="edit_favorites_dialog_tag_section_empty">A kitűzött címkék itt jelennek meg</string>
|
||||||
<string name="owncloud_username">Felhasználónév</string>
|
<string name="owncloud_username">Felhasználónév</string>
|
||||||
<string name="owncloud_login_2fa_hint">Ha engedélyezte a kétfaktoros hitelesítést, akkor itt egy alkalmazásjelszót kell használnia.</string>
|
<string name="owncloud_login_2fa_hint">Ha engedélyezted a kétfaktoros hitelesítést, akkor itt egy alkalmazásjelszót kell használnod.</string>
|
||||||
<string name="owncloud_login_failed">A bejelentkezés sikertelen: helytelen felhasználónév vagy jelszó.</string>
|
<string name="owncloud_login_failed">A bejelentkezés sikertelen: helytelen felhasználónév vagy jelszó.</string>
|
||||||
<string name="owncloud_server_url">Owncloud szerver URL</string>
|
<string name="owncloud_server_url">Owncloud szerver URL</string>
|
||||||
<string name="calendar_widget_pinned_events">Közelgő</string>
|
<string name="calendar_widget_pinned_events">Közelgő</string>
|
||||||
<string name="calendar_widget_next_events">Következő esemény</string>
|
<string name="calendar_widget_next_events">Következő esemény</string>
|
||||||
<string name="unit_converter_show_all">Mindent mutat</string>
|
<string name="unit_converter_show_all">Mindent mutat</string>
|
||||||
<string name="date_today">Ma</string>
|
<string name="date_today">Ma</string>
|
||||||
<string name="weather_condition_lightrain">Gyenge esőzés</string>
|
<string name="weather_condition_lightrain">Enyhe eső</string>
|
||||||
<string name="weather_condition_lightrainshowers">Enyhe záporok</string>
|
<string name="weather_condition_lightrainshowers">Enyhe eső záporok</string>
|
||||||
<string name="weather_condition_lightsnowandthunder">Könnyű havazás és mennydörgés</string>
|
<string name="weather_condition_lightsnowandthunder">Enyhe havazás és mennydörgés</string>
|
||||||
<string name="notes_widget_action_new">Új jegyzet</string>
|
<string name="notes_widget_action_new">Új jegyzet</string>
|
||||||
<string name="notes_widget_action_save">Mentés</string>
|
<string name="notes_widget_action_save">Mentés</string>
|
||||||
<string name="notes_widget_placeholder">Írj egy jegyzetet…</string>
|
<string name="notes_widget_placeholder">Írj egy jegyzetet…</string>
|
||||||
@ -151,7 +151,7 @@
|
|||||||
<string name="notes_widget_dismissed">Jegyzet elvetve.</string>
|
<string name="notes_widget_dismissed">Jegyzet elvetve.</string>
|
||||||
<string name="nextcloud_server_invalid_url">Ez az URL nem egy érvényes Nextcloud telepítésre mutat</string>
|
<string name="nextcloud_server_invalid_url">Ez az URL nem egy érvényes Nextcloud telepítésre mutat</string>
|
||||||
<string name="widget_name_unknown">Ismeretlen alkalmazás modul</string>
|
<string name="widget_name_unknown">Ismeretlen alkalmazás modul</string>
|
||||||
<string name="easter_egg_3">Nem mondom még egyszer: itt egyáltalán nincsenek elrejtett easter egg-ek</string>
|
<string name="easter_egg_3">Nem mondom még egyszer: itt egyáltalán nincsenek elrejtett Easter Egg-ek</string>
|
||||||
<string name="widget_action_replace">Csere</string>
|
<string name="widget_action_replace">Csere</string>
|
||||||
<string name="disclaimer">Jogi nyilatkozat</string>
|
<string name="disclaimer">Jogi nyilatkozat</string>
|
||||||
<string name="edit_favorites_dialog_tags">Címkék</string>
|
<string name="edit_favorites_dialog_tags">Címkék</string>
|
||||||
@ -161,7 +161,7 @@
|
|||||||
<item quantity="other">+%1$d folyamatban lévő esemény az elmúlt napokból</item>
|
<item quantity="other">+%1$d folyamatban lévő esemény az elmúlt napokból</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="edit">Szerkesztés</string>
|
<string name="edit">Szerkesztés</string>
|
||||||
<string name="edit_favorites_dialog_empty_section">Húzza ide az elemeket</string>
|
<string name="edit_favorites_dialog_empty_section">Húzd ide az elemeket</string>
|
||||||
<string name="calendar_widget_open_app">Naptár alkalmazás megnyitása</string>
|
<string name="calendar_widget_open_app">Naptár alkalmazás megnyitása</string>
|
||||||
<string name="action_import">Importálás</string>
|
<string name="action_import">Importálás</string>
|
||||||
<string name="wind_east">Kelet</string>
|
<string name="wind_east">Kelet</string>
|
||||||
@ -176,10 +176,500 @@
|
|||||||
\nUtoljára frissítve: %1$s</string>
|
\nUtoljára frissítve: %1$s</string>
|
||||||
<string name="calendar_widget_new_event">Új esemény</string>
|
<string name="calendar_widget_new_event">Új esemény</string>
|
||||||
<string name="music_widget_no_data">Még nem játszottak le médiát</string>
|
<string name="music_widget_no_data">Még nem játszottak le médiát</string>
|
||||||
<string name="weather_condition_sleetshowers">Havas eső</string>
|
<string name="weather_condition_sleetshowers">Havas eső záporok</string>
|
||||||
<string name="weather_condition_heavysleet">Erős havas eső</string>
|
<string name="weather_condition_heavysleet">Heves havas eső</string>
|
||||||
<string name="weather_condition_heavyrain">Heves esőzés</string>
|
<string name="weather_condition_heavyrain">Heves eső</string>
|
||||||
<string name="weather_condition_lightrainshowersandthunder">Enyhe záporok és mennydörgés</string>
|
<string name="weather_condition_lightrainshowersandthunder">Enyhe eső záporok és mennydörgés</string>
|
||||||
<string name="weather_condition_lightsnow">Gyenge havazás</string>
|
<string name="weather_condition_lightsnow">Enyhe havazás</string>
|
||||||
<string name="weather_condition_heavysleetshowersandthunder">Erős havas eső és mennydörgés</string>
|
<string name="weather_condition_heavysleetshowersandthunder">Heves havas eső záporok és mennydörgés</string>
|
||||||
|
<string name="file_type_launchertheme">%1$s téma</string>
|
||||||
|
<string name="preference_charging_animation">Töltés animáció</string>
|
||||||
|
<string name="file_meta_dimensions">Méretek: %1$s</string>
|
||||||
|
<string name="websearch_dialog_url_description">A \'${1}\' helyőrzőbe a tényleges keresési kifejezés kerül.</string>
|
||||||
|
<string name="websearch_dialog_url_error">A \'${1}\' helyőrző hiányzik ebből az URL-címből</string>
|
||||||
|
<string name="websearch_dialog_query_encoding_form">application/x-www-form-urlencoded</string>
|
||||||
|
<string name="weather_condition_snow">Hó</string>
|
||||||
|
<string name="weather_condition_lightrainandthunder">Enyhe eső és mennydörgés</string>
|
||||||
|
<string name="weather_condition_sleetandthunder">Havas eső és mennydörgés</string>
|
||||||
|
<string name="weather_condition_lightssnowshowersandthunder">Enyhe hó záporok és mennydörgés</string>
|
||||||
|
<string name="weather_condition_fair">Kellemes</string>
|
||||||
|
<string name="weather_condition_rainshowers">Eső záporok</string>
|
||||||
|
<string name="weather_condition_heavysnowandthunder">Heves havazás és mennydörgés</string>
|
||||||
|
<string name="weather_widget_set_location">Hely kiválasztása</string>
|
||||||
|
<string name="weather_location_search_no_result">A hely nem található.</string>
|
||||||
|
<string name="missing_permission_appshortcuts_search">Állítsd be a(z) %1$s alkalmazást alapértelmezett kezdőlapként az alkalmazások parancsikonjainak kereséséhez.</string>
|
||||||
|
<string name="preference_colors_default">Alapértelmezett</string>
|
||||||
|
<string name="missing_permission_plugins">A bővítmények használatához bővítményengedély szükséges.</string>
|
||||||
|
<string name="preference_custom_colors_simple_mode">Egyszerű mód</string>
|
||||||
|
<string name="preference_force_themed_icons">Témázott ikonok kényszerítése</string>
|
||||||
|
<string name="preference_compact_mode_summary">Óránkénti és napi előrejelzések elrejtése</string>
|
||||||
|
<string name="missing_permission_music_widget">A médialejátszás vezérléséhez értesítési hozzáférés szükséges</string>
|
||||||
|
<string name="missing_permission_calendar_search">A naptárban való kereséshez szükséges a naptárhoz való hozzáférés engedélyezése.</string>
|
||||||
|
<string name="preference_debug_dump_heap_summary">Pillanatfelvétel készítése a memóriahasználat elemzéséhez. Az alkalmazás lefagy, amíg ez a folyamat be nem fejeződik.</string>
|
||||||
|
<string name="preference_debug_cleanup_database_summary">Törölt és nem használt bejegyzések eltávolítása az indító adatbázisból</string>
|
||||||
|
<plurals name="debug_cleanup_database_result">
|
||||||
|
<item quantity="one">%1$d bejegyzés törölve</item>
|
||||||
|
<item quantity="other">%1$d bejegyzés törölve</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="preference_screen_integrations_summary">Csatlakoztatott fiókok és szolgáltatások kezelése</string>
|
||||||
|
<string name="missing_permission_calendar_widget">Adj engedélyt a naptárnak a közelgő találkozók és események megjelenítéséhez.</string>
|
||||||
|
<string name="weather_condition_heavysnowshowers">Heves hó záporok</string>
|
||||||
|
<string name="preference_colors_bw">Fekete-fehér</string>
|
||||||
|
<string name="preference_custom_colors_advanced_mode">Haladó mód</string>
|
||||||
|
<string name="preference_force_themed_icons_summary">Az alkalmazás színsémájának alkalmazása az összes ikonra, beleértve a nem támogatottakat is (nem ajánlott)</string>
|
||||||
|
<string name="weather_condition_cloudy">Felhős</string>
|
||||||
|
<string name="weather_condition_hail">Jégeső</string>
|
||||||
|
<string name="weather_condition_thunder">Zivatar</string>
|
||||||
|
<string name="weather_condition_snowshowersandthunder">Hó záporok és mennydörgés</string>
|
||||||
|
<string name="weather_condition_lightssleetshowersandthunder">Enyhe havas eső záporok és mennydörgés</string>
|
||||||
|
<string name="preference_screen_colors">Színösszeállítás</string>
|
||||||
|
<string name="weather_condition_wind">Szél</string>
|
||||||
|
<string name="weather_condition_snowshowers">Hó záporok</string>
|
||||||
|
<string name="weather_condition_heavyrainandthunder">Heves eső és mennydörgés</string>
|
||||||
|
<string name="missing_permission_calendar_widget_settings">Ehhez a widgethez naptár-engedély szükséges</string>
|
||||||
|
<string name="missing_permission_appshortcuts_search_settings">A(z) %1$s-t alapértelmezett kezdőlapként kell beállítani az alkalmazások parancsikonjainak kereséséhez</string>
|
||||||
|
<string name="missing_permission_notification_badges">Az értesítési jelvények megjelenítéséhez értesítési hozzáférés szükséges</string>
|
||||||
|
<string name="preference_category_licenses">Nyílt forráskódú licencek</string>
|
||||||
|
<string name="preference_icon_shape_hexagon">Hatszög</string>
|
||||||
|
<string name="preference_category_searchbar">Keresés sáv</string>
|
||||||
|
<string name="missing_permission_file_search_settings">A helyi fájlok kereséséhez, tárhely engedélyre van szükség</string>
|
||||||
|
<string name="widget_config_calendar_missing_calendars_hint">Nem találod a naptárakat?</string>
|
||||||
|
<string name="missing_permission_file_search_settings_android10">A helyi fájlok kereséséhez, összes fájl kezelése engedélyre van szükség</string>
|
||||||
|
<string name="missing_permission_contact_search">A névjegyek kereséséhez névjegy hozzáférésre van szükség.</string>
|
||||||
|
<string name="preference_category_debug">Hibakeresés</string>
|
||||||
|
<string name="preference_category_debug_tools">Eszközök</string>
|
||||||
|
<string name="preference_category_custom_colors_dark">Sötét színséma</string>
|
||||||
|
<string name="preference_cards_summary">A kártyák megjelenésének testreszabása</string>
|
||||||
|
<string name="preference_font">Betűtípus</string>
|
||||||
|
<string name="preference_font_system">Rendszer alapértelmezett</string>
|
||||||
|
<string name="preference_screen_about">Rólunk</string>
|
||||||
|
<string name="weather_condition_snowandthunder">Havazás és mennydörgés</string>
|
||||||
|
<string name="weather_condition_clearsky">Tiszta ég</string>
|
||||||
|
<string name="weather_condition_heavysleetshowers">Heves havas eső záporok</string>
|
||||||
|
<string name="weather_condition_heavysnow">Heves havazás</string>
|
||||||
|
<string name="weather_condition_fog">Köd</string>
|
||||||
|
<string name="weather_condition_rainandthunder">Eső és mennydörgés</string>
|
||||||
|
<string name="weather_condition_sleetshowersandthunder">Havas eső záporok és mennydörgés</string>
|
||||||
|
<string name="weather_details_humidity">Páratartalom: %1$s</string>
|
||||||
|
<string name="weather_condition_rainshowersandthunder">Eső záporok és mennydörgés</string>
|
||||||
|
<string name="weather_condition_heavyrainshowers">Heves eső záporok</string>
|
||||||
|
<string name="preference_version">Verzió</string>
|
||||||
|
<string name="preference_category_system_bars">Rendszer sávok</string>
|
||||||
|
<string name="preference_layout">Elrendezés</string>
|
||||||
|
<string name="preference_theme">Téma</string>
|
||||||
|
<string name="preference_status_bar_icons">Állapotsori ikonok</string>
|
||||||
|
<string name="preference_category_links">Linkek</string>
|
||||||
|
<string name="preference_hide_nav_bar">Navigációs sáv elrejtése</string>
|
||||||
|
<string name="preference_debug_reinstall_iconpacks">Ikoncsomagok újratelepítése</string>
|
||||||
|
<string name="preference_debug_reinstall_iconpacks_summary">Az ikoncsomag gyorsítótárának törlése és újraépítése</string>
|
||||||
|
<string name="preference_themed_icons_summary">Színes ikonok az alkalmazás színsémájának megfelelően</string>
|
||||||
|
<string name="open_webpage">Weboldal megnyitása</string>
|
||||||
|
<string name="preference_screen_about_summary">Alkalmazás és licenc információk</string>
|
||||||
|
<string name="preference_screen_appearance_summary">A megjelenés testreszabása</string>
|
||||||
|
<string name="preference_weather_provider">Szolgáltató</string>
|
||||||
|
<string name="preference_screen_integrations">Integrációk</string>
|
||||||
|
<string name="provider_metno">MET Norway</string>
|
||||||
|
<string name="provider_openweathermap">OpenWeatherMap</string>
|
||||||
|
<string name="provider_brightsky">Deutscher Wetterdienst (csak Németország)</string>
|
||||||
|
<string name="provider_here">HERE</string>
|
||||||
|
<string name="preference_category_location">Tartózkodási Hely</string>
|
||||||
|
<string name="preference_automatic_location">Automatikus helymeghatározás</string>
|
||||||
|
<string name="grant_permission">Engedélyezés</string>
|
||||||
|
<string name="preference_screen_appearance">Megjelenés</string>
|
||||||
|
<string name="preference_layout_summary">A keresősáv, a widgetek és a keresési eredmények általános elrendezése</string>
|
||||||
|
<string name="preference_theme_light">Világos</string>
|
||||||
|
<string name="preference_theme_dark">Sötét</string>
|
||||||
|
<string name="preference_colors_custom">Egyedi színséma</string>
|
||||||
|
<string name="preference_custom_colors_a1">Elsődleges</string>
|
||||||
|
<string name="preference_custom_colors_a3">Harmadlagos</string>
|
||||||
|
<string name="preference_custom_colors_n1">Semleges</string>
|
||||||
|
<string name="preference_custom_colors_n2">Semleges Változat</string>
|
||||||
|
<string name="preference_custom_colors_error">Hiba</string>
|
||||||
|
<string name="preference_custom_colors_corepalette">Színpaletta</string>
|
||||||
|
<string name="preference_debug_dump_heap_in_progress">Pillanatfelvétel készítése…</string>
|
||||||
|
<string name="preference_icon_shape_square">Négyzet</string>
|
||||||
|
<string name="weather_condition_partlycloudy">Részben felhős</string>
|
||||||
|
<string name="weather_condition_lightsleetandthunder">Enyhe havas eső és mennydörgés</string>
|
||||||
|
<string name="weather_condition_unknown">Ismeretlen</string>
|
||||||
|
<string name="weather_condition_lightsleetshowers">Enyhe havas eső záporok</string>
|
||||||
|
<string name="weather_condition_heavysnowshowersandthunder">Heves hó záporok és mennydörgés</string>
|
||||||
|
<string name="preference_colors_auto_generate">Generálás az elsődleges színből</string>
|
||||||
|
<string name="weather_widget_show_details">Részletek megjelenítése</string>
|
||||||
|
<string name="weather_widget_hide_details">Részletek elrejtése</string>
|
||||||
|
<string name="preference_category_custom_colors_light">Világos színséma</string>
|
||||||
|
<string name="preference_automatic_location_summary">GPS és helymeghatározó szolgáltatások használata a tartózkodási hely automatikus meghatározásához</string>
|
||||||
|
<string name="preference_location">Tartózkodási Hely</string>
|
||||||
|
<string name="preference_imperial_units_summary">Használja a Fahrenheit fokot és a mérföld per órát</string>
|
||||||
|
<string name="preference_imperial_units">Birodalmi mértékegységek</string>
|
||||||
|
<string name="widget_config_weather_compact">Kompakt mód</string>
|
||||||
|
<string name="preference_debug_dump_heap">Memória pillanatkép</string>
|
||||||
|
<string name="preference_debug_cleanup_database">Az adatbázis tisztítása</string>
|
||||||
|
<string name="preference_category_icons">Ikonok</string>
|
||||||
|
<string name="preference_cards">Kártyák</string>
|
||||||
|
<string name="preference_cards_corner_radius">Sarok sugara</string>
|
||||||
|
<string name="weather_details_wind">Szél: %1$s</string>
|
||||||
|
<string name="weather_details_precipitation">Csapadék: %1$s</string>
|
||||||
|
<string name="weather_no_data">Az időjárás-adatok nem állnak rendelkezésre.</string>
|
||||||
|
<string name="missing_permission_auto_location">A hely automatikus meghatározásához helyhozzáférés szükséges</string>
|
||||||
|
<string name="missing_permission_contact_search_settings">A névjegyek kereséséhez, névjegy engedélyre van szükség</string>
|
||||||
|
<string name="preference_cards_stroke_width">Löketszélesség</string>
|
||||||
|
<string name="preference_cards_opacity">Átlátszatlanság</string>
|
||||||
|
<string name="preference_cards_shape">Alakzat</string>
|
||||||
|
<string name="preference_cards_shape_rounded">Kerekített</string>
|
||||||
|
<string name="preference_cards_shape_cut">Csapott</string>
|
||||||
|
<string name="preference_icon_shape">Alakzat</string>
|
||||||
|
<string name="preference_icon_shape_platform">Rendszer alapértelmezett</string>
|
||||||
|
<string name="preference_icon_shape_rounded_square">Kerekített négyzet</string>
|
||||||
|
<string name="preference_icon_shape_squircle">Lekerekített négyzet</string>
|
||||||
|
<string name="preference_icon_shape_triangle">Reuleaux háromszög</string>
|
||||||
|
<string name="preference_icon_shape_circle">Kör</string>
|
||||||
|
<string name="preference_icon_shape_teardrop">Könnycsepp</string>
|
||||||
|
<string name="preference_icon_shape_pebble">Kavics</string>
|
||||||
|
<string name="preference_screen_plugins">Bővítmények</string>
|
||||||
|
<string name="preference_screen_plugins_summary">Telepített kiterjesztések kezelése</string>
|
||||||
|
<string name="no_plugins_installed">Nincsenek telepített bővítmények</string>
|
||||||
|
<string name="plugin_host_not_installed">Bővítmény hoszt nincs telepítve</string>
|
||||||
|
<string name="preference_theme_system">Kövesse a rendszer beállításait</string>
|
||||||
|
<string name="preference_themed_icons">Témázott ikonok</string>
|
||||||
|
<string name="preference_icon_pack">Ikoncsomag</string>
|
||||||
|
<string name="preference_icon_pack_summary_empty">Nincs telepített ikoncsomag</string>
|
||||||
|
<string name="icon_pack_dynamic_colors">Dinamikus színek</string>
|
||||||
|
<string name="preference_category_animations">Animációk</string>
|
||||||
|
<string name="preference_charging_animation_summary">Buborék animáció lejátszása a készülék töltése közben</string>
|
||||||
|
<string name="preference_nav_bar_icons">Navigációs sáv ikonok</string>
|
||||||
|
<string name="preference_system_bar_icons_auto">Automatikus</string>
|
||||||
|
<string name="preference_system_bar_icons_light">Világos</string>
|
||||||
|
<string name="preference_system_bar_icons_dark">Sötét</string>
|
||||||
|
<string name="preference_hide_status_bar">Állapotsor elrejtése</string>
|
||||||
|
<string name="preference_google">Google</string>
|
||||||
|
<string name="preference_signin_user">Bejelentkezve %1$s néven</string>
|
||||||
|
<string name="preference_signin_logout">Kijelentkezés</string>
|
||||||
|
<string name="preference_summary_not_logged_in">Jelenleg nem vagy bejelentkezve</string>
|
||||||
|
<string name="preference_icon_shape_pentagon">Ötszög</string>
|
||||||
|
<string name="preference_category_wallpaper">Háttérkép</string>
|
||||||
|
<string name="weather_condition_sleet">Havas eső</string>
|
||||||
|
<string name="weather_condition_rain">Eső</string>
|
||||||
|
<string name="weather_condition_lightsleet">Enyhe havas eső</string>
|
||||||
|
<string name="missing_permission_calendar_search_settings">A naptárban való kereséshez, naptár engedélyre van szükség</string>
|
||||||
|
<string name="weather_condition_heavyrainshowersandthunder">Heves eső záporok és mennydörgés</string>
|
||||||
|
<string name="weather_condition_heavysleetandthunder">Heves havas eső és mennydörgés</string>
|
||||||
|
<string name="missing_permission_files_search">A fényképek, média és dokumentumok kereséséhez tárhely engedélyre van szükség.</string>
|
||||||
|
<string name="missing_permission_appshortcuts_create">Állítsd be a(z) %1$s alkalmazást alapértelmezett otthoni alkalmazásként a parancsikonok létrehozásához.</string>
|
||||||
|
<string name="preference_custom_colors_a2">Másodlagos</string>
|
||||||
|
<string name="import_theme_error">A kiválasztott fájlt nem lehetett beolvasni. Kérjük, győződj meg róla, hogy érvényes témafájlt (*.kvtheme) választottál ki és hogy a fájl nem sérült.</string>
|
||||||
|
<string name="preference_hidden_items_reveal_button">Kinyit gomb megjelenítése</string>
|
||||||
|
<string name="favorites_empty_tag">Nincsenek elemek ilyen címkével</string>
|
||||||
|
<string name="preference_layout_open_search">Keresés / alkalmazás tár</string>
|
||||||
|
<string name="preference_category_media_apps">Médiaalkalmazások</string>
|
||||||
|
<string name="preference_search_unitconverter_summary">Használat: 1.5 kg, vagy 4 cm >> in</string>
|
||||||
|
<string name="preference_search_bar_launch_on_enter_summary">A kiemelt egyezés megnyitása, vagy gyors műveletet, ha megérinti az Ugrás gombot</string>
|
||||||
|
<string name="preference_hidden_items">Rejtett keresési eredmények</string>
|
||||||
|
<string name="icon_picker_filter_all_packs">Minden ikoncsomag</string>
|
||||||
|
<string name="customize_tags_placeholder">Címkék…</string>
|
||||||
|
<string name="search_action_websearch">Internetes keresés</string>
|
||||||
|
<plurals name="preference_calendar_calendars_summary">
|
||||||
|
<item quantity="one">%1$d naptár kiválasztva</item>
|
||||||
|
<item quantity="other">%1$d naptár kiválasztva</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="plugin_state_setup_required">Először be kell állítanod ezt a bővítményt</string>
|
||||||
|
<string name="plugin_action_setup">Beállítás</string>
|
||||||
|
<string name="plugin_type_weather">Időjárás szolgáltató</string>
|
||||||
|
<string name="plugin_weather_provider_enable">Beállítás időjárás szolgáltatónak</string>
|
||||||
|
<string name="preference_clock_widget_alignment_bottom">Alulra</string>
|
||||||
|
<string name="preference_clockwidget_battery_part_summary">Az akkumulátor aktuális töltöttségi szintjének megjelenítése, amikor az akkumulátor lemerült vagy töltődik</string>
|
||||||
|
<string name="preference_clockwidget_alarm_part_summary">Azon riasztások megjelenítése, amelyek a következő 15 percen belül megszólalnak</string>
|
||||||
|
<string name="preference_logs">Naplók</string>
|
||||||
|
<string name="preference_logs_summary">Alkalmazásnaplók megtekintése és exportálása</string>
|
||||||
|
<string name="preference_search_gdrive">Google Drive</string>
|
||||||
|
<string name="preference_screen_buildinfo_summary">További információ az alkalmazás ezen verziójáról</string>
|
||||||
|
<string name="preference_search_bar_launch_on_enter">Keresés enterrel</string>
|
||||||
|
<string name="preference_hidden_items_summary">Rejtett alkalmazások és keresési eredmények kezelése</string>
|
||||||
|
<string name="preference_wikipedia_customurl">Wikipedia URL</string>
|
||||||
|
<string name="preference_screen_icons_summary">Rács, ikonméret, ikoncsomagok, jelvények</string>
|
||||||
|
<string name="backup_component_themes">Színsémák</string>
|
||||||
|
<string name="backup_select_components">Válaszd ki, hogy miről szeretnél biztonsági másolatot készíteni:</string>
|
||||||
|
<string name="apps_profile_main">Személyes</string>
|
||||||
|
<string name="favorites_empty">A kitűzött és gyakran használt elemek itt jelennek meg</string>
|
||||||
|
<string name="create_app_shortcut">Parancsikon létrehozása</string>
|
||||||
|
<string name="frequently_used_show_in_favorites">Megjelenítés a kedvencekben</string>
|
||||||
|
<string name="search_action_timer">Időzítő indítása</string>
|
||||||
|
<string name="tag_exists_message">Egy ilyen nevű címke már létezik. Ha folytatod, a két címke egyesül.</string>
|
||||||
|
<string name="tag_empty_message">A címke neve nem lehet üres.</string>
|
||||||
|
<string name="search_action_contact">Hozzáadás a névjegyekhez</string>
|
||||||
|
<string name="search_bar_position_top">Fent</string>
|
||||||
|
<string name="preference_layout_search_results">A keresési eredmények elrendezése</string>
|
||||||
|
<string name="preference_layout_fixed_search_bar_summary">Ne görgesse ki a keresősávot a látóteréből</string>
|
||||||
|
<string name="preference_layout_fixed_rotation">Rögzített képernyőforgatás</string>
|
||||||
|
<string name="preference_gesture_swipe_right">Jobbra húzás</string>
|
||||||
|
<string name="gesture_action_open_search">Keresés megnyitása</string>
|
||||||
|
<string name="gesture_action_launch_app">Alkalmazás indítása</string>
|
||||||
|
<string name="preference_layout_fixed_rotation_summary">A képernyő elforgatásának zárolása portré módban</string>
|
||||||
|
<string name="missing_permission_accessibility_gesture_settings">Ehhez a művelethez engedélyezni kell az Kvaesitso kisegítő lehetőségek szolgáltatását.</string>
|
||||||
|
<string name="widget_config_appwidget_height">Magasság</string>
|
||||||
|
<string name="preference_search_result_ordering_weight_factor_default">Kiegyensúlyozott</string>
|
||||||
|
<string name="note_widget_action_unlink_file">Leválasztás</string>
|
||||||
|
<string name="note_widget_conflict_keep_selected">Maradjon kiválasztva</string>
|
||||||
|
<string name="preference_screen_buildinfo">Összeállítási információk</string>
|
||||||
|
<string name="preference_screen_debug">Hibakeresés</string>
|
||||||
|
<string name="preference_screen_widgets_summary">Widgetek konfigurálása</string>
|
||||||
|
<string name="battery_part_charging">⚠⚡︎ Töltés ⚡︎⚠</string>
|
||||||
|
<string name="backup_component_websearches">Internetes keresési parancsikonok</string>
|
||||||
|
<string name="search_action_email">Email</string>
|
||||||
|
<string name="search_action_alarm">Riasztás beállítása</string>
|
||||||
|
<string name="create_search_action_type">Milyen akciót szeretnél létrehozni?</string>
|
||||||
|
<string name="more_information">Több információ</string>
|
||||||
|
<string name="open_search_swipe_right">Jobbra húzás</string>
|
||||||
|
<string name="gesture_action_recents">Futó alkalmazások megjelenítése</string>
|
||||||
|
<string name="preference_notification_badges">Értesítési jelvények</string>
|
||||||
|
<string name="preference_grid_column_count">Oszlopok száma</string>
|
||||||
|
<string name="preference_screen_weatherwidget">Időjárás</string>
|
||||||
|
<string name="preference_clock_widget_fill_height_summary">Szúrjon be extra helyet az óra fölé, hogy kitöltse a teljes képernyőmagasságot</string>
|
||||||
|
<string name="preference_shortcut_badges">Parancsikon jelvények</string>
|
||||||
|
<string name="preference_grid_labels_summary">Az alkalmazás nevének megjelenítése az ikon alatt</string>
|
||||||
|
<string name="preference_screen_clockwidget_summary">Az óra stílusának és összetevőinek konfigurálása</string>
|
||||||
|
<string name="preference_blur_wallpaper_summary">Használjon elmosódást a háttérképen</string>
|
||||||
|
<string name="preference_blur_wallpaper_unsupported">Nem támogatott ezen az eszközön</string>
|
||||||
|
<string name="preference_wallpaper_summary">Háttérkép kiválasztása</string>
|
||||||
|
<string name="preference_shortcut_badges_summary">Egy jelvény megjelenítése, amely jelzi, hogy egy parancsikon melyik alkalmazáshoz tartozik</string>
|
||||||
|
<string name="app_widget_loading_failed">Az alkalmazás widgetet nem sikerült betölteni.</string>
|
||||||
|
<string name="preference_screen_search">Keresés</string>
|
||||||
|
<string name="preference_nextcloud_signin_summary">A Nextcloud szervereden való kereséshez be kell jelentkezned</string>
|
||||||
|
<string name="preference_screen_musicwidget">Zene</string>
|
||||||
|
<string name="preference_screen_debug_summary">Hibaelhárító eszközök</string>
|
||||||
|
<string name="preference_category_widgets">Widgetek</string>
|
||||||
|
<string name="preference_clockwidget_music_part_summary">Médiavezérlők megjelenítése, ha aktív médiamunkamenet van</string>
|
||||||
|
<string name="plugin_type_filesearch">Fájl keresés</string>
|
||||||
|
<string name="preference_crash_reporter_summary">Hiba és összeomlás jelentések</string>
|
||||||
|
<string name="preference_search_result_ordering_weight_factor_high">Variálható</string>
|
||||||
|
<string name="preference_search_currencyconverter">Valutaváltó</string>
|
||||||
|
<string name="preference_search_bar_auto_focus_summary">A billentyűzet automatikus megjelenítése az alkalmazásfiók kinyitásakor</string>
|
||||||
|
<string name="note_widget_link_file_summary">Szinkronizálja a widget tartalmát egy külső fájllal</string>
|
||||||
|
<string name="plugin_weather_provider_enabled">Jelenleg időjárás szolgáltatóként van beállítva</string>
|
||||||
|
<string name="preference_search_websites">Weboldalak</string>
|
||||||
|
<string name="preference_search_websites_summary">Egy weboldal előnézetének megjelenítése, ha a keresési lekérdezés URL</string>
|
||||||
|
<string name="preference_google_signin_summary">Bejelentkezés a Google Drive kereséséhez</string>
|
||||||
|
<string name="preference_edit_favorites_summary">A kitűzött elemek sorrendjének módosítása</string>
|
||||||
|
<string name="preference_widgets_edit_button_summary">Egy gomb megjelenítése a widgetek hozzáadásához, eltávolításához és átrendezéséhez</string>
|
||||||
|
<string name="note_widget_file_read_error_description">A hivatkozott fájlt nem lehetett beolvasni. Lehetséges, hogy áthelyezték vagy törölték. A másolat visszaállításra került a Kvaesitso belső tárolójából. Ha szerkeszted a jegyzetet, a hivatkozott fájl valószínűleg felülírásra kerül.</string>
|
||||||
|
<string name="plugin_state_error">Ez a bővítmény nem működik megfelelően</string>
|
||||||
|
<string name="preference_screen_search_summary">Keresés, címkék, rejtett elemek</string>
|
||||||
|
<string name="preference_search_websearch_summary">A különböző keresőmotorok parancsikonjainak megjelenítése</string>
|
||||||
|
<string name="preference_search_files_summary">Keress helyi- és felhőfájlokat</string>
|
||||||
|
<string name="preference_search_cloud_summary">Keresés a(z) %1$s fájljai között</string>
|
||||||
|
<string name="preference_favorites_frequently_used_summary">Gyakran használt elemek megjelenítése a kedvencek között</string>
|
||||||
|
<string name="backup_component_settings">Beállítások</string>
|
||||||
|
<plurals name="tag_selected_items">
|
||||||
|
<item quantity="one">%1$d kiválasztott elem</item>
|
||||||
|
<item quantity="other">%1$d kiválasztott elem</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="open_search_swipe_left">Balra húzás</string>
|
||||||
|
<string name="preference_search_contacts_summary">Névjegyek keresése ezen az eszközön</string>
|
||||||
|
<string name="no_account_owncloud">Még nem csatlakoztatottál Owncloud fiókot</string>
|
||||||
|
<string name="backup_complete">A biztonsági mentés befejeződött.</string>
|
||||||
|
<string name="search_action_message">Üzenet</string>
|
||||||
|
<string name="preference_calendar_calendars">Naptárak</string>
|
||||||
|
<string name="backup_component_customizations">Testreszabások</string>
|
||||||
|
<string name="preference_calendar_hide_allday">Az egész napos események elrejtése</string>
|
||||||
|
<string name="preference_search_bar_auto_focus">Billentyűzet megjelenítése</string>
|
||||||
|
<string name="search_action_label">Név</string>
|
||||||
|
<string name="preference_layout_fixed_search_bar">Rögzített keresősáv</string>
|
||||||
|
<string name="preference_screen_tags">Címkék</string>
|
||||||
|
<string name="backup_not_included">A csatlakoztatott fiókokról nem készül biztonsági másolat. A harmadik féltől származó alkalmazások widgetjeit csak ezen az eszközön lehet visszaállítani.</string>
|
||||||
|
<string name="backup_component_favorites">Kedvencek & rejtett alkalmazások</string>
|
||||||
|
<string name="restore_meta">Létrehozva a(z) %1$s , a %2$s-n ezzel: %3$s.</string>
|
||||||
|
<string name="search_action_websearch_url_hint">Az URL-sablon, amelyet az internetes keresés URL-jének létrehozásához használatos. Használd a ‘${1}’ szót a tényleges keresési kifejezés helyőrzőjeként, pl. https://google.com/search?q=${1}.</string>
|
||||||
|
<plurals name="battery_part_remaining_charge_time">
|
||||||
|
<item quantity="one">%1$s perc múlva feltöltődik</item>
|
||||||
|
<item quantity="other">%1$s perc múlva feltöltődik</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="search_action_event">Esemény ütemezése</string>
|
||||||
|
<string name="create_search_action_website_url">Add meg a weboldal címét:</string>
|
||||||
|
<string name="search_results_order_bottom_up">Lentről-fölfelé</string>
|
||||||
|
<string name="tag_no_items_message">Ehhez a címkéhez nincsenek elemek hozzárendelve. Ha folytatod, a címke törlődik.</string>
|
||||||
|
<string name="tag_select_items">Elemek kiválasztása:</string>
|
||||||
|
<string name="gesture_failed_message">Egy \"%1$s\" gesztust hajtottál végre. Ez a gesztus jelenleg egy \"%2$s\" művelet kiváltására van beállítva. Az akciót azonban a következő okból nem lehetett végrehajtani:</string>
|
||||||
|
<string name="search_results_order_top_down">Föntről-lefelé</string>
|
||||||
|
<string name="preference_gesture_swipe_down">Lefelé húzás</string>
|
||||||
|
<string name="gesture_action_power_menu">Kikapcsolási menü megjelenítése</string>
|
||||||
|
<string name="preference_search_result_ordering">A keresési eredmények sorrendje</string>
|
||||||
|
<string name="preference_notification_badges_summary">Az olvasatlan értesítésekkel rendelkező alkalmazások jelvényének megjelenítése</string>
|
||||||
|
<string name="create_search_action_type_web">Keresés egy weboldalon</string>
|
||||||
|
<string name="create_search_action_type_app">Keresés egy alkalmazásban</string>
|
||||||
|
<string name="create_search_action_type_intent">Egyedi szándék</string>
|
||||||
|
<string name="create_search_action_title">Új gyors művelet</string>
|
||||||
|
<string name="edit_search_action_title">Gyors művelet szerkesztése</string>
|
||||||
|
<string name="create_search_action_website_invalid_url">Az adott weboldal nem importálható automatikusan webes keresésként. A következő lépésben megpróbálhatsz egy másik webhelyet, vagy manuálisan megadhatod a szükséges adatokat.</string>
|
||||||
|
<string name="search_action_app">Alkalmazás</string>
|
||||||
|
<string name="search_action_websearch_url">URL sablon</string>
|
||||||
|
<string name="experimental_feature">Kísérleti</string>
|
||||||
|
<string name="create_tag_title">Új címke</string>
|
||||||
|
<string name="preference_plugin_badges">Bővítmény jelvények</string>
|
||||||
|
<string name="preference_plugin_badges_summary">Jelezze, hogy a keresési eredményt melyik bővítmény hozta létre</string>
|
||||||
|
<string name="preference_about_telegram">Telegram csoport</string>
|
||||||
|
<string name="preference_about_fdroid">F-Droid tároló</string>
|
||||||
|
<string name="preference_enforce_icon_shape">Kényszerített alakzat</string>
|
||||||
|
<string name="preference_search_contacts">Névjegyek</string>
|
||||||
|
<string name="preference_edit_button">Szerkesztés gomb</string>
|
||||||
|
<string name="preference_favorites_edit_button_summary">Egy gomb megjelenítése a kedvencek átrendezéséhez</string>
|
||||||
|
<string name="preference_screen_icons">Rács & ikonok</string>
|
||||||
|
<string name="no_account_google">Még nem csatlakoztatottál Google fiókot</string>
|
||||||
|
<string name="connect_account">Fiók csatlakoztatása</string>
|
||||||
|
<string name="backup_component_searchactions">Gyors művelet</string>
|
||||||
|
<string name="backup_component_widgets">Beépített widgetek</string>
|
||||||
|
<string name="restore_select_components">Válaszd ki, hogy mit szeretnél visszaállítani. A meglévő adatok felülírásra kerülnek!</string>
|
||||||
|
<string name="icon_picker_search_icon">Keresés az ikoncsomagokban</string>
|
||||||
|
<string name="icon_picker_no_packs_installed">Nincs telepítve ikoncsomag</string>
|
||||||
|
<string name="search_bar_position_bottom">Lent</string>
|
||||||
|
<string name="preference_screen_gestures">Gesztusok</string>
|
||||||
|
<string name="preference_screen_gestures_summary">Gesztusok és gesztusműveletek</string>
|
||||||
|
<string name="preference_gesture_swipe_left">Balra húzás</string>
|
||||||
|
<string name="preference_gesture_double_tap">Dupla érintés</string>
|
||||||
|
<string name="widget_config_appwidget_borderless">Szegély nélküli</string>
|
||||||
|
<string name="apps_profile_work">Munka</string>
|
||||||
|
<string name="preference_search_result_ordering_alphabetic">Abc szerint</string>
|
||||||
|
<string name="preference_search_result_ordering_launch_count">Indítások száma</string>
|
||||||
|
<string name="widget_config_weather_integration_settings">Időjárás integráció beállításai</string>
|
||||||
|
<string name="widget_config_calendar_no_calendars">Nem található naptár</string>
|
||||||
|
<string name="widget_config_music_integration_settings">Médiavezérlő integráció beállításai</string>
|
||||||
|
<string name="note_widget_link_file">Link a fájlhoz</string>
|
||||||
|
<string name="theme_color_scheme_system_default">Rendszer alapértelmezett használata</string>
|
||||||
|
<string name="theme_color_scheme_autogenerate">Az elsődleges színből</string>
|
||||||
|
<string name="shortcut_unavailable_description">Ez a parancsikon nem érhető el, mert a(z) %1$s nem az alapértelmezett indító</string>
|
||||||
|
<string name="restore_different_minor_version">Ez a biztonsági mentés a(z) %1$s egy másik verziójával készült. Előfordulhat, hogy egyes adatok nem lesznek helyesen visszaállítva.</string>
|
||||||
|
<string name="frequently_used_rows">Sorok száma</string>
|
||||||
|
<string name="preference_screen_search_actions">Gyors műveletek</string>
|
||||||
|
<string name="preference_search_search_actions_summary">Gyorsműveletek és keresési parancsikonok konfigurálása</string>
|
||||||
|
<string name="note_widget_action_relink_file">Újraválasztás</string>
|
||||||
|
<string name="note_widget_conflict">Ütközés</string>
|
||||||
|
<string name="note_widget_conflict_action_resolve">Ütközések Megoldása</string>
|
||||||
|
<string name="note_widget_conflict_description">A hivatkozott fájl nem üres, és tartalma nem egyezik a jegyzet utolsó mentett verziójával. Melyik változatot szeretnéd megtartani?</string>
|
||||||
|
<string name="preference_dim_wallpaper">Háttérkép homályosítása</string>
|
||||||
|
<string name="preference_dim_wallpaper_summary">Sötét témák esetén sötétítse a háttérképet</string>
|
||||||
|
<string name="preference_blur_wallpaper">Háttérkép elmosása</string>
|
||||||
|
<string name="preference_blur_wallpaper_radius">Elmosási sugár</string>
|
||||||
|
<string name="preference_screen_badges_summary">Ikonjelvények konfigurálása</string>
|
||||||
|
<string name="preference_suspended_badges_summary">A felfüggesztett alkalmazások jelvényeinek megjelenítése</string>
|
||||||
|
<string name="preference_suspended_badges">Felfüggesztett alkalmazások</string>
|
||||||
|
<string name="preference_cloud_badges">Felhő jelvények</string>
|
||||||
|
<string name="preference_cloud_badges_summary">A felhőben tárolt fájlok jelvényének megjelenítése</string>
|
||||||
|
<string name="preference_nextcloud_signin">Bejelentkezés a Nextcloud-ba</string>
|
||||||
|
<string name="preference_nextcloud">Nextcloud</string>
|
||||||
|
<string name="preference_category_badges">Jelvények</string>
|
||||||
|
<string name="preference_owncloud">Owncloud</string>
|
||||||
|
<string name="preference_owncloud_signin">Bejelentkezés az Owncloud-ba</string>
|
||||||
|
<string name="preference_owncloud_signin_summary">Az Owncloud szervereden való kereséshez be kell jelentkezned</string>
|
||||||
|
<string name="preference_enforce_icon_shape_summary">Alkalmazza az alakzatot az összes ikonra, beleértve azokat is, amelyek általában nem támogatnák</string>
|
||||||
|
<string name="preference_category_license">Licenc</string>
|
||||||
|
<string name="preference_about_license">Ez az alkalmazás egy ingyenes szoftver.</string>
|
||||||
|
<string name="preference_grid_icon_size">Ikon méret</string>
|
||||||
|
<string name="preference_grid_labels">Cimkék mutatása</string>
|
||||||
|
<string name="preference_about_license_summary">Licencelve a GNU General Public License 3.0 alatt</string>
|
||||||
|
<string name="preference_category_grid">Rács</string>
|
||||||
|
<string name="preference_screen_clockwidget">Óra</string>
|
||||||
|
<string name="preference_clockwidget_layout">Elrendezés</string>
|
||||||
|
<string name="preference_clockwidget_layout_vertical">Alapértelmezett</string>
|
||||||
|
<string name="preference_clockwidget_layout_horizontal">Kompakt</string>
|
||||||
|
<string name="preference_clock_widget_fill_height">Képernyő magasságának kitöltése</string>
|
||||||
|
<string name="preference_clock_widget_color">Szín</string>
|
||||||
|
<string name="preference_clock_widget_style">Stílus</string>
|
||||||
|
<string name="preference_clock_widget_style_summary">Válassz egy órát</string>
|
||||||
|
<string name="preference_clock_widget_alignment">Igazítás</string>
|
||||||
|
<string name="preference_clock_widget_alignment_center">Középre</string>
|
||||||
|
<string name="preference_clock_widget_alignment_top">Felülre</string>
|
||||||
|
<string name="preference_clockwidget_dynamic_zone">Dinamikus zóna</string>
|
||||||
|
<string name="preference_clockwidget_date_part">Dátum</string>
|
||||||
|
<string name="preference_clockwidget_date_part_summary">Az aktuális dátum megjelenítése</string>
|
||||||
|
<string name="preference_clockwidget_favorites_part">Dokk</string>
|
||||||
|
<string name="preference_clockwidget_favorites_part_summary">A rögzített elemek első sorának megjelenítése</string>
|
||||||
|
<string name="preference_clockwidget_music_part">Média</string>
|
||||||
|
<string name="preference_clockwidget_battery_part">Akkumulátor</string>
|
||||||
|
<string name="preference_clockwidget_alarm_part">Riasztások</string>
|
||||||
|
<string name="preference_screen_backup">Biztonsági mentés & Visszaállítás</string>
|
||||||
|
<string name="preference_screen_backup_summary">Kvaesitso adatok exportálása és importálása</string>
|
||||||
|
<string name="preference_backup">Biztonsági mentés</string>
|
||||||
|
<string name="preference_backup_summary">A beállítások és az indítóadatok exportálása</string>
|
||||||
|
<string name="preference_restore">Visszaállítás</string>
|
||||||
|
<string name="preference_restore_summary">Importálj egy korábban létrehozott biztonsági másolatot</string>
|
||||||
|
<string name="preference_crash_reporter">Összeomlás jelentő</string>
|
||||||
|
<string name="preference_export_log">Naplófájl exportálása</string>
|
||||||
|
<string name="preference_search_favorites">Kedvencek</string>
|
||||||
|
<string name="preference_search_favorites_summary">Rögzített és gyakran használt elemek megjelenítése az alkalmazásrács felett</string>
|
||||||
|
<string name="preference_search_files">Fájlok</string>
|
||||||
|
<string name="preference_search_calendar">Naptár</string>
|
||||||
|
<string name="preference_search_calendar_summary">Közelgő találkozók és események keresése</string>
|
||||||
|
<string name="preference_search_appshortcuts">Alkalmazás parancsikonok</string>
|
||||||
|
<string name="preference_search_appshortcuts_summary">Alkalmazás parancsikonok keresése</string>
|
||||||
|
<string name="preference_search_calculator">Számológép</string>
|
||||||
|
<string name="preference_search_calculator_summary">Matematikai kifejezések kiértékelése</string>
|
||||||
|
<string name="preference_search_unitconverter">Mértékegység váltó</string>
|
||||||
|
<string name="preference_search_currencyconverter_summary">Rendszeresen töltse le az árfolyamokat a valuták átváltásához</string>
|
||||||
|
<string name="preference_search_wikipedia">Wikipedia</string>
|
||||||
|
<string name="preference_search_wikipedia_summary">Keresés a Wikipedia-n</string>
|
||||||
|
<string name="preference_search_websearch">keresés az interneten</string>
|
||||||
|
<string name="preference_search_localfiles">Helyi fájlok</string>
|
||||||
|
<string name="preference_search_localfiles_summary">Dokumentumok, fényképek és egyéb, ezen az eszközön tárolt fájlok keresése</string>
|
||||||
|
<string name="preference_search_gdrive_summary">Keresés a(z) %1$s fájljai között a Google Drive-on</string>
|
||||||
|
<string name="preference_search_onedrive">OneDrive</string>
|
||||||
|
<string name="preference_search_onedrive_summary">Keressen a(z) %1$s fájljai között a OneDrive-on</string>
|
||||||
|
<string name="preference_search_nextcloud">Nextcloud</string>
|
||||||
|
<string name="preference_search_owncloud">Owncloud</string>
|
||||||
|
<string name="preference_screen_calendarwidget">Naptár</string>
|
||||||
|
<string name="preference_search_wikipedia_pictures">Képek megjelenítése</string>
|
||||||
|
<string name="preference_search_wikipedia_pictures_summary">Jelentősen növeli az adatforgalmat</string>
|
||||||
|
<string name="preference_google_signin">Bejelentkezés a Google segítségével</string>
|
||||||
|
<string name="preference_music_filter_sources">Zenei alkalmazások korlátozása</string>
|
||||||
|
<string name="preference_music_filter_sources_summary">A nem zenei alkalmazások médiaműveleteinek figyelmen kívül hagyása</string>
|
||||||
|
<string name="preference_search_bar_style">Stílus</string>
|
||||||
|
<string name="preference_search_bar_style_summary">A keresősáv megjelenésének testreszabása</string>
|
||||||
|
<string name="preference_search_bar_color">Szín</string>
|
||||||
|
<string name="preference_hidden_items_reveal_button_summary">Egy gomb megjelenítése a rejtett keresési eredmények megjelenítéséhez</string>
|
||||||
|
<string name="preference_screen_tags_summary">Címkék és címkézett elemek kezelése</string>
|
||||||
|
<string name="preference_category_favorites_frequently_used">Gyakran használt</string>
|
||||||
|
<string name="preference_screen_homescreen">Kezdőképernyő</string>
|
||||||
|
<string name="preference_screen_homescreen_summary">Óra, keresősáv, háttérkép, rendszersávok</string>
|
||||||
|
<string name="preference_category_accounts">Fiókok</string>
|
||||||
|
<string name="preference_weather_integration">Időjárás</string>
|
||||||
|
<string name="preference_media_integration">Média vezérlés</string>
|
||||||
|
<string name="no_account_nextcloud">Még nem csatlakoztatottál Nextcloud fiókot</string>
|
||||||
|
<string name="restore_invalid_file">A kiválasztott fájl nem tűnik biztonsági mentésnek. Biztos, hogy a megfelelő fájlt választottad ki?</string>
|
||||||
|
<string name="restore_incompatible_file">Ez a biztonsági mentés a(z) %1$s egy másik verziójával készült, és ezzel a verzióval nem állítható vissza.</string>
|
||||||
|
<string name="restore_complete">A biztonsági mentés visszaállítása megtörtént.</string>
|
||||||
|
<string name="icon_picker_title">Ikon kiválasztása</string>
|
||||||
|
<string name="icon_picker_default_icon">Alapértelmezett</string>
|
||||||
|
<string name="icon_picker_suggestions">Javaslatok</string>
|
||||||
|
<string name="favorites">Kedvencek</string>
|
||||||
|
<string name="search_action_call">Hívás</string>
|
||||||
|
<string name="search_action_open_url">Weboldal meglátogatása</string>
|
||||||
|
<string name="create_search_action_pick_app">Válassz egy alkalmazást a kereséshez:</string>
|
||||||
|
<string name="widget_config_appwidget_background">Háttér kártya</string>
|
||||||
|
<string name="widget_config_appwidget_configure">Widget konfigurálása</string>
|
||||||
|
<string name="widget_config_appwidget_resize_hint">Húzás az átméretezéshez</string>
|
||||||
|
<string name="note_widget_linked_file_summary">Összekapcsolva a(z) %1$s-val/vel</string>
|
||||||
|
<string name="note_widget_conflict_local_version">Utolsó mentett verzió:</string>
|
||||||
|
<string name="note_widget_conflict_file_version">Aktuális fájl tartalma:</string>
|
||||||
|
<string name="note_widget_file_read_error">Hiba a jegyzet olvasásakor</string>
|
||||||
|
<string name="note_widget_file_write_error">Hiba a jegyzet mentése közben</string>
|
||||||
|
<string name="note_widget_file_write_error_description">A jegyzetet nem lehetett a kapcsolódó fájlba írni. Lehetséges, hogy áthelyezték vagy törölték. A másolat el lett mentve a Kvaesitso belső tárolójába.</string>
|
||||||
|
<string name="confirmation_delete_color_scheme">Biztosan törölni szeretné a(z) %1$s színsémát?</string>
|
||||||
|
<string name="new_color_scheme_name">Új színséma</string>
|
||||||
|
<string name="theme_color_scheme_custom_color">Egyedi</string>
|
||||||
|
<string name="theme_color_scheme_palette_color">Paletta</string>
|
||||||
|
<string name="preference_restore_default">Alapértelmezett visszaállítása</string>
|
||||||
|
<string name="import_theme_apply">Téma alkalmazása</string>
|
||||||
|
<string name="shortcut_label_unavailable">Nem elérhető</string>
|
||||||
|
<string name="edit_tag_title">címke szerkesztése</string>
|
||||||
|
<string name="tag_exists_error">Egy ilyen nevű címke már létezik.</string>
|
||||||
|
<string name="tag_name">Címke név</string>
|
||||||
|
<string name="open_search_pull_down">Lefelé húzás</string>
|
||||||
|
<string name="preference_layout_search_bar_position">Keresősáv pozíciója</string>
|
||||||
|
<string name="preference_gesture_long_press">Hosszú érintés</string>
|
||||||
|
<string name="preference_gesture_home_button">Kezdőlap gomb/gesztus</string>
|
||||||
|
<string name="gesture_action_none">Ne csináljon semmit</string>
|
||||||
|
<string name="gesture_action_notifications">Értesítési tár megnyitása</string>
|
||||||
|
<string name="gesture_action_lock_screen">Képernyő kikapcsolása</string>
|
||||||
|
<string name="gesture_action_quick_settings">Gyorsbeállítások megnyitása</string>
|
||||||
|
<string name="missing_permission_accessibility_gesture_failed">A művelet végrehajtásához engedélyezni kell a Kvaesitso kisegítő lehetőségek szolgáltatását.</string>
|
||||||
|
<string name="preference_search_result_ordering_weighted">Használat</string>
|
||||||
|
<string name="preference_search_result_ordering_weight_factor">Rugalmasság a rangsorolásban</string>
|
||||||
|
<string name="preference_search_result_ordering_weight_factor_low">Stabíl</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -264,4 +264,5 @@
|
|||||||
<item quantity="other">kilóméter per óra</item>
|
<item quantity="other">kilóméter per óra</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="unit_degree_celsius_symbol">°C</string>
|
<string name="unit_degree_celsius_symbol">°C</string>
|
||||||
|
<string name="unit_sqinch_symbol">négyzetinch</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -5,7 +5,7 @@
|
|||||||
<string name="wind_south_south_west">Sud sud ovest</string>
|
<string name="wind_south_south_west">Sud sud ovest</string>
|
||||||
<string name="nextcloud_server_url_empty">L\'URL del server non deve essere vuoto</string>
|
<string name="nextcloud_server_url_empty">L\'URL del server non deve essere vuoto</string>
|
||||||
<string name="owncloud_username">Nome utente</string>
|
<string name="owncloud_username">Nome utente</string>
|
||||||
<string name="owncloud_login_2fa_hint">Se hai abilitato l\'autenticazione a due fattori, devi utilizzare una password per l\'app qui.</string>
|
<string name="owncloud_login_2fa_hint">Se hai abilitato l\'autenticazione a due fattori, devi usare una password per l\'app qui.</string>
|
||||||
<string name="wikipedia_url">https://it.wikipedia.org</string>
|
<string name="wikipedia_url">https://it.wikipedia.org</string>
|
||||||
<string name="disclaimer_currency_converter">Tassi di cambio pubblicati una volta al giorno dalla Banca Centrale Europea. Tutte le informazioni sono fornite \"così come sono\" senza alcun tipo di garanzia. Non si assume alcuna responsabilità per queste informazioni.
|
<string name="disclaimer_currency_converter">Tassi di cambio pubblicati una volta al giorno dalla Banca Centrale Europea. Tutte le informazioni sono fornite \"così come sono\" senza alcun tipo di garanzia. Non si assume alcuna responsabilità per queste informazioni.
|
||||||
\n
|
\n
|
||||||
@ -39,7 +39,7 @@
|
|||||||
<string name="preference_clockwidget_layout_horizontal">Compatto</string>
|
<string name="preference_clockwidget_layout_horizontal">Compatto</string>
|
||||||
<string name="preference_clockwidget_music_part_summary">Mostra i controlli multimediali quando c\'è una riproduzione attiva</string>
|
<string name="preference_clockwidget_music_part_summary">Mostra i controlli multimediali quando c\'è una riproduzione attiva</string>
|
||||||
<string name="preference_search_files_summary">Cerca file locali e nel cloud</string>
|
<string name="preference_search_files_summary">Cerca file locali e nel cloud</string>
|
||||||
<string name="preference_search_unitconverter_summary">Utilizzo: 1.5 kg oppure 4 cm >> in</string>
|
<string name="preference_search_unitconverter_summary">Uso: 1.5 kg oppure 4 cm >> in</string>
|
||||||
<string name="edit_favorites_dialog_unpinned">Non appuntati - usati frequentemente</string>
|
<string name="edit_favorites_dialog_unpinned">Non appuntati - usati frequentemente</string>
|
||||||
<string name="preference_search_websearch_summary">Mostra scorciatoie a diversi motori di ricerca</string>
|
<string name="preference_search_websearch_summary">Mostra scorciatoie a diversi motori di ricerca</string>
|
||||||
<string name="edit_favorites_dialog_pinned_unsorted">Appuntati: ordinati automaticamente</string>
|
<string name="edit_favorites_dialog_pinned_unsorted">Appuntati: ordinati automaticamente</string>
|
||||||
@ -454,7 +454,7 @@
|
|||||||
<string name="missing_permission_appshortcuts_create">Imposta %1$s come app home predefinita per creare scorciatoie.</string>
|
<string name="missing_permission_appshortcuts_create">Imposta %1$s come app home predefinita per creare scorciatoie.</string>
|
||||||
<string name="preference_category_debug_tools">Strumenti</string>
|
<string name="preference_category_debug_tools">Strumenti</string>
|
||||||
<string name="preference_debug_cleanup_database">Pulisci database</string>
|
<string name="preference_debug_cleanup_database">Pulisci database</string>
|
||||||
<string name="preference_debug_cleanup_database_summary">Rimuovi le voci interrotte e inutilizzate dal database del launcher</string>
|
<string name="preference_debug_cleanup_database_summary">Rimuovi le voci interrotte e inusate dal database del launcher</string>
|
||||||
<plurals name="debug_cleanup_database_result">
|
<plurals name="debug_cleanup_database_result">
|
||||||
<item quantity="one">%1$d voce è stata rimossa.</item>
|
<item quantity="one">%1$d voce è stata rimossa.</item>
|
||||||
<item quantity="many">%1$d voci sono state rimosse.</item>
|
<item quantity="many">%1$d voci sono state rimosse.</item>
|
||||||
@ -468,7 +468,7 @@
|
|||||||
<string name="customize_tags_placeholder">Tag…</string>
|
<string name="customize_tags_placeholder">Tag…</string>
|
||||||
<string name="edit_favorites_dialog_tags">Tag</string>
|
<string name="edit_favorites_dialog_tags">Tag</string>
|
||||||
<string name="edit_favorites_dialog_tag_section_empty">I tag aggiunti verranno visualizzati qui</string>
|
<string name="edit_favorites_dialog_tag_section_empty">I tag aggiunti verranno visualizzati qui</string>
|
||||||
<string name="favorites_empty">Gli elementi appuntati e utilizzati di frequente appariranno qui</string>
|
<string name="favorites_empty">Gli elementi appuntati e usati di frequente appariranno qui</string>
|
||||||
<string name="favorites_empty_tag">Non ci sono elementi con questo tag</string>
|
<string name="favorites_empty_tag">Non ci sono elementi con questo tag</string>
|
||||||
<string name="edit_favorites_dialog_new_tag">Crea tag…</string>
|
<string name="edit_favorites_dialog_new_tag">Crea tag…</string>
|
||||||
<string name="websearch_dialog_query_encoding_form">application/x-www-form-urlencoded</string>
|
<string name="websearch_dialog_query_encoding_form">application/x-www-form-urlencoded</string>
|
||||||
@ -515,7 +515,7 @@
|
|||||||
<string name="search_action_label">Nome</string>
|
<string name="search_action_label">Nome</string>
|
||||||
<string name="search_action_app">App</string>
|
<string name="search_action_app">App</string>
|
||||||
<string name="search_action_websearch_url">Modello dell\'URL</string>
|
<string name="search_action_websearch_url">Modello dell\'URL</string>
|
||||||
<string name="search_action_websearch_url_hint">Il modello di URL utilizzato per creare l\'URL della ricerca web. Utilizza \'${1}\' come segnaposto per il termine di ricerca effettivo, ad es. https://google.com/search\?q=${1}.</string>
|
<string name="search_action_websearch_url_hint">Il modello di URL usato per creare l\'URL della ricerca web. Usa \'${1}\' come segnaposto per il termine di ricerca effettivo, ad es. https://google.com/search?q=${1}.</string>
|
||||||
<string name="more_information">Maggiori informazioni</string>
|
<string name="more_information">Maggiori informazioni</string>
|
||||||
<string name="experimental_feature">Sperimentale</string>
|
<string name="experimental_feature">Sperimentale</string>
|
||||||
<string name="help">Aiuto</string>
|
<string name="help">Aiuto</string>
|
||||||
@ -584,7 +584,7 @@
|
|||||||
<string name="preference_search_result_ordering_weight_factor_high">Variabile</string>
|
<string name="preference_search_result_ordering_weight_factor_high">Variabile</string>
|
||||||
<string name="preference_search_result_ordering">Ordinamento risultati ricerca</string>
|
<string name="preference_search_result_ordering">Ordinamento risultati ricerca</string>
|
||||||
<string name="preference_search_result_ordering_launch_count">Conteggio avvii</string>
|
<string name="preference_search_result_ordering_launch_count">Conteggio avvii</string>
|
||||||
<string name="preference_search_result_ordering_weighted">Utilizzo</string>
|
<string name="preference_search_result_ordering_weighted">Uso</string>
|
||||||
<string name="preference_screen_integrations">Integrazioni</string>
|
<string name="preference_screen_integrations">Integrazioni</string>
|
||||||
<string name="preference_screen_homescreen">Schermata home</string>
|
<string name="preference_screen_homescreen">Schermata home</string>
|
||||||
<string name="preference_screen_icons_summary">Griglia, dimensione icona, pacchetti icone, indicatori</string>
|
<string name="preference_screen_icons_summary">Griglia, dimensione icona, pacchetti icone, indicatori</string>
|
||||||
@ -664,10 +664,17 @@
|
|||||||
<string name="shortcut_unavailable_description">Questa scorciatoia non è disponibile perché %1$s non è il launcher predefinito</string>
|
<string name="shortcut_unavailable_description">Questa scorciatoia non è disponibile perché %1$s non è il launcher predefinito</string>
|
||||||
<string name="preference_clockwidget_dynamic_zone">Zona dinamica</string>
|
<string name="preference_clockwidget_dynamic_zone">Zona dinamica</string>
|
||||||
<string name="preference_screen_plugins">Plugin</string>
|
<string name="preference_screen_plugins">Plugin</string>
|
||||||
<string name="missing_permission_plugins">Per utilizzare i plugin è necessaria l\'autorizzazione del plugin.</string>
|
<string name="missing_permission_plugins">Per usare i plugin è necessaria l\'autorizzazione del plugin.</string>
|
||||||
<string name="preference_screen_plugins_summary">Gestisci estensioni installate</string>
|
<string name="preference_screen_plugins_summary">Gestisci estensioni installate</string>
|
||||||
<string name="no_plugins_installed">Nessun plugin installato</string>
|
<string name="no_plugins_installed">Nessun plugin installato</string>
|
||||||
<string name="plugin_host_not_installed">Host del plugin non installato</string>
|
<string name="plugin_host_not_installed">Host del plugin non installato</string>
|
||||||
<string name="preference_plugin_badges">Plugin indicatori</string>
|
<string name="preference_plugin_badges">Plugin indicatori</string>
|
||||||
<string name="preference_plugin_badges_summary">Indica con quale plugin è stato creato un risultato di ricerca</string>
|
<string name="preference_plugin_badges_summary">Indica con quale plugin è stato creato un risultato di ricerca</string>
|
||||||
|
<string name="plugin_state_setup_required">Devi prima configurare questo plugin</string>
|
||||||
|
<string name="plugin_action_setup">Imposta</string>
|
||||||
|
<string name="plugin_type_weather">Fornitore meteo</string>
|
||||||
|
<string name="plugin_weather_provider_enabled">Attualmente impostato come fornitore meteo</string>
|
||||||
|
<string name="plugin_state_error">Questo plugin non funziona correttamente</string>
|
||||||
|
<string name="plugin_type_filesearch">Ricerca file</string>
|
||||||
|
<string name="plugin_weather_provider_enable">Imposta come fornitore meteo</string>
|
||||||
</resources>
|
</resources>
|
||||||
96
core/i18n/src/main/res/values-ms/strings.xml
Normal file
96
core/i18n/src/main/res/values-ms/strings.xml
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="menu_share">Kongsi</string>
|
||||||
|
<string name="menu_share_apk_file">Fail pakej</string>
|
||||||
|
<string name="menu_uninstall">Nyahpasang</string>
|
||||||
|
<string name="menu_favorites_pin">Sematkan pada kegemaran</string>
|
||||||
|
<string name="menu_favorites_unpin">Nyahpin</string>
|
||||||
|
<string name="menu_back">Balik</string>
|
||||||
|
<string name="menu_app_info">Maklumat Applikasi</string>
|
||||||
|
<string name="menu_share_store_link">%1$s pautan</string>
|
||||||
|
<string name="menu_launch">Buka</string>
|
||||||
|
<string name="menu_customize">Ubahsuai</string>
|
||||||
|
<string name="menu_open_file">Buka</string>
|
||||||
|
<string name="menu_hide">Sorok</string>
|
||||||
|
<string name="menu_unhide">Paparkan</string>
|
||||||
|
<string name="msg_item_hidden">%1$s telah disorokkan.</string>
|
||||||
|
<string name="action_undo">Kembali</string>
|
||||||
|
<string name="action_import">Import</string>
|
||||||
|
<string name="menu_delete">Padam</string>
|
||||||
|
<string name="menu_remove">Buang</string>
|
||||||
|
<string name="search_bar_placeholder">Carian</string>
|
||||||
|
<string name="app_info_version">Versi %1$s</string>
|
||||||
|
<string name="menu_calendar_open_externally">Buka dalam apl kalender</string>
|
||||||
|
<string name="menu_contacts_open_externally">Buka dalam apl kenalan</string>
|
||||||
|
<string name="settings">Tetapan</string>
|
||||||
|
<string name="help">Bantuan</string>
|
||||||
|
<string name="wallpaper">Kertas Dinding</string>
|
||||||
|
<string name="wind_north_east">Timur Laut</string>
|
||||||
|
<string name="wind_east_north_east">Timur-timur laut</string>
|
||||||
|
<string name="wind_north">Utara</string>
|
||||||
|
<string name="wind_east">Timur</string>
|
||||||
|
<string name="wind_north_north_east">Utara timur laut</string>
|
||||||
|
<string name="wind_east_south_east">Timur tenggara</string>
|
||||||
|
<string name="wind_south_east">Tenggara</string>
|
||||||
|
<string name="wind_south_south_east">Selatan tenggara</string>
|
||||||
|
<string name="wind_south">Selatan</string>
|
||||||
|
<string name="wind_south_south_west">Selatan barat daya</string>
|
||||||
|
<string name="wind_south_west">Barat daya</string>
|
||||||
|
<string name="wind_west_south_west">Barat-barat daya</string>
|
||||||
|
<string name="wind_west">Barat</string>
|
||||||
|
<string name="wind_west_north_west">Barat-barat laut</string>
|
||||||
|
<string name="wind_north_west">Barat laut</string>
|
||||||
|
<string name="wind_north_north_west">Utara barat laut</string>
|
||||||
|
<string name="precipitation_none">Tiada hujan</string>
|
||||||
|
<string name="wikipedia_source">Daripada Wikipedia</string>
|
||||||
|
<string name="file_meta_title">Tajuk: %1$s</string>
|
||||||
|
<string name="file_meta_artist">Artis: %1$s</string>
|
||||||
|
<string name="file_meta_album">Album: %1$s</string>
|
||||||
|
<string name="file_meta_duration">Tempoh: %1$s</string>
|
||||||
|
<string name="file_meta_year">Tahun: %1$s</string>
|
||||||
|
<string name="file_meta_size">Saiz: %1$s</string>
|
||||||
|
<string name="file_meta_type">Jenis: %1$s</string>
|
||||||
|
<string name="file_meta_app_name">Nama apl: %1$s</string>
|
||||||
|
<string name="file_meta_app_version">Versi: %1$s</string>
|
||||||
|
<string name="file_meta_app_pkgname">Nama pakej: %1$s</string>
|
||||||
|
<string name="file_meta_app_min_sdk">Versi SDK min: %1$s</string>
|
||||||
|
<string name="file_meta_owner">Pemilik: %1$s</string>
|
||||||
|
<string name="file_meta_location">Lokasi: %1$s</string>
|
||||||
|
<string name="file_type_directory">Direktori</string>
|
||||||
|
<string name="file_type_android">Fail pakej android</string>
|
||||||
|
<string name="file_type_source_code">Sumber fail kod</string>
|
||||||
|
<string name="file_type_document">Dokumen</string>
|
||||||
|
<string name="file_type_spreadsheet">Lampiran</string>
|
||||||
|
<string name="file_type_music">Fail muzik</string>
|
||||||
|
<string name="file_type_image">Gambar</string>
|
||||||
|
<string name="file_type_presentation">Persembahan</string>
|
||||||
|
<string name="file_type_compressed">Fail termampat</string>
|
||||||
|
<string name="file_type_ebook">E-buku</string>
|
||||||
|
<string name="file_type_drawing">Lukisan</string>
|
||||||
|
<string name="file_type_form">Borang</string>
|
||||||
|
<string name="file_type_launchertheme">%1$s tema</string>
|
||||||
|
<string name="file_type_generic">%1$s fail</string>
|
||||||
|
<string name="alert_delete_file">Fail %1$s akan dipadamkan secara kekal. Teruskan?</string>
|
||||||
|
<string name="default_websearch_1_name">Google</string>
|
||||||
|
<string name="default_websearch_2_name">YouTube</string>
|
||||||
|
<string name="default_websearch_2_url">https://www.youtube.com/results?search_query=${1}</string>
|
||||||
|
<string name="default_websearch_3_name">Google Play</string>
|
||||||
|
<string name="websearch_dialog_create_title">Tambah carian web</string>
|
||||||
|
<string name="websearch_dialog_edit_title">Sunting carian sesawang</string>
|
||||||
|
<string name="websearch_dialog_name">Nama</string>
|
||||||
|
<string name="websearch_dialog_url">URL</string>
|
||||||
|
<string name="alert_delete_directory">Direktori %1$s dan semua kandungannya akan dipadamkan secara kekal. Teruskan?</string>
|
||||||
|
<string name="alert_delete_shortcut">Pintasan %1$s akan dibuang secara kekal. Teruskan?</string>
|
||||||
|
<string name="file_meta_path">Laluan: %1$s</string>
|
||||||
|
<string name="default_websearch_1_url">https://google.com/search?q=${1}</string>
|
||||||
|
<string name="wikipedia_url">https://ms.wikipedia.org</string>
|
||||||
|
<string name="file_type_video">Video</string>
|
||||||
|
<string name="file_type_text">Fail teks</string>
|
||||||
|
<string name="file_type_archive">Fail arkib</string>
|
||||||
|
<string name="file_type_none">Fail</string>
|
||||||
|
<string name="websearch_dialog_url_description">\'${1}\' akan digantikan dengan istilah carian sebenar.</string>
|
||||||
|
<string name="file_meta_dimensions">Dimensi: %1$s</string>
|
||||||
|
<string name="file_type_launcherbackup">%1$s salinan sandar</string>
|
||||||
|
<string name="error_activity_not_found">Tidak dapat membuka %1$s</string>
|
||||||
|
<string name="default_websearch_3_url">https://play.google.com/store/search?q=${1}</string>
|
||||||
|
</resources>
|
||||||
2
core/i18n/src/main/res/values-ms/units.xml
Normal file
2
core/i18n/src/main/res/values-ms/units.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources></resources>
|
||||||
@ -135,7 +135,7 @@
|
|||||||
<string name="weather_condition_heavysnowshowers">Сильный снегопад</string>
|
<string name="weather_condition_heavysnowshowers">Сильный снегопад</string>
|
||||||
<string name="weather_condition_heavyrainshowers">Сильный ливень</string>
|
<string name="weather_condition_heavyrainshowers">Сильный ливень</string>
|
||||||
<string name="weather_condition_rainshowersandthunder">Ливневые дожди и гром</string>
|
<string name="weather_condition_rainshowersandthunder">Ливневые дожди и гром</string>
|
||||||
<string name="weather_condition_sleet">Мокрый снег</string>
|
<string name="weather_condition_sleet">Слякоть</string>
|
||||||
<string name="weather_condition_rain">Дождь</string>
|
<string name="weather_condition_rain">Дождь</string>
|
||||||
<string name="weather_condition_lightssnowshowersandthunder">Слабый снегопад и гроза</string>
|
<string name="weather_condition_lightssnowshowersandthunder">Слабый снегопад и гроза</string>
|
||||||
<string name="weather_condition_heavyrainshowersandthunder">Сильные ливни и гроза</string>
|
<string name="weather_condition_heavyrainshowersandthunder">Сильные ливни и гроза</string>
|
||||||
@ -229,7 +229,7 @@
|
|||||||
<string name="weather_condition_sleetandthunder">Мокрый дождь с грозой</string>
|
<string name="weather_condition_sleetandthunder">Мокрый дождь с грозой</string>
|
||||||
<string name="weather_condition_sleetshowersandthunder">Дожди со снегом и гроза</string>
|
<string name="weather_condition_sleetshowersandthunder">Дожди со снегом и гроза</string>
|
||||||
<string name="weather_condition_rainandthunder">Дождь с грозой</string>
|
<string name="weather_condition_rainandthunder">Дождь с грозой</string>
|
||||||
<string name="weather_condition_heavysleetandthunder">Сильный мокрый снег и гроза</string>
|
<string name="weather_condition_heavysleetandthunder">Сильная слякоть и гроза</string>
|
||||||
<string name="weather_condition_lightsleetshowers">Слабые дожди с мокрым снегом</string>
|
<string name="weather_condition_lightsleetshowers">Слабые дожди с мокрым снегом</string>
|
||||||
<string name="weather_details_humidity">Влажность: %1$s</string>
|
<string name="weather_details_humidity">Влажность: %1$s</string>
|
||||||
<string name="weather_widget_set_location">Установить местоположение</string>
|
<string name="weather_widget_set_location">Установить местоположение</string>
|
||||||
@ -411,7 +411,7 @@
|
|||||||
<string name="preference_search_websites">Веб-сайты</string>
|
<string name="preference_search_websites">Веб-сайты</string>
|
||||||
<string name="preference_screen_buildinfo">Информация о сборке</string>
|
<string name="preference_screen_buildinfo">Информация о сборке</string>
|
||||||
<string name="preference_screen_buildinfo_summary">Больше информации об этой сборке приложения</string>
|
<string name="preference_screen_buildinfo_summary">Больше информации об этой сборке приложения</string>
|
||||||
<string name="preference_search_bar_auto_focus_summary">Автоматически открывать клавиатуру при открытии поиска</string>
|
<string name="preference_search_bar_auto_focus_summary">Автоматически открывать клавиатуру при открытии списка приложений</string>
|
||||||
<string name="preference_gesture_swipe_right">Свайп вправо</string>
|
<string name="preference_gesture_swipe_right">Свайп вправо</string>
|
||||||
<string name="preference_gesture_double_tap">Двойное касание</string>
|
<string name="preference_gesture_double_tap">Двойное касание</string>
|
||||||
<string name="preference_gesture_long_press">Длительное нажатие</string>
|
<string name="preference_gesture_long_press">Длительное нажатие</string>
|
||||||
@ -435,7 +435,7 @@
|
|||||||
<string name="preference_screen_gestures">Жесты</string>
|
<string name="preference_screen_gestures">Жесты</string>
|
||||||
<string name="preference_gesture_swipe_left">Свайп влево</string>
|
<string name="preference_gesture_swipe_left">Свайп влево</string>
|
||||||
<string name="preference_gesture_swipe_down">Свайп вниз</string>
|
<string name="preference_gesture_swipe_down">Свайп вниз</string>
|
||||||
<string name="gesture_action_none">Ничего</string>
|
<string name="gesture_action_none">Ничего не делать</string>
|
||||||
<string name="gesture_action_open_search">Открыть поиск</string>
|
<string name="gesture_action_open_search">Открыть поиск</string>
|
||||||
<string name="gesture_action_notifications">Открыть панель уведомлений</string>
|
<string name="gesture_action_notifications">Открыть панель уведомлений</string>
|
||||||
<string name="preference_screen_gestures_summary">Жесты и действия</string>
|
<string name="preference_screen_gestures_summary">Жесты и действия</string>
|
||||||
@ -447,13 +447,13 @@
|
|||||||
<string name="create_search_action_title">Новое быстрое действие</string>
|
<string name="create_search_action_title">Новое быстрое действие</string>
|
||||||
<string name="create_search_action_pick_app">Выберите приложение для поиска:</string>
|
<string name="create_search_action_pick_app">Выберите приложение для поиска:</string>
|
||||||
<string name="icon_pack_dynamic_colors">Динамические цвета</string>
|
<string name="icon_pack_dynamic_colors">Динамические цвета</string>
|
||||||
<string name="backup_not_included">Подключенные учетные записи и сторонние виджеты не будут включены в резервную копию.</string>
|
<string name="backup_not_included">Подключенные учетные записи не будут включены в резервную копию. Виджеты от сторонних приложений могут быть восстановлены только на этом устройстве.</string>
|
||||||
<string name="preference_nextcloud_signin">Войти в Nextcloud</string>
|
<string name="preference_nextcloud_signin">Войти в Nextcloud</string>
|
||||||
<string name="preference_owncloud">Owncloud</string>
|
<string name="preference_owncloud">Owncloud</string>
|
||||||
<string name="preference_nextcloud_signin_summary">Войдите, для поиска в сервере Nextcloud</string>
|
<string name="preference_nextcloud_signin_summary">Войдите, для поиска в сервере Nextcloud</string>
|
||||||
<string name="preference_owncloud_signin">Войти в Owncloud</string>
|
<string name="preference_owncloud_signin">Войти в Owncloud</string>
|
||||||
<string name="preference_owncloud_signin_summary">Войдите, для поиска в сервере Owncloud</string>
|
<string name="preference_owncloud_signin_summary">Войдите, для поиска в сервере Owncloud</string>
|
||||||
<string name="preference_clockwidget_favorites_part">Избранные</string>
|
<string name="preference_clockwidget_favorites_part">Быстрый доступ</string>
|
||||||
<string name="preference_screen_backup">Резервное копирование</string>
|
<string name="preference_screen_backup">Резервное копирование</string>
|
||||||
<string name="preference_screen_backup_summary">Экспортируйте и импортируйте данные лаунчера</string>
|
<string name="preference_screen_backup_summary">Экспортируйте и импортируйте данные лаунчера</string>
|
||||||
<string name="preference_backup">Создать копию</string>
|
<string name="preference_backup">Создать копию</string>
|
||||||
@ -571,7 +571,7 @@
|
|||||||
<string name="preference_weather_integration">Погода</string>
|
<string name="preference_weather_integration">Погода</string>
|
||||||
<string name="preference_media_integration">Управление медиа</string>
|
<string name="preference_media_integration">Управление медиа</string>
|
||||||
<string name="preference_category_accounts">Аккаунты</string>
|
<string name="preference_category_accounts">Аккаунты</string>
|
||||||
<string name="icon_picker_search_icon">Найти иконку</string>
|
<string name="icon_picker_search_icon">Найти иконку в наборе</string>
|
||||||
<string name="preference_search_bar_launch_on_enter_summary">Запускать подсвеченное совпадение или быстрое действие по клавише \"Вперёд\"</string>
|
<string name="preference_search_bar_launch_on_enter_summary">Запускать подсвеченное совпадение или быстрое действие по клавише \"Вперёд\"</string>
|
||||||
<string name="preference_search_bar_launch_on_enter">Запускать по Enter</string>
|
<string name="preference_search_bar_launch_on_enter">Запускать по Enter</string>
|
||||||
<string name="note_widget_action_unlink_file">Отсоединить</string>
|
<string name="note_widget_action_unlink_file">Отсоединить</string>
|
||||||
@ -597,10 +597,10 @@
|
|||||||
<string name="preference_search_appshortcuts_summary">Искать ярлыки приложений</string>
|
<string name="preference_search_appshortcuts_summary">Искать ярлыки приложений</string>
|
||||||
<string name="note_widget_conflict_local_version">Последняя сохранённая версия:</string>
|
<string name="note_widget_conflict_local_version">Последняя сохранённая версия:</string>
|
||||||
<string name="widget_name_notes">Заметки</string>
|
<string name="widget_name_notes">Заметки</string>
|
||||||
<string name="preference_cloud_badges_summary">Показывать значок для файлов, храняющихся в облачном хранилище</string>
|
<string name="preference_cloud_badges_summary">Показывать значок для файлов, хранящихся в облачном хранилище</string>
|
||||||
<string name="preference_edit_favorites_summary">Изменить порядок закрепленных приложений</string>
|
<string name="preference_edit_favorites_summary">Изменить порядок закрепленных приложений</string>
|
||||||
<string name="note_widget_file_write_error">Ошибка при сохранении заметки</string>
|
<string name="note_widget_file_write_error">Ошибка при сохранении заметки</string>
|
||||||
<string name="preference_shortcut_badges_summary">Показывать значок, обозначающий, какому приложению принадлежит ярлык</string>
|
<string name="preference_shortcut_badges_summary">Показывать значок, указывающий, какому приложению принадлежит ярлык</string>
|
||||||
<string name="tag_empty_message">Название тега не может быть пустым.</string>
|
<string name="tag_empty_message">Название тега не может быть пустым.</string>
|
||||||
<string name="preference_clockwidget_music_part_summary">Показать управление медиа, если активна медиа-сессия</string>
|
<string name="preference_clockwidget_music_part_summary">Показать управление медиа, если активна медиа-сессия</string>
|
||||||
<string name="preference_search_calculator_summary">Вычислять математические выражения</string>
|
<string name="preference_search_calculator_summary">Вычислять математические выражения</string>
|
||||||
@ -639,4 +639,47 @@
|
|||||||
<string name="note_widget_conflict_description">Привязанный файл не пустой и его содержимое не совпадает с последней сохранённой версией этой заметки. Какую версию вы хотите оставить\?</string>
|
<string name="note_widget_conflict_description">Привязанный файл не пустой и его содержимое не совпадает с последней сохранённой версией этой заметки. Какую версию вы хотите оставить\?</string>
|
||||||
<string name="note_widget_conflict_keep_selected">Оставить выбранную</string>
|
<string name="note_widget_conflict_keep_selected">Оставить выбранную</string>
|
||||||
<string name="note_widget_file_write_error_description">Заметка не может быть записана в привязанный файл. Возможно, он был перемещён или удалён. Копия была сохранена во внутреннем хранилище лаунчера.</string>
|
<string name="note_widget_file_write_error_description">Заметка не может быть записана в привязанный файл. Возможно, он был перемещён или удалён. Копия была сохранена во внутреннем хранилище лаунчера.</string>
|
||||||
|
<string name="file_type_launchertheme">Тема %1$s</string>
|
||||||
|
<string name="preference_debug_dump_heap_summary">Заснять срез, чтобы проанализировать использование памяти. Приложение нельзя будет использовать во время этого процесса.</string>
|
||||||
|
<string name="preference_plugin_badges">Значки плагина</string>
|
||||||
|
<string name="preference_plugin_badges_summary">Указывать, каким плагином был создан результат поиска</string>
|
||||||
|
<string name="preference_clock_widget_alignment">Расположить</string>
|
||||||
|
<string name="search_action_websearch">Веб-поиск</string>
|
||||||
|
<string name="theme_color_scheme_system_default">Системный цвет</string>
|
||||||
|
<string name="theme_color_scheme_autogenerate">Из первичного цвета</string>
|
||||||
|
<string name="theme_color_scheme_palette_color">Палитра</string>
|
||||||
|
<string name="theme_color_scheme_custom_color">Выбор</string>
|
||||||
|
<string name="shortcut_unavailable_description">Этот ярлык недоступен, потому что %1$s не является главным экраном по умолчанию</string>
|
||||||
|
<string name="plugin_type_weather">Провайдер погоды</string>
|
||||||
|
<string name="plugin_weather_provider_enabled">В настоящее время назначен провайдером погоды</string>
|
||||||
|
<string name="plugin_state_setup_required">Сначала вам нужно установить этот плагин</string>
|
||||||
|
<string name="plugin_action_setup">Установить</string>
|
||||||
|
<string name="preference_clock_widget_alignment_top">Вверху</string>
|
||||||
|
<string name="plugin_type_filesearch">Найти файлы</string>
|
||||||
|
<string name="preference_clock_widget_alignment_center">По центру</string>
|
||||||
|
<string name="backup_component_themes">Цветовые схемы</string>
|
||||||
|
<string name="import_theme_error">Не удалось прочитать выбранный файл. Убедитесь, что вы выбрали корректный файл темы (*.kvtheme), и что файл не поврежден.</string>
|
||||||
|
<string name="plugin_weather_provider_enable">Назначить провайдером погоды</string>
|
||||||
|
<string name="preference_restore_default">Вернуть по умолчанию</string>
|
||||||
|
<string name="plugin_state_error">Этот плагин не работает правильно</string>
|
||||||
|
<string name="action_import">Импорт</string>
|
||||||
|
<string name="new_color_scheme_name">Новая цветовая схема</string>
|
||||||
|
<string name="confirmation_delete_color_scheme">Вы действительно хотите удалить цветовую схему \"%1$s\"?</string>
|
||||||
|
<string name="preference_debug_dump_heap">Срез памяти</string>
|
||||||
|
<string name="preference_debug_dump_heap_in_progress">Съёмка среза…</string>
|
||||||
|
<string name="edit">Изменить</string>
|
||||||
|
<string name="preference_custom_colors_corepalette">Цветовая палитра</string>
|
||||||
|
<string name="missing_permission_plugins">Для использования плагинов требуется разрешение на них.</string>
|
||||||
|
<string name="preference_screen_plugins">Плагины</string>
|
||||||
|
<string name="preference_screen_plugins_summary">Управление установленными дополнениями</string>
|
||||||
|
<string name="no_plugins_installed">Установленных плагинов нет</string>
|
||||||
|
<string name="preference_category_animations">Анимации</string>
|
||||||
|
<string name="preference_charging_animation">Анимация зарядки</string>
|
||||||
|
<string name="preference_charging_animation_summary">Проигрывать анимацию с пузырьками во время зарядки устройства</string>
|
||||||
|
<string name="plugin_host_not_installed">Хост плагина не установлен</string>
|
||||||
|
<string name="preference_blur_wallpaper_radius">Радиус размытия</string>
|
||||||
|
<string name="preference_clock_widget_alignment_bottom">Внизу</string>
|
||||||
|
<string name="preference_clockwidget_dynamic_zone">Динамическая зона</string>
|
||||||
|
<string name="import_theme_apply">Применить тему</string>
|
||||||
|
<string name="shortcut_label_unavailable">Недоступно</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -854,4 +854,11 @@
|
|||||||
<string name="shortcut_label_unavailable">Unavailable</string>
|
<string name="shortcut_label_unavailable">Unavailable</string>
|
||||||
<!-- %1$s: app name -->
|
<!-- %1$s: app name -->
|
||||||
<string name="shortcut_unavailable_description">This shortcut is unavailable because %1$s isn\'t the default launcher</string>
|
<string name="shortcut_unavailable_description">This shortcut is unavailable because %1$s isn\'t the default launcher</string>
|
||||||
|
<string name="plugin_state_error">This plugin isn\'t working correctly</string>
|
||||||
|
<string name="plugin_state_setup_required">You need to setup this plugin first</string>
|
||||||
|
<string name="plugin_action_setup">Set up</string>
|
||||||
|
<string name="plugin_type_filesearch">File search</string>
|
||||||
|
<string name="plugin_type_weather">Weather provider</string>
|
||||||
|
<string name="plugin_weather_provider_enable">Set as weather provider</string>
|
||||||
|
<string name="plugin_weather_provider_enabled">Currently set as weather provider</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -14,6 +14,11 @@
|
|||||||
<item quantity="one">kilometer</item>
|
<item quantity="one">kilometer</item>
|
||||||
<item quantity="other">kilometers</item>
|
<item quantity="other">kilometers</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<string name="unit_decimeter_symbol">dm</string>
|
||||||
|
<plurals name="unit_decimeter">
|
||||||
|
<item quantity="one">decimeter</item>
|
||||||
|
<item quantity="other">decimeters</item>
|
||||||
|
</plurals>
|
||||||
<string name="unit_centimeter_symbol">cm</string>
|
<string name="unit_centimeter_symbol">cm</string>
|
||||||
<plurals name="unit_centimeter">
|
<plurals name="unit_centimeter">
|
||||||
<item quantity="one">centimeter</item>
|
<item quantity="one">centimeter</item>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ plugins {
|
|||||||
alias(libs.plugins.android.library)
|
alias(libs.plugins.android.library)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.protobuf)
|
alias(libs.plugins.protobuf)
|
||||||
|
alias(libs.plugins.kotlin.plugin.serialization)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -57,6 +58,7 @@ protobuf {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.kotlin.stdlib)
|
implementation(libs.kotlin.stdlib)
|
||||||
|
implementation(libs.kotlinx.serialization.json)
|
||||||
implementation(libs.androidx.core)
|
implementation(libs.androidx.core)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
api(libs.androidx.datastore)
|
api(libs.androidx.datastore)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
-keepclassmembers class de.mm20.launcher2.preferences.Settings {
|
-keepclassmembers class de.mm20.launcher2.preferences.LegacySettings {
|
||||||
<fields>;
|
<fields>;
|
||||||
}
|
}
|
||||||
|
|
||||||
-keepclassmembers class de.mm20.launcher2.preferences.Settings$* {
|
-keepclassmembers class de.mm20.launcher2.preferences.LegacySettings$* {
|
||||||
<fields>;
|
<fields>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,49 +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 = 19
|
|
||||||
|
|
||||||
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(),
|
|
||||||
Migration_18_19(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -2,59 +2,58 @@ package de.mm20.launcher2.preferences
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
|
import de.mm20.launcher2.preferences.LegacySettings.SearchBarSettings.SearchBarColors
|
||||||
import de.mm20.launcher2.preferences.ktx.toSettingsColorsScheme
|
import de.mm20.launcher2.preferences.ktx.toSettingsColorsScheme
|
||||||
import scheme.Scheme
|
import scheme.Scheme
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
fun createFactorySettings(context: Context): Settings {
|
fun createFactorySettings(context: Context): LegacySettings {
|
||||||
return Settings.newBuilder()
|
return LegacySettings.newBuilder()
|
||||||
.setAppearance(
|
.setAppearance(
|
||||||
Settings.AppearanceSettings
|
LegacySettings.AppearanceSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setTheme(Settings.AppearanceSettings.Theme.System)
|
.setTheme(LegacySettings.AppearanceSettings.Theme.System)
|
||||||
.setDimWallpaper(false)
|
.setDimWallpaper(false)
|
||||||
.setBlurWallpaper(true)
|
.setBlurWallpaper(true)
|
||||||
.setBlurWallpaperRadius(32)
|
.setBlurWallpaperRadius(32)
|
||||||
.setThemeId(UUID(0L, 0L).toString())
|
.setThemeId(UUID(0L, 0L).toString())
|
||||||
.setFont(Settings.AppearanceSettings.Font.Outfit)
|
.setFont(LegacySettings.AppearanceSettings.Font.Outfit)
|
||||||
.setForceCompatModeSystemColors(false)
|
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setWeather(
|
.setWeather(
|
||||||
Settings.WeatherSettings
|
LegacySettings.WeatherSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setProvider(Settings.WeatherSettings.WeatherProvider.MetNo)
|
.setProvider(LegacySettings.WeatherSettings.WeatherProvider.MetNo)
|
||||||
.setImperialUnits(context.resources.getBoolean(R.bool.default_imperialUnits))
|
.setImperialUnits(context.resources.getBoolean(R.bool.default_imperialUnits))
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setMusicWidget(
|
.setMusicWidget(
|
||||||
Settings.MusicWidgetSettings
|
LegacySettings.MusicWidgetSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setCalendarWidget(
|
.setCalendarWidget(
|
||||||
Settings.CalendarWidgetSettings
|
LegacySettings.CalendarWidgetSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setHideAlldayEvents(false)
|
.setHideAlldayEvents(false)
|
||||||
)
|
)
|
||||||
.setClockWidget(
|
.setClockWidget(
|
||||||
Settings.ClockWidgetSettings
|
LegacySettings.ClockWidgetSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setLayout(Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical)
|
.setLayout(LegacySettings.ClockWidgetSettings.ClockWidgetLayout.Vertical)
|
||||||
.setClockStyle(Settings.ClockWidgetSettings.ClockStyle.DigitalClock1)
|
.setClockStyle(LegacySettings.ClockWidgetSettings.ClockStyle.DigitalClock1)
|
||||||
.setColor(Settings.ClockWidgetSettings.ClockWidgetColors.Auto)
|
.setColor(LegacySettings.ClockWidgetSettings.ClockWidgetColors.Auto)
|
||||||
.setAlarmPart(true)
|
.setAlarmPart(true)
|
||||||
.setBatteryPart(true)
|
.setBatteryPart(true)
|
||||||
.setMusicPart(true)
|
.setMusicPart(true)
|
||||||
.setDatePart(true)
|
.setDatePart(true)
|
||||||
.setFavoritesPart(false)
|
.setFavoritesPart(false)
|
||||||
.setFillHeight(true)
|
.setFillHeight(true)
|
||||||
.setAlignment(Settings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
.setAlignment(LegacySettings.ClockWidgetSettings.ClockWidgetAlignment.Bottom)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setFavorites(
|
.setFavorites(
|
||||||
Settings.FavoritesSettings
|
LegacySettings.FavoritesSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
.setFrequentlyUsed(true)
|
.setFrequentlyUsed(true)
|
||||||
@ -62,7 +61,7 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setEditButton(true)
|
.setEditButton(true)
|
||||||
)
|
)
|
||||||
.setFileSearch(
|
.setFileSearch(
|
||||||
Settings.FilesSearchSettings
|
LegacySettings.FilesSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setLocalFiles(true)
|
.setLocalFiles(true)
|
||||||
.setNextcloud(false)
|
.setNextcloud(false)
|
||||||
@ -71,50 +70,50 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setNextcloud(false)
|
.setNextcloud(false)
|
||||||
)
|
)
|
||||||
.setContactsSearch(
|
.setContactsSearch(
|
||||||
Settings.ContactsSearchSettings
|
LegacySettings.ContactsSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setCalendarSearch(
|
.setCalendarSearch(
|
||||||
Settings.CalendarSearchSettings
|
LegacySettings.CalendarSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setAppShortcutSearch(
|
.setAppShortcutSearch(
|
||||||
Settings.AppShortcutSearchSettings
|
LegacySettings.AppShortcutSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setCalculatorSearch(
|
.setCalculatorSearch(
|
||||||
Settings.CalculatorSearchSettings
|
LegacySettings.CalculatorSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setUnitConverterSearch(
|
.setUnitConverterSearch(
|
||||||
Settings.UnitConverterSearchSettings
|
LegacySettings.UnitConverterSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
.setCurrencies(true)
|
.setCurrencies(true)
|
||||||
)
|
)
|
||||||
.setWikipediaSearch(
|
.setWikipediaSearch(
|
||||||
Settings.WikipediaSearchSettings
|
LegacySettings.WikipediaSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(false)
|
.setEnabled(false)
|
||||||
.setImages(false)
|
.setImages(false)
|
||||||
.setCustomUrl("")
|
.setCustomUrl("")
|
||||||
)
|
)
|
||||||
.setWebsiteSearch(
|
.setWebsiteSearch(
|
||||||
Settings.WebsiteSearchSettings
|
LegacySettings.WebsiteSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(false)
|
.setEnabled(false)
|
||||||
)
|
)
|
||||||
.setWebSearch(
|
.setWebSearch(
|
||||||
Settings.WebSearchSettings
|
LegacySettings.WebSearchSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setEnabled(true)
|
.setEnabled(true)
|
||||||
)
|
)
|
||||||
.setBadges(
|
.setBadges(
|
||||||
Settings.BadgeSettings
|
LegacySettings.BadgeSettings
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setNotifications(true)
|
.setNotifications(true)
|
||||||
.setCloudFiles(true)
|
.setCloudFiles(true)
|
||||||
@ -122,15 +121,15 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setSuspendedApps(true)
|
.setSuspendedApps(true)
|
||||||
)
|
)
|
||||||
.setGrid(
|
.setGrid(
|
||||||
Settings.GridSettings.newBuilder()
|
LegacySettings.GridSettings.newBuilder()
|
||||||
.setColumnCount(context.resources.getInteger(R.integer.config_columnCount))
|
.setColumnCount(context.resources.getInteger(R.integer.config_columnCount))
|
||||||
.setIconSize(48)
|
.setIconSize(48)
|
||||||
.setShowLabels(true)
|
.setShowLabels(true)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setSearchBar(
|
.setSearchBar(
|
||||||
Settings.SearchBarSettings.newBuilder()
|
LegacySettings.SearchBarSettings.newBuilder()
|
||||||
.setSearchBarStyle(Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
.setSearchBarStyle(LegacySettings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||||
.setAutoFocus(true)
|
.setAutoFocus(true)
|
||||||
.setLaunchOnEnter(true)
|
.setLaunchOnEnter(true)
|
||||||
.setColor(SearchBarColors.Auto)
|
.setColor(SearchBarColors.Auto)
|
||||||
@ -138,67 +137,67 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setIcons(
|
.setIcons(
|
||||||
Settings.IconSettings.newBuilder()
|
LegacySettings.IconSettings.newBuilder()
|
||||||
.setAdaptify(true)
|
.setAdaptify(true)
|
||||||
.setShape(Settings.IconSettings.IconShape.PlatformDefault)
|
.setShape(LegacySettings.IconSettings.IconShape.PlatformDefault)
|
||||||
.setThemedIcons(false)
|
.setThemedIcons(false)
|
||||||
.setIconPack("")
|
.setIconPack("")
|
||||||
.setIconPackThemed(true)
|
.setIconPackThemed(true)
|
||||||
)
|
)
|
||||||
.setEasterEgg(false)
|
.setEasterEgg(false)
|
||||||
.setSystemBars(
|
.setSystemBars(
|
||||||
Settings.SystemBarsSettings.newBuilder()
|
LegacySettings.SystemBarsSettings.newBuilder()
|
||||||
.setNavBarColor(Settings.SystemBarsSettings.SystemBarColors.Auto)
|
.setNavBarColor(LegacySettings.SystemBarsSettings.SystemBarColors.Auto)
|
||||||
.setStatusBarColor(Settings.SystemBarsSettings.SystemBarColors.Auto)
|
.setStatusBarColor(LegacySettings.SystemBarsSettings.SystemBarColors.Auto)
|
||||||
.setHideStatusBar(false)
|
.setHideStatusBar(false)
|
||||||
.setHideNavBar(false)
|
.setHideNavBar(false)
|
||||||
)
|
)
|
||||||
.setCards(
|
.setCards(
|
||||||
Settings.CardSettings.newBuilder()
|
LegacySettings.CardSettings.newBuilder()
|
||||||
.setBorderWidth(0)
|
.setBorderWidth(0)
|
||||||
.setRadius(12)
|
.setRadius(12)
|
||||||
.setOpacity(1f)
|
.setOpacity(1f)
|
||||||
)
|
)
|
||||||
.setWidgets(
|
.setWidgets(
|
||||||
Settings.WidgetSettings.newBuilder()
|
LegacySettings.WidgetSettings.newBuilder()
|
||||||
.setEditButton(true)
|
.setEditButton(true)
|
||||||
)
|
)
|
||||||
.setLayout(
|
.setLayout(
|
||||||
Settings.LayoutSettings.newBuilder()
|
LegacySettings.LayoutSettings.newBuilder()
|
||||||
.setBaseLayout(Settings.LayoutSettings.Layout.PullDown)
|
.setBaseLayout(LegacySettings.LayoutSettings.Layout.PullDown)
|
||||||
.setBottomSearchBar(false)
|
.setBottomSearchBar(false)
|
||||||
.setReverseSearchResults(false)
|
.setReverseSearchResults(false)
|
||||||
.setFixedRotation(false)
|
.setFixedRotation(false)
|
||||||
)
|
)
|
||||||
.setGestures(
|
.setGestures(
|
||||||
Settings.GestureSettings.newBuilder()
|
LegacySettings.GestureSettings.newBuilder()
|
||||||
.setDoubleTap(
|
.setDoubleTap(
|
||||||
if (isAtLeastApiLevel(28)) {
|
if (isAtLeastApiLevel(28)) {
|
||||||
Settings.GestureSettings.GestureAction.LockScreen
|
LegacySettings.GestureSettings.GestureAction.LockScreen
|
||||||
} else {
|
} else {
|
||||||
Settings.GestureSettings.GestureAction.None
|
LegacySettings.GestureSettings.GestureAction.None
|
||||||
})
|
})
|
||||||
.setLongPress(Settings.GestureSettings.GestureAction.None)
|
.setLongPress(LegacySettings.GestureSettings.GestureAction.None)
|
||||||
.setSwipeDown(Settings.GestureSettings.GestureAction.OpenNotificationDrawer)
|
.setSwipeDown(LegacySettings.GestureSettings.GestureAction.OpenNotificationDrawer)
|
||||||
.setSwipeLeft(Settings.GestureSettings.GestureAction.None)
|
.setSwipeLeft(LegacySettings.GestureSettings.GestureAction.None)
|
||||||
.setSwipeRight(Settings.GestureSettings.GestureAction.None)
|
.setSwipeRight(LegacySettings.GestureSettings.GestureAction.None)
|
||||||
)
|
)
|
||||||
.setResultOrdering(
|
.setResultOrdering(
|
||||||
Settings.SearchResultOrderingSettings.newBuilder()
|
LegacySettings.SearchResultOrderingSettings.newBuilder()
|
||||||
.setOrdering(Settings.SearchResultOrderingSettings.Ordering.Weighted)
|
.setOrdering(LegacySettings.SearchResultOrderingSettings.Ordering.Weighted)
|
||||||
.setWeightFactor(Settings.SearchResultOrderingSettings.WeightFactor.Default)
|
.setWeightFactor(LegacySettings.SearchResultOrderingSettings.WeightFactor.Default)
|
||||||
)
|
)
|
||||||
.setAnimations(
|
.setAnimations(
|
||||||
Settings.AnimationSettings.newBuilder()
|
LegacySettings.AnimationSettings.newBuilder()
|
||||||
.setCharging(true)
|
.setCharging(true)
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DefaultCustomColorsBase: Settings.AppearanceSettings.CustomColors.BaseColors
|
internal val DefaultCustomColorsBase: LegacySettings.AppearanceSettings.CustomColors.BaseColors
|
||||||
get() {
|
get() {
|
||||||
val scheme = Scheme.light(0xFFACE330.toInt())
|
val scheme = Scheme.light(0xFFACE330.toInt())
|
||||||
return Settings.AppearanceSettings.CustomColors.BaseColors.newBuilder()
|
return LegacySettings.AppearanceSettings.CustomColors.BaseColors.newBuilder()
|
||||||
.setAccent1(scheme.primary)
|
.setAccent1(scheme.primary)
|
||||||
.setAccent2(scheme.secondary)
|
.setAccent2(scheme.secondary)
|
||||||
.setAccent3(scheme.tertiary)
|
.setAccent3(scheme.tertiary)
|
||||||
@ -208,13 +207,13 @@ internal val DefaultCustomColorsBase: Settings.AppearanceSettings.CustomColors.B
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DefaultLightCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme
|
internal val DefaultLightCustomColorScheme: LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||||
get() {
|
get() {
|
||||||
val scheme = Scheme.light(0xFFACE330.toInt())
|
val scheme = Scheme.light(0xFFACE330.toInt())
|
||||||
return scheme.toSettingsColorsScheme()
|
return scheme.toSettingsColorsScheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DefaultDarkCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme
|
internal val DefaultDarkCustomColorScheme: LegacySettings.AppearanceSettings.CustomColors.Scheme
|
||||||
get() {
|
get() {
|
||||||
val scheme = Scheme.dark(0xFFACE330.toInt())
|
val scheme = Scheme.dark(0xFFACE330.toInt())
|
||||||
return scheme.toSettingsColorsScheme()
|
return scheme.toSettingsColorsScheme()
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
package de.mm20.launcher2.preferences
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.datastore.core.DataStoreFactory
|
|
||||||
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
|
||||||
import de.mm20.launcher2.backup.Backupable
|
|
||||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
internal class LauncherStoreBackupComponent(
|
|
||||||
private val context: Context,
|
|
||||||
private val dataStore: LauncherDataStore
|
|
||||||
): Backupable {
|
|
||||||
override suspend fun backup(toDir: File) {
|
|
||||||
dataStore.export(toDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun restore(fromDir: File) {
|
|
||||||
dataStore.import(context, fromDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun LauncherDataStore.export(toDir: File) {
|
|
||||||
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
||||||
val backupDataStore = DataStoreFactory.create(
|
|
||||||
serializer = SettingsSerializer,
|
|
||||||
produceFile = {
|
|
||||||
File(toDir, "settings")
|
|
||||||
},
|
|
||||||
scope = scope
|
|
||||||
)
|
|
||||||
val settings = this.data.firstOrNull() ?: return
|
|
||||||
backupDataStore.updateData {
|
|
||||||
settings
|
|
||||||
}
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
suspend fun LauncherDataStore.import(context: Context, fromDir: File) {
|
|
||||||
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
||||||
val backupDataStore = DataStoreFactory.create(
|
|
||||||
serializer = SettingsSerializer,
|
|
||||||
migrations = getMigrations(context),
|
|
||||||
corruptionHandler = ReplaceFileCorruptionHandler {
|
|
||||||
CrashReporter.logException(it)
|
|
||||||
Settings.getDefaultInstance()
|
|
||||||
},
|
|
||||||
produceFile = {
|
|
||||||
File(fromDir, "settings")
|
|
||||||
},
|
|
||||||
scope = scope
|
|
||||||
)
|
|
||||||
val settings = backupDataStore.data.firstOrNull() ?: return
|
|
||||||
|
|
||||||
this.updateData {
|
|
||||||
settings
|
|
||||||
}
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
@ -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,333 @@
|
|||||||
|
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 uiCompatModeColors: Boolean = false,
|
||||||
|
val uiFont: Font = Font.Outfit,
|
||||||
|
val uiBaseLayout: BaseLayout = BaseLayout.PullDown,
|
||||||
|
val uiOrientation: ScreenOrientation = ScreenOrientation.Auto,
|
||||||
|
|
||||||
|
val wallpaperDim: Boolean = false,
|
||||||
|
val wallpaperBlur: Boolean = true,
|
||||||
|
val wallpaperBlurRadius: Int = 32,
|
||||||
|
|
||||||
|
val mediaAllowList: Set<String> = emptySet(),
|
||||||
|
val mediaDenyList: Set<String> = emptySet(),
|
||||||
|
|
||||||
|
val clockWidgetCompact: Boolean = false,
|
||||||
|
val clockWidgetStyle: ClockWidgetStyle = ClockWidgetStyle.Digital1(),
|
||||||
|
val clockWidgetColors: ClockWidgetColors = ClockWidgetColors.Auto,
|
||||||
|
val clockWidgetAlarmPart: Boolean = true,
|
||||||
|
val clockWidgetBatteryPart: Boolean = true,
|
||||||
|
val clockWidgetMusicPart: Boolean = true,
|
||||||
|
val clockWidgetDatePart: Boolean = true,
|
||||||
|
val clockWidgetFillHeight: Boolean = true,
|
||||||
|
val clockWidgetAlignment: ClockWidgetAlignment = ClockWidgetAlignment.Bottom,
|
||||||
|
|
||||||
|
val homeScreenDock: Boolean = false,
|
||||||
|
|
||||||
|
val favoritesEnabled: Boolean = true,
|
||||||
|
val favoritesFrequentlyUsed: Boolean = true,
|
||||||
|
val favoritesFrequentlyUsedRows: Int = 1,
|
||||||
|
val favoritesEditButton: Boolean = true,
|
||||||
|
|
||||||
|
val fileSearchProviders: Set<String> = setOf("local"),
|
||||||
|
|
||||||
|
val contactSearchEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val calendarSearchEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val shortcutSearchEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val calculatorEnabled: Boolean = true,
|
||||||
|
|
||||||
|
val unitConverterEnabled: Boolean = true,
|
||||||
|
val unitConverterCurrencies: Boolean = true,
|
||||||
|
|
||||||
|
val wikipediaSearchEnabled: Boolean = false,
|
||||||
|
val wikipediaSearchImages: Boolean = false,
|
||||||
|
val wikipediaCustomUrl: String? = null,
|
||||||
|
|
||||||
|
val websiteSearchEnabled: Boolean = false,
|
||||||
|
|
||||||
|
val badgesNotifications: Boolean = true,
|
||||||
|
val badgesSuspendedApps: Boolean = true,
|
||||||
|
val badgesCloudFiles: Boolean = true,
|
||||||
|
val badgesShortcuts: Boolean = true,
|
||||||
|
val badgesPlugins: Boolean = true,
|
||||||
|
|
||||||
|
val gridColumnCount: Int = 5,
|
||||||
|
val gridIconSize: Int = 48,
|
||||||
|
val gridLabels: Boolean = true,
|
||||||
|
|
||||||
|
val searchBarStyle: SearchBarStyle = SearchBarStyle.Transparent,
|
||||||
|
val searchBarColors: SearchBarColors = SearchBarColors.Auto,
|
||||||
|
val searchBarKeyboard: Boolean = true,
|
||||||
|
val searchLaunchOnEnter: Boolean = true,
|
||||||
|
val searchBarBottom: Boolean = false,
|
||||||
|
val searchBarFixed: Boolean = false,
|
||||||
|
|
||||||
|
val searchResultsReversed: Boolean = false,
|
||||||
|
val searchResultOrder: SearchResultOrder = SearchResultOrder.Weighted,
|
||||||
|
|
||||||
|
val rankingWeightFactor: WeightFactor = WeightFactor.Default,
|
||||||
|
|
||||||
|
val hiddenItemsShowButton: Boolean = true,
|
||||||
|
|
||||||
|
val iconsShape: IconShape = IconShape.PlatformDefault,
|
||||||
|
val iconsAdaptify: Boolean = false,
|
||||||
|
val iconsThemed: Boolean = false,
|
||||||
|
val iconsForceThemed: Boolean = false,
|
||||||
|
val iconsPack: String? = null,
|
||||||
|
val iconsPackThemed: Boolean = false,
|
||||||
|
|
||||||
|
val easterEgg: Boolean = false,
|
||||||
|
|
||||||
|
val systemBarsHideStatus: Boolean = false,
|
||||||
|
val systemBarsHideNav: Boolean = false,
|
||||||
|
val systemBarsStatusColors: SystemBarColors = SystemBarColors.Auto,
|
||||||
|
val systemBarsNavColors: SystemBarColors = SystemBarColors.Auto,
|
||||||
|
|
||||||
|
val surfacesOpacity: Float = 1f,
|
||||||
|
val surfacesRadius: Int = 24,
|
||||||
|
val surfacesBorderWidth: Int = 0,
|
||||||
|
val surfacesShape: SurfaceShape = SurfaceShape.Rounded,
|
||||||
|
|
||||||
|
val widgetsEditButton: Boolean = true,
|
||||||
|
|
||||||
|
val gesturesSwipeDown: GestureAction = GestureAction.Notifications,
|
||||||
|
val gesturesSwipeLeft: GestureAction = GestureAction.NoAction,
|
||||||
|
val gesturesSwipeRight: GestureAction = GestureAction.NoAction,
|
||||||
|
val gesturesDoubleTap: GestureAction = GestureAction.ScreenLock,
|
||||||
|
val gesturesLongPress: GestureAction = GestureAction.NoAction,
|
||||||
|
val gesturesHomeButton: GestureAction = GestureAction.NoAction,
|
||||||
|
|
||||||
|
val animationsCharging: Boolean = true,
|
||||||
|
|
||||||
|
val stateTagsMultiline: Boolean = false,
|
||||||
|
|
||||||
|
val weatherProvider: String = "metno",
|
||||||
|
val weatherAutoLocation: Boolean = true,
|
||||||
|
val weatherLocation: LatLon? = null,
|
||||||
|
val weatherLocationName: String? = null,
|
||||||
|
val weatherLastLocation: LatLon? = null,
|
||||||
|
val weatherLastUpdate: Long = 0L,
|
||||||
|
val weatherProviderSettings: Map<String, ProviderSettings> = emptyMap(),
|
||||||
|
val weatherImperialUnits: Boolean = false,
|
||||||
|
|
||||||
|
) {
|
||||||
|
constructor(
|
||||||
|
context: Context,
|
||||||
|
) : this(
|
||||||
|
weatherImperialUnits = context.resources.getBoolean(R.bool.default_imperialUnits),
|
||||||
|
gridColumnCount = context.resources.getInteger(R.integer.config_columnCount),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ColorScheme {
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class Font {
|
||||||
|
Outfit,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface ThemeDescriptor {
|
||||||
|
@Serializable
|
||||||
|
@SerialName("default")
|
||||||
|
data object Default : ThemeDescriptor
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("bw")
|
||||||
|
data object BlackAndWhite : ThemeDescriptor
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("custom")
|
||||||
|
data class Custom(
|
||||||
|
val id: String,
|
||||||
|
) : ThemeDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface ClockWidgetStyle {
|
||||||
|
@Serializable
|
||||||
|
@SerialName("digital1")
|
||||||
|
data class Digital1(
|
||||||
|
val outlined: Boolean = false,
|
||||||
|
val variant: Variant = Variant.Default,
|
||||||
|
) : ClockWidgetStyle {
|
||||||
|
@Serializable
|
||||||
|
enum class Variant {
|
||||||
|
Default,
|
||||||
|
MDY,
|
||||||
|
OnePlus,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("digital2")
|
||||||
|
data object Digital2 : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("orbit")
|
||||||
|
data object Orbit : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("analog")
|
||||||
|
data object Analog : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("binary")
|
||||||
|
data object Binary : ClockWidgetStyle
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("empty")
|
||||||
|
data object Empty : ClockWidgetStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ClockWidgetColors {
|
||||||
|
Auto,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ClockWidgetAlignment {
|
||||||
|
Top,
|
||||||
|
Center,
|
||||||
|
Bottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SearchBarStyle {
|
||||||
|
Transparent,
|
||||||
|
Solid,
|
||||||
|
Hidden,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SearchBarColors {
|
||||||
|
Auto,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class IconShape {
|
||||||
|
PlatformDefault,
|
||||||
|
Circle,
|
||||||
|
Square,
|
||||||
|
RoundedSquare,
|
||||||
|
Triangle,
|
||||||
|
Squircle,
|
||||||
|
Hexagon,
|
||||||
|
Pentagon,
|
||||||
|
Teardrop,
|
||||||
|
Pebble,
|
||||||
|
EasterEgg,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SystemBarColors {
|
||||||
|
Auto,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SurfaceShape {
|
||||||
|
Rounded,
|
||||||
|
Cut,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class BaseLayout {
|
||||||
|
PullDown,
|
||||||
|
Pager,
|
||||||
|
PagerReversed,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class ScreenOrientation {
|
||||||
|
Auto,
|
||||||
|
Portrait,
|
||||||
|
Landscape,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface GestureAction {
|
||||||
|
@Serializable
|
||||||
|
@SerialName("no_action")
|
||||||
|
data object NoAction : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("notifications")
|
||||||
|
data object Notifications : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("quick_settings")
|
||||||
|
data object QuickSettings : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("screen_lock")
|
||||||
|
data object ScreenLock : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("search")
|
||||||
|
data object Search : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("power_menu")
|
||||||
|
data object PowerMenu : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("recents")
|
||||||
|
data object Recents : GestureAction
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("launch_searchable")
|
||||||
|
data class Launch(val key: String?) : GestureAction
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SearchResultOrder {
|
||||||
|
Weighted,
|
||||||
|
Alphabetical,
|
||||||
|
LaunchCount,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class WeightFactor {
|
||||||
|
Default,
|
||||||
|
Low,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LatLon(
|
||||||
|
val lat: Double,
|
||||||
|
val lon: Double,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ProviderSettings(
|
||||||
|
val locationId: String? = null,
|
||||||
|
val locationName: String? = null,
|
||||||
|
)
|
||||||
@ -1,8 +1,7 @@
|
|||||||
package de.mm20.launcher2.files.settings
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
import androidx.datastore.core.CorruptionException
|
import androidx.datastore.core.CorruptionException
|
||||||
import androidx.datastore.core.Serializer
|
import androidx.datastore.core.Serializer
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
import kotlinx.serialization.json.decodeFromStream
|
||||||
@ -11,27 +10,17 @@ import java.io.IOException
|
|||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@Serializable
|
internal object LauncherSettingsDataSerializer : Serializer<LauncherSettingsData> {
|
||||||
data class FileSearchSettingsData(
|
|
||||||
val localFiles: Boolean = true,
|
|
||||||
val gdriveFiles: Boolean = false,
|
|
||||||
val nextcloudFiles: Boolean = false,
|
|
||||||
val owncloudFiles: Boolean = false,
|
|
||||||
val plugins: Set<String> = emptySet(),
|
|
||||||
val schemaVersion: Int = 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
internal object FileSearchSettingsDataSerializer : Serializer<FileSearchSettingsData> {
|
|
||||||
|
|
||||||
internal val json = Json {
|
internal val json = Json {
|
||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
encodeDefaults = true
|
encodeDefaults = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override val defaultValue: FileSearchSettingsData
|
override val defaultValue: LauncherSettingsData
|
||||||
get() = FileSearchSettingsData(schemaVersion = 0)
|
get() = LauncherSettingsData(schemaVersion = 0)
|
||||||
|
|
||||||
override suspend fun readFrom(input: InputStream): FileSearchSettingsData {
|
override suspend fun readFrom(input: InputStream): LauncherSettingsData {
|
||||||
try {
|
try {
|
||||||
return json.decodeFromStream(input)
|
return json.decodeFromStream(input)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
@ -43,7 +32,7 @@ internal object FileSearchSettingsDataSerializer : Serializer<FileSearchSettings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun writeTo(t: FileSearchSettingsData, output: OutputStream) {
|
override suspend fun writeTo(t: LauncherSettingsData, output: OutputStream) {
|
||||||
json.encodeToStream(t, output)
|
json.encodeToStream(t, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.CorruptionException
|
||||||
|
import androidx.datastore.core.DataMigration
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.core.Serializer
|
||||||
|
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
||||||
|
import androidx.datastore.dataStore
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException
|
||||||
|
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||||
|
import de.mm20.launcher2.preferences.migrations.*
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
internal typealias LegacyDataStore = DataStore<LegacySettings>
|
||||||
|
|
||||||
|
internal val Context.legacyDataStore: LegacyDataStore by dataStore(
|
||||||
|
fileName = "settings.pb",
|
||||||
|
serializer = LegacySettingsSerializer,
|
||||||
|
produceMigrations = {
|
||||||
|
getMigrations(it)
|
||||||
|
},
|
||||||
|
corruptionHandler = ReplaceFileCorruptionHandler {
|
||||||
|
CrashReporter.logException(it)
|
||||||
|
LegacySettings.getDefaultInstance()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
internal const val SchemaVersion = 18
|
||||||
|
|
||||||
|
internal fun getMigrations(context: Context): List<DataMigration<LegacySettings>> {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
object LegacySettingsSerializer : Serializer<LegacySettings> {
|
||||||
|
override val defaultValue: LegacySettings = LegacySettings.getDefaultInstance()
|
||||||
|
|
||||||
|
override suspend fun readFrom(input: InputStream): LegacySettings {
|
||||||
|
try {
|
||||||
|
return LegacySettings.parseFrom(input)
|
||||||
|
} catch (e: InvalidProtocolBufferException) {
|
||||||
|
throw CorruptionException("Cannot read proto.", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun writeTo(t: LegacySettings, output: OutputStream) {
|
||||||
|
t.writeTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,50 @@
|
|||||||
package de.mm20.launcher2.preferences
|
package de.mm20.launcher2.preferences
|
||||||
|
|
||||||
import de.mm20.launcher2.backup.Backupable
|
import de.mm20.launcher2.backup.Backupable
|
||||||
|
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.media.MediaSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.CalculatorSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.CalendarSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FavoritesSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.FileSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.RankingSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.UnitConverterSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WebsiteSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.search.WikipediaSearchSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.BadgeSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.GestureSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.IconSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.SearchUiSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||||
|
import de.mm20.launcher2.preferences.ui.UiState
|
||||||
|
import de.mm20.launcher2.preferences.weather.WeatherSettings
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.core.qualifier.named
|
import org.koin.core.qualifier.named
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val preferencesModule = module {
|
val preferencesModule = module {
|
||||||
single { androidContext().dataStore }
|
single { androidContext().legacyDataStore }
|
||||||
factory<Backupable>(named<LauncherDataStore>()) { LauncherStoreBackupComponent(androidContext(), get()) }
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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