Commit c49077b0 by Demid Merzlyakov

LocationManager: added location list.

parent a7e31619
......@@ -9,6 +9,7 @@ import Foundation
public protocol LocationManagerDelegate: class {
func locationManager(_ locationManager: LocationManager, changedCurrentLocation newLocation: Location?)
func locationManager(_ locationManager: LocationManager, updatedLocationsList newList: [Location])
}
public class LocationManager {
......@@ -18,20 +19,36 @@ public class LocationManager {
private let defaultLocation = Location(lastTimeUpdated: Date(),
coordinates: .init(latitude: 37.3230, longitude: -122.0322), // Cupertino
timeZone: TimeZone(abbreviation: "PST")!)
public private(set) var locations = [Location]() {
didSet {
log.info("Locations list updated: \(locations.map { $0.description }.joined(separator: ", "))")
DispatchQueue.main.async {
self.delegates.invoke { [weak self] (delegate) in
guard let self = self else { return }
delegate.locationManager(self, updatedLocationsList: self.locations)
}
}
}
}
private var _currentLocation: Location? {
didSet {
if oldValue?.description != currentLocation?.description {
log.info("Current location changed to: \(currentLocation?.description ?? "nil")")
}
log.info("Location updated.")
delegates.invoke { [weak self] (delegate) in
guard let self = self else { return }
delegate.locationManager(self, changedCurrentLocation: currentLocation)
DispatchQueue.main.async {
self.delegates.invoke { [weak self] (delegate) in
guard let self = self else { return }
delegate.locationManager(self, changedCurrentLocation: self.currentLocation)
}
}
}
}
public static let shared = LocationManager(weatherUpdateSource: WdtWeatherSource())
public let maxLocationsCount = 12
public init(weatherUpdateSource: WeatherSource) {
self.weatherUpdateSource = weatherUpdateSource
......@@ -40,6 +57,7 @@ public class LocationManager {
public var currentLocation: Location? {
get {
guard let location = _currentLocation else {
// TODO: don't do it this way! We won't be able to show search if there's no location!
return defaultLocation
}
......@@ -56,7 +74,12 @@ public class LocationManager {
log.warning("Update weather: no location.")
return
}
guard Date().timeIntervalSince(location.lastTimeUpdated) >= weatherUpdateSource.weatherUpdateInterval else {
log.info("Update weather: fresh enough (last updated at \(location.lastTimeUpdated)), skip update.")
return
}
log.info("Update weather for location: \(location)")
weatherUpdateSource.updateWeather(for: location) { [weak self] (updatedLocation, error) in
guard let self = self else { return }
guard let updatedLocation = updatedLocation else {
......@@ -74,6 +97,37 @@ public class LocationManager {
}
}
}
// TODO: update weather for all locations
public func add(location: Location) {
if locations.count >= maxLocationsCount {
log.warning("Adding new location, although the location limit is exceeded. New total: \(locations.count + 1)")
// This may happen if a location is added from a push notification.
}
if let existingLocation = locations.first(where: { $0 == location }) {
currentLocation = existingLocation
}
else {
locations.append(location)
currentLocation = location
}
// TODO: we need to update weather for new locations, probably.
// Or not? Should ViewModels handle it?
}
public func remove(location: Location) {
if let index = locations.firstIndex(of: location) {
locations.remove(at: index)
}
else {
log.warning("Couldn't remove \(location), because we couldn't find index.")
}
if currentLocation == location {
currentLocation = locations.first
}
}
// MARK: Delegates management
public func add(delegate: LocationManagerDelegate) {
delegates.add(delegate: delegate)
......
......@@ -21,6 +21,8 @@ public class WdtWeatherSource: WeatherSource {
private static let updateUrlMega = "https://1weather.onelouder.com/feeds/onelouder/mega.php"
private static let updateUrlMicro = "https://1weather.onelouder.com/feeds/onelouder2/fm.php"
public let weatherUpdateInterval = TimeInterval(15 * 60) // 15 minutes
public func updateWeather(for location: Location, completion: @escaping WeatherSourceCompletion) {
log.debug("Start update.")
guard var urlComponents = URLComponents(string: WdtWeatherSource.updateUrlMega) else {
......
......@@ -10,5 +10,6 @@ import Foundation
public typealias WeatherSourceCompletion = (Location?, Error?) -> ()
public protocol WeatherSource {
var weatherUpdateInterval: TimeInterval { get }
func updateWeather(for location: Location, completion: @escaping WeatherSourceCompletion)
}
......@@ -44,4 +44,8 @@ extension TodayViewModel: LocationManagerDelegate {
self.delegate?.viewModelDidChange(model: self)
}
}
func locationManager(_ locationManager: LocationManager, updatedLocationsList newList: [Location]) {
// do nothing
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment