Last active
October 30, 2017 19:38
-
-
Save soxjke/3efeaef6d762a33df3ac459489d54fe1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Redux_ReactiveSwift | |
extension AppState: Defaultable { | |
static var defaultValue: AppState = AppState(location: AppLocation(locationState: .notYetRequested, | |
locationRequestState: .none), | |
weather: AppWeather(geopositionRequestState: .none, | |
weatherRequestState: .none)) | |
} | |
final class AppStore: Store<AppState, AppEvent> { | |
static let shared: AppStore = AppStore() | |
private init() { | |
super.init(state: AppState.defaultValue, reducers: [self.reducer]) | |
} | |
required init(state: AppState, reducers: [AppStore.Reducer]) { | |
fatalError("init(state:reducers:) cannot be called on type AppStore. Use `shared` accessor") | |
} | |
private func reducer(state: AppState, event: AppEvent) -> AppState { | |
return AppState(location: locationReducer(state.location, event), | |
weather: weatherReducer(state.weather, event)) | |
} | |
// MARK: Location reducers | |
private func locationReducer(_ state: AppLocation, _ event: AppEvent) -> AppLocation { | |
switch event { | |
case .locationPermissionResult(let success): return location(permissionResult: success, previous: state) | |
case .locationRequest: return locationRequest(previous: state) | |
case .locationResult(let latitude, let longitude, let timestamp, let error): | |
return locationResult(latitude: latitude, longitude: longitude, timestamp: timestamp, error: error, previous: state) | |
default: return state | |
} | |
} | |
private func location(permissionResult: Bool, previous: AppLocation) -> AppLocation { | |
return AppLocation(locationState: permissionResult ? .available : .notAvailable, | |
locationRequestState: previous.locationRequestState) | |
} | |
private func locationRequest(previous: AppLocation) -> AppLocation { | |
guard case .available = previous.locationState else { return previous } | |
if case .success(_, _, let timestamp) = previous.locationRequestState { | |
if (Date().timeIntervalSince1970 - timestamp < 300) { // Don't do update if location succeeded within last 5 minutes | |
return previous | |
} | |
} | |
return AppLocation(locationState: previous.locationState, locationRequestState: .updating) // Perform location update | |
} | |
private func locationResult(latitude: Double, longitude: Double, timestamp: TimeInterval, error: Swift.Error?, previous: AppLocation) -> AppLocation { | |
guard let error = error else { | |
return AppLocation(locationState: previous.locationState, locationRequestState: .success(latitude: latitude, longitude: longitude, timestamp: timestamp)) | |
} | |
return AppLocation(locationState: previous.locationState, locationRequestState: .error(error: error)) | |
} | |
// MARK: Weather reducers | |
private func weatherReducer(_ state: AppWeather, _ event: AppEvent) -> AppWeather { | |
switch event { | |
case .geopositionRequest: return geopositionRequest(previous: state) | |
case .geopositionResult(let geoposition, let error): return geopositionResult(geoposition: geoposition, error: error, previous: state) | |
case .weatherRequest: return weatherRequest(previous: state) | |
case .weatherResult(let current, let forecast, let error): return weatherResult(current: current, forecast: forecast, error: error, previous: state) | |
default: return state | |
} | |
} | |
private func geopositionRequest(previous: AppWeather) -> AppWeather { | |
return AppWeather(geopositionRequestState: .updating, weatherRequestState: previous.weatherRequestState) | |
} | |
private func geopositionResult(geoposition: Geoposition, error: Swift.Error?, previous: AppWeather) -> AppWeather { | |
guard let error = error else { | |
return AppWeather(geopositionRequestState: .success(geoposition: geoposition), weatherRequestState: previous.weatherRequestState) | |
} | |
return AppWeather(geopositionRequestState: .error(error: error), weatherRequestState: previous.weatherRequestState) | |
} | |
private func weatherRequest(previous: AppWeather) -> AppWeather { | |
return AppWeather(geopositionRequestState: previous.geopositionRequestState, weatherRequestState: .updating) | |
} | |
private func weatherResult(current: Weather, forecast: [Weather], error: Swift.Error?, previous: AppWeather) -> AppWeather { | |
guard let error = error else { | |
return AppWeather(geopositionRequestState: previous.geopositionRequestState, | |
weatherRequestState: .success(currentWeather: current, forecast: forecast)) | |
} | |
return AppWeather(geopositionRequestState: previous.geopositionRequestState, weatherRequestState: .error(error: error)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment