79 lines
2.1 KiB
Swift
79 lines
2.1 KiB
Swift
//
|
|
// FactsFeature.swift
|
|
// Meow
|
|
//
|
|
|
|
import Foundation
|
|
import Core
|
|
import CatFactsKit
|
|
import ComposableArchitecture
|
|
|
|
/// Handles the logic for fetching and displaying a `List` of cat facts from a remote API.
|
|
@Reducer
|
|
public struct FactsFeature {
|
|
@ObservationIgnored
|
|
@Dependency(\.clientFactory) var clientFactory
|
|
|
|
@ObservableState
|
|
public struct State {
|
|
public var baseURL: URL
|
|
public var mode: Mode = .notLoaded
|
|
|
|
public init(baseURL: URL = URL(string: "https://invalid.barf")!, mode: Mode = .notLoaded) {
|
|
self.baseURL = baseURL
|
|
}
|
|
}
|
|
|
|
public enum Mode {
|
|
case notLoaded
|
|
case loading
|
|
case loaded(facts: [String])
|
|
case error(Error)
|
|
}
|
|
|
|
public enum Action {
|
|
case viewAppeared
|
|
case pulledToRefresh
|
|
case fetchNeeded
|
|
case receivedFacts([String])
|
|
case receivedError(Error)
|
|
}
|
|
|
|
// MARK: - Public functionality
|
|
|
|
public init() { }
|
|
|
|
public var body: some ReducerOf<Self> {
|
|
Reduce { state, action in
|
|
switch action {
|
|
case .viewAppeared:
|
|
switch state.mode {
|
|
case .loaded:
|
|
return .none
|
|
default:
|
|
state.mode = .loading
|
|
return .send(.fetchNeeded)
|
|
}
|
|
case .pulledToRefresh:
|
|
return .send(.fetchNeeded)
|
|
case .fetchNeeded:
|
|
let client = clientFactory.createClient(baseURL: state.baseURL)
|
|
return .run { send in
|
|
do {
|
|
let results = try await client.getFacts(count: 5)
|
|
await send(.receivedFacts(results))
|
|
} catch {
|
|
await send(.receivedError(error))
|
|
}
|
|
}
|
|
case let .receivedFacts(facts):
|
|
state.mode = .loaded(facts: facts)
|
|
return .none
|
|
case let .receivedError(error):
|
|
state.mode = .error(error)
|
|
return .none
|
|
}
|
|
}
|
|
}
|
|
}
|