Musynth manages all runtime state with fiveDocumentation 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.
flutter_bloc Cubits. Each Cubit owns a single, immutable state class and exposes focused methods that call emit() to produce a new state. Widgets observe state reactively through context.watch and trigger changes through context.read.
Cubit Reference
| Cubit | State Class | Responsibility |
|---|---|---|
PlaybackStateCubit | PlaybackState | Currently playing song, active playlist, shuffle toggle, isPlaying flag |
AudioControlCubit | AudioControlState | Live playback position (currentDuration) and current track index |
LibraryCubit | LibraryState | Songs, albums, artists, genres, playlists, and lazy per-collection maps |
FavoritesCubit | FavoritesState | Favorite songs list, persisted IDs, isFavoriteSong(id) helper |
UICubit | UIState | Dominant album color, hero animation ID, in-memory color cache |
State Shapes
PlaybackState
PlaybackState
PlaybackStateCubit exposes granular update methods (updateSongPlayed, updateCurrentPlaylist, updateIsShuffling, updateIsPlaying) and a clearSongPlayed helper that resets the track while preserving the playlist and shuffle preference.AudioControlState
AudioControlState
JustAudioPlaybackService, which subscribes to AudioPlayer.positionStream and AudioPlayer.currentIndexStream at app startup and calls audioControlCubit.updateCurrentDuration(...) / audioControlCubit.updateCurrentIndex(...) on each event.LibraryState
LibraryState
LibraryCubit fires all four media-store queries (querySongs, queryAlbums, queryGenres, queryArtists) concurrently. Songs are emitted first so the Songs tab becomes interactive immediately; the rest resolve in-flight. The albumCollection, artistCollection, genreCollection, and playlistCollection maps are populated lazily when a detail screen requests them.FavoritesState
FavoritesState
SharedPreferences. After the library loads, FavoritesCubit.initFavorites(allSongs) runs on an Isolate to reconstruct the full SongModel list from those IDs without blocking the UI thread.UIState
UIState
UICubit subscribes to PlaybackStateCubit.stream in its constructor and automatically calls searchDominantColorByAlbumId whenever the playing song changes. The color is derived natively on the platform side (androidx.palette / Core Image) and cached in dominantColorCollection so subsequent visits to the same album are instant.Reading State in Widgets
Use
context.watch only inside build(). Using it in an initState, callback, or outside the widget lifecycle throws a runtime assertion.LibraryCubit: Emit Pattern in Detail
ThegetAllSongs method illustrates how Cubits emit partial state updates as async work completes:
emit call is an immutable copyWith snapshot. The widget tree receives only the fields it watches, so intermediate loading states are surfaced incrementally.
MultiBlocProvider Setup
All five Cubits are instantiated inmain() before runApp and injected into the widget tree using BlocProvider.value. This pattern hands ownership of each Cubit to main() rather than to a widget subtree, ensuring they survive navigation and are accessible everywhere.
Because
BlocProvider.value is used (not the default BlocProvider constructor), the Cubits are not closed when the MultiBlocProvider widget is removed from the tree. Their lifetime is managed by the GetIt container and main().Cubit Lifecycle Summary
Instantiation in main()
Each Cubit is created with its required repository/cubit dependencies injected directly from the GetIt locator (e.g.,
setupLocator<PreferencesRepository>()).Registration in GetIt
setupServiceLayer(...) immediately registers every Cubit as a singleton via setupLocator.registerSingleton<XCubit>(xCubit), making them available to services without a BuildContext.Exposure to widget tree
MultiBlocProvider + BlocProvider.value makes each Cubit available to all descendants of MyApp via context.read / context.watch.