Create ScanScreen.kt — CameraX + ML Kit
In the code column — ScanScreen.kt. Three parts: (1) request the camera permission at runtime, (2) a CameraX preview via AndroidView, (3) an MlKitAnalyzer that returns the scanned QR and calls onTableScanned(value) — once (the scanned flag). (The real screen also has a decorative instruction overlay — omitted so the mechanics stand out.)
Three environment pieces are needed.
1. Permission and deps in AndroidManifest.xml + build.gradle.kts:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
implementation(libs.androidx.camera.view)
implementation(libs.androidx.camera.mlkit.vision)
implementation(libs.mlkit.barcode.scanning)
2. Navigation — a new Screen.Scan (lesson-4 Nav3), and once a table is scanned we go to the menu:
@Serializable data object Scan : Screen()
entry<Screen.Scan> {
ScanScreen(onTableScanned = { raw ->
tableSession.setTable(raw)
backStack.add(Screen.Menu) // scanned → to the menu
})
}
3. Start at scanning. A logged-in (but not-yet-scanned) user can be routed to Scan — so an order always has a table.
Verify. Generate a test QR with the text table:7 (any online QR generator), and run the app on a real phone (an emulator camera reads QRs poorly):
1. Open Scan → a dialog asks for the camera permission → allow.
2. Point the camera at the QR → the screen jumps to the menu, TableSession = "7".
3. Order → POST /orders with "table_number": "7".
Gotcha (permission). The camera is a runtime permission. If you only put it in the manifest and DON'T request it via
rememberLauncherForActivityResult,checkSelfPermissionreturnsDENIEDand the preview is black — no error, no dialog, just darkness. That's whyScanScreenchecks the permission first and, if it's missing, aLaunchedEffectlaunches the dialog. Remember: manifest + runtime request — both are required.