# Configuring Widgets

### AppIntents

AppIntents is the framework developed by Apple that allows us to configure our widgets with custom information provided by the user.

### Creating a New Intent

We will create a new intent that allows the user to input a location and have the weather widget update its displayed conditions.

Let’s start by creating a new Swift file, which we will call `LocationAppIntent`.

Within that file, we will define a new structure that conforms to the `WidgetConfigurationIntent` protocol. This protocol provides us with an interface for configuring a WidgetKit widget.

{% code title="LocationAppIntent.swift" %}

```swift
import WidgetKit
import AppIntents

struct LocationAppIntent: WidgetConfigurationIntent {

}
```

{% endcode %}

This protocol requires us to implement a title for this Intent. Additionally, we can also implement a description on what this intent does.

{% code title="LocationAppIntent.swift" %}

```swift
static var title: LocalizedStringResource = "Location"
static var description = IntentDescription("Enter a location to view the weather.")
```

{% endcode %}

Next, we can define a parameter for this intent with a default value. The parameter will contain the location that use inputs.

{% code title="LocationAppIntent.swift" %}

```swift
@Parameter(title: "Location", default: "Ithaca, NY")
var location: String
```

{% endcode %}

### Changes to WeatherEntry

Since our intent can make changes to a widget entry within our timeline, we must include it inside of the WeatherEntry model.

{% code title="WeatherWidgetEntry.swift" %}

```swift
import WidgetKit

struct WeatherEntry: TimelineEntry {
    let date: Date
    let weather: Weather
    let configuration: LocationAppIntent
}
```

{% endcode %}

### Changes to WeatherTimelineProvider

We must also update our timeline provider to support this new app intent. We will change our provider to conform to the `AppIntentTimelineProvider` protocol to do so.

{% code title="WeatherWidgetProvider.swift" %}

```swift
struct Provider: AppIntentTimelineProvider {

}
```

{% endcode %}

Additionally, we will need to update the function headers for fetching a snapshot and timeline entry.

{% code title="WeatherWidgetProvider.swift" %}

```swift
func snapshot(for configuration: LocationAppIntent, in context: Context) async -> WeatherEntry {

}
```

{% endcode %}

{% code title="WeatherWidgetProvider.swift" %}

```swift
func timeline(for configuration: LocationAppIntent, in context: Context) async -> Timeline<WeatherEntry> {

}
```

{% endcode %}

These two functions provide us with the intent called `configuration` that contain user-customized values for the location.

Within both of these functions, we have to update our `WeatherEntry` instantiation to pass in the configuration.

{% code title="WeatherWidgetProvider.swift" %}

```swift
let entry = WeatherEntry(date: Date(), weather: possibleWeathers.randomElement()!, configuration: configuration) 
```

{% endcode %}

Additionally, we also have to update the entry created within our placeholder function with a new intent object.

{% code title="WeatherWidgetProvider.swift" %}

```swift
func placeholder(in context: Context) -> WeatherEntry {
    return WeatherEntry(date: Date(), weather: .sunny, configuration: LocationAppIntent())
}
```

{% endcode %}

### Changes to Widget Configuration

Within `WeatherWidget.swift`, we also have to change our widget’s configuration from `StaticConfiguration` to `AppIntentConfiguration`.

{% code title="WeatherWidget.swift" %}

```swift
AppIntentConfiguration(kind: kind, intent: LocationAppIntent.self, provider: Provider()) { entry in
    WeatherWidgetView(entry: entry)
}
```

{% endcode %}

### Changes to View

Finally, within `WeatherWidgetView`, we can update the “Ithaca, NY” string to display the location passed in through the app intent associated with the timeline entry being displayed.

{% code title="WeatherWidgetView\.swift" %}

```swift
HStack {
    Text(entry.configuration.location)
        .font(.system(size: 18, weight: .semibold))
        .minimumScaleFactor(0.5)
    Spacer()
}
```

{% endcode %}

Additionally, to view the widget in the Preview window, we will need to provide it with a default configuration. We can define a default intent as an extension of our `LocationAppIntent` within our view. Since we do not want this default value being used anywhere outside this file, we mark it with `fileprivate`.

{% code title="WeatherWidgetView\.swift" %}

```swift
extension LocationAppIntent {
    fileprivate static var cupertino: LocationAppIntent {
        let intent = LocationAppIntent()
        intent.location = "Cupertino, CA"
        return intent
    }
}
```

{% endcode %}

We then update the preview entries to use this new configuration.

{% code title="WeatherWidgetView\.swift" %}

```swift
#Preview(as: .systemSmall) {
    WeatherWidget()
} timeline: {
    WeatherEntry(date: .now, weather: .sunny, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .cloudy, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .overcast, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .rainy, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .lightning, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .snowy, configuration: .cupertino)
}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ios-course.cornellappdev.com/resources/archived-past-semesters/fa23/lectures/widgets/configuring-widgets.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
