diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheetVM.kt index fceac108..892e2fe0 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheetVM.kt @@ -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() diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt index fd8f2b1b..de354a4f 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt @@ -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() diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt index 0104a2f3..7a06b4ff 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt @@ -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 - } - ) } \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt index f89f3182..856bf1a8 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt @@ -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()?.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> = 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() - } - } - } } \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/badges/BadgeSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/badges/BadgeSettingsScreen.kt deleted file mode 100644 index 66d8a31c..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/badges/BadgeSettingsScreen.kt +++ /dev/null @@ -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) - } - ) - } - } - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/badges/BadgeSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/badges/BadgeSettingsScreenVM.kt deleted file mode 100644 index d3cb1db4..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/badges/BadgeSettingsScreenVM.kt +++ /dev/null @@ -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() - } - } - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt index fa6eb65d..d44c75eb 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt index 892dca00..f99731c0 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreen.kt new file mode 100644 index 00000000..a4a83451 --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreen.kt @@ -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) + } + } + ) + } +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreenVM.kt new file mode 100644 index 00000000..0baf3c1b --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreenVM.kt @@ -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()?.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() + ) + } + } + } +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/icons/IconsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/icons/IconsSettingsScreen.kt new file mode 100644 index 00000000..33637745 --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/icons/IconsSettingsScreen.kt @@ -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 + } + ) +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/icons/IconsSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/icons/IconsSettingsScreenVM.kt new file mode 100644 index 00000000..033039bc --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/icons/IconsSettingsScreenVM.kt @@ -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> = 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(), + ) + } + } + } +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/accounts/AccountsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreen.kt similarity index 59% rename from app/ui/src/main/java/de/mm20/launcher2/ui/settings/accounts/AccountsSettingsScreen.kt rename to app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreen.kt index e4e4e9cd..9cd86a45 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/accounts/AccountsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreen.kt @@ -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 = 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 (account != null) { - stringResource(R.string.preference_signin_logout) + 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() + if (viewModel.isMicrosoftAvailable) { 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,39 +145,32 @@ 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( - onClick = { - 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 = { + if (viewModel.isGoogleAvailable) { + 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 + ) } - ) - } + }, + enabled = !loading, + ) } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/accounts/AccountsSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreenVM.kt similarity index 80% rename from app/ui/src/main/java/de/mm20/launcher2/ui/settings/accounts/AccountsSettingsScreenVM.kt rename to app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreenVM.kt index 0b49d1ef..67e510e2 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/accounts/AccountsSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreenVM.kt @@ -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(null) - val msUser= MutableLiveData(null) - val nextcloudUser = MutableLiveData(null) - val owncloudUser = MutableLiveData(null) + val googleUser = mutableStateOf(null) + val msUser= mutableStateOf(null) + val nextcloudUser = mutableStateOf(null) + val owncloudUser = mutableStateOf(null) - val loading = MutableLiveData(true) + val loading = mutableStateOf(true) fun onResume() { viewModelScope.launch { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/layout/LayoutSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/layout/LayoutSettingsScreen.kt deleted file mode 100644 index d53d034d..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/layout/LayoutSettingsScreen.kt +++ /dev/null @@ -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) - }, - ) - } - } - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/layout/LayoutSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/layout/LayoutSettingsScreenVM.kt deleted file mode 100644 index bf7fe33f..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/layout/LayoutSettingsScreenVM.kt +++ /dev/null @@ -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() - } - } - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/main/MainSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/main/MainSettingsScreen.kt index 15a17807..55c4d171 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/main/MainSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/main/MainSettingsScreen.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/musicwidget/MusicWidgetSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreen.kt similarity index 94% rename from app/ui/src/main/java/de/mm20/launcher2/ui/settings/musicwidget/MusicWidgetSettingsScreen.kt rename to app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreen.kt index f43ccf32..9cc4b595 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/musicwidget/MusicWidgetSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreen.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/musicwidget/MusicWidgetSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreenVM.kt similarity index 92% rename from app/ui/src/main/java/de/mm20/launcher2/ui/settings/musicwidget/MusicWidgetSettingsScreenVM.kt rename to app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreenVM.kt index 6fe60242..e14b4d42 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/musicwidget/MusicWidgetSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreenVM.kt @@ -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() diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt index 3758efb4..67023279 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt @@ -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) + }, + ) + } + } } } \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt index 6224cad9..ee69276e 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt @@ -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) } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weatherwidget/WeatherWidgetSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreen.kt similarity index 97% rename from app/ui/src/main/java/de/mm20/launcher2/ui/settings/weatherwidget/WeatherWidgetSettingsScreen.kt rename to app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreen.kt index e5e90094..84f594f9 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weatherwidget/WeatherWidgetSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreen.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weatherwidget/WeatherWidgetSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreenVM.kt similarity index 93% rename from app/ui/src/main/java/de/mm20/launcher2/ui/settings/weatherwidget/WeatherWidgetSettingsScreenVM.kt rename to app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreenVM.kt index dd8c2b6c..9fc6f91f 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weatherwidget/WeatherWidgetSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreenVM.kt @@ -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) } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetSettingsScreenVM.kt deleted file mode 100644 index a9cec24c..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetSettingsScreenVM.kt +++ /dev/null @@ -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() - } - } - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetsSettingsScreen.kt deleted file mode 100644 index f22594d9..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetsSettingsScreen.kt +++ /dev/null @@ -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) - }) - } - } - } -} \ No newline at end of file diff --git a/core/i18n/src/main/res/values-cs/strings.xml b/core/i18n/src/main/res/values-cs/strings.xml index e1539206..85c8dcca 100644 --- a/core/i18n/src/main/res/values-cs/strings.xml +++ b/core/i18n/src/main/res/values-cs/strings.xml @@ -302,7 +302,7 @@ Reuleauxův trojúhelník Kruh Šestihran - Služby + Služby Podle systému Tématické ikony Barevné ikony s barevným schématem aplikace @@ -310,8 +310,8 @@ Systémové lišty Skrýt stavovou lištu Skrýt navigační lištu - Spravovat připojené účty a služby - Google + Spravovat připojené účty a služby + Google Přihlášen jako %1$s Odhlásit se Pentagon @@ -321,7 +321,7 @@ Rozmazat pozadí Použít na pozadí efekt rozmazání Vybrat pozadí - Puntíky + Puntíky Nastavit puntíky ikon Puntíky oznámení Zobrazit puntík u aplikací s nepřečtenými oznámeními @@ -330,12 +330,12 @@ Ikony cloudu Ikony záložek Zobrazit ikonu značící aplikaci, ke které patří záložka - Microsoft + Microsoft Přihlásit se pomocí Microsoftu Přihlásit se k Nextcloudu Přihlaste se pro prohledání vašeho Nextcloud serveru - Nextcloud - Owncloud + Nextcloud + Owncloud Přihlásit se k Owncloudu Telegram skupina F-Droid repozitář @@ -347,7 +347,7 @@ Velikost ikon Počet sloupců Ladění - Widgety + Widgety Počasí Hudba Hodiny diff --git a/core/i18n/src/main/res/values-de/strings.xml b/core/i18n/src/main/res/values-de/strings.xml index 86288b8d..9199e593 100644 --- a/core/i18n/src/main/res/values-de/strings.xml +++ b/core/i18n/src/main/res/values-de/strings.xml @@ -87,7 +87,7 @@ Min-SDK-Version: %1$s Ort: %1$s Eigentümer: %1$s - Dienste + Dienste Google YouTube Google Play @@ -121,8 +121,8 @@ App-Info Starten Öffnen - Verbundene Accounts und Dienste verwalten - Google + Verbundene Accounts und Dienste verwalten + Google Angemeldet als %1$s Abmelden Zeichnung @@ -206,7 +206,7 @@ Hintergrundbild auswählen Hintergrund dimmen Hintergrundbild bei Verwendung von dunklen Designs abdunkeln - Plaketten + Plaketten Symbolplaketten konfigurieren Benachrichtigungsplaketten Plaketten für Anwendungen mit ungelesenen Benachrichtigungen anzeigen @@ -217,7 +217,7 @@ Eine Plakette für Dateien, die in einer Cloud gespeichert sind anzeigen Für Shortcuts anzeigen, zu welcher App diese gehören Systemstandard - Microsoft + Microsoft Bei Microsoft anmelden Anmelden, um OneDrive durchsuchen zu können Bei Nextcloud anmelden @@ -231,11 +231,11 @@ Weiter Nextcloud-Server-URL Server-URL darf nicht leer sein - Nextcloud + Nextcloud Diese URL verweist auf keine gültige Nextcloud-Installation Anmelden Owncloud-Server-URL - Owncloud + Owncloud Diese URL verweist auf keine gültige Owncloud-Installation Passwort Benutzername @@ -289,7 +289,7 @@ Standort festlegen Debug Werkzeuge zur Fehlerbehebung - Widgets + Widgets Widgets konfigurieren Wetter Musik diff --git a/core/i18n/src/main/res/values-el/strings.xml b/core/i18n/src/main/res/values-el/strings.xml index d5352571..d1afc831 100644 --- a/core/i18n/src/main/res/values-el/strings.xml +++ b/core/i18n/src/main/res/values-el/strings.xml @@ -203,8 +203,8 @@ Αυτόματο Σκοτεινό Απόκρυψη γραμμής πλοήγησης - Διαχείριση συνδεδεμένων λογαριασμών και υπηρεσιών - Google + Διαχείριση συνδεδεμένων λογαριασμών και υπηρεσιών + Google Αποσύνδεση Πεντάγωνο Σε σκούρα θέματα, σκοτείνιασμα ταπετσαρίας @@ -212,24 +212,24 @@ Σκοτείνιασμα ταπετσαρίας Ταπετσαρία Δεν υποστηρίζεται σε αυτήν τη συσκευή - Σήματα + Σήματα Παραμετροποίηση σημάτων εικονιδίων Σήματα ειδοποιήσεων Εφαρμογές σε αναστολή Εμφάνιση σήματος για αρχεία που είναι αποθηκευμένα στο cloud Σήματα συντομεύσεων - Microsoft + Microsoft Σύνδεση σε Nextcloud Σύνδεση για αναζήτηση σε Nextcloud server - Nextcloud - Owncloud + Nextcloud + Owncloud Σύνδεση σε Owncloud Ομάδα Telegram Άδεια χρήσης υπό την άδεια GNU General Public License 3.0 Εμφάνιση ταμπελών Αποσφαλμάτωση Εργαλεία αντιμετώπισης προβλημάτων - Γραφικά στοιχεία + Γραφικά στοιχεία Μουσική Ρολόι Διάταξη @@ -424,7 +424,7 @@ Εφαρμογή σχήματος σε όλα τα εικονίδια, συμπεριλαμβανομένων εκείνων που κανονικά δεν θα το υποστήριζαν Εξάγωνο Άδεια χρήσης - Υπηρεσίες + Υπηρεσίες Αυτή η εφαρμογή αποτελεί ελεύθερο λογισμικό. Θεματικά εικονίδια Πλέγμα diff --git a/core/i18n/src/main/res/values-es/strings.xml b/core/i18n/src/main/res/values-es/strings.xml index 8cd8065a..83f90753 100644 --- a/core/i18n/src/main/res/values-es/strings.xml +++ b/core/i18n/src/main/res/values-es/strings.xml @@ -162,7 +162,7 @@ Radio de esquina Opacidad Barra de búsqueda - Servicios + Servicios +%1$d evento en ejecución de días anteriores +%1$d eventos en ejecución de días anteriores @@ -234,8 +234,8 @@ Mostar botón para añadir, eliminar y reordenar widgets Cargando Paquete de iconos - Insignias - Microsoft + Insignias + Microsoft Registrarse a NextCloud Registrate para buscar en OneDrive Visualizar y exportar registros de aplicación @@ -248,14 +248,14 @@ Buscar en internet Aplicación Elija icono - Owncloud + Owncloud Registrarse a Owncloud Registrate para buscar en tu server Owncloud Repositorio de F-Droid Forzar forma Iconos con esquema de color de la aplicación Barras de sistema - Google + Google Pentágono Compacto Estilo @@ -299,7 +299,7 @@ Auto Claro Oscuro - Administrar cuentas y servicios conectados + Administrar cuentas y servicios conectados Cerrar sesión No soportado en este dispositivo Mostrar una insignia en aplicaciones suspendidas @@ -316,7 +316,7 @@ Mostrar etiquetas Mostrar el nombre de la aplicación debajo del icono Depuración - Widgets + Widgets Tiempo Reloj Selecciona un reloj @@ -413,7 +413,7 @@ Mostrar el teclado automáticamente al abrir la búsqueda Registrarse con Microsoft Administrar aplicaciones y resultados de búsqueda ocultos - NextCloud + NextCloud Registrate para buscar en tu servidor NextCloud Aun no te has conectado a una cuenta de Owncloud Esta aplicación es software libre. diff --git a/core/i18n/src/main/res/values-fr/strings.xml b/core/i18n/src/main/res/values-fr/strings.xml index 146137f6..e48ce371 100644 --- a/core/i18n/src/main/res/values-fr/strings.xml +++ b/core/i18n/src/main/res/values-fr/strings.xml @@ -115,7 +115,7 @@ Version min du SDK : %1$s Position : %1$s Propriétaire : %1$s - Services + Services Suivre le système Google YouTube @@ -150,8 +150,8 @@ Retirer des favoris Retour Infos sur l\'appli - Gérer les comptes et les services - Google + Gérer les comptes et les services + Google Connecté en tant que %1$s Se déconnecter Vous n\'êtes pas connecté @@ -189,7 +189,7 @@ Assombrir le fond d\'écran Assombrir le fond d\'écran en thème sombre Choisir un fond d\'écran - Badges + Badges Configurer les badges d\'icône Badges de notification Afficher un badge pour les applications avec des notifications non-lues @@ -200,7 +200,7 @@ Badges de raccourcis Afficher un badge qui indique à quelle application le raccourci appartient Suivre le système - Microsoft + Microsoft Se connecter avec Microsoft Se connecter pour rechercher dans OneDrive Se connecter avec Nextcloud @@ -214,10 +214,10 @@ Suivant URL du serveur Nextcloud L\'URL ne peut pas être vide - Nextcloud + Nextcloud Cette URL ne dirige pas vers une installation Nextcloud valide URL du serveur Owncloud - Owncloud + Owncloud Cette URL ne dirige pas vers une installation Owncloud valide Mot de passe Nom d\'utilisateur @@ -317,7 +317,7 @@ Définir la position Débogage Outils de débogage - Widgets + Widgets Configurer les widgets Météo Musique diff --git a/core/i18n/src/main/res/values-it/strings.xml b/core/i18n/src/main/res/values-it/strings.xml index 7acd12fc..1aec63ea 100644 --- a/core/i18n/src/main/res/values-it/strings.xml +++ b/core/i18n/src/main/res/values-it/strings.xml @@ -253,7 +253,7 @@ Cerchio Esagono Barra di ricerca - Servizi + Servizi Segui sistema Icone a tema Nessun pacchetto icone installato @@ -261,8 +261,8 @@ Barre di sistema Triangolo di Reuleaux Nascondi barra di navigazione - Gestisce account e servizi connessi - Google + Gestisce account e servizi connessi + Google Accesso eseguito come %1$s Esci Pentagono @@ -272,19 +272,19 @@ Scegli uno sfondo Configura indicatori icona Indicatori notifica - Indicatori + Indicatori Mostra un indicatore per le applicazioni sospese App sospese Indicatori cloud Mostra un indicatore per i file archiviati in un cloud Indicatori scorciatoie - Microsoft + Microsoft Accedi a Microsoft Accedi per cercare su OneDrive Accedi a Nextcloud Accedi per cercare sul tuo server Nextcloud - Nextcloud - Owncloud + Nextcloud + Owncloud Accedi a Owncloud Accedi per cercare sul tuo server Owncloud Gruppo Telegram @@ -294,7 +294,7 @@ Numero colonne Debug Strumenti di risoluzione dei problemi - Widget + Widget Configura widget Meteo Musica diff --git a/core/i18n/src/main/res/values-nl/strings.xml b/core/i18n/src/main/res/values-nl/strings.xml index 564861e9..97252b07 100644 --- a/core/i18n/src/main/res/values-nl/strings.xml +++ b/core/i18n/src/main/res/values-nl/strings.xml @@ -289,7 +289,7 @@ Afgerond vierkant Squircle Zoekbalk - Diensten + Diensten Sleep items naar hier Iconen met thema Kleur pictogrammen met het kleurenschema van de toepassing @@ -306,8 +306,8 @@ Pas het kleurenschema toe op alle iconen, ook wanneer deze dat niet ondersteunen (niet aanbevolen) Geen pictogrammenpakketten geïnstalleerd Navigatiebalk verbergen - Verbonden accounts en diensten beheren - Google + Verbonden accounts en diensten beheren + Google Ingelogd als %1$s Uitloggen Achtergrond dimmen @@ -316,7 +316,7 @@ Vervaag de achtergrond Niet ondersteund op dit apparaat Kies een achtergrond - Badges + Badges Configureer pictogrambadges Meldingsstipjes Toon een badge voor applicaties met ongelezen meldingen @@ -326,13 +326,13 @@ Toon een badge voor bestanden in de cloud Snelkoppelingbadges Toon een badge om te tonen tot welke applicatie een snelkoppeling behoort - Microsoft + Microsoft Inloggen met Microsoft Log in om OneDrive te doorzoeken Inloggen bij Nextcloud Log in om jouw Nextcloudserver te doorzoeken - Nextcloud - Owncloud + Nextcloud + Owncloud Inloggen bij Owncloud Log in om jouw Owncloudserver te doorzoeken Telegramgroep @@ -362,7 +362,7 @@ Applicatienaam onder pictrogram tonen Foutopsporing Hulpmiddelen - Widgets + Widgets Widgets configureren Weer Extra witruimte toevoegen boven de klok om de volledige schermhoogte te vullen diff --git a/core/i18n/src/main/res/values-pl/strings.xml b/core/i18n/src/main/res/values-pl/strings.xml index 30e5dfc1..dbe1a677 100644 --- a/core/i18n/src/main/res/values-pl/strings.xml +++ b/core/i18n/src/main/res/values-pl/strings.xml @@ -177,11 +177,11 @@ Kwadrat Zaokrąglony kwadrat Heksagon - Usługi + Usługi Paczka ikon Brak zainstalowanych paczek ikon Paski systemowe - Google + Google Zalogowany jako %1$s Wyloguj się Nie jesteś zalogowany @@ -192,7 +192,7 @@ Wybierz tapetę Zaloguj się z Microsoft Zaloguj się do Nextcloud - Owncloud + Owncloud Zaloguj się do Owncloud Grupa Telegram Repozytorium F-Droid @@ -203,7 +203,7 @@ Liczba kolumn Debug Narzędzia do rozwiązywania problemów - Widżety + Widżety Konfiguruj widżety Pogoda Muzyka @@ -271,7 +271,7 @@ Nie można otworzyć %1$s Szukaj plików na Dysku Google użytkownika %1$s YouTube - Nextcloud + Nextcloud Licencja https://play.google.com/store/search\?q=${1} Licencjonowana pod GNU General Public License 3.0 @@ -303,7 +303,7 @@ Konto Owncloud nie zostało jeszcze połączone Opad atmosferyczny: %1$s Z %1$s - Microsoft + Microsoft Brak dostępnych informacji o pogodzie. Adres URL serwera Nextcloud Ustaw lokalizację @@ -325,7 +325,7 @@ Okrąg Użyj stopni Fahrenheit\'a oraz mil na godzinę Pasek wyszukiwania - Zarządzaj połączonymi kontami i usługami + Zarządzaj połączonymi kontami i usługami Zaloguj się, aby móc przeszukiwać OneDrive Zaloguj się, aby móc przeszukiwać twój serwer Nextcloud Cyklicznie pobieraj kurs walut do konwersji walut @@ -381,7 +381,7 @@ Ustaw %1$s jako domyślną aplikację ekranu głownego do wyszukiwania skrótów aplikacji. Ustalony obrót ekranu Wymuś tryb portretowy - Plakietki + Plakietki Wymuś kształt Zastosuj kształt do wszystkich ikon, również do tych, które normalnie by go nie obsługiwały Pokaż etykiety diff --git a/core/i18n/src/main/res/values-pt-rBR/strings.xml b/core/i18n/src/main/res/values-pt-rBR/strings.xml index 8c95cfe8..27131ffe 100644 --- a/core/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/core/i18n/src/main/res/values-pt-rBR/strings.xml @@ -207,10 +207,10 @@ Aparência Escurecer papel de parede Escolher o papel de parede - Selos + Selos Configurar os selos dos ícones Selos de notificação - Microsoft + Microsoft Papel de parede Grupo do Telegram Carregando @@ -277,8 +277,8 @@ Barras do sistema Ocultar a barra de status Ocultar a barra de navegação - Gerenciar as contas e serviços conectados - Google + Gerenciar as contas e serviços conectados + Google Autenticado como %1$s Desconectar Você não está logado @@ -287,8 +287,8 @@ Entrar para pesquisar no OneDrive Entrar com Nextcloud Entrar para pesquisar no seu servidor Nextcloud - Nextcloud - Owncloud + Nextcloud + Owncloud Entrar para pesquisar no seu servidor Owncloud Repositório F-Droid Licença @@ -298,7 +298,7 @@ Número de colunas Depuração Ferramentas de solução de problemas - Widgets + Widgets Configurar widgets Clima Música @@ -380,7 +380,7 @@ Círculo Lágrima Barra de pesquisa - Serviços + Serviços Colore os Ícones com o esquema de cores do aplicativo Forçar ícones temáticos Usa efeito de desfoque no papel de parede diff --git a/core/i18n/src/main/res/values-ro/strings.xml b/core/i18n/src/main/res/values-ro/strings.xml index 49cc3d7c..67d4428d 100644 --- a/core/i18n/src/main/res/values-ro/strings.xml +++ b/core/i18n/src/main/res/values-ro/strings.xml @@ -240,7 +240,7 @@ Cerc Hexagon Bară de căutare - Servicii + Servicii Urmează sistemul Pictograme tematice Pachet de pictograme @@ -248,7 +248,7 @@ Bare de sistem Ascunde bara de stare Ascunde bara de navigare - Google + Google Conectat ca %1$s Deconectare În prezent, nu sunteți conectat @@ -256,20 +256,20 @@ Tapet La teme întunecate, tapet întunecat Alege un tapet - Insigne + Insigne Configurarea insignelor pictogramelor Aplicații suspendate Insigne cloud Insigne de scurtătură Afișarea unei insigne care indică aplicația căreia îi aparține o scurtătură - Microsoft + Microsoft Întunecă tapetul Insigne de notificare Afișează o insignă pentru aplicațiile suspendate Conectează-te cu Microsoft Conectează-te la Nextcloud - Nextcloud - Owncloud + Nextcloud + Owncloud Conectează-te la Owncloud Conectează-te pentru a căuta în serverul tău Owncloud Grup Telegram @@ -281,7 +281,7 @@ Numărul de coloane Depanare Instrumente de depanare - Widget-uri + Widget-uri Configurarea widget-urilor Vreme Muzică @@ -370,7 +370,7 @@ \nUltima actualizare:  %1$s Acest widget necesită permisiunea la calendar Deutscher Wetterdienst (doar Germania) - Gestionează conturile și serviciile conectate + Gestionează conturile și serviciile conectate Averse ușoare de ploaie și tunete Particularizarea aspectului cardului Afișarea unei insigne pentru fișierele stocate într-un cloud diff --git a/core/i18n/src/main/res/values-ru/strings.xml b/core/i18n/src/main/res/values-ru/strings.xml index 86c3e282..04f46cd2 100644 --- a/core/i18n/src/main/res/values-ru/strings.xml +++ b/core/i18n/src/main/res/values-ru/strings.xml @@ -195,7 +195,7 @@ Треугольник Рело Круг Шестиугольник - Службы + Службы Следовать системе %1$s ссылка Информация о приложении @@ -282,22 +282,22 @@ Медиа Поиск локальных файлов и облачных файлов Показать ярлыки различных поисковых систем - Google + Google Скрыть строку состояния Скрыть панель навигации Обои Тусклые обои В темных темах, затемнить обои Выберите обои - Microsoft - Nextcloud + Microsoft + Nextcloud Telegram группа F-Droid репозиторий Лицензия Сетка Количество столбцов Отладка - Виджеты + Виджеты Погода Стиль Выберите часы @@ -356,11 +356,11 @@ Размытие фона Использовать эффект размытия для фона Не поддерживается на вашем устройстве - Значки уведомлений + Значки уведомлений Создать тег… Системный Слезинка - Управление подключенными учётными записями и сервисами + Управление подключенными учётными записями и сервисами Шрифт Цвет значков строки состояния Тёмный @@ -453,7 +453,7 @@ Динамические цвета Подключенные учетные записи и сторонние виджеты не будут включены в резервную копию. Войти в Nextcloud - Owncloud + Owncloud Войдите, для поиска в сервере Nextcloud Войти в Owncloud Войдите, для поиска в сервере Owncloud diff --git a/core/i18n/src/main/res/values-sv/strings.xml b/core/i18n/src/main/res/values-sv/strings.xml index c567d236..1b4a2020 100644 --- a/core/i18n/src/main/res/values-sv/strings.xml +++ b/core/i18n/src/main/res/values-sv/strings.xml @@ -80,7 +80,7 @@ Storlek: %1$s Den angivna adressen kan inte importeras automatiskt. Du kan försöka med en annan URL eller manuellt ange den nödvändiga datan. Fästa – manuellt sorterade - Google + Google Dimensioner: %1$s Musik Namn @@ -223,7 +223,7 @@ Reuleaux-triangel Hexagon Sökfält - Tjänster + Tjänster Följ systemet Färglagda ikoner Ikonpaket @@ -231,7 +231,7 @@ Systemfält Göm statusfält Göm navigationsfält - Hantera anslutna konton och tjänster + Hantera anslutna konton och tjänster Inloggad som %1$s Logga ut Pentagon @@ -239,7 +239,7 @@ Dämpa bakgrund Dämpa bakgrunden i mörka teman Välj en bakgrund - Aviseringsprickar + Aviseringsprickar Aviseringsprickar Appar med olästa notifikationer märks med en prick Visa en prick på avslutade appar @@ -247,13 +247,13 @@ Molnprickar Genvägsprickar Prick som visar vilken app en genväg hör till - Microsoft + Microsoft Logga in med Microsoft Logga in för att söka i OneDrive Logga in på Nextcloud Logga in för att söka i din Nextcloud-server - Nextcloud - Owncloud + Nextcloud + Owncloud Logga in på Owncloud Telegram-grupp F-Droid-kodförråd @@ -263,7 +263,7 @@ Rutnät Antal kolumner Felsök - Widgets + Widgets Konfigurera widgets Väder Musik diff --git a/core/i18n/src/main/res/values-zh-rCN/strings.xml b/core/i18n/src/main/res/values-zh-rCN/strings.xml index 5bb4b196..cc8fab31 100644 --- a/core/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/core/i18n/src/main/res/values-zh-rCN/strings.xml @@ -3,7 +3,7 @@ 在深色主题中,使壁纸变暗 配置图标角标 登陆以查找OneDrive - Nextcloud + Nextcloud 登陆到Owncloud 此应用是自由软件。 选择一个时钟 @@ -252,8 +252,8 @@ 系统栏 隐藏状态栏 隐藏导航条 - 管理已连接的账户和服务 - Google + 管理已连接的账户和服务 + Google 以 %1$s 身份登陆 登出 您当前未登录 @@ -272,9 +272,9 @@ 圆形 六边形 搜索栏 - 服务 + 服务 选择一张壁纸 - 徽章 + 徽章 已暂停的应用 通知角标 为带有未读通知的应用程序显示角标 @@ -283,11 +283,11 @@ 为储存在云服务器上的文件显示角标 快捷方式角标 显示指示快捷方式所属应用的角标 - Microsoft + Microsoft 使用Microsoft登陆 登陆以查找你的Nextcloud服务 登陆到Nextcloud - Owncloud + Owncloud 登陆以查找你的Owncloud服务 Telegram群组 F-Droid 储存库 @@ -297,7 +297,7 @@ 列数 调试 故障排除工具 - 组件 + 组件 配置组件 天气 音乐 diff --git a/core/i18n/src/main/res/values-zh-rTW/strings.xml b/core/i18n/src/main/res/values-zh-rTW/strings.xml index fde82b75..4ae63a5e 100644 --- a/core/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/core/i18n/src/main/res/values-zh-rTW/strings.xml @@ -320,7 +320,7 @@ 淚滴形 鵝卵形 六邊形 - 服務 + 服務 跟隨系統 主題圖示 帶有應用程式配色方案的彩色圖示 @@ -337,8 +337,8 @@ 深色 隱藏狀態列 隱藏導覽列 - 管理已連線的帳戶和服務 - Google + 管理已連線的帳戶和服務 + Google 以 %1$s 身份登陸 登出 您當前未登入 @@ -349,17 +349,17 @@ 在桌布上 使用模糊效果 在此裝置上不受支援 選擇一張桌布 - 徽章 + 徽章 組態圖示角標 通知角標 為帶有未讀通知的應用程式顯示角標 - Microsoft + Microsoft 使用Microsoft登陸 登陸以查詢OneDrive 登陸到Nextcloud 登陸以查詢你的Nextcloud服務 - Nextcloud - Owncloud + Nextcloud + Owncloud 登陸到Owncloud 登陸以查詢你的Owncloud服務 Telegram群組 @@ -376,7 +376,7 @@ 在圖示底下顯示應用名稱 除錯 故障排除工具 - 元件 + 元件 組態元件 天氣 音樂 diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index 1eddf8f3..65d04741 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -480,7 +480,7 @@ Pebble Hexagon Search bar - Services + Integrations Follow system Themed icons Color icons with the application\'s color scheme @@ -498,8 +498,8 @@ Dark Hide status bar Hide navigation bar - Manage connected accounts and services - Google + Manage connected accounts and services + Google Signed in as %1$s Log out You are currently not logged in @@ -511,7 +511,7 @@ Use a blur effect on the wallpaper Not supported on this device Choose a wallpaper - Badges + Badges Configure icon badges Notification badges Show a badge for applications with unread notifications @@ -521,13 +521,13 @@ Show a badge for files that are stored in a cloud Shortcut badges Show a badge which indicates to which app a shortcut belongs - Microsoft + Microsoft Sign in with Microsoft Sign in to search OneDrive Sign in to Nextcloud Sign in to search your Nextcloud server - Nextcloud - Owncloud + Nextcloud + Owncloud Sign in to Owncloud Sign in to search your Owncloud server Telegram group @@ -544,11 +544,12 @@ Show the app name below the icon Debug Troubleshooting tools - Widgets + Widgets Configure widgets Weather Music Clock + Configure clock style and components Layout Default Compact @@ -579,7 +580,7 @@ View and export application logs Export log file Search - Configure the search + Search, tags, hidden items Favorites Show pinned and frequently used items above app grid Files @@ -644,6 +645,14 @@ Edit button Show a button to rearrange the favorites Show a button to add, remove and rearrange widgets + Home screen + Clock, search bar, wallpaper, system bars + Grid & icons + Grid, icon size, icon packs, badges + Accounts + Weather + Media control + You haven\'t connected a Nextcloud account yet diff --git a/libs/nextcloud/src/main/AndroidManifest.xml b/libs/nextcloud/src/main/AndroidManifest.xml index ab04e2d9..38ad44a8 100644 --- a/libs/nextcloud/src/main/AndroidManifest.xml +++ b/libs/nextcloud/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ diff --git a/libs/owncloud/src/main/AndroidManifest.xml b/libs/owncloud/src/main/AndroidManifest.xml index fa73c4fc..2d4b7d8d 100644 --- a/libs/owncloud/src/main/AndroidManifest.xml +++ b/libs/owncloud/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@