mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-25 09:41:00 +00:00
Notificatio navigation wip
This commit is contained in:
parent
aea6030d43
commit
03b17d21ee
5 changed files with 48 additions and 27 deletions
|
@ -39,6 +39,7 @@ final class NotificationService: UNNotificationServiceExtension {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bestAttemptContent.userInfo[PushNotificationParsingService.pushNotificationUserInfoKey] = decryptedJSON
|
||||||
bestAttemptContent.title = pushNotification.title
|
bestAttemptContent.title = pushNotification.title
|
||||||
bestAttemptContent.body = XMLUnescaper(string: pushNotification.body).unescape()
|
bestAttemptContent.body = XMLUnescaper(string: pushNotification.body).unescape()
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ public struct PushNotificationParsingService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension PushNotificationParsingService {
|
public extension PushNotificationParsingService {
|
||||||
|
static let identityIdUserInfoKey = "i"
|
||||||
|
static let pushNotificationUserInfoKey = "com.metabolist.metatext.push-notification-user-info-key"
|
||||||
|
|
||||||
func extractAndDecrypt(userInfo: [AnyHashable: Any]) throws -> (Data, Identity.Id) {
|
func extractAndDecrypt(userInfo: [AnyHashable: Any]) throws -> (Data, Identity.Id) {
|
||||||
guard let identityIdString = userInfo[Self.identityIdUserInfoKey] as? String,
|
guard let identityIdString = userInfo[Self.identityIdUserInfoKey] as? String,
|
||||||
let identityId = Identity.Id(uuidString: identityIdString),
|
let identityId = Identity.Id(uuidString: identityIdString),
|
||||||
|
@ -48,7 +51,6 @@ public extension PushNotificationParsingService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension PushNotificationParsingService {
|
private extension PushNotificationParsingService {
|
||||||
static let identityIdUserInfoKey = "i"
|
|
||||||
static let encryptedMessageUserInfoKey = "m"
|
static let encryptedMessageUserInfoKey = "m"
|
||||||
static let saltUserInfoKey = "s"
|
static let saltUserInfoKey = "s"
|
||||||
static let serverPublicKeyUserInfoKey = "k"
|
static let serverPublicKeyUserInfoKey = "k"
|
||||||
|
|
|
@ -9,28 +9,27 @@ import ViewModels
|
||||||
@main
|
@main
|
||||||
struct MetatextApp: App {
|
struct MetatextApp: App {
|
||||||
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||||
private let environment = AppEnvironment.live(
|
// swiftlint:disable:next force_try
|
||||||
userNotificationCenter: .current(),
|
private let viewModel = try! RootViewModel(environment: Self.environment)
|
||||||
reduceMotion: { UIAccessibility.isReduceMotionEnabled })
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
try? AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)
|
try? AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)
|
||||||
try? ImageCacheConfiguration(environment: environment).configure()
|
try? ImageCacheConfiguration(environment: Self.environment).configure()
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
viewModel.registerForRemoteNotifications = appDelegate.registerForRemoteNotifications
|
||||||
RootView(
|
|
||||||
// swiftlint:disable force_try
|
return WindowGroup {
|
||||||
viewModel: try! RootViewModel(
|
RootView(viewModel: viewModel)
|
||||||
environment: environment,
|
|
||||||
registerForRemoteNotifications: appDelegate.registerForRemoteNotifications))
|
|
||||||
// swiftlint:enable force_try
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension MetatextApp {
|
private extension MetatextApp {
|
||||||
|
static let environment = AppEnvironment.live(
|
||||||
|
userNotificationCenter: .current(),
|
||||||
|
reduceMotion: { UIAccessibility.isReduceMotionEnabled })
|
||||||
static let imageCacheName = "Images"
|
static let imageCacheName = "Images"
|
||||||
static let imageCacheDirectoryURL = FileManager.default.containerURL(
|
static let imageCacheDirectoryURL = FileManager.default.containerURL(
|
||||||
forSecurityApplicationGroupIdentifier: AppEnvironment.appGroup)?
|
forSecurityApplicationGroupIdentifier: AppEnvironment.appGroup)?
|
||||||
|
|
|
@ -70,7 +70,7 @@ public extension Instance {
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension RootViewModel {
|
public extension RootViewModel {
|
||||||
static let preview = try! RootViewModel(environment: environment) { Empty().eraseToAnyPublisher() }
|
static let preview = try! RootViewModel(environment: environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension IdentityContext {
|
public extension IdentityContext {
|
||||||
|
|
|
@ -7,20 +7,30 @@ import ServiceLayer
|
||||||
|
|
||||||
public final class RootViewModel: ObservableObject {
|
public final class RootViewModel: ObservableObject {
|
||||||
@Published public private(set) var navigationViewModel: NavigationViewModel?
|
@Published public private(set) var navigationViewModel: NavigationViewModel?
|
||||||
|
public var registerForRemoteNotifications: (() -> AnyPublisher<Data, Error>)? {
|
||||||
|
didSet {
|
||||||
|
guard let registerForRemoteNotifications = registerForRemoteNotifications else { return }
|
||||||
|
|
||||||
|
userNotificationService.isAuthorized(request: false)
|
||||||
|
.filter { $0 }
|
||||||
|
.zip(registerForRemoteNotifications())
|
||||||
|
.map { $1 }
|
||||||
|
.flatMap(allIdentitiesService.updatePushSubscriptions(deviceToken:))
|
||||||
|
.sink { _ in } receiveValue: { _ in }
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Published private var mostRecentlyUsedIdentityId: Identity.Id?
|
@Published private var mostRecentlyUsedIdentityId: Identity.Id?
|
||||||
private let environment: AppEnvironment
|
private let environment: AppEnvironment
|
||||||
private let allIdentitiesService: AllIdentitiesService
|
private let allIdentitiesService: AllIdentitiesService
|
||||||
private let userNotificationService: UserNotificationService
|
private let userNotificationService: UserNotificationService
|
||||||
private let registerForRemoteNotifications: () -> AnyPublisher<Data, Error>
|
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
public init(environment: AppEnvironment,
|
public init(environment: AppEnvironment) throws {
|
||||||
registerForRemoteNotifications: @escaping () -> AnyPublisher<Data, Error>) throws {
|
|
||||||
self.environment = environment
|
self.environment = environment
|
||||||
allIdentitiesService = try AllIdentitiesService(environment: environment)
|
allIdentitiesService = try AllIdentitiesService(environment: environment)
|
||||||
userNotificationService = UserNotificationService(environment: environment)
|
userNotificationService = UserNotificationService(environment: environment)
|
||||||
self.registerForRemoteNotifications = registerForRemoteNotifications
|
|
||||||
|
|
||||||
allIdentitiesService.immediateMostRecentlyUsedIdentityIdPublisher()
|
allIdentitiesService.immediateMostRecentlyUsedIdentityIdPublisher()
|
||||||
.replaceError(with: nil)
|
.replaceError(with: nil)
|
||||||
|
@ -32,14 +42,6 @@ public final class RootViewModel: ObservableObject {
|
||||||
.sink { [weak self] in self?.identitySelected(id: $0) }
|
.sink { [weak self] in self?.identitySelected(id: $0) }
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
userNotificationService.isAuthorized(request: false)
|
|
||||||
.filter { $0 }
|
|
||||||
.zip(registerForRemoteNotifications())
|
|
||||||
.map { $1 }
|
|
||||||
.flatMap(allIdentitiesService.updatePushSubscriptions(deviceToken:))
|
|
||||||
.sink { _ in } receiveValue: { _ in }
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
userNotificationService.events
|
userNotificationService.events
|
||||||
.sink { [weak self] in self?.handle(event: $0) }
|
.sink { [weak self] in self?.handle(event: $0) }
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
@ -116,10 +118,12 @@ private extension RootViewModel {
|
||||||
.sink { _ in } receiveValue: { _ in }
|
.sink { _ in } receiveValue: { _ in }
|
||||||
.store(in: &self.cancellables)
|
.store(in: &self.cancellables)
|
||||||
|
|
||||||
if identityContext.identity.authenticated && !identityContext.identity.pending {
|
if identityContext.identity.authenticated,
|
||||||
|
!identityContext.identity.pending,
|
||||||
|
let registerForRemoteNotifications = self.registerForRemoteNotifications {
|
||||||
self.userNotificationService.isAuthorized(request: true)
|
self.userNotificationService.isAuthorized(request: true)
|
||||||
.filter { $0 }
|
.filter { $0 }
|
||||||
.zip(self.registerForRemoteNotifications())
|
.zip(registerForRemoteNotifications())
|
||||||
.filter { identityContext.identity.lastRegisteredDeviceToken != $1 }
|
.filter { identityContext.identity.lastRegisteredDeviceToken != $1 }
|
||||||
.map { ($1, identityContext.identity.pushSubscriptionAlerts) }
|
.map { ($1, identityContext.identity.pushSubscriptionAlerts) }
|
||||||
.flatMap(identityContext.service.createPushSubscription(deviceToken:alerts:))
|
.flatMap(identityContext.service.createPushSubscription(deviceToken:alerts:))
|
||||||
|
@ -136,8 +140,23 @@ private extension RootViewModel {
|
||||||
switch event {
|
switch event {
|
||||||
case let .willPresentNotification(_, completionHandler):
|
case let .willPresentNotification(_, completionHandler):
|
||||||
completionHandler(.banner)
|
completionHandler(.banner)
|
||||||
|
case let .didReceiveResponse(response, completionHandler):
|
||||||
|
let userInfo = response.notification.request.content.userInfo
|
||||||
|
|
||||||
|
if let identityIdString = userInfo[PushNotificationParsingService.identityIdUserInfoKey] as? String,
|
||||||
|
let identityId = Identity.Id(uuidString: identityIdString),
|
||||||
|
let pushNotificationJSON = userInfo[PushNotificationParsingService.pushNotificationUserInfoKey] as? Data,
|
||||||
|
let pushNotification = try? MastodonDecoder().decode(PushNotification.self, from: pushNotificationJSON) {
|
||||||
|
handle(pushNotification: pushNotification, identityId: identityId)
|
||||||
|
}
|
||||||
|
|
||||||
|
completionHandler()
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handle(pushNotification: PushNotification, identityId: Identity.Id) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue