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
92 lines
4.0 KiB
QML
92 lines
4.0 KiB
QML
// Vertical A-Z jump strip (favorites/FavoritesView.slint:398 `AlphaStrip`;
|
|
// LocalLibraryView.slint:577 is a 1:1 lift of the same component). 18px
|
|
// gutter, 15px rows, 9px semibold muted letters that go accent on hover.
|
|
// Emits jump(ordinal, index); the host scrolls its own view — exactly like
|
|
// the Slint, which scrolls proportionally on the grouped grids (:1996) and by
|
|
// row index on the uniform track list (:1687).
|
|
//
|
|
// PROMOTED from views/local/AlphaStrip.qml, unchanged except for the import
|
|
// depth — same move QbzMultiSelectBar made and for the same reason: the Slint
|
|
// component was always shared (Local Library albums/artists/tracks AND the
|
|
// Library favorites tabs), so the "local" folder was a naming accident. The
|
|
// old views/local/AlphaStrip.qml is GONE; this file is the only copy.
|
|
// Call sites: views/local/{LocalAlbumsTab,LocalArtistsTab,LocalTracksTab}.qml,
|
|
// views/library/{LibraryAlbumsList}.qml and views/LibraryView.qml.
|
|
|
|
import QtQuick
|
|
import com.blitzfc.qbz
|
|
import "../theme"
|
|
|
|
Item {
|
|
id: root
|
|
|
|
/// [{ letter, index }] — index = the row ordinal in the flat model.
|
|
property var jumps: []
|
|
/// Paint the stable # A-Z affordance even when a query has no row for a
|
|
/// letter. Missing buckets are deliberately inert and dimmed; present
|
|
/// buckets retain their exact native/global row index.
|
|
property bool completeAlphabet: false
|
|
signal jump(int ordinal, int index)
|
|
|
|
function entryAt(position) {
|
|
if (!root.completeAlphabet)
|
|
return (root.jumps || [])[position] || ({ "letter": "", "index": -1 })
|
|
var targets = ({})
|
|
var source = root.jumps || []
|
|
for (var i = 0; i < source.length; i++) {
|
|
var letter = String(source[i].letter || "#").toUpperCase()
|
|
if (letter < "A" || letter > "Z") letter = "#"
|
|
if (targets[letter] === undefined)
|
|
targets[letter] = Number(source[i].index)
|
|
}
|
|
var letter = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(position)
|
|
return { "letter": letter,
|
|
"index": targets[letter] === undefined ? -1 : targets[letter] }
|
|
}
|
|
|
|
QbzTheme { id: theme }
|
|
|
|
width: 18
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
spacing: 0
|
|
Repeater {
|
|
// An integer model makes the full rail structural: it always
|
|
// creates exactly 27 delegates, regardless of when the async
|
|
// jump document lands or how a JS-array binding is invalidated.
|
|
model: root.completeAlphabet ? 27 : (root.jumps || []).length
|
|
delegate: Item {
|
|
id: cell
|
|
required property int index
|
|
readonly property var entry: root.entryAt(index)
|
|
width: 18
|
|
// A complete rail is 27 entries (# + A-Z). Keep the reference
|
|
// 15px row when it fits, then compress uniformly on short
|
|
// windows instead of painting letters outside the viewport.
|
|
height: Math.max(1, Math.min(15,
|
|
root.height / Math.max(1, root.completeAlphabet
|
|
? 27 : (root.jumps || []).length)))
|
|
Text {
|
|
anchors.fill: parent
|
|
text: cell.entry.letter
|
|
color: cell.entry.index < 0 ? theme.alphaTier(24)
|
|
: cellArea.containsMouse ? theme.accent : theme.textMuted
|
|
font.pixelSize: Math.min(9, Math.max(7, parent.height - 1))
|
|
font.weight: theme.weightSemibold
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
MouseArea {
|
|
id: cellArea
|
|
anchors.fill: parent
|
|
enabled: cell.entry.index >= 0
|
|
hoverEnabled: true
|
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
onClicked: root.jump(cell.index, cell.entry.index)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|