Hidden items sheet: only show items that match the current search query
This commit is contained in:
parent
5ae0ec42b7
commit
e318664b6e
@ -7,18 +7,19 @@ import android.os.Bundle
|
|||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
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.blur
|
|
||||||
import androidx.compose.ui.geometry.Size
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
@ -38,7 +39,6 @@ import de.mm20.launcher2.ui.base.ProvideSettings
|
|||||||
import de.mm20.launcher2.ui.component.NavBarEffects
|
import de.mm20.launcher2.ui.component.NavBarEffects
|
||||||
import de.mm20.launcher2.ui.ktx.animateTo
|
import de.mm20.launcher2.ui.ktx.animateTo
|
||||||
import de.mm20.launcher2.ui.launcher.modals.EditFavoritesView
|
import de.mm20.launcher2.ui.launcher.modals.EditFavoritesView
|
||||||
import de.mm20.launcher2.ui.launcher.modals.HiddenItemsSheet
|
|
||||||
import de.mm20.launcher2.ui.launcher.transitions.HomeTransitionManager
|
import de.mm20.launcher2.ui.launcher.transitions.HomeTransitionManager
|
||||||
import de.mm20.launcher2.ui.launcher.transitions.LocalHomeTransitionManager
|
import de.mm20.launcher2.ui.launcher.transitions.LocalHomeTransitionManager
|
||||||
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
|
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
|
||||||
@ -143,13 +143,6 @@ class LauncherActivity : BaseActivity() {
|
|||||||
.navigationBarsPadding()
|
.navigationBarsPadding()
|
||||||
.imePadding()
|
.imePadding()
|
||||||
)
|
)
|
||||||
|
|
||||||
val showHiddenItems by viewModel.isHiddenItemsShown.observeAsState(false)
|
|
||||||
if (showHiddenItems) {
|
|
||||||
HiddenItemsSheet(onDismiss = {
|
|
||||||
viewModel.hideHiddenItems()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import org.koin.core.component.inject
|
|||||||
class LauncherActivityVM : ViewModel(), KoinComponent {
|
class LauncherActivityVM : ViewModel(), KoinComponent {
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
val isHiddenItemsShown = MutableLiveData(false)
|
|
||||||
val isEditFavoritesShown = MutableLiveData(false)
|
val isEditFavoritesShown = MutableLiveData(false)
|
||||||
|
|
||||||
private var isDarkInMode = MutableStateFlow(false)
|
private var isDarkInMode = MutableStateFlow(false)
|
||||||
@ -55,13 +54,5 @@ class LauncherActivityVM : ViewModel(), KoinComponent {
|
|||||||
isEditFavoritesShown.value = false
|
isEditFavoritesShown.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showHiddenItems() {
|
|
||||||
isHiddenItemsShown.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hideHiddenItems() {
|
|
||||||
isHiddenItemsShown.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
val layout = dataStore.data.map { it.appearance.layout }.asLiveData()
|
val layout = dataStore.data.map { it.appearance.layout }.asLiveData()
|
||||||
}
|
}
|
||||||
@ -22,12 +22,14 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import de.mm20.launcher2.search.data.Searchable
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||||
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HiddenItemsSheet(
|
fun HiddenItemsSheet(
|
||||||
|
items: List<Searchable>,
|
||||||
onDismiss: () -> Unit
|
onDismiss: () -> Unit
|
||||||
) {
|
) {
|
||||||
val viewModel: HiddenItemsSheetVM = viewModel()
|
val viewModel: HiddenItemsSheetVM = viewModel()
|
||||||
@ -56,8 +58,6 @@ fun HiddenItemsSheet(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
val items by remember { viewModel.hiddenItems }.collectAsState(emptyList())
|
|
||||||
SearchResultGrid(
|
SearchResultGrid(
|
||||||
items,
|
items,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -65,7 +65,3 @@ fun HiddenItemsSheet(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class SwipeState {
|
|
||||||
Default, Dismiss
|
|
||||||
}
|
|
||||||
@ -9,12 +9,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
class HiddenItemsSheetVM: ViewModel(), KoinComponent {
|
class HiddenItemsSheetVM: ViewModel() {
|
||||||
private val repository: FavoritesRepository by inject()
|
|
||||||
|
|
||||||
val hiddenItems = repository.getHiddenItems().map {
|
|
||||||
it.sorted()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun showHiddenItems(context: Context) {
|
fun showHiddenItems(context: Context) {
|
||||||
context.startActivity(
|
context.startActivity(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.search
|
package de.mm20.launcher2.ui.launcher.search
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.VisibilityOff
|
import androidx.compose.material.icons.rounded.VisibilityOff
|
||||||
@ -8,6 +9,8 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@ -20,6 +23,7 @@ import de.mm20.launcher2.ui.launcher.search.calendar.CalendarResults
|
|||||||
import de.mm20.launcher2.ui.launcher.search.contacts.ContactResults
|
import de.mm20.launcher2.ui.launcher.search.contacts.ContactResults
|
||||||
import de.mm20.launcher2.ui.launcher.search.favorites.FavoritesResults
|
import de.mm20.launcher2.ui.launcher.search.favorites.FavoritesResults
|
||||||
import de.mm20.launcher2.ui.launcher.search.files.FileResults
|
import de.mm20.launcher2.ui.launcher.search.files.FileResults
|
||||||
|
import de.mm20.launcher2.ui.launcher.search.hidden.HiddenResults
|
||||||
import de.mm20.launcher2.ui.launcher.search.unitconverter.UnitConverterResults
|
import de.mm20.launcher2.ui.launcher.search.unitconverter.UnitConverterResults
|
||||||
import de.mm20.launcher2.ui.launcher.search.website.WebsiteResults
|
import de.mm20.launcher2.ui.launcher.search.website.WebsiteResults
|
||||||
import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaResults
|
import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaResults
|
||||||
@ -45,33 +49,6 @@ fun SearchColumn(
|
|||||||
WikipediaResults(reverse)
|
WikipediaResults(reverse)
|
||||||
WebsiteResults(reverse)
|
WebsiteResults(reverse)
|
||||||
FileResults(reverse)
|
FileResults(reverse)
|
||||||
Row(
|
HiddenResults()
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth(),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.End
|
|
||||||
) {
|
|
||||||
val viewModel: LauncherActivityVM = viewModel()
|
|
||||||
Surface(
|
|
||||||
shadowElevation = 2.dp,
|
|
||||||
tonalElevation = 2.dp,
|
|
||||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
|
||||||
contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
shape = MaterialTheme.shapes.medium,
|
|
||||||
onClick = { viewModel.showHiddenItems() }
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(vertical = 8.dp, horizontal = 12.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.padding(start = 12.dp, end = 12.dp),
|
|
||||||
imageVector = Icons.Rounded.VisibilityOff,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.search
|
package de.mm20.launcher2.ui.launcher.search
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@ -61,6 +60,8 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
val unitConverterResult = MutableLiveData<UnitConverter?>(null)
|
val unitConverterResult = MutableLiveData<UnitConverter?>(null)
|
||||||
val websearchResults = MutableLiveData<List<Websearch>>(emptyList())
|
val websearchResults = MutableLiveData<List<Websearch>>(emptyList())
|
||||||
|
|
||||||
|
val hiddenResults = MutableLiveData<List<Searchable>>(emptyList())
|
||||||
|
|
||||||
val hideFavorites = MutableLiveData(false)
|
val hideFavorites = MutableLiveData(false)
|
||||||
|
|
||||||
private val hiddenItemKeys = favoritesRepository
|
private val hiddenItemKeys = favoritesRepository
|
||||||
@ -93,6 +94,10 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
fun search(query: String) {
|
fun search(query: String) {
|
||||||
searchQuery.value = query
|
searchQuery.value = query
|
||||||
isSearchEmpty.value = query.isEmpty()
|
isSearchEmpty.value = query.isEmpty()
|
||||||
|
hiddenResults.value = emptyList()
|
||||||
|
|
||||||
|
val hiddenItems = MutableStateFlow(HiddenItemResults())
|
||||||
|
|
||||||
try {
|
try {
|
||||||
searchJob?.cancel()
|
searchJob?.cancel()
|
||||||
} catch (e: CancellationException) {
|
} catch (e: CancellationException) {
|
||||||
@ -103,22 +108,34 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
val jobs = mutableListOf<Deferred<Any>>()
|
val jobs = mutableListOf<Deferred<Any>>()
|
||||||
jobs += async {
|
jobs += async {
|
||||||
appRepository.search(query).collectLatest { apps ->
|
appRepository.search(query).collectLatest { apps ->
|
||||||
hiddenItemKeys.collectLatest { hidden ->
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
appResults.postValue(apps.filter { !hidden.contains(it.key) })
|
val results = apps.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
appResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(apps = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
contactRepository.search(query).collectLatest { contacts ->
|
contactRepository.search(query).collectLatest { contacts ->
|
||||||
hiddenItemKeys.collectLatest { hidden ->
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
contactResults.postValue(contacts.filter { !hidden.contains(it.key) })
|
val results = contacts.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
contactResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(contacts = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
calendarRepository.search(query).collectLatest { events ->
|
calendarRepository.search(query).collectLatest { events ->
|
||||||
hiddenItemKeys.collectLatest { hidden ->
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
calendarResults.postValue(events.filter { !hidden.contains(it.key) })
|
val results = events.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
calendarResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(calendarEvents = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,8 +161,12 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
fileRepository.search(query).collectLatest { files ->
|
fileRepository.search(query).collectLatest { files ->
|
||||||
hiddenItemKeys.collectLatest { hidden ->
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
fileResults.postValue(files.filter { !hidden.contains(it.key) })
|
val results = files.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
fileResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(files = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,6 +182,11 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
launch {
|
||||||
|
hiddenItems.collectLatest {
|
||||||
|
hiddenResults.postValue(it.joinToList())
|
||||||
|
}
|
||||||
|
}
|
||||||
jobs.map { it.await() }
|
jobs.map { it.await() }
|
||||||
isSearching.postValue(false)
|
isSearching.postValue(false)
|
||||||
}
|
}
|
||||||
@ -244,3 +270,15 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class HiddenItemResults(
|
||||||
|
val apps: List<Application> = emptyList(),
|
||||||
|
val contacts: List<Contact> = emptyList(),
|
||||||
|
val calendarEvents: List<CalendarEvent> = emptyList(),
|
||||||
|
val files: List<File> = emptyList(),
|
||||||
|
val appShortcuts: List<AppShortcut> = emptyList(),
|
||||||
|
) {
|
||||||
|
fun joinToList(): List<Searchable> {
|
||||||
|
return apps + contacts + calendarEvents + files + appShortcuts
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
package de.mm20.launcher2.ui.launcher.search.hidden
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.VisibilityOff
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import de.mm20.launcher2.ui.launcher.LauncherActivityVM
|
||||||
|
import de.mm20.launcher2.ui.launcher.modals.HiddenItemsSheet
|
||||||
|
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun ColumnScope.HiddenResults() {
|
||||||
|
val viewModel: SearchVM = viewModel()
|
||||||
|
val hiddenResults by viewModel.hiddenResults.observeAsState(
|
||||||
|
emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
var showHiddenItems by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
AnimatedVisibility(visible = hiddenResults.isNotEmpty()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
shadowElevation = 2.dp,
|
||||||
|
tonalElevation = 2.dp,
|
||||||
|
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
onClick = { showHiddenItems = true }
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(vertical = 8.dp, horizontal = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.padding(start = 12.dp, end = 12.dp),
|
||||||
|
imageVector = Icons.Rounded.VisibilityOff,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showHiddenItems) {
|
||||||
|
HiddenItemsSheet(hiddenResults, onDismiss = {showHiddenItems = false})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user