Kgothatso Ngako 3f78eef1e8 feat: put the chat list beside the conversation, from the expanded breakpoint up
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>
2026-09-08 08:01:16 +02:00
2026-07-05 23:21:02 +02:00
2026-07-28 09:10:20 +02:00
2026-03-24 04:47:19 +02:00
2026-03-23 01:41:39 +02:00
2026-03-23 01:41:39 +02:00
2026-03-23 01:41:39 +02:00

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 thats 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 Apples 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 youre 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 IDEs 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 IDEs 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 IDEs toolbar or open the /iosApp directory in Xcode and run it from there.


Learn more about Kotlin Multiplatform

Description
Mantra as a kotlin multiplatform project
https://mantra.press
Readme 8.2 MiB
Languages
Kotlin 100%