Add bounded native library models, complete grouping rails and scan progress. Bring source-aware metadata editing, media information and collection offline preflight to Qt, and repair inherited Plex album artwork without overriding healthy tokens. cx
168 lines
7.4 KiB
QML
168 lines
7.4 KiB
QML
// Albums tab body (LocalLibraryView.slint:1133).
|
|
//
|
|
// States, in the Slint's own order: initial spinner, load error + Retry,
|
|
// "nothing indexed yet", "nothing matches" (search OR the quality/format/
|
|
// source filter emptied the visible set), then the chunked collection with
|
|
// the bulk bar and the A-Z jump strip.
|
|
//
|
|
// Deviation: the Slint scrolls its MultiSelectBar away with the grid (it
|
|
// lives inside the scrolling page); here the bar is pinned above the
|
|
// collection, because the collection IS the scrolling view (one windowing
|
|
// ListView) rather than a page inside a Flickable.
|
|
|
|
import QtQuick
|
|
import com.blitzfc.qbz
|
|
import "../../controls"
|
|
import "../../theme"
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property var view: null
|
|
readonly property bool nativeActive: root.view.albumsNativeViewActive
|
|
readonly property int albumTotal: nativeActive
|
|
? QbzLocal.localAlbumsNativeTotal : root.view.albums.length
|
|
|
|
QbzTheme { id: theme }
|
|
|
|
// Loading = the SHAPE of the collection that is coming (the Slint mounts
|
|
// a bare 36px LoadingSpinner here), matching the tab's current view mode:
|
|
// the 220x266 card grid or the 56px list rows. ONE instance for the whole
|
|
// viewport — one animator, not one per cell (QbzSkeleton COST note).
|
|
QbzSkeleton {
|
|
visible: QbzLocal.localAlbumsLoading && root.view.albumsView === "grid"
|
|
variant: "cardGrid"
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 32
|
|
anchors.rightMargin: 32
|
|
anchors.topMargin: 16
|
|
cellW: 220
|
|
cellH: 266
|
|
phase: root.view.skelPhase
|
|
}
|
|
QbzSkeleton {
|
|
visible: QbzLocal.localAlbumsLoading && root.view.albumsView !== "grid"
|
|
variant: "rowList"
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 32
|
|
anchors.rightMargin: 32
|
|
anchors.topMargin: 16
|
|
rowH: 56
|
|
rowGap: 0
|
|
rowArtSize: 40
|
|
phase: root.view.skelPhase
|
|
}
|
|
|
|
// Load error + retry.
|
|
Column {
|
|
visible: !QbzLocal.localAlbumsLoading && QbzLocal.localAlbumsError !== ""
|
|
anchors.centerIn: parent
|
|
spacing: 10
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: QbzSession.tr("Couldn't load your local albums.", QbzSession.trRev)
|
|
color: theme.textPrimary
|
|
font.pixelSize: theme.fontBody
|
|
font.weight: theme.weightSemibold
|
|
}
|
|
SettingsButton {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: QbzSession.tr("Retry", QbzSession.trRev)
|
|
onClicked: root.view.loadTabForView("albums")
|
|
}
|
|
}
|
|
|
|
LocalNote {
|
|
visible: !QbzLocal.localAlbumsLoading && QbzLocal.localAlbumsError === ""
|
|
&& root.albumTotal === 0 && root.view.albumsSearch === ""
|
|
text: QbzSession.tr("No albums in your local library yet.", QbzSession.trRev)
|
|
}
|
|
LocalNote {
|
|
visible: !QbzLocal.localAlbumsLoading && QbzLocal.localAlbumsError === ""
|
|
&& ((root.nativeActive && root.albumTotal === 0
|
|
&& root.view.albumsSearch !== "")
|
|
|| (!root.nativeActive && root.view.albums.length > 0
|
|
&& root.view.albumsVisible.length === 0))
|
|
text: QbzSession.tr("No albums match your search.", QbzSession.trRev)
|
|
}
|
|
|
|
Column {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 32
|
|
anchors.rightMargin: 32
|
|
anchors.topMargin: 16
|
|
spacing: 8
|
|
visible: !QbzLocal.localAlbumsLoading && QbzLocal.localAlbumsError === ""
|
|
&& (root.nativeActive ? root.albumTotal > 0
|
|
: root.view.albumsVisible.length > 0)
|
|
|
|
QbzMultiSelectBar {
|
|
visible: root.view.albumsMultiSelect
|
|
width: parent.width
|
|
selectedCount: root.view.albumsSelectedCount
|
|
actions: [
|
|
{ "id": "select-all", "label": QbzSession.tr("Select all", QbzSession.trRev), "icon": "square-check-big", "danger": false, "needsSelection": false },
|
|
{ "id": "queue", "label": QbzSession.tr("Add to queue", QbzSession.trRev), "icon": "list-end", "danger": false, "needsSelection": true },
|
|
{ "id": "play-later", "label": QbzSession.tr("Play later", QbzSession.trRev), "icon": "list-plus", "danger": false, "needsSelection": true },
|
|
{ "id": "play-next", "label": QbzSession.tr("Play next", QbzSession.trRev), "icon": "list-start", "danger": false, "needsSelection": true },
|
|
{ "id": "add-to-playlist", "label": QbzSession.tr("Add to playlist", QbzSession.trRev), "icon": "list-music", "danger": false, "needsSelection": true },
|
|
{ "id": "add-to-mixtape", "label": QbzSession.tr("Add to Mixtape/Collection", QbzSession.trRev), "icon": "cassette-tape", "danger": false, "needsSelection": true },
|
|
{ "id": "clear", "label": QbzSession.tr("Clear", QbzSession.trRev), "icon": "x", "danger": false, "needsSelection": true },
|
|
]
|
|
onAction: function (id) { root.view.albumsBulkAction(id) }
|
|
}
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: parent.height - (root.view.albumsMultiSelect ? 52 : 0)
|
|
|
|
LocalAlbumCollection {
|
|
id: collection
|
|
anchors.fill: parent
|
|
anchors.rightMargin: root.view.albumsGroup === "alpha" ? 20 : 0
|
|
// 32 of tab padding, plus the 20 above when the strip is up.
|
|
hostRightInset: 32 + (root.view.albumsGroup === "alpha" ? 20 : 0)
|
|
scrollBarInset: root.view.albumsGroup === "alpha" ? 34 : 4
|
|
view: root.view
|
|
surface: "albums"
|
|
nativeSurface: true
|
|
nativeActive: root.nativeActive
|
|
nativeModel: root.view.nativeAlbumsModel
|
|
nativeJumpsJson: QbzLocal.localAlbumsNativeJumpsJson
|
|
scrollScope: "local:albums"
|
|
rows: root.view.albumsVisible
|
|
groups: root.view.albumsGrouped
|
|
grouped: root.view.albumsGroup !== "off"
|
|
viewMode: root.view.albumsView
|
|
showSource: true
|
|
selectMode: root.view.albumsMultiSelect
|
|
selected: root.view.albumsSelected
|
|
onOpenRequested: function (id) { root.view.openAlbum(id) }
|
|
onPlayRequested: function (id) {
|
|
QbzLocal.playAlbumFiltered(id, JSON.stringify(root.view.albumsFilter || {}), false)
|
|
}
|
|
onEnqueueRequested: function (id, m) {
|
|
QbzLocal.enqueueAlbumFiltered(id, JSON.stringify(root.view.albumsFilter || {}), m)
|
|
}
|
|
onToggleSelect: function (id, mods) { root.view.toggleAlbumSelected(id, mods) }
|
|
onNativeToggleSelect: function (index, mods) {
|
|
root.view.toggleNativeAlbumSelected(index, mods)
|
|
}
|
|
}
|
|
QbzAlphaStrip {
|
|
visible: root.view.albumsGroup === "alpha"
|
|
&& root.albumTotal > 0
|
|
anchors.right: parent.right
|
|
// Out past the tab's 32 padding to 12 from the window edge,
|
|
// which is where LibraryView.qml:1269 puts the same strip.
|
|
anchors.rightMargin: -20
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
jumps: collection.alphaJumps
|
|
completeAlphabet: true
|
|
onJump: function (ordinal, index) { collection.jumpToEntry(index) }
|
|
}
|
|
}
|
|
}
|
|
}
|