parent
9bee1158d6
commit
0b01019be8
@ -1,5 +1,6 @@
|
||||
package de.mm20.launcher2.ui.launcher.search
|
||||
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
@ -76,6 +77,8 @@ fun SearchColumn(
|
||||
val apps by viewModel.appResults
|
||||
val workApps by viewModel.workAppResults
|
||||
val privateApps by viewModel.privateSpaceAppResults
|
||||
val profiles by viewModel.profiles.collectAsState(emptyList())
|
||||
val profileStates by viewModel.profileStates.collectAsState(emptyList())
|
||||
val workProfile by viewModel.workProfile.collectAsState(null)
|
||||
val workProfileState by viewModel.workProfileState.collectAsState(null)
|
||||
val privateProfile by viewModel.privateProfile.collectAsState(null)
|
||||
@ -110,6 +113,7 @@ fun SearchColumn(
|
||||
|
||||
val expandedCategory: SearchCategory? by viewModel.expandedCategory
|
||||
|
||||
var selectedAppProfileIndex: Int by remember(isSearchEmpty) { mutableIntStateOf(0) }
|
||||
var selectedContactIndex: Int by remember(contacts) { mutableIntStateOf(-1) }
|
||||
var selectedFileIndex: Int by remember(files) { mutableIntStateOf(-1) }
|
||||
var selectedCalendarIndex: Int by remember(events) { mutableIntStateOf(-1) }
|
||||
@ -171,39 +175,34 @@ fun SearchColumn(
|
||||
)
|
||||
}
|
||||
|
||||
AppResults(
|
||||
key = "apps",
|
||||
apps = apps,
|
||||
highlightedItem = bestMatch as? Application,
|
||||
columns = columns,
|
||||
reverse = reverse
|
||||
)
|
||||
|
||||
if (privateProfile != null && isSearchEmpty) {
|
||||
if (isSearchEmpty && profiles.size > 1) {
|
||||
AppResults(
|
||||
key = "apps-priv",
|
||||
apps = privateApps,
|
||||
profile = privateProfile,
|
||||
isProfileLocked = privateProfileState?.locked == true,
|
||||
onProfileLockChange = if (hasProfilesPermission) {
|
||||
{ viewModel.setProfileLock(privateProfile, it) }
|
||||
} else null,
|
||||
apps = when(selectedAppProfileIndex) {
|
||||
1 -> privateApps
|
||||
2 -> workApps
|
||||
else -> apps
|
||||
},
|
||||
highlightedItem = bestMatch as? Application,
|
||||
profiles = profiles,
|
||||
selectedProfileIndex = selectedAppProfileIndex,
|
||||
onProfileSelected = {
|
||||
selectedAppProfileIndex = it
|
||||
},
|
||||
isProfileLocked = profileStates.getOrNull(selectedAppProfileIndex)?.locked == true,
|
||||
onProfileLockChange = { p, l ->
|
||||
viewModel.setProfileLock(p, l)
|
||||
},
|
||||
columns = columns,
|
||||
reverse = reverse
|
||||
reverse = reverse,
|
||||
showProfileLockControls = hasProfilesPermission,
|
||||
)
|
||||
}
|
||||
|
||||
if (workProfile != null && isSearchEmpty) {
|
||||
} else {
|
||||
AppResults(
|
||||
key = "apps-work",
|
||||
apps = workApps,
|
||||
profile = workProfile,
|
||||
isProfileLocked = workProfileState?.locked == true,
|
||||
onProfileLockChange = if (hasProfilesPermission) {
|
||||
{ viewModel.setProfileLock(workProfile, it) }
|
||||
} else null,
|
||||
apps = apps,
|
||||
highlightedItem = bestMatch as? Application,
|
||||
onProfileSelected = {
|
||||
selectedAppProfileIndex = it
|
||||
},
|
||||
columns = columns,
|
||||
reverse = reverse
|
||||
)
|
||||
|
||||
@ -86,6 +86,11 @@ class SearchVM : ViewModel(), KoinComponent {
|
||||
SharingStarted.WhileSubscribed(),
|
||||
replay = 1
|
||||
)
|
||||
val profileStates = profiles.flatMapLatest {
|
||||
combine(it.map { profileManager.getProfileState(it) }) {
|
||||
it.toList()
|
||||
}
|
||||
}
|
||||
val workProfile = profiles.map {
|
||||
it.find { it.type == Profile.Type.Work }
|
||||
}
|
||||
|
||||
@ -1,20 +1,33 @@
|
||||
package de.mm20.launcher2.ui.launcher.search.apps
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
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.material.icons.rounded.WorkOff
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LeadingIconTab
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.PrimaryScrollableTabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.icons.PrivateSpace
|
||||
@ -23,13 +36,16 @@ import de.mm20.launcher2.search.Application
|
||||
import de.mm20.launcher2.ui.R
|
||||
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.LocalGridSettings
|
||||
|
||||
fun LazyListScope.AppResults(
|
||||
key: String,
|
||||
profile: Profile? = null,
|
||||
onProfileSelected: (Int) -> Unit,
|
||||
profiles: List<Profile> = emptyList(),
|
||||
selectedProfileIndex: Int = -1,
|
||||
showProfileLockControls: Boolean = false,
|
||||
isProfileLocked: Boolean = false,
|
||||
onProfileLockChange: ((Boolean) -> Unit)? = null,
|
||||
onProfileLockChange: ((Profile, Boolean) -> Unit)? = null,
|
||||
apps: List<Application>,
|
||||
highlightedItem: Application? = null,
|
||||
columns: Int,
|
||||
@ -37,47 +53,140 @@ fun LazyListScope.AppResults(
|
||||
) {
|
||||
|
||||
GridResults(
|
||||
key = key,
|
||||
key = "apps",
|
||||
items = apps,
|
||||
before = if (profile != null) {
|
||||
before = if (profiles.size > 1) {
|
||||
{
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp, start = 16.dp, end = 4.dp, bottom = 4.dp)
|
||||
.heightIn(min = 40.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
Column(
|
||||
verticalArrangement = if (reverse) Arrangement.BottomReversed else Arrangement.Top,
|
||||
) {
|
||||
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
|
||||
PrimaryScrollableTabRow(
|
||||
selectedTabIndex = selectedProfileIndex,
|
||||
containerColor = Color.Transparent,
|
||||
edgePadding = 16.dp,
|
||||
divider = {}
|
||||
) {
|
||||
for ((i, profile) in profiles.withIndex()) {
|
||||
LeadingIconTab(
|
||||
selected = selectedProfileIndex == profiles.indexOf(profile),
|
||||
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)
|
||||
}
|
||||
)
|
||||
},
|
||||
icon = {
|
||||
when (profile.type) {
|
||||
Profile.Type.Personal -> Icon(
|
||||
Icons.Rounded.Person,
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
Profile.Type.Work -> Icon(
|
||||
Icons.Rounded.Work,
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
Profile.Type.Private -> Icon(
|
||||
Icons.Rounded.PrivateSpace,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
onProfileSelected(i)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
HorizontalDivider()
|
||||
|
||||
val profileType = profiles[selectedProfileIndex].type
|
||||
if (showProfileLockControls && profileType != Profile.Type.Personal) {
|
||||
if (isProfileLocked) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.fillMaxWidth()
|
||||
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, MaterialTheme.shapes.small)
|
||||
.background(MaterialTheme.colorScheme.surfaceContainer, MaterialTheme.shapes.small)
|
||||
.padding(vertical = 64.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
if (profileType == Profile.Type.Work) Icons.Rounded.WorkOff else Icons.Rounded.Lock,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(48.dp),
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
Text(
|
||||
stringResource(
|
||||
if (profileType == Profile.Type.Work) R.string.profile_work_profile_state_locked
|
||||
else R.string.profile_private_profile_state_locked
|
||||
),
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 32.dp),
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
Button(
|
||||
modifier = Modifier,
|
||||
onClick = {
|
||||
onProfileLockChange?.invoke(
|
||||
profiles[selectedProfileIndex],
|
||||
false
|
||||
)
|
||||
},
|
||||
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
||||
) {
|
||||
Icon(
|
||||
if (profileType == Profile.Type.Work) Icons.Rounded.Work else Icons.Rounded.LockOpen,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(end = ButtonDefaults.IconSpacing)
|
||||
.size(ButtonDefaults.IconSize)
|
||||
)
|
||||
Text(
|
||||
stringResource(
|
||||
if (profileType == Profile.Type.Work) R.string.profile_work_profile_action_unlock
|
||||
else R.string.profile_private_profile_action_unlock
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
FilledTonalButton(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.fillMaxWidth(),
|
||||
onClick = {
|
||||
onProfileLockChange?.invoke(
|
||||
profiles[selectedProfileIndex],
|
||||
true
|
||||
)
|
||||
},
|
||||
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
|
||||
) {
|
||||
Icon(
|
||||
if (profileType == Profile.Type.Work) Icons.Rounded.WorkOff else Icons.Rounded.Lock,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(end = ButtonDefaults.IconSpacing)
|
||||
.size(ButtonDefaults.IconSize)
|
||||
)
|
||||
Text(
|
||||
stringResource(
|
||||
if (profileType == Profile.Type.Work) R.string.profile_work_profile_action_lock
|
||||
else R.string.profile_private_profile_action_lock
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else null,
|
||||
|
||||
@ -985,4 +985,10 @@
|
||||
<string name="calendar_widget_next_day">Next day</string>
|
||||
<string name="calendar_widget_create_event">Create new event</string>
|
||||
<string name="calendar_widget_open_calendar">Open calendar app</string>
|
||||
<string name="profile_work_profile_state_locked">Work apps are paused.</string>
|
||||
<string name="profile_work_profile_action_unlock">Unpause</string>
|
||||
<string name="profile_work_profile_action_lock">Pause work apps</string>
|
||||
<string name="profile_private_profile_state_locked">Private space is locked.</string>
|
||||
<string name="profile_private_profile_action_unlock">Unlock</string>
|
||||
<string name="profile_private_profile_action_lock">Lock private space</string>
|
||||
</resources>
|
||||
Loading…
x
Reference in New Issue
Block a user