Skip to content

Commit 7516d5d

Browse files
authored
Merge branch 'trunk' into task/ios17-cardreader-warnings
2 parents 0077d11 + 5a9f525 commit 7516d5d

File tree

13 files changed

+223
-236
lines changed

13 files changed

+223
-236
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<!--
22
Contains editorialized release notes. Raw release notes should go into `RELEASE-NOTES.txt`.
33
-->
4+
## 23.0
5+
Faster performance and smoother experience! This update brings improved product loading, better tax calculations, and enhanced address lookup with map support. We've added guided barcode scanning for POS users and strengthened shipping requirements for EU destinations. Plus, we've fixed stability issues for a more reliable experience.
6+
47
## 22.9
58
This update enhances Shipping Labels with improved accessibility, smarter address validation, and faster performance. We’ve also made the dedicated Point of Sale tab more widely available for quicker access, and POS orders are now filterable in your order list for better organization. Plus, we've optimized assets to reduce the app’s size.
69

Modules/Sources/Experiments/DefaultFeatureFlagService.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
102102
case .pointOfSaleOrdersi2:
103103
return true
104104
case .pointOfSaleBarcodeScanningi2:
105-
return buildConfig == .localDeveloper || buildConfig == .alpha
105+
return true
106106
case .orderAddressMapSearch:
107107
return true
108108
default:

