Skip to content

Commit 507a9b6

Browse files
authored
Merge pull request #1230 from Esri/df/trackPresentedFormWithPref
`FeatureFormView` - Track presented form with preferences
2 parents 41698cc + c5de31a commit 507a9b6

File tree

7 files changed

+69
-31
lines changed

7 files changed

+69
-31
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2025 Esri
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/// An equatable wrapper for an object.
16+
///
17+
/// Equality is determined by object identity.
18+
struct EquatableObject<Object: AnyObject & Sendable>: Equatable {
19+
let object: Object
20+
21+
static func == (lhs: Self, rhs: Self) -> Bool {
22+
lhs.object === rhs.object
23+
}
24+
}

Sources/ArcGISToolkit/Components/FeatureFormView/EmbeddedFeatureFormView.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ import ArcGIS
1616
import SwiftUI
1717

1818
struct EmbeddedFeatureFormView: View {
19-
/// The environment value to access the closure to call when the presented feature form changes.
20-
@Environment(\.formChangedAction) var formChangedAction
21-
2219
/// A Boolean value indicating whether the deprecated FeatureFormView initializer was used.
2320
@Environment(\.formDeprecatedInitializerWasUsed) var deprecatedInitializerWasUsed
2421

@@ -83,12 +80,13 @@ struct EmbeddedFeatureFormView: View {
8380
#endif
8481
.environment(embeddedFeatureFormViewModel)
8582
.padding([.horizontal])
83+
.preference(
84+
key: PresentedFeatureFormPreferenceKey.self,
85+
value: .init(object: embeddedFeatureFormViewModel.featureForm)
86+
)
8687
.task {
8788
await embeddedFeatureFormViewModel.initialEvaluation()
8889
}
89-
.onAppear {
90-
formChangedAction?(embeddedFeatureFormViewModel.featureForm)
91-
}
9290
.featureFormToolbar(embeddedFeatureFormViewModel.featureForm, isAForm: true)
9391
}
9492
}

Sources/ArcGISToolkit/Components/FeatureFormView/FeatureFormView+EnvironmentValues.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ extension EnvironmentValues /* FeatureFormView */ {
2222
/// An error thrown from a call to `FeatureForm.finishEditing()`.
2323
@Entry var finishEditingError: Binding<(any Error)?> = .constant(nil)
2424

25-
/// The environment value to access the closure to call when the presented feature form changes.
26-
@Entry var formChangedAction: ((FeatureForm) -> Void)?
27-
2825
/// A Boolean value indicating whether the deprecated FeatureFormView initializer was used.
2926
@Entry var formDeprecatedInitializerWasUsed = false
3027

Sources/ArcGISToolkit/Components/FeatureFormView/FeatureFormView.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,10 @@ public struct FeatureFormView: View {
143143
.featureFormToolbar(embeddedFeatureFormViewModel.featureForm)
144144
.navigationBarTitleDisplayMode(.inline)
145145
.navigationTitle(result.filter.title, subtitle: embeddedFeatureFormViewModel.title)
146-
.onAppear {
147-
formChangedAction(embeddedFeatureFormViewModel.featureForm)
148-
}
146+
.preference(
147+
key: PresentedFeatureFormPreferenceKey.self,
148+
value: .init(object: embeddedFeatureFormViewModel.featureForm)
149+
)
149150
case let .utilityAssociationGroupResultView(result, embeddedFeatureFormViewModel):
150151
UtilityAssociationGroupResultView(
151152
embeddedFeatureFormViewModel: embeddedFeatureFormViewModel,
@@ -154,9 +155,6 @@ public struct FeatureFormView: View {
154155
.featureFormToolbar(embeddedFeatureFormViewModel.featureForm)
155156
.navigationBarTitleDisplayMode(.inline)
156157
.navigationTitle(result.name, subtitle: embeddedFeatureFormViewModel.title)
157-
.onAppear {
158-
formChangedAction(embeddedFeatureFormViewModel.featureForm)
159-
}
160158
}
161159
}
162160
}
@@ -261,7 +259,6 @@ public struct FeatureFormView: View {
261259
)
262260
.environment(\.editingButtonVisibility, editingButtonsVisibility)
263261
.environment(\.finishEditingError, $finishEditingError)
264-
.environment(\.formChangedAction, formChangedAction)
265262
.environment(\.formDeprecatedInitializerWasUsed, deprecatedInitializerWasUsed)
266263
.environment(\.isPresented, isPresented)
267264
.environment(\.navigationIsDisabled, navigationIsDisabled)
@@ -270,6 +267,10 @@ public struct FeatureFormView: View {
270267
.environment(\.setAlertContinuation, setAlertContinuation)
271268
.environment(\.validationErrorVisibilityExternal, validationErrorVisibilityExternal)
272269
.environment(\.validationErrorVisibilityInternal, $validationErrorVisibilityInternal)
270+
.onPreferenceChange(PresentedFeatureFormPreferenceKey.self) { wrappedFeatureForm in
271+
guard let wrappedFeatureForm else { return }
272+
formChangedAction(wrappedFeatureForm.object)
273+
}
273274
}
274275
}
275276
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2025 Esri
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import ArcGIS
16+
import SwiftUI
17+
18+
/// A preference key that specifies the feature form currently presented in the `FeatureFormView` navigation stack.
19+
struct PresentedFeatureFormPreferenceKey: PreferenceKey {
20+
static let defaultValue: EquatableObject<FeatureForm>? = nil
21+
22+
static func reduce(
23+
value: inout EquatableObject<FeatureForm>?,
24+
nextValue: () -> EquatableObject<FeatureForm>?
25+
) {
26+
guard let nextValue = nextValue() else { return }
27+
value = nextValue
28+
}
29+
}

Sources/ArcGISToolkit/Components/Popups/EmbeddedPopupView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ struct EmbeddedPopupView: View {
6060
.frame(maxWidth: .infinity, maxHeight: .infinity)
6161
.background(Color(.systemBackground))
6262
#endif
63-
.preference(key: PresentedPopupPreferenceKey.self, value: .init(popup: popup))
63+
.preference(key: PresentedPopupPreferenceKey.self, value: .init(object: popup))
6464
.popupViewHeader(title: popup.title)
6565
.task(id: ObjectIdentifier(popup)) {
6666
// Initial evaluation for a newly assigned popup.

Sources/ArcGISToolkit/Components/Popups/PopupView.swift

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public struct PopupView: View {
9191
.environment(\.deprecatedProperties, deprecatedProperties)
9292
.onPreferenceChange(PresentedPopupPreferenceKey.self) { wrappedPopup in
9393
guard let wrappedPopup else { return }
94-
onPopupChanged?(wrappedPopup.popup)
94+
onPopupChanged?(wrappedPopup.object)
9595
}
9696
}
9797
}
@@ -111,20 +111,9 @@ public extension PopupView {
111111

112112
/// A preference key that specifies the popup currently presented in the `PopupView` navigation stack.
113113
struct PresentedPopupPreferenceKey: PreferenceKey {
114-
/// A wrapper for making a popup equatable.
115-
struct EquatablePopup: Equatable {
116-
let popup: Popup
117-
118-
static func == (lhs: Self, rhs: Self) -> Bool {
119-
lhs.popup === rhs.popup
120-
}
121-
}
122-
123-
// MARK: PreferenceKey Conformance
124-
125-
static let defaultValue: EquatablePopup? = nil
114+
static let defaultValue: EquatableObject<Popup>? = nil
126115

127-
static func reduce(value: inout EquatablePopup?, nextValue: () -> EquatablePopup?) {
116+
static func reduce(value: inout EquatableObject<Popup>?, nextValue: () -> EquatableObject<Popup>?) {
128117
guard let nextValue = nextValue() else { return }
129118
value = nextValue
130119
}

0 commit comments

Comments
 (0)