144 lines
7.3 KiB
Swift
144 lines
7.3 KiB
Swift
//
|
||
// NotificationFormatter.swift
|
||
// DamusNotificationService
|
||
//
|
||
// Created by Daniel D’Aquino on 2023-11-13.
|
||
//
|
||
|
||
import Foundation
|
||
import UserNotifications
|
||
|
||
struct NotificationFormatter {
|
||
static var shared = NotificationFormatter()
|
||
|
||
// MARK: - Formatting with NdbNote
|
||
|
||
func format_message(event: NdbNote) -> UNMutableNotificationContent? {
|
||
let content = UNMutableNotificationContent()
|
||
if let event_json_data = try? JSONEncoder().encode(event), // Must be encoded, as the notification completion handler requires this object to conform to `NSSecureCoding`
|
||
let event_json_string = String(data: event_json_data, encoding: .utf8) {
|
||
content.userInfo = [
|
||
NDB_NOTE_JSON_USER_INFO_KEY: event_json_string
|
||
]
|
||
}
|
||
switch event.known_kind {
|
||
case .text:
|
||
content.title = NSLocalizedString("Someone posted a note", comment: "Title label for push notification where someone posted a note")
|
||
content.body = event.content
|
||
break
|
||
case .deprecated_dm:
|
||
content.title = NSLocalizedString("New message", comment: "Title label for push notifications where a direct message was sent to the user")
|
||
content.body = NSLocalizedString("(Contents are encrypted)", comment: "Label on push notification indicating that the contents of the message are encrypted")
|
||
break
|
||
case .like:
|
||
guard let reactionEmoji = to_reaction_emoji(ev: event) else {
|
||
content.title = NSLocalizedString("Someone reacted to your note", comment: "Generic title label for push notifications where someone reacted to the user's post")
|
||
break
|
||
}
|
||
content.title = NSLocalizedString("New note reaction", comment: "Title label for push notifications where someone reacted to the user's post with a specific emoji")
|
||
content.body = String(format: NSLocalizedString("Someone reacted to your note with %@", comment: "Body label for push notifications where someone reacted to the user's post with a specific emoji"), reactionEmoji)
|
||
break
|
||
case .zap:
|
||
content.title = NSLocalizedString("Someone zapped you ⚡️", comment: "Title label for a push notification where someone zapped the user")
|
||
break
|
||
default:
|
||
return nil
|
||
}
|
||
return content
|
||
}
|
||
|
||
// MARK: - Formatting with LocalNotification
|
||
|
||
func format_message(displayName: String, notify: LocalNotification) -> (content: UNMutableNotificationContent, identifier: String)? {
|
||
let content = UNMutableNotificationContent()
|
||
var title = ""
|
||
var identifier = ""
|
||
|
||
switch notify.type {
|
||
case .tagged:
|
||
title = String(format: NSLocalizedString("Tagged by %@", comment: "Tagged by heading in local notification"), displayName)
|
||
identifier = "myMentionNotification"
|
||
case .mention:
|
||
title = String(format: NSLocalizedString("Mentioned by %@", comment: "Mentioned by heading in local notification"), displayName)
|
||
identifier = "myMentionNotification"
|
||
case .repost:
|
||
title = String(format: NSLocalizedString("Reposted by %@", comment: "Reposted by heading in local notification"), displayName)
|
||
identifier = "myBoostNotification"
|
||
case .like:
|
||
title = String(format: NSLocalizedString("%@ reacted with %@", comment: "Reacted by heading in local notification"), displayName, to_reaction_emoji(ev: notify.event) ?? "")
|
||
identifier = "myLikeNotification"
|
||
case .dm:
|
||
title = displayName
|
||
identifier = "myDMNotification"
|
||
case .zap, .profile_zap:
|
||
// not handled here. Try `format_message(displayName: String, notify: LocalNotification, state: HeadlessDamusState) async -> (content: UNMutableNotificationContent, identifier: String)?`
|
||
return nil
|
||
case .reply:
|
||
title = String(format: NSLocalizedString("%@ replied to your note", comment: "Heading for local notification indicating a new reply"), displayName)
|
||
identifier = "myReplyNotification"
|
||
}
|
||
content.title = title
|
||
content.body = notify.content
|
||
content.sound = UNNotificationSound.default
|
||
content.userInfo = notify.to_lossy().to_user_info()
|
||
|
||
return (content, identifier)
|
||
}
|
||
|
||
func format_message(displayName: String, notify: LocalNotification, state: HeadlessDamusState) async -> (content: UNMutableNotificationContent, identifier: String)? {
|
||
// Try sync method first and return if it works
|
||
if let sync_formatted_message = self.format_message(displayName: displayName, notify: notify) {
|
||
return sync_formatted_message
|
||
}
|
||
|
||
// If it does not work, try async formatting methods
|
||
let content = UNMutableNotificationContent()
|
||
|
||
switch notify.type {
|
||
case .zap, .profile_zap:
|
||
guard let zap = await get_zap(from: notify.event, state: state) else {
|
||
Log.debug("format_message: async get_zap failed", for: .push_notifications)
|
||
return nil
|
||
}
|
||
content.title = Self.zap_notification_title(zap)
|
||
content.body = Self.zap_notification_body(profiles: state.profiles, zap: zap)
|
||
content.sound = UNNotificationSound.default
|
||
content.userInfo = LossyLocalNotification(type: .zap, mention: .note(notify.event.id)).to_user_info()
|
||
return (content, "myZapNotification")
|
||
default:
|
||
// The sync method should have taken care of this.
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// MARK: - Formatting zap utility notifications
|
||
|
||
static func zap_notification_title(_ zap: Zap) -> String {
|
||
if zap.private_request != nil {
|
||
return NSLocalizedString("Private Zap", comment: "Title of notification when a private zap is received.")
|
||
} else {
|
||
return NSLocalizedString("Zap", comment: "Title of notification when a non-private zap is received.")
|
||
}
|
||
}
|
||
|
||
static func zap_notification_body(profiles: Profiles, zap: Zap, locale: Locale = Locale.current) -> String {
|
||
let src = zap.request.ev
|
||
let pk = zap.is_anon ? ANON_PUBKEY : src.pubkey
|
||
|
||
let profile_txn = profiles.lookup(id: pk)
|
||
let profile = profile_txn?.unsafeUnownedValue
|
||
let name = Profile.displayName(profile: profile, pubkey: pk).displayName.truncate(maxLength: 50)
|
||
|
||
let sats = NSNumber(value: (Double(zap.invoice.amount) / 1000.0))
|
||
let formattedSats = format_msats_abbrev(zap.invoice.amount)
|
||
|
||
if src.content.isEmpty {
|
||
let format = localizedStringFormat(key: "zap_notification_no_message", locale: locale)
|
||
return String(format: format, locale: locale, sats.decimalValue as NSDecimalNumber, formattedSats, name)
|
||
} else {
|
||
let format = localizedStringFormat(key: "zap_notification_with_message", locale: locale)
|
||
return String(format: format, locale: locale, sats.decimalValue as NSDecimalNumber, formattedSats, name, src.content)
|
||
}
|
||
}
|
||
}
|