diff --git a/OBAKitCore/Orchestration/CoreApplication.swift b/OBAKitCore/Orchestration/CoreApplication.swift index 44d4dd50..289f4a94 100644 --- a/OBAKitCore/Orchestration/CoreApplication.swift +++ b/OBAKitCore/Orchestration/CoreApplication.swift @@ -91,7 +91,7 @@ open class CoreApplication: NSObject, } /// This function reloads the REST API and Obaco Services. - private func refreshServices() { + public func refreshServices() { refreshRESTAPIService() refreshObacoService() apiServicesRefreshed() diff --git a/OBAWidget/Main/OBAAppIntents.swift b/OBAWidget/Main/OBAAppIntents.swift index 6a991c33..120e5b14 100644 --- a/OBAWidget/Main/OBAAppIntents.swift +++ b/OBAWidget/Main/OBAAppIntents.swift @@ -11,9 +11,9 @@ import OBAKitCore struct ConfigurationAppIntent: AppIntent, WidgetConfigurationIntent { static var title: LocalizedStringResource = "Bookmarks" - static var description: IntentDescription = IntentDescription("") - - - -} + static var description: IntentDescription = IntentDescription("Get the transit info") + func perform() async throws -> some IntentResult { + return .result() + } +} diff --git a/OBAWidget/Provider/WidgetDataProvider.swift b/OBAWidget/Provider/WidgetDataProvider.swift index 3c5c8d22..1a38820b 100644 --- a/OBAWidget/Provider/WidgetDataProvider.swift +++ b/OBAWidget/Provider/WidgetDataProvider.swift @@ -10,28 +10,24 @@ import CoreLocation /// `WidgetDataProvider` is responsible for fetching and providing relevant data to the widget timeline provider. class WidgetDataProvider: NSObject, ObservableObject { - - public let formatters = Formatters( - locale: Locale.autoupdatingCurrent, - calendar: Calendar.autoupdatingCurrent, - themeColors: ThemeColors.shared - ) - static let shared = WidgetDataProvider() + private let userDefaults = UserDefaults(suiteName: Bundle.main.appGroup!)! - private lazy var locationManager = CLLocationManager() private lazy var locationService = LocationService( userDefaults: userDefaults, locationManager: locationManager ) - + private lazy var app: CoreApplication = { - let bundledRegions = Bundle.main.path(forResource: "regions", ofType: "json")! - let config = CoreAppConfig(appBundle: Bundle.main, userDefaults: userDefaults, bundledRegionsFilePath: bundledRegions) + let config = CoreAppConfig( + appBundle: Bundle.main, + userDefaults: userDefaults, + bundledRegionsFilePath: Bundle.main.path(forResource: "regions", ofType: "json")! + ) return CoreApplication(config: config) }() - + private var bestAvailableBookmarks: [Bookmark] { var bookmarks = app.userDataStore.favoritedBookmarks if bookmarks.isEmpty { @@ -39,19 +35,43 @@ class WidgetDataProvider: NSObject, ObservableObject { } return bookmarks } - + + /// Dictionary mapping trip bookmark keys to arrival/departure data. + private var arrDepDic = [TripBookmarkKey: [ArrivalDeparture]]() + + /// Formatters for localization and styling. + let formatters = Formatters( + locale: Locale.autoupdatingCurrent, + calendar: Calendar.autoupdatingCurrent, + themeColors: ThemeColors.shared + ) + /// Loads arrivals and departures for all favorited bookmarks for the widget. - public func loadData() async { - guard let apiService = app.apiService else { return } - + func loadData() async { + + arrDepDic = [:] + app.refreshServices() + + guard let apiService = app.apiService else { + Logger.error("Failed to get REST API Service.") + return + } + let bookmarks = getBookmarks() - .filter { $0.isTripBookmark && $0.regionIdentifier == app.regionsService.currentRegion?.id } - - for bookmark in bookmarks { - await fetchArrivalData(for: bookmark, apiService: apiService) + guard !bookmarks.isEmpty else { + Logger.info("No bookmarks found to load data.") + return + } + + await withTaskGroup(of: Void.self) { group in + bookmarks.forEach { bookmark in + group.addTask { [weak self] in + await self?.fetchArrivalData(for: bookmark, apiService: apiService) + } + } } } - + /// Fetch arrival data for a specific bookmark and update the dictionary. private func fetchArrivalData(for bookmark: Bookmark, apiService: RESTAPIService) async { do { @@ -60,31 +80,27 @@ class WidgetDataProvider: NSObject, ObservableObject { minutesBefore: 0, minutesAfter: 60 ).entry - + await MainActor.run { - let keysAndDeps = stopArrivals.arrivalsAndDepartures.tripKeyGroupedElements - for (key, deps) in keysAndDeps { - self.arrDepDic[key] = deps + stopArrivals.arrivalsAndDepartures.tripKeyGroupedElements.forEach { key, deps in + arrDepDic[key] = deps } } } catch { - Logger - .error( - "Error fetching data for bookmark \(bookmark.name) with bookmark id: \(bookmark.id): \(error)" - ) + Logger.error(""" + Error fetching data for bookmark: '\(bookmark.name)' + (ID: \(bookmark.id)). Error: \(error.localizedDescription) + """) } } - + /// Looks up arrival and departure data for a given trip key. - public func lookupArrivalDeparture(with key: TripBookmarkKey) -> [ArrivalDeparture] { - return arrDepDic[key, default: []] + func lookupArrivalDeparture(with key: TripBookmarkKey) -> [ArrivalDeparture] { + arrDepDic[key, default: []] } - - /// Retrieves the best available bookmarks. + + /// Gets bookmarks of the selected region. public func getBookmarks() -> [Bookmark] { - return bestAvailableBookmarks + return bestAvailableBookmarks.filter { $0.isTripBookmark && $0.regionIdentifier == app.regionsService.currentRegion?.id } } - - /// Dictionary to store arrival and departure data grouped by trip keys. - private var arrDepDic = [TripBookmarkKey: [ArrivalDeparture]]() }