Skip to content

Commit bfac5ec

Browse files
committed
Merge branch 'trunk' into task/15128-resolve-card-present-events-from-pos
# Conflicts: # WooCommerce/Classes/POS/Presentation/POSFloatingControlView.swift
2 parents 4748a30 + a406f48 commit bfac5ec

35 files changed

+611
-190
lines changed

Fakes/Fakes/Networking.generated.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,6 +2369,21 @@ extension Networking.StoredProductSettings {
23692369
)
23702370
}
23712371
}
2372+
extension Networking.StoredProductSettings.Setting {
2373+
/// Returns a "ready to use" type filled with fake values.
2374+
///
2375+
public static func fake() -> Networking.StoredProductSettings.Setting {
2376+
.init(
2377+
siteID: .fake(),
2378+
sort: .fake(),
2379+
stockStatusFilter: .fake(),
2380+
productStatusFilter: .fake(),
2381+
productTypeFilter: .fake(),
2382+
productCategoryFilter: .fake(),
2383+
favoriteProduct: .fake()
2384+
)
2385+
}
2386+
}
23722387
extension Networking.Subscription {
23732388
/// Returns a "ready to use" type filled with fake values.
23742389
///

Networking/Networking/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,6 +3502,36 @@ extension Networking.SiteVisitStatsItem {
35023502
}
35033503
}
35043504

