Restructure settings

This commit is contained in:
MM20 2023-04-13 00:53:19 +02:00
parent 971b015d9a
commit dfe1c83c80
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
42 changed files with 1550 additions and 1484 deletions

View File

@ -1,6 +1,7 @@
package de.mm20.launcher2.ui.launcher.sheets
import WidgetsService
import android.app.Application
import android.appwidget.AppWidgetProviderInfo
import android.content.Context
import android.content.pm.PackageManager
@ -10,6 +11,7 @@ import androidx.compose.material.icons.rounded.Star
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
@ -32,11 +34,9 @@ import org.koin.core.component.get
class WidgetPickerSheetVM(
private val widgetsService: WidgetsService,
private val context: Context,
private val packageManager: PackageManager,
) : ViewModel() {
private val packageManager = context.packageManager
val searchQuery = MutableStateFlow("")
private val enabledWidgets = widgetsService.getWidgets()

View File

@ -23,10 +23,9 @@ import de.mm20.launcher2.ui.locals.LocalCardStyle
import de.mm20.launcher2.ui.locals.LocalNavController
import de.mm20.launcher2.ui.locals.LocalWallpaperColors
import de.mm20.launcher2.ui.settings.about.AboutSettingsScreen
import de.mm20.launcher2.ui.settings.accounts.AccountsSettingsScreen
import de.mm20.launcher2.ui.settings.integrations.IntegrationsSettingsScreen
import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
import de.mm20.launcher2.ui.settings.badges.BadgeSettingsScreen
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
import de.mm20.launcher2.ui.settings.calendarwidget.CalendarWidgetSettingsScreen
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
@ -41,17 +40,17 @@ import de.mm20.launcher2.ui.settings.favorites.FavoritesSettingsScreen
import de.mm20.launcher2.ui.settings.filesearch.FileSearchSettingsScreen
import de.mm20.launcher2.ui.settings.gestures.GestureSettingsScreen
import de.mm20.launcher2.ui.settings.hiddenitems.HiddenItemsSettingsScreen
import de.mm20.launcher2.ui.settings.layout.LayoutSettingsScreen
import de.mm20.launcher2.ui.settings.homescreen.HomescreenSettingsScreen
import de.mm20.launcher2.ui.settings.icons.IconsSettingsScreen
import de.mm20.launcher2.ui.settings.license.LicenseScreen
import de.mm20.launcher2.ui.settings.log.LogScreen
import de.mm20.launcher2.ui.settings.main.MainSettingsScreen
import de.mm20.launcher2.ui.settings.musicwidget.MusicWidgetSettingsScreen
import de.mm20.launcher2.ui.settings.media.MediaIntegrationSettingsScreen
import de.mm20.launcher2.ui.settings.search.SearchSettingsScreen
import de.mm20.launcher2.ui.settings.searchactions.SearchActionsSettingsScreen
import de.mm20.launcher2.ui.settings.tags.TagsSettingsScreen
import de.mm20.launcher2.ui.settings.unitconverter.UnitConverterSettingsScreen
import de.mm20.launcher2.ui.settings.weatherwidget.WeatherWidgetSettingsScreen
import de.mm20.launcher2.ui.settings.widgets.WidgetsSettingsScreen
import de.mm20.launcher2.ui.settings.weather.WeatherIntegrationSettingsScreen
import de.mm20.launcher2.ui.settings.wikipedia.WikipediaSettingsScreen
import de.mm20.launcher2.ui.theme.LauncherTheme
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
@ -101,8 +100,11 @@ class SettingsActivity : BaseActivity() {
composable("settings/appearance") {
AppearanceSettingsScreen()
}
composable("settings/appearance/layout") {
LayoutSettingsScreen()
composable("settings/homescreen") {
HomescreenSettingsScreen()
}
composable("settings/icons") {
IconsSettingsScreen()
}
composable("settings/appearance/colorscheme") {
ColorSchemeSettingsScreen()
@ -137,29 +139,23 @@ class SettingsActivity : BaseActivity() {
composable("settings/search/tags") {
TagsSettingsScreen()
}
composable("settings/widgets") {
WidgetsSettingsScreen()
composable("settings/integrations/weather") {
WeatherIntegrationSettingsScreen()
}
composable("settings/widgets/weather") {
WeatherWidgetSettingsScreen()
}
composable("settings/widgets/music") {
MusicWidgetSettingsScreen()
composable("settings/integrations/media") {
MediaIntegrationSettingsScreen()
}
composable("settings/widgets/calendar") {
CalendarWidgetSettingsScreen()
}
composable("settings/widgets/clock") {
composable("settings/homescreen/clock") {
ClockWidgetSettingsScreen()
}
composable("settings/favorites") {
FavoritesSettingsScreen()
}
composable("settings/badges") {
BadgeSettingsScreen()
}
composable("settings/accounts") {
AccountsSettingsScreen()
composable("settings/integrations") {
IntegrationsSettingsScreen()
}
composable("settings/about") {
AboutSettingsScreen()

View File

@ -86,13 +86,6 @@ fun AppearanceSettingsScreen() {
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
item {
PreferenceCategory {
Preference(
title = stringResource(id = R.string.preference_layout),
summary = stringResource(id = R.string.preference_layout_summary),
onClick = {
navController?.navigate("settings/appearance/layout")
}
)
val theme by viewModel.theme.observeAsState()
ListPreference(
title = stringResource(id = R.string.preference_theme),
@ -147,466 +140,6 @@ fun AppearanceSettingsScreen() {
}
)
}
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
val iconSize by viewModel.iconSize.observeAsState(48)
SliderPreference(
title = stringResource(R.string.preference_grid_icon_size),
value = iconSize,
step = 8,
min = 32,
max = 64,
onValueChanged = {
viewModel.setIconSize(it)
}
)
val showLabels by viewModel.showLabels.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_grid_labels),
summary = stringResource(R.string.preference_grid_labels_summary),
value = showLabels == true,
onValueChanged = {
viewModel.setShowLabels(it)
}
)
val columnCount by viewModel.columnCount.observeAsState(5)
SliderPreference(
title = stringResource(R.string.preference_grid_column_count),
value = columnCount,
min = 3,
max = 8,
onValueChanged = {
viewModel.setColumnCount(it)
}
)
}
PreferenceCategory(stringResource(id = R.string.preference_category_wallpaper)) {
Preference(
title = stringResource(R.string.wallpaper),
summary = stringResource(R.string.preference_wallpaper_summary),
onClick = {
viewModel.openWallpaperChooser(context as AppCompatActivity)
}
)
val dimWallpaper by viewModel.dimWallpaper.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_dim_wallpaper),
summary = stringResource(R.string.preference_dim_wallpaper_summary),
value = dimWallpaper == true,
onValueChanged = {
viewModel.setDimWallpaper(it)
}
)
val isBlurSupported = remember { viewModel.isBlurAvailable(context) }
if (isBlurSupported) {
val blurWallpaper by viewModel.blurWallpaper.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_blur_wallpaper),
summary = stringResource(
if (isBlurSupported) R.string.preference_blur_wallpaper_summary
else R.string.preference_blur_wallpaper_unsupported
),
value = blurWallpaper == true && isBlurSupported,
onValueChanged = {
viewModel.setBlurWallpaper(it)
},
enabled = isBlurSupported
)
}
}
PreferenceCategory(stringResource(R.string.preference_category_icons)) {
val iconShape by viewModel.iconShape.observeAsState(IconSettings.IconShape.PlatformDefault)
IconShapePreference(
title = stringResource(R.string.preference_icon_shape),
summary = getShapeName(iconShape),
value = iconShape,
onValueChanged = {
viewModel.setIconShape(it)
}
)
val adaptifyLegacyIcons by viewModel.adaptifyLegacyIcons.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_enforce_icon_shape),
summary = stringResource(R.string.preference_enforce_icon_shape_summary),
value = adaptifyLegacyIcons == true,
onValueChanged = {
viewModel.setAdaptifyLegacyIcons(it)
}
)
val themedIcons by viewModel.themedIcons.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_themed_icons),
summary = stringResource(R.string.preference_themed_icons_summary),
value = themedIcons == true,
onValueChanged = {
viewModel.setThemedIcons(it)
}
)
val forceThemedIcons by viewModel.forceThemedIcons.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_force_themed_icons),
summary = stringResource(R.string.preference_force_themed_icons_summary),
value = forceThemedIcons == true,
enabled = themedIcons == true,
onValueChanged = {
viewModel.setForceThemedIcons(it)
}
)
val iconPackPackage by viewModel.iconPack.observeAsState()
val iconPackThemed by viewModel.iconPackThemed.collectAsState(true)
val installedIconPacks by viewModel.installedIconPacks.collectAsState(emptyList())
val iconPack by remember {
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == iconPackPackage } }
}
val items = installedIconPacks.map {
it.name to it
}
Row(
verticalAlignment = (Alignment.CenterVertically)
) {
Box(
modifier = Modifier.weight(1f)
) {
ListPreference(
title = stringResource(R.string.preference_icon_pack),
items = items,
summary = if (items.size <= 1) {
stringResource(R.string.preference_icon_pack_summary_empty)
} else {
iconPack?.name ?: "System"
},
enabled = installedIconPacks.size > 1,
value = iconPack,
onValueChanged = {
if (it != null) viewModel.setIconPack(it.packageName)
},
itemLabel = {
Column(
verticalArrangement = Arrangement.Center,
) {
Text(
text = it.label,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
if (it.value?.themed == true) {
Surface(
shape = MaterialTheme.shapes.extraSmall,
color = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.padding(top = 4.dp)
) {
Row(
modifier = Modifier.padding(horizontal = 4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
modifier = Modifier
.size(20.dp)
.padding(end = 4.dp),
imageVector = Icons.Rounded.FormatPaint,
contentDescription = null,
)
Text(
text = stringResource(R.string.icon_pack_dynamic_colors),
style = MaterialTheme.typography.labelSmall
)
}
}
}
}
}
)
}
if (iconPack?.themed == true) {
Box(
modifier = Modifier
.height(36.dp)
.width(1.dp)
.alpha(0.38f)
.background(LocalContentColor.current)
)
Box(
modifier = Modifier
.padding(12.dp)
) {
PlainTooltipBox(tooltip = { Text(stringResource(R.string.icon_pack_dynamic_colors)) }) {
FilledIconToggleButton(
modifier = Modifier.tooltipAnchor(),
checked = iconPackThemed,
onCheckedChange = {
viewModel.setIconPackThemed(it)
}) {
Icon(
Icons.Rounded.FormatPaint,
stringResource(R.string.icon_pack_dynamic_colors)
)
}
}
}
}
}
}
PreferenceCategory(stringResource(R.string.preference_category_searchbar)) {
val searchBarStyle by viewModel.searchBarStyle.observeAsState()
SearchBarStylePreference(
title = stringResource(R.string.preference_search_bar_style),
summary = stringResource(R.string.preference_search_bar_style_summary),
value = searchBarStyle,
onValueChanged = {
viewModel.setSearchBarStyle(it)
}
)
AnimatedVisibility(searchBarStyle == SearchBarStyle.Transparent) {
val searchBarColor by viewModel.searchBarColor.observeAsState()
ListPreference(
title = stringResource(R.string.preference_search_bar_color),
value = searchBarColor,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to SearchBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to SearchBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to SearchBarColors.Dark,
),
onValueChanged = {
if (it != null) viewModel.setSearchBarColor(it)
}
)
}
}
PreferenceCategory(stringResource(R.string.preference_category_system_bars)) {
val lightStatusBar by viewModel.statusBarIcons.observeAsState()
ListPreference(
title = stringResource(R.string.preference_status_bar_icons),
value = lightStatusBar,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
),
onValueChanged = {
if (it != null) viewModel.setLightStatusBar(it)
}
)
val lightNavBar by viewModel.navBarIcons.observeAsState()
ListPreference(
title = stringResource(R.string.preference_nav_bar_icons),
value = lightNavBar,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to SystemBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to SystemBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to SystemBarColors.Dark,
),
onValueChanged = {
if (it != null) viewModel.setLightNavBar(it)
}
)
val hideStatusBar by viewModel.hideStatusBar.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_hide_status_bar),
value = hideStatusBar == true,
onValueChanged = {
viewModel.setHideStatusBar(it)
}
)
val hideNavBar by viewModel.hideNavBar.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_hide_nav_bar),
value = hideNavBar == true,
onValueChanged = {
viewModel.setHideNavBar(it)
}
)
}
}
}
}
@Composable
fun SearchBarStylePreference(
title: String,
summary: String? = null,
value: SearchBarSettings.SearchBarStyle?,
onValueChanged: (SearchBarSettings.SearchBarStyle) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
Preference(title = title, summary = summary, onClick = { showDialog = true })
if (showDialog && value != null) {
val styles = remember {
SearchBarSettings.SearchBarStyle.values()
.filter { it != SearchBarSettings.SearchBarStyle.UNRECOGNIZED }
}
val pagerState = rememberPagerState(styles.indexOf(value))
var level by remember { mutableStateOf(SearchBarLevel.Resting) }
var previewSearchValue by remember { mutableStateOf("") }
LaunchedEffect(null) {
while (isActive) {
delay(2000)
level = SearchBarLevel.Active
delay(1000)
previewSearchValue = "A"
delay(100)
previewSearchValue = "AB"
delay(100)
previewSearchValue = "ABC"
delay(800)
level = SearchBarLevel.Raised
delay(2000)
level = SearchBarLevel.Resting
previewSearchValue = ""
}
}
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(
count = styles.size,
state = pagerState,
modifier = Modifier
.height(150.dp)
.padding(bottom = 16.dp)
.background(MaterialTheme.colorScheme.secondary)
) {
SearchBar(
modifier = Modifier.padding(8.dp),
level = level,
style = styles[it],
value = previewSearchValue,
onValueChange = {}
)
}
HorizontalPagerIndicator(pagerState = pagerState)
}
}
)
}
}
@Composable
fun IconShapePreference(
title: String,
summary: String? = null,
value: IconSettings.IconShape?,
onValueChanged: (IconSettings.IconShape) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
Preference(title = title, summary = summary, onClick = { showDialog = true })
if (showDialog && value != null) {
val shapes = remember {
IconSettings.IconShape.values()
.filter { it != IconSettings.IconShape.UNRECOGNIZED && it != IconSettings.IconShape.EasterEgg }
}
Dialog(onDismissRequest = { showDialog = false }) {
Surface(
tonalElevation = 16.dp,
shadowElevation = 16.dp,
shape = MaterialTheme.shapes.extraLarge,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(
start = 24.dp, end = 24.dp, top = 16.dp, bottom = 8.dp
)
)
LazyVerticalGrid(
columns = GridCells.Adaptive(96.dp),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp, start = 16.dp, end = 16.dp)
) {
items(shapes) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
val context = LocalContext.current
ShapedLauncherIcon(
size = 48.dp,
icon = {
StaticLauncherIcon(
foregroundLayer = StaticIconLayer(
icon = ContextCompat.getDrawable(
context,
R.mipmap.ic_launcher_foreground
)!!,
scale = 1.5f,
),
backgroundLayer = StaticIconLayer(
icon = ColorDrawable(
context.getColor(R.color.ic_launcher_background)
)
)
)
},
onClick = {
onValueChanged(it)
showDialog = false
},
shape = getShape(it)
)
Text(
getShapeName(it) ?: "",
textAlign = TextAlign.Center,
style = MaterialTheme.typography.labelMedium,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
}
}
}
}
}
@Composable
private fun getShapeName(shape: IconSettings.IconShape?): String? {
return stringResource(
when (shape) {
IconSettings.IconShape.Triangle -> R.string.preference_icon_shape_triangle
IconSettings.IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
IconSettings.IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
IconSettings.IconShape.Squircle -> R.string.preference_icon_shape_squircle
IconSettings.IconShape.Square -> R.string.preference_icon_shape_square
IconSettings.IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
IconSettings.IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
IconSettings.IconShape.Circle -> R.string.preference_icon_shape_circle
IconSettings.IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
IconSettings.IconShape.Pebble -> R.string.preference_icon_shape_pebble
else -> return null
}
)
}

View File

