Skip to content

fix: QML client UI polish (Now Playing navigation, stuck loads, lyrics landing, playlist create/delete) - #26

Open
PeekMusic wants to merge 6 commits into
Ryoku-dev:mainfrom
PeekMusic:fix/ui-polish
Open

PeekMusic wants to merge 6 commits into
Ryoku-dev:mainfrom
PeekMusic:fix/ui-polish

Conversation

@PeekMusic

Copy link
Copy Markdown

What changed

Six small fixes to the native QML client, one commit each:

  • Navigation closes Now Playing (62fc9b5, 5205662). Picking a page while the Now Playing stage was open routed behind it, so the stage had to be closed by hand to see the page. App now closes the stage on every route change (sidebar, title-bar search and its suggestions, Ctrl+K, a menu's go-to-artist or album, the downloads button, back). The sidebar also raises a navigated signal, so a click onto the page you are already on closes the stage too.
  • Same-type navigation no longer loads forever (97adfc8). Going from one playlist straight to another (and the same for album, artist and list pages) could run onParamsChanged before the playlistId binding saw the new params. load() then fetched the page being left, its reply was dropped as stale, and the new page never sent a request, so it stayed on "Loading playlist…". The load is now deferred with Qt.callLater, which also folds the duplicate calls on open into one.
  • Lyrics opened mid-song land on the current line (1868b34). The first follow ran while the list was still hidden behind the loading state, at height 0, so the view stayed at the top until the next line began. It looked as if the song had no synced lyrics. The first jump now waits until the list has lines and a height, then re-centres for 400 ms while the real line heights settle. A manual scroll ends that at once.
  • A playlist made from the sidebar opens (881086c). create_playlist returns YouTube's bare PL… id, and the sidebar opened that as the page id, so browse failed with 400 Bad Request. The new Ids.playlistBrowseId adds VL the way ui/src/lib/player.svelte.ts already does, and leaves device and Spotify ids untouched.
  • Created and deleted playlists show at once (e571b83). YouTube's library browse still returns the old list for a few seconds after a create or delete, so a new playlist appeared, and a deleted one vanished, only after a restart. A small LibraryEdits singleton lays the pending edits over every get_library answer (sidebar and Library page), drops each one once YouTube's list reflects it, and reloads the lists every 3 s (up to six times) in the meantime. Every create path records its playlist: sidebar, Library page, Add to playlist, and both imports.

Why

Each of these was hit in daily use. The Now Playing and loading issues made the app look stuck or broken, and with the lyrics issue you couldn't tell missing synced lyrics from a view that hadn't caught up yet.

Surface area

QML client only: Now Playing / navigation, playlist, album, artist and list pages, lyrics (sidebar panel, Now Playing, mini player), sidebar and Library playlists. No daemon, Tauri or Svelte changes. The Svelte UI already closes Now Playing on navigation (NowPlaying.svelte beforeNavigate), runs its lyrics scroll after the DOM update, and adds VL on create.

Validation

  • ./scripts/release-check.sh (all green, including the Rust tests)
  • cd ui && pnpm check && pnpm build (via release-check)
  • cargo fmt --all -- --check
  • relevant Rust/frontend tests: added test_playlist_browse_id to client/tests/tst_ids.qml. qmltestrunner exits silently in my environment on main as well, so I checked playlistBrowseId and the LibraryEdits overlay/reconcile logic with node instead.
  • affected Ryoku/Hyprland lifecycle tested when applicable: each fix was reproduced and then checked in the running client (qs -p client against the installed ryotunesd).

Regression contracts

  • background WebKit hibernation
  • MPRIS / tray / explicit Quit semantics
  • stable Home DOM / scrolling
  • live Ryoku theme bridge
  • main vs mini-player window rules
  • replacement-package rollback / ryoku-desktop safety
  • steady-state CPU / frontend timer behaviour: no recurring work at rest. LibraryEdits' 3 s timer runs only after a create or delete, and stops once YouTube catches up or after six tries. The lyrics settle timer fires once, 400 ms after the lines land.

Evidence

  • Stuck playlist, client log with temporary instrumentation while going from "Neue Folgen" to "Conan Openings": the second load still read the old id, and its reply was dropped as stale.
    [DBG-PL] load VLRDPN
    [DBG-PL] send id=16 {"id":"VLRDPN"}
    [DBG-PL] reply id=16 after 216ms len=364
    [DBG-PL] then req=VLRDPN now=VLPLyS6kpEBH9YCDwMH_Fe8huQGSA9g1w3vb items=0
    
    Calling the daemon directly, all 21 library playlists answered get_playlist in 0.0–0.7 s, so the daemon was never the cause.
  • Lyrics, same kind of log: at the first follow the view had h=0, so positionViewAtIndex gave goal=0. One line later it had h=593 and the follow worked.
    [DBG-LY] later idx=19 count=34 vis=true h=0 cy=0 ch=1292
    [DBG-LY] follow i=19 anim=false prev=0 goal=0
    [DBG-LY] follow i=20 anim=true prev=0 goal=926 ... h=593
    

Follow-up

  • The Svelte UI doesn't drop a deleted playlist from the sidebar right away either. delete_playlist emits no library-changed, and YouTube's list lags. Left for a separate change.
  • The mini player has a fixed size (724×356). A corner handle that scales it would be a small follow-up feature.

Picking a page in the rail while Now Playing was open routed behind the stage, so
the user had to close it by hand to see the page. Every rail row and a new playlist
now raise `navigated`, also onto the current page, and App closes the stage.
Going from one playlist straight to another (likewise album, artist and list pages)
could run onParamsChanged before the id binding saw the new params. load() then
fetched the page being left, its reply was dropped as stale, and the new page never
got a request, so it sat on "Loading playlist…". The load is now deferred with
Qt.callLater, which also folds the repeat calls on open into one.
The first follow ran while the list was still hidden behind the loading state, in a
zero-high view, so it stayed at the top until the next line began and it looked as
if the song had no synced lyrics. The first jump now waits until the list has lines
and a height, then re-centres for 400 ms while the real line heights settle; a manual
scroll ends that at once.
The sidebar fix left the other doors open: a title-bar search, its suggestions, Ctrl+K,
a menu's go-to-artist or album, the downloads button and back still opened the page
behind the stage. App now closes the stage on every route change; the sidebar's
`navigated` stays for clicks onto the current page, which change no route.
create_playlist answers with YouTube's bare playlist id (PL…), and the sidebar opened
that as the page id, so the browse call failed with 400 Bad Request. The new
Ids.playlistBrowseId adds the VL prefix the way the Svelte UI does and leaves device
and Spotify ids untouched.
…brary

YouTube's library browse answers with the old list for a few seconds after a create
or a delete, so a new playlist appeared and a deleted one vanished only after a
restart. A small LibraryEdits singleton lays the pending edits over every get_library
answer, drops each once YouTube's list reflects it, and reloads the lists every 3 s
(up to six times) meanwhile. Every create path notes its playlist: the sidebar, the
Library page, Add to playlist and the imports.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant