diff --git a/app/release/app-release.zip b/app/release/app-release.zip new file mode 100644 index 00000000..e53643ae Binary files /dev/null and b/app/release/app-release.zip differ diff --git a/applications/src/main/java/de/mm20/launcher2/search/data/AppInstallation.kt b/applications/src/main/java/de/mm20/launcher2/search/data/AppInstallation.kt index 8de8028c..c014aac5 100644 --- a/applications/src/main/java/de/mm20/launcher2/search/data/AppInstallation.kt +++ b/applications/src/main/java/de/mm20/launcher2/search/data/AppInstallation.kt @@ -26,9 +26,6 @@ class AppInstallation( override val key: String get() = "installer://${session.installerPackageName}:${session.appPackageName}" - override val badgeKey: String - get() = "app://${session.appPackageName}" - override fun getLaunchIntent(context: Context): Intent? { return session.createDetailsIntent() } diff --git a/applications/src/main/java/de/mm20/launcher2/search/data/AppShortcut.kt b/applications/src/main/java/de/mm20/launcher2/search/data/AppShortcut.kt index bbb42e6d..ed6e6609 100644 --- a/applications/src/main/java/de/mm20/launcher2/search/data/AppShortcut.kt +++ b/applications/src/main/java/de/mm20/launcher2/search/data/AppShortcut.kt @@ -32,7 +32,7 @@ class AppShortcut( internal val userSerialNumber: Long = launcherShortcut.userHandle.getSerialNumber(context) - private val isMainProfile = launcherShortcut.userHandle == Process.myUserHandle() + val isMainProfile = launcherShortcut.userHandle == Process.myUserHandle() override val key: String get() = if (isMainProfile) { @@ -41,11 +41,6 @@ class AppShortcut( "shortcut://${launcherShortcut.`package`}/${launcherShortcut.id}:${userSerialNumber}" } - override val badgeKey: String - get() { - return if (isMainProfile) "shortcut://${launcherShortcut.activity?.flattenToShortString()}" else "profile://$userSerialNumber" - } - override fun getLaunchIntent(context: Context): Intent? { return launcherShortcut.intent } diff --git a/applications/src/main/java/de/mm20/launcher2/search/data/Application.kt b/applications/src/main/java/de/mm20/launcher2/search/data/Application.kt index 6ab77ed9..663c5f4f 100644 --- a/applications/src/main/java/de/mm20/launcher2/search/data/Application.kt +++ b/applications/src/main/java/de/mm20/launcher2/search/data/Application.kt @@ -20,9 +20,6 @@ abstract class Application( val shortcuts: List = emptyList() ) : Searchable() { - override val badgeKey: String - get() = "app://${`package`}" - override fun serialize(): String { val json = JSONObject() json.put("package", `package`) diff --git a/applications/src/main/java/de/mm20/launcher2/search/data/LauncherApp.kt b/applications/src/main/java/de/mm20/launcher2/search/data/LauncherApp.kt index fa7c4a41..1e957953 100644 --- a/applications/src/main/java/de/mm20/launcher2/search/data/LauncherApp.kt +++ b/applications/src/main/java/de/mm20/launcher2/search/data/LauncherApp.kt @@ -57,10 +57,7 @@ class LauncherApp( ), KoinComponent { internal val userSerialNumber: Long = launcherActivityInfo.user.getSerialNumber(context) - private val isMainProfile = launcherActivityInfo.user == Process.myUserHandle() - - override val badgeKey: String = - if (isMainProfile) "app://${`package`}" else "profile://$userSerialNumber" + val isMainProfile = launcherActivityInfo.user == Process.myUserHandle() override val key: String get() = if (isMainProfile) "app://$`package`:$activity" else "app://$`package`:$activity:${userSerialNumber}" diff --git a/badges/build.gradle.kts b/badges/build.gradle.kts index 0781bc77..301795e0 100644 --- a/badges/build.gradle.kts +++ b/badges/build.gradle.kts @@ -47,5 +47,6 @@ dependencies { implementation(project(":notifications")) implementation(project(":preferences")) implementation(project(":base")) - + implementation(project(":search")) + implementation(project(":files")) } \ No newline at end of file diff --git a/badges/src/main/java/de/mm20/launcher2/badges/BadgeRepository.kt b/badges/src/main/java/de/mm20/launcher2/badges/BadgeRepository.kt index e69d70d2..ea2ba4b8 100644 --- a/badges/src/main/java/de/mm20/launcher2/badges/BadgeRepository.kt +++ b/badges/src/main/java/de/mm20/launcher2/badges/BadgeRepository.kt @@ -3,13 +3,14 @@ package de.mm20.launcher2.badges import android.content.Context import de.mm20.launcher2.badges.providers.* import de.mm20.launcher2.preferences.LauncherDataStore +import de.mm20.launcher2.search.data.Searchable import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import org.koin.core.component.KoinComponent import org.koin.core.component.inject interface BadgeRepository { - fun getBadge(badgeKey: String): Flow + fun getBadge(searchable: Searchable): Flow } internal class BadgeRepositoryImpl(private val context: Context) : BadgeRepository, KoinComponent { @@ -23,6 +24,7 @@ internal class BadgeRepositoryImpl(private val context: Context) : BadgeReposito scope.launch { dataStore.data.map { it.badges }.distinctUntilChanged().collectLatest { val providers = mutableListOf() + providers += WorkProfileBadgeProvider() if (it.notifications) { providers += NotificationBadgeProvider() } @@ -35,20 +37,19 @@ internal class BadgeRepositoryImpl(private val context: Context) : BadgeReposito if (it.suspendedApps) { providers += SuspendedAppsBadgeProvider() } - providers += WorkProfileBadgeProvider(context) badgeProviders.value = providers } } } - override fun getBadge(badgeKey: String): Flow = channelFlow { + override fun getBadge(searchable: Searchable): Flow = channelFlow { withContext(Dispatchers.Default) { badgeProviders.collectLatest { providers -> if (providers.isEmpty()) { send(null) return@collectLatest } - combine(providers.map { it.getBadge(badgeKey) }) { badges -> + combine(providers.map { it.getBadge(searchable) }) { badges -> if (badges.all { it == null }) { return@combine null } diff --git a/badges/src/main/java/de/mm20/launcher2/badges/providers/AppShortcutBadgeProvider.kt b/badges/src/main/java/de/mm20/launcher2/badges/providers/AppShortcutBadgeProvider.kt index 4f1da0e6..af3169b2 100644 --- a/badges/src/main/java/de/mm20/launcher2/badges/providers/AppShortcutBadgeProvider.kt +++ b/badges/src/main/java/de/mm20/launcher2/badges/providers/AppShortcutBadgeProvider.kt @@ -5,6 +5,8 @@ import android.content.Context import android.content.pm.PackageManager import de.mm20.launcher2.badges.Badge import de.mm20.launcher2.graphics.BadgeDrawable +import de.mm20.launcher2.search.data.AppShortcut +import de.mm20.launcher2.search.data.Searchable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow @@ -13,9 +15,9 @@ import kotlinx.coroutines.withContext class AppShortcutBadgeProvider( private val context: Context ) : BadgeProvider { - override fun getBadge(badgeKey: String): Flow = channelFlow { - if (badgeKey.startsWith("shortcut://")) { - val componentName = ComponentName.unflattenFromString(badgeKey.substring(11)) + override fun getBadge(searchable: Searchable): Flow = channelFlow { + if (searchable is AppShortcut) { + val componentName = searchable.launcherShortcut.activity if (componentName == null) { send(null) return@channelFlow diff --git a/badges/src/main/java/de/mm20/launcher2/badges/providers/BadgeProvider.kt b/badges/src/main/java/de/mm20/launcher2/badges/providers/BadgeProvider.kt index 7010b77f..eec5b033 100644 --- a/badges/src/main/java/de/mm20/launcher2/badges/providers/BadgeProvider.kt +++ b/badges/src/main/java/de/mm20/launcher2/badges/providers/BadgeProvider.kt @@ -1,6 +1,7 @@ package de.mm20.launcher2.badges.providers import de.mm20.launcher2.badges.Badge +import de.mm20.launcher2.search.data.Searchable import kotlinx.coroutines.flow.Flow interface BadgeProvider { @@ -9,5 +10,5 @@ interface BadgeProvider { * BadgeRepository is waiting for values from every provider. * null must be emitted if no badge should be shown. */ - fun getBadge(badgeKey: String): Flow + fun getBadge(searchable: Searchable): Flow } \ No newline at end of file diff --git a/badges/src/main/java/de/mm20/launcher2/badges/providers/CloudBadgeProvider.kt b/badges/src/main/java/de/mm20/launcher2/badges/providers/CloudBadgeProvider.kt index 886e35ce..6dc98e59 100644 --- a/badges/src/main/java/de/mm20/launcher2/badges/providers/CloudBadgeProvider.kt +++ b/badges/src/main/java/de/mm20/launcher2/badges/providers/CloudBadgeProvider.kt @@ -3,17 +3,20 @@ package de.mm20.launcher2.badges.providers import android.util.Log import de.mm20.launcher2.badges.Badge import de.mm20.launcher2.badges.R +import de.mm20.launcher2.search.data.File +import de.mm20.launcher2.search.data.Searchable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow class CloudBadgeProvider: BadgeProvider { - override fun getBadge(badgeKey: String): Flow = flow { - when(badgeKey) { - "gdrive://" -> emit(Badge(iconRes = R.drawable.ic_badge_gdrive)) - "onedrive://" -> emit(Badge(iconRes = R.drawable.ic_badge_onedrive)) - "owncloud://" -> emit(Badge(iconRes = R.drawable.ic_badge_owncloud)) - "nextcloud://" -> emit(Badge(iconRes = R.drawable.ic_badge_nextcloud)) - else -> emit(null) + override fun getBadge(searchable: Searchable): Flow = flow { + if (searchable is File) { + val iconResId = searchable.providerIconRes + if (iconResId != null) { + emit(Badge(iconRes = iconResId)) + return@flow + } } + emit(null) } } \ No newline at end of file diff --git a/badges/src/main/java/de/mm20/launcher2/badges/providers/NotificationBadgeProvider.kt b/badges/src/main/java/de/mm20/launcher2/badges/providers/NotificationBadgeProvider.kt index 46aab6ad..75b5aceb 100644 --- a/badges/src/main/java/de/mm20/launcher2/badges/providers/NotificationBadgeProvider.kt +++ b/badges/src/main/java/de/mm20/launcher2/badges/providers/NotificationBadgeProvider.kt @@ -3,6 +3,9 @@ package de.mm20.launcher2.badges.providers import android.app.Notification import de.mm20.launcher2.badges.Badge import de.mm20.launcher2.notifications.NotificationRepository +import de.mm20.launcher2.search.data.Application +import de.mm20.launcher2.search.data.LauncherApp +import de.mm20.launcher2.search.data.Searchable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.collectLatest @@ -13,9 +16,9 @@ import org.koin.core.component.inject class NotificationBadgeProvider : BadgeProvider, KoinComponent { private val notificationRepository: NotificationRepository by inject() - override fun getBadge(badgeKey: String): Flow = channelFlow { - if (badgeKey.startsWith("app://")) { - val packageName = badgeKey.substring(6) + override fun getBadge(searchable: Searchable): Flow = channelFlow { + if (searchable is Application) { + val packageName = searchable.`package` notificationRepository.notifications.map { it.filter { it.packageName == packageName } }.collectLatest { diff --git a/badges/src/main/java/de/mm20/launcher2/badges/providers/SuspendedAppsBadgeProvider.kt b/badges/src/main/java/de/mm20/launcher2/badges/providers/SuspendedAppsBadgeProvider.kt index 2ef7bb02..c49e766d 100644 --- a/badges/src/main/java/de/mm20/launcher2/badges/providers/SuspendedAppsBadgeProvider.kt +++ b/badges/src/main/java/de/mm20/launcher2/badges/providers/SuspendedAppsBadgeProvider.kt @@ -3,6 +3,9 @@ package de.mm20.launcher2.badges.providers import de.mm20.launcher2.applications.AppRepository import de.mm20.launcher2.badges.Badge import de.mm20.launcher2.badges.R +import de.mm20.launcher2.search.data.Application +import de.mm20.launcher2.search.data.LauncherApp +import de.mm20.launcher2.search.data.Searchable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.collectLatest @@ -12,9 +15,9 @@ import org.koin.core.component.inject class SuspendedAppsBadgeProvider : BadgeProvider, KoinComponent { private val appRepository: AppRepository by inject() - override fun getBadge(badgeKey: String): Flow = channelFlow { - if (badgeKey.startsWith("app://")) { - val packageName = badgeKey.substring(6) + override fun getBadge(searchable: Searchable): Flow = channelFlow { + if (searchable is Application) { + val packageName = searchable.`package` appRepository.getSuspendedPackages().collectLatest { if (it.contains(packageName)) { send( diff --git a/badges/src/main/java/de/mm20/launcher2/badges/providers/WorkProfileBadgeProvider.kt b/badges/src/main/java/de/mm20/launcher2/badges/providers/WorkProfileBadgeProvider.kt index 9d9642f2..593eb91e 100644 --- a/badges/src/main/java/de/mm20/launcher2/badges/providers/WorkProfileBadgeProvider.kt +++ b/badges/src/main/java/de/mm20/launcher2/badges/providers/WorkProfileBadgeProvider.kt @@ -1,26 +1,21 @@ package de.mm20.launcher2.badges.providers -import android.content.Context -import android.os.Process import de.mm20.launcher2.badges.Badge import de.mm20.launcher2.badges.R -import de.mm20.launcher2.ktx.getSerialNumber +import de.mm20.launcher2.search.data.AppShortcut +import de.mm20.launcher2.search.data.LauncherApp +import de.mm20.launcher2.search.data.Searchable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow -class WorkProfileBadgeProvider(private val context: Context) : BadgeProvider { - override fun getBadge(badgeKey: String): Flow = flow { - if (badgeKey.startsWith("profile://")) { - val serialNumber = badgeKey.substring(10).toLong() - if (serialNumber != Process.myUserHandle().getSerialNumber(context)) { - emit( - Badge( - iconRes = R.drawable.ic_badge_workprofile - ) +class WorkProfileBadgeProvider : BadgeProvider { + override fun getBadge(searchable: Searchable): Flow = flow { + if (searchable is LauncherApp && !searchable.isMainProfile || searchable is AppShortcut && !searchable.isMainProfile) { + emit( + Badge( + iconRes = R.drawable.ic_badge_workprofile ) - } else { - emit(null) - } + ) } else { emit(null) } diff --git a/badges/src/main/res/drawable-hdpi/ic_badge_gdrive.webp b/base/src/main/res/drawable-hdpi/ic_badge_gdrive.webp similarity index 100% rename from badges/src/main/res/drawable-hdpi/ic_badge_gdrive.webp rename to base/src/main/res/drawable-hdpi/ic_badge_gdrive.webp diff --git a/badges/src/main/res/drawable-mdpi/ic_badge_gdrive.webp b/base/src/main/res/drawable-mdpi/ic_badge_gdrive.webp similarity index 100% rename from badges/src/main/res/drawable-mdpi/ic_badge_gdrive.webp rename to base/src/main/res/drawable-mdpi/ic_badge_gdrive.webp diff --git a/badges/src/main/res/drawable-xhdpi/ic_badge_gdrive.webp b/base/src/main/res/drawable-xhdpi/ic_badge_gdrive.webp similarity index 100% rename from badges/src/main/res/drawable-xhdpi/ic_badge_gdrive.webp rename to base/src/main/res/drawable-xhdpi/ic_badge_gdrive.webp diff --git a/badges/src/main/res/drawable-xxhdpi/ic_badge_gdrive.webp b/base/src/main/res/drawable-xxhdpi/ic_badge_gdrive.webp similarity index 100% rename from badges/src/main/res/drawable-xxhdpi/ic_badge_gdrive.webp rename to base/src/main/res/drawable-xxhdpi/ic_badge_gdrive.webp diff --git a/badges/src/main/res/drawable-xxxhdpi/ic_badge_gdrive.webp b/base/src/main/res/drawable-xxxhdpi/ic_badge_gdrive.webp similarity index 100% rename from badges/src/main/res/drawable-xxxhdpi/ic_badge_gdrive.webp rename to base/src/main/res/drawable-xxxhdpi/ic_badge_gdrive.webp diff --git a/files/src/main/java/de/mm20/launcher2/search/data/File.kt b/files/src/main/java/de/mm20/launcher2/search/data/File.kt index 2c7e7ff9..0b91178a 100644 --- a/files/src/main/java/de/mm20/launcher2/search/data/File.kt +++ b/files/src/main/java/de/mm20/launcher2/search/data/File.kt @@ -17,6 +17,8 @@ abstract class File( ) : Searchable() { abstract val isStoredInCloud: Boolean + open val providerIconRes: Int? = null + override fun getPlaceholderIcon(context: Context): LauncherIcon { val (resId, bgColor) = when { isDirectory -> R.drawable.ic_file_folder to R.color.lightblue diff --git a/files/src/main/java/de/mm20/launcher2/search/data/GDriveFile.kt b/files/src/main/java/de/mm20/launcher2/search/data/GDriveFile.kt index 8c5ee4c5..10f70589 100644 --- a/files/src/main/java/de/mm20/launcher2/search/data/GDriveFile.kt +++ b/files/src/main/java/de/mm20/launcher2/search/data/GDriveFile.kt @@ -23,11 +23,10 @@ class GDriveFile( override val key: String = "gdrive://$fileId" - override val badgeKey: String - get() = "gdrive://" - override val isStoredInCloud = true + override val providerIconRes = R.drawable.ic_badge_gdrive + override fun getLaunchIntent(context: Context): Intent? { return Intent(Intent.ACTION_VIEW).apply { data = Uri.parse(viewUri) diff --git a/files/src/main/java/de/mm20/launcher2/search/data/NextcloudFile.kt b/files/src/main/java/de/mm20/launcher2/search/data/NextcloudFile.kt index 5bff0dae..53eb09a8 100644 --- a/files/src/main/java/de/mm20/launcher2/search/data/NextcloudFile.kt +++ b/files/src/main/java/de/mm20/launcher2/search/data/NextcloudFile.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri +import de.mm20.launcher2.files.R class NextcloudFile( fileId: Long, @@ -15,13 +16,13 @@ class NextcloudFile( val server: String, metaData: List> ) : File(fileId, path, mimeType, size, isDirectory, metaData) { - override val badgeKey: String = "nextcloud://" - override val key: String = "nextcloud://$server/$fileId" override val isStoredInCloud: Boolean get() = true + override val providerIconRes = R.drawable.ic_badge_nextcloud + override fun getLaunchIntent(context: Context): Intent? { return Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("$server/f/$id") diff --git a/files/src/main/java/de/mm20/launcher2/search/data/OneDriveFile.kt b/files/src/main/java/de/mm20/launcher2/search/data/OneDriveFile.kt index 983ca5ed..42a4f086 100644 --- a/files/src/main/java/de/mm20/launcher2/search/data/OneDriveFile.kt +++ b/files/src/main/java/de/mm20/launcher2/search/data/OneDriveFile.kt @@ -19,10 +19,10 @@ class OneDriveFile( val webUrl: String ) : File(0, path, mimeType, size, isDirectory, metaData) { - override val badgeKey: String = "onedrive://" - override val key: String = "onedrive://$fileId" + override val providerIconRes = R.drawable.ic_badge_onedrive + override val isStoredInCloud = true override fun getLaunchIntent(context: Context): Intent? { diff --git a/files/src/main/java/de/mm20/launcher2/search/data/OwncloudFile.kt b/files/src/main/java/de/mm20/launcher2/search/data/OwncloudFile.kt index 8c05e623..1470f1ed 100644 --- a/files/src/main/java/de/mm20/launcher2/search/data/OwncloudFile.kt +++ b/files/src/main/java/de/mm20/launcher2/search/data/OwncloudFile.kt @@ -17,13 +17,13 @@ class OwncloudFile( val server: String, metaData: List> ) : File(fileId, path, mimeType, size, isDirectory, metaData) { - override val badgeKey: String = "owncloud://" - override val key: String = "owncloud://$server/$fileId" override val isStoredInCloud: Boolean get() = true + override val providerIconRes = R.drawable.ic_badge_owncloud + override fun getLaunchIntent(context: Context): Intent? { return Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("$server/f/$id") diff --git a/search/src/main/java/de/mm20/launcher2/search/data/Searchable.kt b/search/src/main/java/de/mm20/launcher2/search/data/Searchable.kt index 2a2c2c91..98fe1d05 100644 --- a/search/src/main/java/de/mm20/launcher2/search/data/Searchable.kt +++ b/search/src/main/java/de/mm20/launcher2/search/data/Searchable.kt @@ -16,9 +16,6 @@ abstract class Searchable : Comparable { abstract val key: String abstract val label: String - open val badgeKey - get() = key - open fun serialize(): String = "" open fun getLaunchIntent(context: Context): Intent? = null diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/SearchableItemVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/SearchableItemVM.kt index e9697d1d..aff95dee 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/SearchableItemVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/SearchableItemVM.kt @@ -38,7 +38,7 @@ abstract class SearchableItemVM( favoritesRepository.unhideItem(searchable) } - val badge = badgeRepository.getBadge(searchable.badgeKey) + val badge = badgeRepository.getBadge(searchable) fun getIcon(size: Int): Flow { return iconRepository.getIcon(searchable, size)