From 94893a2c4347365b598c64851c7ffa4b8d621c0a Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Wed, 1 May 2024 16:21:39 +0200 Subject: [PATCH] Add filter bar customizations --- .../ui/component/dragndrop/DragAndDropList.kt | 2 +- .../launcher2/ui/launcher/search/SearchVM.kt | 1 + .../search/filters/KeyboardFilterBar.kt | 205 +++--------------- .../search/filters/KeyboardFilterBarItem.kt | 88 ++++++++ .../launcher/searchbar/LauncherSearchBar.kt | 4 +- .../launcher2/ui/settings/SettingsActivity.kt | 4 + .../filterbar/FilterBarSettingsScreen.kt | 139 ++++++++++++ .../filterbar/FilterBarSettingsScreenVM.kt | 41 ++++ .../settings/search/SearchSettingsScreen.kt | 9 + core/i18n/src/main/res/values/strings.xml | 2 + .../preferences/LauncherSettingsData.kt | 1 - .../search/SearchFilterSettings.kt | 9 + 12 files changed, 330 insertions(+), 175 deletions(-) create mode 100644 app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBarItem.kt create mode 100644 app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreen.kt create mode 100644 app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreenVM.kt diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/component/dragndrop/DragAndDropList.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/component/dragndrop/DragAndDropList.kt index b4ce1e3d..a907c96b 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/component/dragndrop/DragAndDropList.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/component/dragndrop/DragAndDropList.kt @@ -301,7 +301,7 @@ fun Modifier.dragAndDrop( dragHorizontal: Boolean = true, hapticFeedback: HapticFeedback ) = - this then pointerInput(null) { + this then Modifier.pointerInput(null) { val scope = CoroutineScope(coroutineContext) detectDragGesturesAfterLongPress( onDragStart = { offset -> diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt index d5c645cd..17647616 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt @@ -96,6 +96,7 @@ class SearchVM : ViewModel(), KoinComponent { private val defaultFilters = searchFilterSettings.defaultFilter.stateIn(viewModelScope, SharingStarted.Eagerly, SearchFilters()) val filters = mutableStateOf(defaultFilters.value) val filterBar = searchFilterSettings.filterBar + val filterBarItems = searchFilterSettings.filterBarItems val separateWorkProfile = searchUiSettings.separateWorkProfile diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBar.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBar.kt index 0f3d7614..de28c0d5 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBar.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBar.kt @@ -31,14 +31,21 @@ import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable 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 de.mm20.launcher2.preferences.KeyboardFilterBarItem import de.mm20.launcher2.search.SearchFilters import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.icons.Wikipedia @Composable -fun KeyboardFilterBar(filters: SearchFilters, onFiltersChange: (SearchFilters) -> Unit) { +fun KeyboardFilterBar( + filters: SearchFilters, + onFiltersChange: (SearchFilters) -> Unit, + items: List, +) { + val context = LocalContext.current val allCategoriesEnabled = filters.allCategoriesEnabled Column( modifier = Modifier @@ -54,178 +61,32 @@ fun KeyboardFilterBar(filters: SearchFilters, onFiltersChange: (SearchFilters) - .padding(horizontal = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { - FilterChip( - selected = filters.allowNetwork, - onClick = { - onFiltersChange(filters.copy(allowNetwork = !filters.allowNetwork)) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Language, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) + for (i in items.indices) { + val item = items[i] + val prevItem = items.getOrNull(i - 1) + if (prevItem != null && prevItem.isCategory != item.isCategory) { + VerticalDivider( + modifier = Modifier + .height(36.dp) + .padding(end = 8.dp) ) - }, - label = { Text(stringResource(R.string.search_filter_online)) } - ) - VerticalDivider( - modifier = Modifier - .height(36.dp) - .padding(horizontal = 8.dp) - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.apps && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleApps()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Apps, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.search_filter_apps)) } - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.files && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleFiles()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Description, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_search_files)) } - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.contacts && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleContacts()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Person, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_search_contacts)) } - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.events && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleEvents()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Today, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_search_calendar)) } - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.shortcuts && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleShortcuts()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.AppShortcut, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_search_appshortcuts)) } - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.articles && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleArticles()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Wikipedia, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_search_wikipedia)) } - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.websites && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleWebsites()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Public, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_search_websites)) } - ) - FilterChip( - modifier = Modifier.padding(end = 8.dp), - selected = filters.places && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.togglePlaces()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Place, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_search_locations)) } - ) - FilterChip( - selected = filters.tools && !allCategoriesEnabled, - onClick = { - onFiltersChange(filters.toggleTools()) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.Handyman, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.search_filter_tools)) } - ) - VerticalDivider( - modifier = Modifier - .height(36.dp) - .padding(horizontal = 8.dp) - ) - FilterChip( - selected = filters.hiddenItems, - onClick = { - onFiltersChange(filters.copy(hiddenItems = !filters.hiddenItems)) - }, - leadingIcon = { - Icon( - imageVector = Icons.Rounded.VisibilityOff, - contentDescription = null, - modifier = Modifier.size(FilterChipDefaults.IconSize) - ) - }, - label = { Text(stringResource(R.string.preference_hidden_items)) } - ) + } + FilterChip( + modifier = Modifier.padding(end = if (i == items.lastIndex) 0.dp else 8.dp), + selected = filters.isSelected(item), + onClick = { + onFiltersChange(filters.toggle(item)) + }, + leadingIcon = { + Icon( + imageVector = item.icon, + contentDescription = null, + modifier = Modifier.size(FilterChipDefaults.IconSize) + ) + }, + label = { Text(item.getLabel(context)) } + ) + } } HorizontalDivider() } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBarItem.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBarItem.kt new file mode 100644 index 00000000..93349853 --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/filters/KeyboardFilterBarItem.kt @@ -0,0 +1,88 @@ +package de.mm20.launcher2.ui.launcher.search.filters + +import android.content.Context +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.AppShortcut +import androidx.compose.material.icons.rounded.Apps +import androidx.compose.material.icons.rounded.Description +import androidx.compose.material.icons.rounded.Handyman +import androidx.compose.material.icons.rounded.Language +import androidx.compose.material.icons.rounded.Person +import androidx.compose.material.icons.rounded.Place +import androidx.compose.material.icons.rounded.Public +import androidx.compose.material.icons.rounded.Today +import androidx.compose.material.icons.rounded.VisibilityOff +import de.mm20.launcher2.preferences.KeyboardFilterBarItem +import de.mm20.launcher2.search.SearchFilters +import de.mm20.launcher2.ui.R +import de.mm20.launcher2.ui.icons.Wikipedia + +val KeyboardFilterBarItem.icon + get() = when (this) { + KeyboardFilterBarItem.Apps -> Icons.Rounded.Apps + KeyboardFilterBarItem.Events -> Icons.Rounded.Today + KeyboardFilterBarItem.Contacts -> Icons.Rounded.Person + KeyboardFilterBarItem.Places -> Icons.Rounded.Place + KeyboardFilterBarItem.Files -> Icons.Rounded.Description + KeyboardFilterBarItem.Tools -> Icons.Rounded.Handyman + KeyboardFilterBarItem.Articles -> Icons.Rounded.Wikipedia + KeyboardFilterBarItem.Websites -> Icons.Rounded.Public + KeyboardFilterBarItem.Shortcuts -> Icons.Rounded.AppShortcut + KeyboardFilterBarItem.HiddenResults -> Icons.Rounded.VisibilityOff + KeyboardFilterBarItem.OnlineResults -> Icons.Rounded.Language + } + +fun KeyboardFilterBarItem.getLabel(context: Context): String { + return when (this) { + KeyboardFilterBarItem.Apps -> context.getString(R.string.search_filter_apps) + KeyboardFilterBarItem.Events -> context.getString(R.string.preference_search_calendar) + KeyboardFilterBarItem.Contacts -> context.getString(R.string.preference_search_contacts) + KeyboardFilterBarItem.Places -> context.getString(R.string.preference_search_locations) + KeyboardFilterBarItem.Files -> context.getString(R.string.preference_search_files) + KeyboardFilterBarItem.Tools -> context.getString(R.string.search_filter_tools) + KeyboardFilterBarItem.Articles -> context.getString(R.string.preference_search_wikipedia) + KeyboardFilterBarItem.Websites -> context.getString(R.string.preference_search_websites) + KeyboardFilterBarItem.Shortcuts -> context.getString(R.string.preference_search_appshortcuts) + KeyboardFilterBarItem.HiddenResults -> context.getString(R.string.preference_hidden_items) + KeyboardFilterBarItem.OnlineResults -> context.getString(R.string.search_filter_online) + } +} + +val KeyboardFilterBarItem.isCategory + get() = when (this) { + KeyboardFilterBarItem.OnlineResults, KeyboardFilterBarItem.HiddenResults -> false + else -> true + } + +fun SearchFilters.isSelected(item: KeyboardFilterBarItem): Boolean { + if (item.isCategory && allCategoriesEnabled) return false + return when (item) { + KeyboardFilterBarItem.Apps -> apps + KeyboardFilterBarItem.Events -> events + KeyboardFilterBarItem.Contacts -> contacts + KeyboardFilterBarItem.Places -> places + KeyboardFilterBarItem.Files -> files + KeyboardFilterBarItem.Tools -> tools + KeyboardFilterBarItem.Articles -> articles + KeyboardFilterBarItem.Websites -> websites + KeyboardFilterBarItem.Shortcuts -> shortcuts + KeyboardFilterBarItem.HiddenResults -> hiddenItems + KeyboardFilterBarItem.OnlineResults -> allowNetwork + } +} + +fun SearchFilters.toggle(item: KeyboardFilterBarItem): SearchFilters { + return when (item) { + KeyboardFilterBarItem.Apps -> return toggleApps() + KeyboardFilterBarItem.Events -> return toggleEvents() + KeyboardFilterBarItem.Contacts -> return toggleContacts() + KeyboardFilterBarItem.Places -> return togglePlaces() + KeyboardFilterBarItem.Files -> return toggleFiles() + KeyboardFilterBarItem.Tools -> return toggleTools() + KeyboardFilterBarItem.Articles -> return toggleArticles() + KeyboardFilterBarItem.Websites -> return toggleWebsites() + KeyboardFilterBarItem.Shortcuts -> return toggleShortcuts() + KeyboardFilterBarItem.HiddenResults -> return copy(hiddenItems = !hiddenItems) + KeyboardFilterBarItem.OnlineResults -> return copy(allowNetwork = !allowNetwork) + } +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt index e1b661e3..aae29036 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt @@ -137,11 +137,13 @@ fun LauncherSearchBar( exit = fadeOut(), modifier = Modifier.align(Alignment.BottomCenter) ) { + val items by searchVM.filterBarItems.collectAsState(emptyList()) KeyboardFilterBar( filters = searchVM.filters.value, onFiltersChange = { searchVM.setFilters(it) - } + }, + items = items ) } } 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 40bd8be1..baa76e92 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 @@ -42,6 +42,7 @@ import de.mm20.launcher2.ui.settings.debug.DebugSettingsScreen import de.mm20.launcher2.ui.settings.easteregg.EasterEggSettingsScreen import de.mm20.launcher2.ui.settings.favorites.FavoritesSettingsScreen import de.mm20.launcher2.ui.settings.filesearch.FileSearchSettingsScreen +import de.mm20.launcher2.ui.settings.filterbar.FilterBarSettingsScreen import de.mm20.launcher2.ui.settings.gestures.GestureSettingsScreen import de.mm20.launcher2.ui.settings.hiddenitems.HiddenItemsSettingsScreen import de.mm20.launcher2.ui.settings.homescreen.HomescreenSettingsScreen @@ -170,6 +171,9 @@ class SettingsActivity : BaseActivity() { composable("settings/search/tags") { TagsSettingsScreen() } + composable("settings/search/filterbar") { + FilterBarSettingsScreen() + } composable(ROUTE_WEATHER_INTEGRATION) { WeatherIntegrationSettingsScreen() } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreen.kt new file mode 100644 index 00000000..4b5a5b9a --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreen.kt @@ -0,0 +1,139 @@ +package de.mm20.launcher2.ui.settings.filterbar + +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +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.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.accompanist.systemuicontroller.rememberSystemUiController +import de.mm20.launcher2.preferences.KeyboardFilterBarItem +import de.mm20.launcher2.ui.R +import de.mm20.launcher2.ui.component.dragndrop.DraggableItem +import de.mm20.launcher2.ui.component.dragndrop.LazyDragAndDropColumn +import de.mm20.launcher2.ui.component.dragndrop.rememberLazyDragAndDropListState +import de.mm20.launcher2.ui.component.preferences.SwitchPreference +import de.mm20.launcher2.ui.launcher.search.filters.getLabel +import de.mm20.launcher2.ui.launcher.search.filters.icon +import de.mm20.launcher2.ui.launcher.search.filters.isCategory +import de.mm20.launcher2.ui.locals.LocalNavController + +@Composable +fun FilterBarSettingsScreen() { + val viewModel: FilterBarSettingsScreenVM = viewModel() + val navController = LocalNavController.current + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(MaterialTheme.colorScheme.surface) + systemUiController.setNavigationBarColor(Color.Black) + + val context = LocalContext.current + val activity = LocalContext.current as? AppCompatActivity + + val listState = rememberLazyDragAndDropListState( + onDragStart = { + it.key is KeyboardFilterBarItem + }, + onItemMove = { from, to -> + val item = (from.key as? KeyboardFilterBarItem) ?: return@rememberLazyDragAndDropListState + val toItem = (to.key as? KeyboardFilterBarItem) ?: return@rememberLazyDragAndDropListState + viewModel.moveItem(item, toItem) + } + ) + + val enabledItems by viewModel.filterBarItems.collectAsState() + + val disabledItems by remember { + derivedStateOf { + KeyboardFilterBarItem.entries.filter { enabledItems?.contains(it) == false } + } + } + + Scaffold( + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + stringResource(id = R.string.preference_customize_filter_bar), + overflow = TextOverflow.Ellipsis, + modifier = Modifier.padding(horizontal = 16.dp), + maxLines = 1 + ) + }, + navigationIcon = { + IconButton(onClick = { + if (navController?.navigateUp() != true) { + activity?.onBackPressed() + } + }) { + Icon(imageVector = Icons.Rounded.ArrowBack, contentDescription = "Back") + } + }, + ) + }) { + + if (enabledItems == null) { + return@Scaffold + } + + LazyDragAndDropColumn( + state = listState, + bidirectionalDrag = false, + contentPadding = it, + modifier = Modifier + .fillMaxSize() + ) { + for (i in 0 until KeyboardFilterBarItem.entries.size) { + val item = enabledItems!!.getOrNull(i) ?: disabledItems[i - enabledItems!!.size] + val prevItem = enabledItems!!.getOrNull(i - 1) ?: disabledItems.getOrNull(i - enabledItems!!.size - 1) + if (prevItem != null && prevItem.isCategory != item.isCategory) { + item(key = "divider-$i") { + HorizontalDivider() + } + } + item(key = item) { + DraggableItem(state = listState, key = item) { + val elevation by animateDpAsState(if (it) 4.dp else 0.dp) + Surface( + shadowElevation = elevation, + tonalElevation = elevation, + modifier = Modifier.zIndex(if (it) 1f else 0f) + ) { + SwitchPreference( + title = item.getLabel(context), + icon = item.icon, + value = enabledItems!!.contains(item), onValueChanged = { + if (it) { + viewModel.addAction(item) + } else { + viewModel.removeAction(item) + } + } + ) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreenVM.kt new file mode 100644 index 00000000..24d7b3f0 --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filterbar/FilterBarSettingsScreenVM.kt @@ -0,0 +1,41 @@ +package de.mm20.launcher2.ui.settings.filterbar + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import de.mm20.launcher2.preferences.KeyboardFilterBarItem +import de.mm20.launcher2.preferences.search.SearchFilterSettings +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +class FilterBarSettingsScreenVM( +) : ViewModel(), KoinComponent { + private val searchFilterSettings: SearchFilterSettings by inject() + + val filterBarItems = searchFilterSettings.filterBarItems + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) + + fun moveItem(item: KeyboardFilterBarItem, toItem: KeyboardFilterBarItem) { + val items = filterBarItems.value?.toMutableList() ?: return + val fromIndex = items.indexOf(item) + val toIndex = items.indexOf(toItem) + if (fromIndex > items.lastIndex) return + if (toIndex > items.lastIndex) return + if (fromIndex != -1) items.removeAt(fromIndex) + if (toIndex != -1) items.add(toIndex, item) + searchFilterSettings.setFilterBarItems(items) + } + + fun addAction(item: KeyboardFilterBarItem) { + val items = filterBarItems.value?.toMutableList() ?: return + items.add(item) + searchFilterSettings.setFilterBarItems(items) + } + + fun removeAction(item: KeyboardFilterBarItem) { + val items = filterBarItems.value?.toMutableList() ?: return + items.remove(item) + searchFilterSettings.setFilterBarItems(items) + } +} \ No newline at end of file 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 e962039a..97b5333a 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 @@ -290,6 +290,15 @@ fun SearchSettingsScreen() { viewModel.setFilterBar(it) } ) + AnimatedVisibility(filterBar == true) { + Preference( + title = stringResource(R.string.preference_customize_filter_bar), + summary = stringResource(R.string.preference_customize_filter_bar_summary), + onClick = { + navController?.navigate("settings/search/filterbar") + } + ) + } } } if (hasWorkProfile) { diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index bbcaf834..b8c457ab 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -922,5 +922,7 @@ Customize the default filter for searches Show filter bar Show quick filters above the keyboard + Customize filter bar + Customize which items are included in the filter bar The current filter enables online results by default. Your search queries might unintentionally be sent to external web services. For privacy reasons, this is not recommended. \ No newline at end of file diff --git a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt index 46851f79..188f183f 100644 --- a/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt +++ b/core/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherSettingsData.kt @@ -154,7 +154,6 @@ data class LauncherSettingsData internal constructor( KeyboardFilterBarItem.Events, KeyboardFilterBarItem.Contacts, KeyboardFilterBarItem.Files, - KeyboardFilterBarItem.Places, KeyboardFilterBarItem.Articles, KeyboardFilterBarItem.Websites, KeyboardFilterBarItem.Places, diff --git a/core/preferences/src/main/java/de/mm20/launcher2/preferences/search/SearchFilterSettings.kt b/core/preferences/src/main/java/de/mm20/launcher2/preferences/search/SearchFilterSettings.kt index 01e76180..78da05d6 100644 --- a/core/preferences/src/main/java/de/mm20/launcher2/preferences/search/SearchFilterSettings.kt +++ b/core/preferences/src/main/java/de/mm20/launcher2/preferences/search/SearchFilterSettings.kt @@ -1,5 +1,6 @@ package de.mm20.launcher2.preferences.search +import de.mm20.launcher2.preferences.KeyboardFilterBarItem import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.search.SearchFilters import kotlinx.coroutines.flow.map @@ -25,4 +26,12 @@ class SearchFilterSettings internal constructor( } } + val filterBarItems + get() = launcherDataStore.data.map { it.searchFilterBarItems.distinct() } + + fun setFilterBarItems(items: List) { + launcherDataStore.update { + it.copy(searchFilterBarItems = items) + } + } } \ No newline at end of file