I am constructing an iOS widget that can show a consumer’s upcoming exercise for the present day.
The frontend of my app makes use of Angular/Ionic and it presently units the widget information any time a consumer provides a exercise to their calendar through the use of the capacitor-widgetsbridge-plugin
, utilising the sharedUserDefaults
desk:
// widget.service.ts
import { WidgetsBridgePlugin } from 'capacitor-widgetsbridge-plugin';
async setWidgetData() {
this.widgetData = {
// set widget information right here
};
await WidgetsBridgePlugin.setItem({
key: this.key,
worth: JSON.stringify(this.widgetData),
group: this.appGroup
});
}
The TimelineProvider units the following consumer exercise like so:
// appWidget.iOS
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
let sharedDefaults = UserDefaults.init(suiteName: "group.app.title")
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let jsonString = sharedDefaults?.string(forKey: "nextWorkout"),
let jsonData = jsonString.information(utilizing: .utf8),
let decodedWorkout = attempt? decoder.decode(Exercise.self, from: jsonData) {
var thumbImage: UIImage?
let dispatchGroup = DispatchGroup()
// Use a dispatch group to attend for the picture information to be loaded
dispatchGroup.enter()
if let thumbUrlString = decodedWorkout.thumbUrl,
let thumbUrl = URL(string: thumbUrlString) {
URLSession.shared.dataTask(with: thumbUrl) { information, _, _ in
defer { dispatchGroup.depart() }
if let information = information {
thumbImage = UIImage(information: information)
}
}.resume()
} else {
dispatchGroup.depart()
}
dispatchGroup.notify(queue: .important) {
let entry = SimpleEntry(date: Date(), nextWorkout: decodedWorkout, thumbImage: thumbImage, configuration: configuration)
entries.append(entry)
let timeline = Timeline(entries: entries, coverage: .atEnd)
completion(timeline)
}
} else {
// Deal with the case the place there is no subsequent exercise information out there
let placeholderEntry = SimpleEntry(date: Date(), nextWorkout: Exercise.noDataFound(), thumbImage: nil, configuration: configuration)
entries.append(placeholderEntry)
let timeline = Timeline(entries: [placeholderEntry], coverage: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let nextWorkout: Exercise
let thumbImage: UIImage?
let configuration: ConfigurationIntent
}
struct Exercise: Codable {
let title: String
let date: Date
let time: String?
let thumbUrl: String?
}
The issue with that is that if a consumer would not full their exercise for a given day, Monday for instance, there’s nothing in place to set the widget information for the next day when the present one passes (i.e. Monday’s information will nonetheless be proven on Tuesday if a consumer hasn’t accomplished their exercise).
I would like to have the ability to cross an array of timeline entries containing the consumer’s exercises for all the week forward. I am comparatively new to Swift and Widget growth so issues have not fairly clicked in my head but.
Up to now, I’ve created a further key within the sharedUserDefaults
desk on the frontend known as upcomingWorkouts
which accommodates an array of scheduled exercises (excluding right this moment’s exercise). The nextWorkout
key within the sharedUserDefaults desk simply accommodates the present day exercise. I am having bother determining the place to go from right here.
Any perception on how finest to implement the specified behaviour can be unimaginable.