Skip to content

Commit 6415e3d

Browse files
authored
Merge pull request #24 from trading-point/michael/sync-upstream
Sync the latest changes from the upstream repo
2 parents 0369187 + a46869c commit 6415e3d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+936
-275
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ jobs:
1414
strategy:
1515
matrix:
1616
xcode:
17-
- 11.4
18-
- 11.5
19-
- 11.6
17+
- 11.7
18+
- 12.0
2019
steps:
2120
- uses: actions/checkout@v2
2221
- name: Select Xcode ${{ matrix.xcode }}

.spi.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
version: 1
2+
builder:
3+
configs:
4+
- platform: watchos
5+
scheme: ComposableArchitecture_watchOS
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1200"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "ComposableArchitecture"
18+
BuildableName = "ComposableArchitecture"
19+
BlueprintName = "ComposableArchitecture"
20+
ReferencedContainer = "container:">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
<BuildActionEntry
24+
buildForTesting = "YES"
25+
buildForRunning = "YES"
26+
buildForProfiling = "YES"
27+
buildForArchiving = "YES"
28+
buildForAnalyzing = "YES">
29+
<BuildableReference
30+
BuildableIdentifier = "primary"
31+
BlueprintIdentifier = "ComposableCoreLocation"
32+
BuildableName = "ComposableCoreLocation"
33+
BlueprintName = "ComposableCoreLocation"
34+
ReferencedContainer = "container:">
35+
</BuildableReference>
36+
</BuildActionEntry>
37+
<BuildActionEntry
38+
buildForTesting = "YES"
39+
buildForRunning = "YES"
40+
buildForProfiling = "YES"
41+
buildForArchiving = "YES"
42+
buildForAnalyzing = "YES">
43+
<BuildableReference
44+
BuildableIdentifier = "primary"
45+
BlueprintIdentifier = "ComposableCoreMotion"
46+
BuildableName = "ComposableCoreMotion"
47+
BlueprintName = "ComposableCoreMotion"
48+
ReferencedContainer = "container:">
49+
</BuildableReference>
50+
</BuildActionEntry>
51+
</BuildActionEntries>
52+
</BuildAction>
53+
<TestAction
54+
buildConfiguration = "Debug"
55+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
56+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
57+
shouldUseLaunchSchemeArgsEnv = "YES">
58+
<Testables>
59+
</Testables>
60+
</TestAction>
61+
<LaunchAction
62+
buildConfiguration = "Debug"
63+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
64+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
65+
launchStyle = "0"
66+
useCustomWorkingDirectory = "NO"
67+
ignoresPersistentStateOnLaunch = "NO"
68+
debugDocumentVersioning = "YES"
69+
debugServiceExtension = "internal"
70+
allowLocationSimulation = "YES">
71+
</LaunchAction>
72+
<ProfileAction
73+
buildConfiguration = "Release"
74+
shouldUseLaunchSchemeArgsEnv = "YES"
75+
savedToolIdentifier = ""
76+
useCustomWorkingDirectory = "NO"
77+
debugDocumentVersioning = "YES">
78+
<MacroExpansion>
79+
<BuildableReference
80+
BuildableIdentifier = "primary"
81+
BlueprintIdentifier = "ComposableArchitecture"
82+
BuildableName = "ComposableArchitecture"
83+
BlueprintName = "ComposableArchitecture"
84+
ReferencedContainer = "container:">
85+
</BuildableReference>
86+
</MacroExpansion>
87+
</ProfileAction>
88+
<AnalyzeAction
89+
buildConfiguration = "Debug">
90+
</AnalyzeAction>
91+
<ArchiveAction
92+
buildConfiguration = "Release"
93+
revealArchiveInOrganizer = "YES">
94+
</ArchiveAction>
95+
</Scheme>

Examples/CaseStudies/CaseStudies.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
4F5AC11F24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5AC11E24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift */; };
1011
CA0C0C4724B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA0C0C4624B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift */; };
1112
CA0C51FB245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */; };
1213
CA25E5D224463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA25E5D124463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift */; };
@@ -144,6 +145,7 @@
144145
/* End PBXCopyFilesBuildPhase section */
145146

