Why is m view not updating using ObservedObject and HealthKit? - ios

In the Home Screen of my app, I have a Capsule() that contains the user's steps. This data is obtained via HealthKit. The data is correct however when it changes in the health app, it should change in my app but this is not happening. How do I get 'steps' variable to listen to HealthKit, there must be an error in my code.
Here is the code for my Home view:
import SwiftUI
import HealthKit
struct Home: View {
#ObservedObject var healthStore = HealthStore()
#State private var steps: [Step] = [Step]()
init() {
healthStore = HealthStore()
}
private func updateUIFromStatistics(_ statisticsCollection: HKStatisticsCollection) {
let startDate = Date()
let endDate = Date()
statisticsCollection.enumerateStatistics(from: startDate, to: endDate) { (statistics, stop) in
let count = statistics.sumQuantity()?.doubleValue(for: .count())
let step = Step(count: Int(count ?? 0), date: statistics.startDate)
steps.append(step)
}
}
var body: some View {
NavigationView {
ScrollView {
ZStack {
Color("BackgroundColour")
.ignoresSafeArea()
VStack {
let totalSteps = steps.reduce(0) { $0 + $1.count }
ForEach($steps, id: \.id) { step in
Button(action: {
// Perform button action here
print("Step Capsule Tapped...")
}) {
HStack {
Image("footsteps")
Text("\(totalSteps)")
}
}
} // ForEach End
} // VStack End
}//ZStack End
.edgesIgnoringSafeArea(.all)
} // ScrollView End
.background(Color("BackgroundColour"))
.onLoad {
healthStore.requestAuthorization { success in
if success {
healthStore.calculateSteps { statisticsCollection in
if let statisticsCollection = statisticsCollection {
// update the UI
updateUIFromStatistics(statisticsCollection)
}
}
}
}
} // .onLoad End
.onAppear(perform: {
let defaults = UserDefaults.standard
let keyString: String? = defaults.string(forKey: "key") ?? ""
print("User's Key:\(keyString ?? "")")
}) // .onAppear End
} // NavigationView End
}
}
Here is the code for the HealthStore:
import Foundation
import HealthKit
import SwiftUI
import Combine
class HealthStore: ObservableObject {
#Published var healthStore: HKHealthStore?
#Published var query: HKStatisticsCollectionQuery?
init() {
if HKHealthStore.isHealthDataAvailable() {
healthStore = HKHealthStore()
}
}
func calculateSteps(completion: #escaping (HKStatisticsCollection?)-> Void) {
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
let startDate = Calendar.current.date(byAdding: .day, value: -7, to: Date())
let anchorDate = Date.mondayAt12AM()
let daily = DateComponents(day: 1)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictStartDate)
let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates:
[.init(format: "metadata.%K != YES", HKMetadataKeyWasUserEntered), predicate]
)
query = HKStatisticsCollectionQuery(
quantityType: stepType,
quantitySamplePredicate: compoundPredicate,
options: .cumulativeSum,
anchorDate: anchorDate,
intervalComponents: daily)
query!.initialResultsHandler = { query, statisticsCollection, error in
completion(statisticsCollection)
}
if let healthStore = healthStore, let query = self.query {
healthStore.execute(query)
}
}
func requestAuthorization(completion: #escaping (Bool) -> Void) {
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
guard let healthStore = self.healthStore else { return completion(false) }
healthStore.requestAuthorization(toShare: [], read: [stepType]) { (success, error) in
completion(success)
}
}
}
extension Date {
static func mondayAt12AM() -> Date {
return Calendar(identifier: .iso8601).date(from: Calendar(identifier: .iso8601).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date()))!
}
}
Here is the code for Step:
import Foundation
struct Step: Identifiable {
let id = UUID()
let count: Int
let date: Date
}
Here is the code for the .onLoad method that is used on the Home view:
import SwiftUI
struct ViewDidLoadModifier: ViewModifier {
#State private var didLoad = false
private let action: (() -> Void)?
init(perform action: (() -> Void)? = nil) {
self.action = action
}
func body(content: Content) -> some View {
content.onAppear {
if didLoad == false {
didLoad = true
action?()
}
}
}
}
extension View {
func onLoad(perform action: (() -> Void)? = nil) -> some View {
modifier(ViewDidLoadModifier(perform: action))
}
}
Any ideas?

