Learn Courses My Dashboard

Having trouble on getting user location and displaying data

I want to get the user’s current location using the LocationButton and then display some Weather Data. Watching some tutorials and stackoverflow, I only saw things relating to the LocationButton and getting permission. I currently have it set up to search a city by name to get the data but want something to automatically be displayed after getting permission to share their location. I have a separate LocationManager and have a separate method but am a bit lost on displaying the data to the UI. I’ve tried different ways I cant seem to put it all together.

Here is my LocationManager

import CoreLocation
import Foundation


class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    
    let locationManager = CLLocationManager()
    @Published var location: CLLocationCoordinate2D?
    
    override init() {
        super.init()
        locationManager.delegate = self
    }
    
    func requestLocation(){
        locationManager.requestLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        location = locations.first?.coordinate
        
        
    }
    
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("There is an error getting your location", error)
    }
    
    
    
}

My ViewModel

import Foundation
import CoreLocation
import SwiftUI


class WeatherViewModel:  ObservableObject {
    
   
    @Published var weatherData: Weather?
    @AppStorage("cityName") var cityName = ""
    
   
    
  

    init(){
        getWeatherData(cityName)
    }
    //Init method gets run when a new instance of WeatherModel is created
    
    
 
    
    //MARK: - OpenWeatherMap API methods
    
    
    func getWeatherData(_ cityName: String){
        CLGeocoder().geocodeAddressString(cityName){(placemarks, error ) in
            if let error = error {
                print(error)
            }
            if let lat = placemarks?.first?.location?.coordinate.latitude,
                let lon = placemarks?.first?.location?.coordinate.longitude {
          
                let weatherUrlString = "https://api.openweathermap.org/data/2.5/onecall?lat=\(lat)&lon=\(lon)&exclude=minutely,alerts&units=imperial&appid=\(Constants.apiKey)"
                
                let weatherUrl = URL(string: weatherUrlString)
                guard weatherUrl != nil else {
                    return
                }
                
                let request = URLRequest(url: weatherUrl!)
                
                //Create a URL session
                
                let session = URLSession.shared
                let dataTask = session.dataTask(with: request) { data, response, error in
                    guard error == nil else {
                        return
                    }
                    
                    do{
                        let decoder = JSONDecoder()
                        let result = try decoder.decode(Weather.self, from: data!)

                        
                        DispatchQueue.main.async {
                            self.weatherData = result
    
                        }
                        
                    }catch {
                        print(error)
                    }
                }
                dataTask.resume()
            }
           }
    }//func getWeatherData
    
    func getCurrentWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees)  {
        
        let weatherStringUrl = "https://api.openweathermap.org/data/2.5/onecall?lat=\(latitude)&lon=\(longitude)&exclude=minutely,alerts&units=imperial&appid=\(Constants.apiKey)"
        
        let getCurrentWeatherStringUrl = URL(string: weatherStringUrl)
        
        guard getCurrentWeatherStringUrl != nil else { return }
        
        let currentRequest = URLRequest(url: getCurrentWeatherStringUrl!)
        
        let currentSession = URLSession.shared
        
        let currentDataTask = currentSession.dataTask(with: currentRequest) { data, response, error in
            guard error == nil else {
                return
            }
            
            
            do {
                let currentDecoder = JSONDecoder()
                
                let currentResults = try currentDecoder.decode(Weather.self, from: data!)
                
                DispatchQueue.main.async {
                    self.weatherData = currentResults
                }
                
            } catch {
                print(error)
            }
            
        }
        currentDataTask.resume()
        
        
    }
    
}

Onboarding View to get the user’s current location

import CoreLocationUI
import SwiftUI

struct OnboardingView: View {
    
    @EnvironmentObject var locationManager: LocationManager

  
    
    var body: some View {
        ZStack {
            Color.gray
                .edgesIgnoringSafeArea(.all
                )
            VStack(spacing: 10) {
                Image(systemName: "cloud.sun.rain")
                Text("Grab-N-Fetch Weather")
                    .font(.largeTitle)
                    .fontWeight(.medium)
                Text("Find out what the weather is like in your area or search a location. Please make sure to select and allow location access.")
                    .font(.title2)
                    .padding(.bottom, 20)
                
                
                
                LocationButton(.shareCurrentLocation) {
                    locationManager.requestLocation()
                }
                .foregroundColor(.white)
                .cornerRadius(10)
                .symbolVariant(.fill)
 .onAppear {
                    HomeView()
                }
                

                
            }//Vstack
            .multilineTextAlignment(.center)
        .padding()
        }//Zstack
    }
}

