-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy path06-NavigationDestinations.swift
132 lines (117 loc) · 2.85 KB
/
06-NavigationDestinations.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import SwiftUI
import SwiftUINavigation
@available(iOS 16, *)
struct NavigationDestinations: View {
@State private var model = FeatureModel()
var body: some View {
List {
Section {
Stepper("Number: \(model.count)", value: $model.count)
HStack {
Button("Get number fact") {
Task { await model.numberFactButtonTapped() }
}
if model.isLoading {
Spacer()
ProgressView()
}
}
} header: {
Text("Fact Finder")
}
Section {
ForEach(model.savedFacts) { fact in
Text(fact.description)
}
.onDelete { model.removeSavedFacts(atOffsets: $0) }
} header: {
Text("Saved Facts")
}
}
.navigationTitle("Destinations")
.navigationDestination(item: $model.fact) { $fact in
FactEditor(fact: $fact.description)
.disabled(model.isLoading)
.foregroundColor(model.isLoading ? .gray : nil)
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
Task { await model.cancelButtonTapped() }
}
}
ToolbarItem(placement: .confirmationAction) {
Button("Save") {
Task { await model.saveButtonTapped(fact: fact) }
}
}
}
}
}
}
private struct FactEditor: View {
@Binding var fact: String
var body: some View {
VStack {
if #available(iOS 14, *) {
TextEditor(text: $fact)
} else {
TextField("Untitled", text: $fact)
}
}
.padding()
.navigationBarTitle("Fact Editor")
}
}
@Observable
private class FeatureModel {
var count = 0
var fact: Fact?
var isLoading = false
var savedFacts: [Fact] = []
private var task: Task<Void, Never>?
deinit {
task?.cancel()
}
@MainActor
func setFactNavigation(isActive: Bool) async {
if isActive {
isLoading = true
fact = Fact(description: "\(count) is still loading...", number: count)
task = Task {
let fact = await getNumberFact(self.count)
isLoading = false
guard !Task.isCancelled
else { return }
self.fact = fact
}
await task?.value
} else {
task?.cancel()
task = nil
fact = nil
}
}
@MainActor
func numberFactButtonTapped() async {
await setFactNavigation(isActive: true)
}
@MainActor
func cancelButtonTapped() async {
await setFactNavigation(isActive: false)
}
@MainActor
func saveButtonTapped(fact: Fact) async {
savedFacts.append(fact)
await setFactNavigation(isActive: false)
}
@MainActor
func removeSavedFacts(atOffsets offsets: IndexSet) {
savedFacts.remove(atOffsets: offsets)
}
}
#Preview {
NavigationStack {
NavigationDestinations()
}
}