Android app¶
The Android app lives in android/. It is a native app written in
Kotlin with Jetpack Compose and Material 3, and it talks to the
same HTTP API as the web pages. Nothing on the server is specific to it.
How it is built¶
| Part | What it uses |
|---|---|
| Screens | Jetpack Compose, Material 3, Navigation Compose; Plus Jakarta Sans from Google Fonts (downloaded by the phone) |
| Network | OkHttp with a cookie jar that keeps vistilla_session across launches; kotlinx.serialization for JSON |
| Player | Media3 ExoPlayer, with Compose controls of its own (ui/watch/VistillaPlayer.kt) copying the web player's look, through OkHttp, so the session cookie reaches /media/videos/{id} and the redirect to the bucket is followed |
| Images | Coil, on the same OkHttp client |
| Camera | CameraX VideoCapture (Full HD, MP4) |
| Screen | MediaProjection + MediaRecorder (H.264 + AAC) in a foreground service of type mediaProjection |
| Uploads | Uploads (reserve with live: true, 16 MiB parts, poster from MediaMetadataRetriever, complete), kept alive by a dataSync foreground service |
| File | Role |
|---|---|
data/Api.kt |
Every server call, the cookie jar, errors as ApiException(status, message) |
data/Models.kt |
The JSON shapes, as @Serializable classes |
data/Uploads.kt |
The upload queue and its progress (StateFlow<List<Upload>>) |
service/UploadService.kt |
The foreground service and its progress notification |
service/ScreenRecordService.kt |
Screen capture (MediaProjection + MediaRecorder); with the camera, a CameraX bubble in an overlay window (SYSTEM_ALERT_WINDOW, foreground type camera) that the capture records with the screen |
ui/MainActivity.kt |
Navigation, the signed-in state (AppModel), links and shared videos |
ui/library, ui/watch, ui/record, ui/settings, ui/notifications, ui/auth |
The screens |
ui/theme, ui/components |
Colours, type, the glowing background, cards, the progress ring, avatars |
res/drawable/logo.xml, ic_launcher_*.xml, ic_splash.xml |
The logo as vectors, redrawn from web/assets/logo.svg: whole on the sign-in screen and the splash screen, and split into the light tile (background) and the screen with its bar (foreground, inside the 66 dp safe circle) for the launcher icon, with a one-colour version for themed icons |
Building¶
- It needs JDK 17 or newer and the Android SDK (platform 36), with
sdk.dirinandroid/local.properties. - The release is signed with
android/keystore/vistilla-release.jks, described byandroid/keystore/keystore.properties. Both are kept out of git; a new version must be signed with the same key to install over the old one. Without them the build falls back to the debug key. - The APK the site offers is
web/assets/app/vistilla.apk: copyapp/build/outputs/apk/release/app-release.apkthere and raiseversionCodeinapp/build.gradle.ktsfor each new one. web/assets/app/version.json(versionCode,versionName,notes) says which version that is. The app (data/Updates.kt) reads it when the library opens; a higherversionCodethan its own shows the Update card, which downloads the APK into the cache and opens the installer through aFileProvider(REQUEST_INSTALL_PACKAGES).- The website's Get the Android app button (
web/assets/apk.js, under the sign-in card and at the foot of the library's rail) reads the same file: it showsversionNameand the APK's size (bytes, whichscripts/worker-site.shadds from the file itself) and linksvistilla.apk?v=<versionCode>, so it always gives the newest APK with no change of its own when a version ships. - Shrinking (R8) and release lint are off: they need more memory than the build machine has.
Languages¶
The app is written in English and shown in English or Arabic. Every screen
imports ui/i18n/Text.kt's Text instead of Material's, which passes its
words through I18n.tr: the same list as the website
(web/assets/i18n/ar.json, packed as an asset by sourceSets.main.assets),
whole strings by exact match and text built from parts by its patterns. In
Arabic, VistillaTheme turns the layout right to left
(LocalLayoutDirection) and sets the type in Cairo (a Google Font fetched by
the phone). The choice is kept on the phone (LanguageSwitch, in Settings
and on the sign-in screen); until made, the phone's language decides. Styled
text (AnnotatedString: comments, transcripts) is people's own words and is
never translated.