Skip to content

Instantly share code, notes, and snippets.

@ocapmycap
Created November 29, 2023 02:08
Show Gist options
  • Save ocapmycap/b96f04343dc98effae98d15a4e7376ca to your computer and use it in GitHub Desktop.
Save ocapmycap/b96f04343dc98effae98d15a4e7376ca to your computer and use it in GitHub Desktop.
//
// Card.swift
// ObservableArchitecture
//
// Created by Brian Lane on 11/28/23.
//
import SwiftUI
import ComposableArchitecture
@Reducer
public struct CardList: Reducer {
// MARK: - Dependencies
// MARK: - State
@ObservableState
public struct State: Equatable {
var cards: IdentifiedArrayOf<Card.State>
public init(cards: IdentifiedArrayOf<Card.State> = []) {
self.cards = cards
}
}
// MARK: - Action
public enum Action: Equatable {
case addCard
case cards(IdentifiedActionOf<Card>)
}
// MARK: - Reducer
public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .addCard:
state.cards.append(Card.State.randomCard())
return .none
case .cards(_):
return .none
}
}
}}
public struct CardListView: View {
let store: StoreOf<CardList>
public init(store: StoreOf<CardList>) {
self.store = store
}
public var body: some View {
WithPerceptionTracking {
VStack {
Button {
store.send(.addCard)
} label: {
Text("Add card")
}
List {
ForEach(store.scope(state: \.cards, action: \.cards)) { store in
CardView(store: store)
}
}
}
}
}
}
struct CardListView_Previews: PreviewProvider {
static var previews: some View {
CardListView(
store: Store(
initialState: CardList.State(cards: .mock),
reducer: { CardList() }
)
)
}
}
@Reducer
public struct Card: Reducer {
// MARK: - Dependencies
// MARK: - State
@ObservableState
public enum State: Equatable, Identifiable {
case cardA(CardA.State)
case cardB(CardB.State)
public var id: UUID {
switch self {
case .cardA(let state):
return state.id
case .cardB(let state):
return state.id
}
}
public init() {
self = .cardA(CardA.State())
}
public static func randomCard() -> Card.State {
return Bool.random() ? .cardA(CardA.State()) : .cardB(CardB.State())
}
}
// MARK: - Action
public enum Action: Equatable {
case cardA(CardA.Action)
case cardB(CardB.Action)
}
// MARK: - Reducer
public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .cardA:
return .none
case .cardB:
return .none
}
}
}
}
public struct CardView: View {
let store: StoreOf<Card>
public init(store: StoreOf<Card>) {
self.store = store
}
public var body: some View {
WithPerceptionTracking {
switch store.state {
case .cardA(let state):
CardAView(store: Store(initialState: state, reducer: { CardA()}))
case .cardB(let state):
CardBView(store: Store(initialState: state, reducer: { CardB()}))
}
}
}
}
@Reducer
public struct CardA: Reducer {
// MARK: - Dependencies
// MARK: - State
@ObservableState
public struct State: Equatable, Identifiable {
public let id = UUID()
var title: String = ""
}
// MARK: - Action
public enum Action: Equatable {
case titleChanged(String)
}
// MARK: - Reducer
public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .titleChanged(let newValue):
state.title = newValue
return .none
}
}
}
}
public struct CardAView: View {
@State var store: StoreOf<CardA>
public init(store: StoreOf<CardA>) {
self.store = store
}
public var body: some View {
TextField("Title", text: $store.title.sending(\.titleChanged)) // <--- could not get simple $store.title to work
}
}
struct CardAView_Previews: PreviewProvider {
static var previews: some View {
CardAView(store: Store(initialState: CardA.State(), reducer: { CardA() }))
}
}
@Reducer
public struct CardB: Reducer {
// MARK: - Dependencies
// MARK: - State
@ObservableState
public struct State: Equatable, Identifiable {
public let id = UUID()
var icon: Icon = .lady
public enum Icon {
case man
case lady
public var image: Image {
switch self {
case .man:
return Image(systemName: "figure.strengthtraining.functional")
case .lady:
return Image(systemName: "ladybug")
}
}
mutating public func toggle() {
self = self == .lady ? .man : .lady
}
}
}
// MARK: - Action
public enum Action: Equatable {
case toggle
}
// MARK: - Reducer
public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .toggle:
state.icon.toggle()
return .none
}
}
}
}
public struct CardBView: View {
let store: StoreOf<CardB>
public init(store: StoreOf<CardB>) {
self.store = store
}
public var body: some View {
HStack {
store.icon.image
Button {
store.send(.toggle)
} label: {
Text("Toggle")
}
}
}
}
struct CardBView_Previews: PreviewProvider {
static var previews: some View {
CardBView(store: Store(initialState: CardB.State(), reducer: { CardB() })
)
}
}
extension IdentifiedArray where ID == Card.State.ID, Element == Card.State {
static let mock: Self = [
Card.State(),
Card.State(),
Card.State()
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment