Refactor pairing process and enhance camera discovery with model name probing#11
Open
Refactor pairing process and enhance camera discovery with model name probing#11
Conversation
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Outdated
Show resolved
Hide resolved
520fa26 to
0fba0d3
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Outdated
Show resolved
Hide resolved
74d17b2 to
60b6214
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
60b6214 to
9abc3af
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
9abc3af to
57d32cf
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
57d32cf to
82704d5
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Outdated
Show resolved
Hide resolved
82704d5 to
4b21371
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Outdated
Show resolved
Hide resolved
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
4b21371 to
9086995
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
9086995 to
8ed2cec
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
8ed2cec to
8f4387c
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/ScanningContent.kt
Show resolved
Hide resolved
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/ScanningContent.kt
Show resolved
Hide resolved
8f4387c to
e87a3a3
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
Replace the single-step pairing screen with a multi-phase flow that scans for nearby cameras, probes model names over BLE, and guides the user through association, bonding, and connection with per-state UI and clear error handling. Core changes: - Add scanning phase with real-time BLE discovery and concurrent model name probing via GATT device name characteristic - Split monolithic PairingComponents into per-state composables (Scanning, Associating, Bonding, Connecting, Success, Error) backed by a shared PairingStateScaffold - Extend CameraVendor with model name capability and add GATT characteristic UUIDs to Ricoh and Sony vendors - Extract CompanionDeviceManagerHelper interface for testability; target specific MAC addresses during system association - Add cancel buttons to all intermediate pairing states ViewModel improvements: - Replace System.currentTimeMillis() bonding timeout with coroutine withTimeout for virtual-time testability - Inject mainDispatcher to eliminate hardcoded Dispatchers.Main - Consolidate duplicated exception handling in connection logic - Fix probeModelName race condition in job map assignment - Extract shared code from removeBondAndRetry branches UI polish: - Replace Modifier.clickable feedback link with accessible TextButton - Remove redundant model name from device row supporting text - Clean up 13 unused string resources from old pairing flow Test coverage (64 pairing tests, up from 26): - Add PairingScreenTest: 13 Robolectric integration tests for full-screen state rendering, chrome persistence, navigation - Extend PairingViewModelTest to 28 tests covering bonding timeout, navigation events, auto-close timer, error mapping, association edge cases, and feedback content - Extend PairingComponentsTest to 23 tests covering callback invocations, error variants, cancel buttons, scanning pill, and mixed device list rendering - Add FakeCompanionDeviceManagerHelper replacing mockk usage
e87a3a3 to
a9a16a2
Compare
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
app/src/main/kotlin/dev/sebastiano/camerasync/pairing/PairingViewModel.kt
Show resolved
Hide resolved
Replace the single-step pairing screen with a multi-phase flow that scans for nearby cameras, probes model names over BLE, and guides the user through association, bonding, and connection with per-state UI and clear error handling. Core changes: - Add scanning phase with real-time BLE discovery and concurrent model name probing via GATT device name characteristic - Split monolithic PairingComponents into per-state composables (Scanning, Associating, Bonding, Connecting, Success, Error) backed by a shared PairingStateScaffold - Extend CameraVendor with model name capability and add GATT characteristic UUIDs to Ricoh and Sony vendors - Extract CompanionDeviceManagerHelper interface for testability; target specific MAC addresses during system association - Add cancel buttons to all intermediate pairing states ViewModel improvements: - Replace System.currentTimeMillis() bonding timeout with coroutine withTimeout for virtual-time testability - Inject mainDispatcher to eliminate hardcoded Dispatchers.Main - Consolidate duplicated exception handling in connection logic - Fix probeModelName race condition in job map assignment - Extract shared code from removeBondAndRetry branches UI polish: - Replace Modifier.clickable feedback link with accessible TextButton - Remove redundant model name from device row supporting text - Clean up 13 unused string resources from old pairing flow Test coverage (64 pairing tests, up from 26): - Add PairingScreenTest: 13 Robolectric integration tests for full-screen state rendering, chrome persistence, navigation - Extend PairingViewModelTest to 28 tests covering bonding timeout, navigation events, auto-close timer, error mapping, association edge cases, and feedback content - Extend PairingComponentsTest to 23 tests covering callback invocations, error variants, cancel buttons, scanning pill, and mixed device list rendering - Add FakeCompanionDeviceManagerHelper replacing mockk usage
1825a34 to
84a8062
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Redesigns the camera pairing flow from a single-step screen into a multi-phase, state-driven experience with real-time camera discovery, model name probing, and granular user feedback through each step.
What changed
New pairing flow
The pairing screen now walks the user through distinct phases, each with its own UI:
All intermediate states now include a cancel button so the user is never stuck.
Architecture improvements
CompanionDeviceManagerHelperextracted to an interface withAndroidCompanionDeviceManagerHelperimplementation, following the existingBluetoothBondingCheckerpattern.PairingViewModelnow injects bothioDispatcherandmainDispatcher, eliminating hardcodedDispatchers.Mainand making all coroutine timing fully controllable in tests.System.currentTimeMillis()loop withwithTimeout(), enabling virtual-time testing.performPairingConnection, shared tail inremoveBondAndRetry, and disconnect cleanup blocks.probeModelName— job is now stored in the map before the coroutine body can execute.PairingStateScaffoldfor consistent layout across Associating, Bonding, Connecting, and Success states.Vendor changes
CameraVendorgainssupportsModelNamecapability flag andextractModelFromPairingName()for fallback model extraction.RicohGattSpecandSonyGattSpecadd device name characteristic UUIDs for model probing.KableCameraRepositoryandKableCameraConnectionsupportreadModelName()via GATT.Cleanup
PairingComponents.kt(417 lines) — replaced by per-state composables.Spacer(weight)usage.Modifier.clickabletoTextButtonfor proper accessibility.Test coverage
64 pairing tests (up from 26):
PairingViewModelTestinitializePairingfailure, already-paired filtering, feedback contentPairingComponentsTestPairingScreenTestNew test infrastructure:
FakeCompanionDeviceManagerHelperreplacesmockkusageWriteRecorderutility for GATT write verificationAndroidManifest.xmlandTestActivityfor Robolectric Compose testsNote
Medium Risk
Medium risk because it rewires the BLE pairing state machine (scanning/association/bonding/connecting) and adds temporary probe connections, which could affect device discovery timing and pairing reliability across vendors.
Overview
Refactors
PairingScreen/PairingViewModelfrom a single-step flow into a multi-phase, state-driven pairing experience (scanning → associating → bonding → connecting → success/error), with cancel/retry paths and updated strings/UI (new per-state composables + sharedPairingStateScaffold, replacesPairingComponents.kt).Enhances discovery by probing camera model names via temporary GATT connections (bounded concurrency + timeouts), adding
CameraConnection.readModelName()/CameraRepositorysupport and vendor wiring (supportsModelNamecapability + new GATT UUIDs for Ricoh/Sony).Improves DI/testability by introducing dispatcher qualifiers (
@IoDispatcher,@MainDispatcher), extractingCompanionDeviceManagerHelperinto an interface withAndroidCompanionDeviceManagerHelper(optionally targets a specific MAC), and expanding unit/Robolectric + Compose UI test infrastructure (Gradle test deps/options, test manifest/activity, new fakes/utilities).Written by Cursor Bugbot for commit 84a8062. This will update automatically on new commits. Configure here.