ios: notification preview mode, show connection entity notification (#781)

* ios: notification preview mode, show connection entity notification

* prepare connection entity notification as best attempt
This commit is contained in:
Evgeny Poberezkin
2022-07-06 11:52:10 +01:00
committed by GitHub
parent 36dc66d5d5
commit ab6301c3e9
8 changed files with 115 additions and 49 deletions

View File

@@ -33,7 +33,7 @@ final class ChatModel: ObservableObject {
@Published var savedToken: DeviceToken?
@Published var tokenStatus: NtfTknStatus?
@Published var notificationMode = NotificationsMode.off
@Published var notificationPreview: NotificationPreviewMode? = .message
@Published var notificationPreview: NotificationPreviewMode? = ntfPreviewModeGroupDefault.get()
// current WebRTC call
@Published var callInvitations: Dictionary<ChatId, RcvCallInvitation> = [:]
@Published var activeCall: Call?

View File

@@ -136,12 +136,11 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: NSLocalizedString("Incoming call", comment: "notification")
),
// TODO remove
UNNotificationCategory(
identifier: ntfCategoryCheckingMessages,
identifier: ntfCategoryConnectionEvent,
actions: [],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: NSLocalizedString("Checking new messages...", comment: "notification")
hiddenPreviewsBodyPlaceholder: NSLocalizedString("SimpleX encrypted message or connection event", comment: "notification")
)
])
}
@@ -189,16 +188,6 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
addNotification(createCallInvitationNtf(invitation))
}
// TODO remove
func notifyCheckingMessages() {
logger.debug("NtfManager.notifyCheckingMessages")
let content = createNotification(
categoryIdentifier: ntfCategoryCheckingMessages,
title: NSLocalizedString("Checking new messages...", comment: "notification")
)
addNotification(content)
}
private func addNotification(_ content: UNMutableNotificationContent) {
if !granted { return }
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: ntfTimeInterval, repeats: false)

View File

