From ff0acf1329aa9c9b09484ea282abccf0bdbe61cf Mon Sep 17 00:00:00 2001 From: Jaclyn Chen Date: Fri, 19 Sep 2025 13:38:02 +0800 Subject: [PATCH 1/2] Fix iOS 17 warnings on deprecated Map usage and remove all iOS 17 available requirements. --- .../Address Edit/AddressMapPickerView.swift | 15 ++++++++------- .../AddressMapPickerViewModel.swift | 19 ++++++++----------- .../AddressMapPickerViewModelTests.swift | 5 ----- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift index 641136a9fe8..c34669ed0cf 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift @@ -3,7 +3,6 @@ import SwiftUI import Observation import struct Yosemite.Country -@available(iOS 17, *) struct AddressMapPickerView: View { @Environment(\.dismiss) private var dismiss @State private var viewModel: AddressMapPickerViewModel @@ -18,12 +17,15 @@ struct AddressMapPickerView: View { var body: some View { NavigationStack { ZStack(alignment: .top) { - Map(coordinateRegion: $viewModel.region, - showsUserLocation: true, - annotationItems: viewModel.annotations) { item in - MapMarker(coordinate: item.coordinate) + Map(position: $viewModel.mapPosition) { + ForEach(viewModel.annotations) { item in + Marker(coordinate: item.coordinate) { + RoundedRectangle(cornerRadius: 5) + } + } } - .ignoresSafeArea() + .mapStyle(.standard(elevation: .realistic)) + .ignoresSafeArea() VStack(spacing: 0) { searchBar @@ -134,7 +136,6 @@ struct AddressMapPickerView: View { } } -@available(iOS 17, *) private extension AddressMapPickerView { enum Localization { static let close = NSLocalizedString("addressMapPicker.button.close", value: "Close", comment: "Text for the close button in the Edit Address Form.") diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift index 8b60b0cc243..a1a985bb002 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift @@ -25,7 +25,6 @@ final class DefaultAddressMapLocalSearchProvider: AddressMapLocalSearchProviding } } -@available(iOS 17, *) @Observable final class AddressMapPickerViewModel: NSObject { var searchQuery = "" { @@ -34,10 +33,10 @@ final class AddressMapPickerViewModel: NSObject { } } private(set) var searchResults: [MKLocalSearchCompletion] = [] - var region = MKCoordinateRegion( + var mapPosition: MapCameraPosition = .region(MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 37.3361, longitude: -122.0380), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05) - ) + )) var annotations: [MapAnnotation] = [] var showsSearchResults: Bool { searchResults.isEmpty == false @@ -124,7 +123,6 @@ final class AddressMapPickerViewModel: NSObject { } } -@available(iOS 17, *) private extension AddressMapPickerViewModel { func configureSearchCompleter() { searchCompleter.resultTypes = .address @@ -140,10 +138,10 @@ private extension AddressMapPickerViewModel { let currentLocation = locationManager.location { DispatchQueue.main.async { [weak self] in guard let self else { return } - region = MKCoordinateRegion( + mapPosition = .region(MKCoordinateRegion( center: currentLocation.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) - ) + )) } return } @@ -159,10 +157,10 @@ private extension AddressMapPickerViewModel { return } - region = MKCoordinateRegion( + mapPosition = .region(MKCoordinateRegion( center: location.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) - ) + )) annotations = [MapAnnotation(coordinate: location.coordinate)] } catch { DDLogError("⛔️ Error geocoding initial address: \(error)") @@ -177,10 +175,10 @@ private extension AddressMapPickerViewModel { withAnimation { [weak self] in guard let self else { return } searchResults = [] - region = MKCoordinateRegion( + mapPosition = .region(MKCoordinateRegion( center: placemark.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) - ) + )) annotations = [MapAnnotation(coordinate: placemark.coordinate)] selectedPlace = placemark } completion: { @@ -196,7 +194,6 @@ private extension AddressMapPickerViewModel { } } -@available(iOS 17, *) extension AddressMapPickerViewModel: MKLocalSearchCompleterDelegate { func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) { searchResults = completer.results diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/AddressMapPickerViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/AddressMapPickerViewModelTests.swift index 64d1e7e9b8b..50748850a07 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/AddressMapPickerViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/AddressMapPickerViewModelTests.swift @@ -22,7 +22,6 @@ struct AddressMapPickerViewModelTests { // MARK: - Initialization Tests - @available(iOS 17, *) @Test func initialization_with_empty_fields_sets_properties_with_default_values() { // Given let emptyFields = AddressFormFields() @@ -38,7 +37,6 @@ struct AddressMapPickerViewModelTests { // MARK: - Selection Tests - @available(iOS 17, *) @Test func selectLocation_updates_annotations_and_hasValidSelection() async { // Given let fields = AddressFormFields() @@ -56,7 +54,6 @@ struct AddressMapPickerViewModelTests { // MARK: - Address Field Updates Tests - @available(iOS 17, *) @Test func updateFields_with_no_selected_place_does_not_modify_fields() { // Given let sut = AddressMapPickerViewModel(fields: .init(), countryByCode: mockCountryByCode) @@ -72,7 +69,6 @@ struct AddressMapPickerViewModelTests { #expect(updatedFields.city == "Original City") } - @available(iOS 17, *) @Test func updateFields_when_country_not_found_in_countryByCode_sets_country_and_state_as_strings() async { // Given let mockSearchProvider = MockAddressMapLocalSearchProvider.withFrenchAddress() @@ -95,7 +91,6 @@ struct AddressMapPickerViewModelTests { #expect(updatedFields.selectedState == nil) } - @available(iOS 17, *) @Test func updateFields_when_country_is_found_in_countryByCode_sets_selected_country_and_state() async { // Given let mockSearchProvider = MockAddressMapLocalSearchProvider.withUSAddress() From 48406639f867dcbfc1817d33069039d153471edf Mon Sep 17 00:00:00 2001 From: Jaclyn Chen Date: Fri, 19 Sep 2025 14:31:54 +0800 Subject: [PATCH 2/2] Set the map region to map search completer's region to potentially enhance the search relevance. --- .../Address Edit/AddressMapPickerView.swift | 6 ++++ .../AddressMapPickerViewModel.swift | 30 +++++++++---------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift index c34669ed0cf..3807ff473c5 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerView.swift @@ -120,6 +120,12 @@ struct AddressMapPickerView: View { .autocorrectionDisabled() .textInputAutocapitalization(.never) .focused($isSearchFocused) + .onChange(of: isSearchFocused) { _, newValue in + viewModel.isSearchFocused = newValue + } + .onChange(of: viewModel.isSearchFocused) { _, newValue in + isSearchFocused = newValue + } if !viewModel.searchQuery.isEmpty { Button(action: { diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift index a1a985bb002..1e91dbee6fd 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressMapPickerViewModel.swift @@ -32,6 +32,8 @@ final class AddressMapPickerViewModel: NSObject { searchQueryContinuation.yield(newValue) } } + // Syncs with the focused state of the search text field in `AddressMapPickerView`. + var isSearchFocused: Bool = false private(set) var searchResults: [MKLocalSearchCompletion] = [] var mapPosition: MapCameraPosition = .region(MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 37.3361, longitude: -122.0380), @@ -78,7 +80,12 @@ final class AddressMapPickerViewModel: NSObject { for await query in searchQueryStream.debounce(for: .seconds(0.3)) { if query.isEmpty { searchResults = [] - } else { + } else if isSearchFocused { + if let region = mapPosition.region { + // ~11km centered in the map region. + searchCompleter.region = .init(center: .init(latitude: region.center.latitude, longitude: region.center.longitude), + span: .init(latitudeDelta: 0.1, longitudeDelta: 0.1)) + } searchCompleter.queryFragment = query } } @@ -171,20 +178,13 @@ private extension AddressMapPickerViewModel { @MainActor func onSelectedPlacemark(_ placemark: MKPlacemark) async { - await withCheckedContinuation { continuation in - withAnimation { [weak self] in - guard let self else { return } - searchResults = [] - mapPosition = .region(MKCoordinateRegion( - center: placemark.coordinate, - span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) - )) - annotations = [MapAnnotation(coordinate: placemark.coordinate)] - selectedPlace = placemark - } completion: { - continuation.resume() - } - } + searchResults = [] + mapPosition = .region(MKCoordinateRegion( + center: placemark.coordinate, + span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) + )) + annotations = [MapAnnotation(coordinate: placemark.coordinate)] + selectedPlace = placemark } func formatAddressString(fields: AddressFormFields) -> String {