android: ability to change profile from share dialog, mobile: do not show profile dropdown when there is only one visible profile (#2084)

* android: ability to change profile from share dialog

* icons swap
This commit is contained in:
Stanislav Dmitrenko 2023-03-27 19:58:14 +03:00 committed by GitHub
parent 48b4b23204
commit f5c11b8faf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 16 deletions

View file

@ -208,7 +208,7 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
} else if (chatModel.users.isEmpty()) { } else if (chatModel.users.isEmpty()) {
NavigationButtonMenu { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } } NavigationButtonMenu { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } }
} else { } else {
val users by remember { derivedStateOf { chatModel.users.toList() } } val users by remember { derivedStateOf { chatModel.users.filter { u -> u.user.activeUser || !u.user.hidden } } }
val allRead = users val allRead = users
.filter { u -> !u.user.activeUser && !u.user.hidden } .filter { u -> !u.user.activeUser && !u.user.hidden }
.all { u -> u.unreadCount == 0 } .all { u -> u.unreadCount == 0 }
@ -247,7 +247,7 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
} }
@Composable @Composable
private fun UserProfileButton(image: String?, allRead: Boolean, onButtonClicked: () -> Unit) { fun UserProfileButton(image: String?, allRead: Boolean, onButtonClicked: () -> Unit) {
IconButton(onClick = onButtonClicked) { IconButton(onClick = onButtonClicked) {
Box { Box {
ProfileImage( ProfileImage(

View file

@ -24,12 +24,15 @@ import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.HighOrLowlight import chat.simplex.app.ui.theme.HighOrLowlight
import chat.simplex.app.ui.theme.Indigo import chat.simplex.app.ui.theme.Indigo
import chat.simplex.app.views.helpers.* import chat.simplex.app.views.helpers.*
import kotlinx.coroutines.flow.MutableStateFlow
@Composable @Composable
fun ShareListView(chatModel: ChatModel, stopped: Boolean) { fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
var searchInList by rememberSaveable { mutableStateOf("") } var searchInList by rememberSaveable { mutableStateOf("") }
val userPickerState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) }
val switchingUsers = rememberSaveable { mutableStateOf(false) }
Scaffold( Scaffold(
topBar = { Column { ShareListToolbar(chatModel, stopped) { searchInList = it.trim() } } }, topBar = { Column { ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } } },
) { ) {
Box(Modifier.padding(it)) { Box(Modifier.padding(it)) {
Column( Column(
@ -45,23 +48,41 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
} }
} }
} }
UserPicker(chatModel, userPickerState, switchingUsers, showSettings = false, showCancel = true, cancelClicked = {
chatModel.sharedContent.value = null
})
} }
@Composable @Composable
private fun EmptyList() { private fun EmptyList() {
Box { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(stringResource(R.string.you_have_no_chats), Modifier.align(Alignment.Center), color = HighOrLowlight) Text(stringResource(R.string.you_have_no_chats), color = HighOrLowlight)
} }
} }
@Composable @Composable
private fun ShareListToolbar(chatModel: ChatModel, stopped: Boolean, onSearchValueChanged: (String) -> Unit) { private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableStateFlow<AnimatedViewState>, stopped: Boolean, onSearchValueChanged: (String) -> Unit) {
var showSearch by rememberSaveable { mutableStateOf(false) } var showSearch by rememberSaveable { mutableStateOf(false) }
val hideSearchOnBack = { onSearchValueChanged(""); showSearch = false } val hideSearchOnBack = { onSearchValueChanged(""); showSearch = false }
if (showSearch) { if (showSearch) {
BackHandler(onBack = hideSearchOnBack) BackHandler(onBack = hideSearchOnBack)
} }
val barButtons = arrayListOf<@Composable RowScope.() -> Unit>() val barButtons = arrayListOf<@Composable RowScope.() -> Unit>()
val users by remember { derivedStateOf { chatModel.users.filter { u -> u.user.activeUser || !u.user.hidden } } }
val navButton: @Composable RowScope.() -> Unit = {
when {
showSearch -> NavigationButtonBack(hideSearchOnBack)
users.size > 1 -> {
val allRead = users
.filter { u -> !u.user.activeUser && !u.user.hidden }
.all { u -> u.unreadCount == 0 }
UserProfileButton(chatModel.currentUser.value?.profile?.image, allRead) {
userPickerState.value = AnimatedViewState.VISIBLE
}
}
else -> NavigationButtonBack { chatModel.sharedContent.value = null }
}
}
if (chatModel.chats.size >= 8) { if (chatModel.chats.size >= 8) {
barButtons.add { barButtons.add {
IconButton({ showSearch = true }) { IconButton({ showSearch = true }) {
@ -87,7 +108,7 @@ private fun ShareListToolbar(chatModel: ChatModel, stopped: Boolean, onSearchVal
} }
DefaultTopAppBar( DefaultTopAppBar(
navigationButton = { if (showSearch) NavigationButtonBack(hideSearchOnBack) else NavigationButtonBack { chatModel.sharedContent.value = null } }, navigationButton = navButton,
title = { title = {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text( Text(

View file

@ -34,7 +34,15 @@ import kotlinx.coroutines.launch
import kotlin.math.roundToInt import kotlin.math.roundToInt
@Composable @Composable
fun UserPicker(chatModel: ChatModel, userPickerState: MutableStateFlow<AnimatedViewState>, switchingUsers: MutableState<Boolean>, openSettings: () -> Unit) { fun UserPicker(
chatModel: ChatModel,
userPickerState: MutableStateFlow<AnimatedViewState>,
switchingUsers: MutableState<Boolean>,
showSettings: Boolean = true,
showCancel: Boolean = false,
cancelClicked: () -> Unit = {},
settingsClicked: () -> Unit = {},
) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
var newChat by remember { mutableStateOf(userPickerState.value) } var newChat by remember { mutableStateOf(userPickerState.value) }
val users by remember { val users by remember {
@ -101,12 +109,12 @@ fun UserPicker(chatModel: ChatModel, userPickerState: MutableStateFlow<AnimatedV
.width(IntrinsicSize.Min) .width(IntrinsicSize.Min)
.height(IntrinsicSize.Min) .height(IntrinsicSize.Min)
.shadow(8.dp, MaterialTheme.shapes.medium, clip = false) .shadow(8.dp, MaterialTheme.shapes.medium, clip = false)
.background(MaterialTheme.colors.background, MaterialTheme.shapes.medium) .background(if (isInDarkTheme()) MaterialTheme.colors.background.darker(-0.7f) else MaterialTheme.colors.background, MaterialTheme.shapes.medium)
) { ) {
Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) { Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
users.forEach { u -> users.forEach { u ->
UserProfilePickerItem(u.user, u.unreadCount, openSettings = { UserProfilePickerItem(u.user, u.unreadCount, openSettings = {
openSettings() settingsClicked()
userPickerState.value = AnimatedViewState.GONE userPickerState.value = AnimatedViewState.GONE
}) { }) {
userPickerState.value = AnimatedViewState.HIDING userPickerState.value = AnimatedViewState.HIDING
@ -126,9 +134,17 @@ fun UserPicker(chatModel: ChatModel, userPickerState: MutableStateFlow<AnimatedV
if (u.user.activeUser) Divider(Modifier.requiredHeight(0.5.dp)) if (u.user.activeUser) Divider(Modifier.requiredHeight(0.5.dp))
} }
} }
SettingsPickerItem { if (showSettings) {
openSettings() SettingsPickerItem {
userPickerState.value = AnimatedViewState.GONE settingsClicked()
userPickerState.value = AnimatedViewState.GONE
}
}
if (showCancel) {
CancelPickerItem {
cancelClicked()
userPickerState.value = AnimatedViewState.GONE
}
} }
} }
} }
@ -211,3 +227,15 @@ private fun SettingsPickerItem(onClick: () -> Unit) {
Icon(Icons.Outlined.Settings, text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Icon(Icons.Outlined.Settings, text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
} }
} }
@Composable
private fun CancelPickerItem(onClick: () -> Unit) {
SectionItemViewSpaceBetween(onClick, minHeight = 68.dp) {
val text = generalGetString(R.string.cancel_verb)
Text(
text,
color = MaterialTheme.colors.onBackground,
)
Icon(Icons.Outlined.Close, text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
}
}

View file

@ -216,12 +216,12 @@ private fun UserView(
}) })
} }
if (user.showNtfs) { if (user.showNtfs) {
ItemAction(stringResource(R.string.user_mute), Icons.Outlined.Notifications, onClick = { ItemAction(stringResource(R.string.user_mute), Icons.Outlined.NotificationsOff, onClick = {
showDropdownMenu = false showDropdownMenu = false
muteUser(user) muteUser(user)
}) })
} else { } else {
ItemAction(stringResource(R.string.user_unmute), Icons.Outlined.NotificationsOff, onClick = { ItemAction(stringResource(R.string.user_unmute), Icons.Outlined.Notifications, onClick = {
showDropdownMenu = false showDropdownMenu = false
unmuteUser(user) unmuteUser(user)
}) })

View file

@ -71,7 +71,7 @@ struct ChatListView: View {
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarLeading) { ToolbarItem(placement: .navigationBarLeading) {
Button { Button {
if chatModel.users.count > 1 { if chatModel.users.filter { u in u.user.activeUser || !u.user.hidden }.count > 1 {
withAnimation { withAnimation {
userPickerVisible.toggle() userPickerVisible.toggle()
} }