Ports the whole playlist-organisation domain, which had no counterpart in this frontend, plus the Library work the owner asked not to defer. Playlist Manager. New controller (playlist_manager_qt, _rows, _ops) over the already-ported folders_qt repository, which until now had zero consumers. Grid, list and folder-tree modes; sort, filter and search; folder cards and chips; drag reorder and up/down arrows. Reached from the sidebar's "..." menu, whose New folder / Manage playlists / Import rows had been rendering dimmed and inert behind a comment saying the seam did not exist. Folders. QbzFolderEdit plus the create/edit modals and PmFolderIcon: preset or custom-image icons, colour, hidden flag, delete. Deleting a folder nulls its LOCAL members' folder_id explicitly, because the app keeps the foreign_keys pragma off, so the schema's ON DELETE SET NULL never fires for them. QbzPlaylistEdit. One shared rename/description/delete editor replacing the inline popup in PlaylistView. Three corrections the old path had wrong: the description is carried through a rename instead of being written as NULL, a FOLLOWED playlist routes to unsubscribe (playlist/delete returns 200 and silently no-ops on a playlist you do not own), and the post-delete back navigation is conditional on actually being on that playlist's page, so deleting from the manager no longer navigates you off it. Importer. Spotify / Apple Music / Tidal / Deezer, over the shared qbz-playlist-import crate. Picker local mode. The reference's four-case matrix — target local or Qobuz, payload local refs or Qobuz ids. Local playlists list unconditionally and Qobuz ones only when online. Local refs onto a Qobuz playlist write the library.db sidecar at next_playlist_sidecar_position(pid, qobuz_count); the 0-based enumerate the reference used before collided slots and lost rows. The carried payload can no longer be parsed as a catalog id when it is a library row id. Unblocks the local bulk add-to-playlist. Library. A-Z jump strip, Albums list mode, Artists side panel, per-tab persistence and multi-select. Preferences land in the same <data-dir>/qbz/favorites_ui.json the shipping build writes, so switching between the two frontends keeps them. LibraryView is split into views/library/ on the way past 1800 lines. Local library. Group-by now persists; playback queues the order on screen rather than the SQL page order; switching album-identity mode invalidates the Artists tab; artist matching folds diacritics and compares normalized credit parts, so "Air" stops listing "Airbourne" and "Beyonce" stops being two artists. Offline. activate_offline never persisted a last-user marker, so every per-user path resolved to None and all local reads came back empty; a session that started offline saw no local playlists at all. The sidebar's load-once latch was function-local and therefore unreachable from the logout reset, so a second login never rebuilt the tree. Both are session-scoped now, and the sidebar Refresh row runs the local-safe verb instead of being dimmed with no way to recover. Also fixes, found while verifying rather than reported: artwork derivatives were written straight to their final path, so a QML Image resolving one mid-encode opened a truncated png and Qt cached that failure against the URL for the rest of the session; Library's track group separators referenced a Component declared in another delegate's scope and could never render; the genre filter was drawn on Tracks and Albums but applied only on All; an All-feed row called a player method that does not exist; and the sidebar's drop-hot highlight used Slint's #RRGGBBAA literals in Qt's #AARRGGBB slot. 17 new msgids across all 8 locales. cc
82 lines
2.7 KiB
QML
82 lines
2.7 KiB
QML
// AlbumListHeader — primitives/AlbumListRow.slint:43-127, the column header
|
|
// above the LIST arm of an album collection (Discover Browse, Label
|
|
// Releases). 32px, 11px semibold muted labels with 0.5 letter-spacing and a
|
|
// bottom hairline.
|
|
//
|
|
// COLUMN SET, and why it is shorter than the Slint's: `AlbumListCols` there
|
|
// is rank · art · ITEM · TYPE · SOURCE · QUALITY · TRACKS · YEAR · overflow.
|
|
// The Qt transport for these pages is `home_qt::HomeCard`, which carries no
|
|
// release type and no track count, and SOURCE is hidden on both catalog
|
|
// pages anyway (`show-source: false`, DiscoverBrowseView.slint:168). Naming
|
|
// columns with nothing under them is worse than not drawing them, so the
|
|
// header lists exactly the three the rows fill. Widths are the Slint's.
|
|
|
|
import QtQuick
|
|
import com.blitzfc.qbz
|
|
import "../theme"
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
QbzTheme { id: theme }
|
|
|
|
/// Mirrors AlbumListRow.selectMode: the rows below grow an 18px leading
|
|
/// checkbox cell in Library > Albums multi-select, and the header has to
|
|
/// inset by the same amount or every column label drifts off its column.
|
|
property bool selectMode: false
|
|
|
|
// AlbumListCols: art 52, quality 150, year 64, overflow 36, gap 12.
|
|
readonly property int colArt: 52
|
|
readonly property int colQuality: 150
|
|
readonly property int colYear: 64
|
|
readonly property int colOverflow: 36
|
|
readonly property int colGap: 12
|
|
|
|
width: parent ? parent.width : 0
|
|
height: 32
|
|
color: "transparent"
|
|
|
|
component ColLabel: Text {
|
|
color: theme.textMuted
|
|
font.pixelSize: 11
|
|
font.weight: theme.weightSemibold
|
|
font.letterSpacing: 0.5
|
|
verticalAlignment: Text.AlignVCenter
|
|
height: 32
|
|
}
|
|
|
|
Row {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 12
|
|
anchors.rightMargin: 12
|
|
spacing: root.colGap
|
|
|
|
Item { visible: root.selectMode; width: visible ? 18 : 0; height: 1 }
|
|
Item { width: root.colArt; height: 1 }
|
|
ColLabel {
|
|
width: parent.width - root.colArt - root.colQuality - root.colYear
|
|
- root.colOverflow - 4 * root.colGap
|
|
- (root.selectMode ? 18 + root.colGap : 0)
|
|
text: QbzSession.tr("ITEM", QbzSession.trRev)
|
|
elide: Text.ElideRight
|
|
}
|
|
ColLabel {
|
|
width: root.colQuality
|
|
text: QbzSession.tr("QUALITY", QbzSession.trRev)
|
|
}
|
|
ColLabel {
|
|
width: root.colYear
|
|
text: QbzSession.tr("YEAR", QbzSession.trRev)
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
Item { width: root.colOverflow; height: 1 }
|
|
}
|
|
|
|
Rectangle {
|
|
y: parent.height - 1
|
|
width: parent.width
|
|
height: 1
|
|
color: theme.borderSubtle
|
|
}
|
|
}
|