Skip to content

Commit af9c688

Browse files
committed
Add a Toast Reducer
1 parent 8593273 commit af9c688

1 file changed

Lines changed: 52 additions & 6 deletions

File tree

Tool/Sources/Toast/Toast.swift

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import ComposableArchitecture
2+
import Dependencies
13
import Foundation
24
import SwiftUI
3-
import Dependencies
45

56
public enum ToastType {
67
case info
@@ -28,14 +29,12 @@ public extension DependencyValues {
2829
get { self[ToastControllerDependencyKey.self] }
2930
set { self[ToastControllerDependencyKey.self] = newValue }
3031
}
31-
32-
var toast: (String, ToastType) -> Void {
33-
get { toastController.toast }
34-
}
32+
33+
var toast: (String, ToastType) -> Void { toastController.toast }
3534
}
3635

3736
public class ToastController: ObservableObject {
38-
public struct Message: Identifiable {
37+
public struct Message: Identifiable, Equatable {
3938
public var id: UUID
4039
public var type: ToastType
4140
public var content: Text
@@ -69,3 +68,50 @@ public class ToastController: ObservableObject {
6968
}
7069
}
7170

71+
public struct Toast: ReducerProtocol {
72+
public typealias Message = ToastController.Message
73+
public struct State: Equatable {
74+
public var messages: [Message] = []
75+
}
76+
77+
public enum Action: Equatable {
78+
case appear
79+
case updateMessages([Message])
80+
case toast(String, ToastType)
81+
}
82+
83+
@Dependency(\.toastController) var toastController
84+
85+
struct CancelID: Hashable {}
86+
87+
public init() {}
88+
89+
public var body: some ReducerProtocol<State, Action> {
90+
Reduce { state, action in
91+
switch action {
92+
case .appear:
93+
return .run { send in
94+
let stream = AsyncStream<[Message]> { continuation in
95+
let cancellable = toastController.$messages.sink { newValue in
96+
continuation.yield(newValue)
97+
}
98+
continuation.onTermination = { _ in
99+
cancellable.cancel()
100+
}
101+
}
102+
for await newValue in stream {
103+
try Task.checkCancellation()
104+
await send(.updateMessages(newValue))
105+
}
106+
}.cancellable(id: CancelID(), cancelInFlight: true)
107+
case let .updateMessages(messages):
108+
state.messages = messages
109+
return .none
110+
case let .toast(content, type):
111+
toastController.toast(content: content, type: type)
112+
return .none
113+
}
114+
}
115+
}
116+
}
117+

0 commit comments

Comments
 (0)