I am constructing an iOS widget that can show a person’s upcoming exercise for the present day.
The frontend of my app makes use of Angular/Ionic and it presently units the widget knowledge any time a person 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 knowledge right here
};
await WidgetsBridgePlugin.setItem({
key: this.key,
worth: JSON.stringify(this.widgetData),
group: this.appGroup
});
}
The TimelineProvider units the following person 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.knowledge(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 knowledge to be loaded
dispatchGroup.enter()
if let thumbUrlString = decodedWorkout.thumbUrl,
let thumbUrl = URL(string: thumbUrlString) {
URLSession.shared.dataTask(with: thumbUrl) { knowledge, _, _ in
defer { dispatchGroup.depart() }
if let knowledge = knowledge {
thumbImage = UIImage(knowledge: knowledge)
}
}.resume()
} else {
dispatchGroup.depart()
}
dispatchGroup.notify(queue: .primary) {
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 isn't any subsequent exercise knowledge obtainable
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 person would not full their exercise for a given day, Monday for instance, there may be nothing in place to set the widget knowledge for the next day when the present one passes (i.e. Monday’s knowledge will nonetheless be proven on Tuesday if a person hasn’t accomplished their exercise).
I need to have the ability to go an array of timeline entries containing the person’s exercises for the complete 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 incorporates an array of scheduled exercises (excluding at the moment’s exercise). The nextWorkout
key within the sharedUserDefaults desk simply incorporates the present day exercise. I am having hassle determining the place to go from right here.
Any perception on how finest to implement the specified behaviour could be unbelievable.