@@ -55,9 +55,19 @@ struct NotificationsView: View {
NavigationLink {
List {
Section {
SelectionListView(list: NotificationPreviewMode.values, selection: $m.notificationPreview)
SelectionListView(list: NotificationPreviewMode.values, selection: $m.notificationPreview) { previewMode in
ntfPreviewModeGroupDefault.set(previewMode)
m.notificationPreview = previewMode
}
} footer: {
VStack(alignment: .leading, spacing: 1) {
Text("You can set lock screen notification preview via settings.")
Button("Open Settings") {
DispatchQueue.main.async {
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
}
}
}
}
}
.navigationTitle("Show preview")

View File

@@ -45,23 +45,14 @@ class NotificationService: UNNotificationServiceExtension {
let encNtfInfo = ntfData["message"] as? String,
let _ = startChat() {
if let ntfMsgInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
if let content = receiveMessageForNotification() {
contentHandler(content)
} else if let connEntity = ntfMsgInfo.connEntity {
switch connEntity {
case let .rcvDirectMsgConnection(_, contact):
()
case let .rcvGroupMsgConnection(_, groupInfo, groupMember):
()
case let .sndFileConnection(_, sndFileTransfer):
()
case let .rcvFileConnection(_, rcvFileTransfer):
()
case let .userContactConnection(_, userContact):
()
}
contentHandler(request.content)
}
if let connEntity = ntfMsgInfo.connEntity {
bestAttemptContent = createConnectionEventNtf(connEntity)
}
if let content = receiveMessageForNotification() {
contentHandler(content)
} else if let content = bestAttemptContent {
contentHandler(content)
}
}
}
}
@@ -70,8 +61,8 @@ class NotificationService: UNNotificationServiceExtension {
logger.debug("NotificationService.serviceExtensionTimeWillExpire")
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = self.contentHandler, let bestAttemptContent = self.bestAttemptContent {
contentHandler(bestAttemptContent)
if let contentHandler = self.contentHandler, let content = bestAttemptContent {
contentHandler(content)
}
}
}

View File

@@ -452,8 +452,8 @@ public enum NotificationPreviewMode: String, SelectableItem {
public var label: LocalizedStringKey {
switch self {
case .hidden: return "Hidden"
case .contact: return "Contact"
case .message: return "Message"
case .contact: return "Contact name"
case .message: return "Message text"
}
}

View File

@@ -12,6 +12,7 @@ import SwiftUI
let GROUP_DEFAULT_APP_STATE = "appState"
let GROUP_DEFAULT_DB_CONTAINER = "dbContainer"
public let GROUP_DEFAULT_CHAT_LAST_START = "chatLastStart"
let GROUP_DEFAULT_NTF_PREVIEW_MODE = "ntfPreviewMode"
let APP_GROUP_NAME = "group.chat.simplex.app"
@@ -51,6 +52,12 @@ public let dbContainerGroupDefault = EnumDefault<DBContainer>(
public let chatLastStartGroupDefault = DateDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_CHAT_LAST_START)
public let ntfPreviewModeGroupDefault = EnumDefault<NotificationPreviewMode>(
defaults: groupDefaults,
forKey: GROUP_DEFAULT_NTF_PREVIEW_MODE,
withDefault: .message
)
public class DateDefault {
var defaults: UserDefaults
var key: String

View File

@@ -426,6 +426,13 @@ public struct GroupMember: Decodable {
}
}
public var chatViewName: String {
get {
let p = memberProfile
return p.displayName + (p.fullName == "" || p.fullName == p.displayName ? "" : " / \(p.fullName)")
}
}
public static let sampleData = GroupMember(
groupMemberId: 1,
memberId: "abcd",

View File

@@ -14,37 +14,59 @@ public let ntfCategoryContactRequest = "NTF_CAT_CONTACT_REQUEST"
public let ntfCategoryContactConnected = "NTF_CAT_CONTACT_CONNECTED"
public let ntfCategoryMessageReceived = "NTF_CAT_MESSAGE_RECEIVED"
public let ntfCategoryCallInvitation = "NTF_CAT_CALL_INVITATION"
public let ntfCategoryConnectionEvent = "NTF_CAT_CONNECTION_EVENT"
public let ntfCategoryCheckMessage = "NTF_CAT_CHECK_MESSAGE"
// TODO remove
public let ntfCategoryCheckingMessages = "NTF_CAT_CHECKING_MESSAGES"
public let appNotificationId = "chat.simplex.app.notification"
let contactHidden = NSLocalizedString("Contact hidden:", comment: "notification")
public func createContactRequestNtf(_ contactRequest: UserContactRequest) -> UNMutableNotificationContent {
createNotification(
let hideContent = ntfPreviewModeGroupDefault.get() == .hidden
return createNotification(
categoryIdentifier: ntfCategoryContactRequest,
title: String.localizedStringWithFormat(NSLocalizedString("%@ wants to connect!", comment: "notification title"), contactRequest.displayName),
body: String.localizedStringWithFormat(NSLocalizedString("Accept contact request from %@?", comment: "notification body"), contactRequest.chatViewName),
title: String.localizedStringWithFormat(
NSLocalizedString("%@ wants to connect!", comment: "notification title"),
hideContent ? NSLocalizedString("Somebody", comment: "notification title") : contactRequest.displayName
),
body: String.localizedStringWithFormat(
NSLocalizedString("Accept contact request from %@?", comment: "notification body"),
hideContent ? NSLocalizedString("this contact", comment: "notification title") : contactRequest.chatViewName
),
targetContentIdentifier: nil,
userInfo: ["chatId": contactRequest.id, "contactRequestId": contactRequest.apiId]
)
}
public func createContactConnectedNtf(_ contact: Contact) -> UNMutableNotificationContent {
createNotification(
let hideContent = ntfPreviewModeGroupDefault.get() == .hidden
return createNotification(
categoryIdentifier: ntfCategoryContactConnected,
title: String.localizedStringWithFormat(NSLocalizedString("%@ is connected!", comment: "notification title"), contact.displayName),
body: String.localizedStringWithFormat(NSLocalizedString("You can now send messages to %@", comment: "notification body"), contact.chatViewName),
title: String.localizedStringWithFormat(
NSLocalizedString("%@ is connected!", comment: "notification title"),
hideContent ? NSLocalizedString("A new contact", comment: "notification title") : contact.displayName
),
body: String.localizedStringWithFormat(
NSLocalizedString("You can now send messages to %@", comment: "notification body"),
hideContent ? NSLocalizedString("this contact", comment: "notification title") : contact.chatViewName
),
targetContentIdentifier: contact.id
// userInfo: ["chatId": contact.id, "contactId": contact.apiId]
)
}
public func createMessageReceivedNtf(_ cInfo: ChatInfo, _ cItem: ChatItem) -> UNMutableNotificationContent {
createNotification(
let previewMode = ntfPreviewModeGroupDefault.get()
var title: String
if case let .group(groupInfo) = cInfo, case let .groupRcv(groupMember) = cItem.chatDir {
title = groupMsgNtfTitle(groupInfo, groupMember, hideContent: previewMode == .hidden)
} else {
title = previewMode == .hidden ? contactHidden : "\(cInfo.chatViewName):"
}
return createNotification(
categoryIdentifier: ntfCategoryMessageReceived,
title: "\(cInfo.chatViewName):",
body: hideSecrets(cItem),
title: title,
body: previewMode == .message ? hideSecrets(cItem) : NSLocalizedString("new message", comment: "notification"),
targetContentIdentifier: cInfo.id
// userInfo: ["chatId": cInfo.id, "chatItemId": cItem.id]
)
@@ -54,15 +76,55 @@ public func createCallInvitationNtf(_ invitation: RcvCallInvitation) -> UNMutabl
let text = invitation.callType.media == .video
? NSLocalizedString("Incoming video call", comment: "notification")
: NSLocalizedString("Incoming audio call", comment: "notification")
let hideContent = ntfPreviewModeGroupDefault.get() == .hidden
return createNotification(
categoryIdentifier: ntfCategoryCallInvitation,
title: "\(invitation.contact.chatViewName):",
title: hideContent ? contactHidden : "\(invitation.contact.chatViewName):",
body: text,
targetContentIdentifier: nil,
userInfo: ["chatId": invitation.contact.id]
)
}
public func createConnectionEventNtf(_ connEntity: ConnectionEntity) -> UNMutableNotificationContent {
let hideContent = ntfPreviewModeGroupDefault.get() == .hidden
var title: String
var body: String? = nil
var targetContentIdentifier: String? = nil
switch connEntity {
case let .rcvDirectMsgConnection(_, contact):
if let contact = contact {
title = hideContent ? contactHidden : "\(contact.chatViewName):"
targetContentIdentifier = contact.id
} else {
title = NSLocalizedString("New contact:", comment: "notification")
}
body = NSLocalizedString("message received", comment: "notification")
case let .rcvGroupMsgConnection(_, groupInfo, groupMember):
title = groupMsgNtfTitle(groupInfo, groupMember, hideContent: hideContent)
body = NSLocalizedString("message received", comment: "notification")
targetContentIdentifier = groupInfo.id
case .sndFileConnection:
title = NSLocalizedString("Sent file event", comment: "notification")
case .rcvFileConnection:
title = NSLocalizedString("Received file event", comment: "notification")
case .userContactConnection:
title = NSLocalizedString("New contact request", comment: "notification")
}
return createNotification(
categoryIdentifier: ntfCategoryCallInvitation,
title: title,
body: body,
targetContentIdentifier: targetContentIdentifier
)
}
private func groupMsgNtfTitle(_ groupInfo: GroupInfo, _ groupMember: GroupMember, hideContent: Bool) -> String {
hideContent
? NSLocalizedString("Group message:", comment: "notification")
: "#\(groupInfo.displayName) \(groupMember.chatViewName):"
}
public func createNotification(categoryIdentifier: String, title: String, subtitle: String? = nil, body: String? = nil,
targetContentIdentifier: String? = nil, userInfo: [AnyHashable : Any] = [:]) -> UNMutableNotificationContent {
let content = UNMutableNotificationContent()