@ -62,248 +62,4 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
}
}
}
val columnCount = dataStore.data.map { it.grid.columnCount }.asLiveData()
fun setColumnCount(columnCount: Int) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setGrid(it.grid.toBuilder().setColumnCount(columnCount))
.build()
}
}
}
val iconSize = dataStore.data.map { it.grid.iconSize }.asLiveData()
fun setIconSize(iconSize: Int) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setGrid(it.grid.toBuilder().setIconSize(iconSize))
.build()
}
}
}
val showLabels = dataStore.data.map { it.grid.showLabels }.asLiveData()
fun setShowLabels(showLabels: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setGrid(it.grid.toBuilder().setShowLabels(showLabels))
.build()
}
}
}
val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }.asLiveData()
fun setDimWallpaper(dimWallpaper: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setAppearance(it.appearance.toBuilder().setDimWallpaper(dimWallpaper))
.build()
}
}
}
fun isBlurAvailable(context: Context): Boolean {
if (!isAtLeastApiLevel(31)) return false
return context.getSystemService<WindowManager>()?.isCrossWindowBlurEnabled == true
}
val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper }.asLiveData()
fun setBlurWallpaper(blurWallpaper: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setAppearance(it.appearance.toBuilder().setBlurWallpaper(blurWallpaper))
.build()
}
}
}
fun openWallpaperChooser(context: AppCompatActivity) {
context.startActivity(Intent.createChooser(Intent(Intent.ACTION_SET_WALLPAPER), null))
}
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }.asLiveData()
fun setSearchBarStyle(searchBarStyle: SearchBarSettings.SearchBarStyle) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSearchBar(
it.searchBar.toBuilder()
.setSearchBarStyle(searchBarStyle)
)
.build()
}
}
}
val iconShape = dataStore.data.map { it.icons.shape }.asLiveData()
fun setIconShape(iconShape: Settings.IconSettings.IconShape) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setShape(iconShape)
)
.build()
}
}
}
val adaptifyLegacyIcons = dataStore.data.map { it.icons.adaptify }.asLiveData()
fun setAdaptifyLegacyIcons(adaptify: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setAdaptify(adaptify)
)
.build()
}
}
}
val themedIcons = dataStore.data.map { it.icons.themedIcons }.asLiveData()
fun setThemedIcons(themedIcons: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setThemedIcons(themedIcons)
)
.build()
}
}
}
val forceThemedIcons = dataStore.data.map { it.icons.forceThemed }.asLiveData()
fun setForceThemedIcons(forceThemedIcons: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setForceThemed(forceThemedIcons)
)
.build()
}
}
}
val installedIconPacks: Flow<List<IconPack>> = iconService.getInstalledIconPacks().map {
listOf(
IconPack(
name = "System",
packageName = "",
version = "",
)
) + it
}
val iconPackThemed = dataStore.data.map { it.icons.iconPackThemed }
fun setIconPackThemed(iconPackThemed: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons
.toBuilder()
.setIconPackThemed(iconPackThemed)
)
.build()
}
}
}
val iconPack = dataStore.data.map { it.icons.iconPack }.asLiveData()
fun setIconPack(iconPack: String) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setIconPack(iconPack)
)
.build()
}
}
}
val searchBarColor = dataStore.data.map { it.searchBar.color }.asLiveData()
fun setSearchBarColor(color: SearchBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSearchBar(
it.searchBar.toBuilder()
.setColor(color)
)
.build()
}
}
}
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }.asLiveData()
fun setLightStatusBar(statusBarColor: SystemBarsSettings.SystemBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setStatusBarColor(statusBarColor)
)
.build()
}
}
}
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }.asLiveData()
fun setLightNavBar(navBarColors: SystemBarsSettings.SystemBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setNavBarColor(navBarColors)
)
.build()
}
}
}
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }.asLiveData()
fun setHideStatusBar(hideStatusBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setHideStatusBar(hideStatusBar)
)
.build()
}
}
}
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }.asLiveData()
fun setHideNavBar(hideNavBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setHideNavBar(hideNavBar)
)
.build()
}
}
}
}

View File

@ -1,77 +0,0 @@
package de.mm20.launcher2.ui.settings.badges
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.MissingPermissionBanner
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
@Composable
fun BadgeSettingsScreen() {
val viewModel: BadgeSettingsScreenVM = viewModel()
val context = LocalContext.current
PreferenceScreen(title = stringResource(R.string.preference_screen_badges)) {
item {
PreferenceCategory {
val notifications by viewModel.notifications.observeAsState()
val hasNotificationsPermission by viewModel.hasNotificationsPermission.observeAsState()
AnimatedVisibility(hasNotificationsPermission == false) {
MissingPermissionBanner(
text = stringResource(R.string.missing_permission_notification_badges),
onClick = {
viewModel.requestNotificationsPermission(context as AppCompatActivity)
},
modifier = Modifier.padding(16.dp)
)
}
SwitchPreference(
title = stringResource(R.string.preference_notification_badges),
summary = stringResource(R.string.preference_notification_badges_summary),
enabled = hasNotificationsPermission != false,
value = notifications == true && hasNotificationsPermission == true,
onValueChanged = {
viewModel.setNotifications(it)
}
)
val cloudFiles by viewModel.cloudFiles.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_cloud_badges),
summary = stringResource(R.string.preference_cloud_badges_summary),
value = cloudFiles == true,
onValueChanged = {
viewModel.setCloudFiles(it)
}
)
val suspendedApps by viewModel.suspendedApps.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_suspended_badges),
summary = stringResource(R.string.preference_suspended_badges_summary),
value = suspendedApps == true,
onValueChanged = {
viewModel.setSuspendedApps(it)
}
)
val shortcuts by viewModel.shortcuts.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_shortcut_badges),
summary = stringResource(R.string.preference_shortcut_badges_summary),
value = shortcuts == true,
onValueChanged = {
viewModel.setShortcuts(it)
}
)
}
}
}
}

View File

@ -1,81 +0,0 @@
package de.mm20.launcher2.ui.settings.badges
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class BadgeSettingsScreenVM : ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject()
private val permissionsManager: PermissionsManager by inject()
val hasNotificationsPermission = permissionsManager.hasPermission(PermissionGroup.Notifications).asLiveData()
val notifications = dataStore.data.map { it.badges.notifications }.asLiveData()
fun setNotifications(notifications: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setNotifications(notifications)
)
.build()
}
}
}
fun requestNotificationsPermission(context: AppCompatActivity) {
permissionsManager.requestPermission(context, PermissionGroup.Notifications)
}
val cloudFiles = dataStore.data.map { it.badges.cloudFiles }.asLiveData()
fun setCloudFiles(cloudFiles: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setCloudFiles(cloudFiles)
)
.build()
}
}
}
val shortcuts = dataStore.data.map { it.badges.shortcuts }.asLiveData()
fun setShortcuts(shortcuts: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setShortcuts(shortcuts)
)
.build()
}
}
}
val suspendedApps = dataStore.data.map { it.badges.suspendedApps }.asLiveData()
fun setSuspendedApps(suspendedApps: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setSuspendedApps(suspendedApps)
)
.build()
}
}
}
}

View File

@ -24,6 +24,7 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.isAtLeastApiLevel
@ -35,7 +36,6 @@ import de.mm20.launcher2.ui.common.SearchablePicker
import de.mm20.launcher2.ui.component.MissingPermissionBanner
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
import de.mm20.launcher2.ui.component.preferences.ListPreference
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.ktx.toPixels
@ -44,8 +44,8 @@ import de.mm20.launcher2.ui.ktx.toPixels
fun GestureSettingsScreen() {
val viewModel: GestureSettingsScreenVM = viewModel()
val layout by viewModel.layout.observeAsState()
val hasPermission by viewModel.hasPermission.observeAsState()
val layout by viewModel.baseLayout.collectAsStateWithLifecycle(null)
val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null)
val options = buildList {
add(stringResource(R.string.gesture_action_none) to GestureAction.None)
@ -60,10 +60,26 @@ fun GestureSettingsScreen() {
val context = LocalContext.current
PreferenceScreen(title = stringResource(R.string.preference_screen_gestures)) {
item {
PreferenceCategory {
val baseLayout by viewModel.baseLayout.collectAsStateWithLifecycle(null)
ListPreference(title = stringResource(R.string.preference_layout_open_search),
items = listOf(
stringResource(R.string.open_search_pull_down) to Layout.PullDown,
stringResource(R.string.open_search_swipe_left) to Layout.Pager,
stringResource(R.string.open_search_swipe_right) to Layout.PagerReversed,
),
value = baseLayout,
onValueChanged = {
if (it != null) viewModel.setBaseLayout(it)
},
)
}
}
item {
val appIconSize = 32.dp.toPixels()
PreferenceCategory {
val doubleTap by viewModel.doubleTap.observeAsState()
val doubleTap by viewModel.doubleTap.collectAsStateWithLifecycle(null)
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(doubleTap)) {
MissingPermissionBanner(
modifier = Modifier.padding(16.dp),
@ -86,7 +102,7 @@ fun GestureSettingsScreen() {
onAppChanged = { viewModel.setDoubleTapApp(it) }
)
val longPress by viewModel.longPress.observeAsState()
val longPress by viewModel.longPress.collectAsStateWithLifecycle(null)
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(longPress)) {
MissingPermissionBanner(
modifier = Modifier.padding(16.dp),
@ -109,7 +125,7 @@ fun GestureSettingsScreen() {
onAppChanged = { viewModel.setLongPressApp(it) }
)
val swipeDown by viewModel.swipeDown.observeAsState()
val swipeDown by viewModel.swipeDown.collectAsStateWithLifecycle(null)
val swipeDownIsSearch = layout == Layout.PullDown
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeDown) && !swipeDownIsSearch) {
MissingPermissionBanner(
@ -133,7 +149,7 @@ fun GestureSettingsScreen() {
onAppChanged = { viewModel.setSwipeDownApp(it) }
)
val swipeLeft by viewModel.swipeLeft.observeAsState()
val swipeLeft by viewModel.swipeLeft.collectAsStateWithLifecycle(null)
val swipeLeftIsSearch = layout == Layout.Pager
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeLeft) && !swipeLeftIsSearch) {
MissingPermissionBanner(
@ -157,7 +173,7 @@ fun GestureSettingsScreen() {
onAppChanged = { viewModel.setSwipeLeftApp(it) }
)
val swipeRight by viewModel.swipeRight.observeAsState()
val swipeRight by viewModel.swipeRight.collectAsStateWithLifecycle(null)
val swipeRightIsSearch = layout == Layout.PagerReversed
AnimatedVisibility(hasPermission == false && requiresAccessibilityService(swipeRight) && !swipeRightIsSearch) {
MissingPermissionBanner(

View File

@ -10,6 +10,7 @@ import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.GestureSettings.GestureAction
import de.mm20.launcher2.search.SavableSearchable
import kotlinx.coroutines.flow.Flow
@ -27,15 +28,25 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
private val searchableRepository: SearchableRepository by inject()
private val iconService: IconService by inject()
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility).asLiveData()
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
val layout = dataStore.data.map { it.layout.baseLayout }.asLiveData()
val baseLayout = dataStore.data.map { it.layout.baseLayout }
val swipeDown = dataStore.data.map { it.gestures.swipeDown }.asLiveData()
val swipeLeft = dataStore.data.map { it.gestures.swipeLeft }.asLiveData()
val swipeRight = dataStore.data.map { it.gestures.swipeRight }.asLiveData()
val doubleTap = dataStore.data.map { it.gestures.doubleTap }.asLiveData()
val longPress = dataStore.data.map { it.gestures.longPress }.asLiveData()
fun setBaseLayout(baseLayout: Settings.LayoutSettings.Layout) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setBaseLayout(baseLayout))
.build()
}
}
}
val swipeDown = dataStore.data.map { it.gestures.swipeDown }
val swipeLeft = dataStore.data.map { it.gestures.swipeLeft }
val swipeRight = dataStore.data.map { it.gestures.swipeRight }
val doubleTap = dataStore.data.map { it.gestures.doubleTap }
val longPress = dataStore.data.map { it.gestures.longPress }
fun setSwipeDown(action: GestureAction) {
viewModelScope.launch {

View File

@ -0,0 +1,303 @@
package de.mm20.launcher2.ui.settings.homescreen
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.pager.HorizontalPagerIndicator
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.SearchBar
import de.mm20.launcher2.ui.component.SearchBarLevel
import de.mm20.launcher2.ui.component.preferences.ListPreference
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.locals.LocalNavController
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
@Composable
fun HomescreenSettingsScreen() {
val viewModel: HomescreenSettingsScreenVM =
viewModel(factory = HomescreenSettingsScreenVM.Factory)
val navController = LocalNavController.current
val context = LocalContext.current
val fixedRotation by viewModel.fixedRotation.collectAsStateWithLifecycle(null)
val editButton by viewModel.widgetEditButton.collectAsStateWithLifecycle(null)
val searchBarStyle by viewModel.searchBarStyle.collectAsStateWithLifecycle(null)
val searchBarColor by viewModel.searchBarColor.collectAsStateWithLifecycle(null)
val bottomSearchBar by viewModel.bottomSearchBar.collectAsStateWithLifecycle(null)
val fixedSearchBar by viewModel.fixedSearchBar.collectAsStateWithLifecycle(null)
val lightStatusBar by viewModel.statusBarIcons.collectAsStateWithLifecycle(null)
val dimWallpaper by viewModel.dimWallpaper.collectAsStateWithLifecycle(false)
val blurWallpaper by viewModel.blurWallpaper.collectAsStateWithLifecycle(false)
val lightNavBar by viewModel.navBarIcons.collectAsStateWithLifecycle(null)
val hideStatusBar by viewModel.hideStatusBar.collectAsStateWithLifecycle(null)
val hideNavBar by viewModel.hideNavBar.collectAsStateWithLifecycle(null)
PreferenceScreen(title = stringResource(id = R.string.preference_screen_homescreen)) {
item {
PreferenceCategory {
SwitchPreference(
title = stringResource(R.string.preference_layout_fixed_rotation),
summary = stringResource(R.string.preference_layout_fixed_rotation_summary),
value = fixedRotation == true,
onValueChanged = {
viewModel.setFixedRotation(it)
},
)
}
}
item {
PreferenceCategory(
title = stringResource(id = R.string.preference_category_widgets)
) {
Preference(
title = stringResource(R.string.preference_screen_clockwidget),
summary = stringResource(R.string.preference_screen_clockwidget_summary),
onClick = {
navController?.navigate("settings/homescreen/clock")
}
)
SwitchPreference(
title = stringResource(id = R.string.preference_edit_button),
summary = stringResource(id = R.string.preference_widgets_edit_button_summary),
value = editButton == true,
onValueChanged = {
viewModel.setWidgetEditButton(it)
})
}
}
item {
PreferenceCategory(stringResource(R.string.preference_category_searchbar)) {
SearchBarStylePreference(
title = stringResource(R.string.preference_search_bar_style),
summary = stringResource(R.string.preference_search_bar_style_summary),
value = searchBarStyle,
onValueChanged = {
viewModel.setSearchBarStyle(it)
}
)
AnimatedVisibility(searchBarStyle == Settings.SearchBarSettings.SearchBarStyle.Transparent) {
ListPreference(
title = stringResource(R.string.preference_search_bar_color),
value = searchBarColor,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SearchBarSettings.SearchBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to Settings.SearchBarSettings.SearchBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SearchBarSettings.SearchBarColors.Dark,
),
onValueChanged = {
if (it != null) viewModel.setSearchBarColor(it)
}
)
}
ListPreference(
title = stringResource(R.string.preference_layout_search_bar_position),
items = listOf(
stringResource(R.string.search_bar_position_top) to false,
stringResource(R.string.search_bar_position_bottom) to true,
),
value = bottomSearchBar,
onValueChanged = {
if (it != null) viewModel.setBottomSearchBar(it)
},
)
SwitchPreference(
title = stringResource(R.string.preference_layout_fixed_search_bar),
summary = stringResource(R.string.preference_layout_fixed_search_bar_summary),
value = fixedSearchBar == true,
onValueChanged = {
viewModel.setFixedSearchBar(it)
},
)
}
}
item {
PreferenceCategory(stringResource(id = R.string.preference_category_wallpaper)) {
Preference(
title = stringResource(R.string.wallpaper),
summary = stringResource(R.string.preference_wallpaper_summary),
onClick = {
viewModel.openWallpaperChooser(context as AppCompatActivity)
}
)
SwitchPreference(
title = stringResource(R.string.preference_dim_wallpaper),
summary = stringResource(R.string.preference_dim_wallpaper_summary),
value = dimWallpaper,
onValueChanged = {
viewModel.setDimWallpaper(it)
}
)
val isBlurSupported = remember { viewModel.isBlurAvailable(context) }
SwitchPreference(
title = stringResource(R.string.preference_blur_wallpaper),
summary = stringResource(
if (isBlurSupported) R.string.preference_blur_wallpaper_summary
else R.string.preference_blur_wallpaper_unsupported
),
value = blurWallpaper && isBlurSupported,
onValueChanged = {
viewModel.setBlurWallpaper(it)
},
enabled = isBlurSupported
)
}
}
item {
PreferenceCategory(stringResource(R.string.preference_category_system_bars)) {
ListPreference(
title = stringResource(R.string.preference_status_bar_icons),
value = lightStatusBar,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
),
onValueChanged = {
if (it != null) viewModel.setLightStatusBar(it)
}
)
ListPreference(
title = stringResource(R.string.preference_nav_bar_icons),
value = lightNavBar,
items = listOf(
stringResource(R.string.preference_system_bar_icons_auto) to Settings.SystemBarsSettings.SystemBarColors.Auto,
stringResource(R.string.preference_system_bar_icons_light) to Settings.SystemBarsSettings.SystemBarColors.Light,
stringResource(R.string.preference_system_bar_icons_dark) to Settings.SystemBarsSettings.SystemBarColors.Dark,
),
onValueChanged = {
if (it != null) viewModel.setLightNavBar(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_hide_status_bar),
value = hideStatusBar == true,
onValueChanged = {
viewModel.setHideStatusBar(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_hide_nav_bar),
value = hideNavBar == true,
onValueChanged = {
viewModel.setHideNavBar(it)
}
)
}
}
}
}
@Composable
fun SearchBarStylePreference(
title: String,
summary: String? = null,
value: Settings.SearchBarSettings.SearchBarStyle?,
onValueChanged: (Settings.SearchBarSettings.SearchBarStyle) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
Preference(title = title, summary = summary, onClick = { showDialog = true })
if (showDialog && value != null) {
val styles = remember {
Settings.SearchBarSettings.SearchBarStyle.values()
.filter { it != Settings.SearchBarSettings.SearchBarStyle.UNRECOGNIZED }
}
val pagerState = rememberPagerState(styles.indexOf(value))
var level by remember { mutableStateOf(SearchBarLevel.Resting) }
var previewSearchValue by remember { mutableStateOf("") }
LaunchedEffect(null) {
while (isActive) {
delay(2000)
level = SearchBarLevel.Active
delay(1000)
previewSearchValue = "A"
delay(100)
previewSearchValue = "AB"
delay(100)
previewSearchValue = "ABC"
delay(800)
level = SearchBarLevel.Raised
delay(2000)
level = SearchBarLevel.Resting
previewSearchValue = ""
}
}
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(
pageCount = styles.size,
state = pagerState,
modifier = Modifier
.height(150.dp)
.padding(bottom = 16.dp)
.background(MaterialTheme.colorScheme.secondary)
) {
SearchBar(
modifier = Modifier.padding(8.dp),
level = level,
style = styles[it],
value = previewSearchValue,
onValueChange = {}
)
}
HorizontalPagerIndicator(pagerState = pagerState, pageCount = styles.size)
}
}
)
}
}

View File

@ -0,0 +1,204 @@
package de.mm20.launcher2.ui.settings.homescreen
import android.content.Context
import android.content.Intent
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
class HomescreenSettingsScreenVM(
private val dataStore: LauncherDataStore,
) : ViewModel() {
val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }
fun setDimWallpaper(dimWallpaper: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setAppearance(
it.appearance.toBuilder()
.setDimWallpaper(dimWallpaper)
).build()
}
}
}
val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper }
fun setBlurWallpaper(blurWallpaper: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setAppearance(
it.appearance.toBuilder()
.setBlurWallpaper(blurWallpaper)
).build()
}
}
}
fun openWallpaperChooser(context: AppCompatActivity) {
context.startActivity(Intent.createChooser(Intent(Intent.ACTION_SET_WALLPAPER), null))
}
fun isBlurAvailable(context: Context): Boolean {
if (!isAtLeastApiLevel(31)) return false
return context.getSystemService<WindowManager>()?.isCrossWindowBlurEnabled == true
}
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }
fun setLightStatusBar(statusBarColor: Settings.SystemBarsSettings.SystemBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setStatusBarColor(statusBarColor)
)
.build()
}
}
}
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }
fun setLightNavBar(navBarColors: Settings.SystemBarsSettings.SystemBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setNavBarColor(navBarColors)
)
.build()
}
}
}
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
fun setHideStatusBar(hideStatusBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setHideStatusBar(hideStatusBar)
)
.build()
}
}
}
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
fun setHideNavBar(hideNavBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSystemBars(
it.systemBars.toBuilder()
.setHideNavBar(hideNavBar)
)
.build()
}
}
}
val searchBarColor = dataStore.data.map { it.searchBar.color }
fun setSearchBarColor(color: Settings.SearchBarSettings.SearchBarColors) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSearchBar(
it.searchBar.toBuilder()
.setColor(color)
)
.build()
}
}
}
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
fun setSearchBarStyle(searchBarStyle: Settings.SearchBarSettings.SearchBarStyle) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setSearchBar(
it.searchBar.toBuilder()
.setSearchBarStyle(searchBarStyle)
)
.build()
}
}
}
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
fun setFixedSearchBar(fixedSearchBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setFixedSearchBar(fixedSearchBar))
.build()
}
}
}
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
fun setBottomSearchBar(bottomSearchBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setBottomSearchBar(bottomSearchBar))
.build()
}
}
}
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
fun setFixedRotation(fixedRotation: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setFixedRotation(fixedRotation))
.build()
}
}
}
val widgetEditButton = dataStore.data.map { it.widgets.editButton }
fun setWidgetEditButton(editButton: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setWidgets(
it.widgets.toBuilder()
.setEditButton(editButton)
)
.build()
}
}
}
companion object : KoinComponent {
val Factory = viewModelFactory {
initializer {
HomescreenSettingsScreenVM(
dataStore = get()
)
}
}
}
}

