mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-21 23:19:48 +00:00
ios: show accept/reject dialog when tapping a chat-invitation notification
A plain tap on a contact-request notification carries the legacy contact request chatId, which has no openable chat view, so unlike a message it could not be opened - previously the tap only switched profile and left a blank screen. Now the tap surfaces the same accept/reject dialog as the chat-list row: NtfManager sets chatModel.showingContactRequest (only when the request is loaded, which changeActiveUser does synchronously) and drops any open chat, and ChatListView presents a model-driven confirmationDialog. The dialog buttons are extracted into a shared contactRequestDialogButtons view builder reused by the chat-list row.
This commit is contained in:
@@ -413,6 +413,8 @@ final class ChatModel: ObservableObject {
|
||||
@Published var notificationPreview: NotificationPreviewMode = ntfPreviewModeGroupDefault.get()
|
||||
// pending notification actions
|
||||
@Published var ntfContactRequest: NTFContactRequest?
|
||||
// contact request whose accept/reject dialog should be surfaced after opening from a notification tap
|
||||
@Published var showingContactRequest: NTFContactRequest?
|
||||
@Published var ntfCallInvitationAction: (ChatId, NtfCallAction)?
|
||||
// current WebRTC call
|
||||
@Published var callInvitations: Dictionary<ChatId, RcvCallInvitation> = [:]
|
||||
|
||||
@@ -64,12 +64,22 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
|
||||
// switched profile's chats, so drop it to land on the chat list instead of a blank chat view
|
||||
chatModel.chatId = nil
|
||||
}
|
||||
if content.categoryIdentifier == ntfCategoryContactRequest && action == ntfActionAcceptContact,
|
||||
if content.categoryIdentifier == ntfCategoryContactRequest,
|
||||
let chatId = content.userInfo["chatId"] as? String {
|
||||
if case let .contactRequest(contactRequest) = chatModel.getChat(chatId)?.chatInfo {
|
||||
Task { await acceptContactRequest(incognito: false, contactRequestId: contactRequest.apiId) }
|
||||
} else {
|
||||
chatModel.ntfContactRequest = NTFContactRequest(chatId: chatId)
|
||||
if action == ntfActionAcceptContact {
|
||||
if case let .contactRequest(contactRequest) = chatModel.getChat(chatId)?.chatInfo {
|
||||
Task { await acceptContactRequest(incognito: false, contactRequestId: contactRequest.apiId) }
|
||||
} else {
|
||||
chatModel.ntfContactRequest = NTFContactRequest(chatId: chatId)
|
||||
}
|
||||
} else if action == UNNotificationDefaultActionIdentifier,
|
||||
case .contactRequest = chatModel.getChat(chatId)?.chatInfo {
|
||||
// a plain tap (not the Accept button) surfaces the accept/reject dialog for the request;
|
||||
// a contact request has no openable chat view, so it cannot be opened like a message.
|
||||
// require the request to be loaded (changeActiveUser above loads chats synchronously)
|
||||
// so the dialog always has buttons, and drop any open chat so it presents over the list
|
||||
chatModel.chatId = nil
|
||||
chatModel.showingContactRequest = NTFContactRequest(chatId: chatId)
|
||||
}
|
||||
} else if let (chatId, ntfAction) = ntfCallAction(content, action) {
|
||||
if let invitation = chatModel.callInvitations.removeValue(forKey: chatId) {
|
||||
|
||||
@@ -518,11 +518,7 @@ struct ChatListNavLink: View {
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { showContactRequestDialog = true }
|
||||
.confirmationDialog("Accept connection request?", isPresented: $showContactRequestDialog, titleVisibility: .visible) {
|
||||
Button("Accept") { Task { await acceptContactRequest(incognito: false, contactRequestId: contactRequest.apiId) } }
|
||||
if !ChatModel.shared.addressShortLinkDataSet {
|
||||
Button("Accept incognito") { Task { await acceptContactRequest(incognito: true, contactRequestId: contactRequest.apiId) } }
|
||||
}
|
||||
Button("Reject (sender NOT notified)", role: .destructive) { Task { await rejectContactRequest(contactRequest.apiId) } }
|
||||
contactRequestDialogButtons(contactRequest)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,6 +681,17 @@ extension View {
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons for the "Accept connection request?" dialog, shared by the chat-list row and the
|
||||
// dialog surfaced when a contact-request notification is tapped (ChatListView).
|
||||
@ViewBuilder
|
||||
func contactRequestDialogButtons(_ contactRequest: UserContactRequest) -> some View {
|
||||
Button("Accept") { Task { await acceptContactRequest(incognito: false, contactRequestId: contactRequest.apiId) } }
|
||||
if !ChatModel.shared.addressShortLinkDataSet {
|
||||
Button("Accept incognito") { Task { await acceptContactRequest(incognito: true, contactRequestId: contactRequest.apiId) } }
|
||||
}
|
||||
Button("Reject (sender NOT notified)", role: .destructive) { Task { await rejectContactRequest(contactRequest.apiId) } }
|
||||
}
|
||||
|
||||
func rejectContactRequestAlert(_ contactRequestId: Int64) -> Alert {
|
||||
Alert(
|
||||
title: Text("Reject contact request"),
|
||||
|
||||
@@ -218,6 +218,15 @@ struct ChatListView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.confirmationDialog("Accept connection request?", isPresented: Binding(
|
||||
get: { chatModel.showingContactRequest != nil },
|
||||
set: { if !$0 { chatModel.showingContactRequest = nil } }
|
||||
), titleVisibility: .visible) {
|
||||
if let ncr = chatModel.showingContactRequest,
|
||||
case let .contactRequest(contactRequest) = chatModel.getChat(ncr.chatId)?.chatInfo {
|
||||
contactRequestDialogButtons(contactRequest)
|
||||
}
|
||||
}
|
||||
.environmentObject(chatTagsModel)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user