From 0b230440af33ab228b46ef12ec3cf650c4a03558 Mon Sep 17 00:00:00 2001 From: "Evgeny @ SimpleX Chat" <259188159+evgeny-simplex@users.noreply.github.com> Date: Sat, 11 Jul 2026 16:45:27 +0000 Subject: [PATCH] improve ui --- .../Views/Chat/Group/GroupChatInfoView.swift | 17 ++- .../Views/UserSettings/UserAddressView.swift | 113 ++++++++++-------- .../views/chat/group/GroupChatInfoView.kt | 30 +++-- .../views/usersettings/SetSimplexNameView.kt | 25 ++-- .../views/usersettings/UserAddressView.kt | 6 +- .../commonMain/resources/MR/base/strings.xml | 3 + 6 files changed, 118 insertions(+), 76 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift index 86307c57e2..a66ad244a3 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift @@ -112,7 +112,6 @@ struct GroupChatInfoView: View { // TODO [relays] allow other owners to manage channel link (requires protocol changes to share link ownership) if groupInfo.isOwner && groupLink != nil { channelLinkButton() - channelSimplexNameButton() } else if let link = groupInfo.groupProfile.publicGroup?.groupLink { SimpleXLinkQRCode(uri: link) Button { @@ -160,6 +159,18 @@ struct GroupChatInfoView: View { } } + if groupInfo.useRelays && groupInfo.isOwner && groupLink != nil { + if groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupDomainClaim?.shortName != nil { + Section(header: Text("Channel SimpleX name").foregroundColor(theme.colors.secondary)) { + channelSimplexNameButton() + } + } else { + Section { + channelSimplexNameButton() + } + } + } + Section { if groupInfo.isOwner && groupInfo.businessChat == nil { editGroupButton() @@ -732,9 +743,9 @@ struct GroupChatInfoView: View { ) } label: { if let d = groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupDomainClaim?.shortName { - Label("#\(d)", systemImage: "number") + Label("\(d)", systemImage: "number") } else { - Label("SimpleX name", systemImage: "number") + Label("Get SimpleX name (BETA)", systemImage: "number") } } } diff --git a/apps/ios/Shared/Views/UserSettings/UserAddressView.swift b/apps/ios/Shared/Views/UserSettings/UserAddressView.swift index ae84ae8bb9..ef38e3c092 100644 --- a/apps/ios/Shared/Views/UserSettings/UserAddressView.swift +++ b/apps/ios/Shared/Views/UserSettings/UserAddressView.swift @@ -191,47 +191,19 @@ struct UserAddressView: View { } } - Section { - NavigationLink { - let simplexName = if let d = chatModel.currentUser?.profile.contactDomain?.domain { "@\(d)" } else { "" } - SetSimplexDomainView( - title: "Your SimpleX name", - footer: "Let people connect to you via name registered with your SimpleX address.", - prompt: "@yourname.testing", - simplexName: simplexName, - save: { simplexDomain in - if simplexDomain != chatModel.currentUser?.profile.contactDomain?.domain { - let confirmed = await withCheckedContinuation { (cont: CheckedContinuation) in - DispatchQueue.main.async { - showAlert( - NSLocalizedString("Profile update will be sent to your SimpleX contacts.", comment: "alert title"), - actions: {[ - UIAlertAction(title: NSLocalizedString("Save", comment: "alert action"), style: .default) { _ in - cont.resume(returning: true) - }, - UIAlertAction(title: NSLocalizedString("Cancel", comment: "alert action"), style: .cancel) { _ in - cont.resume(returning: false) - } - ]} - ) - } - } - if !confirmed { return false } - } - do { - let u = try await apiSetUserDomain(simplexDomain) - await MainActor.run { chatModel.updateUser(u) } - return true - } catch { - return false - } - } - ) - } label: { - if let d = chatModel.currentUser?.profile.contactDomain?.domain { - Label("@\(d)", systemImage: "at") - } else { - Label("Your SimpleX name", systemImage: "at") + if let d = chatModel.currentUser?.profile.contactDomain?.domain { + Section { + setSimplexNameButton { + Label("\(d)", systemImage: "at") + } + } header: { + Text("Your SimpleX name") + .foregroundColor(theme.colors.secondary) + } + } else { + Section { + setSimplexNameButton { + Label("Get SimpleX name (BETA)", systemImage: "at") } } } @@ -255,6 +227,47 @@ struct UserAddressView: View { } } + private func setSimplexNameButton(@ViewBuilder label: () -> L) -> some View { + NavigationLink { + let simplexName = if let d = chatModel.currentUser?.profile.contactDomain?.domain { "@\(d)" } else { "" } + SetSimplexDomainView( + title: "Your SimpleX name", + footer: "Let people connect to you via name registered with your SimpleX address.", + prompt: "@yourname.testing", + simplexName: simplexName, + save: { simplexDomain in + if simplexDomain != chatModel.currentUser?.profile.contactDomain?.domain { + let confirmed = await withCheckedContinuation { (cont: CheckedContinuation) in + DispatchQueue.main.async { + showAlert( + NSLocalizedString("Profile update will be sent to your SimpleX contacts.", comment: "alert title"), + actions: {[ + UIAlertAction(title: NSLocalizedString("Save", comment: "alert action"), style: .default) { _ in + cont.resume(returning: true) + }, + UIAlertAction(title: NSLocalizedString("Cancel", comment: "alert action"), style: .cancel) { _ in + cont.resume(returning: false) + } + ]} + ) + } + } + if !confirmed { return false } + } + do { + let u = try await apiSetUserDomain(simplexDomain) + await MainActor.run { chatModel.updateUser(u) } + return true + } catch { + return false + } + } + ) + } label: { + label() + } + } + @ViewBuilder private func onboardingAddressView(_ userAddress: UserContactLink) -> some View { Section { HStack(spacing: 8) { @@ -773,6 +786,16 @@ struct SetSimplexDomainView: View { Text(footer).foregroundColor(theme.colors.secondary) } Section { + Button { + openBrowserAlert(uri: "https://github.com/simplex-chat/simplex-chat/blob/master/docs/guide/register-simplex-name.md") + } label: { + Text("Register a test name") + } + if !original.isEmpty { + Button("Remove") { + simplexName = "" + } + } Button { saving = true Task { @@ -789,14 +812,6 @@ struct SetSimplexDomainView: View { Text("Save") } .disabled(saving || !isValid || !changed) - if !original.isEmpty { - Button("Copy") { - UIPasteboard.general.string = simplexName - } - Button("Remove") { - simplexName = "" - } - } } } .navigationTitle(title) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt index 9d7c5c0ceb..3e70131bc3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt @@ -638,13 +638,6 @@ fun ModalData.GroupChatInfoLayout( if (groupInfo.isOwner && groupLink != null) { anyTopSectionRowShow = true ChannelLinkButton(manageGroupLink) - val channelDomain = groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupDomainClaim?.shortName - SettingsActionItem( - painterResource(MR.images.ic_tag), - if (channelDomain != null) "#$channelDomain" else stringResource(MR.strings.simplex_name), - setSimplexName, - iconColor = MaterialTheme.colors.secondary - ) } else if (channelLink != null) { anyTopSectionRowShow = true ChannelLinkQRCodeSection(channelLink) @@ -670,6 +663,29 @@ fun ModalData.GroupChatInfoLayout( if (!groupInfo.isOwner && channelLink != null) { SectionTextFooter(stringResource(MR.strings.you_can_share_channel_link_anybody_will_be_able_to_connect)) } + if (groupInfo.isOwner && groupLink != null) { + SectionDividerSpaced() + val channelDomain = groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupDomainClaim?.shortName + if (channelDomain != null) { + SectionView(stringResource(MR.strings.channel_simplex_name)) { + SettingsActionItem( + painterResource(MR.images.ic_tag), + channelDomain, + setSimplexName, + iconColor = MaterialTheme.colors.secondary + ) + } + } else { + SectionView { + SettingsActionItem( + painterResource(MR.images.ic_tag), + stringResource(MR.strings.get_simplex_name_beta), + setSimplexName, + iconColor = MaterialTheme.colors.secondary + ) + } + } + } } else { SectionView { if (groupInfo.canAddMembers && groupInfo.businessChat == null) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetSimplexNameView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetSimplexNameView.kt index f0294ee4d9..405faec824 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetSimplexNameView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetSimplexNameView.kt @@ -10,11 +10,11 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalClipboardManager -import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.platform.LocalUriHandler import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.* +import chat.simplex.common.views.chat.item.openBrowserAlert import chat.simplex.common.views.helpers.* import chat.simplex.res.MR import dev.icerock.moko.resources.compose.stringResource @@ -40,7 +40,7 @@ fun SetSimplexDomainView( ) { val name = rememberSaveable { mutableStateOf(simplexName) } val saving = remember { mutableStateOf(false) } - val clipboard = LocalClipboardManager.current + val uriHandler = LocalUriHandler.current fun addSimplexTLD(s: String): String { return if (s.contains(".")) s else "$s.simplex" @@ -135,23 +135,20 @@ fun SetSimplexDomainView( SectionTextFooter(footer) SectionDividerSpaced() SectionView { + SectionItemView({ openBrowserAlert("https://github.com/simplex-chat/simplex-chat/blob/master/docs/guide/register-simplex-name.md", uriHandler) }) { + Text(stringResource(MR.strings.register_test_name), color = MaterialTheme.colors.primary) + } + if (simplexName.isNotBlank()) { + SectionItemView({ name.value = "" }) { + Text(stringResource(MR.strings.remove_verb), color = MaterialTheme.colors.primary) + } + } SectionItemView({ doSave(close) }, disabled = unchanged || saving.value || !isValid) { Text( stringResource(MR.strings.save_verb), color = if (unchanged || saving.value || !isValid) MaterialTheme.colors.secondary else MaterialTheme.colors.primary ) } - if (simplexName.isNotBlank()) { - SectionItemView({ - clipboard.setText(AnnotatedString(name.value)) - showToast(generalGetString(MR.strings.copied)) - }) { - Text(stringResource(MR.strings.copy_verb), color = MaterialTheme.colors.primary) - } - SectionItemView({ name.value = "" }) { - Text(stringResource(MR.strings.remove_verb), color = MaterialTheme.colors.primary) - } - } } SectionBottomSpacer() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt index 2005ad3b81..bfe42f7078 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt @@ -365,11 +365,11 @@ private fun UserAddressLayout( } SectionDividerSpaced() - SectionView { - val domain = user?.profile?.contactDomain?.domain + val domain = user?.profile?.contactDomain?.domain + SectionView(title = if (domain != null) generalGetString(MR.strings.your_simplex_name) else null) { SettingsActionItem( painterResource(MR.images.ic_at), - if (domain != null) "@$domain" else generalGetString(MR.strings.your_simplex_name), + if (domain != null) "$domain" else generalGetString(MR.strings.get_simplex_name_beta), click = { ModalManager.start.showCustomModal { close -> SetSimplexDomainView( diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index b958938dff..1265621f4c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -395,6 +395,9 @@ Copy Remove Save SimpleX name? + Get SimpleX name (BETA) + Channel SimpleX name + Register a test name Save Edit Info