View File

@ -0,0 +1,406 @@
package de.mm20.launcher2.ui.settings.icons
import android.graphics.drawable.ColorDrawable
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.FormatPaint
import androidx.compose.material3.FilledIconToggleButton
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PlainTooltipBox
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.icons.StaticIconLayer
import de.mm20.launcher2.icons.StaticLauncherIcon
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.MissingPermissionBanner
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
import de.mm20.launcher2.ui.component.getShape
import de.mm20.launcher2.ui.component.preferences.ListPreference
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SliderPreference
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.component.preferences.label
import de.mm20.launcher2.ui.component.preferences.value
@Composable
fun IconsSettingsScreen() {
val viewModel: IconsSettingsScreenVM = viewModel(factory = IconsSettingsScreenVM.Factory)
val context = LocalContext.current
val iconSize by viewModel.iconSize.collectAsStateWithLifecycle(48)
val showLabels by viewModel.showLabels.collectAsStateWithLifecycle(null)
val columnCount by viewModel.columnCount.collectAsStateWithLifecycle(5)
val iconShape by viewModel.iconShape.collectAsStateWithLifecycle(Settings.IconSettings.IconShape.PlatformDefault)
val adaptifyLegacyIcons by viewModel.adaptifyLegacyIcons.collectAsStateWithLifecycle(null)
val themedIcons by viewModel.themedIcons.collectAsStateWithLifecycle(null)
val iconPackPackage by viewModel.iconPack.collectAsStateWithLifecycle(null)
val iconPackThemed by viewModel.iconPackThemed.collectAsState(true)
val installedIconPacks by viewModel.installedIconPacks.collectAsState(emptyList())
val forceThemedIcons by viewModel.forceThemedIcons.collectAsStateWithLifecycle(null)
val hasNotificationsPermission by viewModel.hasNotificationsPermission.collectAsStateWithLifecycle(null)
val notificationBadges by viewModel.notificationBadges.collectAsStateWithLifecycle(null)
val cloudFileBadges by viewModel.cloudFileBadges.collectAsStateWithLifecycle(null)
val suspendedAppBadges by viewModel.suspendedAppBadges.collectAsStateWithLifecycle(null)
val shortcutBadges by viewModel.shortcutBadges.collectAsStateWithLifecycle(null)
PreferenceScreen(title = stringResource(id = R.string.preference_screen_icons)) {
item {
PreferenceCategory(title = stringResource(R.string.preference_category_grid)) {
SliderPreference(
title = stringResource(R.string.preference_grid_icon_size),
value = iconSize,
step = 8,
min = 32,
max = 64,
onValueChanged = {
viewModel.setIconSize(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_grid_labels),
summary = stringResource(R.string.preference_grid_labels_summary),
value = showLabels == true,
onValueChanged = {
viewModel.setShowLabels(it)
}
)
SliderPreference(
title = stringResource(R.string.preference_grid_column_count),
value = columnCount,
min = 3,
max = 8,
onValueChanged = {
viewModel.setColumnCount(it)
}
)
}
}
item {
PreferenceCategory(stringResource(R.string.preference_category_icons)) {
IconShapePreference(
title = stringResource(R.string.preference_icon_shape),
summary = getShapeName(iconShape),
value = iconShape,
onValueChanged = {
viewModel.setIconShape(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_enforce_icon_shape),
summary = stringResource(R.string.preference_enforce_icon_shape_summary),
value = adaptifyLegacyIcons == true,
onValueChanged = {
viewModel.setAdaptifyLegacyIcons(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_themed_icons),
summary = stringResource(R.string.preference_themed_icons_summary),
value = themedIcons == true,
onValueChanged = {
viewModel.setThemedIcons(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_force_themed_icons),
summary = stringResource(R.string.preference_force_themed_icons_summary),
value = forceThemedIcons == true,
enabled = themedIcons == true,
onValueChanged = {
viewModel.setForceThemedIcons(it)
}
)
val iconPack by remember {
derivedStateOf { installedIconPacks.firstOrNull { it.packageName == iconPackPackage } }
}
val items = installedIconPacks.map {
it.name to it
}
Row(
verticalAlignment = (Alignment.CenterVertically)
) {
Box(
modifier = Modifier.weight(1f)
) {
ListPreference(
title = stringResource(R.string.preference_icon_pack),
items = items,
summary = if (items.size <= 1) {
stringResource(R.string.preference_icon_pack_summary_empty)
} else {
iconPack?.name ?: "System"
},
enabled = installedIconPacks.size > 1,
value = iconPack,
onValueChanged = {
if (it != null) viewModel.setIconPack(it.packageName)
},
itemLabel = {
Column(
verticalArrangement = Arrangement.Center,
) {
Text(
text = it.label,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
if (it.value?.themed == true) {
Surface(
shape = MaterialTheme.shapes.extraSmall,
color = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.padding(top = 4.dp)
) {
Row(
modifier = Modifier.padding(horizontal = 4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
modifier = Modifier
.size(20.dp)
.padding(end = 4.dp),
imageVector = Icons.Rounded.FormatPaint,
contentDescription = null,
)
Text(
text = stringResource(R.string.icon_pack_dynamic_colors),
style = MaterialTheme.typography.labelSmall
)
}
}
}
}
}
)
}
if (iconPack?.themed == true) {
Box(
modifier = Modifier
.height(36.dp)
.width(1.dp)
.alpha(0.38f)
.background(LocalContentColor.current)
)
Box(
modifier = Modifier
.padding(12.dp)
) {
PlainTooltipBox(tooltip = { Text(stringResource(R.string.icon_pack_dynamic_colors)) }) {
FilledIconToggleButton(
modifier = Modifier.tooltipAnchor(),
checked = iconPackThemed,
onCheckedChange = {
viewModel.setIconPackThemed(it)
}) {
Icon(
Icons.Rounded.FormatPaint,
stringResource(R.string.icon_pack_dynamic_colors)
)
}
}
}
}
}
}
}
item {
PreferenceCategory(
title = stringResource(R.string.preference_category_badges),
) {
AnimatedVisibility(hasNotificationsPermission == false) {
MissingPermissionBanner(
text = stringResource(R.string.missing_permission_notification_badges),
onClick = {
viewModel.requestNotificationsPermission(context as AppCompatActivity)
},
modifier = Modifier.padding(16.dp)
)
}
SwitchPreference(
title = stringResource(R.string.preference_notification_badges),
summary = stringResource(R.string.preference_notification_badges_summary),
enabled = hasNotificationsPermission != false,
value = notificationBadges == true && hasNotificationsPermission == true,
onValueChanged = {
viewModel.setNotifications(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_cloud_badges),
summary = stringResource(R.string.preference_cloud_badges_summary),
value = cloudFileBadges == true,
onValueChanged = {
viewModel.setCloudFiles(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_suspended_badges),
summary = stringResource(R.string.preference_suspended_badges_summary),
value = suspendedAppBadges == true,
onValueChanged = {
viewModel.setSuspendedApps(it)
}
)
SwitchPreference(
title = stringResource(R.string.preference_shortcut_badges),
summary = stringResource(R.string.preference_shortcut_badges_summary),
value = shortcutBadges == true,
onValueChanged = {
viewModel.setShortcuts(it)
}
)
}
}
}
}
@Composable
fun IconShapePreference(
title: String,
summary: String? = null,
value: Settings.IconSettings.IconShape?,
onValueChanged: (Settings.IconSettings.IconShape) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
Preference(title = title, summary = summary, onClick = { showDialog = true })
if (showDialog && value != null) {
val shapes = remember {
Settings.IconSettings.IconShape.values()
.filter { it != Settings.IconSettings.IconShape.UNRECOGNIZED && it != Settings.IconSettings.IconShape.EasterEgg }
}
Dialog(onDismissRequest = { showDialog = false }) {
Surface(
tonalElevation = 16.dp,
shadowElevation = 16.dp,
shape = MaterialTheme.shapes.extraLarge,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(
start = 24.dp, end = 24.dp, top = 16.dp, bottom = 8.dp
)
)
LazyVerticalGrid(
columns = GridCells.Adaptive(96.dp),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp, start = 16.dp, end = 16.dp)
) {
items(shapes) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
val context = LocalContext.current
ShapedLauncherIcon(
size = 48.dp,
icon = {
StaticLauncherIcon(
foregroundLayer = StaticIconLayer(
icon = ContextCompat.getDrawable(
context,
R.mipmap.ic_launcher_foreground
)!!,
scale = 1.5f,
),
backgroundLayer = StaticIconLayer(
icon = ColorDrawable(
context.getColor(R.color.ic_launcher_background)
)
)
)
},
onClick = {
onValueChanged(it)
showDialog = false
},
shape = getShape(it)
)
Text(
getShapeName(it) ?: "",
textAlign = TextAlign.Center,
style = MaterialTheme.typography.labelMedium,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
}
}
}
}
}
@Composable
private fun getShapeName(shape: Settings.IconSettings.IconShape?): String? {
return stringResource(
when (shape) {
Settings.IconSettings.IconShape.Triangle -> R.string.preference_icon_shape_triangle
Settings.IconSettings.IconShape.Hexagon -> R.string.preference_icon_shape_hexagon
Settings.IconSettings.IconShape.RoundedSquare -> R.string.preference_icon_shape_rounded_square
Settings.IconSettings.IconShape.Squircle -> R.string.preference_icon_shape_squircle
Settings.IconSettings.IconShape.Square -> R.string.preference_icon_shape_square
Settings.IconSettings.IconShape.Pentagon -> R.string.preference_icon_shape_pentagon
Settings.IconSettings.IconShape.PlatformDefault -> R.string.preference_icon_shape_platform
Settings.IconSettings.IconShape.Circle -> R.string.preference_icon_shape_circle
Settings.IconSettings.IconShape.Teardrop -> R.string.preference_icon_shape_teardrop
Settings.IconSettings.IconShape.Pebble -> R.string.preference_icon_shape_pebble
else -> return null
}
)
}

View File

@ -0,0 +1,229 @@
package de.mm20.launcher2.ui.settings.icons
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import de.mm20.launcher2.icons.IconPack
import de.mm20.launcher2.icons.IconService
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
class IconsSettingsScreenVM(
private val dataStore: LauncherDataStore,
private val iconService: IconService,
private val permissionsManager: PermissionsManager,
) : ViewModel() {
val columnCount = dataStore.data.map { it.grid.columnCount }
fun setColumnCount(columnCount: Int) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setGrid(it.grid.toBuilder().setColumnCount(columnCount))
.build()
}
}
}
val iconSize = dataStore.data.map { it.grid.iconSize }
fun setIconSize(iconSize: Int) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setGrid(it.grid.toBuilder().setIconSize(iconSize))
.build()
}
}
}
val showLabels = dataStore.data.map { it.grid.showLabels }
fun setShowLabels(showLabels: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setGrid(it.grid.toBuilder().setShowLabels(showLabels))
.build()
}
}
}
val iconShape = dataStore.data.map { it.icons.shape }
fun setIconShape(iconShape: Settings.IconSettings.IconShape) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setShape(iconShape)
)
.build()
}
}
}
val adaptifyLegacyIcons = dataStore.data.map { it.icons.adaptify }
fun setAdaptifyLegacyIcons(adaptify: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setAdaptify(adaptify)
)
.build()
}
}
}
val themedIcons = dataStore.data.map { it.icons.themedIcons }
fun setThemedIcons(themedIcons: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setThemedIcons(themedIcons)
)
.build()
}
}
}
val forceThemedIcons = dataStore.data.map { it.icons.forceThemed }
fun setForceThemedIcons(forceThemedIcons: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setForceThemed(forceThemedIcons)
)
.build()
}
}
}
val installedIconPacks: Flow<List<IconPack>> = iconService.getInstalledIconPacks().map {
listOf(
IconPack(
name = "System",
packageName = "",
version = "",
)
) + it
}
val iconPackThemed = dataStore.data.map { it.icons.iconPackThemed }
fun setIconPackThemed(iconPackThemed: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons
.toBuilder()
.setIconPackThemed(iconPackThemed)
)
.build()
}
}
}
val iconPack = dataStore.data.map { it.icons.iconPack }
fun setIconPack(iconPack: String) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setIcons(
it.icons.toBuilder()
.setIconPack(iconPack)
)
.build()
}
}
}
val hasNotificationsPermission = permissionsManager.hasPermission(PermissionGroup.Notifications)
val notificationBadges = dataStore.data.map { it.badges.notifications }
fun setNotifications(notifications: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setNotifications(notifications)
)
.build()
}
}
}
fun requestNotificationsPermission(context: AppCompatActivity) {
permissionsManager.requestPermission(context, PermissionGroup.Notifications)
}
val cloudFileBadges = dataStore.data.map { it.badges.cloudFiles }
fun setCloudFiles(cloudFiles: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setCloudFiles(cloudFiles)
)
.build()
}
}
}
val shortcutBadges = dataStore.data.map { it.badges.shortcuts }
fun setShortcuts(shortcuts: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setShortcuts(shortcuts)
)
.build()
}
}
}
val suspendedAppBadges = dataStore.data.map { it.badges.suspendedApps }
fun setSuspendedApps(suspendedApps: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setBadges(
it.badges.toBuilder()
.setSuspendedApps(suspendedApps)
)
.build()
}
}
}
companion object : KoinComponent {
val Factory = viewModelFactory {
initializer {
IconsSettingsScreenVM(
dataStore = get(),
iconService = get(),
permissionsManager = get(),
)
}
}
}
}