146147
/* Begin PBXFileReference section */
148+
4F5AC11E24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-SharedStateTests.swift"; sourceTree = "<group>"; };
147149
CA0C0C4624B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-LifecycleTests.swift"; sourceTree = "<group>"; };
148150
CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift"; sourceTree = "<group>"; };
149151
CA25E5D124463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-Bindings-Basics.swift"; sourceTree = "<group>"; };
@@ -419,6 +421,7 @@
419421
children = (
420422
CA50BE5F24A8F46500FE7DBA /* 01-GettingStarted-AlertsAndActionSheetsTests.swift */,
421423
CA34170724A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift */,
424+
4F5AC11E24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift */,
422425
CAA9ADC324465AB00003A984 /* 02-Effects-BasicsTests.swift */,
423426
CAA9ADC724465D950003A984 /* 02-Effects-CancellationTests.swift */,
424427
CAA9ADCB2446615B0003A984 /* 02-Effects-LongLivingTests.swift */,
@@ -778,6 +781,7 @@
778781
DC07231724465D1E003A8B65 /* 02-Effects-TimersTests.swift in Sources */,
779782
CA50BE6024A8F46500FE7DBA /* 01-GettingStarted-AlertsAndActionSheetsTests.swift in Sources */,
780783
CAA9ADC424465AB00003A984 /* 02-Effects-BasicsTests.swift in Sources */,
784+
4F5AC11F24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift in Sources */,
781785
CAA9ADCC2446615B0003A984 /* 02-Effects-LongLivingTests.swift in Sources */,
782786
);
783787
runOnlyForDeploymentPostprocessing = 0;

Examples/CaseStudies/SwiftUICaseStudies/01-GettingStarted-SharedState.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,19 @@ struct SharedState: Equatable {
6767
}
6868
}
6969

