-
Notifications
You must be signed in to change notification settings - Fork 121
[POS Settings] Hardware section navigation #16038
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bcc710d
afca6d8
f319193
173141a
4ba6abd
3608e36
2098428
9fdcf36
7af11a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,17 @@ | ||
| import SwiftUI | ||
| import enum Yosemite.AppSettingsAction | ||
|
|
||
| struct PointOfSaleSettingsHardwareDetailView: View { | ||
| @State private var navigationPath: [PointOfSaleSettingsView.HardwareDestination] = [] | ||
| @State private var navigationPath: [NavigationDestination] = [] | ||
| @State private var lastKnownLoadedCardReader: String? | ||
| @State private var showBarcodeScanningSetupModal: Bool = false | ||
| @State private var showBarcodeScanningDocumentationModal: Bool = false | ||
| @State private var showCardReaderDocumentationModal: Bool = false | ||
|
|
||
| var body: some View { | ||
| NavigationStack(path: $navigationPath) { | ||
| List(PointOfSaleSettingsView.HardwareDestination.allCases) { destination in | ||
| NavigationLink(value: destination) { | ||
| List(HardwareDestination.allCases) { destination in | ||
| NavigationLink(value: NavigationDestination.hardware(destination)) { | ||
| HStack(alignment: .firstTextBaseline) { | ||
| Image(systemName: destination.icon) | ||
| .font(.posBodyLargeRegular()) | ||
|
|
@@ -20,19 +25,295 @@ struct PointOfSaleSettingsHardwareDetailView: View { | |
| } | ||
| } | ||
| } | ||
| .navigationDestination(for: PointOfSaleSettingsView.HardwareDestination.self) { destination in | ||
| VStack(spacing: POSSpacing.medium) { | ||
| Image(systemName: destination.icon).font(.largeTitle) | ||
| .navigationDestination(for: NavigationDestination.self) { destination in | ||
| switch destination { | ||
| case .hardware(.cardReaders): | ||
| cardReadersView | ||
| case .hardware(.scanners): | ||
| scannersView | ||
| } | ||
| } | ||
| .posModal(isPresented: $showBarcodeScanningSetupModal) { | ||
| PointOfSaleBarcodeScannerSetup(isPresented: $showBarcodeScanningSetupModal) | ||
| } | ||
| .posFullScreenCover(isPresented: $showBarcodeScanningDocumentationModal) { | ||
| SafariView(url: WooConstants.URLs.pointOfSaleDocumentation.asURL()) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private func handleScannerDestination(_ destination: ScannerDestination) { | ||
| switch destination { | ||
| case .setup: | ||
| showBarcodeScanningSetupModal = true | ||
| case .documentation: | ||
| showBarcodeScanningDocumentationModal = true | ||
| } | ||
| } | ||
|
|
||
| private var cardReadersView: some View { | ||
| VStack(spacing: POSSpacing.large) { | ||
| VStack(spacing: POSSpacing.medium) { | ||
| VStack(spacing: POSPadding.small) { | ||
| Text(Localization.cardReadersDescription) | ||
| .font(.posBodyLargeRegular()) | ||
| Text("\(destination.title) settings") | ||
| .multilineTextAlignment(.center) | ||
| Text(Localization.cardReadersSubtitle1) | ||
| .font(.posBodyMediumRegular()) | ||
| .foregroundStyle(.secondary) | ||
| .multilineTextAlignment(.center) | ||
| Text(Localization.cardReadersSubtitle2) | ||
| .font(.posBodyMediumRegular()) | ||
| Text("Some placeholder") | ||
| .foregroundStyle(.secondary) | ||
| .multilineTextAlignment(.center) | ||
| Text(Localization.cardReadersSubtitle3) | ||
| .font(.posBodyMediumRegular()) | ||
| .foregroundStyle(.secondary) | ||
| .multilineTextAlignment(.center) | ||
| } | ||
| } | ||
| .padding() | ||
|
|
||
| if let lastKnownLoadedCardReader { | ||
| HStack { | ||
| Text("Model: \(lastKnownLoadedCardReader)") | ||
| .font(.posBodyMediumRegular()) | ||
| .foregroundStyle(.secondary) | ||
| .multilineTextAlignment(.center) | ||
| } | ||
| } | ||
|
|
||
| List { | ||
| Button { | ||
| showCardReaderDocumentationModal = true | ||
| } label: { | ||
| HStack(alignment: .firstTextBaseline) { | ||
| Image(systemName: "doc.text") | ||
| .font(.posBodyLargeRegular()) | ||
| VStack(alignment: .leading, spacing: POSPadding.xSmall) { | ||
| Text(Localization.cardReaderDocumentationTitle) | ||
| .font(.posBodyLargeRegular()) | ||
| Text(Localization.cardReaderDocumentationSubtitle) | ||
| .font(.posBodyMediumRegular()) | ||
| .foregroundStyle(.secondary) | ||
| } | ||
| } | ||
| } | ||
| .buttonStyle(.plain) | ||
| } | ||
| } | ||
| .navigationTitle(Localization.cardReadersTitle) | ||
| .posFullScreenCover(isPresented: $showCardReaderDocumentationModal) { | ||
| SafariView(url: WooConstants.URLs.inPersonPaymentsLearnMoreWCPay.asURL()) | ||
| } | ||
| .task { @MainActor in | ||
| // TODO: WOOMOB-1172 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is temporary, most likely we'll fetch card reader information from passing in either a reference to the aggregate model or expose its card reader details.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Yes, the aggregate model works. If we think that this state sharing in an aggregate model is not needed, and we only need information within this view, we could rely on a separate view model for this view that fetches information. I had the same question for orders, and at least for order it felt like it made sense to have something separate and there was no value putting information within the aggregate model.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Jinx! I just had the same question when reviewing your PR :D I also think that in this case, for settings, it makes more sense to go through the aggregate, as we'll deal with settings across different features that are part of such aggregate, but we'll see what fits better 👍
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I agree. 👍 |
||
| let action = AppSettingsAction.loadCardReader { reader in | ||
| switch reader { | ||
| case let .success(foundReader): | ||
| lastKnownLoadedCardReader = foundReader | ||
| case let .failure(error): | ||
| debugPrint(error) | ||
| } | ||
| .padding() | ||
| .navigationTitle(destination.title) | ||
| } | ||
| ServiceLocator.stores.dispatch(action) | ||
| } | ||
| } | ||
|
|
||
| private var scannersView: some View { | ||
| List(ScannerDestination.allCases) { destination in | ||
| Button { | ||
| handleScannerDestination(destination) | ||
| } label: { | ||
| HStack(alignment: .firstTextBaseline) { | ||
| Image(systemName: destination.icon) | ||
| .font(.posBodyLargeRegular()) | ||
| VStack(alignment: .leading, spacing: POSPadding.xSmall) { | ||
| Text(destination.title) | ||
| .font(.posBodyLargeRegular()) | ||
| Text(destination.subtitle) | ||
| .font(.posBodyMediumRegular()) | ||
| .foregroundStyle(.secondary) | ||
| } | ||
| } | ||
| } | ||
| .buttonStyle(.plain) | ||
| } | ||
| .navigationTitle(Localization.scannersTitle) | ||
| } | ||
|
|
||
| } | ||
|
|
||
| extension PointOfSaleSettingsHardwareDetailView { | ||
| enum HardwareDestination: Identifiable, CaseIterable { | ||
| case cardReaders | ||
| case scanners | ||
|
|
||
| var id: Self { self } | ||
|
|
||
| var title: String { | ||
| switch self { | ||
| case .cardReaders: | ||
| return Localization.hardwareNavigationCardReaderTitle | ||
| case .scanners: | ||
| return Localization.hardwareNavigationBarcodeTitle | ||
| } | ||
| } | ||
|
|
||
| var subtitle: String { | ||
| switch self { | ||
| case .cardReaders: | ||
| return Localization.hardwareNavigationCardReaderSubtitle | ||
| case .scanners: | ||
| return Localization.hardwareNavigationBarcodeSubtitle | ||
| } | ||
| } | ||
|
|
||
| var icon: String { | ||
| switch self { | ||
| case .cardReaders: | ||
| return "creditcard" | ||
| case .scanners: | ||
| return "qrcode.viewfinder" | ||
| } | ||
| } | ||
| } | ||
|
|
||
| enum NavigationDestination: Hashable { | ||
| case hardware(HardwareDestination) | ||
| } | ||
|
|
||
| enum ScannerDestination: Identifiable, CaseIterable { | ||
| case setup | ||
| case documentation | ||
|
|
||
| var id: Self { self } | ||
|
|
||
| var title: String { | ||
| switch self { | ||
| case .setup: | ||
| return Localization.scannerSetupTitle | ||
| case .documentation: | ||
| return Localization.scannerDocumentationTitle | ||
| } | ||
| } | ||
|
|
||
| var subtitle: String { | ||
| switch self { | ||
| case .setup: | ||
| return Localization.scannerSetupSubtitle | ||
| case .documentation: | ||
| return Localization.scannerDocumentationSubtitle | ||
| } | ||
| } | ||
|
|
||
| var icon: String { | ||
| switch self { | ||
| case .setup: | ||
| return "gearshape" | ||
| case .documentation: | ||
| return "doc.text" | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private extension PointOfSaleSettingsHardwareDetailView { | ||
| enum Localization { | ||
| static let cardReadersTitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.cardReadersTitle", | ||
| value: "Card readers", | ||
| comment: "Navigation title for card readers settings in Point of Sale." | ||
| ) | ||
|
|
||
| static let scannersTitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.scannersTitle", | ||
| value: "Barcode scanners", | ||
| comment: "Navigation title for barcode scanners settings in Point of Sale." | ||
| ) | ||
|
|
||
| static let scannerSetupTitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.scannerSetupTitle", | ||
| value: "Scanner Setup", | ||
| comment: "Title for scanner setup option in barcode scanners settings in Point of Sale." | ||
| ) | ||
|
|
||
| static let scannerSetupSubtitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.scannerSetupSubtitle", | ||
| value: "Configure and test your barcode scanner", | ||
| comment: "Subtitle describing scanner setup in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let scannerDocumentationTitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.scannerDocumentationTitle", | ||
| value: "Documentation", | ||
| comment: "Title for barcode scanner documentation option in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let scannerDocumentationSubtitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.scannerDocumentationSubtitle", | ||
| value: "Learn more about barcode scanning in POS", | ||
| comment: "Subtitle describing barcode scanner documentation in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let cardReadersDescription = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.cardReadersDescription", | ||
| value: "Accept secure and fast payments in person", | ||
| comment: "Main description for card readers functionality in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let cardReadersSubtitle1 = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.cardReadersSubtitle.1", | ||
| value: "Make sure the card reader is charged", | ||
| comment: "Subtitle describing card reader connection in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let cardReadersSubtitle2 = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.cardReadersSubtitle.2", | ||
| value: "Turn the card reader on, and place it next to the mobile device", | ||
| comment: "Subtitle describing card reader connection in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let cardReadersSubtitle3 = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.cardReadersSubtitle.3", | ||
| value: "Turn the mobile device bluetooth on", | ||
| comment: "Subtitle describing card reader connection in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let cardReaderDocumentationTitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.cardReaderDocumentationTitle", | ||
| value: "Documentation", | ||
| comment: "Title for card reader documentation option in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let cardReaderDocumentationSubtitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.cardReaderDocumentationSubtitle", | ||
| value: "Learn more about accepting mobile payments", | ||
| comment: "Subtitle describing card reader documentation in Point of Sale settings." | ||
| ) | ||
|
|
||
| static let hardwareNavigationBarcodeTitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.hardwareNavigationBarcodeTitle", | ||
| value: "Barcode scanners", | ||
| comment: "Navigation title of Barcode scanner settings." | ||
| ) | ||
|
|
||
| static let hardwareNavigationCardReaderTitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.hardwareNavigationCardReaderTitle", | ||
| value: "Card readers", | ||
| comment: "Navigation title of Card reader settings." | ||
| ) | ||
|
|
||
| static let hardwareNavigationCardReaderSubtitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.hardwareNavigationCardReaderSubtitle", | ||
| value: "Manage card reader connections", | ||
| comment: "Description of Card reader settings for connections." | ||
| ) | ||
|
|
||
| static let hardwareNavigationBarcodeSubtitle = NSLocalizedString( | ||
| "pointOfSaleSettingsHardwareDetailView.hardwareNavigationBarcodeSubtitle", | ||
| value: "Configure barcode scanner settings", | ||
| comment: "Description of Barcode scanner settings configuration." | ||
| ) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a broader conversation, I think the fact that "< Back" button is displayed within the details view, the "X" (Close) should be presented within the the list view.
And we likely need to use
POSPageHeaderViewand not the native navigation bar, and of course, not both. As I understand, we leave this for later 👍There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's something I'm precisely discussing today, as Android currently does not show a header across the full view (separates list and detail view), nor
Xto close the view that I can see. Neither this has been provided in the initial design drafts p1756257438170999?thread_ts=1755784099.956039&cid=C070SJRA8DP-slack-C070SJRA8DPI think could even make sense to get the "Help" card up with the rest, and take that bottom-left position to go back to the dashboard, let's see what design thinks 👍