From 23a06f04ab6300280dd3b2c3cb068086a74b44d7 Mon Sep 17 00:00:00 2001 From: ihugo Date: Mon, 12 Apr 2021 21:42:43 +0800 Subject: [PATCH] fixed: subscription API call --- CoreDataStack/Entity/Subscription.swift | 1 + .../Settings/SettingsViewController.swift | 39 +++-- .../Scene/Settings/SettingsViewModel.swift | 156 ++++++++++++------ .../SettingsAppearanceTableViewCell.swift | 10 +- .../APIService/APIService+Notifications.swift | 28 ++++ .../APIService+CoreData+Notification.swift | 16 +- .../MastodonSDK/API/Mastodon+API+Push.swift | 107 +++++++++--- .../Entity/Mastodon+Entity+Subscription.swift | 45 ++++- SubscriptionAlerts.swift | 42 ++--- 9 files changed, 320 insertions(+), 124 deletions(-) diff --git a/CoreDataStack/Entity/Subscription.swift b/CoreDataStack/Entity/Subscription.swift index 5d65129e2..7d7a74570 100644 --- a/CoreDataStack/Entity/Subscription.swift +++ b/CoreDataStack/Entity/Subscription.swift @@ -50,6 +50,7 @@ public extension Subscription { setting.id = property.id setting.endpoint = property.endpoint setting.serverKey = property.serverKey + setting.type = property.type return setting } diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index 8da4faeaf..73dc43df4 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -12,6 +12,8 @@ import ActiveLabel import CoreData import CoreDataStack +// iTODO: when to ask permission to Use Notifications + class SettingsViewController: UIViewController, NeedsDependency { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } @@ -26,7 +28,7 @@ class SettingsViewController: UIViewController, NeedsDependency { let follow = L10n.Scene.Settings.Section.Notifications.Trigger.follow let noOne = L10n.Scene.Settings.Section.Notifications.Trigger.noOne let menu = UIMenu( - image: UIImage(systemName: "escape"), + image: nil, identifier: nil, options: .displayInline, children: [ @@ -173,7 +175,9 @@ class SettingsViewController: UIViewController, NeedsDependency { } private func setupTableView() { - viewModel.dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in + viewModel.dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { [weak self] (tableView, indexPath, item) -> UITableViewCell? in + guard let self = self else { return nil } + switch item { case .apperance(let item): guard let cell = tableView.dequeueReusableCell(withIdentifier: "SettingsAppearanceTableViewCell") as? SettingsAppearanceTableViewCell else { @@ -227,6 +231,10 @@ class SettingsViewController: UIViewController, NeedsDependency { .store(in: &disposeBag) } + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", ((#file as NSString).lastPathComponent), #line, #function) + } + // Mark: - Actions @objc func doneButtonDidClick() { dismiss(animated: true, completion: nil) @@ -306,38 +314,39 @@ extension SettingsViewController { guard let settings = self.viewModel.setting.value else { return } guard let triggerBy = settings.triggerBy else { return } - var values: [Bool?]? - if let alerts = settings.subscription?.first(where: { (s) -> Bool in + guard let alerts = settings.subscription?.first(where: { (s) -> Bool in return s.type == settings.triggerBy - })?.alert { - var items = [Bool?]() - items.append(alerts.favourite) - items.append(alerts.follow) - items.append(alerts.reblog) - items.append(alerts.mention) - values = items + })?.alert else { + return } - guard var alertValues = values else { return } - guard alertValues.count >= 4 else { return } + var alertValues = [Bool?]() + alertValues.append(alerts.favourite?.boolValue) + alertValues.append(alerts.follow?.boolValue) + alertValues.append(alerts.reblog?.boolValue) + alertValues.append(alerts.mention?.boolValue) + // need to update `alerts` to make update API with correct parameter switch title { case L10n.Scene.Settings.Section.Notifications.favorites: alertValues[0] = isOn + alerts.favourite = NSNumber(booleanLiteral: isOn) case L10n.Scene.Settings.Section.Notifications.follows: alertValues[1] = isOn + alerts.follow = NSNumber(booleanLiteral: isOn) case L10n.Scene.Settings.Section.Notifications.boosts: alertValues[2] = isOn + alerts.reblog = NSNumber(booleanLiteral: isOn) case L10n.Scene.Settings.Section.Notifications.mentions: alertValues[3] = isOn + alerts.mention = NSNumber(booleanLiteral: isOn) default: break } - self.viewModel.alertUpdate.send((triggerBy: triggerBy, values: alertValues)) + self.viewModel.updateSubscriptionSubject.send((triggerBy: triggerBy, values: alertValues)) } } extension SettingsViewController: SettingsAppearanceTableViewCellDelegate { func settingsAppearanceCell(_ view: SettingsAppearanceTableViewCell, didSelect: SettingsItem.AppearanceMode) { - print("[SettingsViewController]: didSelect \(didSelect)") guard let setting = self.viewModel.setting.value else { return } context.managedObjectContext.performChanges { diff --git a/Mastodon/Scene/Settings/SettingsViewModel.swift b/Mastodon/Scene/Settings/SettingsViewModel.swift index 1f5bf4e4f..6a817ffff 100644 --- a/Mastodon/Scene/Settings/SettingsViewModel.swift +++ b/Mastodon/Scene/Settings/SettingsViewModel.swift @@ -20,6 +20,9 @@ class SettingsViewModel: NSObject, NeedsDependency { var dataSource: UITableViewDiffableDataSource! var disposeBag = Set() + var updateDisposeBag = Set() + var createDisposeBag = Set() + let viewDidLoad = PassthroughSubject() lazy var fetchResultsController: NSFetchedResultsController = { let fetchRequest = Setting.sortedFetchRequest @@ -42,10 +45,14 @@ class SettingsViewModel: NSObject, NeedsDependency { }() let setting = CurrentValueSubject(nil) - /// trigger when - /// - init alerts - /// - change subscription status everytime - let alertUpdate = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>() + /// create a subscription when: + /// - does not has one + /// - does not find subscription for selected trigger when change trigger + let createSubscriptionSubject = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>() + + /// update a subscription when: + /// - change switch for specified alerts + let updateSubscriptionSubject = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>() lazy var notificationDefaultValue: [String: [Bool?]] = { let followerSwitchItems: [Bool?] = [true, nil, true, true] @@ -77,7 +84,85 @@ class SettingsViewModel: NSObject, NeedsDependency { } func transform(input: Input?) -> Output? { - //guard let input = input else { return nil } + typealias SubscriptionResponse = Mastodon.Response.Content + createSubscriptionSubject + .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) + .sink { _ in + } receiveValue: { [weak self] (arg) in + let (triggerBy, values) = arg + guard let self = self else { + return + } + guard let activeMastodonAuthenticationBox = + self.context.authenticationService.activeMastodonAuthenticationBox.value else { + return + } + guard values.count >= 4 else { + return + } + + self.createDisposeBag.removeAll() + typealias Query = Mastodon.API.Notification.CreateSubscriptionQuery + let domain = activeMastodonAuthenticationBox.domain + let query = Query( + endpoint: "http://www.google.com", + p256dh: "BLQELIDm-6b9Bl07YrEuXJ4BL_YBVQ0dvt9NQGGJxIQidJWHPNa9YrouvcQ9d7_MqzvGS9Alz60SZNCG3qfpk=", + auth: "4vQK-SvRAN5eo-8ASlrwA==", + favourite: values[0], + follow: values[1], + reblog: values[2], + mention: values[3], + poll: nil) + self.context.apiService.changeSubscription( + domain: domain, + mastodonAuthenticationBox: activeMastodonAuthenticationBox, + query: query, + triggerBy: triggerBy + ) + .sink { (_) in + } receiveValue: { (_) in + } + .store(in: &self.createDisposeBag) + } + .store(in: &disposeBag) + + updateSubscriptionSubject + .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) + .sink { _ in + } receiveValue: { [weak self] (arg) in + let (triggerBy, values) = arg + guard let self = self else { + return + } + guard let activeMastodonAuthenticationBox = + self.context.authenticationService.activeMastodonAuthenticationBox.value else { + return + } + guard values.count >= 4 else { + return + } + + self.updateDisposeBag.removeAll() + typealias Query = Mastodon.API.Notification.UpdateSubscriptionQuery + let domain = activeMastodonAuthenticationBox.domain + let query = Query( + favourite: values[0], + follow: values[1], + reblog: values[2], + mention: values[3], + poll: nil) + self.context.apiService.updateSubscription( + domain: domain, + mastodonAuthenticationBox: activeMastodonAuthenticationBox, + query: query, + triggerBy: triggerBy + ) + .sink { (_) in + } receiveValue: { (_) in + } + .store(in: &self.updateDisposeBag) + } + .store(in: &disposeBag) // build data for table view buildDataSource() @@ -85,36 +170,6 @@ class SettingsViewModel: NSObject, NeedsDependency { // request subsription data for updating or initialization requestSubscription() - typealias SubscriptionResponse = Mastodon.Response.Content - alertUpdate - .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) - .flatMap { [weak self] (arg) -> AnyPublisher in - let (triggerBy, values) = arg - guard let self = self else { - return Empty().eraseToAnyPublisher() - } - guard let activeMastodonAuthenticationBox = - self.context.authenticationService.activeMastodonAuthenticationBox.value else { - return Empty().eraseToAnyPublisher() - } - guard values.count >= 4 else { - return Empty().eraseToAnyPublisher() - } - - typealias Query = Mastodon.API.Notification.CreateSubscriptionQuery - let domain = activeMastodonAuthenticationBox.domain - return self.context.apiService.changeSubscription( - domain: domain, - mastodonAuthenticationBox: activeMastodonAuthenticationBox, - query: Query(favourite: values[0], follow: values[1], reblog: values[2], mention: values[3], poll: nil), - triggerBy: triggerBy) - } - .sink { _ in - } receiveValue: { (subscription) in - } - .store(in: &disposeBag) - - do { try fetchResultsController.performFetch() setting.value = fetchResultsController.fetchedObjects?.first @@ -141,15 +196,15 @@ class SettingsViewModel: NSObject, NeedsDependency { return s.type == settings?.triggerBy })?.alert { var items = [Bool?]() - items.append(alerts.favourite) - items.append(alerts.follow) - items.append(alerts.reblog) - items.append(alerts.mention) + items.append(alerts.favourite?.boolValue) + items.append(alerts.follow?.boolValue) + items.append(alerts.reblog?.boolValue) + items.append(alerts.mention?.boolValue) switches = items } else if let triggerBy = settings?.triggerBy, let values = self.notificationDefaultValue[triggerBy] { switches = values - self.alertUpdate.send((triggerBy: triggerBy, values: values)) + self.createSubscriptionSubject.send((triggerBy: triggerBy, values: values)) } else { // fallback a default value let anyone = L10n.Scene.Settings.Section.Notifications.Trigger.anyone @@ -178,7 +233,6 @@ class SettingsViewModel: NSObject, NeedsDependency { L10n.Scene.Settings.Section.BoringZone.privacy] var boringLinkItems = [SettingsItem]() for l in boringLinks { - // FIXME: update color in both light and dark mode let item = SettingsItem.boringZone(item: SettingsItem.Link(title: l, color: .systemBlue)) boringLinkItems.append(item) } @@ -191,7 +245,6 @@ class SettingsViewModel: NSObject, NeedsDependency { L10n.Scene.Settings.Section.SpicyZone.signOut] var spicyLinkItems = [SettingsItem]() for l in spicyLinks { - // FIXME: update color in both light and dark mode let item = SettingsItem.boringZone(item: SettingsItem.Link(title: l, color: .systemRed)) spicyLinkItems.append(item) } @@ -203,15 +256,11 @@ class SettingsViewModel: NSObject, NeedsDependency { } private func buildDataSource() { - setting.filter({ $0 != nil }).sink { [weak self] (settings) in + setting.sink { [weak self] (settings) in guard let self = self else { return } self.processDataSource(settings) } .store(in: &disposeBag) - - // init with no subscription for notification - let settings: Setting? = nil - self.processDataSource(settings) } private func requestSubscription() { @@ -229,11 +278,22 @@ class SettingsViewModel: NSObject, NeedsDependency { domain: domain, mastodonAuthenticationBox: activeMastodonAuthenticationBox) } - .sink { _ in + .sink { [weak self] competion in + if case .failure(_) = competion { + // create a subscription when doesn't has one + let anyone = L10n.Scene.Settings.Section.Notifications.Trigger.anyone + if let values = self?.notificationDefaultValue[anyone] { + self?.createSubscriptionSubject.send((triggerBy: anyone, values: values)) + } + } } receiveValue: { (subscription) in } .store(in: &disposeBag) } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", ((#file as NSString).lastPathComponent), #line, #function) + } } // MARK: - NSFetchedResultsControllerDelegate diff --git a/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift b/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift index 83932a62e..7419e2cad 100644 --- a/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift +++ b/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift @@ -86,12 +86,7 @@ class AppearanceView: UIView { class SettingsAppearanceTableViewCell: UITableViewCell { weak var delegate: SettingsAppearanceTableViewCellDelegate? - var appearance: SettingsItem.AppearanceMode = .automatic { - didSet { - guard let delegate = self.delegate else { return } - delegate.settingsAppearanceCell(self, didSelect: appearance) - } - } + var appearance: SettingsItem.AppearanceMode = .automatic lazy var stackView: UIStackView = { let view = UIStackView() @@ -203,5 +198,8 @@ class SettingsAppearanceTableViewCell: UITableViewCell { if sender == darkTap { appearance = .dark } + + guard let delegate = self.delegate else { return } + delegate.settingsAppearanceCell(self, didSelect: appearance) } } diff --git a/Mastodon/Service/APIService/APIService+Notifications.swift b/Mastodon/Service/APIService/APIService+Notifications.swift index 9bbcd180f..b32251544 100644 --- a/Mastodon/Service/APIService/APIService+Notifications.swift +++ b/Mastodon/Service/APIService/APIService+Notifications.swift @@ -62,5 +62,33 @@ extension APIService { .eraseToAnyPublisher() }.eraseToAnyPublisher() } + + func updateSubscription( + domain: String, + mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox, + query: Mastodon.API.Notification.UpdateSubscriptionQuery, + triggerBy: String + ) -> AnyPublisher, Error> { + let authorization = mastodonAuthenticationBox.userAuthorization + + return Mastodon.API.Notification.updateSubscription( + session: session, + domain: domain, + authorization: authorization, + query: query + ) + .flatMap { response -> AnyPublisher, Error> in + return self.backgroundManagedObjectContext.performChanges { + _ = APIService.CoreData.createOrMergeSubscription( + into: self.backgroundManagedObjectContext, + entity: response.value, + domain: domain, + triggerBy: triggerBy) + } + .setFailureType(to: Error.self) + .map { _ in return response } + .eraseToAnyPublisher() + }.eraseToAnyPublisher() + } } diff --git a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Notification.swift b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Notification.swift index b3cd004b0..8dc189734 100644 --- a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Notification.swift +++ b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Notification.swift @@ -94,11 +94,12 @@ extension APIService.CoreData { type: triggerBy ?? setting.triggerBy ?? "") let alertEntity = entity.alerts let alert = SubscriptionAlerts.Property( - favourite: alertEntity.favourite, - follow: alertEntity.follow, - mention: alertEntity.mention, - poll: alertEntity.poll, - reblog: alertEntity.reblog) + favourite: alertEntity.favouriteNumber, + follow: alertEntity.followNumber, + mention: alertEntity.mentionNumber, + poll: alertEntity.pollNumber, + reblog: alertEntity.reblogNumber + ) if let oldSubscription = oldSubscription { oldSubscription.updateIfNeed(property: property) if nil == oldSubscription.alert { @@ -109,9 +110,10 @@ extension APIService.CoreData { oldSubscription.alert?.updateIfNeed(property: alert) } - if oldSubscription.alert?.hasChanges == true { + if oldSubscription.alert?.hasChanges == true || oldSubscription.hasChanges { // don't expand subscription if add existed subscription - setting.mutableSetValue(forKey: #keyPath(Setting.subscription)).add(oldSubscription) + //setting.mutableSetValue(forKey: #keyPath(Setting.subscription)).add(oldSubscription) + oldSubscription.didUpdate(at: Date()) } return (oldSubscription, false) } else { diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Push.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Push.swift index 555dd22d5..3618b06c5 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Push.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Push.swift @@ -47,9 +47,9 @@ extension Mastodon.API.Notification { .eraseToAnyPublisher() } - /// Change types of notifications + /// Subscribe to push notifications /// - /// Using this endpoint to change types of notifications + /// Add a Web Push API subscription to receive notifications. Each access token can have one push subscription. If you create a new subscription, the old subscription is deleted. /// /// - Since: 2.4.0 /// - Version: 3.3.0 @@ -80,6 +80,40 @@ extension Mastodon.API.Notification { } .eraseToAnyPublisher() } + + /// Change types of notifications + /// + /// Updates the current push subscription. Only the data part can be updated. To change fundamentals, a new subscription must be created instead. + /// + /// - Since: 2.4.0 + /// - Version: 3.3.0 + /// # Last Update + /// 2021/4/9 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/notifications/push/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - authorization: User token. Could be nil if status is public + /// - Returns: `AnyPublisher` contains `Poll` nested in the response + public static func updateSubscription( + session: URLSession, + domain: String, + authorization: Mastodon.API.OAuth.Authorization?, + query: UpdateSubscriptionQuery + ) -> AnyPublisher, Error> { + let request = Mastodon.API.put( + url: pushEndpointURL(domain: domain), + query: query, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: Mastodon.Entity.Subscription.self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } } extension Mastodon.API.Notification { @@ -88,27 +122,56 @@ extension Mastodon.API.Notification { var contentType: String? var body: Data? - let follow: Bool? - let favourite: Bool? - let reblog: Bool? - let mention: Bool? - let poll: Bool? - - // iTODO: missing parameters - // subscription[endpoint] - // subscription[keys][p256dh] - // subscription[keys][auth] - public init(favourite: Bool?, - follow: Bool?, - reblog: Bool?, - mention: Bool?, - poll: Bool?) { - self.follow = follow - self.favourite = favourite - self.reblog = reblog - self.mention = mention - self.poll = poll + public init( + endpoint: String, + p256dh: String, + auth: String, + favourite: Bool?, + follow: Bool?, + reblog: Bool?, + mention: Bool?, + poll: Bool? + ) { + queryItems = [URLQueryItem]() + queryItems?.append(URLQueryItem(name: "subscription[endpoint]", value: endpoint)) + queryItems?.append(URLQueryItem(name: "subscription[keys][p256dh]", value: p256dh)) + queryItems?.append(URLQueryItem(name: "subscription[keys][auth]", value: auth)) + + if let followValue = follow?.queryItemValue { + let followItem = URLQueryItem(name: "data[alerts][follow]", value: followValue) + queryItems?.append(followItem) + } + + if let favouriteValue = favourite?.queryItemValue { + let favouriteItem = URLQueryItem(name: "data[alerts][favourite]", value: favouriteValue) + queryItems?.append(favouriteItem) + } + + if let reblogValue = reblog?.queryItemValue { + let reblogItem = URLQueryItem(name: "data[alerts][reblog]", value: reblogValue) + queryItems?.append(reblogItem) + } + + if let mentionValue = mention?.queryItemValue { + let mentionItem = URLQueryItem(name: "data[alerts][mention]", value: mentionValue) + queryItems?.append(mentionItem) + } + } + } + + public struct UpdateSubscriptionQuery: PutQuery { + var queryItems: [URLQueryItem]? + var contentType: String? + var body: Data? + + public init( + favourite: Bool?, + follow: Bool?, + reblog: Bool?, + mention: Bool?, + poll: Bool? + ) { queryItems = [URLQueryItem]() if let followValue = follow?.queryItemValue { diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Subscription.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Subscription.swift index 24bb2c189..3ae5718e6 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Subscription.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Subscription.swift @@ -32,11 +32,46 @@ extension Mastodon.Entity { } public struct Alerts: Codable { - public let follow: Bool - public let favourite: Bool - public let reblog: Bool - public let mention: Bool - public let poll: Bool + public let follow: Bool? + public let favourite: Bool? + public let reblog: Bool? + public let mention: Bool? + public let poll: Bool? + + public var followNumber: NSNumber? { + guard let value = follow else { return nil } + return NSNumber(booleanLiteral: value) + } + public var favouriteNumber: NSNumber? { + guard let value = favourite else { return nil } + return NSNumber(booleanLiteral: value) + } + public var reblogNumber: NSNumber? { + guard let value = reblog else { return nil } + return NSNumber(booleanLiteral: value) + } + public var mentionNumber: NSNumber? { + guard let value = mention else { return nil } + return NSNumber(booleanLiteral: value) + } + public var pollNumber: NSNumber? { + guard let value = poll else { return nil } + return NSNumber(booleanLiteral: value) + } + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + var id = try? container.decode(String.self, forKey: .id) + if nil == id, let numId = try? container.decode(Int.self, forKey: .id) { + id = String(numId) + } + self.id = id ?? "" + + endpoint = try container.decode(String.self, forKey: .endpoint) + alerts = try container.decode(Alerts.self, forKey: .alerts) + serverKey = try container.decode(String.self, forKey: .serverKey) } } } diff --git a/SubscriptionAlerts.swift b/SubscriptionAlerts.swift index 928a777f5..c240a02a5 100644 --- a/SubscriptionAlerts.swift +++ b/SubscriptionAlerts.swift @@ -11,11 +11,11 @@ import CoreData @objc(SubscriptionAlerts) public final class SubscriptionAlerts: NSManagedObject { - @NSManaged public var follow: Bool - @NSManaged public var favourite: Bool - @NSManaged public var reblog: Bool - @NSManaged public var mention: Bool - @NSManaged public var poll: Bool + @NSManaged public var follow: NSNumber? + @NSManaged public var favourite: NSNumber? + @NSManaged public var reblog: NSNumber? + @NSManaged public var mention: NSNumber? + @NSManaged public var poll: NSNumber? @NSManaged public private(set) var createdAt: Date @NSManaged public private(set) var updatedAt: Date @@ -48,35 +48,35 @@ public extension SubscriptionAlerts { return alerts } - func update(favourite: Bool) { + func update(favourite: NSNumber?) { guard self.favourite != favourite else { return } self.favourite = favourite didUpdate(at: Date()) } - func update(follow: Bool) { + func update(follow: NSNumber?) { guard self.follow != follow else { return } self.follow = follow didUpdate(at: Date()) } - func update(mention: Bool) { + func update(mention: NSNumber?) { guard self.mention != mention else { return } self.mention = mention didUpdate(at: Date()) } - func update(poll: Bool) { + func update(poll: NSNumber?) { guard self.poll != poll else { return } self.poll = poll didUpdate(at: Date()) } - func update(reblog: Bool) { + func update(reblog: NSNumber?) { guard self.reblog != reblog else { return } self.reblog = reblog @@ -86,18 +86,18 @@ public extension SubscriptionAlerts { public extension SubscriptionAlerts { struct Property { - public let favourite: Bool - public let follow: Bool - public let mention: Bool - public let poll: Bool - public let reblog: Bool + public let favourite: NSNumber? + public let follow: NSNumber? + public let mention: NSNumber? + public let poll: NSNumber? + public let reblog: NSNumber? - public init(favourite: Bool?, follow: Bool?, mention: Bool?, poll: Bool?, reblog: Bool?) { - self.favourite = favourite ?? true - self.follow = follow ?? true - self.mention = mention ?? true - self.poll = poll ?? true - self.reblog = reblog ?? true + public init(favourite: NSNumber?, follow: NSNumber?, mention: NSNumber?, poll: NSNumber?, reblog: NSNumber?) { + self.favourite = favourite + self.follow = follow + self.mention = mention + self.poll = poll + self.reblog = reblog } }