View File

@ -1,17 +1,24 @@
package de.mm20.launcher2.ui.settings.accounts
package de.mm20.launcher2.ui.settings.integrations
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.LightMode
import androidx.compose.material.icons.rounded.PlayCircleOutline
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -31,12 +38,14 @@ import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.locals.LocalNavController
@Composable
fun AccountsSettingsScreen() {
val viewModel: AccountsSettingsScreenVM = viewModel()
fun IntegrationsSettingsScreen() {
val viewModel: IntegrationsSettingsScreenVM = viewModel()
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val navController = LocalNavController.current
LaunchedEffect(null) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
@ -44,76 +53,91 @@ fun AccountsSettingsScreen() {
}
}
val loading by viewModel.loading.observeAsState(true)
val owncloudUser by viewModel.owncloudUser
val nextcloudUser by viewModel.nextcloudUser
val msUser by viewModel.msUser
val googleUser by viewModel.googleUser
PreferenceScreen(title = stringResource(R.string.preference_screen_services)) {
val loading by viewModel.loading
PreferenceScreen(title = stringResource(R.string.preference_screen_integrations)) {
if (loading) {
item {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth()
)
}
return@PreferenceScreen
}
item {
PreferenceCategory(title = stringResource(R.string.preference_category_services_nextcloud)) {
val account by viewModel.nextcloudUser.observeAsState()
Preference(
title = if (account != null) {
stringResource(R.string.preference_signin_logout)
title = stringResource(R.string.preference_weather_integration),
icon = Icons.Rounded.LightMode,
onClick = {
navController?.navigate("settings/integrations/weather")
}
)
Preference(
title = stringResource(R.string.preference_media_integration),
icon = Icons.Rounded.PlayCircleOutline,
onClick = {
navController?.navigate("settings/integrations/media")
}
)
}
item {
PreferenceCategory(
title = stringResource(id = R.string.preference_category_accounts)
) {
Preference(
title = if (nextcloudUser != null) {
stringResource(R.string.preference_nextcloud)
} else {
stringResource(R.string.preference_nextcloud_signin)
},
summary = account?.let {
summary = nextcloudUser?.let {
stringResource(R.string.preference_signin_user, it.userName)
} ?: stringResource(R.string.preference_nextcloud_signin_summary),
onClick = {
if (account != null) {
if (nextcloudUser != null) {
viewModel.signOut(AccountType.Nextcloud)
} else {
viewModel.signIn(context as AppCompatActivity, AccountType.Nextcloud)
}
}
},
enabled = !loading,
)
}
}
item {
PreferenceCategory(title = stringResource(R.string.preference_category_services_owncloud)) {
val account by viewModel.owncloudUser.observeAsState()
Preference(
title = if (account != null) {
stringResource(R.string.preference_signin_logout)
title = if (owncloudUser != null) {
stringResource(R.string.preference_owncloud)
} else {
stringResource(R.string.preference_owncloud_signin)
},
summary = account?.let {
summary = owncloudUser?.let {
stringResource(R.string.preference_signin_user, it.userName)
} ?: stringResource(R.string.preference_owncloud_signin_summary),
onClick = {
if (account != null) {
if (owncloudUser != null) {
viewModel.signOut(AccountType.Owncloud)
} else {
viewModel.signIn(context as AppCompatActivity, AccountType.Owncloud)
}
}
},
enabled = !loading,
)
}
}
if (viewModel.isMicrosoftAvailable) {
item {
PreferenceCategory(title = stringResource(R.string.preference_category_services_microsoft)) {
val account by viewModel.msUser.observeAsState()
Preference(
title = if (account != null) {
stringResource(R.string.preference_signin_logout)
title = if (msUser != null) {
stringResource(R.string.preference_microsoft)
} else {
stringResource(R.string.preference_ms_signin)
},
summary = account?.let {
summary = msUser?.let {
stringResource(R.string.preference_signin_user, it.userName)
} ?: stringResource(R.string.preference_ms_signin_summary),
onClick = {
if (account != null) {
if (msUser != null) {
viewModel.signOut(AccountType.Microsoft)
} else {
viewModel.signIn(
@ -121,43 +145,36 @@ fun AccountsSettingsScreen() {
AccountType.Microsoft
)
}
}
},
enabled = !loading,
)
}
}
}
if (viewModel.isGoogleAvailable) {
item {
PreferenceCategory(title = stringResource(R.string.preference_category_services_google)) {
val account by viewModel.googleUser.observeAsState()
if (account == null) {
Box(modifier = Modifier
.padding(start = 56.dp)
.padding(16.dp)) {
GoogleSigninButton(
Preference(
title = if (googleUser != null) {
stringResource(R.string.preference_google)
} else {
stringResource(R.string.preference_google_signin)
},
summary = googleUser?.let {
stringResource(R.string.preference_signin_user, it.userName)
} ?: stringResource(R.string.preference_google_signin_summary),
onClick = {
if (googleUser != null) {
viewModel.signOut(AccountType.Google)
} else {
viewModel.signIn(
context as AppCompatActivity,
AccountType.Google
)
}
)
}
} else {
Preference(
title = stringResource(R.string.preference_signin_logout),
summary = account?.userName?.let {
stringResource(R.string.preference_signin_user, it)
},
onClick = {
viewModel.signOut(AccountType.Google)
}
enabled = !loading,
)
}
}
}
}
}
}
@Composable

View File

@ -1,6 +1,7 @@
package de.mm20.launcher2.ui.settings.accounts
package de.mm20.launcher2.ui.settings.integrations
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@ -11,18 +12,18 @@ import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class AccountsSettingsScreenVM : ViewModel(), KoinComponent {
class IntegrationsSettingsScreenVM : ViewModel(), KoinComponent {
private val accountsRepository: AccountsRepository by inject()
val isGoogleAvailable = accountsRepository.isSupported(AccountType.Google)
val isMicrosoftAvailable = accountsRepository.isSupported(AccountType.Microsoft)
val googleUser = MutableLiveData<Account?>(null)
val msUser= MutableLiveData<Account?>(null)
val nextcloudUser = MutableLiveData<Account?>(null)
val owncloudUser = MutableLiveData<Account?>(null)
val googleUser = mutableStateOf<Account?>(null)
val msUser= mutableStateOf<Account?>(null)
val nextcloudUser = mutableStateOf<Account?>(null)
val owncloudUser = mutableStateOf<Account?>(null)
val loading = MutableLiveData(true)
val loading = mutableStateOf(true)
fun onResume() {
viewModelScope.launch {

View File

@ -1,79 +0,0 @@
package de.mm20.launcher2.ui.settings.layout
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.ListPreference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
@Composable
fun LayoutSettingsScreen() {
val viewModel: LayoutSettingsScreenVM = viewModel()
PreferenceScreen(
title = stringResource(id = R.string.preference_layout)
) {
item {
PreferenceCategory {
val baseLayout by viewModel.baseLayout.observeAsState()
ListPreference(title = stringResource(R.string.preference_layout_open_search),
items = listOf(
stringResource(R.string.open_search_pull_down) to Layout.PullDown,
stringResource(R.string.open_search_swipe_left) to Layout.Pager,
stringResource(R.string.open_search_swipe_right) to Layout.PagerReversed,
),
value = baseLayout,
onValueChanged = {
if (it != null) viewModel.setBaseLayout(it)
},
)
val bottomSearchBar by viewModel.bottomSearchBar.observeAsState()
ListPreference(
title = stringResource(R.string.preference_layout_search_bar_position),
items = listOf(
stringResource(R.string.search_bar_position_top) to false,
stringResource(R.string.search_bar_position_bottom) to true,
),
value = bottomSearchBar,
onValueChanged = {
if (it != null) viewModel.setBottomSearchBar(it)
},
)
val fixedSearchBar by viewModel.fixedSearchBar.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_layout_fixed_search_bar),
summary = stringResource(R.string.preference_layout_fixed_search_bar_summary),
value = fixedSearchBar == true,
onValueChanged = {
viewModel.setFixedSearchBar(it)
},
)
val reverseSearchResults by viewModel.reverseSearchResults.observeAsState()
ListPreference(title = stringResource(R.string.preference_layout_search_results),
items = listOf(
stringResource(R.string.search_results_order_top_down) to false,
stringResource(R.string.search_results_order_bottom_up) to true,
),
value = reverseSearchResults,
onValueChanged = {
if (it != null) viewModel.setReverseSearchResults(it)
},
)
val fixedRotation by viewModel.fixedRotation.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_layout_fixed_rotation),
summary = stringResource(R.string.preference_layout_fixed_rotation_summary),
value = fixedRotation == true,
onValueChanged = {
viewModel.setFixedRotation(it)
},
)
}
}
}
}

View File

@ -1,71 +0,0 @@
package de.mm20.launcher2.ui.settings.layout
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.LayoutSettings.Layout
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class LayoutSettingsScreenVM: ViewModel(), KoinComponent {
private val dataStore : LauncherDataStore by inject()
val baseLayout = dataStore.data.map { it.layout.baseLayout }.asLiveData()
fun setBaseLayout(baseLayout: Layout) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setBaseLayout(baseLayout))
.build()
}
}
}
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }.asLiveData()
fun setBottomSearchBar(bottomSearchBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setBottomSearchBar(bottomSearchBar))
.build()
}
}
}
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }.asLiveData()
fun setReverseSearchResults(reverseSearchResults: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setReverseSearchResults(reverseSearchResults))
.build()
}
}
}
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }.asLiveData()
fun setFixedSearchBar(fixedSearchBar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setFixedSearchBar(fixedSearchBar))
.build()
}
}
}
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }.asLiveData()
fun setFixedRotation(fixedRotation: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setFixedRotation(fixedRotation))
.build()
}
}
}
}

View File

