Phase 6, step 4, chat first as the plan asks. On a window 840dp or wider the home screen is now the room list at a fixed width and the selected conversation filling the rest; on anything narrower it is exactly what it was. **Below expanded is not caution, it is the spec.** The breakpoints page says not to put two dense panes in a medium window, and `calculatePaneScaffoldDirective` in `material3-adaptive` says the same thing in code -- `maxHorizontalPartitions = 1` for compact and medium alike. A chat transcript is precisely the dense content that rule is about. It is also what this app can support. `ChatRoomMessagingRoute` is navigated to from **eleven** places -- a DKG ritual finishing, room-type selection, the npub dialog, a profile -- so the conversation has to remain a pushed destination whatever the window is doing. The list pane is a second way to reach it on a wide window, not a replacement for the first. **Why not `ListDetailPaneScaffold`.** The dependency is available and resolves for every target; the scaffold was not used, and the reason is the paragraph above. It earns its API surface -- a navigator, a destination history, an `AnimatedPane` per pane, three experimental opt-ins -- by owning the single-pane case as well: showing the detail *instead of* the list on a phone and animating between them. This app cannot hand it that, so it would sit permanently in its two-pane state and amount to a `Row` with more words and a history nothing reads. What it does have that is worth keeping is its numbers, and `Panes.kt` takes them: 360dp of list at expanded, 412dp from large upward, 24dp between. A hand-built pair measures the same as the scaffold would. **Three smaller decisions.** The floating action button moves into the list pane when there are two. The `Scaffold`'s slot is the bottom-right of the *window*, which with two panes is on top of the transcript's send button; M3 puts a list-detail layout's primary action in the list pane. It is one composable used from both branches so the two cannot drift. `readableContent()` comes off the pair. Capping two panes together to one column's measure is the opposite of what a second pane is for -- each pane holds its own content instead, and the conversation already did. The detail pane says "Pick a conversation to read it here" rather than being an unexplained empty half of a window, and the conversation is keyed on the room so switching rebuilds its view models rather than feeding a new id to ones already subscribed to another room's relays. **Measured in real windows of the widths the phase names.** 400 and 700 are one pane; 1000 splits with a 360dp list; 1400 splits with a 412dp list. The repositories are the no-op ones with the two reads this screen makes delegated to a fixed answer -- Kotlin's interface delegation makes that ten lines rather than a reimplementation of two large interfaces. Five more unit tests pin the widths against the directive's, including that the detail pane still clears a 40-character line in the narrowest window that allows two of them. 635 jvm tests green; android compiles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This is a Kotlin Multiplatform project targeting Android, iOS, Desktop (JVM).
-
/composeApp is for code that will be shared across your Compose Multiplatform applications. It contains several subfolders:
- commonMain is for code that’s common for all targets.
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name. For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app, the iosMain folder would be the right place for such calls. Similarly, if you want to edit the Desktop (JVM) specific part, the jvmMain folder is the appropriate location.
-
/iosApp contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform, you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
Build and Run Android Application
To build and run the development version of the Android app, use the run configuration from the run widget in your IDE’s toolbar or build it directly from the terminal:
- on macOS/Linux
./gradlew :composeApp:assembleDebug - on Windows
.\gradlew.bat :composeApp:assembleDebug
Build and Run Desktop (JVM) Application
To build and run the development version of the desktop app, use the run configuration from the run widget in your IDE’s toolbar or run it directly from the terminal:
- on macOS/Linux
./gradlew :composeApp:run - on Windows
.\gradlew.bat :composeApp:run
Build and Run iOS Application
To build and run the development version of the iOS app, use the run configuration from the run widget in your IDE’s toolbar or open the /iosApp directory in Xcode and run it from there.
Learn more about Kotlin Multiplatform…