Skip to content

Commit 14c085d

Browse files
committed
Refactor VM to listen to country changes
1 parent e732139 commit 14c085d

File tree

1 file changed

+40
-24
lines changed

1 file changed

+40
-24
lines changed

WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditAddressFormViewModel.swift

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Yosemite
22
import Storage
33
import Combine
4+
import struct SwiftUI.Binding
45

56
final class EditAddressFormViewModel: ObservableObject {
6-
77
/// Current site ID
88
///
99
private let siteID: Int64
@@ -41,24 +41,26 @@ final class EditAddressFormViewModel: ObservableObject {
4141
// Listen only to the first emitted event.
4242
onLoadTrigger.first().sink { [weak self] in
4343
guard let self = self else { return }
44-
self.bindNavigationTrailingItemPublisher()
4544
self.bindSyncTrigger()
45+
self.bindSelectedCountryIntoFields()
46+
self.bindNavigationTrailingItemPublisher()
47+
4648
self.fetchStoredCountriesAndTriggerSyncIfNeeded()
47-
self.updateFieldsWithOriginalAddress()
49+
self.setFieldsInitialValues()
4850
}.store(in: &subscriptions)
4951
}
5052

5153
/// Original `Address` model.
5254
///
5355
private let originalAddress: Address
5456

55-
/// Address form fields
57+
/// Current selected country.
5658
///
57-
@Published var fields = FormFields()
59+
@Published private var selectedCountry: Yosemite.Country?
5860

59-
/// Tracks the current selected country
61+
/// Address form fields
6062
///
61-
private let selectedCountry = CurrentValueSubject<Yosemite.Country?, Never>(nil)
63+
@Published var fields = FormFields()
6264

6365
/// Trigger to perform any one time setups.
6466
///
@@ -80,7 +82,11 @@ final class EditAddressFormViewModel: ObservableObject {
8082
/// Creates a view model to be used when selecting a country
8183
///
8284
func createCountryViewModel() -> CountrySelectorViewModel {
83-
CountrySelectorViewModel(countries: countriesResultsController.fetchedObjects, selected: selectedCountry)
85+
let selectedCountryBinding = Binding(
86+
get: { self.selectedCountry },
87+
set: { self.selectedCountry = $0 }
88+
)
89+
return CountrySelectorViewModel(countries: countriesResultsController.fetchedObjects, selected: selectedCountryBinding)
8490
}
8591

8692
/// Update the address remotely and invoke a completion block when finished
@@ -123,7 +129,7 @@ extension EditAddressFormViewModel {
123129
var country: String = ""
124130
var state: String = ""
125131

126-
mutating func update(from address: Address, selectedCountry: Yosemite.Country?) {
132+
mutating func update(with address: Address) {
127133
firstName = address.firstName
128134
lastName = address.lastName
129135
email = address.email ?? ""
@@ -134,11 +140,15 @@ extension EditAddressFormViewModel {
134140
address2 = address.address2 ?? ""
135141
city = address.city
136142
postcode = address.postcode
137-
country = selectedCountry?.name ?? address.country
138143
state = address.state
139144
}
140145

141-
func toAddress(selectedCountry: Yosemite.Country?) -> Address {
146+
mutating func update(with selectedCountry: Yosemite.Country?) {
147+
country = selectedCountry?.name ?? country
148+
}
149+
150+
151+
func toAddress(selectedCountry: Yosemite.Country?) -> Yosemite.Address {
142152
Address(firstName: firstName,
143153
lastName: lastName,
144154
company: company.isEmpty ? nil : company,
@@ -155,39 +165,45 @@ extension EditAddressFormViewModel {
155165
}
156166

157167
private extension EditAddressFormViewModel {
158-
func updateFieldsWithOriginalAddress() {
159-
updateSelectedCountryFromOriginalAddress()
160-
fields.update(from: originalAddress, selectedCountry: selectedCountry.value)
161-
}
162-
163-
/// Updates the `selectedCountry` subject by matching the address country code in our stored countries.
168+
/// Set initial values from `originalAddress` using the stored countries to compute the current selected country.
164169
///
165-
func updateSelectedCountryFromOriginalAddress() {
166-
selectedCountry.value = countriesResultsController.fetchedObjects.first { $0.code == originalAddress.country }
170+
func setFieldsInitialValues() {
171+
selectedCountry = countriesResultsController.fetchedObjects.first { $0.code == originalAddress.country }
172+
fields.update(with: originalAddress)
167173
}
168174

169175
/// Calculates what navigation trailing item should be shown depending on our internal state.
170176
///
171177
func bindNavigationTrailingItemPublisher() {
172-
Publishers.CombineLatest($fields, performingNetworkRequest)
173-
.map { [originalAddress, selectedCountry] fields, performingNetworkRequest -> NavigationItem in
178+
Publishers.CombineLatest3($fields, performingNetworkRequest, $selectedCountry)
179+
.map { [originalAddress] fields, performingNetworkRequest, selectedCountry -> NavigationItem in
174180
guard !performingNetworkRequest else {
175181
return .loading
176182
}
177-
return .done(enabled: originalAddress != fields.toAddress(selectedCountry: selectedCountry.value))
183+
return .done(enabled: originalAddress != fields.toAddress(selectedCountry: selectedCountry))
178184
}
179185
.assign(to: &$navigationTrailingItem)
180186
}
181187

188+
/// Update published fields when the selected country is updated.
189+
///
190+
func bindSelectedCountryIntoFields() {
191+
$selectedCountry
192+
.sink { [weak self] newCountry in
193+
self?.fields.update(with: newCountry)
194+
}
195+
.store(in: &subscriptions)
196+
}
197+
182198
/// Fetches countries from storage, If there are no stored countries, trigger a sync request.
183199
///
184200
func fetchStoredCountriesAndTriggerSyncIfNeeded() {
185201
// Initial fetch
186202
try? countriesResultsController.performFetch()
187203

188-
// Updates the selected country when the data store changes.
204+
// Updates the initial fields when/if the data store changes(after sync).
189205
countriesResultsController.onDidChangeContent = { [weak self] in
190-
self?.updateSelectedCountryFromOriginalAddress()
206+
self?.setFieldsInitialValues()
191207
}
192208

193209
// Trigger a sync request if there are no countries.

0 commit comments

Comments
 (0)