$ show sosauce/Chocola
Chocola is an offline music player for Android built with Kotlin and Jetpack Compose. It provides a full-featured music experience: library browsing by albums, artists, playlists, and folders; playback with equalizer, speed/pitch control, sleep timer, and shuffle/repeat modes; synced lyrics display and editing; metadata editing; Android Auto support; and home screen widgets. The app uses Material 3 design with a distinctive 'cute' theme, custom navigation, and extensive localization. The architecture follows a typical Android MVVM pattern with Room for playlist persistence, DataStore for preferences, ExoPlayer/Media3 for playback, and Koin for dependency injection. It scans local media via MediaStore and SAF, applies configurable filters (minimum duration, hidden tracks, whitelisted folders), and uses TagLib for metadata editing. While the codebase is well-organized and demonstrates solid Android engineering, it relies heavily on experimental Compose APIs and a custom navigation library, which introduces some technical drift risk. Overall, it's a mature, actively maintained open-source project suitable for reuse of specific UI components and data-layer patterns.
The LLM identified 5 files worth highlighting for reuse:
Provides a structured, configurable pipeline for scanning local audio tracks from MediaStore and SAF URIs. Implements filtering by minimum duration, hidden file exclusion, whitelisted folders, and SAF track deduplication. Returns a sorted list of CuteTrack objects. This is isolated (no imports of other internal modules beyond data models) and could be extracted as a reusable media scanning utility for any Android music app.
Parses synced lyrics from LRC files and embedded lyrics using EnhancedLrcParser and AutoParser from accompanist-lyrics. Handles timing tags, metadata headers, and plain text. The parsing logic is self-contained and could be reused in any application requiring LRC lyric support, with minimal adaptation.
A clean, type-safe wrapper around Jetpack DataStore for managing user preferences. Defines preference keys as top-level properties with default values and serializers, then exposes them as Flow properties in a single class. This pattern is reusable across any Android app that needs structured preference management with minimal boilerplate.
A utility extension function for combining up to 6 flows into one combined flow without nesting. This is a clean, reusable pattern for multi-flow aggregation, often needed in reactive UI layers. The implementation is generic and dependency-free, making it easy to extract into any Kotlin project.
A Compose dialog that handles track deletion with a system confirmation intent (using StartIntentSenderForResult). It manages deletion of multiple items, shows progress, and respects SAF vs MediaStore deletion paths. This is a reusable pattern for any Android app that needs to delete files with user confirmation, handling the complexity of different storage backends.