diff --git a/app/ui/build.gradle.kts b/app/ui/build.gradle.kts index 8d69585f..52b85064 100644 --- a/app/ui/build.gradle.kts +++ b/app/ui/build.gradle.kts @@ -120,6 +120,7 @@ dependencies { implementation(project(":core:i18n")) implementation(project(":core:compat")) implementation(project(":core:ktx")) + implementation(project(":core:profiles")) implementation(project(":services:icons")) implementation(project(":services:music")) implementation(project(":services:tags")) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt index 3b226bf2..80ce027a 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchColumn.kt @@ -17,10 +17,8 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -74,8 +72,15 @@ fun SearchColumn( val hideFavs by viewModel.hideFavorites val favoritesEnabled by viewModel.favoritesEnabled.collectAsState(false) + val apps by viewModel.appResults val workApps by viewModel.workAppResults + val privateApps by viewModel.privateSpaceAppResults + val workProfile by viewModel.workProfile.collectAsState(null) + val workProfileState by viewModel.workProfileState.collectAsState(null) + val privateProfile by viewModel.privateProfile.collectAsState(null) + val privateProfileState by viewModel.privateProfileState.collectAsState(null) + val appShortcuts by viewModel.appShortcutResults val contacts by viewModel.contactResults val files by viewModel.fileResults @@ -96,26 +101,13 @@ fun SearchColumn( val missingContactsPermission by viewModel.missingContactsPermission.collectAsState(false) val missingLocationPermission by viewModel.missingLocationPermission.collectAsState(false) val missingFilesPermission by viewModel.missingFilesPermission.collectAsState(false) + val hasProfilesPermission by viewModel.hasProfilesPermission.collectAsState(false) val pinnedTags by favoritesVM.pinnedTags.collectAsState(emptyList()) val selectedTag by favoritesVM.selectedTag.collectAsState(null) val favoritesEditButton by favoritesVM.showEditButton.collectAsState(false) val favoritesTagsExpanded by favoritesVM.tagsExpanded.collectAsState(false) - var showWorkProfileApps by remember { mutableStateOf(false) } - val separateWorkProfile by viewModel.separateWorkProfile.collectAsState(true) - val visibleApps by remember { - derivedStateOf { - when { - !separateWorkProfile -> (apps + workApps).sorted() - workApps.isEmpty() -> apps - apps.isEmpty() -> workApps - showWorkProfileApps -> workApps - else -> apps - } - } - } - val expandedCategory: SearchCategory? by viewModel.expandedCategory var selectedContactIndex: Int by remember(contacts) { mutableIntStateOf(-1) } @@ -180,15 +172,43 @@ fun SearchColumn( } AppResults( - apps = visibleApps, - showTabs = separateWorkProfile && apps.isNotEmpty() && workApps.isNotEmpty(), + key = "apps", + apps = apps, highlightedItem = bestMatch as? Application, - selectedTab = if (showWorkProfileApps) 1 else 0, - onSelectedTabChange = { showWorkProfileApps = it == 1 }, columns = columns, reverse = reverse ) + if (privateProfile != null && isSearchEmpty) { + AppResults( + key = "apps-priv", + apps = privateApps, + profile = privateProfile, + isProfileLocked = privateProfileState?.locked == true, + onProfileLockChange = if (hasProfilesPermission) { + { viewModel.setProfileLock(privateProfile, it) } + } else null, + highlightedItem = bestMatch as? Application, + columns = columns, + reverse = reverse + ) + } + + if (workProfile != null && isSearchEmpty) { + AppResults( + key = "apps-work", + apps = workApps, + profile = workProfile, + isProfileLocked = workProfileState?.locked == true, + onProfileLockChange = if (hasProfilesPermission) { + { viewModel.setProfileLock(workProfile, it) } + } else null, + highlightedItem = bestMatch as? Application, + columns = columns, + reverse = reverse + ) + } + if (!isSearchEmpty) { ShortcutResults( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt index 94422393..1c3635c1 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import de.mm20.launcher2.devicepose.DevicePoseProvider +import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.preferences.SearchResultOrder @@ -16,6 +17,8 @@ import de.mm20.launcher2.preferences.search.LocationSearchSettings import de.mm20.launcher2.preferences.search.SearchFilterSettings import de.mm20.launcher2.preferences.search.ShortcutSearchSettings import de.mm20.launcher2.preferences.ui.SearchUiSettings +import de.mm20.launcher2.profiles.Profile +import de.mm20.launcher2.profiles.ProfileManager import de.mm20.launcher2.search.AppShortcut import de.mm20.launcher2.search.Application import de.mm20.launcher2.search.Article @@ -41,6 +44,9 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import org.koin.core.component.KoinComponent @@ -51,6 +57,7 @@ class SearchVM : ViewModel(), KoinComponent { private val favoritesService: FavoritesService by inject() private val searchableRepository: SavableSearchableRepository by inject() private val permissionsManager: PermissionsManager by inject() + private val profileManager: ProfileManager by inject() private val fileSearchSettings: FileSearchSettings by inject() private val contactSearchSettings: ContactSearchSettings by inject() @@ -72,9 +79,37 @@ class SearchVM : ViewModel(), KoinComponent { val expandedCategory = mutableStateOf(null) val locationResults = mutableStateOf>(emptyList()) + + val profiles = profileManager.profiles.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), replay = 1) + val workProfile = profiles.map { + it.find { it.type == Profile.Type.Work } + } + val privateProfile = profiles.map { + it.find { it.type == Profile.Type.Private } + } + val workProfileState = workProfile.flatMapLatest { + profileManager.getProfileState(it) + } + val privateProfileState = privateProfile.flatMapLatest { + profileManager.getProfileState(it) + } + + val hasProfilesPermission = permissionsManager.hasPermission(PermissionGroup.ManageProfiles) + + fun setProfileLock(profile: Profile?, locked: Boolean) { + if (isAtLeastApiLevel(28) && profile != null) { + if (locked) { + profileManager.lockProfile(profile) + } else { + profileManager.unlockProfile(profile) + } + } + } + val appResults = mutableStateOf>(emptyList()) val workAppResults = mutableStateOf>(emptyList()) val privateSpaceAppResults = mutableStateOf>(emptyList()) + val appShortcutResults = mutableStateOf>(emptyList()) val fileResults = mutableStateOf>(emptyList()) val contactResults = mutableStateOf>(emptyList()) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppResults.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppResults.kt index 311bf020..39383b69 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppResults.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppResults.kt @@ -1,42 +1,86 @@ package de.mm20.launcher2.ui.launcher.search.apps -import androidx.compose.animation.Crossfade -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListScope -import androidx.compose.material3.HorizontalDivider +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Lock +import androidx.compose.material.icons.rounded.LockOpen +import androidx.compose.material.icons.rounded.Person +import androidx.compose.material.icons.rounded.Work +import androidx.compose.material3.FilledIconToggleButton +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.PrimaryTabRow -import androidx.compose.material3.Tab import androidx.compose.material3.Text +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import de.mm20.launcher2.icons.PrivateSpace +import de.mm20.launcher2.profiles.Profile import de.mm20.launcher2.search.Application import de.mm20.launcher2.ui.R -import de.mm20.launcher2.ui.ktx.animateCorners -import de.mm20.launcher2.ui.ktx.withCorners import de.mm20.launcher2.ui.launcher.search.common.grid.GridItem import de.mm20.launcher2.ui.launcher.search.common.grid.GridResults -import de.mm20.launcher2.ui.layout.BottomReversed -import de.mm20.launcher2.ui.locals.LocalCardStyle import de.mm20.launcher2.ui.locals.LocalGridSettings fun LazyListScope.AppResults( + key: String, + profile: Profile? = null, + isProfileLocked: Boolean = false, + onProfileLockChange: ((Boolean) -> Unit)? = null, apps: List, - showTabs: Boolean, - selectedTab: Int, - onSelectedTabChange: (Int) -> Unit, highlightedItem: Application? = null, columns: Int, reverse: Boolean, ) { GridResults( - key = "app", + key = key, items = apps, + before = if (profile != null) { + { + Row( + modifier = Modifier + .padding(top = 4.dp, start = 16.dp, end = 4.dp, bottom = 4.dp) + .heightIn(min = 40.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + when (profile.type) { + Profile.Type.Work -> Icons.Rounded.Work + Profile.Type.Private -> Icons.Rounded.PrivateSpace + else -> Icons.Rounded.Person + }, + null, + tint = MaterialTheme.colorScheme.primary, + ) + Text( + text = when (profile.type) { + Profile.Type.Personal -> stringResource(R.string.apps_profile_main) + Profile.Type.Work -> stringResource(R.string.apps_profile_work) + Profile.Type.Private -> stringResource(R.string.apps_profile_private) + }, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier + .weight(1f) + .padding(horizontal = 12.dp) + ) + if (onProfileLockChange != null) { + FilledIconToggleButton(checked = isProfileLocked, onCheckedChange = { + onProfileLockChange(it) + }) { + Icon( + if (isProfileLocked) Icons.Rounded.Lock else Icons.Rounded.LockOpen, + null + ) + } + } + } + } + } else null, itemContent = { GridItem( item = it, @@ -44,43 +88,6 @@ fun LazyListScope.AppResults( highlight = it.key == highlightedItem?.key ) }, - before = if (showTabs) { - { - Column( - verticalArrangement = if (reverse) Arrangement.BottomReversed else Arrangement.Top, - ) { - PrimaryTabRow( - selectedTabIndex = selectedTab, - modifier = Modifier - .fillMaxWidth() - .clip( - MaterialTheme.shapes.medium.withCorners( - topStart = !reverse, - topEnd = !reverse, - bottomEnd = reverse, - bottomStart = reverse, - ) - ), - divider = {}, - containerColor = Color.Transparent - ) { - Tab( - selected = selectedTab == 0, - onClick = { onSelectedTabChange(0) }, - text = { Text(stringResource(R.string.apps_profile_main)) }, - unselectedContentColor = MaterialTheme.colorScheme.onSurfaceVariant, - ) - Tab( - selected = selectedTab == 1, - onClick = { onSelectedTabChange(1) }, - text = { Text(stringResource(R.string.apps_profile_work)) }, - unselectedContentColor = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } - HorizontalDivider() - } - } - } else null, reverse = reverse, columns = columns, ) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridResults.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridResults.kt index 66b666ac..72202b43 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridResults.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridResults.kt @@ -34,6 +34,10 @@ fun LazyListScope.GridResults( val isBottom = reverse || items.isEmpty() && after == null Box( modifier = Modifier + .padding( + top = if (reverse && isTop) 8.dp else 0.dp, + bottom = if (!reverse && isBottom) 8.dp else 0.dp, + ) .background( MaterialTheme.colorScheme.surface.copy(alpha = LocalCardStyle.current.opacity), MaterialTheme.shapes.medium.withCorners( diff --git a/core/base/src/main/java/de/mm20/launcher2/icons/Icons.kt b/core/base/src/main/java/de/mm20/launcher2/icons/Icons.kt index 731dc3a1..a6c1451d 100644 --- a/core/base/src/main/java/de/mm20/launcher2/icons/Icons.kt +++ b/core/base/src/main/java/de/mm20/launcher2/icons/Icons.kt @@ -1647,4 +1647,38 @@ private val _Google = materialIcon("Icons.Rounded.Google") { } val Icons.Rounded.Google - get() = _Google \ No newline at end of file + get() = _Google + +private val _PrivateSpace = materialIcon("Icons.Rounded.PrivateSpace") { + materialPath { + moveTo(11.999784f, 1.9998779f) + lineTo(3.9997559f, 5.0002116f) + verticalLineToRelative(6.0895504f) + curveToRelative(0f, 5.049995f, 3.410033f, 9.760447f, 8.0000281f, 10.910446f) + curveToRelative(4.589996f, -1.149999f, 8.000029f, -5.860451f, 8.000029f, -10.910446f) + verticalLineTo(5.0002116f) + close() + moveToRelative(0f, 4.0002727f) + curveToRelative(1.929998f, 0f, 3.500045f, 1.5700466f, 3.500045f, 3.5000447f) + curveToRelative(0f, 1.5799987f, -1.05959f, 2.9098487f, -2.499589f, 3.3398477f) + verticalLineToRelative(2.160075f) + horizontalLineToRelative(1.999878f) + verticalLineToRelative(1.999878f) + horizontalLineTo(13.00024f) + verticalLineToRelative(0.999939f) + horizontalLineTo(10.999845f) + verticalLineTo(12.840043f) + curveTo(9.5598468f, 12.410044f, 8.5002563f, 11.090194f, 8.5002563f, 9.5001953f) + curveToRelative(0f, -1.9299981f, 1.5695297f, -3.5000447f, 3.4995277f, -3.5000447f) + close() + moveToRelative(0f, 1.9998779f) + curveToRelative(-0.827999f, 0f, -1.49965f, 0.6721676f, -1.49965f, 1.5001668f) + curveToRelative(0f, 0.8279987f, 0.671651f, 1.4996497f, 1.49965f, 1.4996497f) + curveToRelative(0.828f, 0f, 1.500167f, -0.671651f, 1.500167f, -1.4996497f) + curveToRelative(0f, -0.8279992f, -0.672167f, -1.5001668f, -1.500167f, -1.5001668f) + close() + } +} + +val Icons.Rounded.PrivateSpace + get() = _PrivateSpace \ No newline at end of file diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index bb17ab02..d7abca98 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -682,6 +682,7 @@ All icon packs Personal Work + Private space Favorites Pinned and frequently used items will appear here There are no items with this tag diff --git a/core/permissions/src/main/java/de/mm20/launcher2/permissions/PermissionsManager.kt b/core/permissions/src/main/java/de/mm20/launcher2/permissions/PermissionsManager.kt index f4595e85..3e59e3b4 100644 --- a/core/permissions/src/main/java/de/mm20/launcher2/permissions/PermissionsManager.kt +++ b/core/permissions/src/main/java/de/mm20/launcher2/permissions/PermissionsManager.kt @@ -18,7 +18,6 @@ import de.mm20.launcher2.crashreporter.CrashReporter import de.mm20.launcher2.ktx.checkPermission import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.ktx.tryStartActivity -import de.mm20.launcher2.plugin.contracts.PluginContract import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -65,7 +64,7 @@ enum class PermissionGroup { Notifications, AppShortcuts, Accessibility, - HiddenProfiles, + ManageProfiles, } internal class PermissionsManagerImpl( @@ -91,8 +90,8 @@ internal class PermissionsManagerImpl( private val appShortcutsPermissionState = MutableStateFlow( checkPermissionOnce(PermissionGroup.AppShortcuts) ) - private val hiddenProfilesPermissionState = MutableStateFlow( - checkPermissionOnce(PermissionGroup.HiddenProfiles) + private val mManageProfilesPermissionState = MutableStateFlow( + checkPermissionOnce(PermissionGroup.ManageProfiles) ) override fun requestPermission(context: AppCompatActivity, permissionGroup: PermissionGroup) { @@ -146,7 +145,7 @@ internal class PermissionsManagerImpl( } } - PermissionGroup.HiddenProfiles, + PermissionGroup.ManageProfiles, PermissionGroup.AppShortcuts -> { if (isAtLeastApiLevel(29)) { val roleManager = context.getSystemService() @@ -201,7 +200,7 @@ internal class PermissionsManagerImpl( context.getSystemService()?.hasShortcutHostPermission() == true } - PermissionGroup.HiddenProfiles -> { + PermissionGroup.ManageProfiles -> { if (isAtLeastApiLevel(29)) { context.getSystemService()?.isRoleHeld(RoleManager.ROLE_HOME) == true } else false @@ -222,7 +221,7 @@ internal class PermissionsManagerImpl( PermissionGroup.Notifications -> notificationsPermissionState PermissionGroup.AppShortcuts -> appShortcutsPermissionState PermissionGroup.Accessibility -> accessibilityPermissionState - PermissionGroup.HiddenProfiles -> hiddenProfilesPermissionState + PermissionGroup.ManageProfiles -> mManageProfilesPermissionState } } @@ -241,14 +240,14 @@ internal class PermissionsManagerImpl( PermissionGroup.Notifications -> notificationsPermissionState.value = granted PermissionGroup.AppShortcuts -> appShortcutsPermissionState.value = granted PermissionGroup.Accessibility -> accessibilityPermissionState.value = granted - PermissionGroup.HiddenProfiles -> hiddenProfilesPermissionState.value = granted + PermissionGroup.ManageProfiles -> mManageProfilesPermissionState.value = granted } } override fun onResume() { externalStoragePermissionState.value = checkPermissionOnce(PermissionGroup.ExternalStorage) appShortcutsPermissionState.value = checkPermissionOnce(PermissionGroup.AppShortcuts) - hiddenProfilesPermissionState.value = checkPermissionOnce(PermissionGroup.HiddenProfiles) + mManageProfilesPermissionState.value = checkPermissionOnce(PermissionGroup.ManageProfiles) } override fun reportNotificationListenerState(running: Boolean) { diff --git a/core/profiles/src/main/java/de/mm20/launcher2/profiles/ProfileManager.kt b/core/profiles/src/main/java/de/mm20/launcher2/profiles/ProfileManager.kt index 51d087f6..ece7bb6e 100644 --- a/core/profiles/src/main/java/de/mm20/launcher2/profiles/ProfileManager.kt +++ b/core/profiles/src/main/java/de/mm20/launcher2/profiles/ProfileManager.kt @@ -8,13 +8,11 @@ import android.content.pm.LauncherApps import android.os.Process import android.os.UserHandle import android.os.UserManager -import android.util.Log import androidx.annotation.RequiresApi import androidx.core.content.getSystemService import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionsManager -import de.mm20.launcher2.plugin.data.get import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -54,6 +52,10 @@ class ProfileManager( } }.shareIn(scope, SharingStarted.WhileSubscribed(), replay = 1) + val profiles: Flow> = profileStates.map { + it.map { it.profile } + }.shareIn(scope, SharingStarted.WhileSubscribed(), replay = 1) + init { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { @@ -82,7 +84,7 @@ class ProfileManager( ) scope.launch { if (isAtLeastApiLevel(35)) { - permissionsManager.hasPermission(PermissionGroup.HiddenProfiles).collectLatest { + permissionsManager.hasPermission(PermissionGroup.ManageProfiles).collectLatest { refreshProfiles() } } else { @@ -108,7 +110,6 @@ class ProfileManager( ) ) } - Log.d("MM20", "Profiles: $profiles") profileStates.value = profiles } } @@ -119,19 +120,16 @@ class ProfileManager( } } - fun getProfileState(profile: Profile): Flow { + fun getProfileState(profile: Profile?): Flow { return profileStates.map { profiles -> profiles.find { it.profile == profile }?.state } } - /** - * This only works when the launcher is installed in the primary profile. - */ private fun getProfileType(userHandle: UserHandle): Profile.Type { if (isAtLeastApiLevel(35)) { val launcherUserInfo = launcherApps.getLauncherUserInfo(userHandle) - return when(launcherUserInfo?.userType) { + return when (launcherUserInfo?.userType) { UserManager.USER_TYPE_PROFILE_PRIVATE -> Profile.Type.Private UserManager.USER_TYPE_PROFILE_MANAGED -> Profile.Type.Work else -> Profile.Type.Personal diff --git a/services/badges/src/main/java/de/mm20/launcher2/badges/providers/ProfileBadgeProvider.kt b/services/badges/src/main/java/de/mm20/launcher2/badges/providers/ProfileBadgeProvider.kt index 15e8d422..1417a1de 100644 --- a/services/badges/src/main/java/de/mm20/launcher2/badges/providers/ProfileBadgeProvider.kt +++ b/services/badges/src/main/java/de/mm20/launcher2/badges/providers/ProfileBadgeProvider.kt @@ -5,6 +5,7 @@ import androidx.compose.material.icons.rounded.Lock import androidx.compose.material.icons.rounded.Work import de.mm20.launcher2.badges.Badge import de.mm20.launcher2.badges.BadgeIcon +import de.mm20.launcher2.icons.PrivateSpace import de.mm20.launcher2.profiles.Profile import de.mm20.launcher2.profiles.ProfileManager import de.mm20.launcher2.search.AppShortcut @@ -47,7 +48,7 @@ class ProfileBadgeProvider : BadgeProvider, KoinComponent { ) private val PrivateProfile = Badge( - icon = BadgeIcon(Icons.Rounded.Lock) + icon = BadgeIcon(Icons.Rounded.PrivateSpace) ) } } \ No newline at end of file diff --git a/services/search/src/main/java/de/mm20/launcher2/search/SearchService.kt b/services/search/src/main/java/de/mm20/launcher2/search/SearchService.kt index 4e17980a..aad53d0b 100644 --- a/services/search/src/main/java/de/mm20/launcher2/search/SearchService.kt +++ b/services/search/src/main/java/de/mm20/launcher2/search/SearchService.kt @@ -259,13 +259,18 @@ internal class SearchServiceImpl( val privateSpace = profiles.find { it.type == Profile.Type.Private } appRepository.search("", false) .withCustomLabels(customAttributesRepository) - .map { - val grouped = it.groupBy { it.user } - val standardProfileApps = - standardProfile?.let { grouped[it.userHandle] } ?: emptyList() - val workProfileApps = workProfile?.let { grouped[it.userHandle] } ?: emptyList() - val privateSpaceApps = - privateSpace?.let { grouped[it.userHandle] } ?: emptyList() + .map { apps -> + val standardProfileApps = mutableListOf() + val workProfileApps = mutableListOf() + val privateSpaceApps = mutableListOf() + for (app in apps) { + when { + standardProfile != null && app.user == standardProfile.userHandle -> standardProfileApps.add(app) + workProfile != null && app.user == workProfile.userHandle -> workProfileApps.add(app) + privateSpace != null && app.user == privateSpace.userHandle -> privateSpaceApps.add(app) + else -> standardProfileApps.add(app) + } + } AllAppsResults( standardProfileApps = standardProfileApps.sorted(),