Add filter bar customizations

This commit is contained in:
MM20 2024-05-01 16:21:39 +02:00
parent 5d824108c7
commit 94893a2c43
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
12 changed files with 330 additions and 175 deletions

View File

@ -301,7 +301,7 @@ fun Modifier.dragAndDrop(
dragHorizontal: Boolean = true, dragHorizontal: Boolean = true,
hapticFeedback: HapticFeedback hapticFeedback: HapticFeedback
) = ) =
this then pointerInput(null) { this then Modifier.pointerInput(null) {
val scope = CoroutineScope(coroutineContext) val scope = CoroutineScope(coroutineContext)
detectDragGesturesAfterLongPress( detectDragGesturesAfterLongPress(
onDragStart = { offset -> onDragStart = { offset ->

View File

@ -96,6 +96,7 @@ class SearchVM : ViewModel(), KoinComponent {
private val defaultFilters = searchFilterSettings.defaultFilter.stateIn(viewModelScope, SharingStarted.Eagerly, SearchFilters()) private val defaultFilters = searchFilterSettings.defaultFilter.stateIn(viewModelScope, SharingStarted.Eagerly, SearchFilters())
val filters = mutableStateOf(defaultFilters.value) val filters = mutableStateOf(defaultFilters.value)
val filterBar = searchFilterSettings.filterBar val filterBar = searchFilterSettings.filterBar
val filterBarItems = searchFilterSettings.filterBarItems
val separateWorkProfile = searchUiSettings.separateWorkProfile val separateWorkProfile = searchUiSettings.separateWorkProfile

View File

@ -31,14 +31,21 @@ import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import de.mm20.launcher2.preferences.KeyboardFilterBarItem
import de.mm20.launcher2.search.SearchFilters import de.mm20.launcher2.search.SearchFilters
import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.icons.Wikipedia import de.mm20.launcher2.ui.icons.Wikipedia
@Composable @Composable
fun KeyboardFilterBar(filters: SearchFilters, onFiltersChange: (SearchFilters) -> Unit) { fun KeyboardFilterBar(
filters: SearchFilters,
onFiltersChange: (SearchFilters) -> Unit,
items: List<KeyboardFilterBarItem>,
) {
val context = LocalContext.current
val allCategoriesEnabled = filters.allCategoriesEnabled val allCategoriesEnabled = filters.allCategoriesEnabled
Column( Column(
modifier = Modifier modifier = Modifier
@ -54,179 +61,33 @@ fun KeyboardFilterBar(filters: SearchFilters, onFiltersChange: (SearchFilters) -
.padding(horizontal = 8.dp), .padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
FilterChip( for (i in items.indices) {
selected = filters.allowNetwork, val item = items[i]
onClick = { val prevItem = items.getOrNull(i - 1)
onFiltersChange(filters.copy(allowNetwork = !filters.allowNetwork)) if (prevItem != null && prevItem.isCategory != item.isCategory) {
},
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Language,
contentDescription = null,
modifier = Modifier.size(FilterChipDefaults.IconSize)
)
},
label = { Text(stringResource(R.string.search_filter_online)) }
)
VerticalDivider( VerticalDivider(
modifier = Modifier modifier = Modifier
.height(36.dp) .height(36.dp)
.padding(horizontal = 8.dp) .padding(end = 8.dp)
) )
}
FilterChip( FilterChip(
modifier = Modifier.padding(end = 8.dp), modifier = Modifier.padding(end = if (i == items.lastIndex) 0.dp else 8.dp),
selected = filters.apps && !allCategoriesEnabled, selected = filters.isSelected(item),
onClick = { onClick = {
onFiltersChange(filters.toggleApps()) onFiltersChange(filters.toggle(item))
}, },
leadingIcon = { leadingIcon = {
Icon( Icon(
imageVector = Icons.Rounded.Apps, imageVector = item.icon,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(FilterChipDefaults.IconSize) modifier = Modifier.size(FilterChipDefaults.IconSize)
) )
}, },
label = { Text(stringResource(R.string.search_filter_apps)) } label = { Text(item.getLabel(context)) }
)
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)) }
) )
} }
}
HorizontalDivider() HorizontalDivider()
} }
} }

