Skip to content

Commit 192dadd

Browse files
authored
Add animation operator to Effect. (pointfreeco#1134)
* Add animation operator to Effect. * Define it only on Effect.
1 parent 65a5320 commit 192dadd

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import Combine
2+
import SwiftUI
3+
4+
extension Effect {
5+
/// Wraps the emission of each element with SwiftUI's `withAnimation`.
6+
///
7+
/// This publisher is most useful when using with ``Effect/task(priority:operation:)-2czg0``
8+
///
9+
/// ```swift
10+
/// case .buttonTapped:
11+
/// return .task {
12+
/// .activityResponse(await environment.apiClient.fetchActivity())
13+
/// }
14+
/// .animation()
15+
/// ```
16+
///
17+
/// - Parameter animation: An animation.
18+
/// - Returns: A publisher.
19+
public func animation(_ animation: Animation? = .default) -> Self {
20+
AnimatedPublisher(upstream: self, animation: animation)
21+
.eraseToEffect()
22+
}
23+
}
24+
25+
private struct AnimatedPublisher<Upstream: Publisher>: Publisher {
26+
typealias Output = Upstream.Output
27+
typealias Failure = Upstream.Failure
28+
29+
var upstream: Upstream
30+
var animation: Animation?
31+
32+
func receive<S: Combine.Subscriber>(subscriber: S)
33+
where S.Input == Output, S.Failure == Failure {
34+
let conduit = Subscriber(downstream: subscriber, animation: self.animation)
35+
self.upstream.receive(subscriber: conduit)
36+
}
37+
38+
private class Subscriber<Downstream: Combine.Subscriber>: Combine.Subscriber {
39+
typealias Input = Downstream.Input
40+
typealias Failure = Downstream.Failure
41+
42+
let downstream: Downstream
43+
let animation: Animation?
44+
45+
init(downstream: Downstream, animation: Animation?) {
46+
self.downstream = downstream
47+
self.animation = animation
48+
}
49+
50+
func receive(subscription: Subscription) {
51+
self.downstream.receive(subscription: subscription)
52+
}
53+
54+
func receive(_ input: Input) -> Subscribers.Demand {
55+
withAnimation(self.animation) {
56+
self.downstream.receive(input)
57+
}
58+
}
59+
60+
func receive(completion: Subscribers.Completion<Failure>) {
61+
self.downstream.receive(completion: completion)
62+
}
63+
}
64+
}

Sources/ComposableArchitecture/TestSupport/TestStore.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@
176176

177177
/// The current state.
178178
///
179-
/// When read from a trailing closure assertion in ``send`` or ``receive``, it will equal the
180-
/// `inout` state passed to the closure.
179+
/// When read from a trailing closure assertion in ``send(_:_:file:line:)`` or
180+
/// ``receive(_:_:file:line:)``, it will equal the `inout` state passed to the closure.
181181
public private(set) var state: State
182182

183183
private let file: StaticString

0 commit comments

Comments
 (0)