Внедрение WeatherKit в виджет — SwiftUI

Итак, у меня есть виджет для приложения погоды (приложение в настоящее время не использует WeatherKit, но в конечном итоге я хотел бы его переместить), но я хочу заранее реализовать виджет с помощью WeatherKit. Я сделал тестовое приложение, используя WeatherKit, и все компоненты, которые я хотел бы использовать в виджете, работали правильно.

Вот все основное приложение, которое отлично работает:

      
import SwiftUI
import CoreLocation
import WeatherKit

var userCity: String  = ""


class LocationManager: NSObject, ObservableObject {
    @Published var currentLocation: CLLocation?
    @Published var userCity: String = ""
    private let locationManager = CLLocationManager()

    override init() {
        super.init()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = kCLDistanceFilterNone
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()
        locationManager.delegate = self
    }
}

extension LocationManager: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last, currentLocation == nil else { return }
        
        
        DispatchQueue.main.async {
            self.currentLocation = location
        }
        
        
        CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in
            print(location)
            guard error == nil else {
                print("Reverse geocoder failed with error" + error!.localizedDescription)
                return
            }
            guard placemarks!.count > 0 else {
                print("Problem with the data received from geocoder")
                return
            }
            let pm = placemarks![0].locality
            print(pm!)
            let userLocation = (pm!)
            print(userLocation)
            
            
            DispatchQueue.main.async {
            self.userCity = userLocation
            }
            
        })
    }
}

struct ContentView: View {
    
    let weatherService = WeatherService.shared
    
    @StateObject private var locationManager = LocationManager()
    @State private var weather: Weather?
    

    var body: some View {
     
        VStack {
            if let weather{
            
                
                let celsiusWeather = weather.currentWeather.temperature.converted(to: .celsius)
                
                let celsiusFormatted = String(format: "%.0f", celsiusWeather.value)
                
                let celsiusFinal = "\(celsiusFormatted)°C"
                
                let fahrenheitWeather = weather.currentWeather.temperature.converted(to: .fahrenheit)
                
                let fahrenheitFormatted = String(format: "%.0f", fahrenheitWeather.value)
                
                let fahrenheitFinal = "\(fahrenheitFormatted)°F"
                
                
                VStack{
                    Image(systemName: weather.currentWeather.symbolName)
                        .resizable()
                        .symbolRenderingMode(.palette)
                        .scaledToFit()
                        .frame(width: 80, height: 80)
                    Text(locationManager.userCity)
                        .font(.largeTitle)
                    Text(fahrenheitFinal)
                    Text(celsiusFinal)
                   
                }
            }
        }
        .padding()
        .task(id: locationManager.currentLocation) {
            do{
                if let location = locationManager.currentLocation{
                    self.weather = try await weatherService.weather(for: location)
                    print(weather!)
                }
                
            }catch{
                print(error)
            }
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

По сути, я просто пытался переместить этот код в виджет, не зная, будет ли он работать правильно (очевидно, что что-то не так).

И вот что я пытался сделать с виджетом, но он пуст, поэтому что-то не работает и не может получить данные о погоде. Но Xcode не дает мне никаких ошибок.

      import WidgetKit
import SwiftUI
import WeatherKit
import CoreLocation

var userCity: String?


class LocationManager: NSObject, ObservableObject {
    @Published var currentLocation: CLLocation?
    @Published var userCity: String = ""
    private let locationManager = CLLocationManager()

    override init() {
        super.init()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = kCLDistanceFilterNone
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()
        locationManager.delegate = self
    }
}

extension LocationManager: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last, currentLocation == nil else { return }
        
        
        DispatchQueue.main.async {
            self.currentLocation = location
        }
        
        
        CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in
            print(location)
            guard error == nil else {
                print("Reverse geocoder failed with error" + error!.localizedDescription)
                return
            }
            guard placemarks!.count > 0 else {
                print("Problem with the data received from geocoder")
                return
            }
            let pm = placemarks![0].locality
            print(pm!)
            let userLocation = (pm!)
            print(userLocation)
            
            
            DispatchQueue.main.async {
                self.userCity = userLocation
            }
            
        })
    }
}

struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), city: "", temp: "0") // placeholder humidity
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date(), city: "", temp: "0") // placeholder humidity
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        
        let locationManager = LocationManager()
        @State var currentWeather: Weather?
        
        
        let nextUpdate = Date().addingTimeInterval(1800)
        
        Task {

            do{
                if let location = locationManager.currentLocation{
                    let currentWeather = try await WeatherService.shared.weather(for: location)
                    print(currentWeather)
                }

            }catch{
                print(error)
            }
        
        }
        
        let entry = SimpleEntry(date: .now, city: userCity!, temp: (currentWeather?.currentWeather.temperature.description)!)
        
        let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
        completion(timeline)
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let city: String
    let temp: String
}

struct WidgetWeatherTestWidgetEntryView : View {
   
    
    var entry: Provider.Entry

    var body: some View {
        VStack{
            Text(entry.city)
            Text(entry.temp)
        }
    }
}

struct ShitsdagWidget: Widget {
    let kind: String = "WidgetWeatherTest"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            WidgetWeatherTestWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("Widget Weather Test")
        .description("Testing weatherkit in a Widget")
        .supportedFamilies([.systemSmall])
    }
}

Поскольку виджеты настроены немного иначе, чем просто SwiftUI с временной шкалой и всем остальным, у меня могут быть вещи в неправильном месте, которые будут запускаться в правильном порядке. Любая помощь будет здорово.

0 ответов

Другие вопросы по тегам