fix(slint): sidebar starts below the artist header, always opens

Two adjustments to land the sidebar truly 1:1 with the Tauri visual.

Top inset now 320px — clears the entire artist header (NavButtons
row + ARTIST label + name + truncated bio + Read more + action
buttons + the 36px spacer before Popular Tracks). The sidebar's top
edge sits inline with where Popular Tracks starts, matching Tauri's
`.network-sidebar-column` natural flow position inside the body
(alongside the sections, never overlapping the header).

Sidebar is always open by default on every artist navigation, with
no cross-session persistence — closing it is a per-view choice only:
  - reset_network_sidebar (called at the start of navigate_artist)
    flips NetworkSidebarState.open back to true alongside the other
    per-artist state resets.
  - network_sidebar_prefs.rs is removed; the on_toggle Rust handler
    is a no-op (Slint already mutates the open flag directly in the
    button click). The previous `<data-dir>/qbz/network_sidebar.json`
    persistence file is no longer written or read.

cc
This commit is contained in:
vicrodh committed 2026-05-20 10:56:26 -06:00
1 parent d68772e3e7
commit 5c9de3e4d1
4 files changed
+23 -94

No files matched your search

+6 -3
View File
@@ -555,11 +555,14 @@ pub struct MbOrigin {
pub location_clickable: bool,
}
/// Reset the network sidebar's MB-driven state. Called when the artist
/// changes so a stale Origin/Relationships/Discovery never bleeds
/// across artists.
/// Reset the network sidebar's MB-driven state and force-open the
/// panel. Called when the artist changes so a stale Origin /
/// Relationships / Discovery never bleeds across artists, and so the
/// sidebar always starts open on every artist visit (per user policy
/// — close is per-session, never persisted).
pub fn reset_network_sidebar(window: &AppWindow) {
let state = window.global::<NetworkSidebarState>();
state.set_open(true);
state.set_mb_available(true);
state.set_mb_mbid("".into());
state.set_origin_loading(false);
+7 -18
View File
@@ -23,7 +23,6 @@ mod commands;
mod discovery_dismiss;
mod home;
mod nav;
mod network_sidebar_prefs;
mod playback;
mod queue;
mod recently;
@@ -1167,24 +1166,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
});
}
// Artist network sidebar — load the persisted open/closed flag
// (defaults to true on first launch), then persist on every toggle.
// The Slint side flips NetworkSidebarState.open before emitting
// the callback.
// Artist network sidebar — no persistence. Default open, user can
// close per-session, and reset_network_sidebar reopens it on every
// artist navigation. The toggle callback stays a no-op on the
// Rust side — Slint already flips NetworkSidebarState.open
// directly in the click handler.
window
.global::<NetworkSidebarState>()
.set_open(network_sidebar_prefs::load_open());
{
let weak = window.as_weak();
window
.global::<NetworkSidebarActions>()
.on_toggle(move || {
if let Some(w) = weak.upgrade() {
let open = w.global::<NetworkSidebarState>().get_open();
network_sidebar_prefs::set_open(open);
}
});
}
.global::<NetworkSidebarActions>()
.on_toggle(|| {});
// Network sidebar — typed click callbacks. Each delivers the
// minimum payload the future target views (ArtistsByLocation,
@@ -1,69 +0,0 @@
//! Persistence for the artist network sidebar open/closed preference.
//!
//! A tiny JSON file at the shared QBZ data path so the sidebar reopens
//! in the same state the user left it. Loaded on demand; written on
//! every toggle. Failures degrade silently — at worst the sidebar
//! starts closed on the next launch.
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Prefs {
#[serde(default = "default_open")]
open: bool,
}
fn default_open() -> bool {
true
}
impl Default for Prefs {
fn default() -> Self {
Self { open: true }
}
}
fn store_path() -> Option<PathBuf> {
Some(dirs::data_dir()?.join("qbz").join("network_sidebar.json"))
}
/// Read the persisted open/closed flag. Defaults to `true` (open) on a
/// fresh install — the artist network sidebar is one of the visible
/// improvements over a generic Linux music player, so it should be on
/// out of the box until the user closes it.
pub fn load_open() -> bool {
let Some(path) = store_path() else {
return true;
};
match std::fs::read(&path) {
Ok(bytes) => serde_json::from_slice::<Prefs>(&bytes)
.map(|p| p.open)
.unwrap_or(true),
Err(_) => true,
}
}
/// Persist the open/closed flag. Called on every sidebar toggle.
#[allow(dead_code)] // wired by the artist controller in phase 3 (network button)
pub fn set_open(open: bool) {
let Some(path) = store_path() else {
return;
};
if let Some(parent) = path.parent() {
if let Err(e) = std::fs::create_dir_all(parent) {
log::warn!("[qbz-slint] network-sidebar prefs dir failed: {e}");
return;
}
}
let prefs = Prefs { open };
match serde_json::to_vec_pretty(&prefs) {
Ok(json) => {
if let Err(e) = std::fs::write(&path, json) {
log::warn!("[qbz-slint] network-sidebar prefs write failed: {e}");
}
}
Err(e) => log::warn!("[qbz-slint] network-sidebar prefs serialize failed: {e}"),
}
}
@@ -601,10 +601,16 @@ export component ArtistPageView inherits Rectangle {
width: 300px;
spacing: 0px;
// 44px to clear the NavButtons row at the top of the
// artist body — mirrors Tauri's sticky jump-nav offset
// (`top: 44px`).
Rectangle { height: 44px; }
// Top inset clears the entire artist header — NavButtons
// (11 padding + ~32 row + 22 spacer = 65) + the artist
// header itself (~214px: ARTIST label + name + truncated
// bio + Read more + action buttons) + the 36px spacer
// before Popular Tracks. Total ~315px so the sidebar's
// top edge sits inline with where Popular Tracks starts,
// matching Tauri's `.network-sidebar-column` natural flow
// position (inside the body, alongside the sections —
// never overlapping the artist header).
Rectangle { height: 320px; }
sidebar-panel := Rectangle {
vertical-stretch: 1;