-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into github_action
- Loading branch information
Showing
17 changed files
with
567 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 0 additions & 22 deletions
22
{{cookiecutter.app_name}}/Common/Sources/Common/BaseAction.swift
This file was deleted.
Oops, something went wrong.
123 changes: 123 additions & 0 deletions
123
{{cookiecutter.app_name}}/Common/Sources/Common/FeatureReducer.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// | ||
// FeatureReducer.swift | ||
// Common | ||
// | ||
// Created by {{ cookiecutter.creator }} on {% now 'utc', '%d/%m/%Y' %}. | ||
// Copyright © {% now 'utc', '%Y' %} {{cookiecutter.company_name}}. All rights reserved. | ||
// | ||
|
||
import ComposableArchitecture | ||
import SwiftUI | ||
|
||
// MARK: FeatureReducer | ||
public protocol FeatureReducer: Reducer where State: Sendable & Hashable, Action == FeatureAction<Self> { | ||
associatedtype ViewAction: Sendable & Equatable = Never | ||
associatedtype InternalAction: Sendable & Equatable = Never | ||
associatedtype ChildAction: Sendable & Equatable = Never | ||
associatedtype DelegateAction: Sendable & Equatable = Never | ||
|
||
func reduce(into state: inout State, viewAction: ViewAction) -> Effect<Action> | ||
func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> | ||
func reduce(into state: inout State, childAction: ChildAction) -> Effect<Action> | ||
func reduce(into state: inout State, presentedAction: Destination.Action) -> Effect<Action> | ||
func reduceDismissDestination(into state: inout State) -> Effect<Action> | ||
|
||
associatedtype Destination: DestinationReducer = EmptyDestination | ||
associatedtype ViewState: Equatable = Never | ||
} | ||
|
||
extension Reducer where Self: FeatureReducer { | ||
public typealias Action = FeatureAction<Self> | ||
|
||
public var body: some ReducerOf<Self> { | ||
Reduce(core) | ||
} | ||
|
||
public func core(into state: inout State, action: Action) -> Effect<Action> { | ||
switch action { | ||
case .destination(.dismiss): | ||
reduceDismissDestination(into: &state) | ||
case let .destination(.presented(presentedAction)): | ||
reduce(into: &state, presentedAction: presentedAction) | ||
case let .view(viewAction): | ||
reduce(into: &state, viewAction: viewAction) | ||
case let .internal(internalAction): | ||
reduce(into: &state, internalAction: internalAction) | ||
case let .child(childAction): | ||
reduce(into: &state, childAction: childAction) | ||
case .delegate: | ||
.none | ||
} | ||
} | ||
|
||
public func reduce(into state: inout State, viewAction: ViewAction) -> Effect<Action> { | ||
.none | ||
} | ||
|
||
public func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> { | ||
.none | ||
} | ||
|
||
public func reduce(into state: inout State, childAction: ChildAction) -> Effect<Action> { | ||
.none | ||
} | ||
|
||
public func reduce(into state: inout State, presentedAction: Destination.Action) -> Effect<Action> { | ||
.none | ||
} | ||
|
||
public func reduceDismissDestination(into state: inout State) -> Effect<Action> { | ||
.none | ||
} | ||
|
||
} | ||
|
||
public typealias PresentationStoreOf<R: Reducer> = Store<PresentationState<R.State>, PresentationAction<R.Action>> | ||
|
||
// MARK: FeatureAction | ||
@CasePathable | ||
public enum FeatureAction<Feature: FeatureReducer>: Sendable, Equatable { | ||
case destination(PresentationAction<Feature.Destination.Action>) | ||
case view(Feature.ViewAction) | ||
case `internal`(Feature.InternalAction) | ||
case child(Feature.ChildAction) | ||
case delegate(Feature.DelegateAction) | ||
} | ||
|
||
// MARK: DestinationReducer | ||
public protocol DestinationReducer: Reducer where State: Sendable & Hashable, Action: Sendable & Equatable & CasePathable { } | ||
|
||
// MARK: EmptyDestination | ||
|
||
public enum EmptyDestination: DestinationReducer { | ||
public struct State: Sendable, Hashable {} | ||
public typealias Action = Never | ||
public func reduce(into state: inout State, action: Never) -> Effect<Action> {} | ||
public func reduceDismissDestination(into state: inout State) -> Effect<Action> { .none } | ||
} | ||
|
||
//MARK: FeatureAction + Hashable | ||
extension FeatureAction: Hashable where Feature.Destination.Action: Hashable, | ||
Feature.ViewAction: Hashable, | ||
Feature.ChildAction: Hashable, | ||
Feature.InternalAction: Hashable, | ||
Feature.DelegateAction: Hashable { | ||
public func hash(into hasher: inout Hasher) { | ||
switch self { | ||
case let .destination(action): | ||
hasher.combine(action) | ||
case let .view(action): | ||
hasher.combine(action) | ||
case let .internal(action): | ||
hasher.combine(action) | ||
case let .child(action): | ||
hasher.combine(action) | ||
case let .delegate(action): | ||
hasher.combine(action) | ||
} | ||
} | ||
} | ||
|
||
/// For scoping to an actionless childstore | ||
public func actionless<T>(never: Never) -> T {} | ||
|
60 changes: 60 additions & 0 deletions
60
{{cookiecutter.app_name}}/Common/Sources/Common/Heap.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// | ||
// Heap.swift | ||
// Common | ||
// | ||
// Created by {{ cookiecutter.creator }} on {% now 'utc', '%d/%m/%Y' %}. | ||
// Copyright © {% now 'utc', '%Y' %} {{cookiecutter.company_name}}. All rights reserved. | ||
// | ||
|
||
private final class Reference<T: Equatable>: Equatable { | ||
var value: T | ||
init(_ value: T) { | ||
self.value = value | ||
} | ||
static func == (lhs: Reference<T>, rhs: Reference<T>) -> Bool { | ||
lhs.value == rhs.value | ||
} | ||
} | ||
|
||
@propertyWrapper public struct Heap<T: Equatable>: Equatable { | ||
private var reference: Reference<T> | ||
|
||
public init(_ value: T) { | ||
reference = .init(value) | ||
} | ||
|
||
public var wrappedValue: T { | ||
get { reference.value } | ||
set { | ||
if !isKnownUniquelyReferenced(&reference) { | ||
reference = .init(newValue) | ||
return | ||
} | ||
reference.value = newValue | ||
} | ||
} | ||
public var projectedValue: Heap<T> { | ||
self | ||
} | ||
} | ||
|
||
extension Heap: Hashable where T: Hashable { | ||
public func hash(into hasher: inout Hasher) { | ||
hasher.combine(wrappedValue) | ||
} | ||
} | ||
|
||
extension Heap: Decodable where T: Decodable { | ||
public init(from decoder: Decoder) throws { | ||
let container = try decoder.singleValueContainer() | ||
let value = try container.decode(T.self) | ||
self = Heap(value) | ||
} | ||
} | ||
|
||
extension Heap: Encodable where T: Encodable { | ||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.singleValueContainer() | ||
try container.encode(wrappedValue) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
{{cookiecutter.app_name}}/Features/Sources/App/AppFeature.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// | ||
// AppFeature.swift | ||
// Features | ||
// | ||
// Created by {{ cookiecutter.creator }} on {% now 'utc', '%d/%m/%Y' %}. | ||
// Copyright © {% now 'utc', '%Y' %} {{cookiecutter.company_name}}. All rights reserved. | ||
// | ||
|
||
import Common | ||
import Counter | ||
import ComposableArchitecture | ||
|
||
public struct AppFeature: FeatureReducer { | ||
public init() { } | ||
|
||
public struct State: Equatable, Hashable { | ||
public init() { } | ||
|
||
@PresentationState var destination: Destination.State? | ||
} | ||
|
||
public enum ViewAction: Equatable { | ||
case showSheet | ||
case showFullScreenCover | ||
} | ||
|
||
public enum InternalAction: Equatable { | ||
case dismissDestination | ||
} | ||
|
||
public var body: some ReducerOf<Self> { | ||
Reduce(core) | ||
.ifLet(\.$destination, action: \.destination) { | ||
Destination() | ||
} | ||
} | ||
|
||
public func reduce(into state: inout State, viewAction: ViewAction) -> Effect<Action> { | ||
switch viewAction { | ||
case .showSheet: | ||
state.destination = .sheet(.init()) | ||
return .none | ||
|
||
case .showFullScreenCover: | ||
state.destination = .fullScreenCover(.init()) | ||
return .none | ||
} | ||
} | ||
|
||
public func reduce(into state: inout State, presentedAction: Destination.Action) -> Effect<Action> { | ||
switch presentedAction { | ||
case .sheet(.delegate(.close)): | ||
return .send(.internal(.dismissDestination)) | ||
|
||
case .fullScreenCover(.delegate(.close)): | ||
return .send(.internal(.dismissDestination)) | ||
|
||
default: | ||
return .none | ||
} | ||
} | ||
|
||
public func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> { | ||
switch internalAction { | ||
case .dismissDestination: | ||
state.destination = nil | ||
return .none | ||
} | ||
} | ||
|
||
public struct Destination: DestinationReducer { | ||
|
||
public init() { } | ||
|
||
@CasePathable | ||
public enum State: Hashable { | ||
case sheet(Counter.State) | ||
case fullScreenCover(Counter.State) | ||
} | ||
|
||
@CasePathable | ||
public enum Action: Equatable { | ||
case sheet(Counter.Action) | ||
case fullScreenCover(Counter.Action) | ||
} | ||
|
||
public var body: some ReducerOf<Self> { | ||
Scope(state: \.sheet, action: \.sheet) { | ||
Counter() | ||
} | ||
Scope(state: \.fullScreenCover, action: \.fullScreenCover) { | ||
Counter() | ||
} | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.