-
Notifications
You must be signed in to change notification settings - Fork 3
/
07-NavigationLinks.swift
122 lines (108 loc) · 2.63 KB
/
07-NavigationLinks.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
import SwiftUI
import SwiftUINavigation
struct OptionalNavigationLinks: 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.setFactNavigation(isActive: true) }
}
if self.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")
}
}
.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) }
}
}
}
}
.navigationTitle("Links")
}
}
private struct FactEditor: View {
@Binding var fact: String
var body: some View {
VStack {
TextEditor(text: $fact)
}
.padding()
.navigationTitle("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 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 {
OptionalNavigationLinks()
}
}