feat(android): app nativa Kotlin/Compose (login, rooms, chat)

App Android Material 3, tema oscuro con acento índigo/violeta que replica el
look & feel de la app web (web/src):

- Login: identidad + contraseña, candado de marca, estilo Card.
- Lista de rooms: avatar+handle, buscador rooms/usuarios/mensajes, items con
  candado (E2E) / hash (cleartext), hora, último mensaje y badge de no leídos.
- Chat estilo Element: avatar+nombre+hora+texto, composer redondeado con send.

Arquitectura por capas: UnibusRepository aísla la UI de la fuente de datos.
MockUnibusRepository (en memoria) alimenta la iteración de diseño;
BindingUnibusRepository implementa la misma interfaz sobre el binding gomobile
(unibus.aar) para conectar el bus real sin tocar las pantallas. AppViewModel
orquesta el estado; navegación por estado (login -> rooms -> chat), KISS.

Build: ./gradlew assembleDebug (AGP 8.5.2, Gradle 8.7, Kotlin 1.9.24,
Compose BOM 2024.06.00, compileSdk 34, minSdk 21). El .aar se regenera con
mobile/gen_aar.sh (no se versiona, 38MB).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 18:16:23 +02:00
parent f92973f5fe
commit 5af945778b
30 changed files with 1735 additions and 0 deletions
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<!-- Material "lock" glyph, white, centered in the adaptive-icon safe zone.
24dp source scaled x3 (=72dp) and translated by 18 to center it. -->
<group
android:scaleX="3"
android:scaleY="3"
android:translateX="18"
android:translateY="18">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2H9V6z" />
</group>
</vector>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/unibus_brand" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/unibus_brand" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- dark.9 — app background -->
<color name="unibus_bg">#101113</color>
<!-- brand.5 — índigo/violeta accent, used as launcher icon background -->
<color name="unibus_brand">#5A2FE2</color>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">unibus</string>
</resources>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Compose-only host theme: no action bar, dark window background matching
the app's dark.9 surface so there is no white flash before Compose draws. -->
<style name="Theme.Unibus" parent="android:Theme.Material.NoActionBar">
<item name="android:windowBackground">@color/unibus_bg</item>
<item name="android:statusBarColor">@color/unibus_bg</item>
<item name="android:navigationBarColor">@color/unibus_bg</item>
<item name="android:windowLightStatusBar">false</item>
</style>
</resources>