$ show TJYSunset/Phocid
Phocid is a full-featured offline Android music player built with Jetpack Compose and Material3, targeting Android 11+. It serves as a modern replacement for Phonograph, offering extensive customization of themes, artwork colors, layouts, and playback behavior. The application manages a local music library by scanning MediaStore and optionally using JAudioTagger and OpusMetadataIo for advanced metadata extraction. It supports playback via Media3 ExoPlayer with custom shuffle, repeat, speed/pitch control, and a sleep timer. The UI includes a tabbed library view (tracks, albums, artists, genres, folders, playlists), a player screen with artwork, synced lyrics (LRC), and a queue, plus home screen widgets and Android Auto integration. Playlist management features M3U import/export with relative paths and bidirectional sync using file timestamps. The codebase is well-structured with clear separation of concerns: data layer (LibraryIndex, Playlist, Preferences), service layer (PlaybackService, PlayerManager), UI components (custom scrollbar, swipe-to-dismiss, carousel, dialogs), and utility modules (AsyncCache, SaveManager, StateFlow extensions). It includes unit tests for core logic (lyrics parsing, playlist I/O, search, sorting, caching) and uses Kotlinx Serialization for persistence with upgrade paths. The architecture follows a single-activity pattern with Compose navigation and a ViewModel-driven state management. While primarily an application, it contains reusable data engineering patterns such as generic persistence, concurrent caching, and locale-aware sorting that could be extracted for other projects.
The LLM identified 10 files worth highlighting for reuse:
A small, generic concurrent cache with automatic eviction and renewal. It uses a fixed-size map with LRU-like eviction and supports asynchronous loading with cancellation. Includes unit tests for concurrency and eviction behavior. Can be extracted and reused in any Kotlin project needing a lightweight in-memory cache.
A generic persistence manager using Kotlinx Serialization and CBOR encoding. It provides a Flow-based API for reading/writing state, automatic backup of previous versions, and recovery from corrupted files. Designed to be reusable for any serializable data class, with minimal coupling to the rest of the app.
A custom scrollbar composable that works with both LazyListState and LazyGridState. Features an animated thumb that scales on drag, a hint label showing the current position, and smooth scrolling. Replaces platform scrollbars with a more polished UX and is fully decoupled from the app's domain logic.
A base dialog composable with three overloads: confirm/dismiss, single button, and custom content. Provides consistent styling (Material3) and behavior across all dialogs in the app. Can be extracted as a standalone UI component for any Compose project.
A custom drag state machine for swipe gestures (e.g., dismissing queue items, revealing player controls). Manages drag thresholds, animation to open/closed positions, and a lock to prevent concurrent gestures. Implemented with Compose's pointerInput and animate*AsState. Self-contained and reusable for any swipeable UI.
A custom progress slider adapted from AOSP, featuring a squiggly wave animation during playback. Supports drag, tap-to-seek, and displays buffered progress. The wave animation is implemented with Canvas drawing and is independent of the player logic. Can be reused as a visually distinctive seekbar.
A composable that presents a list of sorting options (e.g., by title, artist, year) with ascending/descending toggle. Uses a bottom sheet or dialog pattern. Generic enough to be reused in any app that needs sort selection, with minimal dependencies.
A state holder for multi-selection in lists. Manages selected items, search filtering, and sorting within the selection context. Provides a clean API for toggling, clearing, and querying selection. Decoupled from UI and can be reused in any list-based selection scenario.
A custom swipe-to-dismiss composable that replaces Material3's buggy implementation. Supports left/right swipe with configurable background and icon. Uses Compose's pointerInput and animate*AsState. Self-contained and easily extractable for any list item dismissal.
A horizontal carousel composable for displaying track artwork with repetition (infinite scroll) and jump-to-position support. Handles edge cases like rapid scrolling and item recycling. Designed to be reusable for any carousel UI, not tied to music data.