Steps to reproduce
Connect a ScanSnap iX500 (seen on the iX500; the code path is shared by every backend with button support).
In Settings, turn off "Use physical Scan button" and turn it on again.
Press the Scan button on the scanner. A scan runs and is saved.
Press the Scan button again.
Expected behavior: Every press of the Scan button starts a new one-touch scan.
Actual behavior: Only the first press works. After that the button does nothing until hardware-button monitoring is toggled off and on again. A normal scan started from the app also leaves the button unresponsive afterwards.
Root cause: ScannerWorkspaceViewModel.startScan(destinationOverride:) resets its state in defer { activeDevice = nil; isScanning = false } and ends with await restartHardwareMonitoring(). The defer only runs after the function returns, so restartHardwareMonitoring() still sees isScanning == true. Its guard guard hardwareButtonSettings.enabled, !isScanning else { return } then returns early, and HardwareScanCoordinator is never started again. performHardwareScan(for:) restarts monitoring only when the scan fails, so every successful scan leaves the button dead.
Steps to reproduce
Connect a ScanSnap iX500 (seen on the iX500; the code path is shared by every backend with button support).
In Settings, turn off "Use physical Scan button" and turn it on again.
Press the Scan button on the scanner. A scan runs and is saved.
Press the Scan button again.
Expected behavior: Every press of the Scan button starts a new one-touch scan.
Actual behavior: Only the first press works. After that the button does nothing until hardware-button monitoring is toggled off and on again. A normal scan started from the app also leaves the button unresponsive afterwards.
Root cause: ScannerWorkspaceViewModel.startScan(destinationOverride:) resets its state in defer { activeDevice = nil; isScanning = false } and ends with await restartHardwareMonitoring(). The defer only runs after the function returns, so restartHardwareMonitoring() still sees isScanning == true. Its guard guard hardwareButtonSettings.enabled, !isScanning else { return } then returns early, and HardwareScanCoordinator is never started again. performHardwareScan(for:) restarts monitoring only when the scan fails, so every successful scan leaves the button dead.