Flutter App (~/loklok_radio_app)
A native Android radio app — the premium LOKLOK player built with Flutter and media_kit (mpv). All data comes from the same public HTTP endpoints the PWA uses, so it works from any network with no keys or auth.
- Where (local):
E:\loklok_radio_app - Where (remote build):
/home/sms/loklok_radio_app(build only on the remote — local C: is full, and the remote has JDK 17 +/opt/android-sdk) - Flutter:
3.44.9stable at~/flutteronsms@10.10.8.230 - Artifact:
app-release.apk(debug signing config) — local copy atE:\loklok_radio_app\app-release.apk== remotebuild/app/outputs/flutter-apk/app-release.apk
What it does
| Tab | Content |
|---|---|
| Live | Auto-playing HLS stream, live now-playing card (title/artist/type), animated EQ, listener count pill, play/pause, mute, skip, volume, today's genre-mix chips |
| Up Next | The full on-air rotation (/api/station/state) with per-track crowd votes (/api/upnext) — tap the flame to boost a track |
| Chat | Live room chat + presence avatars via the chat-server long-poll REST API |
| About | Station facts + stream URLs |
Design is a branded dark theme: gradient glass cards, glowing rotating "artwork" orb, animated equalizer bars, and a glass bottom-nav shell.
Code layout
| File | Role |
|---|---|
lib/main.dart | entry: MediaKit.ensureInitialized(), MaterialApp theme, glass 4-tab bottom-nav shell, autoplay on launch |
lib/models.dart | typed parsers for every API (Track, ApiStatus, StationState, UpNextTrack, ChatMessage, MmtxSnapshot) + Pal brand colors + typeBadge() |
lib/services.dart | ApiClient (engine proxy), ChatClient (long-poll), PlayerService (media_kit HLS singleton, ChangeNotifier) |
lib/widgets.dart | reusable premium widgets: EqBars, GlassCard, PlayButton, OrbArtwork, LivePill, PresenceStack, GlowBackground |
lib/screens.dart | HomeScreen / QueueScreen / ChatScreen / AboutScreen |
Public endpoints used (no auth)
- Proxy base
http://files.mediahubnetwork.net:8094—/api/status,/api/station/state,/api/upnext?uid=,/api/upnext/vote,/api/station/skip,/api/chat/{join,heartbeat,messages,history,presence} - Listener proxy
http://files.mediahubnetwork.net:19353/v3/paths/list→loklok.readers.length - Audio
https://api.mediahubnetwork.net/loklok/index.m3u8(HLS — HTTPS, standard port, same-origin cookie flow; since 2026-08-13 the plain-http://:19351URL was dropped because mobile carriers block non-443 traffic and libmpv couldn't persist the MediaMTX cookie on it). OGG fallback:https://files.mediahubnetwork.net/main.
Vote identity is a per-install uid persisted in SharedPreferences
(loklok.voteUid); chat auto-rejoins via stored name/token.
Building
# on sms@10.10.8.230
export PATH="$HOME/flutter/bin:$PATH"
cd ~/loklok_radio_app
flutter pub get
flutter analyze # must be clean
flutter build apk --release
Copy changed sources up with scp lib/*.dart pubspec.yaml sms@10.10.8.230:~/loklok_radio_app/…
then pull the APK back with
scp sms@10.10.8.230:~/loklok_radio_app/build/app/outputs/flutter-apk/app-release.apk .
Flutter gotchas hit in this project
MediaKit.ensureInitialized()returns void — do notawaitit (await_only_futures).PlayerService extends ChangeNotifierrequiresimport 'package:flutter/foundation.dart';.Tweentakes named params (Tween<double>(begin: 0.25, end: 1.0)) — the positional form is gone.- A helper like
c(int hex) => Color(hex)is not const, so it can't appear insideconst LinearGradient(...)/const BoxDecoration(...)— drop theconst. - Android manifest already sets
android:label="LOKLOK FM"andandroid:usesCleartextTraffic="true"(the HLS stream is plain HTTP).