diff --git a/WordPress/Classes/Services/BloggingPromptsService.swift b/WordPress/Classes/Services/BloggingPromptsService.swift index bd68c13a6df3..3b3ec5d8af52 100644 --- a/WordPress/Classes/Services/BloggingPromptsService.swift +++ b/WordPress/Classes/Services/BloggingPromptsService.swift @@ -179,17 +179,44 @@ class BloggingPromptsService { // MARK: - Init + /// Initializes a service for blogging prompts. + /// + /// - Parameters: + /// - contextManager: The CoreDataStack instance. + /// - remote: When supplied, the service will use the specified remote service. + /// Otherwise, a remote service with the default account's credentials will be used. + /// - blog: When supplied, the service will perform blogging prompts requests for this specified blog. + /// Otherwise, this falls back to the default account's primary blog. required init?(contextManager: CoreDataStackSwift = ContextManager.shared, remote: BloggingPromptsServiceRemote? = nil, blog: Blog? = nil) { - guard let account = try? WPAccount.lookupDefaultWordPressComAccount(in: contextManager.mainContext), - let siteID = blog?.dotComID ?? account.primaryBlogID else { + let blogObjectID = blog?.objectID + let (siteID, remoteInstance) = contextManager.performQuery { mainContext in + // if a blog exists, then try to use the blog's ID. + var blogInContext: Blog? = nil + if let blogObjectID { + blogInContext = (try? mainContext.existingObject(with: blogObjectID)) as? Blog + } + + // fetch the default account and fall back to default values as needed. + guard let account = try? WPAccount.lookupDefaultWordPressComAccount(in: mainContext) else { + return (blogInContext?.dotComID, remote) + } + + return ( + blogInContext?.dotComID ?? account.primaryBlogID, + remote ?? .init(wordPressComRestApi: account.wordPressComRestV2Api) + ) + } + + guard let siteID, + let remoteInstance else { return nil } self.contextManager = contextManager self.siteID = siteID - self.remote = remote ?? .init(wordPressComRestApi: account.wordPressComRestV2Api) + self.remote = remoteInstance } } diff --git a/WordPress/Classes/Utility/Blogging Prompts/PromptRemindersScheduler.swift b/WordPress/Classes/Utility/Blogging Prompts/PromptRemindersScheduler.swift index 45b94b6d624e..847abf648fda 100644 --- a/WordPress/Classes/Utility/Blogging Prompts/PromptRemindersScheduler.swift +++ b/WordPress/Classes/Utility/Blogging Prompts/PromptRemindersScheduler.swift @@ -43,9 +43,16 @@ class PromptRemindersScheduler { /// - time: The user's preferred time to be notified. /// - completion: Closure called after the process completes. func schedule(_ schedule: BloggingRemindersScheduler.Schedule, for blog: Blog, time: Date? = nil, completion: @escaping (Result) -> Void) { + guard let context = blog.managedObjectContext else { + completion(.failure(Errors.unknown)) + return + } + guard schedule != .none else { - // If there's no schedule, then we don't need to request authorization - processSchedule(schedule, blog: blog, time: time, completion: completion) + context.performAndWait { + // If there's no schedule, then we don't need to request authorization + processSchedule(schedule, blog: blog, time: time, completion: completion) + } return } @@ -59,7 +66,9 @@ class PromptRemindersScheduler { return } - self.processSchedule(schedule, blog: blog, time: time, completion: completion) + context.performAndWait { + self.processSchedule(schedule, blog: blog, time: time, completion: completion) + } } } @@ -149,6 +158,7 @@ private extension PromptRemindersScheduler { return } + let title = blog.title let reminderTime = Time(from: time) ?? Constants.defaultTime let currentDate = currentDateProvider.date() promptsService.fetchPrompts(from: currentDate, number: Constants.promptsToFetch) { [weak self] prompts in @@ -177,7 +187,7 @@ private extension PromptRemindersScheduler { var lastScheduledPrompt: BloggingPrompt? = nil var notificationIds = [String]() promptsToSchedule.forEach { prompt in - guard let identifier = self.addLocalNotification(for: prompt, blog: blog, at: reminderTime) else { + guard let identifier = self.addLocalNotification(for: prompt, siteID: siteID, siteTitle: title, at: reminderTime) else { return } notificationIds.append(identifier) @@ -197,7 +207,10 @@ private extension PromptRemindersScheduler { return lastReminderDate }() - if let staticNotificationIds = self.addStaticNotifications(after: lastReminderDate, with: schedule, time: reminderTime, blog: blog) { + if let staticNotificationIds = self.addStaticNotifications(after: lastReminderDate, + with: schedule, + time: reminderTime, + siteID: siteID) { notificationIds.append(contentsOf: staticNotificationIds) } @@ -224,17 +237,13 @@ private extension PromptRemindersScheduler { /// - blog: The user's blog. /// - time: The preferred reminder time for the notification. /// - Returns: String representing the notification identifier. - func addLocalNotification(for prompt: BloggingPrompt, blog: Blog, at time: Time) -> String? { - guard blog.dotComID != nil else { - return nil - } - + func addLocalNotification(for prompt: BloggingPrompt, siteID: Int, siteTitle: String? = nil, at time: Time) -> String? { let content = UNMutableNotificationContent() content.title = Constants.notificationTitle - content.subtitle = blog.title ?? String() + content.subtitle = siteTitle ?? String() content.body = prompt.text content.categoryIdentifier = InteractiveNotificationsManager.NoteCategoryDefinition.bloggingPrompt.rawValue - content.userInfo = notificationPayload(for: blog, prompt: prompt) + content.userInfo = notificationPayload(for: siteID, prompt: prompt) guard let reminderDateComponents = reminderDateComponents(for: prompt, at: time) else { return nil @@ -282,12 +291,11 @@ private extension PromptRemindersScheduler { func addStaticNotifications(after afterDate: Date, with schedule: Schedule, time: Time, - blog: Blog, + siteID: Int, maxDays: Int = Constants.staticNotificationMaxDays) -> [String]? { guard case .weekdays(let weekdays) = schedule, maxDays > 0, - let maxDate = Calendar.current.date(byAdding: .day, value: maxDays, to: afterDate), - blog.dotComID != nil else { + let maxDate = Calendar.current.date(byAdding: .day, value: maxDays, to: afterDate) else { return nil } @@ -297,7 +305,7 @@ private extension PromptRemindersScheduler { content.title = Constants.notificationTitle content.body = Constants.staticNotificationContent content.categoryIdentifier = InteractiveNotificationsManager.NoteCategoryDefinition.bloggingPrompt.rawValue - content.userInfo = notificationPayload(for: blog) + content.userInfo = notificationPayload(for: siteID) var date = afterDate var identifiers = [String]() @@ -358,11 +366,7 @@ private extension PromptRemindersScheduler { return identifier } - func notificationPayload(for blog: Blog, prompt: BloggingPrompt? = nil) -> [AnyHashable: Any] { - guard let siteID = blog.dotComID?.intValue else { - return [:] - } - + func notificationPayload(for siteID: Int, prompt: BloggingPrompt? = nil) -> [AnyHashable: Any] { var userInfo: [AnyHashable: Any] = [BloggingPrompt.NotificationKeys.siteID: siteID] if let prompt = prompt { diff --git a/WordPress/Classes/ViewRelated/Blog/Blogging Prompts/BloggingPromptCoordinator.swift b/WordPress/Classes/ViewRelated/Blog/Blogging Prompts/BloggingPromptCoordinator.swift index 0e9e87cfd18d..38deb61add14 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blogging Prompts/BloggingPromptCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blogging Prompts/BloggingPromptCoordinator.swift @@ -112,6 +112,7 @@ private extension BloggingPromptCoordinator { guard let service = promptsServiceFactory.makeService(for: blog), let settings = service.localSettings, let reminderDays = settings.reminderDays, + let context = settings.managedObjectContext, settings.promptRemindersEnabled else { completion() return @@ -125,10 +126,12 @@ private extension BloggingPromptCoordinator { return } - // Reschedule the prompt reminders. - let schedule = BloggingRemindersScheduler.Schedule.weekdays(reminderDays.getActiveWeekdays()) - self.scheduler.schedule(schedule, for: blog, time: settings.reminderTimeDate()) { result in - completion() + context.performAndWait { + // Reschedule the prompt reminders. + let schedule = BloggingRemindersScheduler.Schedule.weekdays(reminderDays.getActiveWeekdays()) + self.scheduler.schedule(schedule, for: blog, time: settings.reminderTimeDate()) { result in + completion() + } } } }