├── diagrams
├── movies.gif
├── signin.png
├── counter.gif
├── traffic_light.gif
├── ReactiveFeedback.jpg
└── ReactiveFeedback.xml
├── Example
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── Helpers
│ ├── Log.swift
│ └── PublisherExtensions.swift
├── Views
│ ├── StoreExtensions.swift
│ ├── Activity.swift
│ └── AsyncImage.swift
├── SingleStoreExample
│ ├── Counter
│ │ └── CounterState.swift
│ ├── SingleStoreExampleView.swift
│ ├── SwitchStoreExample
│ │ └── SwitchStoreExample.swift
│ ├── Movies
│ │ ├── MoviesState.swift
│ │ └── FavouriteMovies.swift
│ ├── TrafficLight
│ │ └── TrafficLightState.swift
│ ├── State.swift
│ └── Signin
│ │ └── SigninState.swift
├── TrafficLight
│ ├── TrafficLightView.swift
│ └── TrafficLight.swift
├── CounterExample
│ └── Counter.swift
├── Base.lproj
│ └── LaunchScreen.storyboard
├── Info.plist
├── SceneDelegate.swift
├── MoviesExample
│ └── Movies.swift
└── SignIn
│ └── SignIn.swift
├── ExampleTests
├── ExampleTests.swift
└── Info.plist
├── CombineFeedback.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
├── xcshareddata
│ └── xcschemes
│ │ └── Example.xcscheme
└── project.pbxproj
├── Sources
└── CombineFeedback
│ ├── Internal
│ ├── NSLockExtensions.swift
│ ├── FeedbackEventConsumer.swift
│ ├── Atomic.swift
│ └── Floodgate.swift
│ ├── System.swift
│ ├── Info.plist
│ ├── FeedbackLoop.swift
│ ├── FlatMapLatest.swift
│ ├── SwiftUI
│ ├── WithContextView.swift
│ ├── IfLetStoreView.swift
│ ├── ViewContext.swift
│ └── SwitchStoreView.swift
│ ├── Store
│ ├── Store.swift
│ └── StoreBox.swift
│ ├── Reducer.swift
│ └── Feedback.swift
├── .github
└── workflows
│ └── swift.yml
├── Package.resolved
├── Tests
└── CombineFeedbackTests
│ ├── Info.plist
│ └── CombineFeedbackTests.swift
├── Package.swift
├── LICENSE
├── .gitignore
└── README.md
/diagrams/movies.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sergdort/CombineFeedback/HEAD/diagrams/movies.gif
--------------------------------------------------------------------------------
/diagrams/signin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sergdort/CombineFeedback/HEAD/diagrams/signin.png
--------------------------------------------------------------------------------
/diagrams/counter.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sergdort/CombineFeedback/HEAD/diagrams/counter.gif
--------------------------------------------------------------------------------
/diagrams/traffic_light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sergdort/CombineFeedback/HEAD/diagrams/traffic_light.gif
--------------------------------------------------------------------------------
/diagrams/ReactiveFeedback.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sergdort/CombineFeedback/HEAD/diagrams/ReactiveFeedback.jpg
--------------------------------------------------------------------------------
/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ExampleTests/ExampleTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import Example
3 |
4 | class ExampleTests: XCTestCase {
5 | }
6 |
--------------------------------------------------------------------------------
/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @UIApplicationMain
4 | class AppDelegate: UIResponder, UIApplicationDelegate {
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/Example/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/CombineFeedback.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Helpers/Log.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | func logInit(of object: T) {
4 | print("Init of", type(of: object))
5 | }
6 |
7 | func logBody(of view: T) {
8 | print("Body of", type(of: view))
9 | }
10 |
--------------------------------------------------------------------------------
/Sources/CombineFeedback/Internal/NSLockExtensions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension NSLock {
4 | func perform(_ action: () -> Result) -> Result {
5 | lock()
6 | defer { unlock() }
7 |
8 | return action()
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/CombineFeedback.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Views/StoreExtensions.swift:
--------------------------------------------------------------------------------
1 | import CombineFeedback
2 |
3 | extension Store {
4 | static func empty(_ state: State) -> Store {
5 | Store(initial: state, feedbacks: [], reducer: .empty, dependency: ())
6 | }
7 | }
8 |
9 | extension Reducer {
10 | static var empty: Reducer {
11 | Reducer(reduce: { _, _ in })
12 | }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/.github/workflows/swift.yml:
--------------------------------------------------------------------------------
1 | name: Swift
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: macos-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Build
17 | run: swift build -v
18 | - name: Run tests
19 | run: swift test -v
20 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "CasePaths",
6 | "repositoryURL": "https://github.com/pointfreeco/swift-case-paths.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "a9c1e05518b6d95cf5844d823020376f2b6ff842",
10 | "version": "0.1.0"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Example/Helpers/PublisherExtensions.swift:
--------------------------------------------------------------------------------
1 | import Combine
2 |
3 | extension Publisher {
4 | public func replaceError(
5 | replace: @escaping (Failure) -> Self.Output
6 | ) -> AnyPublisher {
7 | return `catch` { error in
8 | Result.Publisher(replace(error))
9 | }.eraseToAnyPublisher()
10 | }
11 |
12 | public func ignoreError() -> AnyPublisher