Skip to content

Commit

Permalink
SyncUp tutorial fixes (#3139)
Browse files Browse the repository at this point in the history
* Fixes for TestingSyncUpForm

* Typo, heirarchy -> hierarchy

* Typo: recursive -> recursively

* Typo: comes -> combines

* Further fixes for TestingSyncUpForm

* Typo: is -> to be

* Typo: add -> we added

* Typo: 3 -> 2

* Adding a note to avoid confusion

* Add more detail to step

* Remove stray whitespace causing a diff to incorrectly display

* Removed step documentation for unused code

* Typo: apart -> a part

* Fix App.Path Equatable conformance

* App -> AppReducer to avoid conflict with SwiftUI.App

* Fix code file link

* Typo: reducer -> reducers

* Add missing mock

* AppReducer -> AppFeature

* Standardize tutorial on `@Shared(.syncUps)`

* Fix mainactor placement

* Fix transcript param not compiling

* Add durationPerAttendee to be usable

* Add a minimal dismiss override to fit with the docs

* Fix commenting out of Tagged discussion

* Fix commenting out of TestingSyncUpDetail discussion

* Undo a whitespace change

* Partial revert of TestingSyncUpForm-02-code-0004.swift

* Undo unintentionally committed code

* Revert "Add missing mock"

This reverts commit 9672ecb.

* Revert "Fixes for TestingSyncUpForm"

This reverts commit 5bece14.

* wip

---------

Co-authored-by: Stephen Celis <stephen@stephencelis.com>
  • Loading branch information
dafurman and stephencelis committed Jun 7, 2024
1 parent 7461262 commit 8631b5f
Show file tree
Hide file tree
Showing 31 changed files with 150 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ class TimerTests: XCTestCase {
With the basics set up, we can send an action into the system to assert on what happens, such as the
`.startTimerButtonTapped` action. This time we don't actually expect state to change at first
because when starting the timer we don't change state, and so in this case we can leave off the
trailer closure:
trailing closure:

```swift
await store.send(.startTimerButtonTapped)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ received action:
_path: [:],
_syncUpsList: SyncUpsList.State(
_destination: nil,
_syncUps: #1 IdentifiedArray(
_syncUps: [
- SyncUp(
- id: Tagged(rawValue: UUID(BCD45D06-2291-4A22-906A-C1EF07500AB7)),
- attendees: [
Expand All @@ -34,6 +34,6 @@ received action:
- theme: .bubblegum,
- title: "Point-Free Morning Sync"
- )
)
]
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ struct SyncUpForm {
guard
!state.syncUp.attendees.isEmpty,
let firstIndex = indices.first
else { return .none }
else {
state.syncUp.attendees.append(
Attendee(id: Attendee.ID())
)
return .none
}
let index = min(firstIndex, state.syncUp.attendees.count - 1)
state.focus = .attendee(state.syncUp.attendees[index].id)
return .none
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ struct SyncUpForm {
guard
!state.syncUp.attendees.isEmpty,
let firstIndex = indices.first
else { return .none }
else {
state.syncUp.attendees.append(
Attendee(id: Attendee.ID())
)
return .none
}
let index = min(firstIndex, state.syncUp.attendees.count - 1)
state.focus = .attendee(state.syncUp.attendees[index].id)
return .none
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ struct SyncUpForm {
guard
!state.syncUp.attendees.isEmpty,
let firstIndex = indices.first
else { return .none }
else {
state.syncUp.attendees.append(
Attendee(id: Attendee.ID())
)
return .none
}
let index = min(firstIndex, state.syncUp.attendees.count - 1)
state.focus = .attendee(state.syncUp.attendees[index].id)
return .none
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ struct SyncUpForm {
guard
!state.syncUp.attendees.isEmpty,
let firstIndex = indices.first
else { return .none }
else {
state.syncUp.attendees.append(
Attendee(id: uuid())
)
return .none
}
let index = min(firstIndex, state.syncUp.attendees.count - 1)
state.focus = .attendee(state.syncUp.attendees[index].id)
return .none
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,62 @@
import ComposableArchitecture
import SwiftUI

@main
struct SyncUpsApp: App {
@MainActor
static let store = Store(initialState: SyncUpsList.State()) {
SyncUpsList()
@Reducer
struct SyncUpsList {
@ObservableState
struct State: Equatable {
@Presents var addSyncUp: SyncUpForm.State?
@Shared(.syncUps) var syncUps
}
enum Action {
case addSyncUpButtonTapped
case addSyncUp(PresentationAction<SyncUpForm.Action>)
case confirmAddButtonTapped
case discardButtonTapped
case onDelete(IndexSet)
case syncUpTapped(id: SyncUp.ID)
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .addSyncUpButtonTapped:
state.addSyncUp = SyncUpForm.State(syncUp: SyncUp(id: SyncUp.ID()))
return .none

case .addSyncUp:
return .none

case .confirmAddButtonTapped:
guard let newSyncUp = state.addSyncUp?.syncUp
else { return .none }
state.addSyncUp = nil
state.syncUps.append(newSyncUp)
return .none

case .discardButtonTapped:
state.addSyncUp = nil
return .none

case let .onDelete(indexSet):
state.syncUps.remove(atOffsets: indexSet)
return .none

var body: some Scene {
WindowGroup {
NavigationStack {
SyncUpsListView(store: Self.store)
case .syncUpTapped:
return .none
}
}
.ifLet(\.$addSyncUp, action: \.addSyncUp) {
SyncUpForm()
}
}
}

extension PersistenceReaderKey
where Self == PersistenceKeyDefault<FileStorageKey<IdentifiedArrayOf<SyncUp>>> {
static var syncUps: Self {
PersistenceKeyDefault(
.fileStorage(.documentsDirectory.appending(component: "sync-ups.json")),
[]
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,22 @@
bottom of the file to define such a URL, and then provide it to the `.fileStorage` value.

@Code(name: "SyncUpsList.swift", file: PersistingSyncUps-01-code-0003.swift)

> Note: It is possible to provide some type safety between the URL provided and the expected
> type of data to be stored on disk. See
> [type-safe keys](<doc:SharingState#Type-safe-keys>) for more information.
}

With that change the project should be compiling. It is worth noting that
``ComposableArchitecture/PersistenceReaderKey/fileStorage(_:)`` only works with `Codable` data
types, and earlier in the tutorial when we added models to Models.swift we made them codable from
the beginning.


@Step {
Before moving on, we can still make this better.
It is possible to provide some type safety between the URL provided and the expected
type of data to be stored on disk, and make usage more concise. See
[type-safe keys](<doc:SharingState#Type-safe-keys>) for more information.

@Code(name: "SyncUpsList.swift", file: PersistingSyncUps-01-code-0004.swift)
}

To confirm that persistence works we need to run the app in the simulator, but we haven't done
that yet in this tutorial. To do that we need to update the entry point of the app to use the
`SyncUpsListView`.
Expand All @@ -67,14 +72,14 @@
> Note: We construct the ``ComposableArchitecture/Store`` as a static so that it is
initialized only one time, and so that it is not created while running Xcode previews.

@Code(name: "SyncUpsApp.swift", file: PersistingSyncUps-01-code-0004.swift)
@Code(name: "SyncUpsApp.swift", file: PersistingSyncUps-01-code-0005.swift)
}

@Step {
Run the app in the simulator, add a sync-up, and then relaunch the application to see that
it restores the previously created sync-up. This shows that data is persisting.

@Video(source: PersistingSyncUps-01-video-0005.mov)
@Video(source: PersistingSyncUps-01-video-0006.mov)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
@ObservableState
struct State: Equatable {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
@ObservableState
struct State: Equatable {
var syncUpsList = SyncUpsList.State()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
@ObservableState
struct State: Equatable {
var path = StackState<SyncUpDetail.State>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
@Reducer
enum Path {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
@Reducer
enum Path {
case detail(SyncUpDetail)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
@Reducer
struct AppFeature {
@Reducer(state: .equatable)
enum Path {
case detail(SyncUpDetail)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
@Reducer
struct AppFeature {
@Reducer(state: .equatable)
enum Path {
case detail(SyncUpDetail)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
@Reducer
struct AppFeature {
@Reducer(state: .equatable)
enum Path {
case detail(SyncUpDetail)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}

struct AppView: View {
@Bindable var store: StoreOf<App>
@Bindable var store: StoreOf<AppFeature>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}

struct AppView: View {
@Bindable var store: StoreOf<App>
@Bindable var store: StoreOf<AppFeature>

var body: some View {
NavigationStack(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}

struct AppView: View {
@Bindable var store: StoreOf<App>
@Bindable var store: StoreOf<AppFeature>

var body: some View {
NavigationStack(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}

struct AppView: View {
@Bindable var store: StoreOf<App>
@Bindable var store: StoreOf<AppFeature>

var body: some View {
NavigationStack(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}

struct AppView: View {
@Bindable var store: StoreOf<App>
@Bindable var store: StoreOf<AppFeature>

var body: some View {
NavigationStack(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import ComposableArchitecture
import SwiftUI

@Reducer
struct App {
struct AppFeature {
// ...
}

struct AppView: View {
@Bindable var store: StoreOf<App>
@Bindable var store: StoreOf<AppFeature>

var body: some View {
NavigationStack(
Expand All @@ -28,11 +28,11 @@ struct AppView: View {
#Preview {
AppView(
store: Store(
initialState: App.State(
initialState: AppFeature.State(
syncUpsList: SyncUpsList.State()
)
) {
App()
AppFeature()
}
)
}
Loading

0 comments on commit 8631b5f

Please sign in to comment.