diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Reactor.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Reactor.xcscheme
new file mode 100644
index 0000000..c6dcf86
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/Reactor.xcscheme
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/AsyncReactorExample.xcodeproj/xcshareddata/xcschemes/AsyncReactorExample.xcscheme b/Example/AsyncReactorExample.xcodeproj/xcshareddata/xcschemes/AsyncReactorExample.xcscheme
new file mode 100644
index 0000000..119d051
--- /dev/null
+++ b/Example/AsyncReactorExample.xcodeproj/xcshareddata/xcschemes/AsyncReactorExample.xcscheme
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/AsyncReactorExample/ContentView.swift b/Example/AsyncReactorExample/ContentView.swift
index de85640..b437d48 100644
--- a/Example/AsyncReactorExample/ContentView.swift
+++ b/Example/AsyncReactorExample/ContentView.swift
@@ -9,10 +9,8 @@ struct ContentView: View {
}
}
-struct ContentView_Previews: PreviewProvider {
- static var previews: some View {
- NavigationStack {
- ContentView()
- }
+#Preview {
+ NavigationStack {
+ ContentView()
}
}
diff --git a/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDescriptionSheet.swift b/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDescriptionSheet.swift
index 463c8a9..e8a8d44 100644
--- a/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDescriptionSheet.swift
+++ b/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDescriptionSheet.swift
@@ -16,8 +16,6 @@ struct RepositoryDescriptionSheet: View {
}
}
-struct RepositoryDescriptionSheet_Previews: PreviewProvider {
- static var previews: some View {
- RepositoryDescriptionSheet(description: "Description")
- }
+#Preview {
+ RepositoryDescriptionSheet(description: "Description")
}
diff --git a/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDetailView.swift b/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDetailView.swift
index 38c08c8..1f10304 100644
--- a/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDetailView.swift
+++ b/Example/AsyncReactorExample/Features/Repository/Detail/RepositoryDetailView.swift
@@ -77,11 +77,9 @@ struct RepositoryDetailView: View {
}
}
-struct RepositoryDetailView_Previews: PreviewProvider {
- static var previews: some View {
- NavigationStack {
- RepositoryDetailView(repository: Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ultricies nisi elit, non imperdiet nibh euismod in. Sed sit amet tincidunt arcu, nec ornare nisl. Pellentesque sollicitudin quam quis elit tempus, et interdum lorem tristique. Nunc rhoncus ornare efficitur. Ut tellus libero, pretium sit amet dolor a, maximus scelerisque sem. Phasellus posuere aliquam purus. Mauris justo tellus, molestie ut eros at, lobortis luctus nulla. Nullam libero leo, sagittis ac orci nec, viverra faucibus lacus. Phasellus faucibus ipsum nec velit mattis tincidunt. Phasellus nulla mauris, lobortis ac quam non, consectetur viverra odio. Praesent sed venenatis nulla. Praesent non maximus sem, quis ultricies ligula. Aliquam eleifend non velit eget venenatis. Vivamus aliquet, nisl vestibulum cursus aliquet, neque justo feugiat magna, eu suscipit turpis mi id orci.", htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")))
- }
- .environmentObject(RepositoryDetailReactor())
+#Preview {
+ NavigationStack {
+ RepositoryDetailView(repository: Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ultricies nisi elit, non imperdiet nibh euismod in. Sed sit amet tincidunt arcu, nec ornare nisl. Pellentesque sollicitudin quam quis elit tempus, et interdum lorem tristique. Nunc rhoncus ornare efficitur. Ut tellus libero, pretium sit amet dolor a, maximus scelerisque sem. Phasellus posuere aliquam purus. Mauris justo tellus, molestie ut eros at, lobortis luctus nulla. Nullam libero leo, sagittis ac orci nec, viverra faucibus lacus. Phasellus faucibus ipsum nec velit mattis tincidunt. Phasellus nulla mauris, lobortis ac quam non, consectetur viverra odio. Praesent sed venenatis nulla. Praesent non maximus sem, quis ultricies ligula. Aliquam eleifend non velit eget venenatis. Vivamus aliquet, nisl vestibulum cursus aliquet, neque justo feugiat magna, eu suscipit turpis mi id orci.", htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")))
}
+ .environmentObject(RepositoryDetailReactor())
}
diff --git a/Example/AsyncReactorExample/Features/Repository/Search/RepositoryItem.swift b/Example/AsyncReactorExample/Features/Repository/Search/RepositoryItem.swift
index b249662..4507ae5 100644
--- a/Example/AsyncReactorExample/Features/Repository/Search/RepositoryItem.swift
+++ b/Example/AsyncReactorExample/Features/Repository/Search/RepositoryItem.swift
@@ -31,8 +31,6 @@ struct RepositoryItem: View {
}
}
-struct RepositoryItem_Previews: PreviewProvider {
- static var previews: some View {
- RepositoryItem(repository: Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "", htmlUrl: "google.com", watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")))
- }
+#Preview {
+ RepositoryItem(repository: Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "", htmlUrl: "google.com", watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")))
}
diff --git a/Example/AsyncReactorExample/Features/Repository/Search/RepositoryList.swift b/Example/AsyncReactorExample/Features/Repository/Search/RepositoryList.swift
index 485a9c0..31e891f 100644
--- a/Example/AsyncReactorExample/Features/Repository/Search/RepositoryList.swift
+++ b/Example/AsyncReactorExample/Features/Repository/Search/RepositoryList.swift
@@ -18,13 +18,11 @@ struct RepositoryList: View {
}
}
-struct RepositoryList_Previews: PreviewProvider {
- static var previews: some View {
- RepositoryList(repositories: [
- Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "",htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")),
- Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "",htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")),
- Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "",htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")),
- Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "", htmlUrl: "google.com",watchersCount: 1, forks: 1,visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4"))
- ])
- }
+#Preview {
+ RepositoryList(repositories: [
+ Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "",htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")),
+ Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "",htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")),
+ Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "",htmlUrl: "google.com",watchersCount: 1, forks: 1, visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4")),
+ Repository(id: 0, name: "Test Repo", fullName: "github/Test Repo", description: "", htmlUrl: "google.com",watchersCount: 1, forks: 1,visibility: "public", owner: Repository.Owner(avatarUrl: "https://avatars.githubusercontent.com/u/60294?v=4"))
+ ])
}
diff --git a/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchReactor.swift b/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchReactor.swift
index 7e7bb4f..82e3053 100644
--- a/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchReactor.swift
+++ b/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchReactor.swift
@@ -29,7 +29,7 @@ enum SortOptions: String, CaseIterable, Identifiable {
}
class RepositorySearchReactor: AsyncReactor {
- enum Action {
+ enum AsyncAction {
case onHidePrivateToggle
case enterQuery(String)
case load
@@ -66,7 +66,7 @@ class RepositorySearchReactor: AsyncReactor {
}
}
- func action(_ action: Action) async {
+ func action(_ action: AsyncAction) async {
switch action {
case .onHidePrivateToggle:
state.hidePrivate.toggle()
diff --git a/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchView.swift b/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchView.swift
index e979d5e..462305c 100644
--- a/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchView.swift
+++ b/Example/AsyncReactorExample/Features/Repository/Search/RepositorySearchView.swift
@@ -13,13 +13,26 @@ struct RepositorySearchView: View {
@EnvironmentObject
private var reactor: RepositorySearchReactor
- @ActionBinding(RepositorySearchReactor.self, keyPath: \.hidePrivate, action: RepositorySearchReactor.SyncAction.toggleHidePrivate)
+ @ActionBinding(
+ RepositorySearchReactor.self,
+ keyPath: \.hidePrivate,
+ action: RepositorySearchReactor.SyncAction.toggleHidePrivate
+ )
private var hidePrivate: Bool
- @ActionBinding(RepositorySearchReactor.self, keyPath: \.query, cancelId: .init(id: "enterQuery", mode: .inFlight), action: RepositorySearchReactor.Action.enterQuery)
+ @ActionBinding(
+ RepositorySearchReactor.self,
+ keyPath: \.query,
+ cancelId: .init(id: "enterQuery", mode: .inFlight),
+ action: RepositorySearchReactor.AsyncAction.enterQuery
+ )
private var query: String
- @ActionBinding(RepositorySearchReactor.self, keyPath: \.sortBy, action: RepositorySearchReactor.Action.onSortOptionSelected)
+ @ActionBinding(
+ RepositorySearchReactor.self,
+ keyPath: \.sortBy,
+ action: RepositorySearchReactor.AsyncAction.onSortOptionSelected
+ )
private var sortOption: SortOptions
var body: some View {
@@ -78,11 +91,8 @@ struct RepositorySearchView: View {
}
}
-struct RepositorySearchView_Previews: PreviewProvider {
- static var previews: some View {
- ReactorView(RepositorySearchReactor()) {
- RepositorySearchView()
- }
+#Preview {
+ ReactorView(RepositorySearchReactor()) {
+ RepositorySearchView()
}
}
-
diff --git a/Sources/AsyncReactor/AsyncReactor+SwiftUI.swift b/Sources/AsyncReactor/AsyncReactor+SwiftUI.swift
index 19160d0..8587241 100644
--- a/Sources/AsyncReactor/AsyncReactor+SwiftUI.swift
+++ b/Sources/AsyncReactor/AsyncReactor+SwiftUI.swift
@@ -21,25 +21,48 @@ public struct ActionBinding: DynamicProper
let cancelId: CancelId?
- public init(_ reactorType: Reactor.Type, keyPath: KeyPath, cancelId: CancelId? = nil, action: @escaping (Value) -> Reactor.Action) where Action == Reactor.Action {
+ public init(
+ _ reactorType: Reactor.Type,
+ keyPath: KeyPath,
+ cancelId: CancelId? = nil,
+ action: @escaping (Value) -> Reactor.AsyncAction
+ ) where Action == Reactor.AsyncAction {
target = EnvironmentObject()
self.keyPath = keyPath
self.action = action
self.cancelId = cancelId
}
- public init(_ reactorType: Reactor.Type, keyPath: KeyPath, cancelId: CancelId? = nil, action: @escaping @autoclosure () -> Reactor.Action) where Action == Reactor.Action {
- self.init(reactorType, keyPath: keyPath, cancelId: cancelId, action: { _ in action() })
+ public init(
+ _ reactorType: Reactor.Type,
+ keyPath: KeyPath,
+ cancelId: CancelId? = nil,
+ action: @escaping @autoclosure () -> Reactor.AsyncAction
+ ) where Action == Reactor.AsyncAction {
+ self.init(
+ reactorType,
+ keyPath: keyPath,
+ cancelId: cancelId,
+ action: { _ in action() }
+ )
}
- public init(_ reactorType: Reactor.Type, keyPath: KeyPath, action: @escaping (Value) -> Reactor.SyncAction) where Action == Reactor.SyncAction {
+ public init(
+ _ reactorType: Reactor.Type,
+ keyPath: KeyPath,
+ action: @escaping (Value) -> Reactor.SyncAction
+ ) where Action == Reactor.SyncAction {
target = EnvironmentObject()
self.keyPath = keyPath
self.action = action
cancelId = nil
}
- public init(_ reactorType: Reactor.Type, keyPath: KeyPath, action: @escaping @autoclosure () -> Reactor.SyncAction) where Action == Reactor.SyncAction {
+ public init(
+ _ reactorType: Reactor.Type,
+ keyPath: KeyPath,
+ action: @escaping @autoclosure () -> Reactor.SyncAction
+ ) where Action == Reactor.SyncAction {
self.init(reactorType, keyPath: keyPath, action: { _ in action() })
}
@@ -51,7 +74,7 @@ public struct ActionBinding: DynamicProper
public var projectedValue: Binding {
get {
func bindAction() -> Binding {
- target.wrappedValue.bind(keyPath, cancelId: cancelId, action: action as! (Value) -> Reactor.Action)
+ target.wrappedValue.bind(keyPath, cancelId: cancelId, action: action as! (Value) -> Reactor.AsyncAction)
}
func bindSyncAction() -> Binding {
@@ -60,7 +83,7 @@ public struct ActionBinding: DynamicProper
if Action.self == Reactor.SyncAction.self {
return bindSyncAction()
- } else if Action.self == Reactor.Action.self {
+ } else if Action.self == Reactor.AsyncAction.self {
return bindAction()
} else {
fatalError("this should never happen :)")
@@ -76,7 +99,11 @@ public struct ReactorView: View {
@StateObject
private var reactor: R
- public init(_ reactor: @escaping @autoclosure () -> R, definesLifecycle: Bool = true, @ViewBuilder content: () -> Content) {
+ public init(
+ _ reactor: @escaping @autoclosure () -> R,
+ definesLifecycle: Bool = true,
+ @ViewBuilder content: () -> Content
+ ) {
_reactor = StateObject(wrappedValue: reactor())
self.content = content()
self.definesLifecycle = definesLifecycle
diff --git a/Sources/Reactor/Reactor+SwiftUI.swift b/Sources/Reactor/Reactor+SwiftUI.swift
index 1ea4a72..2f0490f 100644
--- a/Sources/Reactor/Reactor+SwiftUI.swift
+++ b/Sources/Reactor/Reactor+SwiftUI.swift
@@ -22,25 +22,43 @@ public struct ActionBinding: DynamicProperty {
let cancelId: CancelId?
- public init(_ reactorType: R.Type, keyPath: KeyPath, cancelId: CancelId? = nil, action: @escaping (Value) -> R.Action) where Action == R.Action {
+ public init(
+ _ reactorType: R.Type,
+ keyPath: KeyPath,
+ cancelId: CancelId? = nil,
+ action: @escaping (Value) -> R.AsyncAction
+ ) where Action == R.AsyncAction {
target = Environment(R.self)
self.keyPath = keyPath
self.action = action
self.cancelId = cancelId
}
- public init(_ reactorType: R.Type, keyPath: KeyPath, cancelId: CancelId? = nil, action: @escaping @autoclosure () -> R.Action) where Action == R.Action {
+ public init(
+ _ reactorType: R.Type,
+ keyPath: KeyPath,
+ cancelId: CancelId? = nil,
+ action: @escaping @autoclosure () -> R.AsyncAction
+ ) where Action == R.AsyncAction {
self.init(reactorType, keyPath: keyPath, cancelId: cancelId, action: { _ in action() })
}
- public init(_ reactorType: R.Type, keyPath: KeyPath, action: @escaping (Value) -> R.SyncAction) where Action == R.SyncAction {
+ public init(
+ _ reactorType: R.Type,
+ keyPath: KeyPath,
+ action: @escaping (Value) -> R.SyncAction
+ ) where Action == R.SyncAction {
target = Environment(R.self)
self.keyPath = keyPath
self.action = action
cancelId = nil
}
- public init(_ reactorType: R.Type, keyPath: KeyPath, action: @escaping @autoclosure () -> R.SyncAction) where Action == R.SyncAction {
+ public init(
+ _ reactorType: R.Type,
+ keyPath: KeyPath,
+ action: @escaping @autoclosure () -> R.SyncAction
+ ) where Action == R.SyncAction {
self.init(reactorType, keyPath: keyPath, action: { _ in action() })
}
@@ -52,7 +70,7 @@ public struct ActionBinding: DynamicProperty {
public var projectedValue: Binding {
get {
func bindAction() -> Binding {
- target.wrappedValue.bind(keyPath, cancelId: cancelId, action: action as! (Value) -> R.Action)
+ target.wrappedValue.bind(keyPath, cancelId: cancelId, action: action as! (Value) -> R.AsyncAction)
}
func bindSyncAction() -> Binding {
@@ -61,7 +79,7 @@ public struct ActionBinding: DynamicProperty {
if Action.self == R.SyncAction.self {
return bindSyncAction()
- } else if Action.self == R.Action.self {
+ } else if Action.self == R.AsyncAction.self {
return bindAction()
} else {
fatalError("this should never happen :)")
@@ -78,7 +96,11 @@ public struct ReactorView: View {
@State
private var reactor: R
- public init(_ reactor: @escaping @autoclosure () -> R, definesLifecycle: Bool = true, @ViewBuilder content: () -> Content) {
+ public init(
+ _ reactor: @escaping @autoclosure () -> R,
+ definesLifecycle: Bool = true,
+ @ViewBuilder content: () -> Content
+ ) {
_reactor = State(initialValue: reactor())
self.content = content()
self.definesLifecycle = definesLifecycle
diff --git a/Sources/ReactorBase/ReactorBase+SwiftUI.swift b/Sources/ReactorBase/ReactorBase+SwiftUI.swift
index 3b03173..dd186f3 100644
--- a/Sources/ReactorBase/ReactorBase+SwiftUI.swift
+++ b/Sources/ReactorBase/ReactorBase+SwiftUI.swift
@@ -10,7 +10,11 @@ import SwiftUI
extension ReactorBase {
@MainActor
- public func bind(_ keyPath: KeyPath, cancelId: CancelId? = nil, action: @escaping (T) -> Action) -> Binding {
+ public func bind(
+ _ keyPath: KeyPath,
+ cancelId: CancelId? = nil,
+ action: @escaping (T) -> AsyncAction
+ ) -> Binding {
Binding {
self.state[keyPath: keyPath]
} set: { newValue in
@@ -25,12 +29,19 @@ extension ReactorBase {
}
@MainActor
- public func bind(_ keyPath: KeyPath, cancelId: CancelId? = nil, action: @escaping @autoclosure () -> Action) -> Binding {
+ public func bind(
+ _ keyPath: KeyPath
+ , cancelId: CancelId? = nil,
+ action: @escaping @autoclosure () -> AsyncAction
+ ) -> Binding {
bind(keyPath, cancelId: cancelId) { _ in action() }
}
@MainActor
- public func bind(_ keyPath: KeyPath, action: @escaping (T) -> SyncAction) -> Binding {
+ public func bind(
+ _ keyPath: KeyPath,
+ action: @escaping (T) -> SyncAction
+ ) -> Binding {
Binding {
self.state[keyPath: keyPath]
} set: { newValue in
@@ -39,7 +50,10 @@ extension ReactorBase {
}
@MainActor
- public func bind(_ keyPath: KeyPath, action: @escaping @autoclosure () -> SyncAction) -> Binding {
+ public func bind(
+ _ keyPath: KeyPath,
+ action: @escaping @autoclosure () -> SyncAction
+ ) -> Binding {
bind(keyPath) { _ in action() }
}
}
diff --git a/Sources/ReactorBase/ReactorBase.swift b/Sources/ReactorBase/ReactorBase.swift
index 48f38f7..eacd155 100644
--- a/Sources/ReactorBase/ReactorBase.swift
+++ b/Sources/ReactorBase/ReactorBase.swift
@@ -10,13 +10,13 @@ import Foundation
@MainActor
@dynamicMemberLookup
public protocol ReactorBase: AnyObject {
- associatedtype Action = Never
+ associatedtype AsyncAction = Never
associatedtype SyncAction = Never
associatedtype State
var state: State { get }
- func action(_ action: Action) async
+ func action(_ action: AsyncAction) async
func action(_ action: SyncAction)
@@ -25,13 +25,13 @@ public protocol ReactorBase: AnyObject {
extension ReactorBase {
@MainActor
- public func send(_ action: Action) {
+ public func send(_ action: AsyncAction) {
Task { await self.action(action) }
}
}
-extension ReactorBase where Action == Never {
- public func action(_ action: Action) async {
+extension ReactorBase where AsyncAction == Never {
+ public func action(_ action: AsyncAction) async {
}
}
@@ -91,7 +91,7 @@ struct TaskKey: Hashable {
extension ReactorBase {
@MainActor
- public func action(_ action: Action, id: CancelId) async {
+ public func action(_ action: AsyncAction, id: CancelId) async {
let key = TaskKey(reactor: self, id: id)
if id.mode.contains(.inFlight) {
@@ -111,7 +111,7 @@ extension ReactorBase {
}
}
- public func send(_ action: Action, id: CancelId) {
+ public func send(_ action: AsyncAction, id: CancelId) {
Task { await self.action(action, id: id) }
}