Reorganize Searchable data types

This commit is contained in:
MM20
2022-10-12 20:36:39 +02:00
parent a01b0aa03d
commit bcda89c211
98 changed files with 817 additions and 738 deletions
@@ -5,7 +5,8 @@ import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.customattrs.CustomAttributesRepository
import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.search.data.Tag
import de.mm20.launcher2.ui.utils.withCustomLabels
import de.mm20.launcher2.widgets.WidgetRepository
@@ -32,7 +33,7 @@ open class FavoritesVM : ViewModel(), KoinComponent {
it.filterIsInstance<Tag>()
}
val favorites: Flow<List<Searchable>> = selectedTag.flatMapLatest { tag ->
val favorites: Flow<List<PinnableSearchable>> = selectedTag.flatMapLatest { tag ->
if (tag == null) {
val columns = dataStore.data.map { it.grid.columnCount }
val excludeCalendar = widgetRepository.isCalendarWidgetEnabled()
@@ -71,7 +71,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.drawOutline
@@ -90,7 +89,8 @@ import androidx.compose.ui.unit.toSize
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.BottomSheetDialog
import de.mm20.launcher2.ui.component.MissingPermissionBanner
@@ -739,7 +739,7 @@ fun ShortcutPicker(viewModel: EditFavoritesSheetVM) {
}
sealed interface FavoritesSheetGridItem {
class Favorite(val item: Searchable) : FavoritesSheetGridItem
class Favorite(val item: PinnableSearchable) : FavoritesSheetGridItem
class Divider(val section: FavoritesSheetSection) : FavoritesSheetGridItem
class Spacer(val span: Int = 1) : FavoritesSheetGridItem
object EmptySection : FavoritesSheetGridItem
@@ -17,12 +17,12 @@ import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.icons.IconRepository
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.normalize
import de.mm20.launcher2.ktx.romanize
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.data.AppShortcut
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.search.data.Tag
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
@@ -48,9 +48,9 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
val createShortcutTarget = MutableLiveData<FavoritesSheetSection?>(null)
private var manuallySorted: MutableList<Searchable> = mutableListOf()
private var automaticallySorted: MutableList<Searchable> = mutableListOf()
private var frequentlyUsed: MutableList<Searchable> = mutableListOf()
private var manuallySorted: MutableList<PinnableSearchable> = mutableListOf()
private var automaticallySorted: MutableList<PinnableSearchable> = mutableListOf()
private var frequentlyUsed: MutableList<PinnableSearchable> = mutableListOf()
val pinnedTags = MutableLiveData<List<Tag>>(emptyList())
val availableTags = MutableLiveData<List<Tag>>(emptyList())
@@ -179,7 +179,7 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
)
}
fun getIcon(searchable: Searchable, size: Int): Flow<LauncherIcon?> {
fun getIcon(searchable: PinnableSearchable, size: Int): Flow<LauncherIcon?> {
return iconRepository.getIcon(searchable, size)
}
@@ -16,14 +16,15 @@ 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.search.PinnableSearchable
import de.mm20.launcher2.search.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>,
items: List<PinnableSearchable>,
onDismiss: () -> Unit
) {
val viewModel: HiddenItemsSheetVM = viewModel()
@@ -43,7 +43,8 @@ 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.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.component.MissingPermissionBanner
@@ -381,7 +382,7 @@ fun SearchColumn(
}
fun LazyListScope.GridResults(
items: ImmutableList<Searchable>,
items: ImmutableList<PinnableSearchable>,
columns: Int,
reverse: Boolean,
showLabels: Boolean,
@@ -446,7 +447,7 @@ fun LazyListScope.GridResults(
@Composable
fun GridRow(
modifier: Modifier = Modifier,
items: ImmutableList<Searchable>,
items: ImmutableList<PinnableSearchable>,
columns: Int,
showLabels: Boolean,
) {
@@ -470,7 +471,7 @@ fun GridRow(
}
fun LazyListScope.ListResults(
items: ImmutableList<Searchable>,
items: ImmutableList<PinnableSearchable>,
reverse: Boolean,
key: String,
before: (@Composable () -> Unit)? = null,
@@ -523,7 +524,7 @@ fun LazyListScope.ListResults(
@Composable
fun ListRow(
modifier: Modifier = Modifier,
item: Searchable,
item: PinnableSearchable,
) {
Box(
modifier = modifier.padding(
@@ -16,12 +16,13 @@ import de.mm20.launcher2.files.FileRepository
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.search.WebsearchRepository
import de.mm20.launcher2.search.data.*
import de.mm20.launcher2.ui.utils.withCustomLabels
import de.mm20.launcher2.unitconverter.UnitConverterRepository
import de.mm20.launcher2.websites.WebsiteRepository
import de.mm20.launcher2.widgets.WidgetRepository
import de.mm20.launcher2.wikipedia.WikipediaRepository
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
@@ -52,8 +53,8 @@ class SearchVM : ViewModel(), KoinComponent {
val showLabels = dataStore.data.map { it.grid.showLabels }.asLiveData()
val appResults = MutableLiveData<List<Application>>(emptyList())
val workAppResults = MutableLiveData<List<Application>>(emptyList())
val appResults = MutableLiveData<List<LauncherApp>>(emptyList())
val workAppResults = MutableLiveData<List<LauncherApp>>(emptyList())
val appShortcutResults = MutableLiveData<List<AppShortcut>>(emptyList())
val fileResults = MutableLiveData<List<File>>(emptyList())
val contactResults = MutableLiveData<List<Contact>>(emptyList())
@@ -64,7 +65,7 @@ class SearchVM : ViewModel(), KoinComponent {
val unitConverterResult = MutableLiveData<UnitConverter?>(null)
val websearchResults = MutableLiveData<List<Websearch>>(emptyList())
val hiddenResults = MutableLiveData<List<Searchable>>(emptyList())
val hiddenResults = MutableLiveData<List<PinnableSearchable>>(emptyList())
val favoritesEnabled = dataStore.data.map { it.favorites.enabled }
val hideFavorites = MutableLiveData(false)
@@ -95,7 +96,7 @@ class SearchVM : ViewModel(), KoinComponent {
val customAttrResults = customAttributesRepository.search(query)
.combine(dataStore.data) { items, settings ->
items.filter {
it is Application
it is LauncherApp
|| it is Contact && settings.contactsSearch.enabled
|| it is CalendarEvent && settings.calendarSearch.enabled
|| it is AppShortcut && settings.appShortcutSearch.enabled
@@ -285,15 +286,15 @@ class SearchVM : ViewModel(), KoinComponent {
}
private inline fun <reified T : Searchable> Flow<List<T>>.withCustomAttributeResults(
customAttributeResults: Flow<List<Searchable>>
private inline fun <reified T : PinnableSearchable> Flow<List<T>>.withCustomAttributeResults(
customAttributeResults: Flow<List<PinnableSearchable>>
): Flow<List<T>> {
return this.combine(customAttributeResults) { items, items2 ->
(items + items2.filterIsInstance<T>()).distinctBy { it.key }
}
}
private suspend fun <T : Searchable> Flow<List<T>>.collectWithHiddenItems(
private suspend fun <T : PinnableSearchable> Flow<List<T>>.collectWithHiddenItems(
hiddenItemKeys: Flow<List<String>>,
action: (items: List<T>, hidden: List<T>) -> Unit
) {
@@ -305,18 +306,18 @@ class SearchVM : ViewModel(), KoinComponent {
}
}
private fun <T : Searchable> Flow<List<T>>.sorted(): Flow<List<T>> = this.map { it.sorted() }
private fun <T : PinnableSearchable> Flow<List<T>>.sorted(): Flow<List<T>> = this.map { it.sorted() }
}
private data class HiddenItemResults(
val apps: List<Application> = emptyList(),
val apps: List<LauncherApp> = 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> {
fun joinToList(): List<PinnableSearchable> {
return apps + contacts + calendarEvents + files + appShortcuts
}
}
@@ -23,7 +23,7 @@ import androidx.core.app.NotificationCompat
import androidx.lifecycle.lifecycleScope
import coil.compose.rememberAsyncImagePainter
import com.google.accompanist.flowlayout.FlowRow
import de.mm20.launcher2.search.data.Application
import de.mm20.launcher2.search.data.LauncherApp
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.*
import de.mm20.launcher2.ui.ktx.toDp
@@ -40,7 +40,7 @@ import kotlin.math.roundToInt
@Composable
fun AppItem(
modifier: Modifier = Modifier,
app: Application,
app: LauncherApp,
onBack: () -> Unit
) {
val viewModel = remember { AppItemVM(app) }
@@ -336,7 +336,7 @@ fun AppItem(
@Composable
fun AppItemGridPopup(
app: Application,
app: LauncherApp,
show: Boolean,
animationProgress: Float,
origin: Rect,
@@ -8,16 +8,13 @@ import android.content.pm.*
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Process
import android.provider.Settings
import android.service.notification.StatusBarNotification
import androidx.core.content.FileProvider
import androidx.core.content.getSystemService
import de.mm20.launcher2.appshortcuts.AppShortcutRepository
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.notifications.NotificationRepository
import de.mm20.launcher2.search.data.AppShortcut
import de.mm20.launcher2.search.data.Application
import de.mm20.launcher2.search.data.LauncherApp
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
import kotlinx.coroutines.Dispatchers
@@ -28,7 +25,7 @@ import kotlinx.coroutines.withContext
import org.koin.core.component.inject
class AppItemVM(
private val app: Application
private val app: LauncherApp
) : SearchableItemVM(app) {
private val notificationRepository: NotificationRepository by inject()
private val appShortcutRepository: AppShortcutRepository by inject()
@@ -44,21 +41,12 @@ class AppItemVM(
fun openAppInfo(context: Context) {
val launcherApps = context.getSystemService<LauncherApps>()!!
if (app is LauncherApp) {
launcherApps.startAppDetailsActivity(
ComponentName(app.`package`, app.activity),
app.getUser(),
null,
null
)
} else {
context.tryStartActivity(
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.parse("package:${app.`package`}")
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
)
}
launcherApps.startAppDetailsActivity(
ComponentName(app.`package`, app.activity),
app.getUser(),
null,
null
)
}
suspend fun shareApkFile(context: Context) {
@@ -128,9 +116,7 @@ class AppItemVM(
}
val shortcuts = flow {
if (app is LauncherApp) {
emit(appShortcutRepository.getShortcutsForActivity(app.launcherActivityInfo, 5))
}
emit(appShortcutRepository.getShortcutsForActivity(app.launcherActivityInfo, 5))
}
fun isShortcutPinned(shortcut: AppShortcut): Flow<Boolean> {
@@ -10,15 +10,15 @@ import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.icons.IconRepository
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.data.AppShortcut
import de.mm20.launcher2.search.data.Application
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.data.LauncherApp
import kotlinx.coroutines.flow.Flow
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
abstract class SearchableItemVM(
private val searchable: Searchable
private val searchable: PinnableSearchable
) : KoinComponent {
protected val favoritesRepository: FavoritesRepository by inject()
protected val badgeRepository: BadgeRepository by inject()
@@ -74,7 +74,7 @@ abstract class SearchableItemVM(
if (searchable.launch(context, bundle)) {
favoritesRepository.incrementLaunchCounter(searchable)
return true
} else if (searchable is Application || searchable is AppShortcut) {
} else if (searchable is LauncherApp || searchable is AppShortcut) {
favoritesRepository.remove(searchable)
}
return false
@@ -23,7 +23,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.icons.CustomIconWithPreview
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.BottomSheetDialog
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
@@ -35,7 +36,7 @@ import kotlinx.coroutines.launch
@Composable
fun CustomizeSearchableSheet(
searchable: Searchable,
searchable: PinnableSearchable,
onDismiss: () -> Unit,
) {
val viewModel: CustomizeSearchableSheetVM =
@@ -4,11 +4,11 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.liveData
import de.mm20.launcher2.customattrs.CustomAttributesRepository
import de.mm20.launcher2.customattrs.CustomIcon
import de.mm20.launcher2.customattrs.customAttrsModule
import de.mm20.launcher2.icons.CustomIconWithPreview
import de.mm20.launcher2.icons.IconRepository
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import org.koin.core.component.KoinComponent
@@ -16,7 +16,7 @@ import org.koin.core.component.inject
import kotlin.coroutines.coroutineContext
class CustomizeSearchableSheetVM(
private val searchable: Searchable
private val searchable: PinnableSearchable
) : KoinComponent {
private val iconRepository: IconRepository by inject()
private val customAttributesRepository: CustomAttributesRepository by inject()
@@ -2,19 +2,15 @@ package de.mm20.launcher2.ui.launcher.search.common.grid
import android.content.ComponentName
import androidx.activity.compose.BackHandler
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
@@ -26,6 +22,8 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.search.data.*
import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
@@ -47,7 +45,7 @@ import kotlinx.coroutines.delay
@Composable
fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolean = true) {
fun GridItem(modifier: Modifier = Modifier, item: PinnableSearchable, showLabels: Boolean = true) {
val viewModel = remember(item.key) { GridItemVM(item) }
val context = LocalContext.current
@@ -59,13 +57,11 @@ fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolea
val iconSize = LocalGridIconSize.current.toPixels()
val icon by remember(item.key) { viewModel.getIcon(iconSize.toInt()) }.collectAsState(null)
// If item is one of these types, try to launch them on click; show details otherwise
val launchOnPress =
item is File || item is Application || item is AppShortcut || item is Website || item is Wikipedia
val launchOnPress = !item.preferDetailsOverLaunch
val windowSize = LocalWindowSize.current
if (item is Application) {
if (item is LauncherApp) {
HandleHomeTransition {
val cn = ComponentName(item.`package`, item.activity)
if (
@@ -164,7 +160,7 @@ fun ItemPopup(origin: Rect, searchable: Searchable, onDismissRequest: () -> Unit
.wrapContentSize()
) {
when (searchable) {
is Application -> {
is LauncherApp -> {
AppItemGridPopup(
app = searchable,
show = show,
@@ -1,8 +1,9 @@
package de.mm20.launcher2.ui.launcher.search.common.grid
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
class GridItemVM(
searchable: Searchable
searchable: PinnableSearchable
): SearchableItemVM(searchable)
@@ -5,14 +5,15 @@ import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.ui.layout.BottomReversed
import de.mm20.launcher2.ui.locals.LocalGridColumns
import kotlin.math.ceil
@Composable
fun SearchResultGrid(
items: List<Searchable>,
items: List<PinnableSearchable>,
modifier: Modifier = Modifier,
showLabels: Boolean = true,
columns: Int = LocalGridColumns.current,
@@ -2,13 +2,14 @@ package de.mm20.launcher2.ui.launcher.search.common.list
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.search.data.*
import de.mm20.launcher2.ui.component.InnerCard
import de.mm20.launcher2.ui.launcher.search.calendar.CalendarItem
@@ -17,7 +18,7 @@ import de.mm20.launcher2.ui.launcher.search.files.FileItem
import de.mm20.launcher2.ui.launcher.search.shortcut.AppShortcutItem
@Composable
fun ListItem(modifier: Modifier = Modifier, item: Searchable) {
fun ListItem(modifier: Modifier = Modifier, item: PinnableSearchable) {
var showDetails by remember { mutableStateOf(false) }
val context = LocalContext.current
@@ -1,8 +1,9 @@
package de.mm20.launcher2.ui.launcher.search.common.list
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
class ListItemVM(
searchable: Searchable
searchable: PinnableSearchable
): SearchableItemVM(searchable)
@@ -8,12 +8,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import de.mm20.launcher2.ui.layout.BottomReversed
@Composable
fun SearchResultList(
items: List<Searchable>,
items: List<PinnableSearchable>,
modifier: Modifier = Modifier,
reverse: Boolean = false
) {
@@ -57,7 +57,7 @@ fun WebsiteItem(
modifier = Modifier.padding(16.dp),
) {
Text(
text = website.label,
text = website.labelOverride ?: website.label,
style = MaterialTheme.typography.titleLarge
)
val tags by remember(viewModel) { viewModel.getTags() }.collectAsState(emptyList())
@@ -1,17 +1,5 @@
package de.mm20.launcher2.ui.launcher.widgets.favorites
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.ui.common.FavoritesVM
import de.mm20.launcher2.widgets.WidgetRepository
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class FavoritesWidgetVM: FavoritesVM()
@@ -1,6 +1,5 @@
package de.mm20.launcher2.ui.settings.hiddenitems
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.*
@@ -21,7 +20,6 @@ import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.search.data.Application
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
@@ -2,11 +2,8 @@ package de.mm20.launcher2.ui.settings.hiddenitems
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.LauncherApps
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import androidx.core.content.getSystemService
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
@@ -17,10 +14,9 @@ import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.icons.IconRepository
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.search.data.Application
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.data.LauncherApp
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.Searchable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
@@ -37,18 +33,18 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
val allApps = appRepository.getAllInstalledApps().map {
withContext(Dispatchers.Default) { it.sorted() }
}.asLiveData()
val hiddenItems: LiveData<List<Searchable>> = liveData {
val hiddenItems: LiveData<List<PinnableSearchable>> = liveData {
val hidden = withContext(Dispatchers.Default) {
favoritesRepository.getHiddenItems().first().filter { it !is Application }.sorted()
favoritesRepository.getHiddenItems().first().filter { it !is LauncherApp }.sorted()
}
emit(hidden)
}
fun isHidden(searchable: Searchable): Flow<Boolean> {
fun isHidden(searchable: PinnableSearchable): Flow<Boolean> {
return favoritesRepository.isHidden(searchable)
}
fun setHidden(searchable: Searchable, hidden: Boolean) {
fun setHidden(searchable: PinnableSearchable, hidden: Boolean) {
if(hidden) {
favoritesRepository.hideItem(searchable)
} else {
@@ -56,11 +52,11 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
}
}
fun getIcon(searchable: Searchable, size: Int): Flow<LauncherIcon> {
fun getIcon(searchable: PinnableSearchable, size: Int): Flow<LauncherIcon> {
return iconRepository.getIcon(searchable, size)
}
fun launch(context: Context, searchable: Searchable) {
fun launch(context: Context, searchable: PinnableSearchable) {
val bundle = Bundle()
if (isAtLeastApiLevel(31)) {
bundle.putInt("android.activity.splashScreenStyle", 1)
@@ -68,23 +64,14 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
searchable.launch(context, bundle)
}
fun openAppInfo(context: Context, app: Application) {
fun openAppInfo(context: Context, app: LauncherApp) {
val launcherApps = context.getSystemService<LauncherApps>()!!
if (app is LauncherApp) {
launcherApps.startAppDetailsActivity(
ComponentName(app.`package`, app.activity),
app.getUser(),
null,
null
)
} else {
context.tryStartActivity(
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.parse("package:${app.`package`}")
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
)
}
launcherApps.startAppDetailsActivity(
ComponentName(app.`package`, app.activity),
app.getUser(),
null,
null
)
}
}
@@ -1,23 +1,26 @@
package de.mm20.launcher2.ui.utils
import de.mm20.launcher2.customattrs.CustomAttributesRepository
import de.mm20.launcher2.customattrs.CustomLabel
import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.search.PinnableSearchable
import de.mm20.launcher2.search.Searchable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
fun <T : Searchable> Flow<List<T>>.withCustomLabels(
fun <T : PinnableSearchable> Flow<List<T>>.withCustomLabels(
customAttributesRepository: CustomAttributesRepository,
): Flow<List<T>> = channelFlow {
this@withCustomLabels.collectLatest { items ->
val customLabels = customAttributesRepository.getCustomLabels(items)
customLabels.collectLatest { labels ->
for (item in items) {
send(items.map { item ->
val customLabel = labels.find { it.key == item.key }
item.labelOverride = customLabel?.label
}
send(items)
if (customLabel != null) {
item.overrideLabel(customLabel.label) as T
} else {
item
}
})
}
}
}