struct AppState {
var settings = Settings()
var pokemonList = PokemonList()
}
extension AppState {
struct Settings {
enum Sorting: CaseIterable {
case id, name, color, favorite
}
var showEnglishName = true
var sorting = Sorting.id
var showFavoriteOnly = false
enum AccountBehavior: CaseIterable {
case register, login
}
var accountBehavior = AccountBehavior.login
var email = ""
var password = ""
var verifyPassword = ""
var loginUser: User?
var loginRequesting = false
var loginError: AppError?
}
}
extension AppState {
struct PokemonList {
var pokemons: [Int: PokemonViewModel]?
var loadingPokemons = false
var allPokemonsByID: [PokemonViewModel] {
guard let pokemons = pokemons?.values else {
return []
}
return pokemons.sorted { $0.id < $1.id }
}
}
}
struct User: Codable {
var email: String
var favoritePokemonIDs: Set
func isFavoritePokemon(id: Int) -> Bool {
favoritePokemonIDs.contains(id)
}
}
这次做了一个获取宠物小精灵列表的demo,当然目前还没有完善,后续会通过进一步的学习来把它做完。封面必须给主角皮卡丘。
先说说思路:
struct AppState { var settings = Settings() var pokemonList = PokemonList() }
extension AppState { struct Settings { enum Sorting: CaseIterable { case id, name, color, favorite } var showEnglishName = true var sorting = Sorting.id var showFavoriteOnly = false
}
extension AppState { struct PokemonList { var pokemons: [Int: PokemonViewModel]? var loadingPokemons = false var allPokemonsByID: [PokemonViewModel] { guard let pokemons = pokemons?.values else { return [] } return pokemons.sorted { $0.id < $1.id } } } }
struct User: Codable { var email: String var favoritePokemonIDs: Set
func isFavoritePokemon(id: Int) -> Bool {
favoritePokemonIDs.contains(id)
}
}
extension AppState.Settings.AccountBehavior { var text: String { switch self { case .register: return "注册" case .login: return "登录" } } }
class Store: ObservableObject { @Published var appState = AppState()
}
enum AppAction { case login(email: String, password: String) case accountBehaviorDone(result: Result<User, AppError>)
}
import Foundation import Combine
struct LoginRequest { let email: String let password: String var publisher: AnyPublisher<User, AppError> { Future { promise in DispatchQueue.global() .asyncAfter(deadline: .now() + 1.5) { if self.password == "password" { let user = User( email: self.email, favoritePokemonIDs: [] ) promise(.success(user)) } else { promise(.failure(.passwordWrong)) } } } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } }
protocol AppCommand { func execute(in store: Store) }
struct LoginAppCommand: AppCommand { let email: String let password: String func execute(in store: Store) { let token = SubscriptionToken()
}
class SubscriptionToken { var cancellable: AnyCancellable? func unseal() { cancellable = nil } } extension AnyCancellable { func seal(in token: SubscriptionToken) { token.cancellable = self } }