HomeView.

import CoreLocation
import SwiftUI

struct HomeView: View {
    
    //MARK: - Properties
    
    @State private var cityName = ""
    @State private var isEditing = false
    @StateObject var locationManager = LocationManager()
    @ObservedObject var model = WeatherViewModel()
    @State private var isCelsius = false
    @FocusState private var isFocused: Bool
   
    
    
   
    
    var hourlyFirstTwelve: [Current] {
        guard let hourly = model.weatherData?.hourly else {
            return []
        }
        return Array(hourly.prefix(13))
    }
    

    var selectTemperatureUnit: some View {
            Menu {
                Picker("", selection: $isCelsius) {
                    Text("Fahrenheit °F").tag(false)
                    Text("Celsius °C").tag(true)
                }
            } label: {
                Image(systemName: "list.dash")
            }
      
    }
    
    var searchField: some View {
        withAnimation {
            Button {
                isEditing = false
                cityName = ""
            } label: {
                Text("Cancel")
            }
            .padding(.trailing, 10)
            .transition(.move(edge: .trailing))
        }
    }
    
    //MARK: - Methods
   func convertTemp(_ temp: Double) -> Double {
           if isCelsius == true {
               return ((temp - 32) * (5/9))
           } else {
               return temp
           }
       }
    
    var body: some View {
        
        if let location = locationManager.location {
            NavigationView {
     
                ZStack {
                    Color.primaryColor
                        .ignoresSafeArea(.all)
                    
                    VStack {
                        
                        HStack {
                         
                            TextField("Enter city", text: $cityName)
                                .textFieldStyle(RoundedBorderTextFieldStyle())
                                .onTapGesture {
                                    isEditing = true
                                }
                                .focused($isFocused)
                                .submitLabel(.search)
                                .onSubmit {
                                    model.getWeatherData(cityName)
                                }
                            
                            if isEditing {
                              searchField
                            }
                        }//HStack
                        .padding()
         
                        VStack {
                          
                                    VStack(spacing: 4) {

                                        HStack(spacing: 0) {
                                            Text(String(format: "%.f°", convertTemp(model.weatherData?.current.temp ?? 0.0))
                                            )
                                            .modifier(TempTextModifier(size: 60))
    //
                                            
                                            Text(isCelsius ? "C" : "F")
                                                .modifier(TempTextModifier(size: 50))
                                               
                                        }
                                        
                                        
                                        Text(model.weatherData?.current.weather.first?.description ?? "Weather Description")
                                            .modifier(TempTextModifier(size: 22))
                                         
                                        
                                        
                                        Text(String(format: "Feels like: %.f°", convertTemp(model.weatherData?.current.feels_like ?? 0.0)))
                                            .modifier(TempTextModifier(size: 26))
                                    }//VStack
                                    .padding([.trailing, .bottom], 20.0)
                                    
                       
                                ScrollView(.horizontal) {
                                    HStack(spacing: 20) {
                                        ForEach(hourlyFirstTwelve) {
                                                hour in
                                            VStack(spacing: 10) {
                                                Text("\(Constants.dtConversion(hour.dt))")
                                                HStack {
                                                    Image(systemName: "thermometer")
                                                    Text(String(format: "%.f°", convertTemp(hour.temp)))
                                                }
                                            }//VStack
                                            .modifier(TileModifier())
                                       
                                                
                                        }
                                    }
                                }
                              
                               
                            }//VStack
                        .padding()
                      
                        GeometryReader {
                            geo in
                            
                            ScrollView {
                                VStack(spacing: 20) {
                                    ForEach(model.weatherData?.daily ?? []) { d in
                                        HStack(){
                                            
                                            Text("\(Constants.dtDaily(d.dt))")
                                            Spacer()
                                            Text(String(format: "Low: %.f°", convertTemp(d.temp.min)))
                                            Spacer()
                                            Text(String(format: "High: %.f°", convertTemp(d.temp.max)))
                                            
                                        }
                                    }
                                }
                                .padding()
                            }
                        }//geometry reader
                        .background(Color.accentColor)
                        .cornerRadius(12)
                        .edgesIgnoringSafeArea(.bottom)
                     
              
                    }//VStack
                    .navigationTitle("Grab-N-Fetch Weather")
                    .navigationBarTitleDisplayMode(.automatic)
                    .toolbar {
                        ToolbarItemGroup(placement: .navigationBarTrailing) {
                            selectTemperatureUnit
                        }
                }
                }//toolbar
                
                
            }//NavigationView

        } else {
            OnboardingView()
                .environmentObject(locationManager)
        }
        
        
    }
}