Search code examples
swiftswiftuiwidgetios14widgetkit

IntentHandler doesn't work with widgetFamily


I added an Intent Extension Target to my project and I'm trying to distinguish which widget type is displayed during edit mode in IntentHandler and based on this information I want to populate the "Edit Widget" list with small, medium or large widget types.

When I use @Environment(\.widgetFamily) var family it gives me .systemMedium all the time but I'm editing a large size of widget at that time.

For ex; When I long-press a small widget to edit and select another widget type from the list, and I see a list full of items containing small, medium, and large widget types from IntentHandler but I want to see only small types.

The question is that possible to fill the list depending on which type of widget that I'm currently editing?


Solution

  • Assuming I understand what you’re trying to do, I think the answer is no, it’s not possible. To replicate what apps like Widgetsmith do, you’ll need to define 3 separate Widgets, one for each of small, medium, and large supportedFamily sizes. Then define 3 separate Intents, one for each widget, and implement a separate Intent Handler for each one.

    Something like this:

    @main
    struct MyWidgetBundle: WidgetBundle {
        @WidgetBundleBuilder
        var body: some Widget {
            SmallWidget()
            MediumWidget()
            LargeWidget()
        }
    }
    
    struct SmallWidget: Widget {
        let kind: String = "SmallWidget"
        
        var body: some WidgetConfiguration {
            IntentConfiguration(kind: kind, intent: SmallWidgetIntent.self, provider: TimelineProvider()) { entry in
                WidgetView(entry: entry)
            }
            .configurationDisplayName("Small Widget")
            .supportedFamilies([.systemSmall])
        }
    }
    
    struct MediumWidget: Widget {
        let kind: String = "MediumWidget"
        
        var body: some WidgetConfiguration {
            IntentConfiguration(kind: kind, intent: MediumWidgetIntent.self, provider: TimelineProvider()) { entry in
                WidgetView(entry: entry)
            }
            .configurationDisplayName("Medium Widget")
            .supportedFamilies([.systemMedium])
        }
    }
    
    struct LargeWidget: Widget {
        let kind: String = "LargeWidget"
        
        var body: some WidgetConfiguration {
            IntentConfiguration(kind: kind, intent: LargeWidgetIntent.self, provider: TimelineProvider()) { entry in
                WidgetView(entry: entry)
            }
            .configurationDisplayName("Large Widget")
            .supportedFamilies([.systemLarge])
        }
    }
    

    In your Intent Definition file, define SmallWidgetIntent, MediumWidgetIntent, and LargeWidgetIntent. And then in your intent handler, you’d implement SmallWidgetIntentHandling, MediumWidgetIntentHandling, and LargeWidgetIntentHandling, which would return the correct options for their associated size.