Hidden items sheet: only show items that match the current search query

This commit is contained in:
MM20 2022-06-12 14:47:33 +02:00
parent 5ae0ec42b7
commit e318664b6e
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
7 changed files with 123 additions and 69 deletions

View File

@ -7,18 +7,19 @@ import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
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.SnackbarHostState
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
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.ktx.animateTo
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.LocalHomeTransitionManager
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
@ -143,13 +143,6 @@ class LauncherActivity : BaseActivity() {
.navigationBarsPadding()
.imePadding()
)
val showHiddenItems by viewModel.isHiddenItemsShown.observeAsState(false)
if (showHiddenItems) {
HiddenItemsSheet(onDismiss = {
viewModel.hideHiddenItems()
})
}
}
}
}

View File

@ -13,7 +13,6 @@ import org.koin.core.component.inject
class LauncherActivityVM : ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject()
val isHiddenItemsShown = MutableLiveData(false)
val isEditFavoritesShown = MutableLiveData(false)
private var isDarkInMode = MutableStateFlow(false)
@ -55,13 +54,5 @@ class LauncherActivityVM : ViewModel(), KoinComponent {
isEditFavoritesShown.value = false
}
fun showHiddenItems() {
isHiddenItemsShown.value = true
}
fun hideHiddenItems() {
isHiddenItemsShown.value = false
}
val layout = dataStore.data.map { it.appearance.layout }.asLiveData()
}

View File

@ -22,12 +22,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.BottomSheetDialog
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
@Composable
fun HiddenItemsSheet(
items: List<Searchable>,
onDismiss: () -> Unit
) {
val viewModel: HiddenItemsSheetVM = viewModel()
@ -56,8 +58,6 @@ fun HiddenItemsSheet(
}
) {
val items by remember { viewModel.hiddenItems }.collectAsState(emptyList())
SearchResultGrid(
items,
modifier = Modifier
@ -65,7 +65,3 @@ fun HiddenItemsSheet(
)
}
}
private enum class SwipeState {
Default, Dismiss
}

View File

@ -9,12 +9,7 @@ import kotlinx.coroutines.flow.map
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class HiddenItemsSheetVM: ViewModel(), KoinComponent {
private val repository: FavoritesRepository by inject()
val hiddenItems = repository.getHiddenItems().map {
it.sorted()
}
class HiddenItemsSheetVM: ViewModel() {
fun showHiddenItems(context: Context) {
context.startActivity(

View File

@ -1,5 +1,6 @@
package de.mm20.launcher2.ui.launcher.search
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
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.Surface
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.Modifier
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.favorites.FavoritesResults
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.website.WebsiteResults
import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaResults
@ -45,33 +49,6 @@ fun SearchColumn(
WikipediaResults(reverse)
WebsiteResults(reverse)
FileResults(reverse)
Row(
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,
)
}
}
}
HiddenResults()
}
}

View File

@ -1,6 +1,5 @@
package de.mm20.launcher2.ui.launcher.search
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
@ -61,6 +60,8 @@ class SearchVM : ViewModel(), KoinComponent {
val unitConverterResult = MutableLiveData<UnitConverter?>(null)
val websearchResults = MutableLiveData<List<Websearch>>(emptyList())
val hiddenResults = MutableLiveData<List<Searchable>>(emptyList())
val hideFavorites = MutableLiveData(false)
private val hiddenItemKeys = favoritesRepository
@ -93,6 +94,10 @@ class SearchVM : ViewModel(), KoinComponent {
fun search(query: String) {
searchQuery.value = query
isSearchEmpty.value = query.isEmpty()
hiddenResults.value = emptyList()
val hiddenItems = MutableStateFlow(HiddenItemResults())
try {
searchJob?.cancel()
} catch (e: CancellationException) {
@ -103,22 +108,34 @@ class SearchVM : ViewModel(), KoinComponent {
val jobs = mutableListOf<Deferred<Any>>()
jobs += async {
appRepository.search(query).collectLatest { apps ->
hiddenItemKeys.collectLatest { hidden ->
appResults.postValue(apps.filter { !hidden.contains(it.key) })
hiddenItemKeys.collectLatest { hiddenKeys ->
val results = apps.partition { !hiddenKeys.contains(it.key) }
appResults.postValue(results.first)
hiddenItems.update {
it.copy(apps = results.second)
}
}
}
}
jobs += async {
contactRepository.search(query).collectLatest { contacts ->
hiddenItemKeys.collectLatest { hidden ->
contactResults.postValue(contacts.filter { !hidden.contains(it.key) })
hiddenItemKeys.collectLatest { hiddenKeys ->
val results = contacts.partition { !hiddenKeys.contains(it.key) }
contactResults.postValue(results.first)
hiddenItems.update {
it.copy(contacts = results.second)
}
}
}
}
jobs += async {
calendarRepository.search(query).collectLatest { events ->
hiddenItemKeys.collectLatest { hidden ->
calendarResults.postValue(events.filter { !hidden.contains(it.key) })
hiddenItemKeys.collectLatest { hiddenKeys ->
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 {
fileRepository.search(query).collectLatest { files ->
hiddenItemKeys.collectLatest { hidden ->
fileResults.postValue(files.filter { !hidden.contains(it.key) })
hiddenItemKeys.collectLatest { hiddenKeys ->
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() }
isSearching.postValue(false)
}
@ -243,4 +269,16 @@ 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
}
}

View File

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