From ff17f8955155e4078c53911729484b713b487a16 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sun, 4 Dec 2022 15:16:41 +0000 Subject: [PATCH] android: improve UX to create groups and UI of group preferences (#1496) --- .../chat/simplex/app/views/chat/ChatView.kt | 2 +- .../views/chat/group/AddGroupMembersView.kt | 42 +++++++++++++++++-- .../app/views/chat/group/GroupChatInfoView.kt | 2 +- .../app/views/chat/group/GroupPreferences.kt | 13 +++++- .../chat/simplex/app/views/helpers/Section.kt | 8 +++- .../simplex/app/views/newchat/AddGroupView.kt | 2 +- .../app/src/main/res/values-de/strings.xml | 7 +++- .../app/src/main/res/values-ru/strings.xml | 3 ++ .../app/src/main/res/values/strings.xml | 3 ++ 9 files changed, 69 insertions(+), 13 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt index 2277a6c71b..0c8d8ec749 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -210,7 +210,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: () -> Unit) { withApi { setGroupMembers(groupInfo, chatModel) ModalManager.shared.showModalCloseable(true) { close -> - AddGroupMembersView(groupInfo, chatModel, close) + AddGroupMembersView(groupInfo, false, chatModel, close) } } }, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt index 502e43b7bd..2d216dd728 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt @@ -31,17 +31,23 @@ import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.SettingsActionItem @Composable -fun AddGroupMembersView(groupInfo: GroupInfo, chatModel: ChatModel, close: () -> Unit) { +fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, chatModel: ChatModel, close: () -> Unit) { val selectedContacts = remember { mutableStateListOf() } val selectedRole = remember { mutableStateOf(GroupMemberRole.Member) } var allowModifyMembers by remember { mutableStateOf(true) } BackHandler(onBack = close) AddGroupMembersLayout( groupInfo = groupInfo, + creatingGroup = creatingGroup, contactsToAdd = getContactsToAdd(chatModel), selectedContacts = selectedContacts, selectedRole = selectedRole, allowModifyMembers = allowModifyMembers, + openPreferences = { + ModalManager.shared.showModal(true) { + GroupPreferencesView(chatModel, groupInfo.id) + } + }, inviteMembers = { allowModifyMembers = false withApi { @@ -59,6 +65,7 @@ fun AddGroupMembersView(groupInfo: GroupInfo, chatModel: ChatModel, close: () -> clearSelection = { selectedContacts.clear() }, addContact = { contactId -> if (contactId !in selectedContacts) selectedContacts.add(contactId) }, removeContact = { contactId -> selectedContacts.removeIf { it == contactId } }, + close = close, ) } @@ -79,14 +86,17 @@ fun getContactsToAdd(chatModel: ChatModel): List { @Composable fun AddGroupMembersLayout( groupInfo: GroupInfo, + creatingGroup: Boolean, contactsToAdd: List, selectedContacts: List, selectedRole: MutableState, allowModifyMembers: Boolean, + openPreferences: () -> Unit, inviteMembers: () -> Unit, clearSelection: () -> Unit, addContact: (Long) -> Unit, removeContact: (Long) -> Unit, + close: () -> Unit, ) { Column( Modifier @@ -120,18 +130,28 @@ fun AddGroupMembersLayout( } } else { SectionView { + if (creatingGroup) { + SectionItemView(openPreferences) { + Text(stringResource(R.string.set_group_preferences)) + } + SectionDivider() + } SectionItemView { RoleSelectionRow(groupInfo, selectedRole, allowModifyMembers) } SectionDivider() - InviteMembersButton(inviteMembers, disabled = selectedContacts.isEmpty() || !allowModifyMembers) + if (creatingGroup && selectedContacts.isEmpty()) { + SkipInvitingButton(close) + } else { + InviteMembersButton(inviteMembers, disabled = selectedContacts.isEmpty() || !allowModifyMembers) + } } SectionCustomFooter { InviteSectionFooter(selectedContactsCount = selectedContacts.size, allowModifyMembers, clearSelection) } SectionSpacer() - SectionView { + SectionView(stringResource(R.string.select_contacts)) { ContactList(contacts = contactsToAdd, selectedContacts, groupInfo, allowModifyMembers, addContact, removeContact) } SectionSpacer() @@ -170,6 +190,17 @@ fun InviteMembersButton(onClick: () -> Unit, disabled: Boolean) { ) } +@Composable +fun SkipInvitingButton(onClick: () -> Unit) { + SettingsActionItem( + Icons.Outlined.Check, + stringResource(R.string.skip_inviting_button), + click = onClick, + textColor = MaterialTheme.colors.primary, + iconColor = MaterialTheme.colors.primary, + ) +} + @Composable fun InviteSectionFooter(selectedContactsCount: Int, enabled: Boolean, clearSelection: () -> Unit) { Row( @@ -288,14 +319,17 @@ fun PreviewAddGroupMembersLayout() { SimpleXTheme { AddGroupMembersLayout( groupInfo = GroupInfo.sampleData, + creatingGroup = false, contactsToAdd = listOf(Contact.sampleData, Contact.sampleData, Contact.sampleData), selectedContacts = remember { mutableStateListOf() }, selectedRole = remember { mutableStateOf(GroupMemberRole.Admin) }, allowModifyMembers = true, + openPreferences = {}, inviteMembers = {}, clearSelection = {}, addContact = {}, - removeContact = {} + removeContact = {}, + close = {}, ) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt index 58ddb8a6ee..144dafc272 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt @@ -49,7 +49,7 @@ fun GroupChatInfoView(chatModel: ChatModel, close: () -> Unit) { withApi { setGroupMembers(groupInfo, chatModel) ModalManager.shared.showModalCloseable(true) { close -> - AddGroupMembersView(groupInfo, chatModel, close) + AddGroupMembersView(groupInfo, false, chatModel, close) } } }, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt index 68a0db0211..e015de1ba6 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt @@ -13,10 +13,12 @@ import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.HighOrLowlight +import chat.simplex.app.ui.theme.SimplexGreen import chat.simplex.app.views.helpers.* @Composable @@ -66,6 +68,7 @@ private fun GroupPreferencesLayout( FeatureSection(GroupFeature.DirectMessages, allowDirectMessages, groupInfo) { applyPrefs(preferences.copy(directMessages = GroupPreference(enable = it))) } + SectionSpacer() val allowFullDeletion = remember(preferences) { mutableStateOf(preferences.fullDelete.enable) } FeatureSection(GroupFeature.FullDelete, allowFullDeletion, groupInfo) { applyPrefs(preferences.copy(fullDelete = GroupPreference(enable = it))) @@ -89,20 +92,26 @@ private fun GroupPreferencesLayout( @Composable private fun FeatureSection(feature: GroupFeature, enableFeature: State, groupInfo: GroupInfo, onSelected: (GroupFeatureEnabled) -> Unit) { SectionView { + val on = enableFeature.value == GroupFeatureEnabled.ON + val icon = if (on) feature.iconFilled else feature.icon + val iconTint = if (on) SimplexGreen else HighOrLowlight if (groupInfo.canEdit) { SectionItemView { ExposedDropDownSettingRow( feature.text, GroupFeatureEnabled.values().map { it to it.text }, enableFeature, - icon = feature.icon, + icon = icon, + iconTint = iconTint, onSelected = onSelected ) } } else { InfoRow( feature.text, - enableFeature.value.text + enableFeature.value.text, + icon = icon, + iconTint = iconTint, ) } } 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 752bab6dc5..57b439e8bf 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 @@ -186,9 +186,13 @@ fun SectionSpacer() { } @Composable -fun InfoRow(title: String, value: String) { +fun InfoRow(title: String, value: String, icon: ImageVector? = null, iconTint: Color? = null) { SectionItemViewSpaceBetween { - Text(title) + Row { + val iconSize = with(LocalDensity.current) { 21.sp.toDp() } + if (icon != null) Icon(icon, title, Modifier.padding(end = 8.dp).size(iconSize), tint = iconTint ?: HighOrLowlight) + Text(title) + } Text(value, color = HighOrLowlight) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt index 86f864b86c..ee93ca23f4 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt @@ -47,7 +47,7 @@ fun AddGroupView(chatModel: ChatModel, close: () -> Unit) { setGroupMembers(groupInfo, chatModel) close.invoke() ModalManager.shared.showModalCloseable(true) { close -> - AddGroupMembersView(groupInfo, chatModel, close) + AddGroupMembersView(groupInfo, true, chatModel, close) } } } diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml index f40eef8f2f..c8fa8b8516 100644 --- a/apps/android/app/src/main/res/values-de/strings.xml +++ b/apps/android/app/src/main/res/values-de/strings.xml @@ -21,7 +21,7 @@ Gelöscht - ***marked deleted + ***markiert gelöscht Das Senden von Dateien wird noch nicht unterstützt Der Empfang von Dateien wird noch nicht unterstützt Meine Daten @@ -61,7 +61,7 @@ Verbindungszeitüberschreitung Verbindungsfehler - *** Bitte überprüfen Sie Ihre Netzwerkverbindung mit %1$s und versuchen Sie es erneut. + Bitte überprüfen Sie Ihre Netzwerkverbindung mit %1$s und versuchen Sie es erneut. Fehler beim Senden der Nachricht Fehler beim Hinzufügen von Mitgliedern Fehler beim Beitritt zur Gruppe @@ -832,6 +832,8 @@ Neue Mitgliedsrolle Rollenauswahl erweitern In Gruppe einladen + ***Skip inviting members + ***Select contacts Kontakt geprüft Löschen %1$s Kontakt(e) ausgewählt @@ -952,6 +954,7 @@ Chat Präferenzen Kontakt Präferenzen Gruppen Präferenzen + ***Gruppenpräferenzen einstellen Ihre Präferenzen ***Direct messages ***Beseitigung für alle diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index 66c233de94..f0a31b831e 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -832,6 +832,8 @@ Роль члена группы Развернуть выбор роли Пригласить в группу + Не приглашать членов + Выберите контакты Контакт выбран Очистить Выбрано контактов: %1$s @@ -951,6 +953,7 @@ Предпочтения Предпочтения контакта Предпочтения группы + Предпочтения группы Ваши предпочтения Прямые сообщения Удаление для всех diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 0293d8a143..e8aeb00267 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -832,6 +832,8 @@ New member role Expand role selection Invite to group + Skip inviting members + Select contacts Contact checked Clear %1$s contact(s) selected @@ -952,6 +954,7 @@ Chat preferences Contact preferences Group preferences + Set group preferences Your preferences Direct messages Delete for everyone