Musynth’s data layer is built around the repository pattern: each abstract interface decouples business logic and UI from the underlying platform APIs. Services and Cubits program against the interfaces;Documentation Index
Fetch the complete documentation index at: https://mintlify.com/CesarArellano/Music-Player-App/llms.txt
Use this file to discover all available pages before exploring further.
GetIt supplies the concrete implementations at runtime without the callers knowing which package or storage mechanism is actually used.
This page covers the three repository interfaces (AudioRepository, ArtworkRepository, PreferencesRepository), their concrete implementations, and ArtworkCacheService, which pre-builds the album art file cache on first launch.
Repository Overview
AudioRepository
Queries songs, albums, artists, genres, and playlists from the device media store. Also manages playlist CRUD operations.
ArtworkRepository
Fetches raw artwork bytes and extracts dominant colours for a given song or album ID.
PreferencesRepository
Reads and writes app-level preferences (last played song, favourites list, dominant colour map) backed by
SharedPreferences.di.dart:
MusicQuerySelectorRepositoryimplements bothAudioRepositoryandArtworkRepository.SharedPreferencesRepositoryimplementsPreferencesRepository.
AudioRepository
Method reference
Method reference
Requests media-library access. On iOS the method polls up to six times (500 ms apart, ~3 s total) because
MPMediaLibrary.requestAuthorization fires a callback asynchronously and the Swift wrapper returns false before it executes.Returns all audio files on the device, sorted alphabetically by title (
SongSortType.TITLE).Returns all album records found in the media store.
Returns all genre records.
Returns all artist records.
Returns all user-created playlists.
Returns all songs belonging to a specific genre, queried with
AudiosFromType.GENRE_ID.Returns all songs inside a specific playlist, queried with
AudiosFromType.PLAYLIST.Creates a new empty playlist. Returns
true on success.Adds a song to an existing playlist.
Removes a song from a playlist without deleting the playlist itself.
Permanently deletes a playlist.
ArtworkRepository
Returns raw JPEG/PNG bytes for a song’s embedded cover art, scaled to
size × size pixels. Returns null if no artwork is embedded. Used by ArtworkCacheService to write <albumId>.jpg files.Extracts the dominant colour of an album’s artwork as a packed ARGB integer. Used to theme the player screen background.
Same as above but accepts a file-system path, useful after artwork has already been cached to disk.
MusicQuerySelectorRepository
Both AudioRepository and ArtworkRepository are implemented by a single class:
GetIt registers it once under AudioRepository and then reuses the same instance for ArtworkRepository by casting:
PreferencesRepository
Property reference
Property reference
Set to
true by ArtworkCacheService.buildArtworkCache once an initial cache build completes. LibraryCubit checks this flag at startup: while it is false, buildArtworkCache is called with force: true, bypassing the numberOfSongs guard and ensuring the cache is always built on the very first launch.The
id of the most recently played song. Read on startup to restore the player to the last track.The playback position (in milliseconds) at the time of the last
pause() or stop(). Passed as initialPosition to loadPlaylist via MusicOrchestratorService.initSong.The song count from the last successful library scan.
ArtworkCacheService compares this with the current count to decide whether to rebuild the artwork cache.The application documents directory path, resolved once by
ArtworkCacheService.resolveAppDirectory and cached here for the lifetime of the app.Persisted list of favourite song IDs (stored as strings). Loaded at startup to hydrate
FavoritesCubit.Album-ID-to-colour-hex map used to theme the player screen. Decoded once from JSON and served from an in-memory cache on subsequent reads.
SharedPreferencesRepository
isNotFirstTime, lastSongId, etc.) are simple pass-throughs to UserPreferences, which wraps SharedPreferences.
The dominantColorCollection property has two performance optimisations:
In-memory read cache
The getter uses
??= to decode the JSON stored in SharedPreferences only once per app session. Every subsequent read returns _colorCache directly, skipping JSON parsing entirely.Isolate-offloaded write
The setter stores the new map in
_colorCache immediately (so reads reflect the latest value without waiting for I/O), then calls Isolate.run(() => json.encode(value)) to serialise the potentially large map on a background isolate. The encoded string is written to SharedPreferences only after the isolate completes.Isolate.run spawns a short-lived isolate for the encoding work, preventing json.encode on a large colour map from blocking the main thread’s frame budget.ArtworkCacheService
ArtworkCacheService builds and maintains the file-based album artwork cache that JustAudioPlaybackService.loadPlaylist references via artUri: Uri.file('$appDirectory/<albumId>.jpg').
How caching works
| Scenario | Behaviour |
|---|---|
First launch (isNotFirstTime == false) | Full build: fetches and writes one JPEG per unique album ID. |
Library unchanged (numberOfSongs matches) | Skipped entirely unless force: true. |
force: true | Re-checks every album; only fetches albums whose .jpg file is missing from disk. |
| Album already cached | File.existsSync() check skips it even on a forced rebuild. |
_maxConcurrentArtworkFetches = 6) to avoid spiking native memory with many simultaneous bitmap decodes. Because Dart is single-threaded per isolate, the shared next++ cursor between await points is a safe way for each worker to claim the next pending album without a mutex.