View File

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

View File

@ -137,11 +137,13 @@ fun LauncherSearchBar(
exit = fadeOut(), exit = fadeOut(),
modifier = Modifier.align(Alignment.BottomCenter) modifier = Modifier.align(Alignment.BottomCenter)
) { ) {
val items by searchVM.filterBarItems.collectAsState(emptyList())
KeyboardFilterBar( KeyboardFilterBar(
filters = searchVM.filters.value, filters = searchVM.filters.value,
onFiltersChange = { onFiltersChange = {
searchVM.setFilters(it) searchVM.setFilters(it)
} },
items = items
) )
} }
} }

View File

@ -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.easteregg.EasterEggSettingsScreen
import de.mm20.launcher2.ui.settings.favorites.FavoritesSettingsScreen import de.mm20.launcher2.ui.settings.favorites.FavoritesSettingsScreen
import de.mm20.launcher2.ui.settings.filesearch.FileSearchSettingsScreen 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.gestures.GestureSettingsScreen
import de.mm20.launcher2.ui.settings.hiddenitems.HiddenItemsSettingsScreen import de.mm20.launcher2.ui.settings.hiddenitems.HiddenItemsSettingsScreen
import de.mm20.launcher2.ui.settings.homescreen.HomescreenSettingsScreen import de.mm20.launcher2.ui.settings.homescreen.HomescreenSettingsScreen
@ -170,6 +171,9 @@ class SettingsActivity : BaseActivity() {
composable("settings/search/tags") { composable("settings/search/tags") {
TagsSettingsScreen() TagsSettingsScreen()
} }
composable("settings/search/filterbar") {
FilterBarSettingsScreen()
}
composable(ROUTE_WEATHER_INTEGRATION) { composable(ROUTE_WEATHER_INTEGRATION) {
WeatherIntegrationSettingsScreen() WeatherIntegrationSettingsScreen()
} }

View File

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

View File

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

View File

@ -290,6 +290,15 @@ fun SearchSettingsScreen() {
viewModel.setFilterBar(it) 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) { if (hasWorkProfile) {

View File

@ -922,5 +922,7 @@
<string name="preference_default_filter_summary">Customize the default filter for searches</string> <string name="preference_default_filter_summary">Customize the default filter for searches</string>
<string name="preference_filter_bar">Show filter bar</string> <string name="preference_filter_bar">Show filter bar</string>
<string name="preference_filter_bar_summary">Show quick filters above the keyboard</string> <string name="preference_filter_bar_summary">Show quick filters above the keyboard</string>
<string name="preference_customize_filter_bar">Customize filter bar</string>
<string name="preference_customize_filter_bar_summary">Customize which items are included in the filter bar</string>
<string name="filter_settings_network_warning">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.</string> <string name="filter_settings_network_warning">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.</string>
</resources> </resources>

View File

@ -154,7 +154,6 @@ data class LauncherSettingsData internal constructor(
KeyboardFilterBarItem.Events, KeyboardFilterBarItem.Events,
KeyboardFilterBarItem.Contacts, KeyboardFilterBarItem.Contacts,
KeyboardFilterBarItem.Files, KeyboardFilterBarItem.Files,
KeyboardFilterBarItem.Places,
KeyboardFilterBarItem.Articles, KeyboardFilterBarItem.Articles,
KeyboardFilterBarItem.Websites, KeyboardFilterBarItem.Websites,
KeyboardFilterBarItem.Places, KeyboardFilterBarItem.Places,

View File

@ -1,5 +1,6 @@
package de.mm20.launcher2.preferences.search package de.mm20.launcher2.preferences.search
import de.mm20.launcher2.preferences.KeyboardFilterBarItem
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.SearchFilters import de.mm20.launcher2.search.SearchFilters
import kotlinx.coroutines.flow.map 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<KeyboardFilterBarItem>) {
launcherDataStore.update {
it.copy(searchFilterBarItems = items)
}
}
} }