Add preference to hide widget edit button

This commit is contained in:
MM20 2022-09-27 21:06:07 +02:00
parent 9309cd4891
commit fc6d1d382c
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
8 changed files with 181 additions and 103 deletions

View File

@ -622,6 +622,7 @@
<string name="preference_favorites_frequently_used_summary">Show frequently used items in favorites</string>
<string name="preference_edit_button">Edit button</string>
<string name="preference_favorites_edit_button_summary">Show a button to rearrange the favorites</string>
<string name="preference_widgets_edit_button_summary">Show a button to add, remove and rearrange widgets</string>
<!-- Used in an info banner if a specific feature requires a Nextcloud account -->
<string name="no_account_nextcloud">You haven\'t connected a Nextcloud account yet</string>
<!-- Used in an info banner if a specific feature requires an Owncloud account -->

View File

@ -155,6 +155,10 @@ fun createFactorySettings(context: Context): Settings {
.setRadius(8)
.setOpacity(1f)
)
.setWidgets(
Settings.WidgetSettings.newBuilder()
.setEditButton(true)
)
.build()
}

View File

@ -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)
)
}
}

View File

@ -259,4 +259,9 @@ message Settings {
bool enabled = 1;
}
AppShortcutSearchSettings app_shortcut_search = 25;
message WidgetSettings {
bool edit_button = 1;
}
WidgetSettings widgets = 26;
}

View File

@ -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 =

View File

@ -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) {

View File

@ -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()
}
}
}
}

View File

@ -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)
})
}
}
}