LambentEx Android client
Native Android client for LambentEx. Everything it does goes over the
Phoenix channels at /socket — there is no REST API and nothing to log into.
See ../docs/socket.md for the protocol.
Sister app to ../../waxx/android in shape, not in dress: same Kotlin/Compose
shell, but the palette and font come from this app’s own web UI rather than the
shared Casabeza set.
Stack
| Layer | Choice |
|---|---|
| Language / UI | Kotlin 2.0 · Jetpack Compose · Material 3 |
| Transport | com.github.dsrees:JavaPhoenixClient (0.3.4, via jitpack) |
| Storage | SharedPreferences — a LAN address, no credential |
| Scanner | com.journeyapps:zxing-android-embedded (ScanContract) |
| Build | Gradle 9.0 · AGP 8.5.2 · JDK 17 |
| minSdk | 26 (Android 8) · targetSdk 34 |
Single activity, single module, no DI, no ViewModels — LambentSocket is an
object holding one socket and a StateFlow per channel, and the screens
collect it. The server publishes whole state on a timer, so every screen is a
reducer over pushes exactly like its LiveView is.
Layout
android/
app/src/main/
java/org/neiam/lambent/app/
MainActivity.kt # connect gate, tabs, snackbar for notices
data/
LambentSocket.kt # the socket, four channels, all commands
Models.kt # Device / Machine / Link / Service + parsing
BaseUrlStore.kt # where the box lives
ui/
ConnectScreen.kt # QR scan or type an address
DevicesScreen.kt # rename / place / order / poke / find-by-IP
MachinesScreen.kt # speed, brightness, persist, quit, previews, library
LinksScreen.kt # toggle / persist / quit, create with channel
ServicesScreen.kt # list + delete, and forget-this-box
theme/ # the afterdark palette and TF2 Build
res/font/tf2build.ttf # converted from assets/css/fonts/TF2Build.woff
Theme
ui/theme/Theme.kt is the web UI’s daisyUI afterdark theme from
assets/tailwind.config.js, mapped onto a Material 3 darkColorScheme —
primary #7B79B5, accent #fef3c7, base #201D65 on a #38357F background.
There is only the one scheme, because the web app is dark-only; honouring the
system light mode would mean inventing a palette that doesn’t exist.
ui/theme/Typography.kt uses TF2 Build, the same face the web UI loads for
font-build. It’s a display font there — titles and nav only — so it stays on
the display/headline/title slots and the platform sans carries body copy. The
TTF was converted from the shipped .woff with fontTools; to regenerate:
python3 -c "from fontTools.ttLib import TTFont; f=TTFont('assets/css/fonts/TF2Build.woff'); f.flavor=None; f.save('android/app/src/main/res/font/tf2build.ttf')"
Building
Needs an Android SDK and JDK 17 — AGP 8.5.2 does not run on JDK 22+, so
point JAVA_HOME at 17 (or use Android Studio’s bundled JDK) even if a newer
one is your default.
cd android
./gradlew :app:assembleDebug
./gradlew :app:installDebug # or: adb install -r app/build/outputs/apk/debug/app-debug.apk
Connecting
Open the ⬛ QR icon in the web UI (top right of any page) and scan it, or type
the address by hand — a bare 172.16.13.5 is fine, port 8033 is assumed and
http:// is not coerced to https, because this is a LAN box with no
certificate. The address is remembered; Services → Forget this box clears
it.
Cleartext HTTP is enabled in the manifest for the same reason.
Not shipped
- Creating custom machines. The library sheet starts a machine from a
library entry; the full machine form is a polymorphic embed per machine type
and would be a screen of its own. The
createcommand on the channel already accepts the same params the web form posts. - Bulk links.
LambentSocket.createLinksspeaks thecreate_bulkcommand, but no screen calls it yet. - Creating services. Not offered by the web UI either — those three form components are still stubs.