Files
mantra-kmp/composeApp/src/jvmMain/kotlin
Kgothatso Ngako eb191d945a feat(chapters): a chapter can be loaded from a file
Phase 1 of docs/chapter-uploads.md. The picker and the decode, with one file
going into the add-chapter form that already works -- so the platform seam is
exercised on its own, before anything knows about several chapters at once.

Three actuals rather than FileKit. This is the app's only dialog, the calls
are a dozen lines each, and the project already keeps four platform seams of
this shape; the library's Compose-version coupling buys nothing here, and the
ios target cannot be compiled on a linux host either way.

ChapterText.decode is the part that matters. The web app does
`file.data.toString()`, where a .docx becomes a chapter of zip-header garbage
the uploader can go back and delete; here the next thing that happens to the
text is that a quorum signs it. So: strict UTF-8, because a lenient decode
hides U+FFFD inside something permanent; a NUL sniff before decoding, because
mostly-ASCII binary decodes cleanly; the byte-order mark stripped and CRLF
normalised, because both change the bytes without changing a word and the
same prose from two machines has to give the same chunk ids.

The pickers stop one byte past the cap rather than at it, so an over-size
file reads as over-size instead of as a chapter with its ending missing.
Android registers both open contracts so asking for one file does not offer a
picker that returns six. The dialog title is a parameter read from the
catalogue, since stringResource is composable and a FileDialog is not.

ChapterNaming came out of the two answers the web app gives on its two routes
-- the filename on the upload, the first chunk on the paste form -- both of
which are right some of the time. The filename minus extension and ordinal
prefix, falling through to a heading and then the first line, because `01.md`
is not a chapter title and `03 - The Wreck.md` is.

FilePicker.ios.kt is unverified: the ios targets are declared only on macos,
so it is not compiled here. Written to the shape of the eight .ios.kt actuals
beside it and says so in its KDoc. A stub returning no files would read as a
working picker that a reader's chapters vanish into.

22 new tests, all pure; m3Audit's budgets all met.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-02 18:29:20 +02:00
..