Refactor search, favorites and calendar widget
This commit is contained in:
@@ -10,70 +10,69 @@ import android.content.pm.ShortcutInfo
|
||||
import android.os.Process
|
||||
import android.os.UserHandle
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import de.mm20.launcher2.badges.Badge
|
||||
import de.mm20.launcher2.badges.BadgeProvider
|
||||
import de.mm20.launcher2.hiddenitems.HiddenItemsRepository
|
||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
||||
import de.mm20.launcher2.search.BaseSearchableRepository
|
||||
import de.mm20.launcher2.search.data.AppInstallation
|
||||
import de.mm20.launcher2.search.data.Application
|
||||
import de.mm20.launcher2.search.data.LauncherApp
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class AppRepository(
|
||||
val context: Context,
|
||||
interface AppRepository {
|
||||
fun search(query: String): Flow<List<Application>>
|
||||
}
|
||||
|
||||
class AppRepositoryImpl(
|
||||
private val context: Context,
|
||||
hiddenItemsRepository: HiddenItemsRepository,
|
||||
badgeProvider: BadgeProvider
|
||||
) : BaseSearchableRepository() {
|
||||
private val badgeProvider: BadgeProvider
|
||||
) : AppRepository {
|
||||
|
||||
private val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
private val launcherApps =
|
||||
context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
|
||||
val applications = MediatorLiveData<List<Application>>()
|
||||
private val installedApps = MutableStateFlow<List<Application>>(emptyList())
|
||||
private val installations = MutableStateFlow<MutableList<AppInstallation>>(mutableListOf())
|
||||
private val hiddenItems = hiddenItemsRepository.hiddenItemsKeys
|
||||
|
||||
|
||||
private val installedApps = MutableLiveData<List<Application>>(emptyList())
|
||||
private val installations = MutableLiveData<MutableList<AppInstallation>>(mutableListOf())
|
||||
private val hiddenItemKeys = hiddenItemsRepository.hiddenItemsKeys
|
||||
private val profiles: List<UserHandle> =
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
launcherApps.profiles.takeIf { it.isNotEmpty() } ?: listOf(Process.myUserHandle())
|
||||
} else {
|
||||
listOf(Process.myUserHandle())
|
||||
}
|
||||
|
||||
|
||||
private val installingPackages = mutableMapOf<Int, String>()
|
||||
|
||||
private val profiles: List<UserHandle> = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
launcherApps.profiles.takeIf { it.isNotEmpty() } ?: listOf(Process.myUserHandle())
|
||||
} else {
|
||||
listOf(Process.myUserHandle())
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
|
||||
applications.addSource(installedApps) {
|
||||
launch { updateAppsForDisplay() }
|
||||
}
|
||||
applications.addSource(installations) {
|
||||
launch { updateAppsForDisplay() }
|
||||
}
|
||||
|
||||
applications.addSource(hiddenItemKeys) {
|
||||
launch { updateAppsForDisplay() }
|
||||
}
|
||||
|
||||
launcherApps.registerCallback(object : LauncherApps.Callback() {
|
||||
override fun onPackagesUnavailable(packageNames: Array<out String>, user: UserHandle, replacing: Boolean) {
|
||||
installedApps.value = installedApps.value?.filter { !packageNames.contains(it.`package`) }
|
||||
override fun onPackagesUnavailable(
|
||||
packageNames: Array<out String>,
|
||||
user: UserHandle,
|
||||
replacing: Boolean
|
||||
) {
|
||||
installedApps.value =
|
||||
installedApps.value.filter { !packageNames.contains(it.`package`) }
|
||||
}
|
||||
|
||||
override fun onPackageChanged(packageName: String, user: UserHandle) {
|
||||
val apps = installedApps.value?.toMutableList() ?: return
|
||||
val apps = installedApps.value.toMutableList()
|
||||
apps.removeAll { packageName == it.`package` }
|
||||
apps.addAll(getApplications(packageName))
|
||||
installedApps.value = apps
|
||||
}
|
||||
|
||||
override fun onPackagesAvailable(packageNames: Array<out String>, user: UserHandle, replacing: Boolean) {
|
||||
val apps = installedApps.value?.toMutableList() ?: return
|
||||
override fun onPackagesAvailable(
|
||||
packageNames: Array<out String>,
|
||||
user: UserHandle,
|
||||
replacing: Boolean
|
||||
) {
|
||||
val apps = installedApps.value.toMutableList()
|
||||
for (packageName in packageNames) {
|
||||
apps.addAll(getApplications(packageName))
|
||||
}
|
||||
@@ -82,16 +81,20 @@ class AppRepository(
|
||||
|
||||
override fun onPackageAdded(packageName: String, user: UserHandle) {
|
||||
Log.d("MM20", "App installed: $packageName")
|
||||
val apps = installedApps.value?.toMutableList() ?: return
|
||||
val apps = installedApps.value.toMutableList()
|
||||
apps.addAll(getApplications(packageName))
|
||||
installedApps.value = apps
|
||||
}
|
||||
|
||||
override fun onPackageRemoved(packageName: String, user: UserHandle) {
|
||||
installedApps.value = installedApps.value?.filter { packageName != (it.`package`) }
|
||||
installedApps.value = installedApps.value.filter { packageName != (it.`package`) }
|
||||
}
|
||||
|
||||
override fun onShortcutsChanged(packageName: String, shortcuts: MutableList<ShortcutInfo>, user: UserHandle) {
|
||||
override fun onShortcutsChanged(
|
||||
packageName: String,
|
||||
shortcuts: MutableList<ShortcutInfo>,
|
||||
user: UserHandle
|
||||
) {
|
||||
super.onShortcutsChanged(packageName, shortcuts, user)
|
||||
onPackageChanged(packageName, user)
|
||||
}
|
||||
@@ -99,11 +102,17 @@ class AppRepository(
|
||||
override fun onPackagesSuspended(packageNames: Array<out String>?, user: UserHandle?) {
|
||||
super.onPackagesSuspended(packageNames, user)
|
||||
packageNames?.forEach {
|
||||
badgeProvider.setBadge("app://$it", Badge(iconRes = R.drawable.ic_badge_suspended))
|
||||
badgeProvider.setBadge(
|
||||
"app://$it",
|
||||
Badge(iconRes = R.drawable.ic_badge_suspended)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPackagesUnsuspended(packageNames: Array<out String>?, user: UserHandle?) {
|
||||
override fun onPackagesUnsuspended(
|
||||
packageNames: Array<out String>?,
|
||||
user: UserHandle?
|
||||
) {
|
||||
super.onPackagesUnsuspended(packageNames, user)
|
||||
packageNames?.forEach {
|
||||
badgeProvider.removeBadge("app://$it")
|
||||
@@ -111,7 +120,10 @@ class AppRepository(
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
val apps = profiles.map { p ->
|
||||
launcherApps.getActivityList(null, p).mapNotNull { getApplication(it, p) }
|
||||
}.flatten()
|
||||
installedApps.value = apps
|
||||
|
||||
val packageInstaller = context.packageManager.packageInstaller
|
||||
|
||||
@@ -139,13 +151,13 @@ class AppRepository(
|
||||
installingPackages.remove(sessionId)
|
||||
val key = "app://$pkg"
|
||||
val badge = badgeProvider.getBadge(key)?.apply { progress = null }
|
||||
?: Badge()
|
||||
?: Badge()
|
||||
badgeProvider.setBadge(key, badge)
|
||||
val inst = installations.value ?: return
|
||||
val inst = installations.value
|
||||
inst.removeAll {
|
||||
it.session.sessionId == sessionId
|
||||
}
|
||||
installations.postValue(inst)
|
||||
installations.value = inst
|
||||
|
||||
}
|
||||
|
||||
@@ -165,41 +177,66 @@ class AppRepository(
|
||||
val appInstallation = AppInstallation(session)
|
||||
val inst = installations.value ?: mutableListOf()
|
||||
inst.add(appInstallation)
|
||||
installations.postValue(inst)
|
||||
installations.value = inst
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
val apps = profiles.map { p -> launcherApps.getActivityList(null, p).mapNotNull { getApplication(it, p) } }.flatten()
|
||||
installedApps.value = apps
|
||||
}
|
||||
|
||||
override suspend fun search(query: String) {
|
||||
updateAppsForDisplay()
|
||||
private fun getApplications(packageName: String): List<Application> {
|
||||
if (packageName == context.packageName) return emptyList()
|
||||
|
||||
return profiles.map { p ->
|
||||
launcherApps.getActivityList(packageName, p).mapNotNull { getApplication(it, p) }
|
||||
}.flatten()
|
||||
}
|
||||
|
||||
private suspend fun updateAppsForDisplay() {
|
||||
val query = searchRepository.currentQuery.value ?: ""
|
||||
|
||||
val componentName = ComponentName.unflattenFromString(query)
|
||||
private fun getApplication(
|
||||
launcherActivityInfo: LauncherActivityInfo,
|
||||
profile: UserHandle
|
||||
): Application? {
|
||||
if (launcherActivityInfo.applicationInfo.packageName == context.packageName && !context.packageName.endsWith(
|
||||
".debug"
|
||||
)
|
||||
) return null
|
||||
return LauncherApp(context, launcherActivityInfo)
|
||||
}
|
||||
|
||||
val apps = withContext(Dispatchers.Default) {
|
||||
val hiddenItems = hiddenItemKeys.value ?: emptyList()
|
||||
val installed = installedApps.value ?: emptyList()
|
||||
val installing = installations.value ?: emptyList<AppInstallation>()
|
||||
val results = mutableListOf<Application>()
|
||||
results.addAll(installed)
|
||||
results.addAll(installing)
|
||||
if (query.isNotEmpty()) {
|
||||
results.removeAll { !it.label.contains(query, ignoreCase = true) }
|
||||
getActivityByComponentName(componentName)?.let { results.add(it) }
|
||||
override fun search(query: String): Flow<List<Application>> = channelFlow {
|
||||
|
||||
combine(installedApps, hiddenItems, installations) {_, _, _ ->
|
||||
null
|
||||
}.collectLatest {
|
||||
withContext(Dispatchers.IO) {
|
||||
val appResults = mutableListOf<Application>()
|
||||
if (query.isEmpty()) {
|
||||
appResults.addAll(installedApps.value)
|
||||
appResults.addAll(installations.value)
|
||||
} else {
|
||||
appResults.addAll(installedApps.value.filter {
|
||||
it.label.contains(
|
||||
query,
|
||||
ignoreCase = true
|
||||
)
|
||||
})
|
||||
appResults.addAll(installations.value.filter {
|
||||
it.label.contains(
|
||||
query,
|
||||
ignoreCase = true
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
val componentName = ComponentName.unflattenFromString(query)
|
||||
getActivityByComponentName(componentName)?.let { appResults.add(it) }
|
||||
|
||||
appResults.removeAll { hiddenItems.value.contains(it.key) }
|
||||
|
||||
appResults.sort()
|
||||
|
||||
send(appResults)
|
||||
}
|
||||
results.removeAll { hiddenItems.contains(it.key) }
|
||||
results.sort()
|
||||
results
|
||||
}
|
||||
|
||||
applications.value = apps
|
||||
}
|
||||
|
||||
private fun getActivityByComponentName(componentName: ComponentName?): Application? {
|
||||
@@ -211,15 +248,4 @@ class AppRepository(
|
||||
LauncherApp(context, lai)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getApplication(launcherActivityInfo: LauncherActivityInfo, profile: UserHandle): Application? {
|
||||
if (launcherActivityInfo.applicationInfo.packageName == context.packageName && !context.packageName.endsWith(".debug")) return null
|
||||
return LauncherApp(context, launcherActivityInfo)
|
||||
}
|
||||
|
||||
private fun getApplications(packageName: String): List<Application> {
|
||||
if (packageName == context.packageName) return emptyList()
|
||||
|
||||
return profiles.map { p -> launcherApps.getActivityList(packageName, p).mapNotNull { getApplication(it, p) } }.flatten()
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package de.mm20.launcher2.applications
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.search.data.Application
|
||||
|
||||
class AppViewModel(
|
||||
appRepository: AppRepository
|
||||
): ViewModel() {
|
||||
val applications: LiveData<List<Application>> = appRepository.applications
|
||||
}
|
||||
|
||||
@@ -5,6 +5,5 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val applicationsModule = module {
|
||||
single { AppRepository(androidContext(), get(), get()) }
|
||||
viewModel { AppViewModel(get()) }
|
||||
single<AppRepository> { AppRepositoryImpl(androidContext(), get(), get()) }
|
||||
}
|
||||
Reference in New Issue
Block a user