mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-17 17:21:58 +00:00
refactor, fix
This commit is contained in:
@@ -160,13 +160,11 @@ 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 {
|
||||
channelSimplexNameButton()
|
||||
} header: {
|
||||
if groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupDomainClaim?.shortName != nil {
|
||||
Text("Channel SimpleX name").foregroundColor(theme.colors.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,21 +191,36 @@ struct UserAddressView: View {
|
||||
}
|
||||
}
|
||||
|
||||
if let d = chatModel.currentUser?.profile.contactDomain?.domain {
|
||||
Section {
|
||||
setSimplexNameButton {
|
||||
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,
|
||||
broadcastWarning: NSLocalizedString("Profile update will be sent to your SimpleX contacts.", comment: "alert title"),
|
||||
save: { simplexDomain in
|
||||
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")
|
||||
}
|
||||
} header: {
|
||||
Text("Your SimpleX name")
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
}
|
||||
} else {
|
||||
Section {
|
||||
setSimplexNameButton {
|
||||
} else {
|
||||
Label("Get SimpleX name (BETA)", systemImage: "at")
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
if chatModel.currentUser?.profile.contactDomain?.domain != nil {
|
||||
Text("Your SimpleX name").foregroundColor(theme.colors.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
@@ -227,47 +242,6 @@ struct UserAddressView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func setSimplexNameButton<L: View>(@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<Bool, Never>) 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) {
|
||||
@@ -751,6 +725,7 @@ struct SetSimplexDomainView: View {
|
||||
let footer: LocalizedStringKey
|
||||
let prompt: String
|
||||
@State var simplexName: String
|
||||
let broadcastWarning: String?
|
||||
let save: (String?) async -> Bool
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
@@ -760,11 +735,12 @@ struct SetSimplexDomainView: View {
|
||||
@State private var editing = false
|
||||
@FocusState private var nameFocused: Bool
|
||||
|
||||
init(title: LocalizedStringKey, footer: LocalizedStringKey, prompt: String, simplexName: String, save: @escaping (String?) async -> Bool) {
|
||||
init(title: LocalizedStringKey, footer: LocalizedStringKey, prompt: String, simplexName: String, broadcastWarning: String? = nil, save: @escaping (String?) async -> Bool) {
|
||||
self.title = title
|
||||
self.footer = footer
|
||||
self.prompt = prompt
|
||||
self._simplexName = State(initialValue: simplexName)
|
||||
self.broadcastWarning = broadcastWarning
|
||||
self.save = save
|
||||
self._original = State(initialValue: simplexName)
|
||||
self._editing = State(initialValue: simplexName.isEmpty)
|
||||
@@ -822,16 +798,13 @@ struct SetSimplexDomainView: View {
|
||||
}
|
||||
}
|
||||
Button {
|
||||
saving = true
|
||||
Task {
|
||||
let ok = await save(normalized(simplexName))
|
||||
await MainActor.run {
|
||||
saving = false
|
||||
if ok {
|
||||
didSave = true
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
if let w = broadcastWarning, changed {
|
||||
showAlert(w, actions: {[
|
||||
UIAlertAction(title: NSLocalizedString("Save", comment: "alert action"), style: .default) { _ in saveAndDismiss() },
|
||||
UIAlertAction(title: NSLocalizedString("Cancel", comment: "alert action"), style: .cancel)
|
||||
]})
|
||||
} else {
|
||||
saveAndDismiss()
|
||||
}
|
||||
} label: {
|
||||
Text("Save")
|
||||
@@ -859,6 +832,7 @@ struct SetSimplexDomainView: View {
|
||||
let saveName = save
|
||||
showAlert(
|
||||
NSLocalizedString("Save SimpleX name?", comment: "alert title"),
|
||||
message: broadcastWarning,
|
||||
actions: {[
|
||||
UIAlertAction(title: NSLocalizedString("Save", comment: "alert action"), style: .default) { _ in
|
||||
Task { _ = await saveName(domain) }
|
||||
@@ -870,6 +844,20 @@ struct SetSimplexDomainView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func saveAndDismiss() {
|
||||
saving = true
|
||||
Task {
|
||||
let ok = await save(normalized(simplexName))
|
||||
await MainActor.run {
|
||||
saving = false
|
||||
if ok {
|
||||
didSave = true
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func normalized(_ s: String) -> String? {
|
||||
let t = s.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return t.isEmpty
|
||||
@@ -893,19 +881,7 @@ struct SetSimplexDomainView: View {
|
||||
|
||||
private func isValidNameLabel(_ label: Substring) -> Bool {
|
||||
if label.isEmpty || label.utf8.count > 63 { return false }
|
||||
var prev: Unicode.Scalar? = nil
|
||||
var isFirst = true
|
||||
for u in label.unicodeScalars {
|
||||
let v = u.value
|
||||
if v == 45 {
|
||||
if isFirst || prev?.value == 45 { return false }
|
||||
} else if !((v >= 97 && v <= 122) || (v >= 65 && v <= 90) || (v >= 48 && v <= 57)) {
|
||||
return false
|
||||
}
|
||||
prev = u
|
||||
isFirst = false
|
||||
}
|
||||
return prev?.value != 45
|
||||
return label.range(of: "^[A-Za-z0-9]+(-[A-Za-z0-9]+)*$", options: .regularExpression) != nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -410,7 +410,7 @@ fun createProfileOnboarding(chatModel: ChatModel, displayName: String, close: ()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ProfileNameField(name: MutableState<String>, placeholder: String = "", isValid: (String) -> Boolean = { true }, focusRequester: FocusRequester? = null, onInvalidTap: (() -> Unit)? = null) {
|
||||
fun ProfileNameField(name: MutableState<String>, placeholder: String = "", isValid: (String) -> Boolean = { true }, focusRequester: FocusRequester? = null) {
|
||||
var valid by rememberSaveable { mutableStateOf(true) }
|
||||
var focused by rememberSaveable { mutableStateOf(false) }
|
||||
val strokeColor by remember {
|
||||
@@ -451,7 +451,7 @@ fun ProfileNameField(name: MutableState<String>, placeholder: String = "", isVal
|
||||
leadingIcon = null,
|
||||
trailingIcon = if (!valid && placeholder != "") {
|
||||
{
|
||||
IconButton((onInvalidTap ?: { showInvalidNameAlert(mkValidName(name.value), name) }), Modifier.size(20.dp)) {
|
||||
IconButton({ showInvalidNameAlert(mkValidName(name.value), name) }, Modifier.size(20.dp)) {
|
||||
Icon(painterResource(MR.images.ic_info), null, tint = MaterialTheme.colors.error)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-18
@@ -666,24 +666,13 @@ fun ModalData.GroupChatInfoLayout(
|
||||
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
|
||||
)
|
||||
}
|
||||
SectionView(title = if (channelDomain != null) generalGetString(MR.strings.channel_simplex_name) else null) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_tag),
|
||||
channelDomain ?: generalGetString(MR.strings.get_simplex_name_beta),
|
||||
setSimplexName,
|
||||
iconColor = MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
+13
-12
@@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
@@ -41,6 +40,7 @@ fun SetSimplexDomainView(
|
||||
placeholder: String,
|
||||
simplexName: String,
|
||||
registerBackgroundClose: Boolean = false,
|
||||
broadcastWarning: String? = null,
|
||||
save: suspend (String?) -> Boolean,
|
||||
close: () -> Unit
|
||||
) {
|
||||
@@ -58,8 +58,8 @@ fun SetSimplexDomainView(
|
||||
val t = s.trim()
|
||||
return when {
|
||||
t.isEmpty() -> null
|
||||
t.startsWith("@") || t.startsWith("#") -> addSimplexTLD(t.substring(1))
|
||||
else -> addSimplexTLD(t)
|
||||
t.startsWith("@") || t.startsWith("#") -> addSimplexTLD(t.substring(1).lowercase())
|
||||
else -> addSimplexTLD(t.lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ fun SetSimplexDomainView(
|
||||
}
|
||||
saving.value = false
|
||||
if (ok) withContext(Dispatchers.Main) {
|
||||
chatModel.centerPanelBackgroundClickHandler = null
|
||||
if (registerBackgroundClose) chatModel.centerPanelBackgroundClickHandler = null
|
||||
close()
|
||||
}
|
||||
}
|
||||
@@ -100,17 +100,18 @@ fun SetSimplexDomainView(
|
||||
return if (changed && valid) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.save_simplex_name_question),
|
||||
text = broadcastWarning,
|
||||
confirmText = generalGetString(MR.strings.save_verb),
|
||||
onConfirm = { doSave(close) },
|
||||
dismissText = generalGetString(MR.strings.exit_without_saving),
|
||||
onDismiss = {
|
||||
chatModel.centerPanelBackgroundClickHandler = null
|
||||
if (registerBackgroundClose) chatModel.centerPanelBackgroundClickHandler = null
|
||||
close()
|
||||
}
|
||||
)
|
||||
true
|
||||
} else {
|
||||
chatModel.centerPanelBackgroundClickHandler = null
|
||||
if (registerBackgroundClose) chatModel.centerPanelBackgroundClickHandler = null
|
||||
close()
|
||||
false
|
||||
}
|
||||
@@ -123,7 +124,7 @@ fun SetSimplexDomainView(
|
||||
}
|
||||
}
|
||||
onDispose {
|
||||
chatModel.centerPanelBackgroundClickHandler = null
|
||||
if (registerBackgroundClose) chatModel.centerPanelBackgroundClickHandler = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,11 +139,11 @@ fun SetSimplexDomainView(
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
SectionItemViewSpaceBetween(click = { focusRequester.requestFocus() }) {
|
||||
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) {
|
||||
Box(Modifier.weight(1f)) {
|
||||
PlainTextEditor(name, placeholder = placeholder, contentPadding = PaddingValues(), focusRequester = focusRequester)
|
||||
if (!isValid) {
|
||||
Icon(painterResource(MR.images.ic_error), null, tint = MaterialTheme.colors.error)
|
||||
}
|
||||
}
|
||||
if (!isValid) {
|
||||
Icon(painterResource(MR.images.ic_error), null, tint = MaterialTheme.colors.error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -164,7 +165,7 @@ fun SetSimplexDomainView(
|
||||
Text(stringResource(MR.strings.register_test_name), color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
SectionItemView({ doSave(close) }, disabled = unchanged || saving.value || !isValid) {
|
||||
SectionItemView({ if (broadcastWarning != null && !unchanged) AlertManager.shared.showAlertDialog(title = broadcastWarning, confirmText = generalGetString(MR.strings.save_verb), onConfirm = { doSave(close) }) else 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
|
||||
|
||||
+9
-24
@@ -35,9 +35,7 @@ import chat.simplex.common.views.newchat.*
|
||||
import chat.simplex.common.BuildConfigCommon
|
||||
import chat.simplex.res.MR
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
@Composable
|
||||
fun UserAddressView(
|
||||
@@ -378,29 +376,16 @@ private fun UserAddressLayout(
|
||||
placeholder = "@yourname.testing",
|
||||
simplexName = if (domain == null) "" else "@$domain",
|
||||
registerBackgroundClose = true,
|
||||
broadcastWarning = generalGetString(MR.strings.profile_update_will_be_sent_to_contacts),
|
||||
save = { simplexDomain ->
|
||||
val changed = simplexDomain != domain
|
||||
val proceed = if (changed) {
|
||||
suspendCancellableCoroutine<Boolean> { cont ->
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.profile_update_will_be_sent_to_contacts),
|
||||
confirmText = generalGetString(MR.strings.save_verb),
|
||||
onConfirm = { if (cont.isActive) cont.resume(true) },
|
||||
onDismiss = { if (cont.isActive) cont.resume(false) },
|
||||
onDismissRequest = { if (cont.isActive) cont.resume(false) },
|
||||
)
|
||||
}
|
||||
} else true
|
||||
if (proceed) {
|
||||
try {
|
||||
val u = chatModel.controller.apiSetUserDomain(user?.remoteHostId, simplexDomain)
|
||||
withContext(Dispatchers.Main) { chatModel.updateUser(u) }
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "apiSetUserDomain: ${e.message}")
|
||||
false
|
||||
}
|
||||
} else false
|
||||
try {
|
||||
val u = chatModel.controller.apiSetUserDomain(user?.remoteHostId, simplexDomain)
|
||||
withContext(Dispatchers.Main) { chatModel.updateUser(u) }
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "apiSetUserDomain: ${e.message}")
|
||||
false
|
||||
}
|
||||
},
|
||||
close = close
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user