import { DataCaptureViewListener, Color, PrivateLoadableFrameData, DataCaptureView, MarginsWithUnit, NumberWithUnit } from '@scandit/web-datacapture-core'; import { ValidationFlowStateManager } from './ValidationFlowStateManager.js'; import { ValidationFlowView } from './ValidationFlowView.js'; import { LabelCaptureValidationFlowSettings } from '../../LabelCaptureValidationFlowSettings.js'; import { ValidationFlowField } from '../../ValidationFlowField.js'; import { PrivateValidationFlowListener, PrivateValidationFlowHandler } from '../../PrivateValidationFlowHandler.js'; import { V as ValidationFlowState } from '../../../sdcLabelInternalModuleCapture-yM8m0vEc.js'; import { L as LabelCapture } from '../../../LabelCapture-DrHOFOh1.js'; import { LabelCaptureValidationFlowFeedback } from '../../LabelCaptureValidationFlowFeedback.js'; import { TextInputScanEvent, TextInputClearEvent, TextInputFocusEvent, TextInputBlurEvent, TextInputKeydownEvent } from '../../../ui/atoms/TextInput.js'; import { LabelCaptureValidationFlowLayoutEventMap, LabelCaptureValidationFlowLayoutEvents } from '../../../ui/organisms/LabelCaptureValidationFlowLayout.js'; import { KeyboardVisibilityController, KeyboardVisibilityChangedEvent } from '../../../ui/controllers/KeyboardVisibilityController.js'; import { LabelResultUpdateType } from '../../LabelResultUpdateType.js'; import { LabelCaptureValidationFlowListener } from '../LabelCaptureValidationFlowOverlay.js'; import '@scandit/web-datacapture-core/build/js/private/nativeHandle.js'; import '../../LabelField.js'; import '@scandit/web-datacapture-barcode'; import '../../LabelFieldState.js'; import '../../LabelFieldType.js'; import '../../LabelFieldValueType.js'; import '../../LabelDateResult.js'; import '../../../NativeProxy-wKE5sxLq.js'; import '@scandit/web-datacapture-core/build/js/worker/dataCaptureWorkerRelated'; import '../../../djinni-types/sdcBarcodeInternalSdkData.js'; import '../../../djinni-types/sdcBarcodeData.js'; import '../../../djinni-types/sdcCoreCommonGeometry.js'; import '../../../djinni-types/sdcCoreCommonBuffer.js'; import '../../../djinni-types/sdcLabelInternalModuleData.js'; import '../../../djinni-types/sdcLabelData.js'; import '../../../djinni-types/sdcCoreInternalSdkArea.js'; import '../../../djinni-types/sdcCoreInternalSdkCommonGeometry.js'; import '../../../djinni-types/sdcCoreCommonGraphic.js'; import '../../../djinni-types/sdcCoreInternalSdkUiViewfinder.js'; import '../../../djinni-types/sdcCoreInternalSdkCommonGraphics.js'; import '../../../djinni-types/sdcLabelInternalModuleUiOverlay.js'; import '../../../djinni-types/sdcCoreInternalSdkCapture.js'; import '../../../djinni-types/sdcCoreInternalSdkUiStyle.js'; import '../../../djinni-types/sdcSymbologySettings.js'; import '../../../djinni-types/sdcCoreInternalSdkCommonAsync.js'; import '../../../djinni-types/sdcCoreInternalSdkOcr.js'; import '../../../djinni-types/sdcCoreCommon.js'; import '../../AdaptiveRecognitionMode.js'; import '../../CapturedLabel.js'; import '../../LabelCaptureSession.js'; import '../../LabelDateFormat.js'; import '../../LabelDateComponentFormat.js'; import '../../LabelFieldLocationType.js'; import '../../ReceiptScanningLineItem.js'; import '../../LabelCaptureFeedback.js'; import '@scandit/web-datacapture-core/build/js/private/Serializable'; import '../../LabelCaptureSettings.js'; import '../../LabelDefinition.js'; import '../../ImeiOneBarcode.js'; import '../../BarcodeField.js'; import '../../LabelFieldDefinition.js'; import '../../ImeiTwoBarcode.js'; import '../../PackingDateText.js'; import '../../TextField.js'; import '../../PartNumberBarcode.js'; import '../../SerialNumberBarcode.js'; import '../../TotalPriceText.js'; import '../../UnitPriceText.js'; import '../../WeightText.js'; import '../../CustomBarcode.js'; import '../../LabelFieldLocation.js'; import '../../CustomText.js'; import '../../DateText.js'; import '../../ExpiryDateText.js'; import '@scandit/web-datacapture-core/build/js/commons/Color.js'; import '@scandit/web-datacapture-core/build/js/private/utils/index.js'; import '@scandit/web-datacapture-core/build/js/private/ui/atoms/Backdrop.js'; import '../../../ui/atoms/Button.js'; import '@scandit/web-datacapture-core/build/js/private/GestureRecognizer/GestureRecognizer.js'; import '@scandit/web-datacapture-core/build/js/private/Serializable.js'; /** * Convert a margin value to pixels, using the view dimension for Fraction unit. * C++ requires all scan area margins to use the same unit (Pixel), so we always * normalize to pixels before setting adjusted margins. */ declare function convertToPx(margin: NumberWithUnit, dimension: number): number; /** * Normalize all four margins to pixel units using the view dimensions. */ declare function toPixelMargins(margins: MarginsWithUnit, viewWidth: number, viewHeight: number): MarginsWithUnit; /** * Business logic presenter for validation flow. * Handles all business rules and coordination between the view, state manager, and validation handler. * Implements ValidationFlowListenerCallbacks to receive validation flow events from the handler. * * Responsibilities: * - Input initialization and configuration * - Scan icon visibility business rules * - Submit button enablement business rules * - Blur validation orchestration * - Field validation and state updates * - Cloud backup task management * - Layout restoration after validation * - Event handling and UI coordination * - Keyboard visibility management * * This presenter is the coordination hub that brings together state management, view operations, * and validation handler calls to orchestrate the complete validation flow. */ declare class ValidationFlowPresenter implements PrivateValidationFlowListener, DataCaptureViewListener { private stateManager; private settings; private validationFlowHandler; private labelCapture; private feedback; private keyboardController; private _view; private externalListener?; private _latestViewScanAreaMargins; private _isAdjustingScanArea; private dataCaptureView; /** * Getter for the view - exposed for testing purposes */ get view(): ValidationFlowView; private readonly onTextInputScanIconClickHandler; private readonly onTextInputClearIconClickHandler; private readonly onTextInputFocusHandler; private readonly onTextInputBlurHandler; private readonly onTextInputKeydownHandler; private readonly onClearAllButtonClickedHandler; private readonly onSubmitButtonClickedHandler; private readonly onPauseButtonClickedHandler; private readonly onClickedOutsideListHandler; private readonly onValidationFlowLayoutChangeHandler; private readonly onKeyboardVisibilityChangedHandler; constructor(stateManager: ValidationFlowStateManager, settings: LabelCaptureValidationFlowSettings, validationFlowHandler: PrivateValidationFlowHandler, labelCapture: LabelCapture, feedback: LabelCaptureValidationFlowFeedback, view?: ValidationFlowView, keyboardController?: KeyboardVisibilityController); /** * Update the settings reference when applySettings is called on the overlay. * This ensures the presenter always uses the most up-to-date settings. */ updateSettings(settings: LabelCaptureValidationFlowSettings): void; private get camera(); /** * Set dependencies needed for event handling */ /** * Set the external listener for validation flow events. * This should be called before mounting the presenter. */ setExternalListener(listener: LabelCaptureValidationFlowListener): void; /** * Start a complete scan and initialize inputs with validation flow fields. * This method orchestrates the initialization of the validation flow. */ goToCompleteScan(): Promise; resumeScan(): Promise; private resumePreviousScanMode; /** * Initialize inputs from validation flow fields */ initializeInputs(validationFlowFields: ValidationFlowField[]): Promise; /** * Update scan icon visibility for a specific input based on business rules. * Logic: showScanIcon = !scanningState && (isFocused || isEmpty) * * Rules: * - If scanning locally (camera active): ALWAYS hide scan icon * - If NOT scanning locally: * - If field is focused: show scan icon * - If field is NOT focused AND filled: hide scan icon * - If field is NOT focused AND empty: show scan icon */ updateScanIconVisibility(fieldName: string): void; /** * Update scan icon visibility for all inputs */ updateAllScanIconsVisibility(): void; /** * Update submit button enabled/disabled state based on business rule: * Submit button is enabled only when all required fields are filled and valid. */ updateSubmitButtonState(): void; private updateFieldValueAndState; private refocusInputForCorrection; private restoreLayout; /** * Update cloud backup task state for a specific field * @param fieldName - Name of the field * @param mode - 'cancel' to cancel task, 'uncancel' to restore task */ private updateCloudBackupTaskState; /** * Update the cloud backup fields map based on validation flow fields from backend. * Delegates to the state manager which owns the business rule for inclusion. */ private updateCloudBackupFieldsMap; /** * Builds the standard configuration object for updateInputForState calls. * Centralizes the repetitive config to avoid duplication across the codebase. */ getInputStateConfig(options?: { hintMessage?: string; backgroundColor?: Color | string; }): { scanningText: string; adaptiveScanningText: string; hintMessage: string; backgroundColor: Color | string; scanIconVisible: boolean; }; /** * Centralised two-step update: store state in state manager (invariant enforced), * then reflect the stored state in the view. */ private applyInputState; /** * Implementation of ValidationFlowListenerCallbacks.onFieldsScanned * Handles the fields scanned event - updates state and processes fields */ onFieldsScanned(fields: ValidationFlowField[]): Promise; /** * Implementation of ValidationFlowListenerCallbacks.onLabelIsMissingRequiredField * Handles validation error event - updates state and processes fields */ onLabelIsMissingRequiredField(fields: ValidationFlowField[]): Promise; /** * Implementation of ValidationFlowListenerCallbacks.onScanTimeout * Handles scan timeout event */ onScanTimeout(): Promise; /** * Single-pass state sync for all inputs. * * Reads the latest scan results from the state manager (stored by onFieldsScanned). * Callers that don't originate from onFieldsScanned operate with an empty result map, * which matches the previous behavior of passing no scan results. * After processing, scan results are cleared so subsequent calls start clean. * * State resolution priority (per input): * 1. Field has a stored scan result AND non-empty scanned value → Validated / Error / Initial * 2. Scanning active AND field empty → Scanning * 3. Cloud backup active for field AND field empty → CloudBackup * 4. Otherwise → Initial * * The focused-field invariant (focused field never gets Scanning/CloudBackup) is enforced * inside setInputState in ValidationFlowStateManager. */ private syncInputWithState; /** * Implementation of ValidationFlowListenerCallbacks.onManualInput * Handles manual input event from user */ onManualInput(field: ValidationFlowField, oldValue: string | undefined, newValue: string): void; /** * Restore button visibility based on current validation flow state. */ private restoreButtonsBasedOnState; /** * Implementation of ValidationFlowListenerCallbacks.onStateChanged * Handles state changes - updates button visibility and processes state */ onStateChanged(state: ValidationFlowState): Promise; /** * Implementation of ValidationFlowListenerCallbacks.onCloudBackupServiceStarted * Handles cloud backup service started event - updates inputs and processes cloud backup start */ onCloudBackupServiceStarted(): Promise; /** * Implementation of ValidationFlowListenerCallbacks.onCloudBackupServiceStopped * Handles cloud backup service stopped event - resets inputs and processes cloud backup stop */ onCloudBackupServiceStopped(): Promise; /** * Implementation of ValidationFlowListener.onResultUpdate * - ASYNC_STARTED: cloud backup task started — fields carry isProcessingInCloud()=true * (C++ sets this before firing the event). Use them directly to set cloud backup state * rather than calling validationFlowFields() async, which risks a race where the task * has already finished by the time the call returns. * - SYNC: confirmed scanner capture → apply teal background + emit scan feedback * - ASYNC_FINISHED: cloud backup recognition complete → feedback emitted natively via onCloudBackupFeedbackEmit */ onResultUpdate(updateType: LabelResultUpdateType, fields: ValidationFlowField[], frameData?: PrivateLoadableFrameData): Promise; /** * Called when the native C++ layer emits the cloud backup feedback. * This replaces the previous manual emit in onResultUpdate for AsyncFinished. */ onCloudBackupFeedbackEmit(): void; /** * Camera management helpers */ private standByCamera; private activateCamera; /** * Event handler: Text input scan icon clicked */ onTextInputScanIconClick(event: TextInputScanEvent): Promise; /** * Event handler: Text input clear icon clicked */ onTextInputClearIconClick(event: TextInputClearEvent): Promise; /** * Event handler: Text input focused */ onTextInputFocus(event: TextInputFocusEvent): Promise; /** * Event handler: Text input blurred */ onTextInputBlur(event: TextInputBlurEvent): Promise; /** * Orchestrate blur validation for a field. * Directly handles validation, state updates, and layout restoration. * * Flow: * - If field is empty: re-enable cloud backup and restore layout * - If field is not empty: validate field value * - If valid: restore layout * - If invalid: refocus for correction * - Always clear focused input at end * * Returns true if field is valid, false otherwise. */ runBlurValidation(currentInputName: string): Promise; /** * Event handler: Text input keydown (Enter/Escape) */ onTextInputKeydown(event: TextInputKeydownEvent): Promise; /** * Event handler: Keyboard visibility changed */ onKeyboardVisibilityChanged(event: KeyboardVisibilityChangedEvent): Promise; /** * Event handler: Clear all button clicked */ onClearAllButtonClicked(_event: LabelCaptureValidationFlowLayoutEventMap[typeof LabelCaptureValidationFlowLayoutEvents.ClearAllButtonClicked]): Promise; /** * Event handler: Submit button clicked */ onSubmitButtonClicked(): Promise; /** * Event handler: Pause button clicked */ onPauseButtonClicked(_event: LabelCaptureValidationFlowLayoutEventMap[typeof LabelCaptureValidationFlowLayoutEvents.PauseButtonClicked]): Promise; /** * Event handler: Clicked outside list * * If a field is focused the tap will blur it naturally, triggering onTextInputBlur which * owns validation. This handler steps aside in that case. * * If already paused with no focused field, restores the previous scan mode: partial scan * if target fields were recorded, complete scan otherwise. */ onClickedOutsideList(_event: LabelCaptureValidationFlowLayoutEventMap[typeof LabelCaptureValidationFlowLayoutEvents.ClickedOutsideList]): Promise; /** * Event handler: Validation flow layout changed (scan area margins) */ onValidationFlowLayoutChange(event: LabelCaptureValidationFlowLayoutEventMap[typeof LabelCaptureValidationFlowLayoutEvents.ValidationFlowLayoutChange]): void; /** * DataCaptureViewListener: Scan area margins are about to change */ willChangeScanAreaMargins(_view: DataCaptureView, _oldMargins: MarginsWithUnit, newMargins: MarginsWithUnit): void; didChangeScanAreaMargins(_view: DataCaptureView, _margins: MarginsWithUnit): void; /** * Helper: Cancel all cloud backup tasks */ private cancelAllCloudBackupTasks; /** * Helper: Handle in pause scan state */ onPauseStateChanged(): Promise; /** * Helper: Handle in scan state */ onScanStateChanged(): Promise; /** * Mount the validation flow - sets up all event listeners and initializes the view */ mount(dataCaptureView: DataCaptureView): Promise; /** * Unmount the validation flow - removes all event listeners and cleans up */ unmount(dataCaptureView: DataCaptureView): Promise; registerEventListeners(): void; unregisterEventListeners(): void; } export { ValidationFlowPresenter, convertToPx, toPixelMargins };