Add a preference to hide the edit favorites button

This commit is contained in:
MM20 2022-09-27 20:45:34 +02:00
parent a2aca9bded
commit 9309cd4891
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
9 changed files with 238 additions and 143 deletions

View File

@ -620,6 +620,8 @@
<string name="preference_edit_favorites_summary">Change the order of pinned items</string>
<string name="preference_category_favorites_frequently_used">Frequently used</string>
<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>
<!-- 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

@ -59,6 +59,7 @@ fun createFactorySettings(context: Context): Settings {
.setEnabled(true)
.setFrequentlyUsed(true)
.setFrequentlyUsedRows(1)
.setEditButton(true)
)
.setFileSearch(
Settings.FilesSearchSettings

View File

@ -8,6 +8,7 @@ class Migration_9_10: VersionedMigration(9, 10) {
builder.favorites.toBuilder()
.setFrequentlyUsed(true)
.setFrequentlyUsedRows(1)
.setEditButton(true)
)
}
}

View File

@ -128,6 +128,7 @@ message Settings {
bool enabled = 1;
bool frequently_used = 2;
int32 frequently_used_rows = 3;
bool edit_button = 4;
}
FavoritesSettings favorites = 8;

View File

@ -22,6 +22,8 @@ open class FavoritesVM : ViewModel(), KoinComponent {
val selectedTag = MutableStateFlow<String?>(null)
val showEditButton = dataStore.data.map { it.favorites.editButton }
val pinnedTags = favoritesRepository.getFavorites(
includeTypes = listOf("tag"),
manuallySorted = true,

View File

@ -2,14 +2,39 @@ package de.mm20.launcher2.ui.launcher.search
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.Person
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material.icons.rounded.Tag
import androidx.compose.material.icons.rounded.Work
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
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.clipToBounds
@ -82,6 +107,7 @@ fun SearchColumn(
val pinnedTags by favoritesVM.pinnedTags.collectAsState(emptyList())
val selectedTag by favoritesVM.selectedTag.collectAsState(null)
val tagsScrollState = rememberScrollState()
val favoritesEditButton by favoritesVM.showEditButton.collectAsState(false)
LazyColumn(
state = state,
@ -115,56 +141,62 @@ fun SearchColumn(
)
}
} else null,
after = {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(
top = if (reverse) 8.dp else 4.dp,
bottom = if (reverse) 4.dp else 8.dp,
end = 8.dp
),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
after = if (pinnedTags.isEmpty() && !favoritesEditButton) {
null
} else {
{
Row(
modifier = Modifier
.weight(1f)
.horizontalScroll(tagsScrollState)
.padding(end = 12.dp),
.fillMaxWidth()
.padding(
top = if (reverse) 8.dp else 4.dp,
bottom = if (reverse) 4.dp else 8.dp,
end = if (favoritesEditButton) 8.dp else 0.dp
),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
FilterChip(
modifier = Modifier.padding(start = 16.dp),
selected = selectedTag == null,
onClick = { favoritesVM.selectTag(null) },
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Star,
contentDescription = null
)
},
label = { Text(stringResource(R.string.favorites)) }
)
for (tag in pinnedTags) {
Row(
modifier = Modifier
.weight(1f)
.horizontalScroll(tagsScrollState)
.padding(end = 12.dp),
) {
FilterChip(
modifier = Modifier.padding(start = 8.dp),
selected = selectedTag == tag.tag,
onClick = { favoritesVM.selectTag(tag.tag) },
modifier = Modifier.padding(start = 16.dp),
selected = selectedTag == null,
onClick = { favoritesVM.selectTag(null) },
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Tag,
imageVector = Icons.Rounded.Star,
contentDescription = null
)
},
label = { Text(tag.label) }
label = { Text(stringResource(R.string.favorites)) }
)
for (tag in pinnedTags) {
FilterChip(
modifier = Modifier.padding(start = 8.dp),
selected = selectedTag == tag.tag,
onClick = { favoritesVM.selectTag(tag.tag) },
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Tag,
contentDescription = null
)
},
label = { Text(tag.label) }
)
}
}
if (favoritesEditButton) {
SmallFloatingActionButton(
elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(),
onClick = { showEditFavoritesDialog = true }
) {
Icon(imageVector = Icons.Rounded.Edit, contentDescription = null)
}
}
}
SmallFloatingActionButton(
elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(),
onClick = { showEditFavoritesDialog = true }
) {
Icon(imageVector = Icons.Rounded.Edit, contentDescription = null)
}
}
}
@ -221,22 +253,24 @@ fun SearchColumn(
} else null
)
ListResults(
before = if (missingShortcutsPermission && !isSearchEmpty){{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_appshortcuts_search),
onClick = { viewModel.requestAppShortcutPermission(context as AppCompatActivity) },
secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableAppShortcutSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
before = if (missingShortcutsPermission && !isSearchEmpty) {
{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_appshortcuts_search),
onClick = { viewModel.requestAppShortcutPermission(context as AppCompatActivity) },
secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableAppShortcutSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
}
}
}
)
}} else null,
)
}
} else null,
items = appShortcuts.toImmutableList(),
reverse = reverse,
key = "shortcuts"
@ -254,42 +288,47 @@ fun SearchColumn(
}
}
ListResults(
before = if (missingCalendarPermission && !isSearchEmpty){{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_calendar_search),
onClick = { viewModel.requestCalendarPermission(context as AppCompatActivity) },secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableCalendarSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
before = if (missingCalendarPermission && !isSearchEmpty) {
{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_calendar_search),
onClick = { viewModel.requestCalendarPermission(context as AppCompatActivity) },
secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableCalendarSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
}
}
}
)
}} else null,
)
}
} else null,
items = events.toImmutableList(),
reverse = reverse,
key = "events"
)
ListResults(
before = if (missingContactsPermission && !isSearchEmpty){{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_contact_search),
onClick = { viewModel.requestContactsPermission(context as AppCompatActivity) },
secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableContactsSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
before = if (missingContactsPermission && !isSearchEmpty) {
{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_contact_search),
onClick = { viewModel.requestContactsPermission(context as AppCompatActivity) },
secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableContactsSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
}
}
}
)
}} else null,
)
}
} else null,
items = contacts.toImmutableList(),
reverse = reverse,
key = "contacts"
@ -307,22 +346,24 @@ fun SearchColumn(
}
}
ListResults(
before = if (missingFilesPermission && !isSearchEmpty){{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_files_search),
onClick = { viewModel.requestFilesPermission(context as AppCompatActivity) },
secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableFilesSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
before = if (missingFilesPermission && !isSearchEmpty) {
{
MissingPermissionBanner(
modifier = Modifier.padding(8.dp),
text = stringResource(R.string.missing_permission_files_search),
onClick = { viewModel.requestFilesPermission(context as AppCompatActivity) },
secondaryAction = {
OutlinedButton(onClick = {
viewModel.disableFilesSearch()
}) {
Text(
stringResource(R.string.turn_off),
)
}
}
}
)
}} else null,
)
}
} else null,
items = files.toImmutableList(),
reverse = reverse,
key = "files"

