Conversation
The app felt unfinished due to a handful of concrete bugs rather than vague roughness: - navigate() applied popUpTo(Home) to every push, including drill-downs into Player/Queue/Search/PlaylistDetail/Favorites, so back from those screens always landed on Home instead of the screen the user came from. Split into navigateToTab() (dock/rail only) and a plain-push navigate() for everything else. - Library's Artist/Genre/Folder rows had no onClick at all, unlike Albums. Wired playArtist/playGenre/playFolder (new GetFolderSongsUseCase + getSongsOfFolder query, mirroring the existing album/artist/genre pattern) so tapping any of them plays and opens the queue. - Playlists list deleted with no confirmation while the detail screen did confirm; unified both on the same ResonanceDialog flow. - Playlist detail had no way to add songs while viewing it; added a SongPickerSheet (searchable multi-select) wired to a new addSongs() on PlaylistDetailViewModel. - "Add to playlist" only existed on Library's Songs tab; extended the same SongOverflowSheet/PlaylistPickerSheet wiring to Home, Search, and Favorites song rows. - Playing an empty playlist silently no-opped with zero feedback (the app had no Toast/snackbar anywhere despite a ready-made ResonanceSnackbar component). Wired a shared SnackbarHost into the app shell and surfaced it there. Also switched every collectAsState() to collectAsStateWithLifecycle() across the app so StateFlow collection pauses while the app is backgrounded instead of running continuously. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
User-facing rename only — app_name, permission rationale string, window theme name, manifest label, root project name, ARCHITECTURE.md title. Kotlin package, applicationId, and internal Resonance* symbol names are unchanged (deferred, no user-facing benefit for the churn). Replaced the launcher icon foreground: it was still the unmodified stock Android Studio template (purple circle, default glyph), never actually designed. New mark is a simple rounded-square outline with a play triangle, flat accent color, no gradients — matches the "simpler/mainstream" direction from the plan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Accent color is now a persisted hue (DataStore, same pattern as themeMode) instead of hardcoded copper. stitchDarkColors(accentHue) derives accent/accentGlow/accentDim/onPrimaryContainer from the hue via android.graphics.Color.HSVToColor (no new dependency); surfaces and the secondary/cyan format-badge color stay fixed per DESIGN.md's existing "only the primary accent may adapt" rule. Settings > Appearance gets a swatch row (6 curated hues) plus a hue slider for a fully custom accent. Also deleted the vinyl-groove Canvas fallback (WaveformFallback) and its ArtworkFallbackStyle enum — no caller ever selected it, every ArtworkImage use already fell through to the plain note-glyph fallback (NoteFallback), so the etched-groove path and the unused legacy ArtworkFallback() wrapper were dead code once collapsed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
All via native Compose animation APIs already on the classpath, no new dependency: - NavHost gets a default fade enter/exit (tab switches and drill-down pushes alike — one crossfade avoids picking wrong directionality for the two different kinds of navigation happening through one graph). - Mini player now mounts/unmounts through AnimatedVisibility (slide + fade) instead of a hard if, and is suppressed on the Player/Queue routes (route-aware, not just song-null-aware) so it stops doubling up with the full transport controls already visible there. - LazyColumn/LazyRow items across Library (all 5 tabs), Search, Favorites, Home's recently-played row, and Playlists get Modifier.animateItem() so inserts/removes/filtering slide instead of jump-cutting. - ReorderableLazyColumn (shared by Queue and playlist detail) gets the same animateItem() on its item wrapper — this is what actually answers the "instant snap-back on drop" and "siblings jump instead of sliding" complaints, for free, since animateItem()'s placement animation is spring-based by default. zIndex (raise dragged row above siblings) moved from the row to the wrapper, since it now needs to apply at the LazyColumn-item level, not inside it. - Play/pause icon crossfades (mini player + full player's ResonancePlaybackButton) instead of an instant swap; nav dock icon tint animates and the dot/label indicator crossfades instead of snapping. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Targeted correctness fixes for the "unfinished" feel reported when testing on-device, found via a code audit (three parallel exploration passes over navigation, theming, and animation) rather than guesswork.
navigate()closure appliedpopUpTo(Home){saveState=true}to every call, including drill-downs into Player/Queue/Search/PlaylistDetail/Favorites — so pressing back from any of those always landed on Home instead of the screen you actually came from. Split intonavigateToTab()(dock/rail tab switches only) and a plain-pushnavigate()for everything else.onClickat all (Albums worked, the other three didn't). WiredplayArtist/playGenre/playFolder, adding a newGetFolderSongsUseCase+getSongsOfFolderDAO query that mirrors the existing album/artist/genre pattern (no schema migration — reuses the existingrelativePathcolumn).PlaylistDetailScreenvia a new searchable multi-selectSongPickerSheetcomponent — previously you could only remove songs, never add, while viewing a playlist.SongOverflowSheet/PlaylistPickerSheet).ResonanceSnackbarcomponent). Wired a sharedSnackbarHostinto the app shell.collectAsState()→collectAsStateWithLifecycle()across every screen, so StateFlow collection pauses while the app is backgrounded instead of running continuously (added thelifecycle-runtime-composedependency).Test plan
Gradle can't reach loopback sockets in the sandbox this was developed in (confirmed via stacktrace —
UnixDomainSocketspipe init failure), so this could not be compiled or run in that environment. Every touched file was manually re-read end-to-end to verify import/brace/constructor consistency. Please build in Android Studio and smoke-test before merging:This is Phase 0 of a larger rebrand/UX plan (name change to "Crate", new app icon, accent-palette picker, motion pass) — those are separate, larger follow-up changes not included here.
🤖 Generated with Claude Code