I think I know what's missing here.
In your class HealthStore, inside the method func calculateSteps(completion: #escaping (HKStatisticsCollection?)-> Void), you have set the initialResultsHandler property of your HKStatisticsCollectionQuery. However, you've not set the statisticsUpdateHandler property.
To continue to listen to updates from HealthKit, after initialResultsHandler completes execution, you need to also set statisticsUpdateHandler.
As-per the statisticsUpdateHandler documentation, in-case statisticsUpdateHandler is nil, which is the case above, the HKStatisticsCollectionQuery will:
"automatically stop as soon as it has finished calculating the initial results"
which seems to be in-line with what you are observing.
Full disclosure, I've never worked with HealthKit, so please pardon me if this doesn't help. I've gone through the HealthKit documentation after looking at your code and writing here what jumps out at me.
If it does help you though, kindly consider marking it as the answer.

Related

Why do views using #ObservedObject disappear when reinitialised?

In this SwiftUI project, I had a profile tab that displayed the username of the user. When I tapped on this tab again (whilst already in the profile view), the name of the user disappeared.
I fixed this issue by changing this line of code:
#ObservedObject var ProfileModel = ProfileViewModel()
To this line of code:
#StateObject var ProfileModel = ProfileViewModel()
I found that changing #ObservedObject to #StateObject fixed the bug.
Therefore I wanted to apply the same fix to my home view (which was experiencing the same bug as the profile view), where I am displaying the User's step data using the HealthKit framework.
However this caused problems in the init().
Changing:
#ObservedObject var healthStore = HealthStore()
To:
#StateObject var healthStore = HealthStore()
Caused this error in my init(): Cannot assign to property: 'healthStore' is a get-only property.
Here is my init():
init() {
healthStore = HealthStore()
}
I need the healthStore to use #ObservedObject in order to listen for changes in the healthStore and update the view accordingly.
Here is HealthStore:
import Foundation
import HealthKit
import SwiftUI
import Combine
class HealthStore: ObservableObject {
#Published var healthStore: HKHealthStore?
#Published var query: HKStatisticsCollectionQuery?
#Published var steps = [Step]()
init() {
if HKHealthStore.isHealthDataAvailable() {
healthStore = HKHealthStore()
}
}
func calculateSteps(completion: #escaping (HKStatisticsCollection?) -> Void) {
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
let startDate = Calendar.current.date(byAdding: .day, value: -7, to: Date())
let anchorDate = Date.mondayAt12AM()
let daily = DateComponents(day: 1)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictStartDate)
let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates:
[.init(format: "metadata.%K != YES", HKMetadataKeyWasUserEntered), predicate]
)
DispatchQueue.main.async {
self.query = HKStatisticsCollectionQuery(
quantityType: stepType,
quantitySamplePredicate: compoundPredicate,
options: .cumulativeSum,
anchorDate: anchorDate,
intervalComponents: daily)
self.query!.initialResultsHandler = { [weak self] query, statisticsCollection, error in
guard let self = self else { return }
DispatchQueue.main.async {
completion(statisticsCollection)
}
}
self.query!.statisticsUpdateHandler = { [weak self] query, statistics, collection, error in
guard let self = self else { return }
DispatchQueue.main.async {
if let stepCount = statistics?.sumQuantity()?.doubleValue(for: HKUnit.count()) {
self.steps.append(Step(count: Int(stepCount), date: statistics!.startDate))
}
}
}
if let healthStore = self.healthStore, let query = self.query {
healthStore.execute(query)
}
}
}
func requestAuthorization(completion: #escaping (Bool) -> Void) {
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
guard let healthStore = self.healthStore else { return completion(false) }
healthStore.requestAuthorization(toShare: [], read: [stepType]) { (success, error) in
completion(success)
}
}
}
How can I fix the issue of the view that contains step data from healthStore disappearing when the Home view is reinitialised (tapping the home tab when already in the home tab)?
SwiftUI views are structs and therefore immutable. What actually happens when a SwiftUI view "updates", is that a new instance of the view is created and shown.
This means that when you declare your view model via #ObservableObject, you get a new instance of ProfileViewModel along with your new ProfileView.
#StateObject tells SwiftUI that you want a single instance of this object to be kept when this view is updated, so SwiftUI takes care of this for you. An implication of this is that you cannot assign new values to the property; It is "get only".
In your HomeView you need to remove the healthStore = HealthStore() from your init - You have already provided an instance of HealthStore and assigned it to healthStore when you declared #StateObject var healthStore = HealthStore()
#StateObject properties still refer to ObservableObjects, so your HealthStore doesn't need to change.

