Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions Sources/OSBarcodeLib/Models/OSBARCScanParameters.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
public struct OSBARCScanParameters {
/// Text to be displayed on the scanner view.
public let scanInstructions: String

/// Text to be displayed for the scan button, if this is configured. `Nil` value means that the button will not be shown.
public let scanButtonText: String?

// Camera to use for input gathering.
public let cameraDirection: OSBARCCameraModel

// Scanner view's orientation.
public let scanOrientation: OSBARCOrientationModel

// The optional hint, to scan a specific format (e.g. only qr code). `Nil` or `unknown` value means it can scan all.
public let hint: OSBARCScannerHint?


/// Optional accessibility label for the cancel button. `Nil` or empty value uses the library's default.
public let cancelButtonAccessibilityLabel: String?

/// Optional accessibility label for the torch button when the torch is on. `Nil` or empty value uses the library's default.
public let torchButtonOnAccessibilityLabel: String?

/// Optional accessibility label for the torch button when the torch is off. `Nil` or empty value uses the library's default.
public let torchButtonOffAccessibilityLabel: String?

public init(scanInstructions: String,
scanButtonText: String?,
cameraDirection: OSBARCCameraModel,
scanOrientation: OSBARCOrientationModel,
hint: OSBARCScannerHint?) {
hint: OSBARCScannerHint?,
cancelButtonAccessibilityLabel: String? = nil,
torchButtonOnAccessibilityLabel: String? = nil,
torchButtonOffAccessibilityLabel: String? = nil) {
self.scanInstructions = scanInstructions
self.scanButtonText = scanButtonText
self.cameraDirection = cameraDirection
self.scanOrientation = scanOrientation
self.hint = hint
self.cancelButtonAccessibilityLabel = cancelButtonAccessibilityLabel
self.torchButtonOnAccessibilityLabel = torchButtonOnAccessibilityLabel
self.torchButtonOffAccessibilityLabel = torchButtonOffAccessibilityLabel
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ extension View {
}
}

/// Applies an accessibility label only when a non-empty value is provided.
/// When `label` is `nil` or empty the view is left untouched, preserving the default behavior (no label).
/// - Parameter label: The accessibility label to apply, if any.
/// - Returns: Either the original `View` or the `View` with the accessibility label applied.
@ViewBuilder
func accessibilityLabelIfPresent(_ label: String?) -> some View {
if let label = label, !label.isEmpty {
self.accessibility(label: Text(label))
} else {
self
}
}

/// Ignores safe area for different versions of iOS.
/// - Returns: the View ignoring all safe areas.
@ViewBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import SwiftUI
struct OSBARCCancelButton: View {
/// The action performed when the button is clicked.
let action: () -> Void

/// The accessibility label read by screen readers. When `nil` or empty no label is set (default behavior).
let accessibilityText: String?

/// The icon to display..
private let cancelIcon: String = "xmark"
/// The scale to apply to the icon to display.
Expand All @@ -31,5 +33,6 @@ struct OSBARCCancelButton: View {
Circle()
.foregroundStyle(forColour: backgroundColour)
)
.accessibilityLabelIfPresent(accessibilityText)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ struct OSBARCTorchButton: View {
let action: () -> Void
/// Indicates if the feature is enabled or not.
let isOn: Bool

/// The accessibility label read by screen readers when the torch is on. When `nil` or empty no label is set (default behavior).
let onAccessibilityText: String?
/// The accessibility label read by screen readers when the torch is off. When `nil` or empty no label is set (default behavior).
let offAccessibilityText: String?

/// Image name to be shown on the button.
private let imageName: String = "flash"
/// Height and width to use (the button is squared).
Expand All @@ -24,7 +28,9 @@ struct OSBARCTorchButton: View {
private var iconName: String { "\(imageName)\(isOn ? "-selected" : "")" }
/// Calculates the background colour to be used based on the toggle value.
private var backgroundColour: Color { isOn ? selectedBackgroundColour : notSelectedBackgroundColour }

/// Calculates the accessibility label to be used based on the toggle value.
private var accessibilityText: String? { isOn ? onAccessibilityText : offAccessibilityText }

var body: some View {
Button(action: action) {
Image(iconName, bundle: Bundle.imageBundle)
Expand All @@ -40,6 +46,7 @@ struct OSBARCTorchButton: View {
)
}
}
.accessibilityLabelIfPresent(accessibilityText)
}
}

Expand Down
14 changes: 11 additions & 3 deletions Sources/OSBarcodeLib/Scanner/OSBARCScannerBehaviour.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import SwiftUI
final class OSBARCScannerBehaviour: OSBARCCoordinatable, OSBARCScannerProtocol {
/// A publisher value responsible for the resulting scanned value.
@Published private var scanResult: OSBARCScanResult = OSBARCScanResult.empty()

/// The publisher's cancellable instance collector.
private var cancellables: Set<AnyCancellable> = []

Expand All @@ -31,7 +31,12 @@ final class OSBARCScannerBehaviour: OSBARCCoordinatable, OSBARCScannerProtocol {

let buttonText = parameters.scanButtonText ?? "" // not having the button enabled is translated into having an empty text.
let shouldShowButton = !buttonText.isEmpty // if empty text is passed, the button is not enabled on the scanner view


// accessibility labels are optional; when not provided (nil/empty) no label is set, preserving the default behavior.
let cancelAccessibilityLabel = parameters.cancelButtonAccessibilityLabel.flatMap { $0.isEmpty ? nil : $0 }
let torchOnAccessibilityLabel = parameters.torchButtonOnAccessibilityLabel.flatMap { $0.isEmpty ? nil : $0 }
let torchOffAccessibilityLabel = parameters.torchButtonOffAccessibilityLabel.flatMap { $0.isEmpty ? nil : $0 }

let barcodeDecoder = OSBARCCaptureOutputDecoder(
scanResultBinding,
shouldShowButton,
Expand All @@ -49,7 +54,10 @@ final class OSBARCScannerBehaviour: OSBARCCoordinatable, OSBARCScannerProtocol {
instructionsText: parameters.scanInstructions,
buttonText: buttonText,
shouldShowButton: shouldShowButton,
deviceType: UIDevice.current.userInterfaceIdiom.deviceTypeModel
deviceType: UIDevice.current.userInterfaceIdiom.deviceTypeModel,
cancelAccessibilityLabel: cancelAccessibilityLabel,
torchOnAccessibilityLabel: torchOnAccessibilityLabel,
torchOffAccessibilityLabel: torchOffAccessibilityLabel
)
let hostingController = OSBARCScannerViewHostingController(rootView: scannerView, parameters.scanOrientation)
hostingController.modalPresentationStyle = .fullScreen
Expand Down
17 changes: 13 additions & 4 deletions Sources/OSBarcodeLib/Scanner/OSBARCScannerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ struct OSBARCScannerView: View {

/// The type of device being used.
let deviceType: OSBARCDeviceTypeModel


/// Accessibility label for the cancel button. `Nil`/empty means no label is set (default behavior).
let cancelAccessibilityLabel: String?
/// Accessibility label for the torch button when the torch is on. `Nil`/empty means no label is set (default behavior).
let torchOnAccessibilityLabel: String?
/// Accessibility label for the torch button when the torch is off. `Nil`/empty means no label is set (default behavior).
let torchOffAccessibilityLabel: String?

/// Frame of portion of the screen used for scanning.
@State private var scanFrame: CGRect = .zero

Expand All @@ -48,9 +55,9 @@ struct OSBARCScannerView: View {

/// Cancel button.
private var cancelButton: OSBARCCancelButton {
.init {
.init(action: {
scanResult = OSBARCScanResult.empty() // cancelling translates in scanResult being empty.
}
}, accessibilityText: cancelAccessibilityLabel)
}

/// Scanning Instructions Text Field.
Expand Down Expand Up @@ -114,7 +121,9 @@ struct OSBARCScannerView: View {
private var torchButton: OSBARCTorchButton {
.init(action: {
viewModel.isTorchButtonOn.toggle()
}, isOn: viewModel.isTorchButtonOn)
}, isOn: viewModel.isTorchButtonOn,
onAccessibilityText: torchOnAccessibilityLabel,
offAccessibilityText: torchOffAccessibilityLabel)
}

private var zoomSelectorView: OSBARCZoomSelectorView? {
Expand Down
Loading