refactor(metadata): split editor workspace
Give track editing a dense spreadsheet pane, move album tags to an independent sidebar, and isolate remote metadata and artwork lookup in a loading-aware popup. cx
This commit is contained in:
4 files changed
+1055
-787
No files matched your search
@@ -326,791 +326,13 @@ Item {
|
||||
visible: QbzTagEditor.editorLoading || !root.seeded
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: scroll
|
||||
visible: root.seeded && !QbzTagEditor.editorLoading
|
||||
TagEditorWorkspace {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: scroll.width - 14
|
||||
spacing: 18
|
||||
|
||||
Text {
|
||||
text: root.tr("Album")
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontSection
|
||||
font.weight: theme.weightSemibold
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 154
|
||||
spacing: 16
|
||||
|
||||
Rectangle {
|
||||
width: 154
|
||||
height: 154
|
||||
radius: theme.radiusMd
|
||||
color: theme.surfaceElevated
|
||||
border.width: 1
|
||||
border.color: theme.borderSubtle
|
||||
clip: true
|
||||
Image {
|
||||
id: albumArtwork
|
||||
anchors.fill: parent
|
||||
source: root.artwork.previewPath || ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: false
|
||||
visible: source !== ""
|
||||
}
|
||||
QbzIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "disc-3"
|
||||
width: 42
|
||||
height: 42
|
||||
tintName: "muted"
|
||||
visible: !albumArtwork.visible
|
||||
}
|
||||
QbzSpinner {
|
||||
anchors.centerIn: parent
|
||||
size: 26
|
||||
visible: QbzTagEditor.artworkLoading
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - 170
|
||||
spacing: 8
|
||||
Row {
|
||||
id: artworkActions
|
||||
width: parent.width
|
||||
spacing: 8
|
||||
SettingsButton {
|
||||
text: root.artwork.previewPath ? root.tr("Choose another file") : root.tr("Choose file")
|
||||
iconName: "image-plus"
|
||||
minWidth: 0
|
||||
enabled: !QbzTagEditor.artworkLoading
|
||||
onClicked: QbzTagEditor.chooseArtwork()
|
||||
}
|
||||
SettingsButton {
|
||||
visible: (root.artwork.token || "") !== ""
|
||||
text: root.tr("Revert selection")
|
||||
iconName: "rotate-ccw"
|
||||
minWidth: 0
|
||||
enabled: !QbzTagEditor.artworkLoading
|
||||
onClicked: QbzTagEditor.clearArtwork()
|
||||
}
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: Math.max(0, artworkActions.width
|
||||
- artworkActions.children[0].width
|
||||
- artworkActions.children[1].width
|
||||
- artworkActions.spacing * 2)
|
||||
text: (root.artwork.source || "")
|
||||
+ (root.artwork.width ? " · " + root.artwork.width + " × " + root.artwork.height : "")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
Row {
|
||||
spacing: 8
|
||||
QbzSelect {
|
||||
width: 150
|
||||
menuWidth: 150
|
||||
options: ["MusicBrainz", "Discogs", "Last.fm"]
|
||||
currentIndex: root.artworkProvider === "discogs" ? 1
|
||||
: root.artworkProvider === "lastfm" ? 2 : 0
|
||||
enabled: !QbzTagEditor.artworkSearching && !QbzTagEditor.artworkLoading
|
||||
onSelected: function(index) {
|
||||
root.artworkProvider = index === 1 ? "discogs"
|
||||
: index === 2 ? "lastfm" : "musicbrainz"
|
||||
}
|
||||
}
|
||||
SettingsButton {
|
||||
text: QbzTagEditor.artworkSearching ? root.tr("Searching…") : root.tr("Find artwork")
|
||||
iconName: "search"
|
||||
minWidth: 0
|
||||
enabled: !QbzTagEditor.artworkSearching && !QbzTagEditor.artworkLoading
|
||||
onClicked: QbzTagEditor.searchArtwork(
|
||||
root.artworkProvider,
|
||||
root.albumTitle,
|
||||
root.albumArtist,
|
||||
root.catalogNumber)
|
||||
}
|
||||
}
|
||||
ListView {
|
||||
id: artworkList
|
||||
width: parent.width
|
||||
height: 92
|
||||
orientation: ListView.Horizontal
|
||||
spacing: 8
|
||||
clip: true
|
||||
model: root.artworkResults
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
width: 196
|
||||
height: 88
|
||||
radius: theme.radiusSm
|
||||
color: artMouse.containsMouse ? theme.surfaceHover : theme.surfaceElevated
|
||||
border.width: 1
|
||||
border.color: theme.borderSubtle
|
||||
Image {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 4
|
||||
width: 80
|
||||
source: modelData.previewUrl || ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
}
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 92
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 3
|
||||
Text {
|
||||
width: parent.width
|
||||
text: modelData.title || ""
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontLegal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
text: modelData.source || ""
|
||||
color: theme.textSecondary
|
||||
font.pixelSize: theme.fontLegal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
text: modelData.detail || ""
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: artMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: !QbzTagEditor.artworkLoading
|
||||
onClicked: QbzTagEditor.selectArtwork(parent.modelData.id || "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Grid {
|
||||
width: parent.width
|
||||
columns: 2
|
||||
columnSpacing: 16
|
||||
rowSpacing: 12
|
||||
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("Album title"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.albumTitle
|
||||
onEdited: function(value) { root.albumTitle = value }
|
||||
onCommitted: function(value) { root.albumTitle = value }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("Album artists (ordered; separate with semicolons)"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.albumArtistsText
|
||||
onEdited: function(value) { root.albumArtistsText = value }
|
||||
onCommitted: function(value) { root.albumArtistsText = value }
|
||||
}
|
||||
}
|
||||
Row {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 8
|
||||
QbzToggle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: root.compilation
|
||||
onToggled: function(value) { root.compilation = value }
|
||||
}
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.tr("Compilation / Various Artists")
|
||||
color: theme.textSecondary
|
||||
font.pixelSize: theme.fontBody
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("Album artist"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.albumArtist
|
||||
onEdited: function(value) { root.albumArtist = value }
|
||||
onCommitted: function(value) { root.albumArtist = value }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("Genre"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.genre
|
||||
onEdited: function(value) { root.genre = value }
|
||||
onCommitted: function(value) { root.genre = value }
|
||||
}
|
||||
}
|
||||
Row {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 12
|
||||
Column {
|
||||
width: (parent.width - 12) * 0.34
|
||||
spacing: 5
|
||||
Text { text: root.tr("Year"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.year
|
||||
onEdited: function(value) { root.year = value }
|
||||
onCommitted: function(value) { root.year = value }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (parent.width - 12) * 0.66
|
||||
spacing: 5
|
||||
Text { text: root.tr("Catalog number"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.catalogNumber
|
||||
onEdited: function(value) { root.catalogNumber = value }
|
||||
onCommitted: function(value) { root.catalogNumber = value }
|
||||
}
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("MusicBrainz release ID"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.musicbrainzReleaseId
|
||||
onEdited: function(value) { root.musicbrainzReleaseId = value }
|
||||
onCommitted: function(value) { root.musicbrainzReleaseId = value }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("MusicBrainz release-group ID"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.musicbrainzReleaseGroupId
|
||||
onEdited: function(value) { root.musicbrainzReleaseGroupId = value }
|
||||
onCommitted: function(value) { root.musicbrainzReleaseGroupId = value }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("MusicBrainz album artist IDs"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.musicbrainzAlbumArtistIdsText
|
||||
onEdited: function(value) { root.musicbrainzAlbumArtistIdsText = value }
|
||||
onCommitted: function(value) { root.musicbrainzAlbumArtistIdsText = value }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (content.width - 16) / 2
|
||||
spacing: 5
|
||||
Text { text: root.tr("Discogs release ID"); color: theme.textSecondary; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: root.discogsReleaseId
|
||||
onEdited: function(value) { root.discogsReleaseId = value }
|
||||
onCommitted: function(value) { root.discogsReleaseId = value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { width: parent.width; height: 1; color: theme.borderSubtle }
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: 16
|
||||
|
||||
Column {
|
||||
width: (parent.width - 16) * 0.53
|
||||
spacing: 10
|
||||
Text {
|
||||
text: root.tr("Tag layers")
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontSection
|
||||
font.weight: theme.weightSemibold
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
text: root.inspection.error
|
||||
? root.inspection.error
|
||||
: root.tr("Canonical") + ": "
|
||||
+ root.layerSummary(root.inspection.canonicalLayers || [])
|
||||
color: root.inspection.error ? theme.danger : theme.textSecondary
|
||||
font.pixelSize: theme.fontBody
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
text: root.tr("Detected") + ": "
|
||||
+ root.layerSummary(root.inspection.presentLayers || [])
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
Rectangle {
|
||||
visible: (root.inspection.conflictingFiles || 0) > 0
|
||||
width: parent.width
|
||||
height: conflictText.implicitHeight + 18
|
||||
radius: theme.radiusSm
|
||||
color: theme.warningBg
|
||||
Text {
|
||||
id: conflictText
|
||||
anchors.fill: parent
|
||||
anchors.margins: 9
|
||||
text: root.tr("Some files contain conflicting tag layers. The canonical layer wins unless synchronization is enabled.")
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontLegal
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - 16) * 0.47
|
||||
spacing: 10
|
||||
Text {
|
||||
text: root.tr("Find metadata")
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontSection
|
||||
font.weight: theme.weightSemibold
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: 8
|
||||
QbzSelect {
|
||||
width: 150
|
||||
menuWidth: 150
|
||||
options: ["MusicBrainz", "Discogs"]
|
||||
currentIndex: root.remoteProvider === "discogs" ? 1 : 0
|
||||
enabled: !QbzTagEditor.remoteSearching && !QbzTagEditor.remoteLoading
|
||||
onSelected: function(index) {
|
||||
root.remoteProvider = index === 1 ? "discogs" : "musicbrainz"
|
||||
}
|
||||
}
|
||||
SettingsButton {
|
||||
text: QbzTagEditor.remoteSearching ? root.tr("Searching…") : root.tr("Search")
|
||||
iconName: "search"
|
||||
minWidth: 0
|
||||
enabled: !QbzTagEditor.remoteSearching && !QbzTagEditor.remoteLoading
|
||||
onClicked: QbzTagEditor.searchRemote(root.remoteProvider, root.albumTitle, root.albumArtist)
|
||||
}
|
||||
}
|
||||
ListView {
|
||||
id: resultList
|
||||
width: parent.width
|
||||
height: 116
|
||||
clip: true
|
||||
spacing: 4
|
||||
model: root.remoteResults
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
width: resultList.width
|
||||
height: 54
|
||||
radius: theme.radiusSm
|
||||
color: resultArea.containsMouse ? theme.surfaceHover : theme.surfaceElevated
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.right: openResult.left
|
||||
anchors.rightMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
Text {
|
||||
width: parent.width
|
||||
text: modelData.title || ""
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontBody
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
text: (modelData.artist || "")
|
||||
+ (modelData.year ? " · " + modelData.year : "")
|
||||
+ (modelData.track_count ? " · " + modelData.track_count + " " + root.tr("tracks") : "")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
QbzIcon {
|
||||
id: openResult
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: QbzTagEditor.remoteLoading ? "loader-circle" : "chevron-right"
|
||||
width: 15
|
||||
height: 15
|
||||
tintName: "muted"
|
||||
}
|
||||
MouseArea {
|
||||
id: resultArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: !QbzTagEditor.remoteLoading
|
||||
onClicked: QbzTagEditor.loadRemote(root.remoteProvider, parent.modelData.provider_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row {
|
||||
visible: root.remoteMetadata !== null
|
||||
spacing: 8
|
||||
SettingsButton {
|
||||
text: root.tr("Open source")
|
||||
iconName: "external-link"
|
||||
minWidth: 0
|
||||
onClicked: QbzTagEditor.openRemote(String(root.remoteMetadata.provider || root.remoteProvider), root.remoteMetadata.provider_id || "")
|
||||
}
|
||||
SettingsButton {
|
||||
text: root.tr("Apply to form")
|
||||
iconName: "download"
|
||||
minWidth: 0
|
||||
onClicked: root.applyRemote()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { width: parent.width; height: 1; color: theme.borderSubtle }
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
Text {
|
||||
text: root.tr("Tracks")
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontSection
|
||||
font.weight: theme.weightSemibold
|
||||
}
|
||||
Text {
|
||||
width: parent.width - parent.children[0].implicitWidth
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: root.tr("File names are shown for reference and cannot be changed here.")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
color: theme.surfaceElevated
|
||||
border.width: 1
|
||||
border.color: theme.borderSubtle
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
width: 64
|
||||
height: parent.height
|
||||
leftPadding: 10
|
||||
text: root.tr("Disc")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Text {
|
||||
width: 72
|
||||
height: parent.height
|
||||
leftPadding: 10
|
||||
text: root.tr("Track")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Text {
|
||||
width: Math.max(160, parent.width - 64 - 72 - 220 - 240 - 4)
|
||||
height: parent.height
|
||||
leftPadding: 10
|
||||
text: root.tr("Title")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Text {
|
||||
width: 220
|
||||
height: parent.height
|
||||
leftPadding: 10
|
||||
text: root.tr("Artist credit")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Text {
|
||||
width: 240
|
||||
height: parent.height
|
||||
leftPadding: 10
|
||||
text: root.tr("File")
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
ListView {
|
||||
id: trackList
|
||||
width: parent.width
|
||||
height: Math.min(360, Math.max(112, root.tracks.length * 36))
|
||||
clip: true
|
||||
spacing: 0
|
||||
model: root.tracks
|
||||
delegate: Rectangle {
|
||||
id: trackDelegate
|
||||
required property var modelData
|
||||
required property int index
|
||||
width: trackList.width
|
||||
height: 36
|
||||
color: trackDelegate.index % 2
|
||||
? theme.surfaceElevated : "transparent"
|
||||
border.width: 1
|
||||
border.color: theme.borderSubtle
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
width: 64
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
TextInput {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 8
|
||||
text: modelData.discNumber
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontBody
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
selectByMouse: true
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
onTextEdited: modelData.discNumber = text
|
||||
onActiveFocusChanged: if (activeFocus)
|
||||
root.selectedTrackIndex = trackDelegate.index
|
||||
}
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Rectangle {
|
||||
width: 72
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
TextInput {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 8
|
||||
text: modelData.trackNumber
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontBody
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
selectByMouse: true
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
onTextEdited: modelData.trackNumber = text
|
||||
onActiveFocusChanged: if (activeFocus)
|
||||
root.selectedTrackIndex = trackDelegate.index
|
||||
}
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Rectangle {
|
||||
width: Math.max(160, parent.width - 64 - 72 - 220 - 240 - 4)
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
TextInput {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 8
|
||||
text: modelData.title
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontBody
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
selectByMouse: true
|
||||
clip: true
|
||||
onTextEdited: modelData.title = text
|
||||
onActiveFocusChanged: if (activeFocus)
|
||||
root.selectedTrackIndex = trackDelegate.index
|
||||
}
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Rectangle {
|
||||
width: 220
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
TextInput {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 8
|
||||
text: modelData.artistCredit
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontBody
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
selectByMouse: true
|
||||
clip: true
|
||||
onTextEdited: modelData.artistCredit = text
|
||||
onActiveFocusChanged: if (activeFocus)
|
||||
root.selectedTrackIndex = trackDelegate.index
|
||||
}
|
||||
}
|
||||
Rectangle { width: 1; height: parent.height; color: theme.borderSubtle }
|
||||
Text {
|
||||
id: fileName
|
||||
width: 240
|
||||
height: parent.height
|
||||
leftPadding: 10
|
||||
rightPadding: 8
|
||||
text: modelData.fileName
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideMiddle
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.selectedTrackIndex = trackDelegate.index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: trackDetails
|
||||
property var rowData: root.selectedTrackIndex >= 0
|
||||
&& root.selectedTrackIndex < root.tracks.length
|
||||
? root.tracks[root.selectedTrackIndex] : null
|
||||
visible: rowData !== null
|
||||
width: parent.width
|
||||
height: visible ? 190 : 0
|
||||
color: theme.surfaceElevated
|
||||
border.width: 1
|
||||
border.color: theme.borderSubtle
|
||||
radius: theme.radiusSm
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 8
|
||||
Row {
|
||||
width: parent.width
|
||||
Text {
|
||||
text: root.tr("Selected track details")
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: theme.fontBody
|
||||
font.weight: theme.weightSemibold
|
||||
}
|
||||
Text {
|
||||
width: parent.width - parent.children[0].implicitWidth
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: trackDetails.rowData ? trackDetails.rowData.fileName : ""
|
||||
color: theme.textMuted
|
||||
font.pixelSize: theme.fontLegal
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
}
|
||||
Grid {
|
||||
width: parent.width
|
||||
columns: 2
|
||||
columnSpacing: 12
|
||||
rowSpacing: 7
|
||||
Column {
|
||||
width: (trackDetails.width - 32) / 2
|
||||
spacing: 3
|
||||
Text { text: root.tr("Artists (ordered; semicolon separated)"); color: theme.textMuted; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: trackDetails.rowData ? root.listText(trackDetails.rowData.artists) : ""
|
||||
onEdited: function(value) { if (trackDetails.rowData) trackDetails.rowData.artists = root.splitList(value) }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (trackDetails.width - 32) / 2
|
||||
spacing: 3
|
||||
Text { text: root.tr("Composers"); color: theme.textMuted; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: trackDetails.rowData ? root.listText(trackDetails.rowData.composers) : ""
|
||||
onEdited: function(value) { if (trackDetails.rowData) trackDetails.rowData.composers = root.splitList(value) }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (trackDetails.width - 32) / 2
|
||||
spacing: 3
|
||||
Text { text: root.tr("Performers"); color: theme.textMuted; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: trackDetails.rowData ? root.listText(trackDetails.rowData.performers) : ""
|
||||
onEdited: function(value) { if (trackDetails.rowData) trackDetails.rowData.performers = root.splitList(value) }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (trackDetails.width - 32) / 2
|
||||
spacing: 3
|
||||
Text { text: root.tr("MusicBrainz artist IDs"); color: theme.textMuted; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: trackDetails.rowData ? root.listText(trackDetails.rowData.musicbrainzArtistIds) : ""
|
||||
onEdited: function(value) { if (trackDetails.rowData) trackDetails.rowData.musicbrainzArtistIds = root.splitList(value) }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (trackDetails.width - 32) / 2
|
||||
spacing: 3
|
||||
Text { text: root.tr("MusicBrainz recording ID"); color: theme.textMuted; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: trackDetails.rowData ? trackDetails.rowData.musicbrainzRecordingId : ""
|
||||
onEdited: function(value) { if (trackDetails.rowData) trackDetails.rowData.musicbrainzRecordingId = value }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
width: (trackDetails.width - 32) / 2
|
||||
spacing: 3
|
||||
Text { text: root.tr("MusicBrainz track ID"); color: theme.textMuted; font.pixelSize: theme.fontLegal }
|
||||
QbzLineEdit {
|
||||
width: parent.width
|
||||
text: trackDetails.rowData ? trackDetails.rowData.musicbrainzTrackId : ""
|
||||
onEdited: function(value) { if (trackDetails.rowData) trackDetails.rowData.musicbrainzTrackId = value }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QbzScrollBar {
|
||||
target: scroll
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
anchors.margins: 16
|
||||
visible: root.seeded && !QbzTagEditor.editorLoading
|
||||
editor: root
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle { y: body.y + body.height; width: parent.width; height: 1; color: theme.borderSubtle }
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user