From 15ed6ea4a6baf4fafa7d0001d36d6cc21a8e68ea Mon Sep 17 00:00:00 2001 From: Avently <7953703+avently@users.noreply.github.com> Date: Thu, 26 Jan 2023 21:23:25 +0300 Subject: [PATCH 1/3] android: multiusers-profilemanager --- .../java/chat/simplex/app/MainActivity.kt | 2 +- .../java/chat/simplex/app/model/SimpleXAPI.kt | 22 +-- .../chat/simplex/app/views/WelcomeView.kt | 29 ++-- .../simplex/app/views/chatlist/UserPicker.kt | 19 ++- .../simplex/app/views/helpers/AlertManager.kt | 19 ++- .../chat/simplex/app/views/helpers/Section.kt | 4 +- .../app/views/onboarding/OnboardingView.kt | 4 +- .../app/views/usersettings/SettingsView.kt | 2 + .../views/usersettings/UserProfilesView.kt | 132 ++++++++++++++++++ .../app/src/main/res/values/strings.xml | 10 ++ 10 files changed, 207 insertions(+), 36 deletions(-) create mode 100644 apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt diff --git a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt index feff6ff573..36a5c3f396 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt @@ -393,7 +393,7 @@ fun MainPage( } } onboarding == OnboardingStage.Step1_SimpleXInfo -> SimpleXInfo(chatModel, onboarding = true) - onboarding == OnboardingStage.Step2_CreateProfile -> CreateProfile(chatModel) + onboarding == OnboardingStage.Step2_CreateProfile -> CreateProfile(chatModel) {} onboarding == OnboardingStage.Step3_SetNotificationsMode -> SetNotificationsMode(chatModel) } ModalManager.shared.showInView() diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt index 0518ac819e..857a5035e0 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt @@ -293,16 +293,20 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a suspend fun changeActiveUser(toUserId: Long) { try { - chatModel.currentUser.value = apiSetActiveUser(toUserId) - val users = listUsers() - chatModel.users.clear() - chatModel.users.addAll(users) - getUserChatData() + changeActiveUser_(toUserId) } catch (e: Exception) { Log.e(TAG, "Unable to set active user: ${e.stackTraceToString()}") } } + suspend fun changeActiveUser_(toUserId: Long) { + chatModel.currentUser.value = apiSetActiveUser(toUserId) + val users = listUsers() + chatModel.users.clear() + chatModel.users.addAll(users) + getUserChatData() + } + suspend fun getUserChatData() { chatModel.userAddress.value = apiGetUserAddress() val smpServers = getUserSMPServers() @@ -396,8 +400,8 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a throw Exception("failed to set the user as active ${r.responseType} ${r.details}") } - suspend fun apiDeleteUser(userId: Long) { - val r = sendCmd(CC.ApiDeleteUser(userId)) + suspend fun apiDeleteUser(userId: Long, delSMPQueues: Boolean) { + val r = sendCmd(CC.ApiDeleteUser(userId, delSMPQueues)) if (r is CR.CmdOk) return Log.d(TAG, "apiDeleteUser: ${r.responseType} ${r.details}") throw Exception("failed to delete the user ${r.responseType} ${r.details}") @@ -1729,7 +1733,7 @@ sealed class CC { class CreateActiveUser(val profile: Profile): CC() class ListUsers: CC() class ApiSetActiveUser(val userId: Long): CC() - class ApiDeleteUser(val userId: Long): CC() + class ApiDeleteUser(val userId: Long, val delSMPQueues: Boolean): CC() class StartChat(val expire: Boolean): CC() class ApiStopChat: CC() class SetFilesFolder(val filesFolder: String): CC() @@ -1804,7 +1808,7 @@ sealed class CC { is CreateActiveUser -> "/create user ${profile.displayName} ${profile.fullName}" is ListUsers -> "/users" is ApiSetActiveUser -> "/_user $userId" - is ApiDeleteUser -> "/_delete user $userId" + is ApiDeleteUser -> "/_delete user $userId del_smp=${onOff(delSMPQueues)}" is StartChat -> "/_start subscribe=on expire=${onOff(expire)}" is ApiStopChat -> "/_stop" is SetFilesFolder -> "/_files_folder $filesFolder" diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt index 75bf2e1fd4..a82ee0272c 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt @@ -38,7 +38,7 @@ fun isValidDisplayName(name: String) : Boolean { } @Composable -fun CreateProfilePanel(chatModel: ChatModel) { +fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) { val displayName = remember { mutableStateOf("") } val fullName = remember { mutableStateOf("") } val focusRequester = remember { FocusRequester() } @@ -72,10 +72,12 @@ fun CreateProfilePanel(chatModel: ChatModel) { ProfileNameField(fullName) Spacer(Modifier.fillMaxHeight().weight(1f)) Row { - SimpleButton( - text = stringResource(R.string.about_simplex), - icon = Icons.Outlined.ArrowBackIosNew - ) { chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo } + if (chatModel.users.isEmpty()) { + SimpleButton( + text = stringResource(R.string.about_simplex), + icon = Icons.Outlined.ArrowBackIosNew + ) { chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo } + } Spacer(Modifier.fillMaxWidth().weight(1f)) @@ -83,7 +85,7 @@ fun CreateProfilePanel(chatModel: ChatModel) { val createModifier: Modifier val createColor: Color if (enabled) { - createModifier = Modifier.clickable { createProfile(chatModel, displayName.value, fullName.value) }.padding(8.dp) + createModifier = Modifier.clickable { createProfile(chatModel, displayName.value, fullName.value, close) }.padding(8.dp) createColor = MaterialTheme.colors.primary } else { createModifier = Modifier.padding(8.dp) @@ -105,13 +107,22 @@ fun CreateProfilePanel(chatModel: ChatModel) { } } -fun createProfile(chatModel: ChatModel, displayName: String, fullName: String) { +fun createProfile(chatModel: ChatModel, displayName: String, fullName: String, close: () -> Unit) { withApi { val user = chatModel.controller.apiCreateActiveUser( Profile(displayName, fullName, null) ) - chatModel.controller.startChat(user) - chatModel.onboardingStage.value = OnboardingStage.Step3_SetNotificationsMode + chatModel.currentUser.value = user + if (chatModel.users.isEmpty()) { + chatModel.controller.startChat(user) + chatModel.onboardingStage.value = OnboardingStage.Step3_SetNotificationsMode + } else { + val users = chatModel.controller.listUsers() + chatModel.users.clear() + chatModel.users.addAll(users) + chatModel.controller.getUserChatData() + close() + } } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt index 605dc117d7..47a72f3c01 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt @@ -23,8 +23,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.* import chat.simplex.app.R import chat.simplex.app.TAG -import chat.simplex.app.model.ChatModel -import chat.simplex.app.model.UserInfo +import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import kotlinx.coroutines.delay @@ -107,7 +106,7 @@ fun UserPicker(chatModel: ChatModel, userPickerState: MutableStateFlow - UserProfilePickerItem(u) { + UserProfilePickerItem(u.user, u.unreadCount) { userPickerState.value = AnimatedViewState.HIDING if (!u.user.activeUser) { chatModel.chats.clear() @@ -137,8 +136,8 @@ fun UserPicker(chatModel: ChatModel, userPickerState: MutableStateFlow Unit) { - SectionItemViewSpaceBetween(onClick, padding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) { +fun UserProfilePickerItem(u: User, unreadCount: Int = 0, onLongClick: () -> Unit = {}, onClick: () -> Unit) { + SectionItemViewSpaceBetween(onClick, onLongClick, padding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) { Row( Modifier .widthIn(max = LocalConfiguration.current.screenWidthDp.dp * 0.7f) @@ -146,20 +145,20 @@ private fun UserProfilePickerItem(u: UserInfo, onClick: () -> Unit) { verticalAlignment = Alignment.CenterVertically ) { ProfileImage( - image = u.user.image, + image = u.image, size = 54.dp ) Text( - u.user.chatViewName, + u.chatViewName, modifier = Modifier .padding(start = 8.dp, end = 8.dp) ) } - if (u.user.activeUser) { + if (u.activeUser) { Icon(Icons.Filled.Done, null, Modifier.size(20.dp), tint = MaterialTheme.colors.primary) - } else if (u.unreadCount > 0) { + } else if (unreadCount > 0) { Text( - unreadCountStr(u.unreadCount), + unreadCountStr(unreadCount), color = MaterialTheme.colors.onPrimary, fontSize = 11.sp, modifier = Modifier diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt index 4909d3eb66..71d98d139e 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt @@ -8,11 +8,12 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.* import androidx.compose.ui.window.Dialog import chat.simplex.app.R import chat.simplex.app.TAG -import chat.simplex.app.ui.theme.DEFAULT_PADDING +import chat.simplex.app.ui.theme.* class AlertManager { var alertViews = mutableStateListOf<(@Composable () -> Unit)>() @@ -49,10 +50,20 @@ class AlertManager { ) { showAlert { Dialog(onDismissRequest = this::hideAlert) { - Column(Modifier.background(MaterialTheme.colors.background)) { - Text(title, Modifier.padding(DEFAULT_PADDING), fontSize = 18.sp) + Column(Modifier.background(MaterialTheme.colors.background, MaterialTheme.shapes.medium)) { + Text(title, + Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, top = DEFAULT_PADDING, bottom = if (text == null) DEFAULT_PADDING else DEFAULT_PADDING_HALF), + fontSize = 15.sp, + fontWeight = FontWeight.SemiBold + ) if (text != null) { - Text(text) + CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) { + Text( + text, + Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING), + fontSize = 14.sp, + ) + } } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) { buttons() diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt index 57b439e8bf..ed5f7998e0 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt @@ -1,4 +1,5 @@ import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.* @@ -99,6 +100,7 @@ fun SectionItemView( @Composable fun SectionItemViewSpaceBetween( click: (() -> Unit)? = null, + onLongClick: (() -> Unit)? = null, minHeight: Dp = 46.dp, padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING), disabled: Boolean = false, @@ -108,7 +110,7 @@ fun SectionItemViewSpaceBetween( .fillMaxWidth() .sizeIn(minHeight = minHeight) Row( - if (click == null || disabled) modifier.padding(padding) else modifier.clickable(onClick = click).padding(padding), + if (click == null || disabled) modifier.padding(padding) else modifier.combinedClickable(onClick = click, onLongClick = onLongClick).padding(padding), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt index b1a5c09d71..ada3de9dad 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt @@ -21,7 +21,7 @@ enum class OnboardingStage { } @Composable -fun CreateProfile(chatModel: ChatModel) { +fun CreateProfile(chatModel: ChatModel, close: () -> Unit) { val scope = rememberCoroutineScope() val scrollState = rememberScrollState() val keyboardState by getKeyboardState() @@ -34,7 +34,7 @@ fun CreateProfile(chatModel: ChatModel) { .background(color = MaterialTheme.colors.background) .padding(20.dp) ) { - CreateProfilePanel(chatModel) + CreateProfilePanel(chatModel, close) LaunchedEffect(Unit) { setLastVersionDefault(chatModel) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt index f2c9446187..2faf4c18f3 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt @@ -121,6 +121,8 @@ fun SettingsLayout( ProfilePreview(profile, stopped = stopped) } SectionDivider() + SettingsActionItem(Icons.Outlined.HowToReg, stringResource(R.string.your_chat_profiles), showSettingsModal { UserProfilesView(it) }, disabled = stopped) + SectionDivider() SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { showModal { IncognitoView() }() } SectionDivider() SettingsActionItem(Icons.Outlined.QrCode, stringResource(R.string.your_simplex_contact_address), showModal { CreateLinkView(it, CreateLinkTab.LONG_TERM) }, disabled = stopped) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt new file mode 100644 index 0000000000..9f1422adda --- /dev/null +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt @@ -0,0 +1,132 @@ +package chat.simplex.app.views.usersettings + +import SectionDivider +import SectionItemView +import SectionTextFooter +import SectionView +import androidx.compose.foundation.* +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import chat.simplex.app.R +import chat.simplex.app.model.* +import chat.simplex.app.ui.theme.* +import chat.simplex.app.views.chat.item.ItemAction +import chat.simplex.app.views.chatlist.UserProfilePickerItem +import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.onboarding.CreateProfile + +@Composable +fun UserProfilesView(m: ChatModel) { + val users by remember { derivedStateOf { m.users.map { it.user } } } + UserProfilesView( + users = users, + addUser = { + ModalManager.shared.showModalCloseable { close -> + CreateProfile(m, close) + } + }, + activateUser = { user -> + withBGApi { + m.controller.changeActiveUser(user.userId) + } + }, + removeUser = { user -> + AlertManager.shared.showAlertDialogButtonsColumn( + title = generalGetString(R.string.users_delete_question), + text = generalGetString(R.string.users_delete_all_chats_deleted), + buttons = { + Column { + SectionItemView({ + AlertManager.shared.hideAlert() + removeUser(m, user, users, true) + }) { + Text(stringResource(R.string.users_delete_with_connections), color = Color.Red) + } + SectionItemView({ + AlertManager.shared.hideAlert() + removeUser(m, user, users, false) + } + ) { + Text(stringResource(R.string.users_delete_data_only), color = Color.Red) + } + } + } + ) + } + ) +} + +@Composable +private fun UserProfilesView( + users: List, + addUser: () -> Unit, + activateUser: (User) -> Unit, + removeUser: (User) -> Unit, +) { + Column( + Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(bottom = DEFAULT_PADDING), + ) { + AppBarTitle(stringResource(R.string.your_chat_profiles)) + + SectionView { + for (user in users) { + UserView(user, activateUser, removeUser) + SectionDivider() + } + SectionItemView(addUser, minHeight = 68.dp) { + Icon(Icons.Outlined.Add, stringResource(R.string.users_add), tint = MaterialTheme.colors.primary) + Spacer(Modifier.padding(horizontal = 4.dp)) + Text(stringResource(R.string.users_add), color = MaterialTheme.colors.primary) + } + } + SectionTextFooter(stringResource(R.string.your_chat_profiles_stored_locally)) + } +} + +@Composable +private fun UserView(user: User, activateUser: (User) -> Unit, removeUser: (User) -> Unit) { + var showDropdownMenu by remember { mutableStateOf(false) } + UserProfilePickerItem(user, onLongClick = { showDropdownMenu = true }) { + activateUser(user) + } + Box(Modifier.padding(horizontal = 16.dp)) { + DropdownMenu( + expanded = showDropdownMenu, + onDismissRequest = { showDropdownMenu = false }, + Modifier.width(220.dp) + ) { + ItemAction(stringResource(R.string.delete_verb), Icons.Outlined.Delete, color = Color.Red, onClick = { + removeUser(user) + showDropdownMenu = false + } + ) + } + } +} + +private fun removeUser(m: ChatModel, user: User, users: List, delSMPQueues: Boolean) { + if (users.isEmpty()) return + + withBGApi { + try { + if (user.activeUser) { + val newActive = users.first { !it.activeUser } + m.controller.changeActiveUser_(newActive.userId) + } + m.controller.apiDeleteUser(user.userId, delSMPQueues) + m.users.removeAll { it.user.userId == user.userId } + } catch (e: Exception) { + AlertManager.shared.showAlertMsg(generalGetString(R.string.error_deleting_user), e.stackTraceToString()) + } + } +} diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index b00c1364e2..5e66033aac 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -96,6 +96,7 @@ Secure queue Delete queue Disconnect + Error deleting user profile Instant notifications @@ -414,6 +415,7 @@ Your settings Your SimpleX contact address + Your chat profiles Database passphrase & export About SimpleX Chat How to use it @@ -972,6 +974,14 @@ Updating settings will re-connect the client to all servers. Update + + Your chat profiles are stored locally, only on your device + Add profile + Delete chat profile? + All chats and messages will be deleted - this cannot be undone! + Profile and server connections + Local profile data only + Incognito Your random profile From 3b3db562cd21c45157fc95a3c570ce789eb11a3b Mon Sep 17 00:00:00 2001 From: Avently <7953703+avently@users.noreply.github.com> Date: Thu, 26 Jan 2023 23:14:33 +0300 Subject: [PATCH 2/3] added description --- .../chat/simplex/app/views/helpers/AlertManager.kt | 3 ++- .../app/views/usersettings/UserProfilesView.kt | 11 ++++++++++- apps/android/app/src/main/res/values/strings.xml | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt index 71d98d139e..03cabe4c83 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.* import androidx.compose.ui.window.Dialog @@ -45,7 +46,7 @@ class AlertManager { fun showAlertDialogButtonsColumn( title: String, - text: String? = null, + text: AnnotatedString? = null, buttons: @Composable () -> Unit, ) { showAlert { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt index 9f1422adda..68026b395d 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt @@ -13,6 +13,8 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.* +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.* @@ -38,9 +40,16 @@ fun UserProfilesView(m: ChatModel) { } }, removeUser = { user -> + val text = buildAnnotatedString { + append(generalGetString(R.string.users_delete_all_chats_deleted) + "\n\n" + generalGetString(R.string.users_delete_profile_for) + " ") + withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { + append(user.chatViewName) + } + append(":") + } AlertManager.shared.showAlertDialogButtonsColumn( title = generalGetString(R.string.users_delete_question), - text = generalGetString(R.string.users_delete_all_chats_deleted), + text = text, buttons = { Column { SectionItemView({ diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 5e66033aac..47a3aca422 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -979,6 +979,7 @@ Add profile Delete chat profile? All chats and messages will be deleted - this cannot be undone! + Delete chat profile for Profile and server connections Local profile data only From 451aab46dc114705d8153bc40654fad0854fb882 Mon Sep 17 00:00:00 2001 From: Avently <7953703+avently@users.noreply.github.com> Date: Thu, 26 Jan 2023 23:46:10 +0300 Subject: [PATCH 3/3] disable deleting the last user --- .../simplex/app/views/usersettings/UserProfilesView.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt index 68026b395d..94a74c2389 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt @@ -89,7 +89,7 @@ private fun UserProfilesView( SectionView { for (user in users) { - UserView(user, activateUser, removeUser) + UserView(user, users, activateUser, removeUser) SectionDivider() } SectionItemView(addUser, minHeight = 68.dp) { @@ -103,9 +103,9 @@ private fun UserProfilesView( } @Composable -private fun UserView(user: User, activateUser: (User) -> Unit, removeUser: (User) -> Unit) { +private fun UserView(user: User, users: List, activateUser: (User) -> Unit, removeUser: (User) -> Unit) { var showDropdownMenu by remember { mutableStateOf(false) } - UserProfilePickerItem(user, onLongClick = { showDropdownMenu = true }) { + UserProfilePickerItem(user, onLongClick = { if (users.size > 1) showDropdownMenu = true }) { activateUser(user) } Box(Modifier.padding(horizontal = 16.dp)) { @@ -124,7 +124,7 @@ private fun UserView(user: User, activateUser: (User) -> Unit, removeUser: (User } private fun removeUser(m: ChatModel, user: User, users: List, delSMPQueues: Boolean) { - if (users.isEmpty()) return + if (users.size < 2) return withBGApi { try {