3505+
extension Networking.StoredProductSettings.Setting {
3506+
public func copy(
3507+
siteID: CopiableProp<Int64> = .copy,
3508+
sort: NullableCopiableProp<String> = .copy,
3509+
stockStatusFilter: NullableCopiableProp<ProductStockStatus> = .copy,
3510+
productStatusFilter: NullableCopiableProp<ProductStatus> = .copy,
3511+
productTypeFilter: NullableCopiableProp<ProductType> = .copy,
3512+
productCategoryFilter: NullableCopiableProp<ProductCategory> = .copy,
3513+
favoriteProduct: CopiableProp<Bool> = .copy
3514+
) -> Networking.StoredProductSettings.Setting {
3515+
let siteID = siteID ?? self.siteID
3516+
let sort = sort ?? self.sort
3517+
let stockStatusFilter = stockStatusFilter ?? self.stockStatusFilter
3518+
let productStatusFilter = productStatusFilter ?? self.productStatusFilter
3519+
let productTypeFilter = productTypeFilter ?? self.productTypeFilter
3520+
let productCategoryFilter = productCategoryFilter ?? self.productCategoryFilter
3521+
let favoriteProduct = favoriteProduct ?? self.favoriteProduct
3522+
3523+
return Networking.StoredProductSettings.Setting(
3524+
siteID: siteID,
3525+
sort: sort,
3526+
stockStatusFilter: stockStatusFilter,
3527+
productStatusFilter: productStatusFilter,
3528+
productTypeFilter: productTypeFilter,
3529+
productCategoryFilter: productCategoryFilter,
3530+
favoriteProduct: favoriteProduct
3531+
)
3532+
}
3533+
}
3534+
35053535
extension Networking.Subscription {
35063536
public func copy(
35073537
siteID: CopiableProp<Int64> = .copy,

Networking/Networking/Model/Product/StoredProductSettings.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Codegen
66
///
77
public struct StoredProductSettings: Codable, Equatable, GeneratedFakeable {
88

9-
public struct Setting: Codable, Equatable {
9+
public struct Setting: Codable, Equatable, GeneratedFakeable, GeneratedCopiable {
1010
public let siteID: Int64
1111
public let sort: String?
1212
public let stockStatusFilter: ProductStockStatus?

RELEASE-NOTES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
- [*] Now "Suggested by AI" label is visible in dark mode in Blaze campaign creation flow. [https://github.com/woocommerce/woocommerce-ios/pull/15088]
88
- [*] Improved image loading in Blaze Campaign Creation: displays a redacted and shimmering effects when loading product image and falls back to a placeholder if no image is available. [https://github.com/woocommerce/woocommerce-ios/pull/15098]
99
- [*] Product List: Display syncing animation on items with image upload in progress [https://github.com/woocommerce/woocommerce-ios/pull/15052]
10+
- [*] Background image upload: Fix issue showing uploaded images while saving is in progress [https://github.com/woocommerce/woocommerce-ios/pull/15107]
1011
- [*] Background image upload: Fix missing error notice in iPhones [https://github.com/woocommerce/woocommerce-ios/pull/15117]
12+
- [*] Background image upload: Show a notice when the user leaves product details while uploads are pending [https://github.com/woocommerce/woocommerce-ios/pull/15134]
13+
- [*] Filters applied in product selector no longer affect the main product list screen. [https://github.com/woocommerce/woocommerce-ios/pull/14764]
1114

1215
21.7
1316
-----

WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentPreviewService.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import struct Yosemite.Order
55

66
#if DEBUG
77

8-
struct CardPresentPaymentPreviewService: CardPresentPaymentFacade {
8+
final class CardPresentPaymentPreviewService: CardPresentPaymentFacade {
99
let paymentEventPublisher: AnyPublisher<CardPresentPaymentEvent, Never> = Just(.idle).eraseToAnyPublisher()
1010

11-
let readerConnectionStatusPublisher: AnyPublisher<CardPresentPaymentReaderConnectionStatus, Never> = Just(.disconnected)
12-
.eraseToAnyPublisher()
11+
@Published var readerConnectionStatus: CardPresentPaymentReaderConnectionStatus = .disconnected
12+
13+
var readerConnectionStatusPublisher: AnyPublisher<CardPresentPaymentReaderConnectionStatus, Never> {
14+
$readerConnectionStatus.eraseToAnyPublisher()
15+
}
1316

1417
func connectReader(using connectionMethod: CardReaderConnectionMethod) async throws -> CardPresentPaymentReaderConnectionResult {
1518
.connected(CardPresentPaymentCardReader(name: "Test reader", batteryLevel: 0.85))

WooCommerce/Classes/POS/Presentation/CardReaderConnection/CardReaderConnectionStatusView.swift

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,17 @@ struct CardReaderConnectionStatusView: View {
4444
posModel.connectCardReader()
4545
} label: {
4646
HStack(spacing: Constants.buttonImageAndTextSpacing) {
47-
circleIcon(with: Color(.wooCommerceAmber(.shade60)))
47+
circleIcon(with: Color.posAlert)
4848
Text(Localization.readerDisconnected)
4949
.foregroundColor(disconnectedFontColor)
5050
}
51-
.padding(.horizontal, Constants.overlayInnerHorizontalPadding)
52-
.frame(maxHeight: .infinity)
53-
.overlay {
54-
RoundedRectangle(cornerRadius: Constants.overlayRadius)
55-
.stroke(Constants.overlayColor, lineWidth: Constants.overlayLineWidth)
56-
}
57-
.padding(.horizontal, Constants.overlayOuterHorizontalPadding)
58-
.padding(.vertical, Constants.overlayOuterVerticalPadding)
51+
.padding(.horizontal, Constants.disconnectedBorderAndContentSpacing)
5952
.frame(maxHeight: .infinity)
53+
.overlay(
54+
RoundedRectangle(cornerRadius: Constants.disconnectedBorderCornerRadius)
55+
.stroke(disconnectedBorderColor, lineWidth: Constants.disconnectedBorderWidth)
56+
)
57+
.padding(Constants.disconnectedBorderInset)
6058
}
6159
}
6260
}
@@ -102,23 +100,30 @@ private extension CardReaderConnectionStatusView {
102100
POSFloatingControlView.secondaryFontColor
103101
}
104102
}
103+
104+
var disconnectedBorderColor: Color {
105+
switch backgroundAppearance {
106+
case .primary:
107+
.posPrimary
108+
case .secondary:
109+
POSFloatingControlView.secondaryFontColor
110+
}
111+
}
105112
}
106113

107114
@available(iOS 17.0, *)
108115
private extension CardReaderConnectionStatusView {
109116
enum Constants {
110-
static let buttonImageAndTextSpacing: CGFloat = 12
111-
static let imageDimension: CGFloat = 12
117+
static let buttonImageAndTextSpacing: CGFloat = 16
118+
static let imageDimension: CGFloat = 14
112119
static let progressIndicatorDimension: CGFloat = 10
113120
static let progressIndicatorLineWidth: CGFloat = 2
114121
static let font = POSFontStyle.posBodyMediumRegular()
115122
static let horizontalPadding: CGFloat = 24
116-
static let overlayRadius: CGFloat = 4
117-
static let overlayLineWidth: CGFloat = 2
118-
static let overlayColor: Color = Color.init(uiColor: .wooCommercePurple(.shade60))
119-
static let overlayInnerHorizontalPadding: CGFloat = 16 + Self.overlayLineWidth
120-
static let overlayOuterHorizontalPadding: CGFloat = 8 + Self.overlayLineWidth
121-
static let overlayOuterVerticalPadding: CGFloat = 8 + Self.overlayLineWidth
123+
static let disconnectedBorderAndContentSpacing: CGFloat = 16
124+
static let disconnectedBorderCornerRadius: CGFloat = POSCornerRadiusStyle.small.value
125+
static let disconnectedBorderWidth: CGFloat = 2
126+
static let disconnectedBorderInset: CGFloat = 8
122127
}
123128
}
124129

@@ -171,6 +176,8 @@ private extension CardReaderConnectionStatusView {
171176
)
172177
VStack {
173178
CardReaderConnectionStatusView()
179+
.background(Color.posSurfaceContainerLow)
180+
.frame(height: 80)
174181
.environment(posModel)
175182
}
176183
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import SwiftUI
2+
3+
struct GhostItemCardView: View {
4+
@ScaledMetric private var scale: CGFloat = 1.0
5+
6+
private var dimension: CGFloat {
7+
min(Constants.productCardSize * scale, Constants.maximumProductCardSize)
8+
}
9+
10+
var body: some View {
11+
HStack(spacing: Constants.cardSpacing) {
12+
Spacer()
13+
.frame(width: dimension, height: dimension)
14+
Rectangle()
15+
.foregroundColor(.posOnSurfaceVariantLowest)
16+
.frame(height: Layout.placeholderHeight * scale)
17+
.cornerRadius(Layout.cornerRadius)
18+
.padding(.horizontal, Constants.horizontalTextPadding)
19+
Spacer()
20+
.frame(width: dimension, height: dimension)
21+
}
22+
.shimmering()
23+
.frame(maxWidth: .infinity, idealHeight: dimension)
24+
.background(Color.posSurfaceBright)
25+
.posItemCardBorderStyles()
26+
}
27+
}
28+
29+
private extension GhostItemCardView {
30+
typealias Constants = PointOfSaleItemListCardConstants
31+
32+
enum Layout {
33+
static let placeholderHeight: CGFloat = 36
34+
static let cornerRadius: CGFloat = POSCornerRadiusStyle.medium.value
35+
}
36+
}
37+
38+
#Preview {
39+
GhostItemCardView()
40+
}

WooCommerce/Classes/POS/Presentation/ItemListView.swift

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private extension ItemListView {
114114
.fixedSize(horizontal: false, vertical: true)
115115
.background(Color.posSurfaceBright)
116116
.cornerRadius(Constants.bannerCornerRadius)
117-
.shadow(color: Color.black.opacity(0.08), radius: 4, y: 2)
117+
.posShadow(.medium)
118118
.accessibilityAddTraits(.isButton)
119119
.onTapGesture {
120120
showSimpleProductsModal = true
@@ -126,7 +126,7 @@ private extension ItemListView {
126126
Text(headerBannerHint + " ") +
127127
Text(Localization.headerBannerLearnMoreHint)
128128
.font(POSFontStyle.posBodySmallBold.font())
129-
.foregroundColor(Color(.accent))
129+
.foregroundColor(Color(.posPrimary))
130130
}
131131

132132
@ViewBuilder
@@ -173,53 +173,14 @@ private extension ItemListState {
173173
}
174174
}
175175

176-
struct GhostItemCardView: View {
177-
@ScaledMetric private var scale: CGFloat = 1.0
178-
179-
var body: some View {
180-
HStack(spacing: 0) {
181-
Rectangle()
182-
.frame(width: Constants.productCardSize * scale, height: Constants.productCardSize * scale)
183-
HStack {
184-
Rectangle()
185-
.foregroundColor(Constants.textForegroundColor)
186-
.frame(width: Constants.textWidth * 2 * scale, height: Constants.textHeight * scale)
187-
.padding(.horizontal)
188-
Spacer()
189-
Rectangle()
190-
.foregroundColor(Constants.textForegroundColor)
191-
.frame(width: Constants.textWidth * scale, height: Constants.textHeight * scale)
192-
.padding(.horizontal)
193-
}
194-
.frame(height: Constants.productCardSize * scale)
195-
}
196-
.overlay {
197-
RoundedRectangle(cornerRadius: Constants.cornerRadius)
198-
}
199-
.foregroundColor(Constants.cardForegroundColor)
200-
.shimmering()
201-
}
202-
}
203-
204-
private extension GhostItemCardView {
205-
enum Constants {
206-
static let cornerRadius: CGFloat = 8
207-
static let cardForegroundColor: Color = Color.gray.opacity(0.5)
208-
static let textForegroundColor: Color = Color.gray.opacity(0.8)
209-
static let productCardSize: CGFloat = 112
210-
static let textWidth: CGFloat = 112
211-
static let textHeight: CGFloat = 32
212-
}
213-
}
214-
215176
/// Constants
216177
///
217178
@available(iOS 17.0, *)
218179
private extension ItemListView {
219180
enum Constants {
220181
static let bannerTitleFont: POSFontStyle = .posBodyLargeBold
221182
static let bannerSubtitleFont: POSFontStyle = .posBodySmallRegular()
222-
static let bannerCornerRadius: CGFloat = 8
183+
static let bannerCornerRadius: CGFloat = POSCornerRadiusStyle.medium.value
223184
static let bannerVerticalPadding: CGFloat = 26
224185
static let bannerTextSpacing: CGFloat = 4
225186
static let bannerTitleSpacing: CGFloat = 8

WooCommerce/Classes/POS/Presentation/POSFloatingControlView.swift

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import SwiftUI
44
struct POSFloatingControlView: View {
55
@Environment(\.posBackgroundAppearance) var backgroundAppearance
66
@Environment(PointOfSaleAggregateModel.self) private var posModel
7-
@Environment(\.colorScheme) var colorScheme
87
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
98
@Binding private var showExitPOSModal: Bool
109
@Binding private var showSupport: Bool
@@ -71,6 +70,7 @@ struct POSFloatingControlView: View {
7170
.frame(height: Constants.size)
7271
.background(Color.clear)
7372
.animation(.default, value: backgroundAppearance)
73+
.posShadow(.large)
7474
}
7575
}
7676

@@ -81,7 +81,7 @@ private extension POSFloatingControlView {
8181
case .primary:
8282
.posSurfaceContainerLow
8383
case .secondary:
84-
colorScheme == .light ? Color(.wooCommercePurple(.shade80)) : Color(.wooCommercePurple(.shade20))
84+
.posDisabledContainer
8585
}
8686
}
8787

@@ -93,15 +93,15 @@ private extension POSFloatingControlView {
9393
@available(iOS 17.0, *)
9494
extension POSFloatingControlView {
9595
static var secondaryFontColor: Color {
96-
return .posDarkGray.opacity(0.6)
96+
.posOnDisabledContainer
9797
}
9898
}
9999

100100
@available(iOS 17.0, *)
101101
private extension POSFloatingControlView {
102102
enum Constants {
103-
static let size: CGFloat = 56
104-
static let cornerRadius: CGFloat = 8
103+
static let size: CGFloat = 80
104+
static let cornerRadius: CGFloat = POSCornerRadiusStyle.medium.value
105105
}
106106

107107
enum Localization {
@@ -127,17 +127,43 @@ private extension POSFloatingControlView {
127127
}
128128

129129
#if DEBUG
130+
130131
@available(iOS 17.0, *)
131-
#Preview {
132+
#Preview("Reader Disconnected") {
132133
let posModel = PointOfSaleAggregateModel(
133134
itemsController: PointOfSalePreviewItemsController(),
134135
cardPresentPaymentService: CardPresentPaymentPreviewService(),
135136
orderController: PointOfSalePreviewOrderController(),
136137
collectOrderPaymentAnalyticsTracker: POSCollectOrderPaymentAnalytics())
138+
POSFloatingControlView(showExitPOSModal: .constant(false), showSupport: .constant(false), showDocumentation: .constant(false))
139+
.environment(\.posBackgroundAppearance, .primary)
140+
.environment(posModel)
141+
}
137142

138-
POSFloatingControlView(showExitPOSModal: .constant(false),
139-
showSupport: .constant(false),
140-
showDocumentation: .constant(false))
141-
.environment(posModel)
143+
@available(iOS 17.0, *)
144+
#Preview("Reader Connected") {
145+
let paymentService = CardPresentPaymentPreviewService()
146+
let posModel = PointOfSaleAggregateModel(
147+
itemsController: PointOfSalePreviewItemsController(),
148+
cardPresentPaymentService: CardPresentPaymentPreviewService(),
149+
orderController: PointOfSalePreviewOrderController(),
150+
collectOrderPaymentAnalyticsTracker: POSCollectOrderPaymentAnalytics())
151+
paymentService.readerConnectionStatus = .connected(.init(name: "", batteryLevel: 0.6))
152+
return POSFloatingControlView(showExitPOSModal: .constant(false), showSupport: .constant(false), showDocumentation: .constant(false))
153+
.environment(\.posBackgroundAppearance, .primary)
154+
.environment(posModel)
142155
}
156+
157+
@available(iOS 17.0, *)
158+
#Preview("Secondary/disabled Background") {
159+
let posModel = PointOfSaleAggregateModel(
160+
itemsController: PointOfSalePreviewItemsController(),
161+
cardPresentPaymentService: CardPresentPaymentPreviewService(),
162+
orderController: PointOfSalePreviewOrderController(),
163+
collectOrderPaymentAnalyticsTracker: POSCollectOrderPaymentAnalytics())
164+
POSFloatingControlView(showExitPOSModal: .constant(false), showSupport: .constant(false), showDocumentation: .constant(false))
165+
.environment(\.posBackgroundAppearance, .secondary)
166+
.environment(posModel)
167+
}
168+
143169
#endif

WooCommerce/Classes/POS/Presentation/POSReceiptEligibilityBanner.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct POSReceiptEligibilityBanner: View {
2929
private extension POSReceiptEligibilityBanner {
3030
enum Constants {
3131
static let elementSpacing: CGFloat = 8
32-
static let cornerRadius: CGFloat = 20
32+
static let cornerRadius: CGFloat = POSCornerRadiusStyle.large.value
3333
static let imagesize: CGFloat = 40
3434
static let imagePadding: CGFloat = 4
3535
static let bannerPadding: CGFloat = 16
@@ -42,3 +42,8 @@ private extension POSReceiptEligibilityBanner {
4242
comment: "Text for the banner requiring specific WooCommerce version.")
4343
}
4444
}
45+
46+
#Preview {
47+
POSReceiptEligibilityBanner(isVisible: .constant(true))
48+
.padding()
49+
}

0 commit comments

Comments
 (0)