diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt index 0e4a6f36..df107e5b 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt @@ -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() - }) - } } } } diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivityVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivityVM.kt index 16b6ae0a..3be824c1 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivityVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivityVM.kt @@ -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() } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheet.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheet.kt index 944f9604..e84873db 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheet.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheet.kt @@ -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, 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 -} \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheetVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheetVM.kt index b4046554..5b174892 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheetVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/modals/HiddenItemsSheetVM.kt @@ -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( diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt index 99f6472b..8a7fe682 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt @@ -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() } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt index 2ff43856..401f5f81 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt @@ -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(null) val websearchResults = MutableLiveData>(emptyList()) + val hiddenResults = MutableLiveData>(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>() 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 = emptyList(), + val contacts: List = emptyList(), + val calendarEvents: List = emptyList(), + val files: List = emptyList(), + val appShortcuts: List = emptyList(), +) { + fun joinToList(): List { + return apps + contacts + calendarEvents + files + appShortcuts + } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/hidden/HiddenResults.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/hidden/HiddenResults.kt new file mode 100644 index 00000000..6f3d16f7 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/hidden/HiddenResults.kt @@ -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}) + } +} \ No newline at end of file