// // WidgetHelper.swift // Reader // // Created by Shadowfacts on 6/19/22. // import Foundation import WidgetKit import Persistence import OSLog private let logger = Logger(subsystem: "net.shadowfacts.Reader", category: "WidgetHelper") private let signposter = OSSignposter(logger: logger) struct WidgetHelper { private init() {} private static let maxDisplayableItems = 8 static func updateWidgetData(fervorController: FervorController) async { // Accessing CoreData from the widget extension puts us over the memory limit, so we pre-generate all the data it needs and save it to disk let context = fervorController.persistentContainer.backgroundContext let prioritizedItems: [WidgetData.Item] = await context.perform { let req = Item.fetchRequest() req.sortDescriptors = [NSSortDescriptor(key: "published", ascending: false)] req.fetchLimit = 32 req.predicate = NSPredicate(format: "read = NO") let state = signposter.beginInterval("fetch") var items = (try? context.fetch(req)) ?? [] signposter.endInterval("fetch", state) var prioritizedItems: [Item] = [] while prioritizedItems.count < maxDisplayableItems { let firstFromUnseenFeedIdx = items.firstIndex { item in prioritizedItems.allSatisfy { existing in existing.feed != item.feed } } if let firstFromUnseenFeedIdx { prioritizedItems.append(items.remove(at: firstFromUnseenFeedIdx)) } else if let item = items.first { prioritizedItems.append(item) items.removeFirst() } else { break } } return prioritizedItems.map { WidgetData.Item(id: $0.id!, feedTitle: $0.feed?.title, title: $0.title, published: $0.published) } } if let item = prioritizedItems.first { logger.info("Saving widget data with first item: '\(item.title ?? "", privacy: .public)'") } WidgetData(recentItems: prioritizedItems).save(account: fervorController.account!) WidgetCenter.shared.reloadAllTimelines() } }