70-
enum SharedStateAction {
70+
enum SharedStateAction: Equatable {
7171
case counter(CounterAction)
7272
case profile(ProfileAction)
7373
case selectTab(SharedState.Tab)
7474

75-
enum CounterAction {
75+
enum CounterAction: Equatable {
7676
case alertDismissed
7777
case decrementButtonTapped
7878
case incrementButtonTapped
7979
case isPrimeButtonTapped
8080
}
8181

82-
enum ProfileAction {
82+
enum ProfileAction: Equatable {
8383
case resetCounterButtonTapped
8484
}
8585
}

Examples/CaseStudies/SwiftUICaseStudies/04-HigherOrderReducers-Recursion.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ComposableArchitecture
2+
import ReactiveSwift
23
import SwiftUI
34

45
private let readMe = """
@@ -34,6 +35,7 @@ struct NestedState: Equatable, Identifiable {
3435

3536
indirect enum NestedAction: Equatable {
3637
case append
38+
case exclaim
3739
case node(index: Int, action: NestedAction)
3840
case remove(IndexSet)
3941
case rename(String)
@@ -51,16 +53,24 @@ let nestedReducer = Reducer<
5153
state.children.append(NestedState(id: environment.uuid()))
5254
return .none
5355

56+
case .exclaim:
57+
state.description += "!"
58+
return .none
59+
5460
case let .node(index, action):
5561
return self.run(&state.children[index], action, environment)
62+
.map { .node(index: index, action: $0) }
5663

5764
case let .remove(indexSet):
5865
state.children.remove(atOffsets: indexSet)
5966
return .none
6067

6168
case let .rename(name):
69+
struct ExclaimId: Hashable {}
70+
6271
state.description = name
63-
return .none
72+
return Effect(value: .exclaim)
73+
.debounce(id: ExclaimId(), interval: 1, scheduler: QueueScheduler.main)
6474
}
6575
}
6676

Examples/CaseStudies/SwiftUICaseStudies/04-HigherOrderReducers-ReusableFavoriting.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ extension Reducer {
7979
.cancellable(id: FavoriteCancelId(id: state.id), cancelInFlight: true)
8080

8181
case let .response(.failure(error)):
82-
state.alert = .init(title: error.localizedDescription)
82+
state.alert = .init(title: .init(error.localizedDescription))
8383
return .none
8484

8585
case let .response(.success(isFavorite)):
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import Combine
2+
import ComposableArchitecture
3+
import XCTest
4+
5+
@testable import SwiftUICaseStudies
6+
7+
class SharedStateTests: XCTestCase {
8+
func testTabRestoredOnReset() {
9+
let store = TestStore(
10+
initialState: SharedState(),
11+
reducer: sharedStateReducer,
12+
environment: ()
13+
)
14+
15+
store.assert(
16+
.send(.selectTab(.profile)) {
17+
$0.currentTab = .profile
18+
$0.profile = .init(currentTab: .profile, count: 0, maxCount: 0, minCount: 0, numberOfCounts: 0)
19+
},
20+
.send(.profile(.resetCounterButtonTapped)) {
21+
$0.currentTab = .counter
22+
$0.profile = .init(currentTab: .counter, count: 0, maxCount: 0, minCount: 0, numberOfCounts: 0)
23+
})
24+
}
25+
26+
func testTabSelection() {
27+
let store = TestStore(
28+
initialState: SharedState(),
29+
reducer: sharedStateReducer,
30+
environment: ()
31+
)
32+
33+
store.assert(
34+
.send(.selectTab(.profile)) {
35+
$0.currentTab = .profile
36+
$0.profile = .init(currentTab: .profile, count: 0, maxCount: 0, minCount: 0, numberOfCounts: 0)
37+
},
38+
.send(.selectTab(.counter)) {
39+
$0.currentTab = .counter
40+
$0.profile = .init(currentTab: .counter, count: 0, maxCount: 0, minCount: 0, numberOfCounts: 0)
41+
})
42+
}
43+
44+
func testSharedCounts() {
45+
let store = TestStore(
46+
initialState: SharedState(),
47+
reducer: sharedStateReducer,
48+
environment: ()
49+
)
50+
51+
store.assert(
52+
.send(.counter(.incrementButtonTapped)) {
53+
$0.counter.count = 1
54+
$0.counter.maxCount = 1
55+
$0.counter.numberOfCounts = 1
56+
},
57+
.send(.counter(.decrementButtonTapped)) {
58+
$0.counter.count = 0
59+
$0.counter.numberOfCounts = 2
60+
},
61+
.send(.counter(.decrementButtonTapped)) {
62+
$0.counter.count = -1
63+
$0.counter.minCount = -1
64+
$0.counter.numberOfCounts = 3
65+
})
66+
}
67+
68+
func testIsPrimeWhenPrime() {
69+
let store = TestStore(
70+
initialState: SharedState.CounterState(alert: nil, count: 3, maxCount: 0, minCount: 0, numberOfCounts: 0),
71+
reducer: sharedStateCounterReducer,
72+
environment: ()
73+
)
74+
75+
store.assert(
76+
.send(.isPrimeButtonTapped) {
77+
$0.alert = .init(
78+
title: "👍 The number \($0.count) is prime!"
79+
)
80+
},
81+
.send(.alertDismissed) {
82+
$0.alert = nil
83+
}
84+
)
85+
}
86+
87+
func testIsPrimeWhenNotPrime() {
88+
let store = TestStore(
89+
initialState: SharedState.CounterState(alert: nil, count: 6, maxCount: 0, minCount: 0, numberOfCounts: 0),
90+
reducer: sharedStateCounterReducer,
91+
environment: ()
92+
)
93+
94+
store.assert(
95+
.send(.isPrimeButtonTapped) {
96+
$0.alert = .init(
97+
title: "👎 The number \($0.count) is not prime :("
98+
)
99+
},
100+
.send(.alertDismissed) {
101+
$0.alert = nil
102+
}
103+
)
104+
}
105+
}

Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-LongLivingTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class LongLivingEffectsTests: XCTestCase {
2828

2929
.send(.onDisappear),
3030

31-
// Simulate a screenshot being taken to show not effects
31+
// Simulate a screenshot being taken to show no effects
3232
// are executed.
3333
.do { screenshotTaken.input.send(value: ()) }
3434
)

Examples/MotionManager/MotionManager/MotionManagerView.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,12 @@ struct AppView_Previews: PreviewProvider {
176176
create: { _ in .fireAndForget {} },
177177
destroy: { _ in .fireAndForget {} },
178178
deviceMotion: { _ in nil },
179-
startDeviceMotionUpdates: { _, _, _ in
179+
startDeviceMotionUpdates: { _, _, _ -> Effect<DeviceMotion, Error> in
180180
isStarted = true
181181
return Effect.timer(interval: .milliseconds(100), on: QueueScheduler.main)
182-
.filter { _ in isStarted }
183-
.map { $0.timeIntervalSince1970 * 2 }
184-
.map { t in
182+
.filter { _ -> Bool in isStarted }
183+
.map { t -> TimeInterval in t.timeIntervalSince1970 * 2 }
184+
.map { t -> DeviceMotion in
185185
DeviceMotion(
186186
attitude: .init(quaternion: .init(x: 1, y: 0, z: 0, w: 0)),
187187
gravity: .init(x: sin(2 * t), y: -cos(-t), z: sin(3 * t)),

0 commit comments

Comments
 (0)