From fc6d1d382cdd7853dbd56d74125fe99f74d38a6e Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Tue, 27 Sep 2022 21:06:07 +0200 Subject: [PATCH] Add preference to hide widget edit button --- i18n/src/main/res/values/strings.xml | 1 + .../de/mm20/launcher2/preferences/Defaults.kt | 4 + .../preferences/migrations/Migration_9_10.kt | 19 +-- preferences/src/main/proto/settings.proto | 5 + .../ui/launcher/widgets/WidgetColumn.kt | 119 ++++++++++-------- .../ui/launcher/widgets/WidgetsVM.kt | 6 + .../widgets/WidgetSettingsScreenVM.kt | 21 +++- .../settings/widgets/WidgetsSettingsScreen.kt | 109 +++++++++------- 8 files changed, 181 insertions(+), 103 deletions(-) diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 81990716..43793d98 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -622,6 +622,7 @@ Show frequently used items in favorites Edit button Show a button to rearrange the favorites + Show a button to add, remove and rearrange widgets You haven\'t connected a Nextcloud account yet diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt index 11e1d7a6..e3951933 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt @@ -155,6 +155,10 @@ fun createFactorySettings(context: Context): Settings { .setRadius(8) .setOpacity(1f) ) + .setWidgets( + Settings.WidgetSettings.newBuilder() + .setEditButton(true) + ) .build() } diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_9_10.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_9_10.kt index 192fe122..8bafb65c 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_9_10.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_9_10.kt @@ -2,13 +2,18 @@ package de.mm20.launcher2.preferences.migrations import de.mm20.launcher2.preferences.Settings -class Migration_9_10: VersionedMigration(9, 10) { +class Migration_9_10 : VersionedMigration(9, 10) { override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder { - return builder.setFavorites( - builder.favorites.toBuilder() - .setFrequentlyUsed(true) - .setFrequentlyUsedRows(1) - .setEditButton(true) - ) + return builder + .setFavorites( + builder.favorites.toBuilder() + .setFrequentlyUsed(true) + .setFrequentlyUsedRows(1) + .setEditButton(true) + ) + .setWidgets( + Settings.WidgetSettings.newBuilder() + .setEditButton(true) + ) } } \ No newline at end of file diff --git a/preferences/src/main/proto/settings.proto b/preferences/src/main/proto/settings.proto index 441656b0..7b6a2b0d 100644 --- a/preferences/src/main/proto/settings.proto +++ b/preferences/src/main/proto/settings.proto @@ -259,4 +259,9 @@ message Settings { bool enabled = 1; } AppShortcutSearchSettings app_shortcut_search = 25; + + message WidgetSettings { + bool edit_button = 1; + } + WidgetSettings widgets = 26; } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt index 1cf68aa0..77bff548 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt @@ -7,20 +7,37 @@ import android.content.Intent import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi import androidx.compose.animation.graphics.res.animatedVectorResource import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.rememberDraggableState -import androidx.compose.foundation.layout.* +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.offset +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Add -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.ExtendedFloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +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.key import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onPlaced @@ -35,10 +52,9 @@ import androidx.compose.ui.window.Dialog import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import de.mm20.launcher2.ui.launcher.widgets.clock.ClockWidget import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.ktx.animateTo -import de.mm20.launcher2.ui.ktx.conditional +import de.mm20.launcher2.ui.launcher.widgets.clock.ClockWidget import de.mm20.launcher2.ui.launcher.widgets.picker.PickAppWidgetActivity import de.mm20.launcher2.widgets.ExternalWidget import kotlinx.coroutines.awaitCancellation @@ -69,17 +85,18 @@ fun WidgetColumn( } } - val pickWidgetLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { - val data = it.data ?: return@rememberLauncherForActivityResult - val widgetId = data.getIntExtra( - AppWidgetManager.EXTRA_APPWIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID - ) - if (widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) return@rememberLauncherForActivityResult - if (it.resultCode == Activity.RESULT_OK) { - viewModel.addAppWidget(context, widgetId) + val pickWidgetLauncher = + rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { + val data = it.data ?: return@rememberLauncherForActivityResult + val widgetId = data.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID + ) + if (widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) return@rememberLauncherForActivityResult + if (it.resultCode == Activity.RESULT_OK) { + viewModel.addAppWidget(context, widgetId) + } } - } Column( modifier = modifier @@ -168,43 +185,47 @@ fun WidgetColumn( } } - val icon = - AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_edit_add) - ExtendedFloatingActionButton( - modifier = Modifier - .padding(16.dp) - .align(Alignment.CenterHorizontally), - icon = { - Icon( - painter = rememberAnimatedVectorPainter( - animatedImageVector = icon, - atEnd = !editMode - ), contentDescription = null - ) - }, - text = { - Text( - stringResource( - if (editMode) R.string.widget_add_widget - else R.string.menu_edit_widgets + val editButton by viewModel.editButton.observeAsState() + if (editButton == true) { + val icon = + AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_edit_add) + ExtendedFloatingActionButton( + modifier = Modifier + .padding(16.dp) + .align(Alignment.CenterHorizontally), + icon = { + Icon( + painter = rememberAnimatedVectorPainter( + animatedImageVector = icon, + atEnd = !editMode + ), contentDescription = null ) - ) - }, onClick = { - if (!editMode) { - onEditModeChange(true) - } else { - if (viewModel.getAvailableBuiltInWidgets().isEmpty()) { - pickWidgetLauncher.launch( - Intent( - context, - PickAppWidgetActivity::class.java - ) + }, + text = { + Text( + stringResource( + if (editMode) R.string.widget_add_widget + else R.string.menu_edit_widgets ) + ) + }, onClick = { + if (!editMode) { + onEditModeChange(true) } else { - showAddDialog = true + if (viewModel.getAvailableBuiltInWidgets().isEmpty()) { + pickWidgetLauncher.launch( + Intent( + context, + PickAppWidgetActivity::class.java + ) + ) + } else { + showAddDialog = true + } } - } - }) + }) + + } if (showAddDialog) { val availableBuiltInWidgets = diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt index bbfb3105..f9ae71b0 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt @@ -6,18 +6,24 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.liveData +import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.widgets.ExternalWidget import de.mm20.launcher2.widgets.Widget import de.mm20.launcher2.widgets.WidgetRepository import de.mm20.launcher2.widgets.WidgetType import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map import org.koin.core.component.KoinComponent import org.koin.core.component.inject class WidgetsVM : ViewModel(), KoinComponent { private val widgetRepository: WidgetRepository by inject() + private val dataStore: LauncherDataStore by inject() + + val editButton = dataStore.data.map { it.widgets.editButton }.asLiveData() + val widgets = widgetRepository.getWidgets().asLiveData() fun addWidget(widget: Widget) { diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetSettingsScreenVM.kt index eceeb3be..1c37a1a9 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetSettingsScreenVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetSettingsScreenVM.kt @@ -2,16 +2,35 @@ 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.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 { +class WidgetSettingsScreenVM : ViewModel(), KoinComponent { + private val widgetRepository: WidgetRepository by inject() + private val dataStore: LauncherDataStore by inject() val calendarWidget = widgetRepository.isCalendarWidgetEnabled().asLiveData() val musicWidget = widgetRepository.isMusicWidgetEnabled().asLiveData() val weatherWidget = widgetRepository.isWeatherWidgetEnabled().asLiveData() val favoritesWidget = widgetRepository.isFavoritesWidgetEnabled().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/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetsSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetsSettingsScreen.kt index 42e95f38..f22594d9 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetsSettingsScreen.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/widgets/WidgetsSettingsScreen.kt @@ -13,7 +13,9 @@ 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 @@ -22,56 +24,71 @@ fun WidgetsSettingsScreen() { val viewModel: WidgetSettingsScreenVM = viewModel() PreferenceScreen(title = stringResource(R.string.preference_screen_widgets)) { item { - Preference( - title = stringResource(R.string.preference_screen_clockwidget), - icon = Icons.Rounded.Schedule, - onClick = { - navController?.navigate("settings/widgets/clock") + 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 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") + } + ) + } } + } - 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) + }) } } }