Can you use WeatherKit to show the 10-Day Forecast before the current date?

45 Views Asked by At

I am attempting to plot on a lineMark chart the ambient temperature for 10-days prior to the current date. Currently my LineMark chart is show the current date and a 10-day forecast out(For example: Todays date is March 14th so the chart show up until March 24th. But I want the chart to show March 4th to today's current date March 14th). I am new to using WeatherKit so I am not sure this is even possible. I have tried to add an extension to get the previous 10-days but then it starts to just show one point for one day on the chart instead of the full chart. This code provided below, shows the 10-day forecast for ambient temperature from March 14th to March 24th.

import SwiftUI
import CoreLocation
import WeatherKit
import Charts
import Foundation


enum ForecastType: String, CaseIterable, Identifiable {
case hourly = "Hourly Forecast"
case daily = "10-Day Forecast"

var id: String { self.rawValue }
}

@MainActor
class WeatherData: ObservableObject {
static let shared = WeatherData()
private let service = WeatherService.shared
@Published var currentWeather: CurrentWeather?
@Published var hourlyForecast: [HourWeather] = []
@Published var dailyForecast: [DayWeather] = []

func updateCurrentWeather(userLocation: CLLocation) {
    Task.detached(priority: .userInitiated) {
        do {
            let forecast = try await self.service.weather(
                for: userLocation,
                including: .current)
            DispatchQueue.main.async {
                self.currentWeather = forecast
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}


func updateHourlyWeather(userLocation: CLLocation) {
    Task.detached(priority: .userInitiated) {
        do {
            let forecast = try await self.service.weather(
                for: userLocation,
                including: .hourly)
            DispatchQueue.main.async {
                self.hourlyForecast = forecast.forecast.sorted(by: { $0.date < $1.date })
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}

func updateDailyWeather(userLocation: CLLocation) {
    Task.detached(priority: .userInitiated) {
        do {
            let forecast = try await self.service.weather(for: userLocation, including: .daily)
            DispatchQueue.main.async {
                self.dailyForecast = forecast.forecast
            }
        } catch {
            print("Failed to fetch daily weather data: \(error.localizedDescription)")
        }
    }
}
}

struct DailyForecastChartView: View {
var dailyForecast: [DayWeather]

var body: some View {
    Chart {
        ForEach(dailyForecast, id: \.date) { day in
            let averageTemp = (day.highTemperature.value + day.lowTemperature.value) / 2
            LineMark(
                x: .value("Day", day.date, unit: .day),
                y: .value("High Temperature", averageTemp)
            )
            .foregroundStyle(.green)
        }
        .symbol(Circle().strokeBorder())
        .interpolationMethod(.catmullRom)
    }
    
    .chartXAxis {
        AxisMarks(preset: .aligned, position: .bottom)
    }
    .chartYAxis {
        AxisMarks(preset: .aligned, position: .leading)
    }
}
}


struct LocalizedWeatherView: View {
@ObservedObject var weatherDataHelper = WeatherData.shared
@ObservedObject var userLocationHelper = WeatherLocationManager.shared
@State private var selectedDate: Date = Date()
@State private var selectedForecastType: ForecastType = .hourly

var body: some View {
    Form {
        if let currentWeather = weatherDataHelper.currentWeather {
            Section {
                Label(currentWeather.temperature.formatted(), systemImage: "thermometer")
                Label("\(Int(currentWeather.humidity * 100))%", systemImage: "humidity.fill")
                
                if userLocationHelper.userLocation == nil {
                    Button("Load user current location") {
                        loadUserCurrentLocation()
                    }
                }
                Button("Fetch current weather") {
                    loadCurrentWeatherData()
                }
            }
            
        }
        
        Section(header: Text(selectedForecastType == .hourly ? "" : "")) {
            Picker("Forecast Type", selection: $selectedForecastType) {
                ForEach(ForecastType.allCases) { type in
                    Text(type.rawValue).tag(type)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            
            if selectedForecastType == .hourly {
                if !weatherDataHelper.hourlyForecast.isEmpty {
                    HourlyForecastChartView(hourlyForecast: weatherDataHelper.hourlyForecast)
                        .frame(height: 300)
                } else {
                    Text("No hourly forecast data available.")
                }
            } else if selectedForecastType == .daily {
                if !weatherDataHelper.dailyForecast.isEmpty {
                    DailyForecastChartView(dailyForecast: weatherDataHelper.dailyForecast)
                        .frame(height: 300)
                } else {
                    Text("Loading daily forecast data")
                }
            }
        }
    }
    .navigationTitle("Localized Weather")
    .onAppear {
        loadAllWeatherData()
        
    }
}

func loadAllWeatherData() {
    guard let userLocation = userLocationHelper.userLocation else {
        return
    }
    weatherDataHelper.updateCurrentWeather(userLocation: userLocation)
    weatherDataHelper.updateHourlyWeather(userLocation: userLocation)
    weatherDataHelper.updateDailyWeather(userLocation: userLocation)
    
}

func loadUserCurrentLocation() {
    userLocationHelper.requestPermission()
    userLocationHelper.locationManager.requestLocation()
}

func loadCurrentWeatherData() {
    guard let userLocation = WeatherLocationManager.shared.userLocation else {
        return
    }
    Task.detached { @MainActor in
        weatherDataHelper.updateCurrentWeather(userLocation: userLocation)
    }
}
}


extension WeatherData {
var last10DaysForecast: [DayWeather] {
    let calendar = Calendar.current
    guard let tenDaysAgo = calendar.date(byAdding: .day, value: -10, to: Date()) else { return [] }
    
    return dailyForecast.filter {
        let isBeforeToday = $0.date < Date()
        let isAfterTenDaysAgo = $0.date >= tenDaysAgo
        return isBeforeToday && isAfterTenDaysAgo
    }
    
    .sorted { $0.date < $1.date }
}
}
0

There are 0 best solutions below