mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-27 22:34:51 +00:00
ios: reliably show API alerts (use UIKit) (#7195)
* ios: reliably show API alerts (use UIKit) * fix infinite recursion
This commit is contained in:
@@ -569,7 +569,7 @@ private func processSendMessageCmd(toChatType: ChatType, cmd: ChatCommand) async
|
||||
return cItems
|
||||
}
|
||||
if let networkErrorAlert = networkErrorAlert(r) {
|
||||
AlertManager.shared.showAlert(networkErrorAlert)
|
||||
await MainActor.run { showAlert(networkErrorAlert) }
|
||||
} else {
|
||||
sendMessageErrorAlert(r.unexpected)
|
||||
}
|
||||
@@ -1003,15 +1003,15 @@ func apiVerifyGroupMember(_ groupId: Int64, _ groupMemberId: Int64, connectionCo
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiAddContact(incognito: Bool) async -> ((CreatedConnLink, PendingContactConnection)?, Alert?) {
|
||||
func apiAddContact(incognito: Bool) async -> (CreatedConnLink, PendingContactConnection)? {
|
||||
guard let userId = ChatModel.shared.currentUser?.userId else {
|
||||
logger.error("apiAddContact: no current user")
|
||||
return (nil, nil)
|
||||
return nil
|
||||
}
|
||||
let r: APIResult<ChatResponse1>? = await chatApiSendCmdWithRetry(.apiAddContact(userId: userId, incognito: incognito), bgTask: false)
|
||||
if case let .result(.invitation(_, connLinkInv, connection)) = r { return ((connLinkInv, connection), nil) }
|
||||
let alert: Alert? = if let r { connectionErrorAlert(r) } else { nil }
|
||||
return (nil, alert)
|
||||
if case let .result(.invitation(_, connLinkInv, connection)) = r { return (connLinkInv, connection) }
|
||||
if let r { await MainActor.run { showAlert(connectionErrorAlert(r)) } }
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiSetConnectionIncognito(connId: Int64, incognito: Bool) async throws -> PendingContactConnection? {
|
||||
@@ -1026,130 +1026,124 @@ func apiChangeConnectionUser(connId: Int64, userId: Int64) async throws -> Pendi
|
||||
if let r { throw r.unexpected } else { return nil }
|
||||
}
|
||||
|
||||
func apiConnectPlan(connLink: String, linkOwnerSig: LinkOwnerSig? = nil, inProgress: BoxedValue<Bool>) async -> ((CreatedConnLink, ConnectionPlan)?, Alert?) {
|
||||
func apiConnectPlan(connLink: String, linkOwnerSig: LinkOwnerSig? = nil, inProgress: BoxedValue<Bool>) async -> (CreatedConnLink, ConnectionPlan)? {
|
||||
guard let userId = ChatModel.shared.currentUser?.userId else {
|
||||
logger.error("apiConnectPlan: no current user")
|
||||
return (nil, nil)
|
||||
return nil
|
||||
}
|
||||
let r: APIResult<ChatResponse1>? = await chatApiSendCmdWithRetry(.apiConnectPlan(userId: userId, connLink: connLink, linkOwnerSig: linkOwnerSig), inProgress: inProgress)
|
||||
if case let .result(.connectionPlan(_, connLink, connPlan)) = r { return ((connLink, connPlan), nil) }
|
||||
let alert: Alert? = if let r { apiConnectResponseAlert(r) } else { nil }
|
||||
return (nil, alert)
|
||||
if case let .result(.connectionPlan(_, connLink, connPlan)) = r { return (connLink, connPlan) }
|
||||
if let r { await apiConnectResponseAlert(r) }
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiConnect(incognito: Bool, connLink: CreatedConnLink) async -> (ConnReqType, PendingContactConnection)? {
|
||||
let (r, alert) = await apiConnect_(incognito: incognito, connLink: connLink)
|
||||
if let alert = alert {
|
||||
AlertManager.shared.showAlert(alert)
|
||||
return nil
|
||||
} else {
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
func apiConnect_(incognito: Bool, connLink: CreatedConnLink) async -> ((ConnReqType, PendingContactConnection)?, Alert?) {
|
||||
guard let userId = ChatModel.shared.currentUser?.userId else {
|
||||
logger.error("apiConnect: no current user")
|
||||
return (nil, nil)
|
||||
return nil
|
||||
}
|
||||
let r: APIResult<ChatResponse1>? = await chatApiSendCmdWithRetry(.apiConnect(userId: userId, incognito: incognito, connLink: connLink))
|
||||
let m = ChatModel.shared
|
||||
switch r {
|
||||
case let .result(.sentConfirmation(_, connection)):
|
||||
return ((.invitation, connection), nil)
|
||||
return (.invitation, connection)
|
||||
case let .result(.sentInvitation(_, connection)):
|
||||
return ((.contact, connection), nil)
|
||||
return (.contact, connection)
|
||||
case let .result(.contactAlreadyExists(_, contact)):
|
||||
if let c = m.getContactChat(contact.contactId) {
|
||||
ItemsModel.shared.loadOpenChat(c.id)
|
||||
}
|
||||
let alert = contactAlreadyExistsAlert(contact)
|
||||
return (nil, alert)
|
||||
await contactAlreadyExistsAlert(contact)
|
||||
return nil
|
||||
default: ()
|
||||
}
|
||||
let alert: Alert? = if let r { apiConnectResponseAlert(r) } else { nil }
|
||||
return (nil, alert)
|
||||
if let r { await apiConnectResponseAlert(r) }
|
||||
return nil
|
||||
}
|
||||
|
||||
private func apiConnectResponseAlert<R>(_ r: APIResult<R>) -> Alert {
|
||||
switch r.unexpected {
|
||||
case .error(.invalidConnReq):
|
||||
mkAlert(
|
||||
title: "Invalid connection link",
|
||||
message: "Please check that you used the correct link or ask your contact to send you another one."
|
||||
)
|
||||
case .error(.unsupportedConnReq):
|
||||
mkAlert(
|
||||
title: "Unsupported connection link",
|
||||
message: "This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link."
|
||||
)
|
||||
case let .error(.simplexDomainNotReady(domain, err)):
|
||||
switch err {
|
||||
case .noValidLink:
|
||||
mkAlert(
|
||||
title: "No valid link",
|
||||
message: "The SimpleX name \(domain.fullDomainName) is registered, but it has no valid link."
|
||||
private func apiConnectResponseAlert<R>(_ r: APIResult<R>) async {
|
||||
await MainActor.run {
|
||||
switch r.unexpected {
|
||||
case .error(.invalidConnReq):
|
||||
showAlert(
|
||||
NSLocalizedString("Invalid connection link", comment: ""),
|
||||
message: NSLocalizedString("Please check that you used the correct link or ask your contact to send you another one.", comment: "")
|
||||
)
|
||||
case .unknownDomain:
|
||||
mkAlert(
|
||||
title: "Unconfirmed name",
|
||||
message: "The SimpleX name \(domain.fullDomainName) is registered, but not added to profile. Please add it to your address or channel profile, if you are the owner."
|
||||
case .error(.unsupportedConnReq):
|
||||
showAlert(
|
||||
NSLocalizedString("Unsupported connection link", comment: ""),
|
||||
message: NSLocalizedString("This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link.", comment: "")
|
||||
)
|
||||
}
|
||||
case .errorAgent(.NO_NAME_SERVERS):
|
||||
mkAlert(
|
||||
title: "SimpleX name error",
|
||||
message: "None of your servers are set to resolve SimpleX names. Configure servers, or use a connection link."
|
||||
)
|
||||
case .errorAgent(.SMP(_, .AUTH)):
|
||||
mkAlert(
|
||||
title: "Connection error (AUTH)",
|
||||
message: "Unless your contact deleted the connection or this link was already used, it might be a bug - please report it.\nTo connect, please ask your contact to create another connection link and check that you have a stable network connection."
|
||||
)
|
||||
case let .errorAgent(.SMP(_, .BLOCKED(info))):
|
||||
Alert(
|
||||
title: Text("Connection blocked"),
|
||||
message: Text("Connection is blocked by server operator:\n\(info.reason.text)"),
|
||||
primaryButton: .default(Text("Ok")),
|
||||
secondaryButton: .default(Text("How it works")) {
|
||||
DispatchQueue.main.async {
|
||||
UIApplication.shared.open(contentModerationPostLink)
|
||||
}
|
||||
case let .error(.simplexDomainNotReady(domain, err)):
|
||||
switch err {
|
||||
case .noValidLink:
|
||||
showAlert(
|
||||
NSLocalizedString("No valid link", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("The SimpleX name %@ is registered, but it has no valid link.", comment: ""), domain.fullDomainName)
|
||||
)
|
||||
case .unknownDomain:
|
||||
showAlert(
|
||||
NSLocalizedString("Unconfirmed name", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("The SimpleX name %@ is registered, but not added to profile. Please add it to your address or channel profile, if you are the owner.", comment: ""), domain.fullDomainName)
|
||||
)
|
||||
}
|
||||
)
|
||||
case .errorAgent(.SMP(_, .QUOTA)):
|
||||
mkAlert(
|
||||
title: "Undelivered messages",
|
||||
message: "The connection reached the limit of undelivered messages, your contact may be offline."
|
||||
)
|
||||
case let .errorAgent(.INTERNAL(internalErr)):
|
||||
if internalErr == "SEUniqueID" {
|
||||
mkAlert(
|
||||
title: "Already connected?",
|
||||
message: "It seems like you are already connected via this link. If it is not the case, there was an error (\(internalErr))."
|
||||
case .errorAgent(.NO_NAME_SERVERS):
|
||||
showAlert(
|
||||
NSLocalizedString("SimpleX name error", comment: ""),
|
||||
message: NSLocalizedString("None of your servers are set to resolve SimpleX names. Configure servers, or use a connection link.", comment: "")
|
||||
)
|
||||
} else {
|
||||
connectionErrorAlert(r)
|
||||
case .errorAgent(.SMP(_, .AUTH)):
|
||||
showAlert(
|
||||
NSLocalizedString("Connection error (AUTH)", comment: ""),
|
||||
message: NSLocalizedString("Unless your contact deleted the connection or this link was already used, it might be a bug - please report it.\nTo connect, please ask your contact to create another connection link and check that you have a stable network connection.", comment: "")
|
||||
)
|
||||
case let .errorAgent(.SMP(_, .BLOCKED(info))):
|
||||
showAlert(
|
||||
NSLocalizedString("Connection blocked", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Connection is blocked by server operator:\n%@", comment: ""), info.reason.text),
|
||||
actions: {[
|
||||
okAlertAction,
|
||||
UIAlertAction(title: NSLocalizedString("How it works", comment: ""), style: .default) { _ in
|
||||
DispatchQueue.main.async {
|
||||
UIApplication.shared.open(contentModerationPostLink)
|
||||
}
|
||||
}
|
||||
]}
|
||||
)
|
||||
case .errorAgent(.SMP(_, .QUOTA)):
|
||||
showAlert(
|
||||
NSLocalizedString("Undelivered messages", comment: ""),
|
||||
message: NSLocalizedString("The connection reached the limit of undelivered messages, your contact may be offline.", comment: "")
|
||||
)
|
||||
case let .errorAgent(.INTERNAL(internalErr)):
|
||||
if internalErr == "SEUniqueID" {
|
||||
showAlert(
|
||||
NSLocalizedString("Already connected?", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("It seems like you are already connected via this link. If it is not the case, there was an error (%@).", comment: ""), internalErr)
|
||||
)
|
||||
} else {
|
||||
showAlert(connectionErrorAlert(r))
|
||||
}
|
||||
case let .errorAgent(.SMP(serverAddress, .NAME(nameErr))):
|
||||
switch nameErr {
|
||||
case .NOT_FOUND:
|
||||
showAlert(
|
||||
NSLocalizedString("Name not found", comment: ""),
|
||||
message: NSLocalizedString("This SimpleX name is not registered. Please check the name.", comment: "")
|
||||
)
|
||||
case .NO_RESOLVER:
|
||||
showAlert(
|
||||
NSLocalizedString("SimpleX name error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Server %@ does not support name resolution. Configure servers, or use a connection link.", comment: ""), serverAddress)
|
||||
)
|
||||
case let .RESOLVER(resolverErr):
|
||||
showAlert(
|
||||
NSLocalizedString("SimpleX name error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Resolver error: %@", comment: ""), resolverErr)
|
||||
)
|
||||
}
|
||||
default: showAlert(connectionErrorAlert(r))
|
||||
}
|
||||
case let .errorAgent(.SMP(serverAddress, .NAME(nameErr))):
|
||||
switch nameErr {
|
||||
case .NOT_FOUND:
|
||||
mkAlert(
|
||||
title: "Name not found",
|
||||
message: "This SimpleX name is not registered. Please check the name."
|
||||
)
|
||||
case .NO_RESOLVER:
|
||||
mkAlert(
|
||||
title: "SimpleX name error",
|
||||
message: "Server \(serverAddress) does not support name resolution. Configure servers, or use a connection link."
|
||||
)
|
||||
case let .RESOLVER(resolverErr):
|
||||
mkAlert(
|
||||
title: "SimpleX name error",
|
||||
message: "Resolver error: \(resolverErr)"
|
||||
)
|
||||
}
|
||||
default: connectionErrorAlert(r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,36 +1156,34 @@ func connErrorText(_ e: ChatError) -> String {
|
||||
case .errorAgent(.SMP(_, .AUTH)):
|
||||
NSLocalizedString("Connection error (AUTH)", comment: "conn error description")
|
||||
case let .errorAgent(.SMP(_, .BLOCKED(info))):
|
||||
NSLocalizedString("Connection blocked: \(info.reason.text)", comment: "conn error description")
|
||||
String.localizedStringWithFormat(NSLocalizedString("Connection blocked: %@", comment: "conn error description"), info.reason.text)
|
||||
case .errorAgent(.SMP(_, .QUOTA)):
|
||||
NSLocalizedString("The connection reached the limit of undelivered messages", comment: "conn error description")
|
||||
default:
|
||||
if getNetworkErrorAlert(e) != nil {
|
||||
NSLocalizedString("Network error", comment: "conn error description")
|
||||
} else {
|
||||
"\(NSLocalizedString("Error", comment: "conn error description")): \(responseError(e))"
|
||||
String.localizedStringWithFormat(NSLocalizedString("Error: %@", comment: "conn error description"), responseError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func contactAlreadyExistsAlert(_ contact: Contact) -> Alert {
|
||||
mkAlert(
|
||||
title: "Contact already exists",
|
||||
message: "You are already connected to \(contact.displayName)."
|
||||
)
|
||||
}
|
||||
|
||||
private func connectionErrorAlert<R>(_ r: APIResult<R>) -> Alert {
|
||||
if let networkErrorAlert = networkErrorAlert(r) {
|
||||
return networkErrorAlert
|
||||
} else {
|
||||
return mkAlert(
|
||||
title: "Connection error",
|
||||
message: "Error: \(responseError(r.unexpected))"
|
||||
func contactAlreadyExistsAlert(_ contact: Contact) async {
|
||||
await MainActor.run {
|
||||
showAlert(
|
||||
NSLocalizedString("Contact already exists", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("You are already connected to %@.", comment: ""), contact.displayName)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func connectionErrorAlert<R>(_ r: APIResult<R>) -> (title: String, message: String?) {
|
||||
networkErrorAlert(r) ?? (
|
||||
title: NSLocalizedString("Connection error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Error: %@", comment: ""), responseError(r.unexpected))
|
||||
)
|
||||
}
|
||||
|
||||
func apiPrepareContact(connLink: CreatedConnLink, contactShortLinkData: ContactShortLinkData, verifiedDomain: SimplexDomain? = nil) async throws -> ChatData {
|
||||
let userId = try currentUserId("apiPrepareContact")
|
||||
let r: ChatResponse1 = try await chatSendCmd(.apiPrepareContact(userId: userId, connLink: connLink, contactShortLinkData: contactShortLinkData, verifiedDomain: verifiedDomain))
|
||||
@@ -1221,30 +1213,29 @@ func apiChangePreparedGroupUser(groupId: Int64, newUserId: Int64) async throws -
|
||||
func apiConnectPreparedContact(contactId: Int64, incognito: Bool, msg: MsgContent?) async -> Contact? {
|
||||
let r: APIResult<ChatResponse1>? = await chatApiSendCmdWithRetry(.apiConnectPreparedContact(contactId: contactId, incognito: incognito, msg: msg))
|
||||
if case let .result(.startedConnectionToContact(_, contact)) = r { return contact }
|
||||
if let r { AlertManager.shared.showAlert(apiConnectResponseAlert(r)) }
|
||||
if let r { await apiConnectResponseAlert(r) }
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiConnectPreparedGroup(groupId: Int64, incognito: Bool, msg: MsgContent?) async -> (GroupInfo, [RelayConnectionResult])? {
|
||||
let r: APIResult<ChatResponse1>? = await chatApiSendCmdWithRetry(.apiConnectPreparedGroup(groupId: groupId, incognito: incognito, msg: msg))
|
||||
if case let .result(.startedConnectionToGroup(_, groupInfo, relayResults)) = r { return (groupInfo, relayResults) }
|
||||
if let r { AlertManager.shared.showAlert(apiConnectResponseAlert(r)) }
|
||||
if let r { await apiConnectResponseAlert(r) }
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiConnectContactViaAddress(incognito: Bool, contactId: Int64) async -> (Contact?, Alert?) {
|
||||
func apiConnectContactViaAddress(incognito: Bool, contactId: Int64) async -> Contact? {
|
||||
guard let userId = ChatModel.shared.currentUser?.userId else {
|
||||
logger.error("apiConnectContactViaAddress: no current user")
|
||||
return (nil, nil)
|
||||
return nil
|
||||
}
|
||||
let r: APIResult<ChatResponse1>? = await chatApiSendCmdWithRetry(.apiConnectContactViaAddress(userId: userId, incognito: incognito, contactId: contactId))
|
||||
if case let .result(.sentInvitationToContact(_, contact, _)) = r { return (contact, nil) }
|
||||
if case let .result(.sentInvitationToContact(_, contact, _)) = r { return contact }
|
||||
if let r {
|
||||
logger.error("apiConnectContactViaAddress error: \(responseError(r.unexpected))")
|
||||
return (nil, connectionErrorAlert(r))
|
||||
} else {
|
||||
return (nil, nil)
|
||||
await MainActor.run { showAlert(connectionErrorAlert(r)) }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiDeleteChat(type: ChatType, id: Int64, chatDeleteMode: ChatDeleteMode = .full(notify: true)) async throws {
|
||||
@@ -1365,16 +1356,16 @@ func apiSetProfileAddress(on: Bool) async throws -> User? {
|
||||
}
|
||||
}
|
||||
|
||||
// name is the encoded SimplexName (e.g. "@alice.simplex"); nil clears it
|
||||
// owner-specific SNENoValidLink wording; everything else reuses the general apiConnectResponseAlert
|
||||
func showSetSimplexNameError<R>(_ r: APIResult<R>, isChannel: Bool) {
|
||||
func showSetSimplexNameError<R>(_ r: APIResult<R>, isChannel: Bool) async {
|
||||
if case let .error(.simplexDomainNotReady(domain, .noValidLink)) = r.unexpected {
|
||||
let format = isChannel
|
||||
? NSLocalizedString("The SimpleX name #%@ is registered without channel link. Add channel link to the name via the registration page.", comment: "alert message")
|
||||
: NSLocalizedString("The SimpleX name @%@ is registered without SimpleX address. Add your SimpleX address to the name via the registration page.", comment: "alert message")
|
||||
showAlert(NSLocalizedString("Error saving name", comment: "alert title"), message: String.localizedStringWithFormat(format, domain.fullDomainName))
|
||||
await MainActor.run {
|
||||
showAlert(NSLocalizedString("Error saving name", comment: "alert title"), message: String.localizedStringWithFormat(format, domain.fullDomainName))
|
||||
}
|
||||
} else {
|
||||
AlertManager.shared.showAlert(apiConnectResponseAlert(r))
|
||||
await apiConnectResponseAlert(r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1385,7 +1376,7 @@ func apiSetUserDomain(_ simplexDomain: String?) async throws -> User {
|
||||
case let .result(.userProfileUpdated(user, _, _, _)): return user
|
||||
case let .result(.userProfileNoChange(user)): return user
|
||||
default:
|
||||
showSetSimplexNameError(r, isChannel: false)
|
||||
await showSetSimplexNameError(r, isChannel: false)
|
||||
throw r.unexpected
|
||||
}
|
||||
}
|
||||
@@ -1502,23 +1493,22 @@ func apiSetUserAddressSettings(_ settings: AddressSettings) async throws -> User
|
||||
|
||||
func apiAcceptContactRequest(incognito: Bool, contactReqId: Int64) async -> Contact? {
|
||||
let r: APIResult<ChatResponse1>? = await chatApiSendCmdWithRetry(.apiAcceptContact(incognito: incognito, contactReqId: contactReqId))
|
||||
let am = AlertManager.shared
|
||||
|
||||
if case let .result(.acceptingContactRequest(_, contact)) = r { return contact }
|
||||
if case .error(.errorAgent(.SMP(_, .AUTH))) = r {
|
||||
am.showAlertMsg(
|
||||
title: "Connection error (AUTH)",
|
||||
message: "Sender may have deleted the connection request."
|
||||
)
|
||||
await MainActor.run { showAlert(
|
||||
NSLocalizedString("Connection error (AUTH)", comment: ""),
|
||||
message: NSLocalizedString("Sender may have deleted the connection request.", comment: "")
|
||||
) }
|
||||
} else if let r {
|
||||
if let networkErrorAlert = networkErrorAlert(r) {
|
||||
am.showAlert(networkErrorAlert)
|
||||
await MainActor.run { showAlert(networkErrorAlert) }
|
||||
} else {
|
||||
logger.error("apiAcceptContactRequest error: \(String(describing: r))")
|
||||
am.showAlertMsg(
|
||||
title: "Error accepting contact request",
|
||||
message: "Error: \(responseError(r.unexpected))"
|
||||
)
|
||||
await MainActor.run { showAlert(
|
||||
NSLocalizedString("Error accepting contact request", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Error: %@", comment: ""), responseError(r.unexpected))
|
||||
) }
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -1762,11 +1752,11 @@ func deleteRemoteCtrl(_ rcId: Int64) async throws {
|
||||
try await sendCommandOkResp(.deleteRemoteCtrl(remoteCtrlId: rcId))
|
||||
}
|
||||
|
||||
func networkErrorAlert<R>(_ res: APIResult<R>) -> Alert? {
|
||||
if case let .error(e) = res, let alert = getNetworkErrorAlert(e) {
|
||||
return mkAlert(title: alert.title, message: alert.message)
|
||||
func networkErrorAlert<R>(_ res: APIResult<R>) -> (title: String, message: String?)? {
|
||||
if case let .error(e) = res {
|
||||
getNetworkErrorAlert(e)
|
||||
} else {
|
||||
return nil
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2071,7 +2061,7 @@ func apiUpdateGroup(_ groupId: Int64, _ groupProfile: GroupProfile) async throws
|
||||
func apiSetPublicGroupAccess(_ groupId: Int64, access: PublicGroupAccess) async throws -> GroupInfo {
|
||||
let r: APIResult<ChatResponse2> = await chatApiSendCmd(.apiSetPublicGroupAccess(groupId: groupId, access: access))
|
||||
if case let .result(.groupUpdated(_, toGroup)) = r { return toGroup }
|
||||
showSetSimplexNameError(r, isChannel: true)
|
||||
await showSetSimplexNameError(r, isChannel: true)
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
@@ -2129,7 +2119,7 @@ func apiSendMemberContactInvitation(_ contactId: Int64, _ msg: MsgContent) async
|
||||
func apiAcceptMemberContact(contactId: Int64) async -> Contact? {
|
||||
let r: APIResult<ChatResponse2>? = await chatApiSendCmdWithRetry(.apiAcceptMemberContact(contactId: contactId))
|
||||
if case let .result(.memberContactAccepted(_, contact)) = r { return contact }
|
||||
if let r { AlertManager.shared.showAlert(apiConnectResponseAlert(r)) }
|
||||
if let r { await apiConnectResponseAlert(r) }
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -283,8 +283,9 @@ struct ChatInfoView: View {
|
||||
}
|
||||
} catch let e {
|
||||
logger.error("apiContactQueueInfo error: \(responseError(e))")
|
||||
let a = getErrorAlert(e, "Error")
|
||||
await MainActor.run { alert = .error(title: a.title, error: a.message) }
|
||||
await MainActor.run {
|
||||
showErrorAlert(e, NSLocalizedString("Error", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,7 +335,7 @@ struct ChatInfoView: View {
|
||||
case .syncConnectionForceAlert:
|
||||
return syncConnectionForceAlert({
|
||||
Task {
|
||||
if let stats = await syncContactConnection(contact, force: true, showAlert: { alert = .someAlert(alert: $0) }) {
|
||||
if let stats = await syncContactConnection(contact, force: true) {
|
||||
connectionStats = stats
|
||||
dismiss()
|
||||
}
|
||||
@@ -541,7 +542,7 @@ struct ChatInfoView: View {
|
||||
private func synchronizeConnectionButton() -> some View {
|
||||
Button {
|
||||
Task {
|
||||
if let stats = await syncContactConnection(contact, force: false, showAlert: { alert = .someAlert(alert: $0) }) {
|
||||
if let stats = await syncContactConnection(contact, force: false) {
|
||||
connectionStats = stats
|
||||
dismiss()
|
||||
}
|
||||
@@ -618,9 +619,8 @@ struct ChatInfoView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("switchContactAddress apiSwitchContact error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error changing address")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error changing address", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -636,9 +636,8 @@ struct ChatInfoView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("abortSwitchContactAddress apiAbortSwitchContact error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error aborting address change")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error aborting address change", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -748,7 +747,7 @@ struct ChatTTLOption: View {
|
||||
}
|
||||
}
|
||||
|
||||
func syncContactConnection(_ contact: Contact, force: Bool, showAlert: (SomeAlert) -> Void) async -> ConnectionStats? {
|
||||
func syncContactConnection(_ contact: Contact, force: Bool) async -> ConnectionStats? {
|
||||
do {
|
||||
let stats = try apiSyncContactRatchet(contact.apiId, force)
|
||||
await MainActor.run {
|
||||
@@ -757,14 +756,8 @@ func syncContactConnection(_ contact: Contact, force: Bool, showAlert: (SomeAler
|
||||
return stats
|
||||
} catch let error {
|
||||
logger.error("syncContactConnection apiSyncContactRatchet error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error synchronizing connection")
|
||||
await MainActor.run {
|
||||
showAlert(
|
||||
SomeAlert(
|
||||
alert: mkAlert(title: a.title, message: a.message),
|
||||
id: "syncContactConnection error"
|
||||
)
|
||||
)
|
||||
showErrorAlert(error, NSLocalizedString("Error synchronizing connection", comment: ""))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -844,7 +837,7 @@ private struct CallButton: View {
|
||||
message: Text("Connection requires encryption renegotiation."),
|
||||
primaryButton: .default(Text("Fix")) {
|
||||
Task {
|
||||
if let stats = await syncContactConnection(contact, force: false, showAlert: showAlert) {
|
||||
if let stats = await syncContactConnection(contact, force: false) {
|
||||
connectionStats = stats
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,9 +185,8 @@ struct CIRcvDecryptionError: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("syncMemberConnection apiSyncGroupMemberRatchet error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error synchronizing connection")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error synchronizing connection", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,9 +201,8 @@ struct CIRcvDecryptionError: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("syncContactConnection apiSyncContactRatchet error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error synchronizing connection")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error synchronizing connection", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,8 +174,9 @@ struct AddGroupMembersViewCommon: View {
|
||||
}
|
||||
addedMembersCb(selectedContacts)
|
||||
} catch {
|
||||
let a = getErrorAlert(error, "Error adding member(s)")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error adding member(s)", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +155,9 @@ struct GroupLinkView: View {
|
||||
do {
|
||||
groupLink = try await apiGroupLinkMemberRole(groupId, memberRole: groupLinkMemberRole)
|
||||
} catch let error {
|
||||
let a = getErrorAlert(error, "Error updating group link")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error updating group link", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,8 +189,7 @@ struct GroupLinkView: View {
|
||||
logger.error("GroupLinkView apiCreateGroupLink: \(responseError(error))")
|
||||
await MainActor.run {
|
||||
creatingLink = false
|
||||
let a = getErrorAlert(error, "Error creating group link")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error creating group link", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,8 +230,7 @@ struct GroupLinkView: View {
|
||||
logger.error("apiAddGroupShortLink: \(responseError(error))")
|
||||
await MainActor.run {
|
||||
creatingLink = false
|
||||
let a = getErrorAlert(error, "Error adding short link")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error adding short link", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +278,9 @@ struct GroupMemberInfoView: View {
|
||||
}
|
||||
} catch let e {
|
||||
logger.error("apiContactQueueInfo error: \(responseError(e))")
|
||||
let a = getErrorAlert(e, "Error")
|
||||
await MainActor.run { alert = .error(title: a.title, error: a.message) }
|
||||
await MainActor.run {
|
||||
showErrorAlert(e, NSLocalizedString("Error", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -473,10 +474,9 @@ struct GroupMemberInfoView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("createMemberContactButton apiCreateMemberContact error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error creating member contact")
|
||||
await MainActor.run {
|
||||
progressIndicator = false
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error creating member contact", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -752,8 +752,9 @@ struct GroupMemberInfoView: View {
|
||||
} catch let error {
|
||||
newRole = mem.memberRole
|
||||
logger.error("apiMembersRole error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error changing role")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error changing role", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -774,9 +775,8 @@ struct GroupMemberInfoView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("switchMemberAddress apiSwitchGroupMember error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error changing address")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error changing address", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -792,9 +792,8 @@ struct GroupMemberInfoView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("abortSwitchMemberAddress apiAbortSwitchGroupMember error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error aborting address change")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error aborting address change", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -811,9 +810,8 @@ struct GroupMemberInfoView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("syncMemberConnection apiSyncGroupMemberRatchet error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error synchronizing connection")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error synchronizing connection", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,9 +532,7 @@ struct ChatListNavLink: View {
|
||||
.frameCompat(height: dynamicRowHeight)
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
Button {
|
||||
AlertManager.shared.showAlert(deleteContactConnectionAlert(contactConnection) { a in
|
||||
AlertManager.shared.showAlertMsg(title: a.title, message: a.message)
|
||||
})
|
||||
AlertManager.shared.showAlert(deleteContactConnectionAlert(contactConnection))
|
||||
} label: {
|
||||
deleteLabel
|
||||
}
|
||||
@@ -698,7 +696,7 @@ func rejectContactRequestAlert(_ contactRequestId: Int64) -> Alert {
|
||||
)
|
||||
}
|
||||
|
||||
func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection, showError: @escaping (ErrorAlert) -> Void, success: @escaping () -> Void = {}) -> Alert {
|
||||
func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection, success: @escaping () -> Void = {}) -> Alert {
|
||||
Alert(
|
||||
title: Text("Delete pending connection?"),
|
||||
message: Text(contactConnection.displayName + "\n\n")
|
||||
@@ -715,7 +713,7 @@ func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection,
|
||||
}
|
||||
} catch let error {
|
||||
await MainActor.run {
|
||||
showError(getErrorAlert(error, "Error deleting connection"))
|
||||
showErrorAlert(error, NSLocalizedString("Error deleting connection", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,11 +723,7 @@ func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection,
|
||||
}
|
||||
|
||||
func connectContactViaAddress(_ contactId: Int64, _ incognito: Bool, showAlert: (Alert) -> Void) async -> Bool {
|
||||
let (contact, alert) = await apiConnectContactViaAddress(incognito: incognito, contactId: contactId)
|
||||
if let alert = alert {
|
||||
showAlert(alert)
|
||||
return false
|
||||
} else if let contact = contact {
|
||||
if let contact = await apiConnectContactViaAddress(incognito: incognito, contactId: contactId) {
|
||||
await MainActor.run {
|
||||
ChatModel.shared.updateContact(contact)
|
||||
}
|
||||
@@ -757,8 +751,9 @@ func joinGroup(_ groupId: Int64, _ onComplete: @escaping () async -> Void) {
|
||||
await onComplete()
|
||||
} catch let error {
|
||||
await onComplete()
|
||||
let a = getErrorAlert(error, "Error joining group")
|
||||
AlertManager.shared.showAlertMsg(title: a.title, message: a.message)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error joining group", comment: ""))
|
||||
}
|
||||
}
|
||||
|
||||
func deleteGroup() async {
|
||||
@@ -773,12 +768,13 @@ func joinGroup(_ groupId: Int64, _ onComplete: @escaping () async -> Void) {
|
||||
}
|
||||
}
|
||||
|
||||
func getErrorAlert(_ error: Error, _ title: LocalizedStringKey) -> ErrorAlert {
|
||||
func showErrorAlert(_ error: Error, _ title: String) {
|
||||
let err = { String.localizedStringWithFormat(NSLocalizedString("Error: %@", comment: ""), responseError(error)) }
|
||||
if let r = error as? ChatError,
|
||||
let alert = getNetworkErrorAlert(r) {
|
||||
return alert
|
||||
showAlert(alert.title, message: alert.message ?? err())
|
||||
} else {
|
||||
return ErrorAlert(title: title, message: "Error: \(responseError(error))")
|
||||
showAlert(title, message: err())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,11 +103,7 @@ struct ContactConnectionInfo: View {
|
||||
.alert(item: $alert) { _alert in
|
||||
switch _alert {
|
||||
case .deleteInvitationAlert:
|
||||
return deleteContactConnectionAlert(contactConnection) { a in
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
} success: {
|
||||
dismiss()
|
||||
}
|
||||
return deleteContactConnectionAlert(contactConnection, success: { dismiss() })
|
||||
case let .error(title, error): return mkAlert(title: title, message: error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ func showAlert(
|
||||
}
|
||||
}
|
||||
|
||||
func showAlert(_ a: (title: String, message: String?)) {
|
||||
showAlert(a.title, message: a.message)
|
||||
}
|
||||
|
||||
func showAlert(
|
||||
_ title: String,
|
||||
message: String? = nil,
|
||||
|
||||
@@ -204,8 +204,7 @@ struct NewChatView: View {
|
||||
creatingConnReq = true
|
||||
Task {
|
||||
_ = try? await Task.sleep(nanoseconds: 250_000000)
|
||||
let (r, apiAlert) = await apiAddContact(incognito: incognitoGroupDefault.get())
|
||||
if let (connLink, pcc) = r {
|
||||
if let (connLink, pcc) = await apiAddContact(incognito: incognitoGroupDefault.get()) {
|
||||
await MainActor.run {
|
||||
m.updateContactConnection(pcc)
|
||||
m.showingInvitation = ShowingInvitation(pcc: pcc, connChatUsed: false)
|
||||
@@ -215,9 +214,6 @@ struct NewChatView: View {
|
||||
} else {
|
||||
await MainActor.run {
|
||||
creatingConnReq = false
|
||||
if let apiAlert = apiAlert {
|
||||
alert = .newChatSomeAlert(alert: SomeAlert(alert: apiAlert, id: "createInvitation error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,15 +430,9 @@ private struct ActiveProfilePicker: View {
|
||||
profileSwitchStatus = .idle
|
||||
incognitoEnabled = !incognito
|
||||
logger.error("apiSetConnectionIncognito error: \(responseError(error))")
|
||||
let err = getErrorAlert(error, "Error changing to incognito!")
|
||||
|
||||
alert = SomeAlert(
|
||||
alert: Alert(
|
||||
title: Text(err.title),
|
||||
message: Text(err.message ?? "Error: \(responseError(error))")
|
||||
),
|
||||
id: "setConnectionIncognitoError"
|
||||
)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error changing to incognito!", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,14 +484,7 @@ private struct ActiveProfilePicker: View {
|
||||
if let currentUser = chatModel.currentUser {
|
||||
selectedProfile = currentUser
|
||||
}
|
||||
let err = getErrorAlert(error, "Error changing connection profile")
|
||||
alert = SomeAlert(
|
||||
alert: Alert(
|
||||
title: Text(err.title),
|
||||
message: Text(err.message ?? "Error: \(responseError(error))")
|
||||
),
|
||||
id: "changeConnectionUserError"
|
||||
)
|
||||
showErrorAlert(error, NSLocalizedString("Error changing connection profile", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1331,7 +1314,7 @@ func planAndConnect(
|
||||
|
||||
func connectTask(_ inProgress: BoxedValue<Bool>) {
|
||||
Task {
|
||||
let (result, alert) = await apiConnectPlan(connLink: shortOrFullLink, linkOwnerSig: linkOwnerSig, inProgress: inProgress)
|
||||
let result = await apiConnectPlan(connLink: shortOrFullLink, linkOwnerSig: linkOwnerSig, inProgress: inProgress)
|
||||
await MainActor.run {
|
||||
ConnectProgressManager.shared.stopConnectProgress()
|
||||
}
|
||||
@@ -1623,17 +1606,8 @@ func planAndConnect(
|
||||
cleanup: cleanup
|
||||
)
|
||||
}
|
||||
} else {
|
||||
await MainActor.run {
|
||||
if let alert {
|
||||
dismissAllSheets(animated: true) {
|
||||
AlertManager.shared.showAlert(alert)
|
||||
cleanup?()
|
||||
}
|
||||
} else {
|
||||
cleanup?()
|
||||
}
|
||||
}
|
||||
} else if let cleanup {
|
||||
await MainActor.run { cleanup() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,12 +86,10 @@ struct CreateSimpleXAddress: View {
|
||||
await MainActor.run { progressIndicator = false }
|
||||
} catch let error {
|
||||
logger.error("CreateSimpleXAddress create address: \(responseError(error))")
|
||||
await MainActor.run { progressIndicator = false }
|
||||
let a = getErrorAlert(error, "Error creating address")
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title: a.title,
|
||||
message: a.message
|
||||
)
|
||||
await MainActor.run {
|
||||
progressIndicator = false
|
||||
showErrorAlert(error, NSLocalizedString("Error creating address", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
@@ -156,11 +154,7 @@ struct CreateSimpleXAddress: View {
|
||||
}
|
||||
case let .failure(error):
|
||||
logger.error("CreateSimpleXAddress share via email: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error sending email")
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title: a.title,
|
||||
message: a.message
|
||||
)
|
||||
showErrorAlert(error, NSLocalizedString("Error sending email", comment: ""))
|
||||
}
|
||||
mailViewResult = nil
|
||||
}
|
||||
|
||||
@@ -180,11 +180,9 @@ struct YourNetworkView: View {
|
||||
m.notificationMode = notificationMode
|
||||
}
|
||||
} catch let error {
|
||||
let a = getErrorAlert(error, "Error enabling notifications")
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title: a.title,
|
||||
message: a.message
|
||||
)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error enabling notifications", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,8 +535,7 @@ struct ConnectDesktopView: View {
|
||||
}
|
||||
|
||||
private func errorAlert(_ error: Error) {
|
||||
let a = getErrorAlert(error, "Error")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error", comment: ""))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -316,9 +316,10 @@ struct UserAddressView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("UserAddressView apiCreateUserAddress: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error creating address")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
await MainActor.run { progressIndicator = false }
|
||||
await MainActor.run {
|
||||
progressIndicator = false
|
||||
showErrorAlert(error, NSLocalizedString("Error creating address", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,8 +391,7 @@ struct UserAddressView: View {
|
||||
case .success: ()
|
||||
case let .failure(error):
|
||||
logger.error("UserAddressView share via email: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error sending email")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
showErrorAlert(error, NSLocalizedString("Error sending email", comment: ""))
|
||||
}
|
||||
mailViewResult = nil
|
||||
}
|
||||
|
||||
@@ -319,8 +319,9 @@ struct UserProfilesView: View {
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("Error deleting user profile: \(error)")
|
||||
let a = getErrorAlert(error, "Error deleting user profile")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error deleting user profile", comment: ""))
|
||||
}
|
||||
}
|
||||
|
||||
func deleteUser() async throws {
|
||||
@@ -436,8 +437,9 @@ struct UserProfilesView: View {
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
let a = getErrorAlert(error, "Error updating user privacy")
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
await MainActor.run {
|
||||
showErrorAlert(error, NSLocalizedString("Error updating user privacy", comment: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,20 +34,16 @@ public struct ErrorAlert: Error {
|
||||
}
|
||||
|
||||
public init(_ error: any Error) {
|
||||
self = if let e = error as? ChatError {
|
||||
ErrorAlert(e)
|
||||
self = if let chatError = error as? ChatError {
|
||||
if let a = getNetworkErrorAlert(chatError) {
|
||||
ErrorAlert(title: "\(a.title)", message: a.message.map { "\($0)" })
|
||||
} else {
|
||||
ErrorAlert("\(chatErrorString(chatError))")
|
||||
}
|
||||
} else {
|
||||
ErrorAlert("\(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
public init(_ chatError: ChatError) {
|
||||
self = if let networkErrorAlert = getNetworkErrorAlert(chatError) {
|
||||
networkErrorAlert
|
||||
} else {
|
||||
ErrorAlert("\(chatErrorString(chatError))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension LocalizedStringKey: @unchecked Sendable { }
|
||||
@@ -83,18 +79,33 @@ extension View {
|
||||
}
|
||||
}
|
||||
|
||||
public func getNetworkErrorAlert(_ e: ChatError) -> ErrorAlert? {
|
||||
public func getNetworkErrorAlert(_ e: ChatError) -> (title: String, message: String?)? {
|
||||
switch e {
|
||||
case let .errorAgent(.BROKER(addr, .TIMEOUT)):
|
||||
ErrorAlert(title: "Connection timeout", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
|
||||
(
|
||||
title: NSLocalizedString("Connection timeout", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Please check your network connection with %@ and try again.", comment: ""), serverHostname(addr))
|
||||
)
|
||||
case let .errorAgent(.BROKER(addr, .NETWORK(.unknownCAError))):
|
||||
ErrorAlert(title: "Connection error", message: "Fingerprint in server address does not match certificate: \(serverHostname(addr)).")
|
||||
(
|
||||
title: NSLocalizedString("Connection error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Fingerprint in server address does not match certificate: %@.", comment: ""), serverHostname(addr))
|
||||
)
|
||||
case let .errorAgent(.BROKER(addr, .NETWORK)):
|
||||
ErrorAlert(title: "Connection error", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
|
||||
(
|
||||
title: NSLocalizedString("Connection error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Please check your network connection with %@ and try again.", comment: ""), serverHostname(addr))
|
||||
)
|
||||
case let .errorAgent(.BROKER(addr, .HOST)):
|
||||
ErrorAlert(title: "Connection error", message: "Server address is incompatible with network settings: \(serverHostname(addr)).")
|
||||
(
|
||||
title: NSLocalizedString("Connection error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Server address is incompatible with network settings: %@.", comment: ""), serverHostname(addr))
|
||||
)
|
||||
case let .errorAgent(.BROKER(addr, .TRANSPORT(.version))):
|
||||
ErrorAlert(title: "Connection error", message: "Server version is incompatible with your app: \(serverHostname(addr)).")
|
||||
(
|
||||
title: NSLocalizedString("Connection error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Server version is incompatible with your app: %@.", comment: ""), serverHostname(addr))
|
||||
)
|
||||
case let .errorAgent(.SMP(serverAddress, .PROXY(proxyErr))):
|
||||
smpProxyErrorAlert(proxyErr, serverAddress)
|
||||
case let .errorAgent(.PROXY(proxyServer, relayServer, .protocolError(.PROXY(proxyErr)))):
|
||||
@@ -103,39 +114,72 @@ public func getNetworkErrorAlert(_ e: ChatError) -> ErrorAlert? {
|
||||
}
|
||||
}
|
||||
|
||||
private func smpProxyErrorAlert(_ proxyErr: ProxyError, _ srvAddr: String) -> ErrorAlert? {
|
||||
private func smpProxyErrorAlert(_ proxyErr: ProxyError, _ srvAddr: String) -> (title: String, message: String?)? {
|
||||
switch proxyErr {
|
||||
case .BROKER(brokerErr: .TIMEOUT):
|
||||
return ErrorAlert(title: "Private routing error", message: "Error connecting to forwarding server \(serverHostname(srvAddr)). Please try later.")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Error connecting to forwarding server %@. Please try later.", comment: ""), serverHostname(srvAddr))
|
||||
)
|
||||
case .BROKER(brokerErr: .NETWORK(.unknownCAError)):
|
||||
return ErrorAlert(title: "Private routing error", message: "Fingerprint in forwarding server address does not match certificate: \(serverHostname(srvAddr)).")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Fingerprint in forwarding server address does not match certificate: %@.", comment: ""), serverHostname(srvAddr))
|
||||
)
|
||||
case .BROKER(brokerErr: .NETWORK):
|
||||
return ErrorAlert(title: "Private routing error", message: "Error connecting to forwarding server \(serverHostname(srvAddr)). Please try later.")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Error connecting to forwarding server %@. Please try later.", comment: ""), serverHostname(srvAddr))
|
||||
)
|
||||
case .BROKER(brokerErr: .HOST):
|
||||
return ErrorAlert(title: "Private routing error", message: "Forwarding server address is incompatible with network settings: \(serverHostname(srvAddr)).")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server address is incompatible with network settings: %@.", comment: ""), serverHostname(srvAddr))
|
||||
)
|
||||
case .BROKER(brokerErr: .TRANSPORT(.version)):
|
||||
return ErrorAlert(title: "Private routing error", message: "Forwarding server version is incompatible with network settings: \(serverHostname(srvAddr)).")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server version is incompatible with network settings: %@.", comment: ""), serverHostname(srvAddr))
|
||||
)
|
||||
default:
|
||||
return nil
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
private func proxyDestinationErrorAlert(_ proxyErr: ProxyError, _ proxyServer: String, _ relayServer: String) -> ErrorAlert? {
|
||||
private func proxyDestinationErrorAlert(_ proxyErr: ProxyError, _ proxyServer: String, _ relayServer: String) -> (title: String, message: String?)? {
|
||||
switch proxyErr {
|
||||
case .BROKER(brokerErr: .TIMEOUT):
|
||||
return ErrorAlert(title: "Private routing error", message: "Forwarding server \(serverHostname(proxyServer)) failed to connect to destination server \(serverHostname(relayServer)). Please try later.")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server %@ failed to connect to destination server %@. Please try later.", comment: ""), serverHostname(proxyServer), serverHostname(relayServer))
|
||||
)
|
||||
case .BROKER(brokerErr: .NETWORK(.unknownCAError)):
|
||||
return ErrorAlert(title: "Private routing error", message: "Fingerprint in destination server address does not match certificate: \(serverHostname(relayServer)).")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Fingerprint in destination server address does not match certificate: %@.", comment: ""), serverHostname(relayServer))
|
||||
)
|
||||
case .BROKER(brokerErr: .NETWORK):
|
||||
return ErrorAlert(title: "Private routing error", message: "Forwarding server \(serverHostname(proxyServer)) failed to connect to destination server \(serverHostname(relayServer)). Please try later.")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server %@ failed to connect to destination server %@. Please try later.", comment: ""), serverHostname(proxyServer), serverHostname(relayServer))
|
||||
)
|
||||
case .NO_SESSION:
|
||||
return ErrorAlert(title: "Private routing error", message: "Forwarding server \(serverHostname(proxyServer)) failed to connect to destination server \(serverHostname(relayServer)). Please try later.")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server %@ failed to connect to destination server %@. Please try later.", comment: ""), serverHostname(proxyServer), serverHostname(relayServer))
|
||||
)
|
||||
case .BROKER(brokerErr: .HOST):
|
||||
return ErrorAlert(title: "Private routing error", message: "Destination server address of \(serverHostname(relayServer)) is incompatible with forwarding server \(serverHostname(proxyServer)) settings.")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Destination server address of %@ is incompatible with forwarding server %@ settings.", comment: ""), serverHostname(relayServer), serverHostname(proxyServer))
|
||||
)
|
||||
case .BROKER(brokerErr: .TRANSPORT(.version)):
|
||||
return ErrorAlert(title: "Private routing error", message: "Destination server version of \(serverHostname(relayServer)) is incompatible with forwarding server \(serverHostname(proxyServer)).")
|
||||
(
|
||||
title: NSLocalizedString("Private routing error", comment: ""),
|
||||
message: String.localizedStringWithFormat(NSLocalizedString("Destination server version of %@ is incompatible with forwarding server %@.", comment: ""), serverHostname(relayServer), serverHostname(proxyServer))
|
||||
)
|
||||
default:
|
||||
return nil
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user