@ -1,21 +1,21 @@
package de.mm20.launcher2.ui.settings.main
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.AccountBox
import androidx.compose.material.icons.rounded.Apps
import androidx.compose.material.icons.rounded.BugReport
import androidx.compose.material.icons.rounded.Gesture
import androidx.compose.material.icons.rounded.Home
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Palette
import androidx.compose.material.icons.rounded.Power
import androidx.compose.material.icons.rounded.Search
import androidx.compose.material.icons.rounded.SettingsBackupRestore
import androidx.compose.material.icons.rounded.Widgets
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.icons.NotificationBadge
import de.mm20.launcher2.ui.locals.LocalNavController
@Composable
@ -34,6 +34,22 @@ fun MainSettingsScreen() {
navController?.navigate("settings/appearance")
}
)
Preference(
icon = Icons.Rounded.Home,
title = stringResource(id = R.string.preference_screen_homescreen),
summary = stringResource(id = R.string.preference_screen_homescreen_summary),
onClick = {
navController?.navigate("settings/homescreen")
}
)
Preference(
icon = Icons.Rounded.Apps,
title = stringResource(id = R.string.preference_screen_icons),
summary = stringResource(id = R.string.preference_screen_icons_summary),
onClick = {
navController?.navigate("settings/icons")
}
)
Preference(
icon = Icons.Rounded.Search,
title = stringResource(id = R.string.preference_screen_search),
@ -42,14 +58,6 @@ fun MainSettingsScreen() {
navController?.navigate("settings/search")
}
)
Preference(
icon = Icons.Rounded.Widgets,
title = stringResource(id = R.string.preference_screen_widgets),
summary = stringResource(id = R.string.preference_screen_widgets_summary),
onClick = {
navController?.navigate("settings/widgets")
}
)
Preference(
icon = Icons.Rounded.Gesture,
title = stringResource(id = R.string.preference_screen_gestures),
@ -59,19 +67,11 @@ fun MainSettingsScreen() {
}
)
Preference(
icon = Icons.Rounded.NotificationBadge,
title = stringResource(id = R.string.preference_screen_badges),
summary = stringResource(id = R.string.preference_screen_badges_summary),
icon = Icons.Rounded.Power,
title = stringResource(id = R.string.preference_screen_integrations),
summary = stringResource(id = R.string.preference_screen_integrations_summary),
onClick = {
navController?.navigate("settings/badges")
}
)
Preference(
icon = Icons.Rounded.AccountBox,
title = stringResource(id = R.string.preference_screen_services),
summary = stringResource(id = R.string.preference_screen_services_summary),
onClick = {
navController?.navigate("settings/accounts")
navController?.navigate("settings/integrations")
}
)
Preference(

View File

@ -1,4 +1,4 @@
package de.mm20.launcher2.ui.settings.musicwidget
package de.mm20.launcher2.ui.settings.media
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
@ -20,9 +20,9 @@ import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
@Composable
fun MusicWidgetSettingsScreen() {
fun MediaIntegrationSettingsScreen() {
val context = LocalContext.current
val viewModel: MusicWidgetSettingsScreenVM = viewModel()
val viewModel: MediaIntegrationSettingsScreenVM = viewModel()
val hasPermission by viewModel.hasPermission.observeAsState()
PreferenceScreen(
stringResource(R.string.preference_screen_musicwidget),

View File

@ -1,4 +1,4 @@
package de.mm20.launcher2.ui.settings.musicwidget
package de.mm20.launcher2.ui.settings.media
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
@ -13,7 +13,7 @@ import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class MusicWidgetSettingsScreenVM : ViewModel(), KoinComponent {
class MediaIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
private val permissionsManager: PermissionsManager by inject()
private val musicService: MusicService by inject()
private val dataStore: LauncherDataStore by inject()

View File

@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.ui.R
@ -31,7 +32,7 @@ fun SearchSettingsScreen() {
PreferenceScreen(title = stringResource(R.string.preference_screen_search)) {
item {
PreferenceCategory {
val favorites by viewModel.favorites.observeAsState()
val favorites by viewModel.favorites.collectAsStateWithLifecycle(null)
PreferenceWithSwitch(
title = stringResource(R.string.preference_search_favorites),
summary = stringResource(R.string.preference_search_favorites_summary),
@ -54,7 +55,7 @@ fun SearchSettingsScreen() {
}
)
val hasContactsPermission by viewModel.hasContactsPermission.observeAsState()
val hasContactsPermission by viewModel.hasContactsPermission.collectAsStateWithLifecycle(null)
AnimatedVisibility(hasContactsPermission == false) {
MissingPermissionBanner(
text = stringResource(R.string.missing_permission_contact_search_settings),
@ -64,7 +65,7 @@ fun SearchSettingsScreen() {
modifier = Modifier.padding(16.dp)
)
}
val contacts by viewModel.contacts.observeAsState()
val contacts by viewModel.contacts.collectAsStateWithLifecycle(null)
SwitchPreference(
title = stringResource(R.string.preference_search_contacts),
summary = stringResource(R.string.preference_search_contacts_summary),
@ -76,7 +77,7 @@ fun SearchSettingsScreen() {
enabled = hasContactsPermission == true
)
val hasCalendarPermission by viewModel.hasCalendarPermission.observeAsState()
val hasCalendarPermission by viewModel.hasCalendarPermission.collectAsStateWithLifecycle(null)
AnimatedVisibility(hasCalendarPermission == false) {
MissingPermissionBanner(
text = stringResource(R.string.missing_permission_calendar_search_settings),
@ -86,7 +87,7 @@ fun SearchSettingsScreen() {
modifier = Modifier.padding(16.dp)
)
}
val calendar by viewModel.calendar.observeAsState()
val calendar by viewModel.calendar.collectAsStateWithLifecycle(null)
SwitchPreference(
title = stringResource(R.string.preference_search_calendar),
summary = stringResource(R.string.preference_search_calendar_summary),
@ -98,7 +99,7 @@ fun SearchSettingsScreen() {
enabled = hasCalendarPermission == true
)
val hasAppShortcutsPermission by viewModel.hasAppShortcutPermission.observeAsState()
val hasAppShortcutsPermission by viewModel.hasAppShortcutPermission.collectAsStateWithLifecycle(null)
AnimatedVisibility(hasAppShortcutsPermission == false) {
MissingPermissionBanner(
text = stringResource(
@ -111,7 +112,7 @@ fun SearchSettingsScreen() {
modifier = Modifier.padding(16.dp)
)
}
val appShortcuts by viewModel.appShortcuts.observeAsState()
val appShortcuts by viewModel.appShortcuts.collectAsStateWithLifecycle(null)
SwitchPreference(
title = stringResource(R.string.preference_search_appshortcuts),
summary = stringResource(R.string.preference_search_appshortcuts_summary),
@ -123,7 +124,7 @@ fun SearchSettingsScreen() {
enabled = hasAppShortcutsPermission == true
)
val calculator by viewModel.calculator.observeAsState()
val calculator by viewModel.calculator.collectAsStateWithLifecycle(null)
SwitchPreference(
title = stringResource(R.string.preference_search_calculator),
summary = stringResource(R.string.preference_search_calculator_summary),
@ -134,7 +135,7 @@ fun SearchSettingsScreen() {
}
)
val unitConverter by viewModel.unitConverter.observeAsState()
val unitConverter by viewModel.unitConverter.collectAsStateWithLifecycle(null)
PreferenceWithSwitch(
title = stringResource(R.string.preference_search_unitconverter),
summary = stringResource(R.string.preference_search_unitconverter_summary),
@ -148,7 +149,7 @@ fun SearchSettingsScreen() {
}
)
val wikipedia by viewModel.wikipedia.observeAsState()
val wikipedia by viewModel.wikipedia.collectAsStateWithLifecycle(null)
PreferenceWithSwitch(
title = stringResource(R.string.preference_search_wikipedia),
summary = stringResource(R.string.preference_search_wikipedia_summary),
@ -162,7 +163,7 @@ fun SearchSettingsScreen() {
}
)
val websites by viewModel.websites.observeAsState()
val websites by viewModel.websites.collectAsStateWithLifecycle(null)
SwitchPreference(
title = stringResource(R.string.preference_search_websites),
summary = stringResource(R.string.preference_search_websites_summary),
@ -183,43 +184,6 @@ fun SearchSettingsScreen() {
)
}
}
item {
PreferenceCategory {
val autoFocus by viewModel.autoFocus.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_search_bar_auto_focus),
summary = stringResource(R.string.preference_search_bar_auto_focus_summary),
icon = Icons.Rounded.Keyboard,
value = autoFocus == true,
onValueChanged = {
viewModel.setAutoFocus(it)
}
)
val launchOnEnter by viewModel.launchOnEnter.observeAsState()
SwitchPreference(
title = stringResource(R.string.preference_search_bar_launch_on_enter),
summary = stringResource(R.string.preference_search_bar_launch_on_enter_summary),
icon = Icons.Rounded.ArrowRightAlt,
value = launchOnEnter == true,
onValueChanged = {
viewModel.setLaunchOnEnter(it)
}
)
val searchResultOrdering by viewModel.searchResultOrdering.observeAsState()
ListPreference(
title = stringResource(R.string.preference_search_result_ordering),
items = listOf(
stringResource(R.string.preference_search_result_ordering_alphabetic) to Settings.SearchResultOrderingSettings.Ordering.Alphabetic,
stringResource(R.string.preference_search_result_ordering_weighted) to Settings.SearchResultOrderingSettings.Ordering.Weighted
),
value = searchResultOrdering,
onValueChanged = {
if (it != null) viewModel.setSearchResultOrdering(it)
},
icon = Icons.Rounded.Sort
)
}
}
item {
PreferenceCategory {
Preference(
@ -240,5 +204,57 @@ fun SearchSettingsScreen() {
)
}
}
item {
PreferenceCategory {
val autoFocus by viewModel.autoFocus.collectAsStateWithLifecycle(null)
SwitchPreference(
title = stringResource(R.string.preference_search_bar_auto_focus),
summary = stringResource(R.string.preference_search_bar_auto_focus_summary),
icon = Icons.Rounded.Keyboard,
value = autoFocus == true,
onValueChanged = {
viewModel.setAutoFocus(it)
}
)
val launchOnEnter by viewModel.launchOnEnter.collectAsStateWithLifecycle(null)
SwitchPreference(
title = stringResource(R.string.preference_search_bar_launch_on_enter),
summary = stringResource(R.string.preference_search_bar_launch_on_enter_summary),
value = launchOnEnter == true,
onValueChanged = {
viewModel.setLaunchOnEnter(it)
}
)
}
}
item {
PreferenceCategory {
val searchResultOrdering by viewModel.searchResultOrdering.collectAsStateWithLifecycle(null)
ListPreference(
title = stringResource(R.string.preference_search_result_ordering),
items = listOf(
stringResource(R.string.preference_search_result_ordering_alphabetic) to Settings.SearchResultOrderingSettings.Ordering.Alphabetic,
stringResource(R.string.preference_search_result_ordering_weighted) to Settings.SearchResultOrderingSettings.Ordering.Weighted
),
value = searchResultOrdering,
onValueChanged = {
if (it != null) viewModel.setSearchResultOrdering(it)
},
icon = Icons.Rounded.Sort
)
val reverseSearchResults by viewModel.reverseSearchResults.collectAsStateWithLifecycle(null)
ListPreference(title = stringResource(R.string.preference_layout_search_results),
items = listOf(
stringResource(R.string.search_results_order_top_down) to false,
stringResource(R.string.search_results_order_bottom_up) to true,
),
value = reverseSearchResults,
onValueChanged = {
if (it != null) viewModel.setReverseSearchResults(it)
},
)
}
}
}
}

View File

@ -18,7 +18,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject()
private val permissionsManager: PermissionsManager by inject()
val favorites = dataStore.data.map { it.favorites.enabled }.asLiveData()
val favorites = dataStore.data.map { it.favorites.enabled }
fun setFavorites(favorites: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -30,8 +30,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts).asLiveData()
val contacts = dataStore.data.map { it.contactsSearch.enabled }.asLiveData()
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
val contacts = dataStore.data.map { it.contactsSearch.enabled }
fun setContacts(contacts: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -46,8 +46,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
permissionsManager.requestPermission(activity, PermissionGroup.Contacts)
}
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar).asLiveData()
val calendar = dataStore.data.map { it.calendarSearch.enabled }.asLiveData()
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
val calendar = dataStore.data.map { it.calendarSearch.enabled }
fun setCalendar(calendar: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -62,7 +62,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
permissionsManager.requestPermission(activity, PermissionGroup.Calendar)
}
val calculator = dataStore.data.map { it.calculatorSearch.enabled }.asLiveData()
val calculator = dataStore.data.map { it.calculatorSearch.enabled }
fun setCalculator(calculator: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -73,7 +73,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }.asLiveData()
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
fun setUnitConverter(unitConverter: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -84,7 +84,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }.asLiveData()
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
fun setWikipedia(wikipedia: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -95,7 +95,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val websites = dataStore.data.map { it.websiteSearch.enabled }.asLiveData()
val websites = dataStore.data.map { it.websiteSearch.enabled }
fun setWebsites(websites: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -106,7 +106,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val webSearch = dataStore.data.map { it.webSearch.enabled }.asLiveData()
val webSearch = dataStore.data.map { it.webSearch.enabled }
fun setWebSearch(webSearch: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -117,7 +117,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val autoFocus = dataStore.data.map { it.searchBar.autoFocus }.asLiveData()
val autoFocus = dataStore.data.map { it.searchBar.autoFocus }
fun setAutoFocus(autoFocus: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -128,7 +128,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }.asLiveData()
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
fun setLaunchOnEnter(launchOnEnter: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -139,8 +139,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts).asLiveData()
val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled }.asLiveData()
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled }
fun setAppShortcuts(appShortcuts: Boolean) {
viewModelScope.launch {
dataStore.updateData {
@ -151,7 +151,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering }.asLiveData()
val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering }
fun setSearchResultOrdering(searchResultOrdering: Settings.SearchResultOrderingSettings.Ordering) {
viewModelScope.launch {
dataStore.updateData {
@ -162,6 +162,18 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
}
}
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
fun setReverseSearchResults(reverseSearchResults: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setLayout(it.layout.toBuilder().setReverseSearchResults(reverseSearchResults))
.build()
}
}
}
fun requestAppShortcutsPermission(activity: AppCompatActivity) {
permissionsManager.requestPermission(activity, PermissionGroup.AppShortcuts)
}

View File

@ -1,4 +1,4 @@
package de.mm20.launcher2.ui.settings.weatherwidget
package de.mm20.launcher2.ui.settings.weather
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
@ -19,8 +19,8 @@ import de.mm20.launcher2.ui.component.preferences.*
import de.mm20.launcher2.weather.WeatherLocation
@Composable
fun WeatherWidgetSettingsScreen() {
val viewModel: WeatherWidgetSettingsScreenVM = viewModel()
fun WeatherIntegrationSettingsScreen() {
val viewModel: WeatherIntegrationSettingsScreenVM = viewModel()
val context = LocalContext.current
PreferenceScreen(

View File

@ -1,4 +1,4 @@
package de.mm20.launcher2.ui.settings.weatherwidget
package de.mm20.launcher2.ui.settings.weather
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
@ -18,7 +18,7 @@ import kotlinx.coroutines.flow.map
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class WeatherWidgetSettingsScreenVM : ViewModel(), KoinComponent {
class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
private val repository: WeatherRepository by inject()
private val dataStore: LauncherDataStore by inject()
private val permissionsManager: PermissionsManager by inject()
@ -75,7 +75,7 @@ class WeatherWidgetSettingsScreenVM : ViewModel(), KoinComponent {
if (autoLoc) lastLoc
else loc
}.collectLatest {
this@WeatherWidgetSettingsScreenVM.location.postValue(it)
this@WeatherIntegrationSettingsScreenVM.location.postValue(it)
}
}
}

View File

@ -1,40 +0,0 @@
package de.mm20.launcher2.ui.settings.widgets
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.widgets.CalendarWidget
import de.mm20.launcher2.widgets.FavoritesWidget
import de.mm20.launcher2.widgets.MusicWidget
import de.mm20.launcher2.widgets.WeatherWidget
import de.mm20.launcher2.widgets.WidgetRepository
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class WidgetSettingsScreenVM : ViewModel(), KoinComponent {
private val widgetRepository: WidgetRepository by inject()
private val dataStore: LauncherDataStore by inject()
val calendarWidget = widgetRepository.exists(CalendarWidget.Type).asLiveData()
val musicWidget = widgetRepository.exists(MusicWidget.Type).asLiveData()
val weatherWidget = widgetRepository.exists(WeatherWidget.Type).asLiveData()
val favoritesWidget = widgetRepository.exists(FavoritesWidget.Type).asLiveData()
val editButton = dataStore.data.map { it.widgets.editButton }.asLiveData()
fun setEditButton(editButton: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setWidgets(
it.widgets.toBuilder()
.setEditButton(editButton)
)
.build()
}
}
}
}

View File

@ -1,95 +0,0 @@
package de.mm20.launcher2.ui.settings.widgets
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Audiotrack
import androidx.compose.material.icons.rounded.LightMode
import androidx.compose.material.icons.rounded.Schedule
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material.icons.rounded.Today
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.locals.LocalNavController
@Composable
fun WidgetsSettingsScreen() {
val navController = LocalNavController.current
val viewModel: WidgetSettingsScreenVM = viewModel()
PreferenceScreen(title = stringResource(R.string.preference_screen_widgets)) {
item {
PreferenceCategory {
Preference(
title = stringResource(R.string.preference_screen_clockwidget),
icon = Icons.Rounded.Schedule,
onClick = {
navController?.navigate("settings/widgets/clock")
}
)
val weatherWidget by viewModel.weatherWidget.observeAsState()
if (weatherWidget == true) {
Preference(
title = stringResource(R.string.preference_screen_weatherwidget),
icon = Icons.Rounded.LightMode,
onClick = {
navController?.navigate("settings/widgets/weather")
}
)
}
val musicWidget by viewModel.musicWidget.observeAsState()
if (musicWidget == true) {
Preference(
title = stringResource(R.string.preference_screen_musicwidget),
icon = Icons.Rounded.Audiotrack,
onClick = {
navController?.navigate("settings/widgets/music")
}
)
}
val calendarWidget by viewModel.calendarWidget.observeAsState()
if (calendarWidget == true) {
Preference(
title = stringResource(R.string.preference_screen_calendarwidget),
icon = Icons.Rounded.Today,
onClick = {
navController?.navigate("settings/widgets/calendar")
}
)
}
val favoritesWidget by viewModel.favoritesWidget.observeAsState()
if (favoritesWidget == true) {
Preference(
title = stringResource(R.string.favorites),
icon = Icons.Rounded.Star,
onClick = {
navController?.navigate("settings/favorites")
}
)
}
}
}
item {
PreferenceCategory {
val editButton by viewModel.editButton.observeAsState()
SwitchPreference(
title = stringResource(id = R.string.preference_edit_button),
summary = stringResource(id = R.string.preference_widgets_edit_button_summary),
value = editButton == true,
onValueChanged = {
viewModel.setEditButton(it)
})
}
}
}
}

View File

@ -302,7 +302,7 @@
<string name="preference_icon_shape_triangle">Reuleauxův trojúhelník</string>
<string name="preference_icon_shape_circle">Kruh</string>
<string name="preference_icon_shape_hexagon">Šestihran</string>
<string name="preference_screen_services">Služby</string>
<string name="preference_screen_integrations">Služby</string>
<string name="preference_theme_system">Podle systému</string>
<string name="preference_themed_icons">Tématické ikony</string>
<string name="preference_themed_icons_summary">Barevné ikony s barevným schématem aplikace</string>
@ -310,8 +310,8 @@
<string name="preference_category_system_bars">Systémové lišty</string>
<string name="preference_hide_status_bar">Skrýt stavovou lištu</string>
<string name="preference_hide_nav_bar">Skrýt navigační lištu</string>
<string name="preference_screen_services_summary">Spravovat připojené účty a služby</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Spravovat připojené účty a služby</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Přihlášen jako %1$s</string>
<string name="preference_signin_logout">Odhlásit se</string>
<string name="preference_icon_shape_pentagon">Pentagon</string>
@ -321,7 +321,7 @@
<string name="preference_blur_wallpaper">Rozmazat pozadí</string>
<string name="preference_blur_wallpaper_summary">Použít na pozadí efekt rozmazání</string>
<string name="preference_wallpaper_summary">Vybrat pozadí</string>
<string name="preference_screen_badges">Puntíky</string>
<string name="preference_category_badges">Puntíky</string>
<string name="preference_screen_badges_summary">Nastavit puntíky ikon</string>
<string name="preference_notification_badges">Puntíky oznámení</string>
<string name="preference_notification_badges_summary">Zobrazit puntík u aplikací s nepřečtenými oznámeními</string>
@ -330,12 +330,12 @@
<string name="preference_cloud_badges">Ikony cloudu</string>
<string name="preference_shortcut_badges">Ikony záložek</string>
<string name="preference_shortcut_badges_summary">Zobrazit ikonu značící aplikaci, ke které patří záložka</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">Přihlásit se pomocí Microsoftu</string>
<string name="preference_nextcloud_signin">Přihlásit se k Nextcloudu</string>
<string name="preference_nextcloud_signin_summary">Přihlaste se pro prohledání vašeho Nextcloud serveru</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Přihlásit se k Owncloudu</string>
<string name="preference_about_telegram">Telegram skupina</string>
<string name="preference_about_fdroid">F-Droid repozitář</string>
@ -347,7 +347,7 @@
<string name="preference_grid_icon_size">Velikost ikon</string>
<string name="preference_grid_column_count">Počet sloupců</string>
<string name="preference_screen_debug">Ladění</string>
<string name="preference_screen_widgets">Widgety</string>
<string name="preference_category_widgets">Widgety</string>
<string name="preference_screen_weatherwidget">Počasí</string>
<string name="preference_screen_musicwidget">Hudba</string>
<string name="preference_screen_clockwidget">Hodiny</string>

View File

@ -87,7 +87,7 @@
<string name="file_meta_app_min_sdk">Min-SDK-Version: %1$s</string>
<string name="file_meta_location">Ort: %1$s</string>
<string name="file_meta_owner">Eigentümer: %1$s</string>
<string name="preference_screen_services">Dienste</string>
<string name="preference_screen_integrations">Dienste</string>
<string name="default_websearch_1_name">Google</string>
<string name="default_websearch_2_name">YouTube</string>
<string name="default_websearch_3_name">Google Play</string>
@ -121,8 +121,8 @@
<string name="menu_app_info">App-Info</string>
<string name="menu_launch">Starten</string>
<string name="menu_open_file">Öffnen</string>
<string name="preference_screen_services_summary">Verbundene Accounts und Dienste verwalten</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Verbundene Accounts und Dienste verwalten</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Angemeldet als %1$s</string>
<string name="preference_signin_logout">Abmelden</string>
<string name="file_type_drawing">Zeichnung</string>
@ -206,7 +206,7 @@
<string name="preference_wallpaper_summary">Hintergrundbild auswählen</string>
<string name="preference_dim_wallpaper">Hintergrund dimmen</string>
<string name="preference_dim_wallpaper_summary">Hintergrundbild bei Verwendung von dunklen Designs abdunkeln</string>
<string name="preference_screen_badges">Plaketten</string>
<string name="preference_category_badges">Plaketten</string>
<string name="preference_screen_badges_summary">Symbolplaketten konfigurieren</string>
<string name="preference_notification_badges">Benachrichtigungsplaketten</string>
<string name="preference_notification_badges_summary">Plaketten für Anwendungen mit ungelesenen Benachrichtigungen anzeigen</string>
@ -217,7 +217,7 @@
<string name="preference_cloud_badges_summary">Eine Plakette für Dateien, die in einer Cloud gespeichert sind anzeigen</string>
<string name="preference_shortcut_badges_summary">Für Shortcuts anzeigen, zu welcher App diese gehören</string>
<string name="preference_icon_shape_platform">Systemstandard</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">Bei Microsoft anmelden</string>
<string name="preference_ms_signin_summary">Anmelden, um OneDrive durchsuchen zu können</string>
<string name="preference_nextcloud_signin">Bei Nextcloud anmelden</string>
@ -231,11 +231,11 @@
<string name="login_flow_continue">Weiter</string>
<string name="nextcloud_server_url">Nextcloud-Server-URL</string>
<string name="nextcloud_server_url_empty">Server-URL darf nicht leer sein</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="nextcloud_server_invalid_url">Diese URL verweist auf keine gültige Nextcloud-Installation</string>
<string name="login_flow_login">Anmelden</string>
<string name="owncloud_server_url">Owncloud-Server-URL</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="owncloud_server_invalid_url">Diese URL verweist auf keine gültige Owncloud-Installation</string>
<string name="owncloud_password">Passwort</string>
<string name="owncloud_username">Benutzername</string>
@ -289,7 +289,7 @@
<string name="weather_widget_set_location">Standort festlegen</string>
<string name="preference_screen_debug">Debug</string>
<string name="preference_screen_debug_summary">Werkzeuge zur Fehlerbehebung</string>
<string name="preference_screen_widgets">Widgets</string>
<string name="preference_category_widgets">Widgets</string>
<string name="preference_screen_widgets_summary">Widgets konfigurieren</string>
<string name="preference_screen_weatherwidget">Wetter</string>
<string name="preference_screen_musicwidget">Musik</string>

View File

@ -203,8 +203,8 @@
<string name="preference_system_bar_icons_auto">Αυτόματο</string>
<string name="preference_system_bar_icons_dark">Σκοτεινό</string>
<string name="preference_hide_nav_bar">Απόκρυψη γραμμής πλοήγησης</string>
<string name="preference_screen_services_summary">Διαχείριση συνδεδεμένων λογαριασμών και υπηρεσιών</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Διαχείριση συνδεδεμένων λογαριασμών και υπηρεσιών</string>
<string name="preference_google">Google</string>
<string name="preference_signin_logout">Αποσύνδεση</string>
<string name="preference_icon_shape_pentagon">Πεντάγωνο</string>
<string name="preference_dim_wallpaper_summary">Σε σκούρα θέματα, σκοτείνιασμα ταπετσαρίας</string>
@ -212,24 +212,24 @@
<string name="preference_dim_wallpaper">Σκοτείνιασμα ταπετσαρίας</string>
<string name="preference_category_wallpaper">Ταπετσαρία</string>
<string name="preference_blur_wallpaper_unsupported">Δεν υποστηρίζεται σε αυτήν τη συσκευή</string>
<string name="preference_screen_badges">Σήματα</string>
<string name="preference_category_badges">Σήματα</string>
<string name="preference_screen_badges_summary">Παραμετροποίηση σημάτων εικονιδίων</string>
<string name="preference_notification_badges">Σήματα ειδοποιήσεων</string>
<string name="preference_suspended_badges">Εφαρμογές σε αναστολή</string>
<string name="preference_cloud_badges_summary">Εμφάνιση σήματος για αρχεία που είναι αποθηκευμένα στο cloud</string>
<string name="preference_shortcut_badges">Σήματα συντομεύσεων</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_nextcloud_signin">Σύνδεση σε Nextcloud</string>
<string name="preference_nextcloud_signin_summary">Σύνδεση για αναζήτηση σε Nextcloud server</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Σύνδεση σε Owncloud</string>
<string name="preference_about_telegram">Ομάδα Telegram</string>
<string name="preference_about_license_summary">Άδεια χρήσης υπό την άδεια GNU General Public License 3.0</string>
<string name="preference_grid_labels">Εμφάνιση ταμπελών</string>
<string name="preference_screen_debug">Αποσφαλμάτωση</string>
<string name="preference_screen_debug_summary">Εργαλεία αντιμετώπισης προβλημάτων</string>
<string name="preference_screen_widgets">Γραφικά στοιχεία</string>
<string name="preference_category_widgets">Γραφικά στοιχεία</string>
<string name="preference_screen_musicwidget">Μουσική</string>
<string name="preference_screen_clockwidget">Ρολόι</string>
<string name="preference_clockwidget_layout">Διάταξη</string>
@ -424,7 +424,7 @@
<string name="preference_enforce_icon_shape_summary">Εφαρμογή σχήματος σε όλα τα εικονίδια, συμπεριλαμβανομένων εκείνων που κανονικά δεν θα το υποστήριζαν</string>
<string name="preference_icon_shape_hexagon">Εξάγωνο</string>
<string name="preference_category_license">Άδεια χρήσης</string>
<string name="preference_screen_services">Υπηρεσίες</string>
<string name="preference_screen_integrations">Υπηρεσίες</string>
<string name="preference_about_license">Αυτή η εφαρμογή αποτελεί ελεύθερο λογισμικό.</string>
<string name="preference_themed_icons">Θεματικά εικονίδια</string>
<string name="preference_category_grid">Πλέγμα</string>

View File

@ -162,7 +162,7 @@
<string name="preference_cards_corner_radius">Radio de esquina</string>
<string name="preference_cards_opacity">Opacidad</string>
<string name="preference_category_searchbar">Barra de búsqueda</string>
<string name="preference_screen_services">Servicios</string>
<string name="preference_screen_integrations">Servicios</string>
<plurals name="calendar_widget_running_events">
<item quantity="one">+%1$d evento en ejecución de días anteriores</item>
<item quantity="many">+%1$d eventos en ejecución de días anteriores</item>
@ -234,8 +234,8 @@
<string name="preference_widgets_edit_button_summary">Mostar botón para añadir, eliminar y reordenar widgets</string>
<string name="battery_part_charging">Cargando</string>
<string name="preference_icon_pack">Paquete de iconos</string>
<string name="preference_screen_badges">Insignias</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_category_badges">Insignias</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_nextcloud_signin">Registrarse a NextCloud</string>
<string name="preference_ms_signin_summary">Registrate para buscar en OneDrive</string>
<string name="preference_logs_summary">Visualizar y exportar registros de aplicación</string>
@ -248,14 +248,14 @@
<string name="create_search_action_type_web">Buscar en internet</string>
<string name="search_action_app">Aplicación</string>
<string name="icon_picker_title">Elija icono</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Registrarse a Owncloud</string>
<string name="preference_owncloud_signin_summary">Registrate para buscar en tu server Owncloud</string>
<string name="preference_about_fdroid">Repositorio de F-Droid</string>
<string name="preference_enforce_icon_shape">Forzar forma</string>
<string name="preference_themed_icons_summary">Iconos con esquema de color de la aplicación</string>
<string name="preference_category_system_bars">Barras de sistema</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_google">Google</string>
<string name="preference_icon_shape_pentagon">Pentágono</string>
<string name="preference_clockwidget_layout_horizontal">Compacto</string>
<string name="preference_clock_widget_style">Estilo</string>
@ -299,7 +299,7 @@
<string name="preference_system_bar_icons_auto">Auto</string>
<string name="preference_system_bar_icons_light">Claro</string>
<string name="preference_system_bar_icons_dark">Oscuro</string>
<string name="preference_screen_services_summary">Administrar cuentas y servicios conectados</string>
<string name="preference_screen_integrations_summary">Administrar cuentas y servicios conectados</string>
<string name="preference_signin_logout">Cerrar sesión</string>
<string name="preference_blur_wallpaper_unsupported">No soportado en este dispositivo</string>
<string name="preference_suspended_badges_summary">Mostrar una insignia en aplicaciones suspendidas</string>
@ -316,7 +316,7 @@
<string name="preference_grid_labels">Mostrar etiquetas</string>
<string name="preference_grid_labels_summary">Mostrar el nombre de la aplicación debajo del icono</string>
<string name="preference_screen_debug">Depuración</string>
<string name="preference_screen_widgets">Widgets</string>
<string name="preference_category_widgets">Widgets</string>
<string name="preference_screen_weatherwidget">Tiempo</string>
<string name="preference_screen_clockwidget">Reloj</string>
<string name="preference_clock_widget_style_summary">Selecciona un reloj</string>
@ -413,7 +413,7 @@
<string name="preference_search_bar_auto_focus_summary">Mostrar el teclado automáticamente al abrir la búsqueda</string>
<string name="preference_ms_signin">Registrarse con Microsoft</string>
<string name="preference_hidden_items_summary">Administrar aplicaciones y resultados de búsqueda ocultos</string>
<string name="preference_category_services_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="no_account_owncloud">Aun no te has conectado a una cuenta de Owncloud</string>
<string name="preference_about_license">Esta aplicación es software libre.</string>

View File

@ -115,7 +115,7 @@
<string name="file_meta_app_min_sdk">Version min du SDK: %1$s</string>
<string name="file_meta_location">Position: %1$s</string>
<string name="file_meta_owner">Propriétaire: %1$s</string>
<string name="preference_screen_services">Services</string>
<string name="preference_screen_integrations">Services</string>
<string name="preference_theme_system">Suivre le système</string>
<string name="default_websearch_1_name">Google</string>
<string name="default_websearch_2_name">YouTube</string>
@ -150,8 +150,8 @@
<string name="menu_favorites_unpin">Retirer des favoris</string>
<string name="menu_back">Retour</string>
<string name="menu_app_info">Infos sur l\'appli</string>
<string name="preference_screen_services_summary">Gérer les comptes et les services</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Gérer les comptes et les services</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Connecté en tant que %1$s</string>
<string name="preference_signin_logout">Se déconnecter</string>
<string name="preference_summary_not_logged_in">Vous n\'êtes pas connecté</string>
@ -189,7 +189,7 @@
<string name="preference_dim_wallpaper">Assombrir le fond d\'écran</string>
<string name="preference_dim_wallpaper_summary">Assombrir le fond d\'écran en thème sombre</string>
<string name="preference_wallpaper_summary">Choisir un fond d\'écran</string>
<string name="preference_screen_badges">Badges</string>
<string name="preference_category_badges">Badges</string>
<string name="preference_screen_badges_summary">Configurer les badges d\'icône</string>
<string name="preference_notification_badges">Badges de notification</string>
<string name="preference_notification_badges_summary">Afficher un badge pour les applications avec des notifications non-lues</string>
@ -200,7 +200,7 @@
<string name="preference_shortcut_badges">Badges de raccourcis</string>
<string name="preference_shortcut_badges_summary">Afficher un badge qui indique à quelle application le raccourci appartient</string>
<string name="preference_icon_shape_platform">Suivre le système</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">Se connecter avec Microsoft</string>
<string name="preference_ms_signin_summary">Se connecter pour rechercher dans OneDrive</string>
<string name="preference_nextcloud_signin">Se connecter avec Nextcloud</string>
@ -214,10 +214,10 @@
<string name="login_flow_continue">Suivant</string>
<string name="nextcloud_server_url">URL du serveur Nextcloud</string>
<string name="nextcloud_server_url_empty">L\'URL ne peut pas être vide</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="nextcloud_server_invalid_url">Cette URL ne dirige pas vers une installation Nextcloud valide</string>
<string name="owncloud_server_url">URL du serveur Owncloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="owncloud_server_invalid_url">Cette URL ne dirige pas vers une installation Owncloud valide</string>
<string name="owncloud_password">Mot de passe</string>
<string name="owncloud_username">Nom d\'utilisateur</string>
@ -317,7 +317,7 @@
<string name="weather_widget_set_location">Définir la position</string>
<string name="preference_screen_debug">Débogage</string>
<string name="preference_screen_debug_summary">Outils de débogage</string>
<string name="preference_screen_widgets">Widgets</string>
<string name="preference_category_widgets">Widgets</string>
<string name="preference_screen_widgets_summary">Configurer les widgets</string>
<string name="preference_screen_weatherwidget">Météo</string>
<string name="preference_screen_musicwidget">Musique</string>

View File

@ -253,7 +253,7 @@
<string name="preference_icon_shape_circle">Cerchio</string>
<string name="preference_icon_shape_hexagon">Esagono</string>
<string name="preference_category_searchbar">Barra di ricerca</string>
<string name="preference_screen_services">Servizi</string>
<string name="preference_screen_integrations">Servizi</string>
<string name="preference_theme_system">Segui sistema</string>
<string name="preference_themed_icons">Icone a tema</string>
<string name="preference_icon_pack_summary_empty">Nessun pacchetto icone installato</string>
@ -261,8 +261,8 @@
<string name="preference_category_system_bars">Barre di sistema</string>
<string name="preference_icon_shape_triangle">Triangolo di Reuleaux</string>
<string name="preference_hide_nav_bar">Nascondi barra di navigazione</string>
<string name="preference_screen_services_summary">Gestisce account e servizi connessi</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Gestisce account e servizi connessi</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Accesso eseguito come %1$s</string>
<string name="preference_signin_logout">Esci</string>
<string name="preference_icon_shape_pentagon">Pentagono</string>
@ -272,19 +272,19 @@
<string name="preference_wallpaper_summary">Scegli uno sfondo</string>
<string name="preference_screen_badges_summary">Configura indicatori icona</string>
<string name="preference_notification_badges">Indicatori notifica</string>
<string name="preference_screen_badges">Indicatori</string>
<string name="preference_category_badges">Indicatori</string>
<string name="preference_suspended_badges_summary">Mostra un indicatore per le applicazioni sospese</string>
<string name="preference_suspended_badges">App sospese</string>
<string name="preference_cloud_badges">Indicatori cloud</string>
<string name="preference_cloud_badges_summary">Mostra un indicatore per i file archiviati in un cloud</string>
<string name="preference_shortcut_badges">Indicatori scorciatoie</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">Accedi a Microsoft</string>
<string name="preference_ms_signin_summary">Accedi per cercare su OneDrive</string>
<string name="preference_nextcloud_signin">Accedi a Nextcloud</string>
<string name="preference_nextcloud_signin_summary">Accedi per cercare sul tuo server Nextcloud</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Accedi a Owncloud</string>
<string name="preference_owncloud_signin_summary">Accedi per cercare sul tuo server Owncloud</string>
<string name="preference_about_telegram">Gruppo Telegram</string>
@ -294,7 +294,7 @@
<string name="preference_grid_column_count">Numero colonne</string>
<string name="preference_screen_debug">Debug</string>
<string name="preference_screen_debug_summary">Strumenti di risoluzione dei problemi</string>
<string name="preference_screen_widgets">Widget</string>
<string name="preference_category_widgets">Widget</string>
<string name="preference_screen_widgets_summary">Configura widget</string>
<string name="preference_screen_weatherwidget">Meteo</string>
<string name="preference_screen_musicwidget">Musica</string>

View File

@ -289,7 +289,7 @@
<string name="preference_icon_shape_rounded_square">Afgerond vierkant</string>
<string name="preference_icon_shape_squircle">Squircle</string>
<string name="preference_category_searchbar">Zoekbalk</string>
<string name="preference_screen_services">Diensten</string>
<string name="preference_screen_integrations">Diensten</string>
<string name="edit_favorites_dialog_empty_section">Sleep items naar hier</string>
<string name="preference_themed_icons">Iconen met thema</string>
<string name="preference_themed_icons_summary">Kleur pictogrammen met het kleurenschema van de toepassing</string>
@ -306,8 +306,8 @@
<string name="preference_force_themed_icons_summary">Pas het kleurenschema toe op alle iconen, ook wanneer deze dat niet ondersteunen (niet aanbevolen)</string>
<string name="preference_icon_pack_summary_empty">Geen pictogrammenpakketten geïnstalleerd</string>
<string name="preference_hide_nav_bar">Navigatiebalk verbergen</string>
<string name="preference_screen_services_summary">Verbonden accounts en diensten beheren</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Verbonden accounts en diensten beheren</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Ingelogd als %1$s</string>
<string name="preference_signin_logout">Uitloggen</string>
<string name="preference_dim_wallpaper">Achtergrond dimmen</string>
@ -316,7 +316,7 @@
<string name="preference_blur_wallpaper_summary">Vervaag de achtergrond</string>
<string name="preference_blur_wallpaper_unsupported">Niet ondersteund op dit apparaat</string>
<string name="preference_wallpaper_summary">Kies een achtergrond</string>
<string name="preference_screen_badges">Badges</string>
<string name="preference_category_badges">Badges</string>
<string name="preference_screen_badges_summary">Configureer pictogrambadges</string>
<string name="preference_notification_badges">Meldingsstipjes</string>
<string name="preference_notification_badges_summary">Toon een badge voor applicaties met ongelezen meldingen</string>
@ -326,13 +326,13 @@
<string name="preference_cloud_badges_summary">Toon een badge voor bestanden in de cloud</string>
<string name="preference_shortcut_badges">Snelkoppelingbadges</string>
<string name="preference_shortcut_badges_summary">Toon een badge om te tonen tot welke applicatie een snelkoppeling behoort</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">Inloggen met Microsoft</string>
<string name="preference_ms_signin_summary">Log in om OneDrive te doorzoeken</string>
<string name="preference_nextcloud_signin">Inloggen bij Nextcloud</string>
<string name="preference_nextcloud_signin_summary">Log in om jouw Nextcloudserver te doorzoeken</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Inloggen bij Owncloud</string>
<string name="preference_owncloud_signin_summary">Log in om jouw Owncloudserver te doorzoeken</string>
<string name="preference_about_telegram">Telegramgroep</string>
@ -362,7 +362,7 @@
<string name="preference_grid_labels_summary">Applicatienaam onder pictrogram tonen</string>
<string name="preference_screen_debug">Foutopsporing</string>
<string name="preference_screen_debug_summary">Hulpmiddelen</string>
<string name="preference_screen_widgets">Widgets</string>
<string name="preference_category_widgets">Widgets</string>
<string name="preference_screen_widgets_summary">Widgets configureren</string>
<string name="preference_screen_weatherwidget">Weer</string>
<string name="preference_clock_widget_fill_height_summary">Extra witruimte toevoegen boven de klok om de volledige schermhoogte te vullen</string>

View File

@ -177,11 +177,11 @@
<string name="preference_icon_shape_square">Kwadrat</string>
<string name="preference_icon_shape_rounded_square">Zaokrąglony kwadrat</string>
<string name="preference_icon_shape_hexagon">Heksagon</string>
<string name="preference_screen_services">Usługi</string>
<string name="preference_screen_integrations">Usługi</string>
<string name="preference_icon_pack">Paczka ikon</string>
<string name="preference_icon_pack_summary_empty">Brak zainstalowanych paczek ikon</string>
<string name="preference_category_system_bars">Paski systemowe</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Zalogowany jako %1$s</string>
<string name="preference_signin_logout">Wyloguj się</string>
<string name="preference_summary_not_logged_in">Nie jesteś zalogowany</string>
@ -192,7 +192,7 @@
<string name="preference_wallpaper_summary">Wybierz tapetę</string>
<string name="preference_ms_signin">Zaloguj się z Microsoft</string>
<string name="preference_nextcloud_signin">Zaloguj się do Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Zaloguj się do Owncloud</string>
<string name="preference_about_telegram">Grupa Telegram</string>
<string name="preference_about_fdroid">Repozytorium F-Droid</string>
@ -203,7 +203,7 @@
<string name="preference_grid_column_count">Liczba kolumn</string>
<string name="preference_screen_debug">Debug</string>
<string name="preference_screen_debug_summary">Narzędzia do rozwiązywania problemów</string>
<string name="preference_screen_widgets">Widżety</string>
<string name="preference_category_widgets">Widżety</string>
<string name="preference_screen_widgets_summary">Konfiguruj widżety</string>
<string name="preference_screen_weatherwidget">Pogoda</string>
<string name="preference_screen_musicwidget">Muzyka</string>
@ -271,7 +271,7 @@
<string name="error_activity_not_found">Nie można otworzyć %1$s</string>
<string name="preference_search_gdrive_summary">Szukaj plików na Dysku Google użytkownika %1$s</string>
<string name="default_websearch_2_name">YouTube</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_category_license">Licencja</string>
<string name="default_websearch_3_url">https://play.google.com/store/search\?q=${1}</string>
<string name="preference_about_license_summary">Licencjonowana pod GNU General Public License 3.0</string>
@ -303,7 +303,7 @@
<string name="no_account_owncloud">Konto Owncloud nie zostało jeszcze połączone</string>
<string name="weather_details_precipitation">Opad atmosferyczny: %1$s</string>
<string name="shortcut_summary">Z %1$s</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="weather_no_data">Brak dostępnych informacji o pogodzie.</string>
<string name="nextcloud_server_url">Adres URL serwera Nextcloud</string>
<string name="weather_widget_set_location">Ustaw lokalizację</string>
@ -325,7 +325,7 @@
<string name="preference_icon_shape_circle">Okrąg</string>
<string name="preference_imperial_units_summary">Użyj stopni Fahrenheit\'a oraz mil na godzinę</string>
<string name="preference_category_searchbar">Pasek wyszukiwania</string>
<string name="preference_screen_services_summary">Zarządzaj połączonymi kontami i usługami</string>
<string name="preference_screen_integrations_summary">Zarządzaj połączonymi kontami i usługami</string>
<string name="preference_ms_signin_summary">Zaloguj się, aby móc przeszukiwać OneDrive</string>
<string name="preference_nextcloud_signin_summary">Zaloguj się, aby móc przeszukiwać twój serwer Nextcloud</string>
<string name="preference_search_currencyconverter_summary">Cyklicznie pobieraj kurs walut do konwersji walut</string>
@ -381,7 +381,7 @@
<string name="missing_permission_appshortcuts_search">Ustaw %1$s jako domyślną aplikację ekranu głownego do wyszukiwania skrótów aplikacji.</string>
<string name="preference_layout_fixed_rotation">Ustalony obrót ekranu</string>
<string name="preference_layout_fixed_rotation_summary">Wymuś tryb portretowy</string>
<string name="preference_screen_badges">Plakietki</string>
<string name="preference_category_badges">Plakietki</string>
<string name="preference_enforce_icon_shape">Wymuś kształt</string>
<string name="preference_enforce_icon_shape_summary">Zastosuj kształt do wszystkich ikon, również do tych, które normalnie by go nie obsługiwały</string>
<string name="preference_grid_labels">Pokaż etykiety</string>

View File

@ -207,10 +207,10 @@
<string name="preference_screen_appearance">Aparência</string>
<string name="preference_dim_wallpaper">Escurecer papel de parede</string>
<string name="preference_wallpaper_summary">Escolher o papel de parede</string>
<string name="preference_screen_badges">Selos</string>
<string name="preference_category_badges">Selos</string>
<string name="preference_screen_badges_summary">Configurar os selos dos ícones</string>
<string name="preference_notification_badges">Selos de notificação</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_category_wallpaper">Papel de parede</string>
<string name="preference_about_telegram">Grupo do Telegram</string>
<string name="battery_part_charging">Carregando</string>
@ -277,8 +277,8 @@
<string name="preference_category_system_bars">Barras do sistema</string>
<string name="preference_hide_status_bar">Ocultar a barra de status</string>
<string name="preference_hide_nav_bar">Ocultar a barra de navegação</string>
<string name="preference_screen_services_summary">Gerenciar as contas e serviços conectados</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Gerenciar as contas e serviços conectados</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Autenticado como %1$s</string>
<string name="preference_signin_logout">Desconectar</string>
<string name="preference_summary_not_logged_in">Você não está logado</string>
@ -287,8 +287,8 @@
<string name="preference_ms_signin_summary">Entrar para pesquisar no OneDrive</string>
<string name="preference_nextcloud_signin">Entrar com Nextcloud</string>
<string name="preference_nextcloud_signin_summary">Entrar para pesquisar no seu servidor Nextcloud</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin_summary">Entrar para pesquisar no seu servidor Owncloud</string>
<string name="preference_about_fdroid">Repositório F-Droid</string>
<string name="preference_category_license">Licença</string>
@ -298,7 +298,7 @@
<string name="preference_grid_column_count">Número de colunas</string>
<string name="preference_screen_debug">Depuração</string>
<string name="preference_screen_debug_summary">Ferramentas de solução de problemas</string>
<string name="preference_screen_widgets">Widgets</string>
<string name="preference_category_widgets">Widgets</string>
<string name="preference_screen_widgets_summary">Configurar widgets</string>
<string name="preference_screen_weatherwidget">Clima</string>
<string name="preference_screen_musicwidget">Música</string>
@ -380,7 +380,7 @@
<string name="preference_icon_shape_circle">Círculo</string>
<string name="preference_icon_shape_teardrop">Lágrima</string>
<string name="preference_category_searchbar">Barra de pesquisa</string>
<string name="preference_screen_services">Serviços</string>
<string name="preference_screen_integrations">Serviços</string>
<string name="preference_themed_icons_summary">Colore os Ícones com o esquema de cores do aplicativo</string>
<string name="preference_force_themed_icons">Forçar ícones temáticos</string>
<string name="preference_blur_wallpaper_summary">Usa efeito de desfoque no papel de parede</string>

View File

@ -240,7 +240,7 @@
<string name="preference_icon_shape_circle">Cerc</string>
<string name="preference_icon_shape_hexagon">Hexagon</string>
<string name="preference_category_searchbar">Bară de căutare</string>
<string name="preference_screen_services">Servicii</string>
<string name="preference_screen_integrations">Servicii</string>
<string name="preference_theme_system">Urmează sistemul</string>
<string name="preference_themed_icons">Pictograme tematice</string>
<string name="preference_icon_pack">Pachet de pictograme</string>
@ -248,7 +248,7 @@
<string name="preference_category_system_bars">Bare de sistem</string>
<string name="preference_hide_status_bar">Ascunde bara de stare</string>
<string name="preference_hide_nav_bar">Ascunde bara de navigare</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Conectat ca %1$s</string>
<string name="preference_signin_logout">Deconectare</string>
<string name="preference_summary_not_logged_in">În prezent, nu sunteți conectat</string>
@ -256,20 +256,20 @@
<string name="preference_category_wallpaper">Tapet</string>
<string name="preference_dim_wallpaper_summary">La teme întunecate, tapet întunecat</string>
<string name="preference_wallpaper_summary">Alege un tapet</string>
<string name="preference_screen_badges">Insigne</string>
<string name="preference_category_badges">Insigne</string>
<string name="preference_screen_badges_summary">Configurarea insignelor pictogramelor</string>
<string name="preference_suspended_badges">Aplicații suspendate</string>
<string name="preference_cloud_badges">Insigne cloud</string>
<string name="preference_shortcut_badges">Insigne de scurtătură</string>
<string name="preference_shortcut_badges_summary">Afișarea unei insigne care indică aplicația căreia îi aparține o scurtătură</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_dim_wallpaper">Întunecă tapetul</string>
<string name="preference_notification_badges">Insigne de notificare</string>
<string name="preference_suspended_badges_summary">Afișează o insignă pentru aplicațiile suspendate</string>
<string name="preference_ms_signin">Conectează-te cu Microsoft</string>
<string name="preference_nextcloud_signin">Conectează-te la Nextcloud</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Conectează-te la Owncloud</string>
<string name="preference_owncloud_signin_summary">Conectează-te pentru a căuta în serverul tău Owncloud</string>
<string name="preference_about_telegram">Grup Telegram</string>
@ -281,7 +281,7 @@
<string name="preference_grid_column_count">Numărul de coloane</string>
<string name="preference_screen_debug">Depanare</string>
<string name="preference_screen_debug_summary">Instrumente de depanare</string>
<string name="preference_screen_widgets">Widget-uri</string>
<string name="preference_category_widgets">Widget-uri</string>
<string name="preference_screen_widgets_summary">Configurarea widget-urilor</string>
<string name="preference_screen_weatherwidget">Vreme</string>
<string name="preference_screen_musicwidget">Muzică</string>
@ -370,7 +370,7 @@
\nUltima actualizare:  %1$s</string>
<string name="missing_permission_calendar_widget_settings">Acest widget necesită permisiunea la calendar</string>
<string name="provider_brightsky">Deutscher Wetterdienst (doar Germania)</string>
<string name="preference_screen_services_summary">Gestionează conturile și serviciile conectate</string>
<string name="preference_screen_integrations_summary">Gestionează conturile și serviciile conectate</string>
<string name="weather_condition_lightrainshowersandthunder">Averse ușoare de ploaie și tunete</string>
<string name="preference_cards_summary">Particularizarea aspectului cardului</string>
<string name="preference_cloud_badges_summary">Afișarea unei insigne pentru fișierele stocate într-un cloud</string>

View File

@ -195,7 +195,7 @@
<string name="preference_icon_shape_triangle">Треугольник Рело</string>
<string name="preference_icon_shape_circle">Круг</string>
<string name="preference_icon_shape_hexagon">Шестиугольник</string>
<string name="preference_screen_services">Службы</string>
<string name="preference_screen_integrations">Службы</string>
<string name="preference_theme_system">Следовать системе</string>
<string name="menu_share_store_link">%1$s ссылка</string>
<string name="menu_app_info">Информация о приложении</string>
@ -282,22 +282,22 @@
<string name="preference_clockwidget_music_part">Медиа</string>
<string name="preference_search_files_summary">Поиск локальных файлов и облачных файлов</string>
<string name="preference_search_websearch_summary">Показать ярлыки различных поисковых систем</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_google">Google</string>
<string name="preference_hide_status_bar">Скрыть строку состояния</string>
<string name="preference_hide_nav_bar">Скрыть панель навигации</string>
<string name="preference_category_wallpaper">Обои</string>
<string name="preference_dim_wallpaper">Тусклые обои</string>
<string name="preference_dim_wallpaper_summary">В темных темах, затемнить обои</string>
<string name="preference_wallpaper_summary">Выберите обои</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_about_telegram">Telegram группа</string>
<string name="preference_about_fdroid">F-Droid репозиторий</string>
<string name="preference_category_license">Лицензия</string>
<string name="preference_category_grid">Сетка</string>
<string name="preference_grid_column_count">Количество столбцов</string>
<string name="preference_screen_debug">Отладка</string>
<string name="preference_screen_widgets">Виджеты</string>
<string name="preference_category_widgets">Виджеты</string>
<string name="preference_screen_weatherwidget">Погода</string>
<string name="preference_clock_widget_style">Стиль</string>
<string name="preference_clock_widget_style_summary">Выберите часы</string>
@ -356,11 +356,11 @@
<string name="preference_blur_wallpaper">Размытие фона</string>
<string name="preference_blur_wallpaper_summary">Использовать эффект размытия для фона</string>
<string name="preference_blur_wallpaper_unsupported">Не поддерживается на вашем устройстве</string>
<string name="preference_screen_badges">Значки уведомлений</string>
<string name="preference_category_badges">Значки уведомлений</string>
<string name="edit_favorites_dialog_new_tag">Создать тег…</string>
<string name="preference_font_system">Системный</string>
<string name="preference_icon_shape_teardrop">Слезинка</string>
<string name="preference_screen_services_summary">Управление подключенными учётными записями и сервисами</string>
<string name="preference_screen_integrations_summary">Управление подключенными учётными записями и сервисами</string>
<string name="preference_font">Шрифт</string>
<string name="preference_status_bar_icons">Цвет значков строки состояния</string>
<string name="preference_system_bar_icons_dark">Тёмный</string>
@ -453,7 +453,7 @@
<string name="icon_pack_dynamic_colors">Динамические цвета</string>
<string name="backup_not_included">Подключенные учетные записи и сторонние виджеты не будут включены в резервную копию.</string>
<string name="preference_nextcloud_signin">Войти в Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_nextcloud_signin_summary">Войдите, для поиска в сервере Nextcloud</string>
<string name="preference_owncloud_signin">Войти в Owncloud</string>
<string name="preference_owncloud_signin_summary">Войдите, для поиска в сервере Owncloud</string>

View File

@ -80,7 +80,7 @@
<string name="file_meta_size">Storlek: %1$s</string>
<string name="websearch_dialog_import_error">Den angivna adressen kan inte importeras automatiskt. Du kan försöka med en annan URL eller manuellt ange den nödvändiga datan.</string>
<string name="edit_favorites_dialog_pinned_sorted">Fästa manuellt sorterade</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_google">Google</string>
<string name="file_meta_dimensions">Dimensioner: %1$s</string>
<string name="widget_name_music">Musik</string>
<string name="websearch_dialog_name">Namn</string>
@ -223,7 +223,7 @@
<string name="preference_icon_shape_triangle">Reuleaux-triangel</string>
<string name="preference_icon_shape_hexagon">Hexagon</string>
<string name="preference_category_searchbar">Sökfält</string>
<string name="preference_screen_services">Tjänster</string>
<string name="preference_screen_integrations">Tjänster</string>
<string name="preference_theme_system">Följ systemet</string>
<string name="preference_themed_icons">Färglagda ikoner</string>
<string name="preference_icon_pack">Ikonpaket</string>
@ -231,7 +231,7 @@
<string name="preference_category_system_bars">Systemfält</string>
<string name="preference_hide_status_bar">Göm statusfält</string>
<string name="preference_hide_nav_bar">Göm navigationsfält</string>
<string name="preference_screen_services_summary">Hantera anslutna konton och tjänster</string>
<string name="preference_screen_integrations_summary">Hantera anslutna konton och tjänster</string>
<string name="preference_signin_user">Inloggad som %1$s</string>
<string name="preference_signin_logout">Logga ut</string>
<string name="preference_icon_shape_pentagon">Pentagon</string>
@ -239,7 +239,7 @@
<string name="preference_dim_wallpaper">Dämpa bakgrund</string>
<string name="preference_dim_wallpaper_summary">Dämpa bakgrunden i mörka teman</string>
<string name="preference_wallpaper_summary">Välj en bakgrund</string>
<string name="preference_screen_badges">Aviseringsprickar</string>
<string name="preference_category_badges">Aviseringsprickar</string>
<string name="preference_notification_badges">Aviseringsprickar</string>
<string name="preference_notification_badges_summary">Appar med olästa notifikationer märks med en prick</string>
<string name="preference_suspended_badges_summary">Visa en prick på avslutade appar</string>
@ -247,13 +247,13 @@
<string name="preference_cloud_badges">Molnprickar</string>
<string name="preference_shortcut_badges">Genvägsprickar</string>
<string name="preference_shortcut_badges_summary">Prick som visar vilken app en genväg hör till</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">Logga in med Microsoft</string>
<string name="preference_ms_signin_summary">Logga in för att söka i OneDrive</string>
<string name="preference_nextcloud_signin">Logga in på Nextcloud</string>
<string name="preference_nextcloud_signin_summary">Logga in för att söka i din Nextcloud-server</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Logga in på Owncloud</string>
<string name="preference_about_telegram">Telegram-grupp</string>
<string name="preference_about_fdroid">F-Droid-kodförråd</string>
@ -263,7 +263,7 @@
<string name="preference_category_grid">Rutnät</string>
<string name="preference_grid_column_count">Antal kolumner</string>
<string name="preference_screen_debug">Felsök</string>
<string name="preference_screen_widgets">Widgets</string>
<string name="preference_category_widgets">Widgets</string>
<string name="preference_screen_widgets_summary">Konfigurera widgets</string>
<string name="preference_screen_weatherwidget">Väder</string>
<string name="preference_screen_musicwidget">Musik</string>

View File

@ -3,7 +3,7 @@
<string name="preference_dim_wallpaper_summary">在深色主题中,使壁纸变暗</string>
<string name="preference_screen_badges_summary">配置图标角标</string>
<string name="preference_ms_signin_summary">登陆以查找OneDrive</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud_signin">登陆到Owncloud</string>
<string name="preference_about_license">此应用是自由软件。</string>
<string name="preference_clock_widget_style_summary">选择一个时钟</string>
@ -252,8 +252,8 @@
<string name="preference_category_system_bars">系统栏</string>
<string name="preference_hide_status_bar">隐藏状态栏</string>
<string name="preference_hide_nav_bar">隐藏导航条</string>
<string name="preference_screen_services_summary">管理已连接的账户和服务</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">管理已连接的账户和服务</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">以 %1$s 身份登陆</string>
<string name="preference_signin_logout">登出</string>
<string name="preference_summary_not_logged_in">您当前未登录</string>
@ -272,9 +272,9 @@
<string name="preference_icon_shape_circle">圆形</string>
<string name="preference_icon_shape_hexagon">六边形</string>
<string name="preference_category_searchbar">搜索栏</string>
<string name="preference_screen_services">服务</string>
<string name="preference_screen_integrations">服务</string>
<string name="preference_wallpaper_summary">选择一张壁纸</string>
<string name="preference_screen_badges">徽章</string>
<string name="preference_category_badges">徽章</string>
<string name="preference_suspended_badges">已暂停的应用</string>
<string name="preference_notification_badges">通知角标</string>
<string name="preference_notification_badges_summary">为带有未读通知的应用程序显示角标</string>
@ -283,11 +283,11 @@
<string name="preference_cloud_badges_summary">为储存在云服务器上的文件显示角标</string>
<string name="preference_shortcut_badges">快捷方式角标</string>
<string name="preference_shortcut_badges_summary">显示指示快捷方式所属应用的角标</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">使用Microsoft登陆</string>
<string name="preference_nextcloud_signin_summary">登陆以查找你的Nextcloud服务</string>
<string name="preference_nextcloud_signin">登陆到Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin_summary">登陆以查找你的Owncloud服务</string>
<string name="preference_about_telegram">Telegram群组</string>
<string name="preference_about_fdroid">F-Droid 储存库</string>
@ -297,7 +297,7 @@
<string name="preference_grid_column_count">列数</string>
<string name="preference_screen_debug">调试</string>
<string name="preference_screen_debug_summary">故障排除工具</string>
<string name="preference_screen_widgets">组件</string>
<string name="preference_category_widgets">组件</string>
<string name="preference_screen_widgets_summary">配置组件</string>
<string name="preference_screen_weatherwidget">天气</string>
<string name="preference_screen_musicwidget">音乐</string>

View File

@ -320,7 +320,7 @@
<string name="preference_icon_shape_teardrop">淚滴形</string>
<string name="preference_icon_shape_pebble">鵝卵形</string>
<string name="preference_icon_shape_hexagon">六邊形</string>
<string name="preference_screen_services">服務</string>
<string name="preference_screen_integrations">服務</string>
<string name="preference_theme_system">跟隨系統</string>
<string name="preference_themed_icons">主題圖示</string>
<string name="preference_themed_icons_summary">帶有應用程式配色方案的彩色圖示</string>
@ -337,8 +337,8 @@
<string name="preference_system_bar_icons_dark">深色</string>
<string name="preference_hide_status_bar">隱藏狀態列</string>
<string name="preference_hide_nav_bar">隱藏導覽列</string>
<string name="preference_screen_services_summary">管理已連線的帳戶和服務</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">管理已連線的帳戶和服務</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">以 %1$s 身份登陸</string>
<string name="preference_signin_logout">登出</string>
<string name="preference_summary_not_logged_in">您當前未登入</string>
@ -349,17 +349,17 @@
<string name="preference_blur_wallpaper_summary">在桌布上 使用模糊效果</string>
<string name="preference_blur_wallpaper_unsupported">在此裝置上不受支援</string>
<string name="preference_wallpaper_summary">選擇一張桌布</string>
<string name="preference_screen_badges">徽章</string>
<string name="preference_category_badges">徽章</string>
<string name="preference_screen_badges_summary">組態圖示角標</string>
<string name="preference_notification_badges">通知角標</string>
<string name="preference_notification_badges_summary">為帶有未讀通知的應用程式顯示角標</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">使用Microsoft登陸</string>
<string name="preference_ms_signin_summary">登陸以查詢OneDrive</string>
<string name="preference_nextcloud_signin">登陸到Nextcloud</string>
<string name="preference_nextcloud_signin_summary">登陸以查詢你的Nextcloud服務</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">登陸到Owncloud</string>
<string name="preference_owncloud_signin_summary">登陸以查詢你的Owncloud服務</string>
<string name="preference_about_telegram">Telegram群組</string>
@ -376,7 +376,7 @@
<string name="preference_grid_labels_summary">在圖示底下顯示應用名稱</string>
<string name="preference_screen_debug">除錯</string>
<string name="preference_screen_debug_summary">故障排除工具</string>
<string name="preference_screen_widgets">元件</string>
<string name="preference_category_widgets">元件</string>
<string name="preference_screen_widgets_summary">組態元件</string>
<string name="preference_screen_weatherwidget">天氣</string>
<string name="preference_screen_musicwidget">音樂</string>

View File

@ -480,7 +480,7 @@
<string name="preference_icon_shape_pebble">Pebble</string>
<string name="preference_icon_shape_hexagon">Hexagon</string>
<string name="preference_category_searchbar">Search bar</string>
<string name="preference_screen_services">Services</string>
<string name="preference_screen_integrations">Integrations</string>
<string name="preference_theme_system">Follow system</string>
<string name="preference_themed_icons">Themed icons</string>
<string name="preference_themed_icons_summary">Color icons with the application\'s color scheme</string>
@ -498,8 +498,8 @@
<string name="preference_system_bar_icons_dark">Dark</string>
<string name="preference_hide_status_bar">Hide status bar</string>
<string name="preference_hide_nav_bar">Hide navigation bar</string>
<string name="preference_screen_services_summary">Manage connected accounts and services</string>
<string name="preference_category_services_google">Google</string>
<string name="preference_screen_integrations_summary">Manage connected accounts and services</string>
<string name="preference_google">Google</string>
<string name="preference_signin_user">Signed in as %1$s</string>
<string name="preference_signin_logout">Log out</string>
<string name="preference_summary_not_logged_in">You are currently not logged in</string>
@ -511,7 +511,7 @@
<string name="preference_blur_wallpaper_summary">Use a blur effect on the wallpaper</string>
<string name="preference_blur_wallpaper_unsupported">Not supported on this device</string>
<string name="preference_wallpaper_summary">Choose a wallpaper</string>
<string name="preference_screen_badges">Badges</string>
<string name="preference_category_badges">Badges</string>
<string name="preference_screen_badges_summary">Configure icon badges</string>
<string name="preference_notification_badges">Notification badges</string>
<string name="preference_notification_badges_summary">Show a badge for applications with unread notifications</string>
@ -521,13 +521,13 @@
<string name="preference_cloud_badges_summary">Show a badge for files that are stored in a cloud</string>
<string name="preference_shortcut_badges">Shortcut badges</string>
<string name="preference_shortcut_badges_summary">Show a badge which indicates to which app a shortcut belongs</string>
<string name="preference_category_services_microsoft">Microsoft</string>
<string name="preference_microsoft">Microsoft</string>
<string name="preference_ms_signin">Sign in with Microsoft</string>
<string name="preference_ms_signin_summary">Sign in to search OneDrive</string>
<string name="preference_nextcloud_signin">Sign in to Nextcloud</string>
<string name="preference_nextcloud_signin_summary">Sign in to search your Nextcloud server</string>
<string name="preference_category_services_nextcloud">Nextcloud</string>
<string name="preference_category_services_owncloud">Owncloud</string>
<string name="preference_nextcloud">Nextcloud</string>
<string name="preference_owncloud">Owncloud</string>
<string name="preference_owncloud_signin">Sign in to Owncloud</string>
<string name="preference_owncloud_signin_summary">Sign in to search your Owncloud server</string>
<string name="preference_about_telegram">Telegram group</string>
@ -544,11 +544,12 @@
<string name="preference_grid_labels_summary">Show the app name below the icon</string>
<string name="preference_screen_debug">Debug</string>
<string name="preference_screen_debug_summary">Troubleshooting tools</string>
<string name="preference_screen_widgets">Widgets</string>
<string name="preference_category_widgets">Widgets</string>
<string name="preference_screen_widgets_summary">Configure widgets</string>
<string name="preference_screen_weatherwidget">Weather</string>
<string name="preference_screen_musicwidget">Music</string>
<string name="preference_screen_clockwidget">Clock</string>
<string name="preference_screen_clockwidget_summary">Configure clock style and components</string>
<string name="preference_clockwidget_layout">Layout</string>
<string name="preference_clockwidget_layout_vertical">Default</string>
<string name="preference_clockwidget_layout_horizontal">Compact</string>
@ -579,7 +580,7 @@
<string name="preference_logs_summary">View and export application logs</string>
<string name="preference_export_log">Export log file</string>
<string name="preference_screen_search">Search</string>
<string name="preference_screen_search_summary">Configure the search</string>
<string name="preference_screen_search_summary">Search, tags, hidden items</string>
<string name="preference_search_favorites">Favorites</string>
<string name="preference_search_favorites_summary">Show pinned and frequently used items above app grid</string>
<string name="preference_search_files">Files</string>
@ -644,6 +645,14 @@
<string name="preference_edit_button">Edit button</string>
<string name="preference_favorites_edit_button_summary">Show a button to rearrange the favorites</string>
<string name="preference_widgets_edit_button_summary">Show a button to add, remove and rearrange widgets</string>
<string name="preference_screen_homescreen">Home screen</string>
<string name="preference_screen_homescreen_summary">Clock, search bar, wallpaper, system bars</string>
<string name="preference_screen_icons">Grid &amp; icons</string>
<string name="preference_screen_icons_summary">Grid, icon size, icon packs, badges</string>
<string name="preference_category_accounts">Accounts</string>
<string name="preference_weather_integration">Weather</string>
<string name="preference_media_integration">Media control</string>
<!-- Used in an info banner if a specific feature requires a Nextcloud account -->
<string name="no_account_nextcloud">You haven\'t connected a Nextcloud account yet</string>
<!-- Used in an info banner if a specific feature requires an Owncloud account -->

View File

@ -3,7 +3,7 @@
<application>
<activity
android:name="de.mm20.launcher2.nextcloud.LoginActivity"
android:label="@string/preference_category_services_nextcloud"
android:label="@string/preference_nextcloud"
android:taskAffinity="de.mm20.launcher2.nextcloud"
android:theme="@style/NextcloudLoginTheme" />
</application>

View File

@ -3,7 +3,7 @@
<application>
<activity
android:name=".LoginActivity"
android:label="@string/preference_category_services_nextcloud"
android:label="@string/preference_nextcloud"
android:taskAffinity="de.mm20.launcher2.nextcloud"
android:parentActivityName="de.mm20.launcher2.ui.settings.SettingsActivity"
android:theme="@style/OwncloudLoginTheme" >