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_edit_favorites_summary">Change the order of pinned items</string>
<string name="preference_category_favorites_frequently_used">Frequently used</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_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 --> <!-- 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> <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 --> <!-- 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) .setEnabled(true)
.setFrequentlyUsed(true) .setFrequentlyUsed(true)
.setFrequentlyUsedRows(1) .setFrequentlyUsedRows(1)
.setEditButton(true)
) )
.setFileSearch( .setFileSearch(
Settings.FilesSearchSettings Settings.FilesSearchSettings

View File

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

View File

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

View File

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

View File

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

View File

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