Repository navigation
UI density: compact mode, flat placeholders, Settings tab, shelf play - #656
PylotLight wants to merge 37 commits into
Conversation
Remaining 8 modules still targeted JVM 11 with stale comments about pre-KMP inline constraints (core, networking). All consumers are now on JVM 17 (app, designsystem, fixtures), AGP 9.4.1 + Kotlin 2.4.20 fully support 17, desugaring is on. Bump compileOptions + jvmTarget together so inline functions can't mix bytecode levels. Majors verified current as of 2026-09-27, intentionally untouched: AGP 9.4.1, Kotlin 2.4.20, Media3 1.11.1, Compose BOM 2026.09.00, Coil 3.6.2, Ktor 3.6.0, Room 2.8.3. R8 fullMode=false left as-is (Retrofit-adapter crash needs root-causing before AGP 10). Needs ./gradlew :android:app:assembleDebug on a machine with Android SDK + JDK 21 to verify.
…torage flag - enableOnBackInvokedCallback=true (targetSdk 36) - localeConfig locales_config.xml (en seed for Settings per-app picker) - remove requestLegacyExternalStorage (ignored since API 30) M3 Expressive stays on 1.5.0-alpha29 (latest as of 2026-09-27; stable 1.4.0, 1.5.0 stable later in 2026). M2 styles.xml + google.material dep stay: Cast route chooser + server sign-in dialog fragments still need the View theme (see MainActivity KDoc).
Port OffBookPlus k8s flow for standalone k3s: tar+kubectl-cp seed pod instead of rsync/hostPath, SDK bootstraps at runtime from temurin JDK 21 into a local-path PVC (sdk+gradle+workspace survive across builds). Keeps Dockerfile for docker-capable hosts. OffBookPlus scripts unusable here: no docker/colima/rsync on host, cluster is remote (node luxai, amd64) so hostPath sync can't work.
…rops Remote build failed two ways: KMP requests a Java 17 toolchain but the temurin image ships only 21 (no auto-provisioning configured), and app/build.gradle.kts shells to git for versioning (binary missing broke config-cache store). Bootstrap now fetches Temurin 17 once into the PVC and registers installations.paths, ensures git exists, and build-remote.sh forwards local git-describe as -PversionCode/Name since .git (714M) is excluded from the sync.
TaglibMediaProvider.findSongs ignored its existingSongs and re-parsed every file with an FD + TagLib open per row. Build an existingByPath map and emit the stored song directly when its lastModified + size match (plus duration within 1s, for DATE_MODIFIED's 1-second granularity), preserving id, play counts and artworkVersion.
…r tuning MediaStore ContentObserver in the media-provider startup initializer (debounced 20s, gated on music permission + already-scanned-once) reuses MediaImporter.import's own coalescing. New exported LibraryScanReceiver (RESCAN_LIBRARY, 60s debounce, no DUMP gate) for automation apps via goAsync. Worker drops the never-firing setRequiresDeviceIdle, gains setRequiresStorageNotLow, and staggers its first run 15-30min instead of a full interval. Extra SAF trees documented as manual/periodic-only (no DocumentsProvider observer).
The success-only kubectl-wait burned the full deadline on failed builds. Poll succeeded/failed explicitly, break on either, dump the last 40 log lines on failure.
…ion-deps-compose-base
…on-deps-compose-base
Previous build OOMKilled at mergeProjectDexDebug under 6Gi. Node has headroom (32GB, ~21% used): 4 CPU / 10Gi limit, Gradle heap 6g.
S2Sheet pulls expressive internals; the new caller missed the @OptIn. Caught by :android:app:compileDebugKotlin (OPT_IN_USAGE_ERROR).
Leftover from the dialog→S2Dialog extraction. Caught by :android:app:compileDebugKotlin (SYNTAX error).
S2ActionsSheet still needs it; the BasicAlertDialog removal took the annotation with it.
The success-path kubectl cp from the build pod silently fetched nothing. Route through the alpine seed pod like the source sync.
Settings -> Library gains Back up library / Restore library backup. Export writes play counts, positions, favourites, exclusions, dates and playlists (identity: path, remote id, tag fingerprint; never Room ids, tokens or grant URIs). Restore matches exact, relative-path, remote-id then fuzzy, and merges field-by-field (max counts, latest times, earliest favourite) so neither side loses newer activity. Includes matcher/schema unit tests.
SettingsViewModel gained a LibraryBackupManager dependency; the direct constructions in SettingsViewModelTest/SettingsIntegrationTest now pass a relaxed mock (backup flows have their own tests).
…, remote test - relativePath now strips /storage/emulated/<n>/ as well as physical volume ids (primary storage is the common reinstall case). - latestOf/earliestOf replace maxOf/minOf helpers that recursed via overload resolution (StackOverflowError in merge). - remote-id test now uses differing paths so exact match can't win.
The optional-group regex ate one path segment too many on emulated storage. (emulated/N | volume) alternatives are now exclusive.
Restore now overwrites playCount, timestamps, position, excluded and favouritedAt from the backup snapshot instead of merging field-by-field (max counts, latest times). dateAdded keeps its current value when the backup has none. Adds SongDataDao.setFavouritedAt; matcher tests pin the snapshot behaviour.
…library density Replaces wavy progress indicators with flat ones; slims Expressive chrome (settings rows, nav bar, hero, tiles, mini-player); adds an Appearance compact-mode toggle (dense rows, 36dp headers, 96dp tiles, pinned one-row library/settings bars, smaller detail heros); flattens missing-artwork placeholders to bare icons; adds a Settings bottom tab; adds play buttons to Home shelf headers.
Flat resume row (no hero card), flat shadowless tiles, icon-only nav bar, 28/40dp row art, 32dp headers, 3-column grids, tighter detail heros. Renames the toggle to Classic mode; pref key unchanged.
Settings lives in the bottom tab: removes the Home/Library top-bar gears and their plumbing. Restores the old home's shortcut row (History, Recently Added, Favorites, Shuffle) opening the smart playlists, two-line shelf headers with subtitles, and play-count badges on most-played tiles (count out of the subtitle). Resume hero gains a test tag so its actions stay tappable beside the shortcuts.
Drops Home's empty top bar (Shuffle lives in the shortcut row), adds classic vertical spacing between shortcuts and shelves, shrinks classic shortcut circles to 48dp, and densifies classic tile subtitles.
Each one-shot builder minted its own ~/.android debug key, so every APK had a new signature and Android refused to install it over the previous build. The debug build type now signs with a checked-in debug key (not a secret); release signing is untouched.
Brand row with the launcher logo and Shuttle name tops Home. Shortcut circles go solid classic colors (orange/green/red/blue) with white glyphs. Shelf tiles grow (128dp classic, 144dp modern) so rows fill the screen vertically.
Brand logo 40/44dp with headlineSmall name. Shortcuts keep their 48/56dp circles but swap Rounded for the sharp Filled glyphs the classic app used. Dual debug+release now the default cluster build; dev release signs with the shared debug key under the .dev id.
Brand mark, shortcut row, two-line shelf headers and play-count badges render in classic mode only; modern returns to the plain top bar. Settings > About shows version (code/sha) so dev builds are told apart; build-remote.sh forwards the local sha as -PGitSha.
Restores ic_history, ic_playlist_add and ic_favorite_border from before the legacy-resource deletion, pairing with the surviving shuffle glyph. Classic shortcuts render them tinted in the reference accent colors on dark circles; modern keeps filled white glyphs. Brand splits by mode: centered Shuttle Music Player in classic, small row in modern.
|
Holding this one for now. It stacks on #655 (see the split request there), and several of its changes are design-language decisions rather than density tweaks: removing the wavy progress indicators, flattening the missing-artwork placeholders, and adding a fourth Settings tab with its own back stack. Those need a call from Tim against Once #655 is split and landed, a rebased PR with just the compact-mode toggle (off by default) and the resume-hero size fix would be the easiest piece to take first; the indicator, placeholder and Settings-tab changes are better raised as separate issues so each can be decided on its own. |
|
🤖 Claude here (an AI agent), reviewing for Tim. A follow-up on the hold above. #655 is being finished on the maintainer side (see the note there), so this one no longer needs to wait for it. To move forward:
I can review (a) as soon as it's up. |
|
started on the split as suggested. opened #860 with just the (a) slice: compact-mode toggle plumbing off current main, no readers yet so zero visual change, none of the old stack (no k8s/build/scanner/theme/keystore). one note: the resume-hero size fix does not carry over. main's Home is a JumpBackIn grid now and the old ResumeHero card is gone. happy to fold in a sizing fix if one still applies to the new layout. keeping this PR open until #860 is up for review, then we can close/supersede. design-language pieces to follow one at a time with screenshots. |
Changelog: none Idea-by: PylotLight (#656)
A play icon beside See all plays every song of the shelf in order, replacing the queue. Not on Jump back in or Genre picks. Idea-by: PylotLight (#656)
|
🤖 Claude here (an AI agent), reviewing for Tim. Closing in favour of the summary on #860. Thanks! |
Stacked on #655 (retarget once it merges; the diff below includes it until then). Slims the M3 Expressive chrome and adds a density option; no behaviour changes to playback, scanning or backup.
LinearProgressIndicatoreverywhere)MaterialShapescookie/blob containers);design-language.mdupdatedModifier.sizevssizeconflict left it at 160dp, which also made the first compact pass a no-op)Verification: home/settings/shell/library/theme suites green (incl. new shelf-play tests),
assembleDebuggreen. Roborazzi goldens underdocs/design/need re-recording (placeholders/headers/tabs changed).