swiftswiftuiwidgetkitios17appintents

Widget not updated when selecting AppEnum with AppIntents


I'm trying to select options for a widget using a drop-down, and provide the user with a limited list of options that will never change. I'm using an AppEnum as recommended. However, when selecting an element from the back of the widget, the widget doesn't update.

Here's my code:

import AppIntents
import SwiftUI
import WidgetKit

struct TestProvider: AppIntentTimelineProvider {
    func placeholder(in context: Context) -> TestEntry {
        TestEntry(date: .now, bool: false, str: "Apple", enum1: TestEnum.test1)
    }
    
    func snapshot(for configuration: TestIntent, in context: Context) async -> TestEntry {
        return TestEntry(date: .now, bool: false, str: "Apple", enum1: TestEnum.test1)
    }
    
    func timeline(for configuration: TestIntent, in context: Context) async -> Timeline<TestEntry> {
        let testBool = configuration.bool
        let testStr = configuration.str

        return Timeline(entries: [
            TestEntry(
                date: .now,
                bool: testBool,
                str: testStr,
                enum1: TestEnum.test1
            )
        ], policy: .atEnd)
    }
}

struct TestEntry: TimelineEntry {
    let date: Date
    let bool: Bool
    let str: String
    let enum1: TestEnum
}

struct TestIntent: AppIntent, WidgetConfigurationIntent {
    static var title: LocalizedStringResource = "Testing"
    static var description: IntentDescription = .init(stringLiteral: "1, 2, 3, testing")

    @Parameter(title: "Test bool")
    var bool: Bool

    @Parameter(title: "Test string", default: "Apple")
    var str: String

    @Parameter(title: "Test enum", default: .test1)
    var enum1: TestEnum
}

struct TestWidgetView: View {
    var entry: TestEntry

    var body: some View {
        VStack {
            Text(entry.str)
                .foregroundStyle(entry.bool ? .green : .red)
            Text(entry.enum1 == TestEnum.test1 ? "1" : "2")
            Text(entry.enum1.rawValue)
        }
        .containerBackground(for: .widget) {}
    }
}

struct testWidget: Widget {
    let kind: String = "Test Widget"
    
    var body: some WidgetConfiguration {
        AppIntentConfiguration(kind: kind, intent: TestIntent.self, provider: TestProvider()) { entry in
            TestWidgetView(entry: entry)
        }
        .configurationDisplayName("Test widget")
        .description("Just a test")
        .supportedFamilies([.systemSmall])
    }
}

enum TestEnum: String, AppEnum {
    static var typeDisplayRepresentation: TypeDisplayRepresentation = "Test title 1"

    case test1 = "1"
    case test2 = "2"

    static var caseDisplayRepresentations: [TestEnum : DisplayRepresentation] = [
        .test1: "test 1",
        .test2: "test 2"
    ]
}

#Preview(as: .systemSmall) {
    testWidget()
} timeline: {
    TestEntry(date: .now, bool: false, str: "Apple", enum1: TestEnum.test1)
}

It's a barebones example. The widget updates correctly if I change the boolean or the string, but not if I change the enum selection.

What am I doing wrong?

Many thanks in advance for the help.


Solution

  • You need to set the selected value using the given configuration in timeLine().

    func timeline(for configuration: TestIntent, in context: Context) async -> Timeline<TestEntry> {
            let testBool = configuration.bool
            let testStr = configuration.str
    
            return Timeline(entries: [
                TestEntry(
                    date: .now,
                    bool: testBool,
                    str: testStr,
                    enum1: configuration. enum1 //<= here
                )
            ], policy: .atEnd)
        }