Skip to content

Commit b30c5c7

Browse files
authored
[iPadOS 26][Woo POS] Adjust Checkout view layout for smaller window heights (#16129)
2 parents 5cff5f0 + e7f9351 commit b30c5c7

11 files changed

+166
-15
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ final class CardPresentPaymentPreviewService: CardPresentPaymentFacade {
1414
$readerConnectionStatus.eraseToAnyPublisher()
1515
}
1616

17+
init(connectionStatus: CardPresentPaymentReaderConnectionStatus = .disconnected) {
18+
self.readerConnectionStatus = connectionStatus
19+
}
20+
1721
func connectReader(using connectionMethod: CardReaderConnectionMethod) async throws -> CardPresentPaymentReaderConnectionResult {
1822
.connected(CardPresentPaymentCardReader(name: "Test reader", batteryLevel: 0.85))
1923
}

WooCommerce/Classes/POS/Models/PointOfSaleAggregateModel.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,3 +627,12 @@ private extension PointOfSaleAggregateModel {
627627
static let initialPage: Int = 1
628628
}
629629
}
630+
631+
#if DEBUG
632+
extension PointOfSaleAggregateModel {
633+
func setPreviewState(paymentState: PointOfSalePaymentState, inlineMessage: PointOfSaleCardPresentPaymentMessageType?) {
634+
self.paymentState = paymentState
635+
self.cardPresentPaymentInlineMessage = inlineMessage
636+
}
637+
}
638+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import SwiftUI
2+
3+
struct POSCardPresentPaymentMessageViewImage: View {
4+
private let imageName: String
5+
6+
init(imageName: String) {
7+
self.imageName = imageName
8+
}
9+
10+
var body: some View {
11+
Image(decorative: imageName)
12+
.resizable()
13+
.aspectRatio(contentMode: .fit)
14+
.frame(
15+
minWidth: PointOfSaleCardPresentPaymentLayout.compactHeaderSize.width,
16+
maxWidth: PointOfSaleCardPresentPaymentLayout.headerSize.width,
17+
minHeight: PointOfSaleCardPresentPaymentLayout.compactHeaderSize.height,
18+
maxHeight: PointOfSaleCardPresentPaymentLayout.headerSize.height
19+
)
20+
.accessibilityHidden(true)
21+
}
22+
}

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentCardInsertedMessageView.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ struct PointOfSaleCardPresentPaymentCardInsertedMessageView: View {
77

88
var body: some View {
99
VStack(alignment: .center, spacing: Constants.imageAndTextSpacing) {
10-
Image(decorative: viewModel.imageName)
11-
.resizable()
12-
.aspectRatio(contentMode: .fill)
13-
.frame(width: PointOfSaleCardPresentPaymentLayout.headerSize.width,
14-
height: PointOfSaleCardPresentPaymentLayout.headerSize.height)
10+
POSCardPresentPaymentMessageViewImage(imageName: viewModel.imageName)
1511
.matchedGeometryEffect(id: animation.iconTransitionId, in: animation.namespace, properties: .position)
1612
.renderedIf(!dynamicTypeSize.isAccessibilitySize)
1713
VStack(alignment: .center, spacing: PointOfSaleCardPresentPaymentLayout.textSpacing) {

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentDisconnectedMessageView.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct PointOfSaleCardPresentPaymentReaderDisconnectedMessageView: View {
1313

1414
var body: some View {
1515
VStack(alignment: .center, spacing: POSSpacing.none) {
16-
Image(decorative: PointOfSaleAssets.readerDisconnected.imageName)
16+
POSCardPresentPaymentMessageViewImage(imageName: PointOfSaleAssets.readerDisconnected.imageName)
1717

1818
Spacer()
1919
.frame(height: dynamicSpacing(PointOfSaleCardPresentPaymentLayout.imageAndTextSpacing))
@@ -41,6 +41,7 @@ struct PointOfSaleCardPresentPaymentReaderDisconnectedMessageView: View {
4141
.buttonStyle(POSFilledButtonStyle(size: .normal))
4242
.frame(width: width * 0.5)
4343
}
44+
.frame(maxWidth: .infinity)
4445
.measureWidth({ containerWidth in
4546
width = containerWidth
4647
})

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentLayout.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Foundation
22

33
enum PointOfSaleCardPresentPaymentLayout {
44
static let headerSize: CGSize = .init(width: 156, height: 156)
5+
static let compactHeaderSize: CGSize = .init(width: 48, height: 48)
56
static let imageAndTextSpacing: CGFloat = POSSpacing.large
67
static let textAndButtonSpacing: CGFloat = POSSpacing.xxLarge
78
static let textSpacing: CGFloat = POSSpacing.small

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentTapSwipeInsertCardMessageView.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ struct PointOfSaleCardPresentPaymentTapSwipeInsertCardMessageView: View {
77

88
var body: some View {
99
VStack(alignment: .center, spacing: Constants.imageAndTextSpacing) {
10-
Image(decorative: viewModel.imageName)
11-
.resizable()
12-
.aspectRatio(contentMode: .fill)
13-
.frame(width: PointOfSaleCardPresentPaymentLayout.headerSize.width,
14-
height: PointOfSaleCardPresentPaymentLayout.headerSize.height)
10+
POSCardPresentPaymentMessageViewImage(imageName: viewModel.imageName)
1511
.matchedGeometryEffect(id: animation.iconTransitionId, in: animation.namespace, properties: .position)
1612
.renderedIf(!dynamicTypeSize.isAccessibilitySize)
1713
VStack(alignment: .center, spacing: PointOfSaleCardPresentPaymentLayout.textSpacing) {

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentValidatingOrderErrorMessageView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct PointOfSaleCardPresentPaymentValidatingOrderErrorMessageView: View {
3939
}
4040
}
4141
.multilineTextAlignment(.center)
42+
.frame(maxWidth: .infinity)
4243
.measureWidth({ containerWidth in
4344
width = containerWidth
4445
})

WooCommerce/Classes/POS/Presentation/TotalsView.swift

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct TotalsView: View {
6565
)
6666
}
6767
.animation(.default, value: isShowingPaymentView)
68+
.scrollVerticallyIfNeeded()
6869
case .error(.other(let message), let handler):
6970
PointOfSaleOrderSyncErrorMessageView(message: message, retryHandler: handler)
7071
.transition(.opacity)
@@ -567,8 +568,120 @@ private struct CashPaymentButton: View {
567568
}
568569

569570
#if DEBUG
570-
#Preview {
571+
#Preview("Card Reader Not Connected") {
571572
TotalsView()
572-
.environment(POSPreviewHelpers.makePreviewAggregateModel())
573+
.environment(POSPreviewHelpers.makePreviewAggregateModel(
574+
cardPresentPaymentService: CardPresentPaymentPreviewService(connectionStatus: .disconnected)
575+
))
576+
}
577+
578+
#Preview("Card Reader Connected") {
579+
TotalsView()
580+
.environment(POSPreviewHelpers.makePreviewAggregateModel(
581+
cardPresentPaymentService: CardPresentPaymentPreviewService(
582+
connectionStatus: .connected(CardPresentPaymentCardReader(name: "Reader", batteryLevel: 0.85))
583+
)
584+
))
573585
}
586+
587+
#Preview("Validating Order") {
588+
let aggregateModel = POSPreviewHelpers.makePreviewAggregateModel(
589+
cardPresentPaymentService: CardPresentPaymentPreviewService(
590+
connectionStatus: .connected(CardPresentPaymentCardReader(name: "Reader", batteryLevel: 0.85))
591+
)
592+
)
593+
Task { @MainActor in
594+
aggregateModel.setPreviewState(
595+
paymentState: PointOfSalePaymentState(card: .validatingOrder, cash: .idle),
596+
inlineMessage: .validatingOrder(viewModel: PointOfSaleCardPresentPaymentValidatingOrderMessageViewModel())
597+
)
598+
}
599+
return TotalsView()
600+
.environment(aggregateModel)
601+
}
602+
603+
#Preview("Accepting Card") {
604+
let aggregateModel = POSPreviewHelpers.makePreviewAggregateModel(
605+
cardPresentPaymentService: CardPresentPaymentPreviewService(
606+
connectionStatus: .connected(CardPresentPaymentCardReader(name: "Reader", batteryLevel: 0.85))
607+
)
608+
)
609+
Task { @MainActor in
610+
aggregateModel.setPreviewState(
611+
paymentState: PointOfSalePaymentState(card: .acceptingCard, cash: .idle),
612+
inlineMessage: .tapSwipeOrInsertCard(viewModel: PointOfSaleCardPresentPaymentTapSwipeInsertCardMessageViewModel(inputMethods: []))
613+
)
614+
}
615+
return TotalsView()
616+
.environment(aggregateModel)
617+
}
618+
619+
#Preview("Processing Payment") {
620+
let aggregateModel = POSPreviewHelpers.makePreviewAggregateModel(
621+
cardPresentPaymentService: CardPresentPaymentPreviewService(
622+
connectionStatus: .connected(CardPresentPaymentCardReader(name: "Reader", batteryLevel: 0.85))
623+
)
624+
)
625+
Task { @MainActor in
626+
aggregateModel.setPreviewState(
627+
paymentState: PointOfSalePaymentState(card: .processingPayment, cash: .idle),
628+
inlineMessage: .processing(viewModel: PointOfSaleCardPresentPaymentProcessingMessageViewModel())
629+
)
630+
}
631+
return TotalsView()
632+
.environment(aggregateModel)
633+
}
634+
635+
#Preview("Card Payment Successful") {
636+
let aggregateModel = POSPreviewHelpers.makePreviewAggregateModel(
637+
cardPresentPaymentService: CardPresentPaymentPreviewService(
638+
connectionStatus: .connected(CardPresentPaymentCardReader(name: "Reader", batteryLevel: 0.85))
639+
)
640+
)
641+
Task { @MainActor in
642+
aggregateModel.setPreviewState(
643+
paymentState: PointOfSalePaymentState(card: .cardPaymentSuccessful, cash: .idle),
644+
inlineMessage: .paymentSuccess(viewModel: PointOfSalePaymentSuccessViewModel(formattedOrderTotal: "$12.00", paymentMethod: .card))
645+
)
646+
}
647+
return TotalsView()
648+
.environment(aggregateModel)
649+
}
650+
651+
#Preview("Display Reader Message") {
652+
let aggregateModel = POSPreviewHelpers.makePreviewAggregateModel(
653+
cardPresentPaymentService: CardPresentPaymentPreviewService(
654+
connectionStatus: .connected(CardPresentPaymentCardReader(name: "Reader", batteryLevel: 0.85))
655+
)
656+
)
657+
Task { @MainActor in
658+
aggregateModel.setPreviewState(
659+
paymentState: PointOfSalePaymentState(card: .processingPayment, cash: .idle),
660+
inlineMessage: .displayReaderMessage(viewModel: PointOfSaleCardPresentPaymentDisplayReaderMessageMessageViewModel(message: "Remove card"))
661+
)
662+
}
663+
return TotalsView()
664+
.environment(aggregateModel)
665+
}
666+
667+
#Preview("Payment Error") {
668+
let aggregateModel = POSPreviewHelpers.makePreviewAggregateModel(
669+
cardPresentPaymentService: CardPresentPaymentPreviewService(
670+
connectionStatus: .connected(CardPresentPaymentCardReader(name: "Reader", batteryLevel: 0.85))
671+
)
672+
)
673+
Task { @MainActor in
674+
aggregateModel.setPreviewState(
675+
paymentState: PointOfSalePaymentState(card: .paymentError, cash: .idle),
676+
inlineMessage: .paymentError(viewModel: PointOfSaleCardPresentPaymentErrorMessageViewModel(
677+
error: NSError(domain: "CardPaymentError", code: 1001, userInfo: [NSLocalizedDescriptionKey: "Card declined"]),
678+
tryPaymentAgainButtonAction: {},
679+
backToCheckoutButtonAction: {}
680+
))
681+
)
682+
}
683+
return TotalsView()
684+
.environment(aggregateModel)
685+
}
686+
574687
#endif

WooCommerce/Classes/POS/Utils/PointOfSalePreviewOrderController.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import struct Yosemite.Order
44
import Combine
55

66
class PointOfSalePreviewOrderController: PointOfSaleOrderControllerProtocol {
7-
var orderState: PointOfSaleInternalOrderState = .loaded(
7+
var orderState: PointOfSaleInternalOrderState
8+
9+
init(orderState: PointOfSaleInternalOrderState = .loaded(
810
.init(cartTotal: "$10.50",
911
orderTotal: "$12.00",
1012
taxTotal: "$1.50",
1113
orderTotalDecimal: 12.00),
1214
OrderFactory.newOrder(currency: .USD)
13-
)
15+
)) {
16+
self.orderState = orderState
17+
}
1418

1519
func syncOrder(for cart: Cart, retryHandler: @escaping () async -> Void) async -> Result<SyncOrderState, Error> {
1620
return .success(.newOrder)

0 commit comments

Comments
 (0)