View File

@ -1,14 +1,28 @@
package de.mm20.launcher2.ui.launcher.widgets.favorites
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material.icons.rounded.Tag
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
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.res.stringResource
@ -25,6 +39,7 @@ fun FavoritesWidget() {
val pinnedTags by viewModel.pinnedTags.collectAsState(emptyList())
val selectedTag by viewModel.selectedTag.collectAsState(null)
var showEditFavoritesDialog by remember { mutableStateOf(false) }
val favoritesEditButton by viewModel.showEditButton.collectAsState(false)
Column {
if (favorites.isNotEmpty()) {
@ -41,54 +56,59 @@ fun FavoritesWidget() {
color = MaterialTheme.colorScheme.outline
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(
top = 4.dp,
bottom = 8.dp,
end = 8.dp
),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
if (pinnedTags.isNotEmpty() || favoritesEditButton) {
Row(
modifier = Modifier
.weight(1f)
.horizontalScroll(rememberScrollState()),
.fillMaxWidth()
.padding(
top = 4.dp,
bottom = 8.dp,
end = if (favoritesEditButton) 8.dp else 0.dp
),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
FilterChip(
modifier = Modifier.padding(start = 16.dp),
selected = selectedTag == null,
onClick = { viewModel.selectTag(null) },
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Star,
contentDescription = null
)
},
label = { Text(stringResource(R.string.favorites)) }
)
for (tag in pinnedTags) {
Row(
modifier = Modifier
.weight(1f)
.horizontalScroll(rememberScrollState())
.padding(end = 12.dp),
) {
FilterChip(
modifier = Modifier.padding(start = 8.dp),
selected = selectedTag == tag.tag,
onClick = { viewModel.selectTag(tag.tag) },
modifier = Modifier.padding(start = 16.dp),
selected = selectedTag == null,
onClick = { viewModel.selectTag(null) },
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Tag,
imageVector = Icons.Rounded.Star,
contentDescription = null
)
},
label = { Text(tag.label) }
label = { Text(stringResource(R.string.favorites)) }
)
for (tag in pinnedTags) {
FilterChip(
modifier = Modifier.padding(start = 8.dp),
selected = selectedTag == tag.tag,
onClick = { viewModel.selectTag(tag.tag) },
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Tag,
contentDescription = null
)
},
label = { Text(tag.label) }
)
}
}
if (favoritesEditButton) {
SmallFloatingActionButton(
elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(),
onClick = { showEditFavoritesDialog = true }
) {
Icon(imageVector = Icons.Rounded.Edit, contentDescription = null)
}
}
}
SmallFloatingActionButton(
elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(),
onClick = { showEditFavoritesDialog = true }
) {
Icon(imageVector = Icons.Rounded.Edit, contentDescription = null)
}
}
}

View File

@ -58,6 +58,19 @@ fun FavoritesSettingsScreen() {
)
}
}
item {
val editButton by viewModel.editButton.observeAsState()
PreferenceCategory {
SwitchPreference(
title = stringResource(R.string.preference_edit_button),
summary = stringResource(R.string.preference_favorites_edit_button_summary),
value = editButton == true,
onValueChanged = {
viewModel.setEditButton(it)
}
)
}
}
}
if (showEditSheet) {

View File

@ -39,4 +39,18 @@ class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
}
}
}
val editButton = dataStore.data.map { it.favorites.editButton }.asLiveData()
fun setEditButton(editButton: Boolean) {
viewModelScope.launch {
dataStore.updateData {
it.toBuilder()
.setFavorites(
it.favorites.toBuilder()
.setEditButton(editButton)
)
.build()
}
}
}
}