···2323pub struct NowPlayingManager {
2424 controls: MediaControls,
2525 cmd_rx: mpsc::Receiver<MediaCommand>,
2626- /// Last track id pushed to the OS so we only re-send metadata on change.
2626+ /// Last track id pushed to the OS — guards against redundant metadata sends.
2727 last_track_id: String,
2828+ /// Last cover URL — re-send metadata when art arrives after the track id.
2929+ last_cover_url: Option<String>,
2830}
29313032impl NowPlayingManager {
···5961 })
6062 .ok()?;
61636262- Some(NowPlayingManager { controls, cmd_rx, last_track_id: String::new() })
6464+ Some(NowPlayingManager {
6565+ controls,
6666+ cmd_rx,
6767+ last_track_id: String::new(),
6868+ last_cover_url: None,
6969+ })
6370 }
64716572 /// Drain all pending OS media-key commands (non-blocking).
···8289 };
8390 let _ = self.controls.set_playback(playback);
84918585- // Metadata only on track change
8692 let track_id = track.map(|t| t.id.as_str()).unwrap_or("");
8787- if track_id == self.last_track_id {
8888- return;
8989- }
9090- self.last_track_id = track_id.to_string();
9191-9293 // album_art is a bare filename served by rockboxd's cover HTTP server.
9394 let cover_url = track
9495 .and_then(|t| t.album_art.as_deref())
9596 .filter(|s| !s.is_empty())
9697 .map(|name| format!("http://localhost:6062/covers/{}", name));
9898+9999+ // Re-send metadata when either the track or the cover art changes.
100100+ // Cover art can arrive in a later poll tick after the track id was set.
101101+ let track_changed = track_id != self.last_track_id;
102102+ let cover_changed = cover_url != self.last_cover_url;
103103+ if !track_changed && !cover_changed {
104104+ return;
105105+ }
106106+ self.last_track_id = track_id.to_string();
107107+ self.last_cover_url = cover_url.clone();
9710898109 let meta = track
99110 .map(|t| MediaMetadata {
+6-4
gpui/src/ui/components/pages/library.rs
···19921992 let max_x = viewport.width - menu_w - margin;
19931993 let menu_x = if menu.pos.x > max_x { max_x } else { menu.pos.x };
19941994 let menu_x = if menu_x < margin { margin } else { menu_x };
19951995- let max_y = viewport.height - menu_h - margin;
19961996- let menu_y = if menu.pos.y > max_y { max_y } else { menu.pos.y };
19951995+ // Flip above cursor when the menu would overflow the bottom edge.
19961996+ let overflows_bottom = (menu.pos.y + menu_h + margin) > viewport.height;
19971997+ let menu_y = if overflows_bottom { menu.pos.y - menu_h } else { menu.pos.y };
19971998 let menu_y = if menu_y < margin { margin } else { menu_y };
19981999 this.child(
19992000 div()
···21762177 let max_x = viewport.width - menu_w - margin;
21772178 let menu_x = if menu.pos.x > max_x { max_x } else { menu.pos.x };
21782179 let menu_x = if menu_x < margin { margin } else { menu_x };
21792179- let max_y = viewport.height - menu_h - margin;
21802180- let menu_y = if menu.pos.y > max_y { max_y } else { menu.pos.y };
21802180+ // Flip above cursor when the menu would overflow the bottom edge.
21812181+ let overflows_bottom = (menu.pos.y + menu_h + margin) > viewport.height;
21822182+ let menu_y = if overflows_bottom { menu.pos.y - menu_h } else { menu.pos.y };
21812183 let menu_y = if menu_y < margin { margin } else { menu_y };
21822184 this.child(
21832185 div()