From 366ea17d04ed797b00f9dd3c3e514f496460cd6d Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Thu, 28 Jan 2021 20:59:06 -0800 Subject: [PATCH] Notification registration improvements --- DB/Sources/DB/Identity/IdentityDatabase.swift | 4 ++- .../Services/UserNotificationService.swift | 14 ++++---- .../View Models/RootViewModel.swift | 33 ++++++++++++++----- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/DB/Sources/DB/Identity/IdentityDatabase.swift b/DB/Sources/DB/Identity/IdentityDatabase.swift index ed4f1a1..77af7bc 100644 --- a/DB/Sources/DB/Identity/IdentityDatabase.swift +++ b/DB/Sources/DB/Identity/IdentityDatabase.swift @@ -210,7 +210,9 @@ public extension IdentityDatabase { func fetchIdentitiesWithOutdatedDeviceTokens(deviceToken: Data) -> AnyPublisher<[Identity], Error> { databaseWriter.readPublisher( value: IdentityInfo.request(IdentityRecord.order(IdentityRecord.Columns.lastUsedAt.desc)) - .filter(IdentityRecord.Columns.lastRegisteredDeviceToken != deviceToken) + .filter(IdentityRecord.Columns.authenticated == true + && IdentityRecord.Columns.pending == false + && IdentityRecord.Columns.lastRegisteredDeviceToken != deviceToken) .fetchAll) .map { $0.map(Identity.init(info:)) } .eraseToAnyPublisher() diff --git a/ServiceLayer/Sources/ServiceLayer/Services/UserNotificationService.swift b/ServiceLayer/Sources/ServiceLayer/Services/UserNotificationService.swift index a0d50cd..52e5ef7 100644 --- a/ServiceLayer/Sources/ServiceLayer/Services/UserNotificationService.swift +++ b/ServiceLayer/Sources/ServiceLayer/Services/UserNotificationService.swift @@ -5,7 +5,7 @@ import Foundation import UserNotifications public struct UserNotificationService { - let events: AnyPublisher + public let events: AnyPublisher private let userNotificationClient: UserNotificationClient @@ -16,12 +16,14 @@ public struct UserNotificationService { } public extension UserNotificationService { - func isAuthorized() -> AnyPublisher { + typealias Event = UserNotificationClient.DelegateEvent + + func isAuthorized(request: Bool) -> AnyPublisher { getNotificationSettings() .map(\.authorizationStatus) .flatMap { status -> AnyPublisher in - if status == .notDetermined { - return requestProvisionalAuthorization().eraseToAnyPublisher() + if request, status == .notDetermined { + return requestAuthorization().eraseToAnyPublisher() } return Just(status == .authorized || status == .provisional) @@ -40,9 +42,9 @@ private extension UserNotificationService { .eraseToAnyPublisher() } - func requestProvisionalAuthorization() -> AnyPublisher { + func requestAuthorization() -> AnyPublisher { Future { promise in - userNotificationClient.requestAuthorization([.alert, .sound, .badge, .provisional]) { granted, error in + userNotificationClient.requestAuthorization([.alert, .sound, .badge]) { granted, error in if let error = error { promise(.failure(error)) } else { diff --git a/ViewModels/Sources/ViewModels/View Models/RootViewModel.swift b/ViewModels/Sources/ViewModels/View Models/RootViewModel.swift index d7c7a65..a9e94c4 100644 --- a/ViewModels/Sources/ViewModels/View Models/RootViewModel.swift +++ b/ViewModels/Sources/ViewModels/View Models/RootViewModel.swift @@ -32,13 +32,17 @@ public final class RootViewModel: ObservableObject { .sink { [weak self] in self?.identitySelected(id: $0) } .store(in: &cancellables) - userNotificationService.isAuthorized() + userNotificationService.isAuthorized(request: false) .filter { $0 } .zip(registerForRemoteNotifications()) .map { $1 } .flatMap(allIdentitiesService.updatePushSubscriptions(deviceToken:)) .sink { _ in } receiveValue: { _ in } .store(in: &cancellables) + + userNotificationService.events + .sink { [weak self] in self?.handle(event: $0) } + .store(in: &cancellables) } } @@ -112,17 +116,28 @@ private extension RootViewModel { .sink { _ in } receiveValue: { _ in } .store(in: &self.cancellables) - self.userNotificationService.isAuthorized() - .filter { $0 } - .zip(self.registerForRemoteNotifications()) - .filter { identityContext.identity.lastRegisteredDeviceToken != $1 } - .map { ($1, identityContext.identity.pushSubscriptionAlerts) } - .flatMap(identityContext.service.createPushSubscription(deviceToken:alerts:)) - .sink { _ in } receiveValue: { _ in } - .store(in: &self.cancellables) + if identityContext.identity.authenticated && !identityContext.identity.pending { + self.userNotificationService.isAuthorized(request: true) + .filter { $0 } + .zip(self.registerForRemoteNotifications()) + .filter { identityContext.identity.lastRegisteredDeviceToken != $1 } + .map { ($1, identityContext.identity.pushSubscriptionAlerts) } + .flatMap(identityContext.service.createPushSubscription(deviceToken:alerts:)) + .sink { _ in } receiveValue: { _ in } + .store(in: &self.cancellables) + } return NavigationViewModel(identityContext: identityContext) } .assign(to: &$navigationViewModel) } + + func handle(event: UserNotificationService.Event) { + switch event { + case let .willPresentNotification(_, completionHandler): + completionHandler(.banner) + default: + break + } + } }