Modules/Sources/Hardware/CardReader/CurrencyCode.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public struct CurrencyCode {
1616

1717
public var wrappedValue: String {
1818
get {
19-
guard Locale.Currency.isoCurrencies.map({ $0.identifier }).contains(value.uppercased()) else {
19+
guard Locale.Currency.isoCurrencies.map({ $0.identifier.uppercased() }).contains(value.uppercased()) else {
2020
return ""
2121
}
2222
return value.lowercased()

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- [*] Order Details > Edit Shipping/Billing Address: Added map-based address lookup support for iOS 17+. [https://github.com/woocommerce/woocommerce-ios/pull/15964]
1717
- [*] Order Creation: Prevent subscription products to be added to an order [https://github.com/woocommerce/woocommerce-ios/pull/15960]
1818
- [internal] Replace COTS_DEVICE reader model name with TAP_TO_PAY_DEVICE. [https://github.com/woocommerce/woocommerce-ios/pull/15961]
19+
[**] POS: Added a guided setup flow for barcode scanning, and improved the scanning experience with better error handling and support for starting a new order on scan. [https://github.com/woocommerce/woocommerce-ios/pull/15979]
1920

2021
22.9
2122
-----

WooCommerce/Classes/ViewRelated/Orders/Order Creation/PaymentSection/Taxes/TaxEducationalDialogView.swift

Lines changed: 70 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,89 +16,90 @@ struct TaxEducationalDialogView: View {
1616
ZStack {
1717
Color.black.opacity(Layout.backgroundOpacity).edgesIgnoringSafeArea(.all)
1818

19-
VStack {
20-
GeometryReader { geometry in
21-
ScrollView {
22-
VStack(alignment: .center, spacing: Layout.verticalSpacing) {
23-
Text(Localization.title)
24-
.headlineStyle()
25-
Text(Localization.bodyFirstParagraph)
26-
.bodyStyle()
27-
.fixedSize(horizontal: false, vertical: true)
28-
Text(Localization.bodySecondParagraph)
29-
.bodyStyle()
19+
VStack {
20+
ScrollView {
21+
VStack(alignment: .center, spacing: Layout.verticalSpacing) {
22+
Text(Localization.title)
23+
.headlineStyle()
3024

25+
Text(Localization.bodyFirstParagraph)
26+
.bodyStyle()
27+
.fixedSize(horizontal: false, vertical: true)
3128

32-
VStack(alignment: .leading, spacing: Layout.verticalSpacing) {
33-
Divider()
34-
.frame(height: Layout.dividerHeight)
35-
.foregroundColor(Color(.opaqueSeparator))
36-
if let taxBasedOnSettingExplanatoryText = viewModel.taxBasedOnSettingExplanatoryText {
37-
Text(taxBasedOnSettingExplanatoryText)
38-
.bodyStyle()
39-
.fixedSize(horizontal: false, vertical: true)
40-
}
29+
Text(Localization.bodySecondParagraph)
30+
.bodyStyle()
4131

42-
ForEach(viewModel.taxLines, id: \.title) { taxLine in
43-
HStack {
44-
AdaptiveStack(horizontalAlignment: .leading, spacing: Layout.taxLinesInnerSpacing) {
45-
Text(taxLine.title)
46-
.font(.body)
47-
.fontWeight(.semibold)
48-
.multilineTextAlignment(.leading)
49-
.frame(maxWidth: .infinity, alignment: .leading)
32+
if viewModel.taxLines.isNotEmpty {
33+
VStack(alignment: .leading, spacing: Layout.verticalSpacing) {
34+
Divider()
35+
.frame(height: Layout.dividerHeight)
36+
.foregroundColor(Color(.opaqueSeparator))
5037

51-
Text(taxLine.value)
52-
.font(.body)
53-
.fontWeight(.semibold)
54-
.multilineTextAlignment(.trailing)
55-
.frame(width: nil, alignment: .trailing)
56-
}
57-
}
58-
}
59-
Divider()
60-
.frame(height: Layout.dividerHeight)
61-
.foregroundColor(Color(.opaqueSeparator))
62-
}.renderedIf(viewModel.taxLines.isNotEmpty)
38+
if let explanatoryText = viewModel.taxBasedOnSettingExplanatoryText {
39+
Text(explanatoryText)
40+
.bodyStyle()
41+
.fixedSize(horizontal: false, vertical: true)
42+
}
6343

64-
Button {
65-
viewModel.onGoToWpAdminButtonTapped()
66-
showingWPAdminWebview = true
67-
} label: {
68-
Label {
69-
Text(Localization.editTaxRatesInAdminButtonTitle)
44+
ForEach(viewModel.taxLines, id: \.title) { taxLine in
45+
AdaptiveStack(horizontalAlignment: .leading, spacing: Layout.taxLinesInnerSpacing) {
46+
Text(taxLine.title)
7047
.font(.body)
71-
.fontWeight(.bold)
72-
} icon: {
73-
Image(systemName: "arrow.up.forward.square")
74-
.resizable()
75-
.frame(width: Layout.externalLinkImageSize * scale, height: Layout.externalLinkImageSize * scale)
48+
.fontWeight(.semibold)
49+
.multilineTextAlignment(.leading)
50+
.frame(maxWidth: .infinity, alignment: .leading)
51+
52+
Text(taxLine.value)
53+
.font(.body)
54+
.fontWeight(.semibold)
55+
.multilineTextAlignment(.trailing)
56+
.frame(width: nil, alignment: .trailing)
7657
}
7758
}
78-
.buttonStyle(PrimaryButtonStyle())
79-
.safariSheet(isPresented: $showingWPAdminWebview, url: viewModel.wpAdminTaxSettingsURL, onDismiss: {
80-
onDismissWpAdminWebView()
81-
showingWPAdminWebview = false
82-
})
8359

84-
Button {
85-
dismiss()
86-
} label: {
87-
Text(Localization.doneButtonTitle)
88-
}
89-
.buttonStyle(SecondaryButtonStyle())
60+
Divider()
61+
.frame(height: Layout.dividerHeight)
62+
.foregroundColor(Color(.opaqueSeparator))
9063
}
91-
.padding(Layout.outterPadding)
92-
.frame(maxWidth: .infinity, alignment: .center)
93-
.background(Color(.systemBackground))
94-
.cornerRadius(Layout.cornerRadius)
95-
.frame(width: geometry.size.width) // Make the scroll view full-width
96-
.frame(minHeight: geometry.size.height)
9764
}
65+
66+
Button {
67+
viewModel.onGoToWpAdminButtonTapped()
68+
showingWPAdminWebview = true
69+
} label: {
70+
Label {
71+
Text(Localization.editTaxRatesInAdminButtonTitle)
72+
.font(.body)
73+
.fontWeight(.bold)
74+
} icon: {
75+
Image(systemName: "arrow.up.forward.square")
76+
.resizable()
77+
.frame(width: Layout.externalLinkImageSize * scale,
78+
height: Layout.externalLinkImageSize * scale)
79+
}
80+
}
81+
.buttonStyle(PrimaryButtonStyle())
82+
.safariSheet(
83+
isPresented: $showingWPAdminWebview,
84+
url: viewModel.wpAdminTaxSettingsURL,
85+
onDismiss: {
86+
onDismissWpAdminWebView()
87+
showingWPAdminWebview = false
88+
})
89+
90+
Button {
91+
dismiss()
92+
} label: {
93+
Text(Localization.doneButtonTitle)
94+
}
95+
.buttonStyle(SecondaryButtonStyle())
96+
}
97+
.padding(Layout.outterPadding)
9898
}
9999
}
100+
.background(Color(.systemBackground))
101+
.cornerRadius(Layout.cornerRadius)
100102
.padding(Layout.outterPadding)
101-
.frame(maxWidth: .infinity, alignment: .center)
102103
}
103104
}
104105
}

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShipping Customs/WooShippingCustomsFormViewModel.swift

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -120,34 +120,28 @@ private extension WooShippingCustomsFormViewModel {
120120
}
121121
.assign(to: &$isMissingITN)
122122

123-
let hsTariffNumberTotalValueDictionary = $itemsViewModels
124-
.map { childViewModels in
125-
childViewModels.map { $0.$hsTariffNumberTotalValue.eraseToAnyPublisher() }
126-
}
127-
.flatMap { childPublishers in
128-
childPublishers.combineLatest()
129-
}
130-
.map { values in
131-
var hsTariffNumberTotalValueDictionary: [String: Decimal] = [:]
132-
for (hsTariffNumber, totalValuePerItem) in values.compacted() {
133-
hsTariffNumberTotalValueDictionary[hsTariffNumber, default: 0] += totalValuePerItem
134-
}
135-
return hsTariffNumberTotalValueDictionary
136-
}
123+
let totalItemValue = $itemsViewModels
124+
.map { childViewModels in
125+
childViewModels.map { $0.$totalValue.eraseToAnyPublisher() }
126+
}
127+
.flatMap { childPublishers in
128+
childPublishers.combineLatest()
129+
}
130+
.map { values in
131+
return values.reduce(0) { partialResult, value in
132+
return partialResult + value
133+
}
134+
}
137135

138136
$internationalTransactionNumber.combineLatest(
139-
$itemsViewModels,
140-
hsTariffNumberTotalValueDictionary,
137+
totalItemValue,
141138
$destinationCountryCode)
142139
.map { input -> ITNValidationError? in
143-
let (itn, items, hsTariffNumberTotalValueDictionary, countryCode) = input
140+
let (itn, totalItemValue, countryCode) = input
144141
guard itn.isEmpty else {
145142
return ITNNumberValidator.isValid(itn) ? nil : .invalidFormat
146143
}
147144

148-
let totalItemValue = items.reduce(0, { sum, item in
149-
sum + item.totalValue
150-
})
151145
if totalItemValue > Constants.minimumValueForRequiredITN {
152146
return .missingForTotalShipmentValue
153147
}
@@ -160,11 +154,6 @@ private extension WooShippingCustomsFormViewModel {
160154
return .missingForRequiredDestination
161155
}
162156

163-
for (_, value) in hsTariffNumberTotalValueDictionary {
164-
if value > Constants.minimumValueForRequiredITN {
165-
return .missingForTariffClass
166-
}
167-
}
168157
return nil
169158
}
170159
.assign(to: &$itnValidationError)

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShipping Customs/WooShippingCustomsItemViewModel.swift

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ final class WooShippingCustomsItemViewModel: ObservableObject {
99
@Published var hsTariffNumber: String = ""
1010
@Published var valuePerUnit: String = ""
1111
@Published var weightPerUnit: String = ""
12-
// Useful to determine externally if the shipping requires an ITN
13-
@Published var hsTariffNumberTotalValue: (String, Decimal)?
1412

1513
@Published private var originCountryCode: String?
1614

@@ -31,13 +29,7 @@ final class WooShippingCustomsItemViewModel: ObservableObject {
3129

3230
@Published private(set) var countries: [Country] = []
3331

34-
var totalValue: Decimal {
35-
guard currencySymbol == "$",
36-
let valuePerUnitDecimal = Decimal(string: valuePerUnit) else {
37-
return 0
38-
}
39-
return valuePerUnitDecimal * itemQuantity
40-
}
32+
@Published private(set) var totalValue: Decimal = 0
4133

4234
/// View model for selecting a country from a list.
4335
var countrySelectorVM: CountrySelectorViewModel {
@@ -104,7 +96,7 @@ final class WooShippingCustomsItemViewModel: ObservableObject {
10496

10597
combineToPreselectCountry()
10698
combineRequiredInformationIsEntered()
107-
combineHSTariffNumberTotalValue()
99+
combineTotalItemValue()
108100
}
109101
}
110102

@@ -162,22 +154,19 @@ private extension WooShippingCustomsItemViewModel {
162154
.store(in: &cancellables)
163155
}
164156

165-
func combineHSTariffNumberTotalValue() {
166-
Publishers.CombineLatest($valuePerUnit, $hsTariffNumber)
167-
.sink { [weak self] valuePerUnit, hsTariffNumber in
168-
guard let self = self else { return }
169-
170-
guard self.currencySymbol == "$",
171-
let valuePerUnitDecimal = Decimal(string: valuePerUnit),
172-
hsTariffNumber.isNotEmpty,
173-
isValidTariffNumber else {
174-
self.hsTariffNumberTotalValue = nil
175-
return
176-
}
177-
178-
self.hsTariffNumberTotalValue = (hsTariffNumber, valuePerUnitDecimal * itemQuantity)
157+
func combineTotalItemValue() {
158+
$valuePerUnit.map { [weak self] valuePerUnit in
159+
guard
160+
let self,
161+
currencySymbol == "$",
162+
let valuePerUnitDecimal = Decimal(string: valuePerUnit)
163+
else {
164+
return 0
179165
}
180-
.store(in: &cancellables)
166+
167+
return valuePerUnitDecimal * itemQuantity
168+
}
169+
.assign(to: &$totalValue)
181170
}
182171

183172
/// Specifically introduced to check for a `0` value

WooCommerce/Resources/AppStoreStrings.pot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ msgctxt "app_store_promo_text"
6161
msgid "Run your store from anywhere"
6262
msgstr ""
6363

64-
msgctxt "v22.9-whats-new"
64+
msgctxt "v23.0-whats-new"
6565
msgid ""
66-
"This update enhances Shipping Labels with improved accessibility, smarter address validation, and faster performance. We've also added a dedicated Point of Sale tab for quicker access, and POS orders are now filterable in your order list for better organization. Plus, we've optimized assets to reduce the app's size!\n"
66+
"Faster performance and smoother experience! This update brings improved product loading, better tax calculations, and enhanced address lookup with map support. We've added guided barcode scanning for POS users and strengthened shipping requirements for EU destinations. Plus, we've fixed stability issues for a more reliable experience.\n"
6767
msgstr ""
6868

6969
#. translators: This is a promo message that will be attached on top of a screenshot in the App Store.

0 commit comments

Comments
 (0)