WAVORA is a production-grade, offline-first Android music player built to demonstrate clean architecture, modern Android engineering, and attention to every detail β from battery-aware ExoPlayer buffers to TalkBack-ready semantic modifiers.
No subscriptions. No accounts. No internet required. Your music, your device, your privacy.
| Category | Feature | Status |
|---|---|---|
| Library | Songs, Albums, Artists, Folders, Playlists | β |
| Playback | ExoPlayer + MediaSession + ForegroundService | β |
| Controls | Background notification, Bluetooth, lock screen | β |
| Queue | Add / remove / drag-reorder, persist across kills | β |
| Playlists | Create / rename / delete / reorder songs | β |
| Smart Playlists | Most Played, Recently Played, Recently Added, Favourites | β |
| Search | FTS4 full-text search across songs, albums, artists | β |
| Now Playing | Album art with palette gradient, seek bar, favourite | β |
| Equalizer | 5-band EQ with 10 presets (Android AudioEffect) | β |
| Lyrics | Animated panel, LRC sync ready (Phase 9 full impl) | β |
| Sleep Timer | 5β60 min options, active countdown display | β |
| Settings | Dark/dynamic theme, gapless, crossfade, skip duration | β |
| Performance | Battery-aware buffers, Coil cache tuning, scan throttle | β |
| Accessibility | Full TalkBack support with semantic modifiers | β |
| Onboarding | Animated first-launch permission flow | β |
| Tool | Version |
|---|---|
| Android Studio | Hedgehog (2023.1.1) or newer |
| JDK | 17 (Temurin recommended) |
| Android SDK | API 34 |
| Gradle | 8.x (wrapper included) |
Min SDK: Android 8.0 (API 26)
Target SDK: Android 14 (API 34)
# Clone
git clone https://github.com/muhamedamin308/wavora.git
cd wavora
# Build debug APK
./gradlew assembleDebug
# Install on connected device
./gradlew installDebug
# Run unit tests
./gradlew test
# Run instrumented tests (requires emulator/device)
./gradlew connectedAndroidTestThe debug APK is placed at app/build/outputs/apk/debug/app-debug.apk.
WAVORA follows MVVM + Clean Architecture with strict layer separation:
UI Layer (Compose)
β uiState: StateFlow<UiState>
β events: Flow<Event>
ViewModel (BaseViewModel)
β suspend / Flow calls
Repository Interface (domain)
β
Repository Implementation (data)
βββ Room Database (single source of truth)
βββ MediaStore API (device music discovery)
βββ DataStore (user preferences)
See ARCHITECTURE.md for a detailed breakdown of every layer, key design decisions, and the reasoning behind them.
app/src/main/java/com/wavora/app/
βββ core/
β βββ base/ BaseViewModel, AsyncResult
β βββ performance/ BatteryAwareBufferConfig, CoilImageCacheConfig, ScanThrottleManager
β βββ util/ Extensions, Constants
βββ data/
β βββ local/
β β βββ dao/ SongDao, AlbumDao, ArtistDao, PlaylistDao, PlayHistoryDao, QueueDao
β β βββ entity/ Room entities with FTS4 shadow table
β βββ mediastore/ MediaStoreScanner
β βββ preferences/ UserPreferencesRepositoryImpl (DataStore)
β βββ repository/ MusicRepositoryImpl, PlaylistRepositoryImpl, PlayerRepositoryImpl
βββ di/ AppModule, DatabaseModule, PlayerModule, PreferencesModule, WorkerModule
βββ domain/
β βββ model/ Song, Album, Artist, Playlist, PlayerState, UserPreferences
β βββ repository/ Repository interfaces (contracts)
βββ navigation/ WavoraNavHost, WavoraRoutes
βββ player/
β βββ notification/ WavoraNotificationManager (Media3 PlayerNotificationManager)
β βββ queue/ QueueManager (pure Kotlin, Fisher-Yates shuffle)
β βββ service/ WavoraPlaybackService (MediaSessionService + ExoPlayer)
β AudioFocusManager (ducking, BECOME_NOISY)
βββ ui/
β βββ album/ AlbumDetailScreen + ViewModel
β βββ artist/ ArtistDetailScreen + ViewModel
β βββ components/ MiniPlayer, SleepTimerSheet, LyricsPanel, Accessibility, Dialogs
β βββ equalizer/ EqualizerScreen + ViewModel (Android AudioEffect)
β βββ folder/ FolderDetailScreen + ViewModel
β βββ library/ LibraryScreen + LibraryViewModel (5-tab pager)
β βββ onboarding/ OnboardingScreen (first-launch permission flow)
β βββ player/ NowPlayingScreen + PlayerViewModel
β βββ playlist/ PlaylistScreen + PlaylistViewModel
β βββ queue/ QueueScreen + QueueViewModel (drag-reorder)
β βββ search/ SearchScreen + SearchViewModel (debounced FTS4)
β βββ settings/ SettingsScreen + SettingsViewModel (DataStore)
β βββ smartplaylist/ SmartPlaylistScreen + ViewModel (4 auto-playlists)
β βββ theme/ Color, Shape, Type, WavoraTheme (OLED dark + Material You)
βββ worker/ LibraryScanWorker (@HiltWorker, WorkManager)
| Layer | Technology | Reason |
|---|---|---|
| UI | Jetpack Compose + Material 3 | Declarative, type-safe, single toolkit |
| Navigation | Navigation Compose | Type-safe routes, back stack management |
| Playback | Media3 / ExoPlayer | Hardware decode, MediaSession, Auto/WearOS |
| Background | MediaSessionService | Foreground service lifecycle managed by Media3 |
| Database | Room + SQLite | FTS4 for search, strict migrations, type-safe DAOs |
| DI | Hilt (Dagger 2) | Compile-time verified, scoped lifetimes |
| Async | Coroutines + Flow | Structured concurrency, reactive UI |
| Images | Coil 2 | Compose-native, disk + memory cache, RGB_565 |
| Preferences | DataStore (Preferences) | Async, crash-safe, replaces SharedPreferences |
| Background jobs | WorkManager | Doze-mode safe, battery constraints |
| Build | Gradle KTS + Version Catalogs | Type-safe, single source of truth for versions |
- Adaptive ExoPlayer buffers β 50s generous (charging) vs 8s conservative (battery saver / < 20%)
- Coil cache β 15% heap (vs default 25%), 100 MB disk,
allowRgb565(true)for 50% RAM reduction - Scan throttle β 15-minute cooldown prevents MediaStore burst scans
- WorkManager constraints β periodic scans only on
BATTERY_NOT_LOW + STORAGE_NOT_LOW - Log stripping β
android.util.Log.v/d/iremoved from release via R8assumenosideeffects - R8 full mode β enabled in
gradle.propertiesfor maximal dead-code removal
220 unit tests (JVM, zero Android dependencies)
32 instrumented (Room in-memory, Android JUnit4)
βββββββββββββββββββ
252 total
./gradlew test # unit tests, HTML report at app/build/reports/tests/
./gradlew connectedAndroidTest # instrumented (Room DAO integration tests)
./gradlew koverXmlReport # code coverage (add Kover plugin for full report)Key test areas: QueueManager (27 cases), ExtensionsTest (32 cases), SongDaoIntegrationTest (19 cases), PlaylistDaoIntegrationTest (13 cases β including the 3-step atomic reorder transaction).
See CONTRIBUTING.md for branch naming, commit conventions, code style requirements, and the PR checklist.
See CHANGELOG.md for a full version history.
MIT License β Copyright (c) 2024 WAVORA Contributors
See LICENSE for the full text.