The Flutter half
The renderer, and the window it runs in. Everything else is Nim.
lib/main.dart the entry point: reads FRQ_AUTOCONNECT, then runs the app
lib/nim_renderer.dart the widget tree from Nim, as Flutter widgets
lib/nim_theme.dart the design tokens
test/nim_layout_test.dart every screen laid out for real, at three sizes
What the renderer knows
The tag vocabulary, and nothing else — no screens, no state, no idea what
"connect" means. Nim decides what the screen is; this decides what a vbox
looks like. The measure of whether the split is honest is how boring this file
is: if a feature ever needs a change here AND in Nim, the boundary is in the
wrong place.
Three rules in it are worth knowing before changing any of it, because each
cost a screenful of Cannot hit test a render box that has never been laid out to find:
Expandedonly inside a Flex. The renderer threads the axis it is
building into, because Flutter offers no way to ask after the fact. An
Expandedin aWrapfails the layout, and every box under it is then
hit-tested having never been laid out.- A paragraph is one
RichText, not a row of words. Children of aWrap
are given unbounded width, so a long URL can never wrap — it overflows and
takes the screen with it. expandis stated by the node that expands. A row that fills the
remaining height stretches on its cross axis, and stretch needs a bounded
height to stretch to.
test/nim_layout_test.dart is what enforces all three. It renders every screen
at phone, desktop and a deliberately cramped size, headless, and fails on
anything that reaches FlutterError — which is where a layout error goes
instead of to the caller, so a test that only pumps and asserts on widgets
passes while the screen is in pieces.
Building
just build desktop # the debug bundle
just run desktop # and open it
just test layout # the widget tests, headless
just builds libfrqcore.so first: the app dlopens it at startup, and a
missing one is a blank window with a StateError behind it. The core resolves
OpenSSL through dynlib at run time, which is why the recipe puts the host's
library on the loader path.
What used to be here
src/, 5,500 lines of ClojureDart: the screens, the host implementations, and
a frq.hiccup that did what nim_renderer.dart does now. It compiled to
three targets — Android, Linux and the web — and both of the others went with
it. A browser has no dart:ffi, so the web needs the Nim core built to wasm
rather than ClojureDart brought back; Android needs libfrqcore.so for its
ABIs, which is a build problem rather than a design one.
The android/ and web/ directories are still here and still describe real
targets. Nothing builds them today.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
|