Reputation: 163
I'm reading up on WidgetBundle
and having multiple Widgets - in my case I want to offer the user two different widgets based on gender. So the user can choose to see the Mens one and also the Womens one.
For each widget the timeline would need to call a different API - what's the best way to do this? I can't see any examples of having a WidgetBundle
and modifying the timelines to be slightly different for each (it's literally a parameter in the api URL). Or is this not possible?
Code:
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
// Call API here and get gifts
// I'd want to set "womens" or "mens" in the api url here depending on the widget
let entry = WidgetTimelineEntry(date: Date(), gifts: gifts, widgetURL: widgetURL)
let date = Calendar.current.date(byAdding: .minute, value: 30, to: Date())!
let timeline = Timeline(entries: [entry], policy: TimelineReloadPolicy.after(date))
completion(timeline)
}
...
struct WidgetTimelineEntry: TimelineEntry {
let date: Date
let gifts: [Product]
let widgetURL: URL
}
struct GiftWidgetEntryView : View {
@Environment(\.widgetFamily) private var widgetFamily
var entry: Provider.Entry
var body: some View {
Group {
if widgetFamily == .systemMedium {
MediumWidgetView(gifts: entry.gifts)
}
}
.widgetURL(entry.widgetURL)
}
}
@main
struct GiftWidgets: WidgetBundle {
@WidgetBundleBuilder
var body: some Widget {
// My widgets
WomensWidget()
MensWidget()
}
}
struct WomensWidget: Widget {
let kind: String = "WomensWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
GiftWidgetEntryView(entry: entry)
}
.configurationDisplayName("Women's Gift Widget")
.description("See some womens gift ideas")
}
}
struct MensWidget: Widget {
let kind: String = "MensWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
GiftWidgetEntryView(entry: entry)
}
.configurationDisplayName("Men's Gift Widget")
.description("See some mens gift ideas")
}
}
Upvotes: 3
Views: 1720
Reputation: 54591
You can pass the gender
parameter to the Provider
so it can be used later in the getTimeline
function:
enum Gender {
case male, female // ...
}
struct Provider: TimelineProvider {
let gender: Gender
...
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
// Configure the API call based on the `gender` property
let entry = WidgetTimelineEntry(date: Date(), gifts: gifts, widgetURL: widgetURL)
let date = Calendar.current.date(byAdding: .minute, value: 30, to: Date())!
let timeline = Timeline(entries: [entry], policy: TimelineReloadPolicy.after(date))
completion(timeline)
}
}
Then, you only need to pass the correct parameter to the Provider
:
struct WomensWidget: Widget {
let kind: String = "WomensWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider(gender: .female)) { entry in
GiftWidgetEntryView(entry: entry)
}
.configurationDisplayName("Women's Gift Widget")
.description("See some womens gift ideas")
}
}
struct MensWidget: Widget {
let kind: String = "MensWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider(gender: .male)) { entry in
GiftWidgetEntryView(entry: entry)
}
.configurationDisplayName("Men's Gift Widget")
.description("See some mens gift ideas")
}
}
Upvotes: 3