Issue with LiveActivity

so here's my issue with LiveActivities. My code doesn't work, but no error is thrown...
Here's how I enable/disable the activity:
let helper = JourneyActivityHelper.shared
TagComponent(journey: journey)
.onChange(of: journey.isTracked) { value in
journey.isTracked ? helper.start(departureTime: departureTime, arrivalTime: arrivalTime, journey: journey) : helper.stop(departureTime: departureTime, arrivalTime: arrivalTime)
}
Here's my helper class:
struct JourneyAttributes: ActivityAttributes {
public typealias JourneyStatus = ContentState
public struct ContentState: Codable, Hashable {
var departureTime: Date
var arrivalTime: Date
}
var journey: Journey
}
class JourneyActivityHelper {
static let shared = JourneyActivityHelper()
var activity: Activity<JourneyAttributes>?
func start(departureTime: Date, arrivalTime: Date, journey: Journey) {
// We check that activities can be enabled
guard ActivityAuthorizationInfo().areActivitiesEnabled else { return }
// Initializing variables
let initialState = JourneyAttributes.ContentState(departureTime: departureTime, arrivalTime: arrivalTime)
let staleDate = departureTime <= Date() ? nil : departureTime
let initialContent = ActivityContent(state: initialState, staleDate: staleDate)
let attributes = JourneyAttributes(journey: journey)
do {
activity = try Activity.request(attributes: attributes, content: initialContent)
print("New live activity activated!")
} catch (let error) {
print(error.localizedDescription)
}
}
func stop(departureTime: Date, arrivalTime: Date) {
Task {
let finalState = JourneyAttributes.ContentState(departureTime: departureTime, arrivalTime: arrivalTime)
let finalContent = ActivityContent(state: finalState, staleDate: nil)
for activity in Activity<JourneyAttributes>.activities {
await activity.end(finalContent, dismissalPolicy: .immediate)
}
}
}
}
And finally, here's my LiveActivity code (Widget):
#main
struct TrainlyWidgetBundle: WidgetBundle {
#WidgetBundleBuilder
var body: some Widget {
TrainlyWidget()
if #available(iOS 16.2, *) {
ActivityConfiguration(for: JourneyAttributes.self) { context in
LockScreenLiveActivity(context: context)
} dynamicIsland: { context in
...
}
}
}
}
Thanks in advance for anyone who could help me resolve my issue!
EDIT: What I expected: for my LiveActivity to show up. What happens: it doesn't show up!
I solved my own issue. departureTime and arrivalTime (dates that were passed to start() and stop() functions) weren't actual dates. Therefore, the Live Activity didn't start because the dates were in the past (year 2000 instead of 2023)

How can i wait for data to be loaded from API and then create events in CalendarKit library

