diff --git a/apps/ios/Shared/ContentView.swift b/apps/ios/Shared/ContentView.swift index 2ad8d546f2..180af685e5 100644 --- a/apps/ios/Shared/ContentView.swift +++ b/apps/ios/Shared/ContentView.swift @@ -45,21 +45,10 @@ struct ContentView: View { @State private var showChooseLAMode = false @State private var showSetPasscode = false @State private var waitingForOrPassedAuth = true - @State private var chatListActionSheet: ChatListActionSheet? = nil @State private var chatListUserPickerSheet: UserPickerSheet? = nil private let callTopPadding: CGFloat = 40 - private enum ChatListActionSheet: Identifiable { - case planAndConnectSheet(sheet: PlanAndConnectActionSheet) - - var id: String { - switch self { - case let .planAndConnectSheet(sheet): return sheet.id - } - } - } - private var accessAuthenticated: Bool { chatModel.contentViewAccessAuthenticated || contentAccessAuthenticationExtended } @@ -181,11 +170,6 @@ struct ContentView: View { if case .onboardingComplete = step, chatModel.currentUser != nil { mainView() - .actionSheet(item: $chatListActionSheet) { sheet in - switch sheet { - case let .planAndConnectSheet(sheet): return planAndConnectActionSheet(sheet, dismiss: false) - } - } } else { OnboardingView(onboarding: step) } @@ -453,10 +437,7 @@ struct ContentView: View { let link = url.absoluteString.replacingOccurrences(of: "///\(path)", with: "/\(path)") planAndConnect( link, - showAlert: showPlanAndConnectAlert, - showActionSheet: { chatListActionSheet = .planAndConnectSheet(sheet: $0) }, - dismiss: false, - incognito: nil + dismiss: false ) } else { AlertManager.shared.showAlert(Alert(title: Text("Error: URL is invalid"))) @@ -479,10 +460,6 @@ struct ContentView: View { } } } - - private func showPlanAndConnectAlert(_ alert: PlanAndConnectAlert) { - AlertManager.shared.showAlert(planAndConnectAlert(alert, dismiss: false)) - } } final class AlertManager: ObservableObject { diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift index fa7fc7cae4..c62c25c071 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift @@ -26,7 +26,6 @@ struct GroupMemberInfoView: View { @State private var knownContactConnectionStats: ConnectionStats? = nil @State private var newRole: GroupMemberRole = .member @State private var alert: GroupMemberInfoViewAlert? - @State private var sheet: PlanAndConnectActionSheet? @AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false @State private var justOpened = true @State private var progressIndicator = false @@ -41,7 +40,6 @@ struct GroupMemberInfoView: View { case switchAddressAlert case abortSwitchAddressAlert case syncConnectionForceAlert - case planAndConnectAlert(alert: PlanAndConnectAlert) case queueInfo(info: String) case someAlert(alert: SomeAlert) case error(title: LocalizedStringKey, error: LocalizedStringKey?) @@ -57,7 +55,6 @@ struct GroupMemberInfoView: View { case .switchAddressAlert: return "switchAddressAlert" case .abortSwitchAddressAlert: return "abortSwitchAddressAlert" case .syncConnectionForceAlert: return "syncConnectionForceAlert" - case let .planAndConnectAlert(alert): return "planAndConnectAlert \(alert.id)" case let .queueInfo(info): return "queueInfo \(info)" case let .someAlert(alert): return "someAlert \(alert.id)" case let .error(title, _): return "error \(title)" @@ -270,13 +267,11 @@ struct GroupMemberInfoView: View { case .switchAddressAlert: return switchAddressAlert(switchMemberAddress) case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchMemberAddress) case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncMemberConnection(force: true) }) - case let .planAndConnectAlert(alert): return planAndConnectAlert(alert, dismiss: true) case let .queueInfo(info): return queueInfoAlert(info) case let .someAlert(a): return a.alert case let .error(title, error): return mkAlert(title: title, message: error) } } - .actionSheet(item: $sheet) { s in planAndConnectActionSheet(s, dismiss: true) } if progressIndicator { ProgressView().scaleEffect(2) @@ -350,10 +345,7 @@ struct GroupMemberInfoView: View { Button { planAndConnect( contactLink, - showAlert: { alert = .planAndConnectAlert(alert: $0) }, - showActionSheet: { sheet = $0 }, - dismiss: true, - incognito: nil + dismiss: true ) } label: { Label("Connect", systemImage: "link") diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 377764ac83..58e0882e38 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -579,8 +579,6 @@ struct ChatListSearchBar: View { @Binding var searchChatFilteredBySimplexLink: String? @Binding var parentSheet: SomeSheet? @State private var ignoreSearchTextChange = false - @State private var alert: PlanAndConnectAlert? - @State private var sheet: PlanAndConnectActionSheet? var body: some View { VStack(spacing: 12) { @@ -645,12 +643,6 @@ struct ChatListSearchBar: View { .onChange(of: chatTagsModel.activeFilter) { _ in searchText = "" } - .alert(item: $alert) { a in - planAndConnectAlert(a, dismiss: true, cleanup: { searchText = "" }) - } - .actionSheet(item: $sheet) { s in - planAndConnectActionSheet(s, dismiss: true, cleanup: { searchText = "" }) - } } private func toggleFilterButton() -> some View { @@ -676,10 +668,11 @@ struct ChatListSearchBar: View { private func connect(_ link: String) { planAndConnect( link, - showAlert: { alert = $0 }, - showActionSheet: { sheet = $0 }, dismiss: false, - incognito: nil, + cleanup: { + searchText = "" + searchFocussed = false + }, filterKnownContact: { searchChatFilteredBySimplexLink = $0.id }, filterKnownGroup: { searchChatFilteredBySimplexLink = $0.id } ) diff --git a/apps/ios/Shared/Views/Helpers/ShareSheet.swift b/apps/ios/Shared/Views/Helpers/ShareSheet.swift index b8de0e4ceb..753d92b6d9 100644 --- a/apps/ios/Shared/Views/Helpers/ShareSheet.swift +++ b/apps/ios/Shared/Views/Helpers/ShareSheet.swift @@ -65,6 +65,27 @@ func showAlert( } } +func showSheet( + _ title: String?, + message: String? = nil, + actions: () -> [UIAlertAction] = { [okAlertAction] }, + sourceView: UIView? = nil // For iPad support +) { + if let topController = getTopViewController() { + let sheet = UIAlertController(title: title, message: message, preferredStyle: .actionSheet) + for action in actions() { sheet.addAction(action) } + + // Required for iPad: Configure popover presentation + if let popover = sheet.popoverPresentationController { + popover.sourceView = sourceView ?? topController.view + popover.sourceRect = sourceView?.bounds ?? CGRect(x: topController.view.bounds.midX, y: topController.view.bounds.midY, width: 0, height: 0) + popover.permittedArrowDirections = [] + } + + topController.present(sheet, animated: true) + } +} + let okAlertAction = UIAlertAction(title: NSLocalizedString("Ok", comment: "alert button"), style: .default) let cancelAlertAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: "alert button"), style: .cancel) diff --git a/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift index 98f43f49b2..7a49c30b38 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift @@ -346,8 +346,6 @@ struct ContactsListSearchBar: View { @Binding var searchShowingSimplexLink: Bool @Binding var searchChatFilteredBySimplexLink: String? @State private var ignoreSearchTextChange = false - @State private var alert: PlanAndConnectAlert? - @State private var sheet: PlanAndConnectActionSheet? @AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false var body: some View { @@ -416,12 +414,6 @@ struct ContactsListSearchBar: View { } } } - .alert(item: $alert) { a in - planAndConnectAlert(a, dismiss: true, cleanup: { searchText = "" }) - } - .actionSheet(item: $sheet) { s in - planAndConnectActionSheet(s, dismiss: true, cleanup: { searchText = "" }) - } } private func toggleFilterButton() -> some View { @@ -442,10 +434,11 @@ struct ContactsListSearchBar: View { private func connect(_ link: String) { planAndConnect( link, - showAlert: { alert = $0 }, - showActionSheet: { sheet = $0 }, dismiss: true, - incognito: nil, + cleanup: { + searchText = "" + searchFocussed = false + }, filterKnownContact: { searchChatFilteredBySimplexLink = $0.id } ) } diff --git a/apps/ios/Shared/Views/NewChat/NewChatView.swift b/apps/ios/Shared/Views/NewChat/NewChatView.swift index 110eda7882..45c4f42a19 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatView.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatView.swift @@ -29,11 +29,9 @@ struct SomeSheet: Identifiable { } private enum NewChatViewAlert: Identifiable { - case planAndConnectAlert(alert: PlanAndConnectAlert) case newChatSomeAlert(alert: SomeAlert) var id: String { switch self { - case let .planAndConnectAlert(alert): return "planAndConnectAlert \(alert.id)" case let .newChatSomeAlert(alert): return "newChatSomeAlert \(alert.id)" } } @@ -165,8 +163,6 @@ struct NewChatView: View { } .alert(item: $alert) { a in switch(a) { - case let .planAndConnectAlert(alert): - return planAndConnectAlert(alert, dismiss: true, cleanup: { pastedLink = "" }) case let .newChatSomeAlert(a): return a.alert } @@ -593,7 +589,6 @@ private struct ConnectView: View { @Binding var showQRCodeScanner: Bool @Binding var pastedLink: String @Binding var alert: NewChatViewAlert? - @State private var sheet: PlanAndConnectActionSheet? @State private var pasteboardHasStrings = UIPasteboard.general.hasStrings var body: some View { @@ -605,9 +600,6 @@ private struct ConnectView: View { ScannerInView(showQRCodeScanner: $showQRCodeScanner, processQRCode: processQRCode) } } - .actionSheet(item: $sheet) { s in - planAndConnectActionSheet(s, dismiss: true, cleanup: { pastedLink = "" }) - } } @ViewBuilder private func pasteLinkView() -> some View { @@ -662,10 +654,7 @@ private struct ConnectView: View { private func connect(_ link: String) { planAndConnect( link, - showAlert: { alert = .planAndConnectAlert(alert: $0) }, - showActionSheet: { sheet = $0 }, - dismiss: true, - incognito: nil + dismiss: true ) } } @@ -839,187 +828,184 @@ func sharedProfileInfo(_ incognito: Bool) -> Text { ) } -enum PlanAndConnectAlert: Identifiable { - case ownInvitationLinkConfirmConnect(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan, incognito: Bool) - case invitationLinkConnecting(connectionLink: CreatedConnLink) - case ownContactAddressConfirmConnect(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan, incognito: Bool) - case contactAddressConnectingConfirmReconnect(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan, incognito: Bool) - case groupLinkConfirmConnect(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan, incognito: Bool) - case groupLinkConnectingConfirmReconnect(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan, incognito: Bool) - case groupLinkConnecting(connectionLink: CreatedConnLink, groupInfo: GroupInfo?) - case error(shortOrFullLink: String, alert: Alert) - - var id: String { - switch self { - case let .ownInvitationLinkConfirmConnect(connectionLink, _, _): return "ownInvitationLinkConfirmConnect \(connectionLink.connFullLink)" - case let .invitationLinkConnecting(connectionLink): return "invitationLinkConnecting \(connectionLink.connFullLink)" - case let .ownContactAddressConfirmConnect(connectionLink, _, _): return "ownContactAddressConfirmConnect \(connectionLink.connFullLink)" - case let .contactAddressConnectingConfirmReconnect(connectionLink, _, _): return "contactAddressConnectingConfirmReconnect \(connectionLink.connFullLink)" - case let .groupLinkConfirmConnect(connectionLink, _, _): return "groupLinkConfirmConnect \(connectionLink.connFullLink)" - case let .groupLinkConnectingConfirmReconnect(connectionLink, _, _): return "groupLinkConnectingConfirmReconnect \(connectionLink.connFullLink)" - case let .groupLinkConnecting(connectionLink, _): return "groupLinkConnecting \(connectionLink.connFullLink)" - case let .error(shortOrFullLink, alert): return "error \(shortOrFullLink)" - } - } +private func showInvitationLinkConnectingAlert(cleanup: (() -> Void)?) { + showAlert( + NSLocalizedString("Already connecting!", comment: "new chat sheet title"), + message: NSLocalizedString("You are already connecting via this one-time link!", comment: "new chat sheet message"), + actions: {[ + okCleanupAlertAction(cleanup: cleanup) + ]} + ) } -func planAndConnectAlert(_ alert: PlanAndConnectAlert, dismiss: Bool, cleanup: (() -> Void)? = nil) -> Alert { - switch alert { - case let .ownInvitationLinkConfirmConnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Connect to yourself?"), - message: Text("This is your own one-time link!"), - primaryButton: .destructive( - Text(incognito ? "Connect incognito" : "Connect"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } - ), - secondaryButton: .cancel() { cleanup?() } - ) - case .invitationLinkConnecting: - return Alert( - title: Text("Already connecting!"), - message: Text("You are already connecting via this one-time link!"), - dismissButton: .default(Text("OK")) { cleanup?() } - ) - case let .ownContactAddressConfirmConnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Connect to yourself?"), - message: Text("This is your own SimpleX address!"), - primaryButton: .destructive( - Text(incognito ? "Connect incognito" : "Connect"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } - ), - secondaryButton: .cancel() { cleanup?() } - ) - case let .contactAddressConnectingConfirmReconnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Repeat connection request?"), - message: Text("You have already requested connection via this address!"), - primaryButton: .destructive( - Text(incognito ? "Connect incognito" : "Connect"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } - ), - secondaryButton: .cancel() { cleanup?() } - ) - case let .groupLinkConfirmConnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Join group?"), - message: Text("You will connect to all group members."), - primaryButton: .default( - Text(incognito ? "Join incognito" : "Join"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } - ), - secondaryButton: .cancel() { cleanup?() } - ) - case let .groupLinkConnectingConfirmReconnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Repeat join request?"), - message: Text("You are already joining the group via this link!"), - primaryButton: .destructive( - Text(incognito ? "Join incognito" : "Join"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } - ), - secondaryButton: .cancel() { cleanup?() } - ) - case let .groupLinkConnecting(_, groupInfo): - if let groupInfo = groupInfo { - return groupInfo.businessChat == nil - ? Alert( - title: Text("Group already exists!"), - message: Text("You are already joining the group \(groupInfo.displayName)."), - dismissButton: .default(Text("OK")) { cleanup?() } - ) - : Alert( - title: Text("Chat already exists!"), - message: Text("You are already connecting to \(groupInfo.displayName)."), - dismissButton: .default(Text("OK")) { cleanup?() } +private func showGroupLinkConnectingAlert(groupInfo: GroupInfo?, cleanup: (() -> Void)?) { + if let groupInfo = groupInfo { + if groupInfo.businessChat == nil { + showAlert( + NSLocalizedString("Group already exists!", comment: "new chat sheet title"), + message: + String.localizedStringWithFormat( + NSLocalizedString("You are already joining the group %@.", comment: "new chat sheet message"), + groupInfo.displayName + ), + actions: {[ + okCleanupAlertAction(cleanup: cleanup) + ]} ) } else { - return Alert( - title: Text("Already joining the group!"), - message: Text("You are already joining the group via this link."), - dismissButton: .default(Text("OK")) { cleanup?() } + showAlert( + NSLocalizedString("Chat already exists!", comment: "new chat sheet title"), + message: + String.localizedStringWithFormat( + NSLocalizedString("You are already connecting to %@.", comment: "new chat sheet message"), + groupInfo.displayName + ), + actions: {[ + okCleanupAlertAction(cleanup: cleanup) + ]} ) } - case let .error(_, alert): return alert + } else { + showAlert( + NSLocalizedString("Already joining the group!", comment: "new chat sheet title"), + message: NSLocalizedString("You are already joining the group via this link.", comment: "new chat sheet message"), + actions: {[ + okCleanupAlertAction(cleanup: cleanup) + ]} + ) } } -enum PlanAndConnectActionSheet: Identifiable { - case askCurrentOrIncognitoProfile(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan?, title: LocalizedStringKey) - case askCurrentOrIncognitoProfileDestructive(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan, title: LocalizedStringKey) - case askCurrentOrIncognitoProfileConnectContactViaAddress(contact: Contact) - case ownGroupLinkConfirmConnect(connectionLink: CreatedConnLink, connectionPlan: ConnectionPlan, incognito: Bool?, groupInfo: GroupInfo) - - var id: String { - switch self { - case let .askCurrentOrIncognitoProfile(connectionLink, _, _): return "askCurrentOrIncognitoProfile \(connectionLink.connFullLink)" - case let .askCurrentOrIncognitoProfileDestructive(connectionLink, _, _): return "askCurrentOrIncognitoProfileDestructive \(connectionLink.connFullLink)" - case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact): return "askCurrentOrIncognitoProfileConnectContactViaAddress \(contact.contactId)" - case let .ownGroupLinkConfirmConnect(connectionLink, _, _, _): return "ownGroupLinkConfirmConnect \(connectionLink.connFullLink)" +private func okCleanupAlertAction(cleanup: (() -> Void)?) -> UIAlertAction { + UIAlertAction( + title: NSLocalizedString("Ok", comment: "new chat action"), + style: .default, + handler: { _ in + cleanup?() } - } + ) } -func planAndConnectActionSheet(_ sheet: PlanAndConnectActionSheet, dismiss: Bool, cleanup: (() -> Void)? = nil) -> ActionSheet { - switch sheet { - case let .askCurrentOrIncognitoProfile(connectionLink, connectionPlan, title): - return ActionSheet( - title: Text(title), - buttons: [ - .default(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) }, - .default(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) }, - .cancel() { cleanup?() } - ] - ) - case let .askCurrentOrIncognitoProfileDestructive(connectionLink, connectionPlan, title): - return ActionSheet( - title: Text(title), - buttons: [ - .destructive(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) }, - .destructive(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) }, - .cancel() { cleanup?() } - ] - ) - case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact): - return ActionSheet( - title: Text("Connect with \(contact.chatViewName)"), - buttons: [ - .default(Text("Use current profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: false, cleanup: cleanup) }, - .default(Text("Use new incognito profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: true, cleanup: cleanup) }, - .cancel() { cleanup?() } - ] - ) - case let .ownGroupLinkConfirmConnect(connectionLink, connectionPlan, incognito, groupInfo): - if let incognito = incognito { - return ActionSheet( - title: Text("Join your group?\nThis is your link for group \(groupInfo.displayName)!"), - buttons: [ - .default(Text("Open group")) { openKnownGroup(groupInfo, dismiss: dismiss, showAlreadyExistsAlert: nil) }, - .destructive(Text(incognito ? "Join incognito" : "Join with current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) }, - .cancel() { cleanup?() } - ] +private func showAskCurrentOrIncognitoProfileSheet( + title: String, + actionStyle: UIAlertAction.Style = .default, + connectionLink: CreatedConnLink, + connectionPlan: ConnectionPlan?, + dismiss: Bool, + cleanup: (() -> Void)? +) { + showSheet( + title, + actions: {[ + UIAlertAction( + title: NSLocalizedString("Use current profile", comment: "new chat action"), + style: actionStyle, + handler: { _ in + connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) + } + ), + UIAlertAction( + title: NSLocalizedString("Use new incognito profile", comment: "new chat action"), + style: actionStyle, + handler: { _ in + connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) + } + ), + UIAlertAction( + title: NSLocalizedString("Cancel", comment: "new chat action"), + style: .default, + handler: { _ in + cleanup?() + } ) - } else { - return ActionSheet( - title: Text("Join your group?\nThis is your link for group \(groupInfo.displayName)!"), - buttons: [ - .default(Text("Open group")) { openKnownGroup(groupInfo, dismiss: dismiss, showAlreadyExistsAlert: nil) }, - .destructive(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) }, - .destructive(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) }, - .cancel() { cleanup?() } - ] + ]} + ) +} + +private func showAskCurrentOrIncognitoProfileConnectContactViaAddressSheet( + contact: Contact, + dismiss: Bool, + cleanup: (() -> Void)? +) { + showSheet( + String.localizedStringWithFormat( + NSLocalizedString("Connect with %@", comment: "new chat action"), + contact.chatViewName + ), + actions: {[ + UIAlertAction( + title: NSLocalizedString("Use current profile", comment: "new chat action"), + style: .default, + handler: { _ in + connectContactViaAddress_(contact, dismiss: dismiss, incognito: false, cleanup: cleanup) + } + ), + UIAlertAction( + title: NSLocalizedString("Use new incognito profile", comment: "new chat action"), + style: .default, + handler: { _ in + connectContactViaAddress_(contact, dismiss: dismiss, incognito: true, cleanup: cleanup) + } + ), + UIAlertAction( + title: NSLocalizedString("Cancel", comment: "new chat action"), + style: .default, + handler: { _ in + cleanup?() + } ) - } - } + ]} + ) +} + +private func showOwnGroupLinkConfirmConnectSheet( + groupInfo: GroupInfo, + connectionLink: CreatedConnLink, + connectionPlan: ConnectionPlan?, + dismiss: Bool, + cleanup: (() -> Void)? +) { + showSheet( + String.localizedStringWithFormat( + NSLocalizedString("Join your group?\nThis is your link for group %@!", comment: "new chat action"), + groupInfo.displayName + ), + actions: {[ + UIAlertAction( + title: NSLocalizedString("Open group", comment: "new chat action"), + style: .default, + handler: { _ in + openKnownGroup(groupInfo, dismiss: dismiss, showAlreadyExistsAlert: nil) + } + ), + UIAlertAction( + title: NSLocalizedString("Use current profile", comment: "new chat action"), + style: .destructive, + handler: { _ in + connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) + } + ), + UIAlertAction( + title: NSLocalizedString("Use new incognito profile", comment: "new chat action"), + style: .destructive, + handler: { _ in + connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) + } + ), + UIAlertAction( + title: NSLocalizedString("Cancel", comment: "new chat action"), + style: .default, + handler: { _ in + cleanup?() + } + ) + ]} + ) } func planAndConnect( _ shortOrFullLink: String, - showAlert: @escaping (PlanAndConnectAlert) -> Void, - showActionSheet: @escaping (PlanAndConnectActionSheet) -> Void, dismiss: Bool, - incognito: Bool?, cleanup: (() -> Void)? = nil, filterKnownContact: ((Contact) -> Void)? = nil, filterKnownGroup: ((GroupInfo) -> Void)? = nil @@ -1031,25 +1017,30 @@ func planAndConnect( case let .invitationLink(ilp): switch ilp { case .ok: - logger.debug("planAndConnect, .invitationLink, .ok, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) - } else { - await MainActor.run { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect via one-time link")) - } + logger.debug("planAndConnect, .invitationLink, .ok") + await MainActor.run { + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("Connect via one-time link", comment: "new chat sheet title"), + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case .ownLink: - logger.debug("planAndConnect, .invitationLink, .ownLink, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .invitationLink, .ownLink") await MainActor.run { - if let incognito = incognito { - showAlert(.ownInvitationLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own one-time link!")) - } + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("Connect to yourself?\nThis is your own one-time link!", comment: "new chat sheet title"), + actionStyle: .destructive, + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case let .connecting(contact_): - logger.debug("planAndConnect, .invitationLink, .connecting, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .invitationLink, .connecting") await MainActor.run { if let contact = contact_ { if let f = filterKnownContact { @@ -1058,11 +1049,11 @@ func planAndConnect( openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyConnectingAlert(contact)) } } } else { - showAlert(.invitationLinkConnecting(connectionLink: connectionLink)) + showInvitationLinkConnectingAlert(cleanup: cleanup) } } case let .known(contact): - logger.debug("planAndConnect, .invitationLink, .known, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .invitationLink, .known") await MainActor.run { if let f = filterKnownContact { f(contact) @@ -1074,34 +1065,42 @@ func planAndConnect( case let .contactAddress(cap): switch cap { case .ok: - logger.debug("planAndConnect, .contactAddress, .ok, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) - } else { - await MainActor.run { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect via contact address")) - } + logger.debug("planAndConnect, .contactAddress, .ok") + await MainActor.run { + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("Connect via contact address", comment: "new chat sheet title"), + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case .ownLink: - logger.debug("planAndConnect, .contactAddress, .ownLink, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .contactAddress, .ownLink") await MainActor.run { - if let incognito = incognito { - showAlert(.ownContactAddressConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own SimpleX address!")) - } + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("Connect to yourself?\nThis is your own SimpleX address!", comment: "new chat sheet title"), + actionStyle: .destructive, + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case .connectingConfirmReconnect: - logger.debug("planAndConnect, .contactAddress, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .contactAddress, .connectingConfirmReconnect") await MainActor.run { - if let incognito = incognito { - showAlert(.contactAddressConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You have already requested connection!\nRepeat connection request?")) - } + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("You have already requested connection!\nRepeat connection request?", comment: "new chat sheet title"), + actionStyle: .destructive, + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case let .connectingProhibit(contact): - logger.debug("planAndConnect, .contactAddress, .connectingProhibit, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .contactAddress, .connectingProhibit") await MainActor.run { if let f = filterKnownContact { f(contact) @@ -1110,7 +1109,7 @@ func planAndConnect( } } case let .known(contact): - logger.debug("planAndConnect, .contactAddress, .known, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .contactAddress, .known") await MainActor.run { if let f = filterKnownContact { f(contact) @@ -1119,49 +1118,60 @@ func planAndConnect( } } case let .contactViaAddress(contact): - logger.debug("planAndConnect, .contactAddress, .contactViaAddress, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - connectContactViaAddress_(contact, dismiss: dismiss, incognito: incognito, cleanup: cleanup) - } else { - await MainActor.run { - showActionSheet(.askCurrentOrIncognitoProfileConnectContactViaAddress(contact: contact)) - } + logger.debug("planAndConnect, .contactAddress, .contactViaAddress") + await MainActor.run { + showAskCurrentOrIncognitoProfileConnectContactViaAddressSheet( + contact: contact, + dismiss: dismiss, + cleanup: cleanup + ) } } case let .groupLink(glp): switch glp { case .ok: await MainActor.run { - if let incognito = incognito { - showAlert(.groupLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Join group")) - } + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("Join group", comment: "new chat sheet title"), + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case let .ownLink(groupInfo): - logger.debug("planAndConnect, .groupLink, .ownLink, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .groupLink, .ownLink") await MainActor.run { if let f = filterKnownGroup { f(groupInfo) } - showActionSheet(.ownGroupLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito, groupInfo: groupInfo)) + showOwnGroupLinkConfirmConnectSheet( + groupInfo: groupInfo, + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case .connectingConfirmReconnect: - logger.debug("planAndConnect, .groupLink, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .groupLink, .connectingConfirmReconnect") await MainActor.run { - if let incognito = incognito { - showAlert(.groupLinkConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You are already joining the group!\nRepeat join request?")) - } + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("You are already joining the group!\nRepeat join request?", comment: "new chat sheet title"), + actionStyle: .destructive, + connectionLink: connectionLink, + connectionPlan: connectionPlan, + dismiss: dismiss, + cleanup: cleanup + ) } case let .connectingProhibit(groupInfo_): - logger.debug("planAndConnect, .groupLink, .connectingProhibit, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .groupLink, .connectingProhibit") await MainActor.run { - showAlert(.groupLinkConnecting(connectionLink: connectionLink, groupInfo: groupInfo_)) + showGroupLinkConnectingAlert(groupInfo: groupInfo_, cleanup: cleanup) } case let .known(groupInfo): - logger.debug("planAndConnect, .groupLink, .known, incognito=\(incognito?.description ?? "nil")") + logger.debug("planAndConnect, .groupLink, .known") await MainActor.run { if let f = filterKnownGroup { f(groupInfo) @@ -1172,15 +1182,20 @@ func planAndConnect( } case let .error(chatError): logger.debug("planAndConnect, .error \(chatErrorString(chatError))") - if let incognito = incognito { - connectViaLink(connectionLink, connectionPlan: nil, dismiss: dismiss, incognito: incognito, cleanup: cleanup) - } else { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: nil, title: "Connect via link")) - } + showAskCurrentOrIncognitoProfileSheet( + title: NSLocalizedString("Connect via link", comment: "new chat sheet title"), + connectionLink: connectionLink, + connectionPlan: nil, + dismiss: dismiss, + cleanup: cleanup + ) } } else if let alert { await MainActor.run { - showAlert(.error(shortOrFullLink: shortOrFullLink, alert: alert)) + dismissAllSheets(animated: true) { + AlertManager.shared.showAlert(alert) + cleanup?() + } } } }