vanilla_splsh
vanilla_splsh

Reputation: 163

How to get different data for each widget

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

Answers (1)

pawello2222
pawello2222

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

Related Questions