mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-19 09:27:30 +00:00
refactor
This commit is contained in:
@@ -393,26 +393,7 @@ struct ChatInfoView: View {
|
||||
.lineLimit(3)
|
||||
.padding(.bottom, 2)
|
||||
}
|
||||
if let domain = contact.profile.contactDomain,
|
||||
contact.profile.contactDomainVerified != nil || domain.proof != nil {
|
||||
SimplexNameView(
|
||||
simplexName: "@\(domain.domain)",
|
||||
verified: contact.profile.contactDomainVerified,
|
||||
verify: {
|
||||
do {
|
||||
let (ct, reason) = try await apiVerifyContactDomain(contact.contactId)
|
||||
await MainActor.run {
|
||||
chatModel.updateContact(ct)
|
||||
contact = ct
|
||||
}
|
||||
return (ct.profile.contactDomainVerified, reason)
|
||||
} catch {
|
||||
logger.error("apiVerifyContactDomain: \(responseError(error))")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
contactSimplexNameView(contact) { contact = $0 }
|
||||
if let descr = cInfo.shortDescr?.trimmingCharacters(in: .whitespacesAndNewlines), descr != "" {
|
||||
let r = markdownText(descr, textStyle: .subheadline, showSecrets: showSecrets, backgroundColor: theme.colors.background)
|
||||
msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets, centered: true, smallFont: true)
|
||||
@@ -1374,19 +1355,80 @@ private func deleteNotReadyContact(
|
||||
))
|
||||
}
|
||||
|
||||
@ViewBuilder func contactSimplexNameView(_ contact: Contact, verifiable: Bool = true, onUpdate: ((Contact) -> Void)? = nil) -> some View {
|
||||
if let domain = contact.profile.contactDomain,
|
||||
contact.profile.contactDomainVerified != nil || domain.proof != nil {
|
||||
SimplexNameView(
|
||||
simplexName: "@\(domain.domain)",
|
||||
verified: contact.profile.contactDomainVerified,
|
||||
verify: {
|
||||
do {
|
||||
let (ct, reason) = try await apiVerifyContactDomain(contact.contactId)
|
||||
await MainActor.run {
|
||||
ChatModel.shared.updateContact(ct)
|
||||
onUpdate?(ct)
|
||||
}
|
||||
return (ct.profile.contactDomainVerified, reason)
|
||||
} catch {
|
||||
logger.error("apiVerifyContactDomain: \(responseError(error))")
|
||||
return nil
|
||||
}
|
||||
},
|
||||
verifiable: verifiable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder func groupSimplexNameView(_ groupInfo: GroupInfo, verifiable: Bool = true, onUpdate: ((GroupInfo) -> Void)? = nil) -> some View {
|
||||
if groupInfo.businessChat == nil {
|
||||
if let access = groupInfo.groupProfile.publicGroup?.publicGroupAccess,
|
||||
let domain = access.groupDomainClaim?.shortName,
|
||||
groupInfo.groupDomainVerified != nil || access.groupDomainClaim?.proof != nil {
|
||||
SimplexNameView(
|
||||
simplexName: "#\(domain)",
|
||||
verified: groupInfo.groupDomainVerified,
|
||||
verify: {
|
||||
do {
|
||||
let (gInfo, reason) = try await apiVerifyGroupDomain(groupInfo.groupId)
|
||||
await MainActor.run {
|
||||
ChatModel.shared.updateGroup(gInfo)
|
||||
onUpdate?(gInfo)
|
||||
}
|
||||
return (gInfo.groupDomainVerified, reason)
|
||||
} catch {
|
||||
logger.error("apiVerifyGroupDomain: \(responseError(error))")
|
||||
return nil
|
||||
}
|
||||
},
|
||||
verifiable: verifiable
|
||||
)
|
||||
}
|
||||
} else if let claim = groupInfo.businessChat?.businessDomain,
|
||||
groupInfo.groupDomainVerified != nil || claim.proof != nil {
|
||||
// A business presents as a contact, so the name retains its .simplex suffix; it cannot be re-verified.
|
||||
SimplexNameView(
|
||||
simplexName: "@\(claim.domain)",
|
||||
verified: groupInfo.groupDomainVerified,
|
||||
verify: { nil },
|
||||
verifiable: false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct SimplexNameView: View {
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
@AppStorage(DEFAULT_PRIVACY_VERIFY_SIMPLEX_NAMES) var autoVerify = false
|
||||
let simplexName: String
|
||||
let verified: Bool?
|
||||
let verify: () async -> (Bool?, String?)?
|
||||
var verifiable: Bool = true
|
||||
@State private var inFlight = false
|
||||
@State private var showSpinner = false
|
||||
|
||||
var body: some View {
|
||||
content
|
||||
.padding(.bottom, 2)
|
||||
.onAppear { if autoVerify && verified == nil { runVerify(manual: false) } }
|
||||
.onAppear { if verifiable && autoVerify && verified == nil { runVerify(manual: false) } }
|
||||
}
|
||||
|
||||
private var nameText: Text {
|
||||
@@ -1415,6 +1457,8 @@ struct SimplexNameView: View {
|
||||
UIPasteboard.general.string = simplexName
|
||||
UIImpactFeedbackGenerator(style: .rigid).impactOccurred()
|
||||
}
|
||||
} else if !verifiable {
|
||||
nameText
|
||||
} else if verified == false {
|
||||
HStack(alignment: .firstTextBaseline, spacing: 4) {
|
||||
nameText
|
||||
|
||||
@@ -1039,57 +1039,9 @@ struct ChatView: View {
|
||||
|
||||
switch chat.chatInfo {
|
||||
case let .direct(contact):
|
||||
if let domain = contact.profile.contactDomain,
|
||||
contact.profile.contactDomainVerified != nil || domain.proof != nil {
|
||||
SimplexNameView(
|
||||
simplexName: "@\(domain.domain)",
|
||||
verified: contact.profile.contactDomainVerified,
|
||||
verify: {
|
||||
do {
|
||||
let (ct, reason) = try await apiVerifyContactDomain(contact.contactId)
|
||||
await MainActor.run {
|
||||
ChatModel.shared.updateContact(ct)
|
||||
}
|
||||
return (ct.profile.contactDomainVerified, reason)
|
||||
} catch {
|
||||
logger.error("apiVerifyContactDomain: \(responseError(error))")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
contactSimplexNameView(contact, verifiable: false)
|
||||
case let .group(groupInfo, _):
|
||||
if groupInfo.businessChat == nil {
|
||||
if let access = groupInfo.groupProfile.publicGroup?.publicGroupAccess,
|
||||
let domain = access.groupDomainClaim?.shortName,
|
||||
groupInfo.groupDomainVerified != nil || access.groupDomainClaim?.proof != nil {
|
||||
SimplexNameView(
|
||||
simplexName: "#\(domain)",
|
||||
verified: groupInfo.groupDomainVerified,
|
||||
verify: {
|
||||
do {
|
||||
let (gInfo, reason) = try await apiVerifyGroupDomain(groupInfo.groupId)
|
||||
await MainActor.run {
|
||||
ChatModel.shared.updateGroup(gInfo)
|
||||
}
|
||||
return (gInfo.groupDomainVerified, reason)
|
||||
} catch {
|
||||
logger.error("apiVerifyGroupDomain: \(responseError(error))")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if let claim = groupInfo.businessChat?.businessDomain,
|
||||
groupInfo.groupDomainVerified != nil || claim.proof != nil {
|
||||
SimplexNameView(
|
||||
simplexName: "@\(claim.domain)",
|
||||
verified: groupInfo.groupDomainVerified,
|
||||
verify: { nil }
|
||||
)
|
||||
}
|
||||
}
|
||||
groupSimplexNameView(groupInfo, verifiable: false)
|
||||
default:
|
||||
EmptyView()
|
||||
}
|
||||
|
||||
@@ -341,38 +341,7 @@ struct GroupChatInfoView: View {
|
||||
.lineLimit(4)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
if let access = groupInfo.groupProfile.publicGroup?.publicGroupAccess,
|
||||
let domain = access.groupDomainClaim?.shortName,
|
||||
groupInfo.groupDomainVerified != nil || access.groupDomainClaim?.proof != nil {
|
||||
SimplexNameView(
|
||||
simplexName: "#\(domain)",
|
||||
verified: groupInfo.groupDomainVerified,
|
||||
verify: {
|
||||
do {
|
||||
let (gInfo, reason) = try await apiVerifyGroupDomain(groupInfo.groupId)
|
||||
await MainActor.run {
|
||||
chatModel.updateGroup(gInfo)
|
||||
groupInfo = gInfo
|
||||
}
|
||||
return (gInfo.groupDomainVerified, reason)
|
||||
} catch {
|
||||
logger.error("apiVerifyGroupDomain: \(responseError(error))")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
if let claim = groupInfo.businessChat?.businessDomain,
|
||||
groupInfo.groupDomainVerified != nil || claim.proof != nil {
|
||||
// A business presents as a contact, so the name retains its .simplex suffix. The tick comes from
|
||||
// groupDomainVerified (set at connect); its domain proof is not received on the wire yet, so
|
||||
// re-verification is not wired.
|
||||
SimplexNameView(
|
||||
simplexName: "@\(claim.domain)",
|
||||
verified: groupInfo.groupDomainVerified,
|
||||
verify: { nil }
|
||||
)
|
||||
}
|
||||
groupSimplexNameView(groupInfo) { groupInfo = $0 }
|
||||
if let webPage = groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupWebPage,
|
||||
let url = URL(string: webPage) {
|
||||
Link(destination: url) {
|
||||
|
||||
+1
-14
@@ -757,20 +757,7 @@ fun ChatInfoHeader(cInfo: ChatInfo, contact: Contact) {
|
||||
modifier = Modifier.combinedClickable(onClick = copyDisplayName, onLongClick = copyDisplayName).onRightClick(copyDisplayName)
|
||||
)
|
||||
ChatInfoDescription(cInfo, displayName, copyNameToClipboard)
|
||||
val domain = contact.profile.contactDomain
|
||||
if (domain != null && (contact.profile.contactDomainVerified != null || domain.proof != null)) {
|
||||
SimplexNameView(
|
||||
simplexName = "@${domain.domain}",
|
||||
verified = contact.profile.contactDomainVerified,
|
||||
verify = {
|
||||
val rhId = chatModel.remoteHostId()
|
||||
chatModel.controller.apiVerifyContactDomain(rhId, contact.contactId)?.let { (ct, reason) ->
|
||||
chatModel.chatsContext.updateContact(rhId, ct)
|
||||
ct.profile.contactDomainVerified to reason
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
ContactSimplexNameView(contact)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-49
@@ -2344,55 +2344,8 @@ fun BoxScope.ChatItemsList(
|
||||
}
|
||||
|
||||
when (chatInfo) {
|
||||
is ChatInfo.Direct -> {
|
||||
val contact = chatInfo.contact
|
||||
val domain = contact.profile.contactDomain
|
||||
if (domain != null && (contact.profile.contactDomainVerified != null || domain.proof != null)) {
|
||||
SimplexNameView(
|
||||
simplexName = "@${domain.domain}",
|
||||
verified = contact.profile.contactDomainVerified,
|
||||
verify = {
|
||||
val rhId = chatModel.remoteHostId()
|
||||
chatModel.controller.apiVerifyContactDomain(rhId, contact.contactId)?.let { (ct, reason) ->
|
||||
chatModel.chatsContext.updateContact(rhId, ct)
|
||||
ct.profile.contactDomainVerified to reason
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
is ChatInfo.Group -> {
|
||||
val groupInfo = chatInfo.groupInfo
|
||||
if (groupInfo.businessChat == null) {
|
||||
val access = groupInfo.groupProfile.publicGroup?.publicGroupAccess
|
||||
val domain = access?.groupDomainClaim?.shortName
|
||||
if (domain != null && (groupInfo.groupDomainVerified != null || access.groupDomainClaim?.proof != null)) {
|
||||
SimplexNameView(
|
||||
simplexName = "#${domain}",
|
||||
verified = groupInfo.groupDomainVerified,
|
||||
verify = {
|
||||
val rhId = chatModel.remoteHostId()
|
||||
chatModel.controller.apiVerifyGroupDomain(rhId, groupInfo.groupId)?.let { (gInfo, reason) ->
|
||||
chatModel.chatsContext.updateGroup(rhId, gInfo)
|
||||
gInfo.groupDomainVerified to reason
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val businessClaim = groupInfo.businessChat?.businessDomain
|
||||
if (businessClaim != null && (groupInfo.groupDomainVerified != null || businessClaim.proof != null)) {
|
||||
// A business presents as a contact, so the name retains its .simplex suffix. The tick comes from
|
||||
// groupDomainVerified (set at connect); its domain proof is not received on the wire yet, so
|
||||
// re-verification is not wired.
|
||||
SimplexNameView(
|
||||
simplexName = "@${businessClaim.domain}",
|
||||
verified = groupInfo.groupDomainVerified,
|
||||
verify = { null }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is ChatInfo.Direct -> ContactSimplexNameView(chatInfo.contact, verifiable = false)
|
||||
is ChatInfo.Group -> GroupSimplexNameView(chatInfo.groupInfo, verifiable = false)
|
||||
else -> {}
|
||||
}
|
||||
|
||||
|
||||
+56
-2
@@ -11,7 +11,7 @@ import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.text.*
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.icerock.moko.resources.ImageResource
|
||||
import chat.simplex.common.model.SimplexNameInfo
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF
|
||||
import chat.simplex.common.views.helpers.*
|
||||
@@ -28,6 +28,7 @@ import kotlinx.coroutines.*
|
||||
fun SimplexNameView(
|
||||
simplexName: String,
|
||||
verified: Boolean?,
|
||||
verifiable: Boolean = true,
|
||||
verify: suspend () -> Pair<Boolean?, String?>?
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -60,7 +61,7 @@ fun SimplexNameView(
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (chatModel.controller.appPrefs.privacyVerifySimplexNames.get() && verified == null) runVerify(manual = false)
|
||||
if (verifiable && chatModel.controller.appPrefs.privacyVerifySimplexNames.get() && verified == null) runVerify(manual = false)
|
||||
}
|
||||
|
||||
val clipboard = LocalClipboardManager.current
|
||||
@@ -82,6 +83,7 @@ fun SimplexNameView(
|
||||
clipboard.setText(AnnotatedString(simplexName))
|
||||
showToast(generalGetString(MR.strings.copied))
|
||||
}
|
||||
!verifiable -> Text(simplexName, style = nameStyle)
|
||||
verified == false ->
|
||||
SimplexNameWithIcon(simplexName, nameStyle, MR.images.ic_close, Color.Red) { runVerify(manual = true) }
|
||||
else -> {
|
||||
@@ -113,3 +115,55 @@ private fun SimplexNameWithIcon(name: String, style: TextStyle, icon: ImageResou
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContactSimplexNameView(contact: Contact, verifiable: Boolean = true) {
|
||||
val domain = contact.profile.contactDomain
|
||||
if (domain != null && (contact.profile.contactDomainVerified != null || domain.proof != null)) {
|
||||
SimplexNameView(
|
||||
simplexName = "@${domain.domain}",
|
||||
verified = contact.profile.contactDomainVerified,
|
||||
verifiable = verifiable,
|
||||
verify = {
|
||||
val rhId = chatModel.remoteHostId()
|
||||
chatModel.controller.apiVerifyContactDomain(rhId, contact.contactId)?.let { (ct, reason) ->
|
||||
chatModel.chatsContext.updateContact(rhId, ct)
|
||||
ct.profile.contactDomainVerified to reason
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GroupSimplexNameView(groupInfo: GroupInfo, verifiable: Boolean = true) {
|
||||
if (groupInfo.businessChat == null) {
|
||||
val access = groupInfo.groupProfile.publicGroup?.publicGroupAccess
|
||||
val domain = access?.groupDomainClaim?.shortName
|
||||
if (domain != null && (groupInfo.groupDomainVerified != null || access.groupDomainClaim?.proof != null)) {
|
||||
SimplexNameView(
|
||||
simplexName = "#${domain}",
|
||||
verified = groupInfo.groupDomainVerified,
|
||||
verifiable = verifiable,
|
||||
verify = {
|
||||
val rhId = chatModel.remoteHostId()
|
||||
chatModel.controller.apiVerifyGroupDomain(rhId, groupInfo.groupId)?.let { (gInfo, reason) ->
|
||||
chatModel.chatsContext.updateGroup(rhId, gInfo)
|
||||
gInfo.groupDomainVerified to reason
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val businessClaim = groupInfo.businessChat?.businessDomain
|
||||
if (businessClaim != null && (groupInfo.groupDomainVerified != null || businessClaim.proof != null)) {
|
||||
// A business presents as a contact, so the name retains its .simplex suffix; it cannot be re-verified.
|
||||
SimplexNameView(
|
||||
simplexName = "@${businessClaim.domain}",
|
||||
verified = groupInfo.groupDomainVerified,
|
||||
verifiable = false,
|
||||
verify = { null }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-26
@@ -979,32 +979,7 @@ private fun GroupChatInfoHeader(cInfo: ChatInfo, groupInfo: GroupInfo) {
|
||||
modifier = Modifier.combinedClickable(onClick = copyDisplayName, onLongClick = copyDisplayName).onRightClick(copyDisplayName)
|
||||
)
|
||||
ChatInfoDescription(cInfo, displayName, copyNameToClipboard)
|
||||
val access = groupInfo.groupProfile.publicGroup?.publicGroupAccess
|
||||
val domain = access?.groupDomainClaim?.shortName
|
||||
if (domain != null && (groupInfo.groupDomainVerified != null || access.groupDomainClaim?.proof != null)) {
|
||||
SimplexNameView(
|
||||
simplexName = "#${domain}",
|
||||
verified = groupInfo.groupDomainVerified,
|
||||
verify = {
|
||||
val rhId = chatModel.remoteHostId()
|
||||
chatModel.controller.apiVerifyGroupDomain(rhId, groupInfo.groupId)?.let { (gInfo, reason) ->
|
||||
chatModel.chatsContext.updateGroup(rhId, gInfo)
|
||||
gInfo.groupDomainVerified to reason
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
val businessClaim = groupInfo.businessChat?.businessDomain
|
||||
if (businessClaim != null && (groupInfo.groupDomainVerified != null || businessClaim.proof != null)) {
|
||||
// A business presents as a contact, so the name retains its .simplex suffix. The tick comes from
|
||||
// groupDomainVerified (set at connect); its domain proof is not received on the wire yet, so
|
||||
// re-verification is not wired.
|
||||
SimplexNameView(
|
||||
simplexName = "@${businessClaim.domain}",
|
||||
verified = groupInfo.groupDomainVerified,
|
||||
verify = { null }
|
||||
)
|
||||
}
|
||||
GroupSimplexNameView(groupInfo)
|
||||
val webPage = groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupWebPage
|
||||
if (webPage != null) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Reference in New Issue
Block a user