I have a problem with fetching data from API. The DayViewCalendar is creating View before events data is fetched from API.
My main view is in SwiftUI
struct CalendarScreen: View {
#StateObject private var viewModel: ViewModel = ViewModel()
var body: some View {
NavigationView {
ZStack(alignment: .trailing) {
CalendarKitDisplayView(viewModel: viewModel)
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
I have a ViewModel which is fetching events data from API
import Combine
import Foundation
extension NSNotification.Name {
static let onEventLoaded = Notification.Name("onEventLoaded")
}
extension CalendarScreen {
class ViewModel: ObservableObject {
let calendarService = CalendarService()
#Published var calendarEvents: [CalendarEvent]
var cancellable: AnyCancellable?
init() {
self.calendarEvents = [CalendarEvent()]
}
func fetchCalendarEvents() {
cancellable = calendarService.getEvents()
.sink(
receiveCompletion: { _ in },
receiveValue: {
calendarEvents in self.calendarEvents = calendarEvents
NotificationCenter.default.post(name: .onEventLoaded, object: nil)
})
}
}
}
Calendar Service is just a service for singletion of repository
import Foundation
import Combine
struct CalendarService {
private var calendarRepository = CalendarRepository()
func getEvents() -> AnyPublisher<[CalendarEvent], Error> {
return calendarRepository.getEvents()
}
}
And calendarRepository is just simple URL Request for my API
import Combine
struct CalendarRepository {
private let agent = Agent()
private let calendarurl = "\(api)/calendars_events"
func getEvents() -> AnyPublisher<[CalendarEvent], Error>{
let urlString = "\(calendarurl)"
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("Bearer \(AuthManager.shared.token)", forHTTPHeaderField: "Authorization")
return agent.run(request)
}
}
Agent is handling the request
class Agent {
let session = URLSession.shared
var cancelBag: Set<AnyCancellable> = []
func run<T: Decodable>(_ request: URLRequest) -> AnyPublisher<T, Error> {
return session
.dataTaskPublisher(for: request)
.decode(type: T.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
Everything is going in CalendarViewController from CalendarKit library which stands as follow:
import SwiftUI
import UIKit
class CalendarViewController: DayViewController {
convenience init(viewModel: CalendarScreen.ViewModel) {
self.init()
self.viewModel = viewModel
}
var viewModel = CalendarScreen.ViewModel()
var refresh: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
subscribeToNotification()
}
func subscribeToNotification() {
NotificationCenter.default.addObserver(
self, selector: #selector(eventChanged(_:)), name: .onDataImported, object: nil)
}
#objc func eventChanged(_ notification: Notification) {
print("notification")
reloadData()
}
override func eventsForDate(_ date: Date) -> [EventDescriptor] {
// HOW CAN I WAIT FOR THIS LINE TO FINISH FETCH DATA FROM API
viewModel.fetchCalendarEvents()
//
let calendarKitEvents = viewModel.calendarEvents.filter {
dateTimeFormat.date(from: $0.start) ?? Date() >= date
&& dateTimeFormat.date(from: $0.end) ?? Date() <= date
}.map { item in
let event = Event()
event.dateInterval = DateInterval(
start: self.dateTimeFormat.date(from: item.start) ?? Date(),
end: self.dateTimeFormat.date(from: item.end) ?? Date())
event.color = UIColor(InvoiceColor(title: item.title))
event.isAllDay = false
event.text = item.title
return event
}
return calendarKitEvents
}
let dateTimeFormat: DateFormatter = {
let df = DateFormatter()
df.locale = Locale(identifier: "pl")
df.timeZone = TimeZone(abbreviation: "CET")
df.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
return df
}()
}
And the SwiftUI and UIKit is bridged by UIViewControllerRepresntable
import SwiftUI
import UIKit
struct CalendarKitDisplayView: UIViewControllerRepresentable {
#ObservedObject var viewModel: CalendarScreen.ViewModel
func makeUIViewController(context: Context) -> DayViewController {
let dayViewCalendar = CalendarViewController(viewModel: viewModel)
return dayViewCalendar
}
func updateUIViewController(_ uiViewController: DayViewController, context: Context) {
}
}
And the entity CalendarEvent which is coded to CalendarKit event
public struct CalendarEvent: Codable, Identifiable {
public var id: Int = 0
var title: String = ""
var start: String = ""
var end: String = ""
var note: String?
}
My goal is to wait for viewModel.fetchCalendarEvents() to fetch data from API and then start other tasks.
override func eventsForDate(_ date: Date) -> [EventDescriptor] {
// HOW CAN I WAIT FOR THIS LINE TO FINISH FETCH DATA FROM API
viewModel.fetchCalendarEvents()
//
I tried to implement NotificationCenter with variable refresh but when i added and changed functions
To the CalendarViewController variable var refresh: Bool = false and push notification to ViewModel
func fetchCalendarEvents() {
cancellable = calendarService.getEvents()
.sink(
receiveCompletion: { _ in },
receiveValue: {
calendarEvents in self.calendarEvents = calendarEvents
NotificationCenter.default.post(name: .eventChanged, object: nil)
})
}
After that i added subscribe to event in init() function in my CalendarViewController and #selector as follow
#objc func eventChanged(_ notification: Notification) {
print("notification")
refresh = true
reloadData()
}
I tried to add but it stay in infinite loop and variable never change
override func eventsForDate(_ date: Date) -> [EventDescriptor] {
viewModel.fetchCalendarEvents()
while refresh == true {
}
}
I was thinking about using conclusion or completion handler but i am new in Swift programming and dont really know how it should looks like.
Using a completion handler your function should look like this:
func fetchCalendarEvents(_ completion: #escaping () -> Void) {
cancellable = calendarService.getEvents()
.sink(
receiveCompletion: { _ in },
receiveValue: {
calendarEvents in self.calendarEvents = calendarEvents
NotificationCenter.default.post(name: .eventChanged, object: nil)
completion()
})
}
And when calling it:
fetchCalendarEvents {
//finished, run some code.
}

Events are not loading Calendar with first APICall

I am using SwiftUI, UIKit and external library CalendarKit in my project. The problem is that events don't load while initializing on first load of calendar. When I change date in the in the nav, update event or create new event everything works fine. Events are reloading and are showed up on screen.
I have few classes in my projects. First is CalendarScreen which renders the SwiftUI view, ViewModel of CalendarScreen which loads data fetched from API. Service which provides repository and Repository class which runs URLRequest. The UIKit class of DayViewController where everything is going in:
class CalendarViewController: DayViewController {
convenience init(viewModel: CalendarScreen.ViewModel) {
self.init()
self.viewModel = viewModel
}
var viewModel = CalendarScreen.ViewModel()
override func viewDidLoad() {
super.viewDidLoad()
reloadData()
}
override func reloadData() {
dayView.timelinePagerView.pagingViewController.children.forEach({ (controller) in
if let controller = controller as? TimelineContainerController {
controller.timeline.layoutAttributes = eventsForDate(Date()).map(EventLayoutAttributes.init)
}
})
}
override func eventsForDate(_ date: Date) -> [EventDescriptor] {
return viewModel.fetchCalendarEvents {
var calendarKitEvents = [Event()]
calendarKitEvents = self.viewModel.calendarEvents.compactMap { item in
let event = Event()
event.dateInterval = DateInterval(
start: self.dateTimeFormat.date(from: item.start) ?? Date(),
end: self.dateTimeFormat.date(from: item.end) ?? Date())
event.color = UIColor(InvoiceColor(title: item.title))
event.isAllDay = false
event.text = item.title
return event
}
self.eventsOnCeldanr = calendarKitEvents
}
}
}
And the classes corresponding to my APICall the main function is func fetchCalendarEvents which return Events to my Controller
class Agent {
let session = URLSession.shared
func run<T: Decodable>(_ request: URLRequest) -> AnyPublisher<T, Error> {
return
session
.dataTaskPublisher(for: request)
.decode(type: T.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
struct CalendarRepository {
private let agent = Agent()
func getEvents() -> AnyPublisher<[CalendarEvent], Error> {
let urlString = "\(calendarurl)"
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
return agent.run(request)
}
}
struct CalendarService {
private var calendarRepository = CalendarRepository()
func getEvents() -> AnyPublisher<[CalendarEvent], Error> {
return calendarRepository.getEvents()
}
extension CalendarScreen {
class ViewModel: ObservableObject {
let calendarService = CalendarService()
#Published var calendarEvents: [CalendarEvent]
#Published var events: [Event]
var cancellable: AnyCancellable?
init() {
self.calendarEvents = [CalendarEvent()]
self.events = []
}
func fetchCalendarEvents(_ completion: #escaping () -> Void)
-> [EventDescriptor]
{
cancellable = calendarService.getEvents()
.sink(
receiveCompletion: { _ in },
receiveValue: {
calendarEvents in self.calendarEvents = calendarEvents
NotificationCenter.default.post(name: .onEventLoaded, object: nil)
self.createEvents()
completion()
})
return events
}
func createEvents() {
self.events = self.calendarEvents.compactMap({ (item) in
var event = Event()
event.dateInterval = DateInterval(
start: self.dateTimeFormat.date(from: item.start)!,
end: self.dateTimeFormat.date(from: item.end)!)
event.color = UIColor(InvoiceColor(title: item.title))
event.isAllDay = false
event.text = item.title
return event
})
}
}
}
}
So the problem is when I load view for the first time the reloadDate() returning empty [] array.
While i try to debug Events are in variable calendarKitEvents but without sucessful return and on first load function ends on reciveCompletion call instead of reciveValue call in fetchCalendarEvents function.

WidgetKit not work for an Intent Handler to Provide Dynamic Values

I am trying to implement a widget where the user can choose a city dynamically via an intent.
I followed the step by step guide provided by apple here:
https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget
I think I have done everything correctly but the result I have is always this:
I can see the list of cities but when I select one the screen goes black, as seen in the video and the debug crashes. Both on simulator and device.
My goal is to have the city selected within the widget's getTimeline
Here is the code I use:
IntentHandler.swift in SiriIntent's target:
import Intents
class IntentHandler: INExtension, DynamicCitySelectionIntentHandling {
func provideCity_paramOptionsCollection(for intent: DynamicCitySelectionIntent, with completion: #escaping (INObjectCollection<City>?, Error?) -> Void) {
let dataSource = PersistenceController.shared.getAllForecastDataCoreData()
let coreDataCities: [City] = dataSource.map { cityCoreData in
let city = City(identifier: "\(cityCoreData.cityID ?? -1)", display: cityCoreData.cityName ?? "")
return city
}
let collection = INObjectCollection(items: coreDataCities)
completion(collection, nil)
}
override func handler(for intent: INIntent) -> Any {
return self
}
}
Part of code in Widget class:
import WidgetKit
import SwiftUI
import Combine
import MapKit
typealias Entry = ForecastEntry
struct Provider: IntentTimelineProvider {
let snapshotEntry = Entry(date: Date(), forecastViewModel: .initForPlaceholder())
func placeholder(in context: Context) -> ForecastEntry {
snapshotEntry
}
public func getSnapshot(
for configuration: DynamicCitySelectionIntent,
in context: Context,
completion: #escaping (Entry) -> Void
) {
let entry = snapshotEntry
completion(entry)
}
public func getTimeline(
for configuration: DynamicCitySelectionIntent,
in context: Context,
completion: #escaping (Timeline<Entry>) -> Void
) {
let currentDate = Date()
let correctDate = Calendar.current.date(byAdding: .second, value: 150, to: currentDate)
WidgetServiceManager.shared.fetchWeather(forCityId: configuration.city_param?.identifier ?? "") { data in
guard let _data = data else { return }
let entry = Entry(date: currentDate,
forecastViewModel: ForecastCardViewModel(weatherModel: _data,
isForUserPosition: false))
let timeline = Timeline(entries: [entry],
policy: .after(correctDate ?? Date()))
completion(timeline)
}
}
}
#main
struct WeatherAppWidget: Widget {
let kind: String = "WeatherAppWidget"
init() {
}
var body: some WidgetConfiguration {
IntentConfiguration(
kind: kind,
intent: DynamicCitySelectionIntent.self,
provider: Provider()
) { entry in
WeatherAppWidgetEntryView(entry: entry)
}
.configurationDisplayName("Weather Widget")
.description("Forecasts in your location.")
.supportedFamilies([.systemMedium, .systemSmall])
}
}
.intentdefinition file:
struct LargeWidgetEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationIntent
}
Use configuration

Resources