Skip to content

Commit 43a0e68

Browse files
authored
[Woo POS][Barcodes] Disable scanning when the support view is open (#15972)
2 parents 56ca8c3 + 04949bb commit 43a0e68

10 files changed

+155
-14
lines changed

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Connection Alerts/PointOfSaleCardPresentPaymentConnectingFailedUpdateAddressView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct PointOfSaleCardPresentPaymentConnectingFailedUpdateAddressView: View {
2828
accessibilityLabel: viewModel.cancelButtonViewModel.title)
2929
.multilineTextAlignment(.center)
3030
.accessibilityElement(children: .contain)
31-
.sheet(isPresented: $viewModel.shouldShowSettingsWebView) {
31+
.posSheet(isPresented: $viewModel.shouldShowSettingsWebView) {
3232
WCSettingsWebView(adminUrl: viewModel.settingsAdminUrl,
3333
completion: viewModel.settingsWebViewWasDismissed)
3434
}

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Connection Alerts/PointOfSaleCardPresentPaymentOptionalReaderUpdateInProgressView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ struct PointOfSaleCardPresentPaymentOptionalReaderUpdateInProgressPreviewView: V
6969
showsSheet = true
7070
}
7171
}
72-
.sheet(isPresented: $showsSheet) {
72+
.posSheet(isPresented: $showsSheet) {
7373
PointOfSaleCardPresentPaymentOptionalReaderUpdateInProgressView(viewModel: .init(
7474
progress: 0.6, cancel: nil
7575
), animation: .init(namespace: namespace))

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Connection Alerts/PointOfSaleCardPresentPaymentReaderUpdateCompletionView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct PointOfSaleCardPresentPaymentReaderUpdateCompletionPreviewView: View {
4949
showsSheet = true
5050
}
5151
}
52-
.sheet(isPresented: $showsSheet) {
52+
.posSheet(isPresented: $showsSheet) {
5353
PointOfSaleCardPresentPaymentReaderUpdateCompletionView(
5454
viewModel: .init(),
5555
animation: .init(namespace: namespace)

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Connection Alerts/PointOfSaleCardPresentPaymentRequiredReaderUpdateInProgressView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ struct CardPresentPaymentRequiredReaderUpdateInProgressPreviewView: View {
7070
showsSheet = true
7171
}
7272
}
73-
.sheet(isPresented: $showsSheet) {
73+
.posSheet(isPresented: $showsSheet) {
7474
PointOfSaleCardPresentPaymentRequiredReaderUpdateInProgressView(viewModel: .init(
7575
progress: 0.6, cancel: nil
7676
), animation: .init(namespace: namespace))

WooCommerce/Classes/POS/Presentation/Coupons/POSCouponCreationSheet.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ private struct POSCouponCreationSheetModifier: ViewModifier {
2222

2323
func body(content: Content) -> some View {
2424
content
25-
.sheet(item: $selectedType) { (posDiscountType: POSCouponDiscountType) in
25+
.posSheet(item: $selectedType) { (posDiscountType: POSCouponDiscountType) in
2626
POSCouponCreationView(
2727
discountType: posDiscountType.discountType,
2828
showTypeSelection: $showCouponSelectionSheet,
@@ -89,7 +89,7 @@ private extension View {
8989
isPresented: Binding<Bool>,
9090
onSelection: @escaping (POSCouponDiscountType) -> Void
9191
) -> some View {
92-
sheet(isPresented: isPresented) {
92+
posSheet(isPresented: isPresented) {
9393
let command = DiscountTypeBottomSheetListSelectorCommand(selected: nil) { type in
9494
onSelection(.init(discountType: type))
9595
}

WooCommerce/Classes/POS/Presentation/ItemListView.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct ItemListView: View {
99
@Environment(PointOfSaleAggregateModel.self) private var posModel
1010
@Environment(\.keyboardObserver) private var keyboardObserver
1111
@EnvironmentObject var modalManager: POSModalManager
12+
@EnvironmentObject var sheetManager: POSSheetManager
1213

1314
@Binding var selectedItemListType: ItemListType
1415
@Binding var searchTerm: String
@@ -42,7 +43,7 @@ struct ItemListView: View {
4243

4344
private var isBarcodeScanningEnabled: Binding<Bool> {
4445
Binding(
45-
get: { !isSearching && !modalManager.isPresented },
46+
get: { !isSearching && !modalManager.isPresented && !sheetManager.isPresented },
4647
set: { _ in }
4748
)
4849
}
@@ -457,13 +458,17 @@ private extension ItemListView {
457458
return ItemListView(selectedItemListType: .constant(.products(search: false)),
458459
searchTerm: .constant(""))
459460
.environment(posModel)
461+
.environmentObject(POSModalManager())
462+
.environmentObject(POSSheetManager())
460463
}
461464

462465
@available(iOS 17.0, *)
463466
#Preview("Loading") {
464467
ItemListView(selectedItemListType: .constant(.products(search: false)),
465468
searchTerm: .constant(""))
466469
.environment(POSPreviewHelpers.makePreviewAggregateModel())
470+
.environmentObject(POSModalManager())
471+
.environmentObject(POSSheetManager())
467472
}
468473

469474
#endif

WooCommerce/Classes/POS/Presentation/PointOfSaleDashboardView.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,11 @@ struct PointOfSaleDashboardView: View {
123123
.frame(maxWidth: Constants.exitPOSSheetMaxWidth)
124124
}
125125
.posRootModal()
126-
.sheet(isPresented: $showSupport) {
126+
.posSheet(isPresented: $showSupport) {
127127
supportForm
128128
.interactiveDismissDisabled(true)
129129
}
130-
.sheet(isPresented: $showDocumentation) {
130+
.posSheet(isPresented: $showDocumentation) {
131131
documentationView
132132
}
133133
.onChange(of: posModel.entryPointController.eligibilityState) { oldValue, newValue in
@@ -190,8 +190,8 @@ private extension PointOfSaleDashboardView {
190190
viewModel: SupportFormViewModel(sourceTag: Constants.supportTag,
191191
defaultSite: ServiceLocator.stores.sessionManager.defaultSite))
192192
.toolbar {
193-
ToolbarItem(placement: .confirmationAction) {
194-
Button(Localization.supportDone) {
193+
ToolbarItem(placement: .cancellationAction) {
194+
Button(Localization.supportCancel) {
195195
showSupport = false
196196
}
197197
}
@@ -258,9 +258,9 @@ private extension PointOfSaleDashboardView {
258258
}
259259

260260
enum Localization {
261-
static let supportDone = NSLocalizedString(
262-
"pointOfSaleDashboard.support.done",
263-
value: "Done",
261+
static let supportCancel = NSLocalizedString(
262+
"pointOfSaleDashboard.support.cancel",
263+
value: "Cancel",
264264
comment: "Button to dismiss the support form from the POS dashboard."
265265
)
266266
}

WooCommerce/Classes/POS/Presentation/PointOfSaleEntryPointView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import protocol Yosemite.PointOfSaleBarcodeScanServiceProtocol
66
struct PointOfSaleEntryPointView: View {
77
@State private var posModel: PointOfSaleAggregateModel?
88
@StateObject private var posModalManager = POSModalManager()
9+
@StateObject private var posSheetManager = POSSheetManager()
910
@State private var posEntryPointController: POSEntryPointController
1011
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
1112

@@ -75,6 +76,7 @@ struct PointOfSaleEntryPointView: View {
7576
barcodeScanService: barcodeScanService)
7677
}
7778
.environmentObject(posModalManager)
79+
.environmentObject(posSheetManager)
7880
.injectKeyboardObserver()
7981
.onAppear {
8082
onPointOfSaleModeActiveStateChange(true)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import SwiftUI
2+
3+
//
4+
// POSSheet - Wraps default SwiftUI .sheet() modifiers to support sheet presentation detection within POS.
5+
//
6+
// Usage: Replace .sheet() with .posSheet() and inject POSSheetManager at the POS root.
7+
// Sheet presentation can be detected via POSSheetManager.isPresented.
8+
//
9+
10+
// MARK: - Sheet Detection Infrastructure
11+
12+
final class POSSheetManager: ObservableObject {
13+
@Published private(set) var isPresented: Bool = false
14+
private var presentedSheets: Set<String> = []
15+
16+
func registerSheetPresented(id: String) {
17+
presentedSheets.insert(id)
18+
updateState()
19+
}
20+
21+
func registerSheetDismissed(id: String) {
22+
presentedSheets.remove(id)
23+
updateState()
24+
}
25+
26+
private func updateState() {
27+
isPresented = !presentedSheets.isEmpty
28+
}
29+
}
30+
31+
// MARK: - Individual Sheet Modifiers
32+
33+
struct POSSheetViewModifier<SheetContent: View>: ViewModifier {
34+
@EnvironmentObject var sheetManager: POSSheetManager
35+
@Binding var isPresented: Bool
36+
let onDismiss: (() -> Void)?
37+
let sheetContent: () -> SheetContent
38+
39+
@State private var sheetId = UUID().uuidString
40+
41+
func body(content: Content) -> some View {
42+
content
43+
.sheet(isPresented: $isPresented, onDismiss: onDismiss, content: sheetContent)
44+
.onChange(of: isPresented) { newValue in
45+
if newValue {
46+
sheetManager.registerSheetPresented(id: sheetId)
47+
} else {
48+
sheetManager.registerSheetDismissed(id: sheetId)
49+
}
50+
}
51+
}
52+
}
53+
54+
struct POSSheetViewModifierForItem<Item: Identifiable & Equatable, SheetContent: View>: ViewModifier {
55+
@EnvironmentObject var sheetManager: POSSheetManager
56+
@Binding var item: Item?
57+
let onDismiss: (() -> Void)?
58+
let sheetContent: (Item) -> SheetContent
59+
60+
@State private var sheetId = UUID().uuidString
61+
62+
func body(content: Content) -> some View {
63+
content
64+
.sheet(item: $item, onDismiss: onDismiss, content: sheetContent)
65+
.onChange(of: item) { newItem in
66+
let newValue = newItem != nil
67+
if newValue {
68+
sheetManager.registerSheetPresented(id: sheetId)
69+
} else {
70+
sheetManager.registerSheetDismissed(id: sheetId)
71+
}
72+
}
73+
}
74+
}
75+
76+
// MARK: - View Modifiers
77+
78+
extension View {
79+
/// Shows a sheet with automatic detection of presentation.
80+
///
81+
/// This works exactly like the native .sheet() modifier but automatically tracks
82+
/// presentation state.
83+
///
84+
/// This will only work in a view hierarchy containing a `POSSheetManager` environment object.
85+
///
86+
/// - Parameters:
87+
/// - isPresented: Binding to control when the sheet is shown.
88+
/// - onDismiss: Optional closure executed when the sheet is dismissed.
89+
/// - content: Content to show in the sheet
90+
/// - Returns: a modified view which can show the sheet content specified, when applicable.
91+
func posSheet<SheetContent: View>(
92+
isPresented: Binding<Bool>,
93+
onDismiss: (() -> Void)? = nil,
94+
@ViewBuilder content: @escaping () -> SheetContent
95+
) -> some View {
96+
self.modifier(
97+
POSSheetViewModifier(
98+
isPresented: isPresented,
99+
onDismiss: onDismiss,
100+
sheetContent: content
101+
)
102+
)
103+
}
104+
105+
/// Shows a sheet with automatic detection of presentation.
106+
///
107+
/// This works exactly like the native .sheet(item:) modifier but automatically tracks
108+
/// presentation state.
109+
///
110+
/// This will only work in a view hierarchy containing a `POSSheetManager` environment object.
111+
///
112+
/// - Parameters:
113+
/// - item: Binding to control when the sheet is shown. When non-nil, the item is used to build the content.
114+
/// - onDismiss: Optional closure executed when the sheet is dismissed.
115+
/// - content: Content to show in the sheet
116+
/// - Returns: a modified view which can show the sheet content specified, when applicable.
117+
func posSheet<Item: Identifiable & Equatable, SheetContent: View>(
118+
item: Binding<Item?>,
119+
onDismiss: (() -> Void)? = nil,
120+
@ViewBuilder content: @escaping (Item) -> SheetContent
121+
) -> some View {
122+
self.modifier(
123+
POSSheetViewModifierForItem(
124+
item: item,
125+
onDismiss: onDismiss,
126+
sheetContent: content
127+
)
128+
)
129+
}
130+
}

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
01695EB82E22600800B731DA /* PointOfSaleBarcodeScannerSetupFlowManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01695EB72E22600300B731DA /* PointOfSaleBarcodeScannerSetupFlowManagerTests.swift */; };
4747
016A77692D9D24B00004FCD6 /* POSCouponCreationSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016A77682D9D24A70004FCD6 /* POSCouponCreationSheet.swift */; };
4848
016C6B972C74AB17000D86FD /* POSConnectivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016C6B962C74AB17000D86FD /* POSConnectivityView.swift */; };
49+
016DE5332E40B03200F53DF7 /* POSSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016DE5322E40B03200F53DF7 /* POSSheet.swift */; };
4950
0174DDBB2CE5FD60005D20CA /* ReceiptEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0174DDBA2CE5FD5D005D20CA /* ReceiptEmailViewModel.swift */; };
5051
0174DDBF2CE600C5005D20CA /* ReceiptEmailViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0174DDBE2CE600C0005D20CA /* ReceiptEmailViewModelTests.swift */; };
5152
0177250C2E1CFF7F00016148 /* GameControllerBarcodeParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0177250B2E1CFF7F00016148 /* GameControllerBarcodeParser.swift */; };
@@ -3227,6 +3228,7 @@
32273228
01695EB72E22600300B731DA /* PointOfSaleBarcodeScannerSetupFlowManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleBarcodeScannerSetupFlowManagerTests.swift; sourceTree = "<group>"; };
32283229
016A77682D9D24A70004FCD6 /* POSCouponCreationSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = POSCouponCreationSheet.swift; sourceTree = "<group>"; };
32293230
016C6B962C74AB17000D86FD /* POSConnectivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = POSConnectivityView.swift; sourceTree = "<group>"; };
3231+
016DE5322E40B03200F53DF7 /* POSSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = POSSheet.swift; sourceTree = "<group>"; };
32303232
0174DDBA2CE5FD5D005D20CA /* ReceiptEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptEmailViewModel.swift; sourceTree = "<group>"; };
32313233
0174DDBE2CE600C0005D20CA /* ReceiptEmailViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptEmailViewModelTests.swift; sourceTree = "<group>"; };
32323234
0177250B2E1CFF7F00016148 /* GameControllerBarcodeParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameControllerBarcodeParser.swift; sourceTree = "<group>"; };
@@ -6427,6 +6429,7 @@
64276429
01620C4C2C5394A400D3EA2F /* Reusable Views */ = {
64286430
isa = PBXGroup;
64296431
children = (
6432+
016DE5322E40B03200F53DF7 /* POSSheet.swift */,
64306433
0210A2452D55EC140054C78D /* Buttons */,
64316434
01620C4D2C5394B200D3EA2F /* POSProgressViewStyle.swift */,
64326435
204D1D612C5A50840064A6BE /* POSModalViewModifier.swift */,
@@ -15213,6 +15216,7 @@
1521315216
26D1E9E82949818B00A7DC62 /* AnalyticsHubTimeRageAdapter.swift in Sources */,
1521415217
CE32B11A20BF8E32006FBCF4 /* UIButton+Helpers.swift in Sources */,
1521515218
02667A1C2AC159A000C77B56 /* GiftCardCodeScannerNavigationView.swift in Sources */,
15219+
016DE5332E40B03200F53DF7 /* POSSheet.swift in Sources */,
1521615220
262562352C52A6410075A8CC /* WooAnalyticsEvent+BackgroudUpdates.swift in Sources */,
1521715221
45BBFBC5274FDCE900213001 /* HubMenu.swift in Sources */,
1521815222
02A9BCD62737F73C00159C79 /* JetpackBenefitItem.swift in Sources */,

0 commit comments

Comments
 (0)