Aether is a username-based social messenger — not a WhatsApp clone. It fuses Signal-Protocol end-to-end encrypted chat with expressive customizable profiles, Instagram-style stories, Discord-style notes, and Spotify-style music presence — all wrapped in a glassmorphism UI on a pure-AMOLED dark base.
Crafted by (Itz_Me) / KairoCloud
- Highlights
- Feature tour
- Download the APK
- Tech stack
- Architecture
- Getting started
- Building locally
- CI / APK workflow
- Quality gates & conventions
- Security model
- Roadmap & known limitations
- License
🔒 End-to-end encrypted — real Signal Protocol, not a hand-rolled cipher.
🎨 Yours to theme — 8 accent presets + custom hex that re-skins the entire app live.
🎵 Music presence — animated equalizer + album art, on your profile and your notes.
📖 Stories & notes — full-screen viewer and 60-char status notes, both auto-expiring at 24h.
🪟 Glassmorphism — consistent blurred-glass surfaces over a #0A0A0F AMOLED base.
⚡ Realtime — messages, typing, and read receipts arrive without a refresh.
| Area | What you get |
|---|---|
| Messaging | Signal Protocol E2EE · realtime delivery · typing indicators · read receipts (✓ / ✓✓ / blue ✓✓) · reactions, replies, pin, edit, delete · 30-message cursor pagination |
| Voice | Hold-to-record with live waveform + slide-to-cancel · playback with waveform seekbar and 1× / 1.5× / 2× speed |
| Media | Image / video / file sharing with full-screen, zoomable previews |
| Profiles | Parallax banner · avatar with animated music ring · badges · bio · social links · accent color that propagates app-wide |
| Friends | Debounced search with mutual counts · requests · accept / decline / block · privacy-aware visibility |
| Stories | Image & text stories · animated progress bars · tap-to-navigate · hold-to-pause · swipe-to-dismiss · reactions · "seen by" · 24h expiry |
| Notes | 60-char status with optional music · home strip · expand sheet with equalizer |
| Music status | Manual song/artist/art entry · animated equalizer · blurred album-art backdrop |
| Notifications | FCM push + local notifications · presence · unread badges |
CI builds release APKs on every push to main.
- Latest build: open the Build APK workflow → pick the most recent run → download the
aether-apkartifact. - Tagged releases: push a
v*tag (e.g.v1.0.0) and the APKs are attached to a GitHub Release automatically.
The workflow produces per-ABI APKs (
arm64-v8a,armeabi-v7a,x86_64) plus a universal APK. For most modern phones, install the arm64-v8a one.
| Layer | Choice |
|---|---|
| Framework | Flutter (stable, 3.22+) |
| State | flutter_riverpod + riverpod_annotation (codegen) |
| Routing | go_router with auth + profile guards |
| Models | freezed + json_serializable |
| Local DB | isar — Signal stores + decrypted-text cache |
| Backend | Supabase — Postgres · Auth · Realtime · Storage · Edge Functions |
| Encryption | libsignal_protocol_dart |
| Push | firebase_messaging + flutter_local_notifications |
| Audio | just_audio (playback) · record (capture) |
| Fonts | Sora (headings) + DM Sans (body) via google_fonts |
Feature-first Clean Architecture. Every feature owns its data/ (repositories,
datasources), domain/ (entities, repository interfaces), and presentation/
(screens, widgets, Riverpod providers). Shared building blocks live in lib/core/.
lib/
├── core/
│ ├── animations/ transitions + reusable effect configs
│ ├── constants/ colors, sizes, strings, route names
│ ├── db/ Isar collections + service
│ ├── services/ supabase, encryption, media, notifications, storage
│ ├── theme/ AMOLED theme + AetherColors ThemeExtension (accent)
│ ├── utils/ validators, color/hex, debounce, formatters
│ └── widgets/ 14 reusable glassmorphism components
├── models/ Freezed models (AppUser, Message, Story, Note, ...)
├── providers/ global providers (auth, user, theme, preferences)
├── features/ auth · home · chats · friends · profile · social
│ · notifications · settings · media
└── routes/ go_router config + guards
supabase/
├── migrations/ schema · indexes · RLS · RPCs · storage policies (0001–0008)
└── functions/ send-notification · clean-expired (Deno edge functions)
- Flutter SDK 3.22+
- A Supabase project
- (Optional) A Firebase project for push notifications
Run the SQL migrations in supabase/migrations/ in order (0001 → 0008) against your
Supabase project, then deploy the edge functions in supabase/functions/ and set their secrets
(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, and FIREBASE_SERVICE_ACCOUNT for push).
flutter pub get
dart run build_runner build --delete-conflicting-outputsflutter run \
--dart-define=SUPABASE_URL=https://YOUR_PROJECT.supabase.co \
--dart-define=SUPABASE_ANON_KEY=YOUR_ANON_KEYAdd your platform Firebase config (google-services.json / GoogleService-Info.plist and a
generated firebase_options.dart). Without it, notifications are silently disabled and the app
still runs.
# Universal release APK
flutter build apk --release \
--dart-define=SUPABASE_URL=... --dart-define=SUPABASE_ANON_KEY=...
# Smaller, per-architecture APKs
flutter build apk --release --split-per-abi \
--dart-define=SUPABASE_URL=... --dart-define=SUPABASE_ANON_KEY=...Output lands in build/app/outputs/flutter-apk/.
.github/workflows/build-apk.yml runs on every push/PR to main, on v* tags, and on manual
dispatch. Each run:
- sets up Java 17 + Flutter 3.22.2,
- installs deps and runs codegen,
- gates on
dart analyze+flutter test, - builds per-ABI and universal release APKs,
- uploads them as the
aether-apkartifact, and - on a
v*tag (or a manual run with release checked) attaches them to a GitHub Release.
Required repository secrets (Settings → Secrets and variables → Actions):
| Secret | Purpose |
|---|---|
SUPABASE_URL |
Your Supabase project URL |
SUPABASE_ANON_KEY |
Supabase anon/publishable key |
Builds are unsigned (debug-signed) by default. To ship a Play Store build, add a release keystore + signing config and wire it into
android/app/build.gradle.
dart analyze # 0 issues
flutter test # unit tests: models, RPC mappers, validators, hashingEnforced throughout: sound null-safety · @freezed on every model · @riverpod providers ·
constants in lib/core/constants/ · ListView.builder for dynamic lists · 300-line file cap ·
const everywhere allowed · no plaintext logging · no custom crypto.
- Text messages are end-to-end encrypted. Supabase only ever stores ciphertext; the identity
private key never leaves
flutter_secure_storage; decrypted text is cached on-device in Isar (the Signal ratchet only allows decrypting a message once). - Row Level Security is enabled on every table. Cross-table checks (chat membership,
friendship, blocks) go through
SECURITY DEFINERhelper functions to prevent policy recursion. - One-time prekeys are claimed atomically server-side and replenished when low.
- No secrets in source — all credentials are injected via
--dart-define/ CI secrets.
- 📎 Media is not E2E-encrypted — blobs are transport-encrypted (HTTPS + RLS), text is E2EE.
- 👥 1:1 E2EE only — group sender-key encryption is not yet implemented.
- 🟢 Presence has no background teardown — online status is set on app open; a heartbeat / lifecycle teardown is pending.
- 🔔 Push requires Firebase config — disabled gracefully until added.
Proprietary — © KairoCloud. All rights reserved.