Code

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, checkSelfPermission returns DENIED and the preview is black — no error, no dialog, just darkness. That's why ScanScreen checks the permission first and, if it's missing, a LaunchedEffect launches the dialog. Remember: manifest + runtime request — both are required.