diff --git a/src/qml/AlbumView.qml b/src/qml/AlbumView.qml --- a/src/qml/AlbumView.qml +++ b/src/qml/AlbumView.qml @@ -75,6 +75,7 @@ rating: model.rating isFirstTrackOfDisc: true isSingleDiscAlbum: true + isSelected: albumGridView.currentIndex === index isAlternateColor: (index % 2) === 1 mediaTrack.onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Track, diff --git a/src/qml/ContentView.qml b/src/qml/ContentView.qml --- a/src/qml/ContentView.qml +++ b/src/qml/ContentView.qml @@ -260,11 +260,6 @@ } Rectangle { - border { - color: (mainContentView.activeFocus ? myPalette.highlight : myPalette.base) - width: 1 - } - radius: 3 color: myPalette.base diff --git a/src/qml/FrequentlyPlayedTracks.qml b/src/qml/FrequentlyPlayedTracks.qml --- a/src/qml/FrequentlyPlayedTracks.qml +++ b/src/qml/FrequentlyPlayedTracks.qml @@ -65,14 +65,16 @@ title: model.title artist: model.artist album: (model.album !== undefined && model.album !== '' ? model.album : '') - albumArtist: model.albumArtist + albumArtist: (model.albumArtist !== undefined && model.albumArtist !== '' ? model.albumArtist : '') duration: model.duration imageUrl: (model.imageUrl !== undefined && model.imageUrl !== '' ? model.imageUrl : '') trackNumber: model.trackNumber discNumber: model.discNumber rating: model.rating isFirstTrackOfDisc: false isSingleDiscAlbum: model.isSingleDiscAlbum + isSelected: listView.currentIndex === index + isAlternateColor: (index % 2) === 1 onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, @@ -82,7 +84,10 @@ ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onClicked: contentDirectoryView.currentIndex = index + onClicked: { + listView.currentIndex = index + entry.forceActiveFocus() + } } Loader { diff --git a/src/qml/GridBrowserDelegate.qml b/src/qml/GridBrowserDelegate.qml --- a/src/qml/GridBrowserDelegate.qml +++ b/src/qml/GridBrowserDelegate.qml @@ -42,8 +42,24 @@ Keys.onReturnPressed: open() Keys.onEnterPressed: open() + Rectangle { + anchors.fill: parent + z: 1 + + border.color: gridEntry.activeFocus ? myPalette.highlight : "transparent" + + Behavior on border.color { + ColorAnimation { + duration: 300 + } + } + + radius: 3 + } + ColumnLayout { anchors.fill: parent + z: 2 spacing: 0 @@ -231,6 +247,7 @@ Layout.maximumWidth: gridEntry.width * 0.9 Layout.minimumWidth: Layout.maximumWidth Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + Layout.bottomMargin: delegateDisplaySecondaryText ? 0 : elisaTheme.layoutVerticalMargin elide: Text.ElideRight } @@ -246,6 +263,7 @@ // See https://bugreports.qt.io/browse/QTBUG-49646 horizontalAlignment: Text.AlignHCenter + Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.maximumWidth: gridEntry.width * 0.9 Layout.minimumWidth: Layout.maximumWidth Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom @@ -299,7 +317,7 @@ NumberAnimation { properties: "opacity" easing.type: Easing.InOutQuad - duration: 100 + duration: 300 } } }, @@ -309,7 +327,7 @@ NumberAnimation { properties: "opacity" easing.type: Easing.InOutQuad - duration: 100 + duration: 300 } PropertyAction { properties: "active" diff --git a/src/qml/GridBrowserView.qml b/src/qml/GridBrowserView.qml --- a/src/qml/GridBrowserView.qml +++ b/src/qml/GridBrowserView.qml @@ -102,7 +102,6 @@ id: contentDirectoryView anchors.topMargin: 20 - focus: true activeFocusOnTab: true keyNavigationEnabled: true diff --git a/src/qml/ListBrowserView.qml b/src/qml/ListBrowserView.qml --- a/src/qml/ListBrowserView.qml +++ b/src/qml/ListBrowserView.qml @@ -98,16 +98,18 @@ Layout.fillHeight: true Layout.fillWidth: true + Layout.margins: 2 ListView { id: contentDirectoryView anchors.topMargin: 20 anchors.fill: parent - focus: true activeFocusOnTab: true keyNavigationEnabled: true + currentIndex: -1 + ScrollBar.vertical: ScrollBar { id: scrollBar } @@ -119,6 +121,10 @@ flickable: contentDirectoryView anchors.fill: contentDirectoryView } + + onCountChanged: if (count === 0) { + currentIndex = -1; + } } } } diff --git a/src/qml/MediaAlbumTrackDelegate.qml b/src/qml/MediaAlbumTrackDelegate.qml --- a/src/qml/MediaAlbumTrackDelegate.qml +++ b/src/qml/MediaAlbumTrackDelegate.qml @@ -35,6 +35,7 @@ property alias rating: mediaTrack.rating property alias isFirstTrackOfDisc: mediaTrack.isFirstTrackOfDisc property alias isSingleDiscAlbum: mediaTrack.isSingleDiscAlbum + property alias isSelected: mediaTrack.isSelected property alias isAlternateColor: mediaTrack.isAlternateColor ColumnLayout { diff --git a/src/qml/MediaTrackDelegate.qml b/src/qml/MediaTrackDelegate.qml --- a/src/qml/MediaTrackDelegate.qml +++ b/src/qml/MediaTrackDelegate.qml @@ -39,6 +39,7 @@ property int rating property bool isFirstTrackOfDisc property bool isSingleDiscAlbum + property bool isSelected property bool isAlternateColor property bool detailedView: true @@ -93,264 +94,264 @@ id: rowRoot anchors.fill: parent + z: 1 color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) + } - MouseArea { - id: hoverArea + MouseArea { + id: hoverArea - anchors.fill: parent + anchors.fill: parent + z: 2 - hoverEnabled: true - focus: true - acceptedButtons: Qt.LeftButton + hoverEnabled: true + acceptedButtons: Qt.LeftButton - onClicked: { - hoverArea.forceActiveFocus() - mediaTrack.clicked() - } + onClicked: { + mediaTrack.clicked() + } - onDoubleClicked: enqueue(databaseId, title) + onDoubleClicked: enqueue(databaseId, title) - RowLayout { - anchors.fill: parent - spacing: 0 + RowLayout { + anchors.fill: parent + spacing: 0 - LabelWithToolTip { - id: mainLabel + LabelWithToolTip { + id: mainLabel - visible: !detailedView + visible: !detailedView - text: { - if (trackNumber !== 0) { - if (artist !== albumArtist) - return i18nc("%1: track number. %2: track title. %3: artist name", - "%1 - %2 - %3", - trackNumber.toLocaleString(Qt.locale(), 'f', 0), - title, artist); - else - return i18nc("%1: track number. %2: track title.", - "%1 - %2", - trackNumber.toLocaleString(Qt.locale(), 'f', 0), - title); - } else { - if (artist !== albumArtist) - return i18nc("%1: track title. %2: artist name", - "%1 - %2", - title, artist); - else - return i18nc("%1: track title", - "%1", - title); - } + text: { + if (trackNumber !== 0) { + if (artist !== albumArtist) + return i18nc("%1: track number. %2: track title. %3: artist name", + "%1 - %2 - %3", + trackNumber.toLocaleString(Qt.locale(), 'f', 0), + title, artist); + else + return i18nc("%1: track number. %2: track title.", + "%1 - %2", + trackNumber.toLocaleString(Qt.locale(), 'f', 0), + title); + } else { + if (artist !== albumArtist) + return i18nc("%1: track title. %2: artist name", + "%1 - %2", + title, artist); + else + return i18nc("%1: track title", + "%1", + title); } + } - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + horizontalAlignment: Text.AlignLeft - color: myPalette.text + color: myPalette.text - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - Layout.fillWidth: true - Layout.leftMargin: { - if (!LayoutMirroring.enabled) - return (!isSingleDiscAlbum ? elisaTheme.layoutHorizontalMargin * 4 : elisaTheme.layoutHorizontalMargin) - else - return 0 - } - Layout.rightMargin: { - if (LayoutMirroring.enabled) - return (!isSingleDiscAlbum ? elisaTheme.layoutHorizontalMargin * 4 : elisaTheme.layoutHorizontalMargin) - else - return 0 - } + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillWidth: true + Layout.leftMargin: { + if (!LayoutMirroring.enabled) + return (!isSingleDiscAlbum ? elisaTheme.layoutHorizontalMargin * 4 : elisaTheme.layoutHorizontalMargin) + else + return 0 + } + Layout.rightMargin: { + if (LayoutMirroring.enabled) + return (!isSingleDiscAlbum ? elisaTheme.layoutHorizontalMargin * 4 : elisaTheme.layoutHorizontalMargin) + else + return 0 } + } - Item { - Layout.preferredHeight: mediaTrack.height * 0.9 - Layout.preferredWidth: mediaTrack.height * 0.9 + Item { + Layout.preferredHeight: mediaTrack.height * 0.9 + Layout.preferredWidth: mediaTrack.height * 0.9 - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - visible: detailedView + visible: detailedView - Image { - id: coverImageElement + Image { + id: coverImageElement - anchors.fill: parent + anchors.fill: parent - sourceSize.width: mediaTrack.height * 0.9 - sourceSize.height: mediaTrack.height * 0.9 - fillMode: Image.PreserveAspectFit - smooth: true + sourceSize.width: mediaTrack.height * 0.9 + sourceSize.height: mediaTrack.height * 0.9 + fillMode: Image.PreserveAspectFit + smooth: true - source: (imageUrl != '' ? imageUrl : Qt.resolvedUrl(elisaTheme.defaultAlbumImage)) + source: (imageUrl != '' ? imageUrl : Qt.resolvedUrl(elisaTheme.defaultAlbumImage)) - asynchronous: true + asynchronous: true - layer.enabled: imageUrl != '' + layer.enabled: imageUrl != '' - layer.effect: DropShadow { - source: coverImageElement + layer.effect: DropShadow { + source: coverImageElement - radius: 10 - spread: 0.1 - samples: 21 + radius: 10 + spread: 0.1 + samples: 21 - color: myPalette.shadow - } + color: myPalette.shadow } } + } - ColumnLayout { - visible: detailedView + ColumnLayout { + visible: detailedView - Layout.fillWidth: true - Layout.fillHeight: true - Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignLeft - spacing: 0 + spacing: 0 - LabelWithToolTip { - id: mainLabelDetailed + LabelWithToolTip { + id: mainLabelDetailed - text: { - if (trackNumber !== 0) { - return i18nc("%1: track number. %2: track title", "%1 - %2", - trackNumber.toLocaleString(Qt.locale(), 'f', 0), title); - } else { - return title; - } + text: { + if (trackNumber !== 0) { + return i18nc("%1: track number. %2: track title", "%1 - %2", + trackNumber.toLocaleString(Qt.locale(), 'f', 0), title); + } else { + return title; } + } - horizontalAlignment: Text.AlignLeft + horizontalAlignment: Text.AlignLeft - font.weight: Font.Bold - color: myPalette.text + font.weight: Font.Bold + color: myPalette.text - Layout.alignment: Qt.AlignLeft | Qt.AlignTop - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.fillWidth: true - Layout.topMargin: elisaTheme.layoutVerticalMargin / 2 + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.fillWidth: true + Layout.topMargin: elisaTheme.layoutVerticalMargin / 2 - elide: Text.ElideRight - } + elide: Text.ElideRight + } - Item { - Layout.fillHeight: true - } + Item { + Layout.fillHeight: true + } - LabelWithToolTip { - id: artistLabel + LabelWithToolTip { + id: artistLabel - text: { - var labelText = "" - if (artist) { - labelText += artist - } - if (album !== '') { - labelText += ' - ' + album - if (!isSingleDiscAlbum) { - labelText += ' - CD ' + discNumber - } + text: { + var labelText = "" + if (artist) { + labelText += artist + } + if (album !== '') { + labelText += ' - ' + album + if (!isSingleDiscAlbum) { + labelText += ' - CD ' + discNumber } - return labelText; } - horizontalAlignment: Text.AlignLeft + return labelText; + } + horizontalAlignment: Text.AlignLeft - font.weight: Font.Light - font.italic: true - color: myPalette.text + font.weight: Font.Light + font.italic: true + color: myPalette.text - Layout.alignment: Qt.AlignLeft | Qt.AlignBottom - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.fillWidth: true - Layout.bottomMargin: elisaTheme.layoutVerticalMargin / 2 + Layout.alignment: Qt.AlignLeft | Qt.AlignBottom + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.fillWidth: true + Layout.bottomMargin: elisaTheme.layoutVerticalMargin / 2 - elide: Text.ElideRight - } + elide: Text.ElideRight } + } - Loader { - id: hoverLoader - active: false + Loader { + id: hoverLoader + active: false - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - Layout.rightMargin: 10 + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.rightMargin: 10 - z: 1 - opacity: 0 + z: 1 + opacity: 0 - sourceComponent: Row { - anchors.centerIn: parent + sourceComponent: Row { + anchors.centerIn: parent - Controls1.ToolButton { - id: detailsButton + Controls1.ToolButton { + id: detailsButton - height: elisaTheme.delegateHeight - width: elisaTheme.delegateHeight + height: elisaTheme.delegateHeight + width: elisaTheme.delegateHeight - action: viewDetailsAction - } + action: viewDetailsAction + } - Controls1.ToolButton { - id: enqueueButton + Controls1.ToolButton { + id: enqueueButton - height: elisaTheme.delegateHeight - width: elisaTheme.delegateHeight + height: elisaTheme.delegateHeight + width: elisaTheme.delegateHeight - action: enqueueAction - } + action: enqueueAction + } - Controls1.ToolButton { - id: clearAndEnqueueButton + Controls1.ToolButton { + id: clearAndEnqueueButton - scale: LayoutMirroring.enabled ? -1 : 1 + scale: LayoutMirroring.enabled ? -1 : 1 - height: elisaTheme.delegateHeight - width: elisaTheme.delegateHeight + height: elisaTheme.delegateHeight + width: elisaTheme.delegateHeight - action: replaceAndPlayAction - } + action: replaceAndPlayAction } } + } - RatingStar { - id: ratingWidget + RatingStar { + id: ratingWidget - starSize: elisaTheme.ratingStarSize + starSize: elisaTheme.ratingStarSize - starRating: rating + starRating: rating - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - Layout.leftMargin: elisaTheme.layoutHorizontalMargin - Layout.rightMargin: elisaTheme.layoutHorizontalMargin - } + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.leftMargin: elisaTheme.layoutHorizontalMargin + Layout.rightMargin: elisaTheme.layoutHorizontalMargin + } - LabelWithToolTip { - id: durationLabel + LabelWithToolTip { + id: durationLabel - text: duration + text: duration - font.weight: Font.Light - color: myPalette.text + font.weight: Font.Light + color: myPalette.text - horizontalAlignment: Text.AlignRight + horizontalAlignment: Text.AlignRight - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - } + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 } } } states: [ State { name: 'notSelected' - when: !hoverArea.containsMouse && !mediaTrack.activeFocus + when: !mediaTrack.activeFocus && !hoverArea.containsMouse && !mediaTrack.isSelected PropertyChanges { target: hoverLoader active: false @@ -367,10 +368,14 @@ target: rowRoot color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) } + PropertyChanges { + target: rowRoot + opacity: 1 + } }, State { - name: 'hoveredOrSelected' - when: hoverArea.containsMouse || mediaTrack.activeFocus + name: 'hovered' + when: !mediaTrack.activeFocus && hoverArea.containsMouse PropertyChanges { target: hoverLoader active: true @@ -383,51 +388,83 @@ target: ratingWidget hoverWidgetOpacity: 1.0 } + PropertyChanges { + target: rowRoot + color: myPalette.highlight + } + PropertyChanges { + target: rowRoot + opacity: 0.2 + } + }, + State { + name: 'selected' + when: !mediaTrack.activeFocus && mediaTrack.isSelected + PropertyChanges { + target: hoverLoader + active: false + } + PropertyChanges { + target: hoverLoader + opacity: 0.0 + } + PropertyChanges { + target: ratingWidget + hoverWidgetOpacity: 1.0 + } PropertyChanges { target: rowRoot color: myPalette.mid } + PropertyChanges { + target: rowRoot + opacity: 1. + } + }, + State { + name: 'focused' + when: mediaTrack.activeFocus + PropertyChanges { + target: hoverLoader + active: true + } + PropertyChanges { + target: hoverLoader + opacity: 1.0 + } + PropertyChanges { + target: ratingWidget + hoverWidgetOpacity: 1.0 + } + PropertyChanges { + target: rowRoot + color: myPalette.highlight + } + PropertyChanges { + target: rowRoot + opacity: 0.6 + } } ] transitions: [ Transition { - to: 'hoveredOrSelected' SequentialAnimation { PropertyAction { properties: "active" } ParallelAnimation { NumberAnimation { properties: "opacity, hoverWidgetOpacity" easing.type: Easing.InOutQuad - duration: 250 + duration: 200 } ColorAnimation { properties: "color" - duration: 250 + duration: 350 } } } - }, - Transition { - to: 'notSelected' - SequentialAnimation { - ParallelAnimation { - NumberAnimation { - properties: "opacity, hoverWidgetOpacity" - easing.type: Easing.InOutQuad - duration: 250 - } - ColorAnimation { - properties: "color" - duration: 250 - } - } - PropertyAction { - properties: "active" - } - } } ] } diff --git a/src/qml/NavigationActionBar.qml b/src/qml/NavigationActionBar.qml --- a/src/qml/NavigationActionBar.qml +++ b/src/qml/NavigationActionBar.qml @@ -21,9 +21,14 @@ import QtQuick.Controls 2.2 import QtQuick.Controls 1.4 as Controls1 -FocusScope { +ColumnLayout { id: navigationBar + spacing: 0 + + anchors.topMargin: elisaTheme.layoutVerticalMargin + anchors.bottomMargin: elisaTheme.layoutVerticalMargin + property string mainTitle property string secondaryTitle property url image @@ -73,290 +78,296 @@ onTriggered: sortOrder ? sort(Qt.DescendingOrder) : sort(Qt.AscendingOrder) } - ColumnLayout { - anchors.fill: parent + RowLayout { spacing: 0 + Layout.alignment: Qt.AlignTop + Layout.preferredHeight: elisaTheme.navigationBarHeight + Layout.minimumHeight: elisaTheme.navigationBarHeight + Layout.maximumHeight: elisaTheme.navigationBarHeight - anchors.topMargin: elisaTheme.layoutVerticalMargin - anchors.bottomMargin: elisaTheme.layoutVerticalMargin + Controls1.ToolButton { + action: goPreviousAction + objectName: 'goPreviousButton' - RowLayout { - spacing: 0 - Layout.alignment: Qt.AlignTop - Layout.preferredHeight: elisaTheme.navigationBarHeight - Layout.minimumHeight: elisaTheme.navigationBarHeight - Layout.maximumHeight: elisaTheme.navigationBarHeight + Keys.onReturnPressed: action.trigger() - Controls1.ToolButton { - action: goPreviousAction - objectName: 'goPreviousButton' + activeFocusOnTab: true + focus: enableGoBack + + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + visible: enableGoBack + } - Keys.onReturnPressed: action.trigger() + Image { + id: mainIcon + source: image - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - visible: enableGoBack - } + asynchronous: true - Image { - id: mainIcon - source: image + sourceSize.height: elisaTheme.coverImageSize / 2 + sourceSize.width: elisaTheme.coverImageSize / 2 - asynchronous: true + fillMode: Image.PreserveAspectFit - sourceSize.height: elisaTheme.coverImageSize / 2 - sourceSize.width: elisaTheme.coverImageSize / 2 + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - fillMode: Image.PreserveAspectFit + Layout.preferredHeight: elisaTheme.coverImageSize / 2 + Layout.minimumHeight: elisaTheme.coverImageSize / 2 + Layout.maximumHeight: elisaTheme.coverImageSize / 2 + Layout.preferredWidth: elisaTheme.coverImageSize / 2 + Layout.minimumWidth: elisaTheme.coverImageSize / 2 + Layout.maximumWidth: elisaTheme.coverImageSize / 2 + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + } - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + ColumnLayout { + Layout.preferredHeight: elisaTheme.coverImageSize / 1.9 + Layout.minimumHeight: elisaTheme.coverImageSize / 1.9 + Layout.maximumHeight: elisaTheme.coverImageSize / 1.9 - Layout.preferredHeight: elisaTheme.coverImageSize / 2 - Layout.minimumHeight: elisaTheme.coverImageSize / 2 - Layout.maximumHeight: elisaTheme.coverImageSize / 2 - Layout.preferredWidth: elisaTheme.coverImageSize / 2 - Layout.minimumWidth: elisaTheme.coverImageSize / 2 - Layout.maximumWidth: elisaTheme.coverImageSize / 2 - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - } + spacing: 0 - ColumnLayout { - Layout.preferredHeight: elisaTheme.coverImageSize / 1.9 - Layout.minimumHeight: elisaTheme.coverImageSize / 1.9 - Layout.maximumHeight: elisaTheme.coverImageSize / 1.9 + Layout.fillWidth: true + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - spacing: 0 + LabelWithToolTip { + id: albumLabel + + text: mainTitle Layout.fillWidth: true - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.alignment: Qt.AlignTop | Qt.AlignLeft + Layout.topMargin: secondaryTitle !== "" ? 0 : 9 - LabelWithToolTip { - id: albumLabel + elide: Text.ElideRight + fontSizeMode: Text.Fit - text: mainTitle + Layout.preferredHeight: elisaTheme.coverImageSize / 5 + Layout.minimumHeight: elisaTheme.coverImageSize / 5 + Layout.maximumHeight: elisaTheme.coverImageSize / 5 - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop | Qt.AlignLeft - Layout.topMargin: secondaryTitle !== "" ? 0 : 9 + color: myPalette.text + + font { + pointSize: elisaTheme.defaultFontPointSize * 2 + } + } - elide: Text.ElideRight - fontSizeMode: Text.Fit + LabelWithToolTip { + id: authorLabel - Layout.preferredHeight: elisaTheme.coverImageSize / 5 - Layout.minimumHeight: elisaTheme.coverImageSize / 5 - Layout.maximumHeight: elisaTheme.coverImageSize / 5 + text: secondaryTitle - color: myPalette.text + color: myPalette.text - font { - pointSize: elisaTheme.defaultFontPointSize * 2 - } + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + + font { + pointSize: elisaTheme.defaultFontPointSize } - LabelWithToolTip { - id: authorLabel + elide: Text.ElideRight - text: secondaryTitle + visible: secondaryTitle !== "" + } - color: myPalette.text + RowLayout { + Layout.fillWidth: true + spacing: 0 + Layout.bottomMargin: secondaryTitle !== "" ? 0 : 14 - Layout.fillWidth: true - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Controls1.Button { + objectName: 'enqueueButton' + text: i18nc("Add current list to playlist", "Enqueue") + iconName: "media-track-add-amarok" - font { - pointSize: elisaTheme.defaultFontPointSize - } + activeFocusOnTab: true + focus: true - elide: Text.ElideRight + onClicked: enqueue() + Keys.onReturnPressed: enqueue() - visible: secondaryTitle !== "" + Layout.leftMargin: 0 + Layout.rightMargin: 0 } - RowLayout { - Layout.fillWidth: true - spacing: 0 - Layout.bottomMargin: secondaryTitle !== "" ? 0 : 14 - - Controls1.Button { - objectName: 'enqueueButton' - text: i18nc("Add current list to playlist", "Enqueue") - iconName: "media-track-add-amarok" + Controls1.Button { + objectName: 'replaceAndPlayButton' + text: i18nc("Clear playlist and play", "Replace and Play") + tooltip: i18nc("Clear playlist and add current list to it", "Replace PlayList and Play Now") + iconName: "media-playback-start" - onClicked: enqueue() - Keys.onReturnPressed: enqueue() + activeFocusOnTab: true - Layout.leftMargin: 0 - Layout.rightMargin: 0 - } + onClicked: replaceAndPlay() + Keys.onReturnPressed: replaceAndPlay() - Controls1.Button { - objectName: 'replaceAndPlayButton' - text: i18nc("Clear playlist and play", "Replace and Play") - tooltip: i18nc("Clear playlist and add current list to it", "Replace PlayList and Play Now") - iconName: "media-playback-start" + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + } - onClicked: replaceAndPlay() - Keys.onReturnPressed: replaceAndPlay() + Controls1.Button { + objectName: 'showArtistButton' + id: showArtistButton - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - } + visible: allowArtistNavigation + text: i18nc("Button to navigate to the artist of the album", "Display Artist") + iconName: "view-media-artist" - Controls1.Button { - objectName: 'showArtistButton' - id: showArtistButton + activeFocusOnTab: true - visible: allowArtistNavigation - text: i18nc("Button to navigate to the artist of the album", "Display Artist") - iconName: "view-media-artist" + onClicked: showArtist() + Keys.onReturnPressed: showArtist() - onClicked: showArtist() - Keys.onReturnPressed: showArtist() + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + } - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - } + Item { + Layout.fillWidth: true + } - Item { - Layout.fillWidth: true - } + Controls1.ToolButton { + action: showFilterAction + objectName: 'showFilterButton' - Controls1.ToolButton { - action: showFilterAction - objectName: 'showFilterButton' + activeFocusOnTab: true - Keys.onReturnPressed: action.trigger() + Keys.onReturnPressed: action.trigger() - Layout.alignment: Qt.AlignRight - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - } + Layout.alignment: Qt.AlignRight + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 } } } + } - RowLayout { - id: filterRow + RowLayout { + id: filterRow - spacing: 0 + spacing: 0 - visible: opacity > 0.0 + visible: opacity > 0.0 - opacity: 0 + opacity: 0 - Layout.preferredHeight: elisaTheme.navigationBarFilterHeight - Layout.minimumHeight: elisaTheme.navigationBarFilterHeight - Layout.maximumHeight: elisaTheme.navigationBarFilterHeight - Layout.fillWidth: true - Layout.topMargin: elisaTheme.layoutVerticalMargin * 2 - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.alignment: Qt.AlignTop + Layout.preferredHeight: elisaTheme.navigationBarFilterHeight + Layout.minimumHeight: elisaTheme.navigationBarFilterHeight + Layout.maximumHeight: elisaTheme.navigationBarFilterHeight + Layout.fillWidth: true + Layout.topMargin: elisaTheme.layoutVerticalMargin * 2 + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.alignment: Qt.AlignTop - LabelWithToolTip { - text: i18nc("before the TextField input of the filter", "Search: ") + LabelWithToolTip { + text: i18nc("before the TextField input of the filter", "Search: ") - font.bold: true + font.bold: true - Layout.bottomMargin: 0 + Layout.bottomMargin: 0 - color: myPalette.text - } + color: myPalette.text + } - TextField { - id: filterTextInput - objectName: 'filterTextInput' + TextField { + id: filterTextInput + objectName: 'filterTextInput' - horizontalAlignment: TextInput.AlignLeft + horizontalAlignment: TextInput.AlignLeft - placeholderText: i18nc("Placeholder text in the filter text box", "Album name, artist, etc.") + placeholderText: i18nc("Placeholder text in the filter text box", "Album name, artist, etc.") - Layout.bottomMargin: 0 - Layout.fillWidth: true - Layout.minimumWidth: (placeHolderTextWidth.boundingRect.width - placeHolderTextWidth.boundingRect.x) * 1.2 - implicitWidth: (placeHolderTextWidth.boundingRect.width - placeHolderTextWidth.boundingRect.x) * 1.2 + Layout.bottomMargin: 0 + Layout.fillWidth: true + Layout.minimumWidth: (placeHolderTextWidth.boundingRect.width - placeHolderTextWidth.boundingRect.x) * 1.2 + implicitWidth: (placeHolderTextWidth.boundingRect.width - placeHolderTextWidth.boundingRect.x) * 1.2 - TextMetrics { - id: placeHolderTextWidth - text: filterTextInput.placeholderText - } + TextMetrics { + id: placeHolderTextWidth + text: filterTextInput.placeholderText + } - Image { - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.margins: elisaTheme.filterClearButtonMargin - id: clearText - fillMode: Image.PreserveAspectFit - smooth: true - visible: parent.text - source: Qt.resolvedUrl(elisaTheme.clearIcon) - height: parent.height - width: parent.height - sourceSize.width: parent.height - sourceSize.height: parent.height - mirror: LayoutMirroring.enabled - - MouseArea { - id: clear - anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } - height: parent.parent.height - width: parent.parent.height - onClicked: { - parent.parent.text = "" - parent.parent.forceActiveFocus() - } + Image { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.margins: elisaTheme.filterClearButtonMargin + id: clearText + fillMode: Image.PreserveAspectFit + smooth: true + visible: parent.text + source: Qt.resolvedUrl(elisaTheme.clearIcon) + height: parent.height + width: parent.height + sourceSize.width: parent.height + sourceSize.height: parent.height + mirror: LayoutMirroring.enabled + + MouseArea { + id: clear + anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } + height: parent.parent.height + width: parent.parent.height + onClicked: { + parent.parent.text = "" + parent.parent.forceActiveFocus() } } } + } - LabelWithToolTip { - text: i18nc("before the Rating widget input of the filter", "Rating: ") + LabelWithToolTip { + text: i18nc("before the Rating widget input of the filter", "Rating: ") - visible: showRating + visible: showRating - font.bold: true + font.bold: true - color: myPalette.text + color: myPalette.text - Layout.bottomMargin: 0 - Layout.leftMargin: !LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin * 2) : 0 - Layout.rightMargin: LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin * 2) : 0 - } + Layout.bottomMargin: 0 + Layout.leftMargin: !LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin * 2) : 0 + Layout.rightMargin: LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin * 2) : 0 + } - RatingStar { - id: ratingFilter - objectName: 'ratingFilter' + RatingStar { + id: ratingFilter + objectName: 'ratingFilter' - visible: showRating - hoverWidgetOpacity: 1 + visible: showRating + hoverWidgetOpacity: 1 - readOnly: false + readOnly: false - starSize: elisaTheme.ratingStarSize + starSize: elisaTheme.ratingStarSize - Layout.bottomMargin: 0 - } + Layout.bottomMargin: 0 + } - Item { - Layout.fillWidth: true - implicitWidth: elisaTheme.layoutHorizontalMargin * 4 - } + Item { + Layout.fillWidth: true + implicitWidth: elisaTheme.layoutHorizontalMargin * 4 + } - Controls1.ToolButton { - action: sortAction - objectName: 'sortAscendingButton' + Controls1.ToolButton { + action: sortAction + objectName: 'sortAscendingButton' - Keys.onReturnPressed: action.trigger() + activeFocusOnTab: true - Layout.alignment: Qt.AlignRight - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - visible: enableSorting - } + Keys.onReturnPressed: action.trigger() + + Layout.alignment: Qt.AlignRight + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + visible: enableSorting } } diff --git a/src/qml/PlayListBasicView.qml b/src/qml/PlayListBasicView.qml --- a/src/qml/PlayListBasicView.qml +++ b/src/qml/PlayListBasicView.qml @@ -34,6 +34,8 @@ activeFocusOnTab: true keyNavigationEnabled: true + currentIndex: -1 + section.property: 'albumSection' section.criteria: ViewSection.FullString section.labelPositioning: ViewSection.InlineLabels @@ -152,4 +154,8 @@ } } } + + onCountChanged: if (count === 0) { + currentIndex = -1; + } } diff --git a/src/qml/PlayListEntry.qml b/src/qml/PlayListEntry.qml --- a/src/qml/PlayListEntry.qml +++ b/src/qml/PlayListEntry.qml @@ -118,297 +118,298 @@ anchors.fill: parent anchors.rightMargin: LayoutMirroring.enabled ? scrollBarWidth : 0 + z: 1 - color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) + color: myPalette.base height: elisaTheme.playListDelegateHeight + } - focus: true - - ColumnLayout { - spacing: 0 + ColumnLayout { + spacing: 0 - anchors.fill: parent + anchors.fill: parent + anchors.rightMargin: LayoutMirroring.enabled ? scrollBarWidth : 0 + z: 2 - Item { - Layout.fillWidth: true - Layout.fillHeight: true + Item { + Layout.fillWidth: true + Layout.fillHeight: true - RowLayout { - id: trackRow + RowLayout { + id: trackRow - anchors.fill: parent + anchors.fill: parent - spacing: elisaTheme.layoutHorizontalMargin / 4 + spacing: elisaTheme.layoutHorizontalMargin / 4 - Item { - id: playIconItem + Item { + id: playIconItem - implicitHeight: elisaTheme.smallDelegateToolButtonSize - implicitWidth: elisaTheme.smallDelegateToolButtonSize - Layout.maximumWidth: elisaTheme.smallDelegateToolButtonSize - Layout.maximumHeight: elisaTheme.smallDelegateToolButtonSize - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin / 2 : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin / 2 : 0 + implicitHeight: elisaTheme.smallDelegateToolButtonSize + implicitWidth: elisaTheme.smallDelegateToolButtonSize + Layout.maximumWidth: elisaTheme.smallDelegateToolButtonSize + Layout.maximumHeight: elisaTheme.smallDelegateToolButtonSize + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin / 2 : 0 + Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin / 2 : 0 - Image { - id: playIcon + Image { + id: playIcon - anchors.fill: parent + anchors.fill: parent - opacity: 0 + opacity: 0 - source: (isPlaying === MediaPlayList.IsPlaying ? - Qt.resolvedUrl(elisaTheme.playingIndicatorIcon) : Qt.resolvedUrl(elisaTheme.pausedIndicatorIcon)) + source: (isPlaying === MediaPlayList.IsPlaying ? + Qt.resolvedUrl(elisaTheme.playingIndicatorIcon) : Qt.resolvedUrl(elisaTheme.pausedIndicatorIcon)) - width: parent.height * 1. - height: parent.height * 1. + width: parent.height * 1. + height: parent.height * 1. - sourceSize.width: parent.height * 1. - sourceSize.height: parent.height * 1. - fillMode: Image.PreserveAspectFit - mirror: LayoutMirroring.enabled - visible: opacity > 0.0 - } + sourceSize.width: parent.height * 1. + sourceSize.height: parent.height * 1. + fillMode: Image.PreserveAspectFit + mirror: LayoutMirroring.enabled + visible: opacity > 0.0 } + } - Item { - id: fakeDiscNumberItem + Item { + id: fakeDiscNumberItem - visible: isValid && (!hasValidDiscNumber || isSingleDiscAlbum) + visible: isValid && (!hasValidDiscNumber || isSingleDiscAlbum) - Layout.preferredWidth: (fakeDiscNumberSize.boundingRect.width - fakeDiscNumberSize.boundingRect.x) + (elisaTheme.layoutHorizontalMargin / 4) - Layout.minimumWidth: (fakeDiscNumberSize.boundingRect.width - fakeDiscNumberSize.boundingRect.x) + (elisaTheme.layoutHorizontalMargin / 4) - Layout.maximumWidth: (fakeDiscNumberSize.boundingRect.width - fakeDiscNumberSize.boundingRect.x) + (elisaTheme.layoutHorizontalMargin / 4) + Layout.preferredWidth: (fakeDiscNumberSize.boundingRect.width - fakeDiscNumberSize.boundingRect.x) + (elisaTheme.layoutHorizontalMargin / 4) + Layout.minimumWidth: (fakeDiscNumberSize.boundingRect.width - fakeDiscNumberSize.boundingRect.x) + (elisaTheme.layoutHorizontalMargin / 4) + Layout.maximumWidth: (fakeDiscNumberSize.boundingRect.width - fakeDiscNumberSize.boundingRect.x) + (elisaTheme.layoutHorizontalMargin / 4) - TextMetrics { - id: fakeDiscNumberSize + TextMetrics { + id: fakeDiscNumberSize - text: '/9' - } + text: '/9' } + } - Label { - id: trackNumberLabel + Label { + id: trackNumberLabel - horizontalAlignment: Text.AlignRight + horizontalAlignment: Text.AlignRight - text: trackNumber !== 0 && trackNumber !== -1 ? Number(trackNumber).toLocaleString(Qt.locale(), 'f', 0) : '' + text: trackNumber !== 0 && trackNumber !== -1 ? Number(trackNumber).toLocaleString(Qt.locale(), 'f', 0) : '' - font.weight: (isPlaying ? Font.Bold : Font.Light) - color: myPalette.text + font.weight: (isPlaying ? Font.Bold : Font.Light) + color: myPalette.text - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - visible: isValid + visible: isValid - Layout.preferredWidth: ((trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) > (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x) ? (trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) : (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x)) - Layout.minimumWidth: ((trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) > (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x) ? (trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) : (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x)) - Layout.maximumWidth: ((trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) > (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x) ? (trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) : (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x)) + Layout.preferredWidth: ((trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) > (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x) ? (trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) : (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x)) + Layout.minimumWidth: ((trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) > (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x) ? (trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) : (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x)) + Layout.maximumWidth: ((trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) > (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x) ? (trackNumberSize.boundingRect.width - trackNumberSize.boundingRect.x) : (realTrackNumberSize.boundingRect.width - realTrackNumberSize.boundingRect.x)) - Layout.rightMargin: !LayoutMirroring.enabled ? (discNumber !== 0 && !isSingleDiscAlbum ? - 0 : elisaTheme.layoutHorizontalMargin / 2) : 0 - Layout.leftMargin: LayoutMirroring.enabled ? (discNumber !== 0 && !isSingleDiscAlbum ? - 0 : elisaTheme.layoutHorizontalMargin / 2) : 0 + Layout.rightMargin: !LayoutMirroring.enabled ? (discNumber !== 0 && !isSingleDiscAlbum ? + 0 : elisaTheme.layoutHorizontalMargin / 2) : 0 + Layout.leftMargin: LayoutMirroring.enabled ? (discNumber !== 0 && !isSingleDiscAlbum ? + 0 : elisaTheme.layoutHorizontalMargin / 2) : 0 - TextMetrics { - id: trackNumberSize + TextMetrics { + id: trackNumberSize - text: (99).toLocaleString(Qt.locale(), 'f', 0) - } + text: (99).toLocaleString(Qt.locale(), 'f', 0) + } - TextMetrics { - id: realTrackNumberSize + TextMetrics { + id: realTrackNumberSize - text: Number(trackNumber).toLocaleString(Qt.locale(), 'f', 0) - } + text: Number(trackNumber).toLocaleString(Qt.locale(), 'f', 0) } + } - Label { - horizontalAlignment: Text.AlignCenter + Label { + horizontalAlignment: Text.AlignCenter - text: '/' + text: '/' - visible: isValid && discNumber !== 0 && !isSingleDiscAlbum + visible: isValid && discNumber !== 0 && !isSingleDiscAlbum - font.weight: (isPlaying ? Font.Bold : Font.Light) - color: myPalette.text + font.weight: (isPlaying ? Font.Bold : Font.Light) + color: myPalette.text - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.preferredWidth: (numberSeparatorSize.boundingRect.width - numberSeparatorSize.boundingRect.x) - Layout.minimumWidth: (numberSeparatorSize.boundingRect.width - numberSeparatorSize.boundingRect.x) - Layout.maximumWidth: (numberSeparatorSize.boundingRect.width - numberSeparatorSize.boundingRect.x) + Layout.preferredWidth: (numberSeparatorSize.boundingRect.width - numberSeparatorSize.boundingRect.x) + Layout.minimumWidth: (numberSeparatorSize.boundingRect.width - numberSeparatorSize.boundingRect.x) + Layout.maximumWidth: (numberSeparatorSize.boundingRect.width - numberSeparatorSize.boundingRect.x) - TextMetrics { - id: numberSeparatorSize + TextMetrics { + id: numberSeparatorSize - text: '/' - } + text: '/' } + } - Label { - horizontalAlignment: Text.AlignRight + Label { + horizontalAlignment: Text.AlignRight - font.weight: (isPlaying ? Font.Bold : Font.Light) - color: myPalette.text + font.weight: (isPlaying ? Font.Bold : Font.Light) + color: myPalette.text - text: Number(discNumber).toLocaleString(Qt.locale(), 'f', 0) + text: Number(discNumber).toLocaleString(Qt.locale(), 'f', 0) - visible: isValid && discNumber !== 0 && !isSingleDiscAlbum + visible: isValid && discNumber !== 0 && !isSingleDiscAlbum - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - Layout.preferredWidth: ((discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) > (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x) ? - (discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) : - (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x)) - Layout.minimumWidth: ((discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) > (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x) ? - (discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) : - (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x)) - Layout.maximumWidth: ((discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) > (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x) ? - (discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) : - (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x)) + Layout.preferredWidth: ((discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) > (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x) ? + (discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) : + (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x)) + Layout.minimumWidth: ((discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) > (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x) ? + (discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) : + (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x)) + Layout.maximumWidth: ((discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) > (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x) ? + (discNumberSize.boundingRect.width - discNumberSize.boundingRect.x) : + (realDiscNumberSize.boundingRect.width - realDiscNumberSize.boundingRect.x)) - Layout.rightMargin: !LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin / 2) : 0 - Layout.leftMargin: LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin / 2) : 0 + Layout.rightMargin: !LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin / 2) : 0 + Layout.leftMargin: LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin / 2) : 0 - TextMetrics { - id: discNumberSize + TextMetrics { + id: discNumberSize - text: '9' - } + text: '9' + } - TextMetrics { - id: realDiscNumberSize + TextMetrics { + id: realDiscNumberSize - text: Number(discNumber).toLocaleString(Qt.locale(), 'f', 0) - } + text: Number(discNumber).toLocaleString(Qt.locale(), 'f', 0) } + } - LabelWithToolTip { - id: mainCompactLabel + LabelWithToolTip { + id: mainCompactLabel - text: title + text: title - font.weight: (isPlaying ? Font.Bold : Font.Normal) - color: myPalette.text + font.weight: (isPlaying ? Font.Bold : Font.Normal) + color: myPalette.text - Layout.maximumWidth: mainCompactLabel.implicitWidth + 1 - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + Layout.maximumWidth: mainCompactLabel.implicitWidth + 1 + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - visible: isValid + visible: isValid - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } + elide: Text.ElideRight + horizontalAlignment: Text.AlignLeft + } - LabelWithToolTip { - id: mainInvalidCompactLabel + LabelWithToolTip { + id: mainInvalidCompactLabel - text: title + text: title - font.weight: Font.Normal - color: myPalette.text + font.weight: Font.Normal + color: myPalette.text - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - visible: !isValid + visible: !isValid - elide: Text.ElideRight - } + elide: Text.ElideRight + } - Item { - Layout.fillWidth: true - Layout.preferredWidth: 0 - } + Item { + Layout.fillWidth: true + Layout.preferredWidth: 0 + } - Controls1.ToolButton { - id: infoButton - objectName: 'infoButton' + Controls1.ToolButton { + id: infoButton + objectName: 'infoButton' - implicitHeight: elisaTheme.smallDelegateToolButtonSize - implicitWidth: elisaTheme.smallDelegateToolButtonSize + implicitHeight: elisaTheme.smallDelegateToolButtonSize + implicitWidth: elisaTheme.smallDelegateToolButtonSize - opacity: 0 + opacity: 0 - visible: opacity > 0.1 + visible: opacity > 0.1 - action: showInfo - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - } + action: showInfo + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } - Controls1.ToolButton { - id: playPauseButton - objectName: 'playPauseButton' + Controls1.ToolButton { + id: playPauseButton + objectName: 'playPauseButton' - implicitHeight: elisaTheme.smallDelegateToolButtonSize - implicitWidth: elisaTheme.smallDelegateToolButtonSize + implicitHeight: elisaTheme.smallDelegateToolButtonSize + implicitWidth: elisaTheme.smallDelegateToolButtonSize - opacity: 0 + opacity: 0 - scale: LayoutMirroring.enabled ? -1 : 1 // We can mirror the symmetrical pause icon + scale: LayoutMirroring.enabled ? -1 : 1 // We can mirror the symmetrical pause icon - visible: opacity > 0.1 - action: !(isPlaying === MediaPlayList.IsPlaying) ? playNow : pauseNow - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - } + visible: opacity > 0.1 + action: !(isPlaying === MediaPlayList.IsPlaying) ? playNow : pauseNow + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } - Item { - implicitHeight: elisaTheme.smallDelegateToolButtonSize - implicitWidth: elisaTheme.smallDelegateToolButtonSize - Layout.maximumWidth: elisaTheme.smallDelegateToolButtonSize - Layout.maximumHeight: elisaTheme.smallDelegateToolButtonSize - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + Item { + implicitHeight: elisaTheme.smallDelegateToolButtonSize + implicitWidth: elisaTheme.smallDelegateToolButtonSize + Layout.maximumWidth: elisaTheme.smallDelegateToolButtonSize + Layout.maximumHeight: elisaTheme.smallDelegateToolButtonSize + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Controls1.ToolButton { - id: removeButton - objectName: 'removeButton' + Controls1.ToolButton { + id: removeButton + objectName: 'removeButton' - anchors.fill: parent + anchors.fill: parent - opacity: 0 + opacity: 0 - visible: opacity > 0.1 - action: removeFromPlayList - } + visible: opacity > 0.1 + action: removeFromPlayList } + } - RatingStar { - id: ratingWidget + RatingStar { + id: ratingWidget - starRating: rating + starRating: rating - starSize: elisaTheme.ratingStarSize + starSize: elisaTheme.ratingStarSize - visible: rating > 0 - } + visible: rating > 0 + } - LabelWithToolTip { - id: durationLabel + LabelWithToolTip { + id: durationLabel - text: duration + text: duration - font.weight: (isPlaying ? Font.Bold : Font.Normal) - color: myPalette.text + font.weight: (isPlaying ? Font.Bold : Font.Normal) + color: myPalette.text - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - Layout.leftMargin: elisaTheme.layoutHorizontalMargin / 2 - Layout.rightMargin: elisaTheme.layoutHorizontalMargin / 2 + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.leftMargin: elisaTheme.layoutHorizontalMargin / 2 + Layout.rightMargin: elisaTheme.layoutHorizontalMargin / 2 - horizontalAlignment: Text.AlignRight - } + horizontalAlignment: Text.AlignRight } } } } states: [ State { name: 'notSelected' - when: !containsMouse && (!playListEntry.activeFocus || !isSelected) + when: !containsMouse && !isSelected PropertyChanges { target: removeButton opacity: 0 @@ -429,14 +430,18 @@ target: entryBackground color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) } + PropertyChanges { + target: entryBackground + opacity: 1. + } PropertyChanges { target: ratingWidget hoverWidgetOpacity: 0.0 } }, State { - name: 'hoveredOrSelected' - when: containsMouse || (playListEntry.activeFocus && isSelected) + name: 'hovered' + when: containsMouse && !playListEntry.activeFocus PropertyChanges { target: removeButton opacity: 1 @@ -453,10 +458,78 @@ target: playIcon opacity: (isPlaying === MediaPlayList.IsPlaying || isPlaying === MediaPlayList.IsPaused ? 1.0 : 0.0) } + PropertyChanges { + target: entryBackground + color: myPalette.highlight + } + PropertyChanges { + target: entryBackground + opacity: 0.2 + } + PropertyChanges { + target: ratingWidget + hoverWidgetOpacity: 1.0 + } + }, + State { + name: 'selected' + when: !playListEntry.activeFocus && isSelected + PropertyChanges { + target: removeButton + opacity: 0 + } + PropertyChanges { + target: playPauseButton + opacity: 0 + } + PropertyChanges { + target: infoButton + opacity: 0 + } + PropertyChanges { + target: playIcon + opacity: (isPlaying === MediaPlayList.IsPlaying || isPlaying === MediaPlayList.IsPaused ? 1.0 : 0.0) + } PropertyChanges { target: entryBackground color: myPalette.mid } + PropertyChanges { + target: entryBackground + opacity: 1. + } + PropertyChanges { + target: ratingWidget + hoverWidgetOpacity: 1.0 + } + }, + State { + name: 'focused' + when: playListEntry.activeFocus + PropertyChanges { + target: removeButton + opacity: 1 + } + PropertyChanges { + target: playPauseButton + opacity: 1 + } + PropertyChanges { + target: infoButton + opacity: 1 + } + PropertyChanges { + target: playIcon + opacity: (isPlaying === MediaPlayList.IsPlaying || isPlaying === MediaPlayList.IsPaused ? 1.0 : 0.0) + } + PropertyChanges { + target: entryBackground + color: myPalette.highlight + } + PropertyChanges { + target: entryBackground + opacity: 0.6 + } PropertyChanges { target: ratingWidget hoverWidgetOpacity: 1.0 diff --git a/src/qml/RecentlyPlayedTracks.qml b/src/qml/RecentlyPlayedTracks.qml --- a/src/qml/RecentlyPlayedTracks.qml +++ b/src/qml/RecentlyPlayedTracks.qml @@ -65,14 +65,16 @@ title: model.title artist: model.artist album: (model.album !== undefined && model.album !== '' ? model.album : '') - albumArtist: model.albumArtist + albumArtist: (model.albumArtist !== undefined && model.albumArtist !== '' ? model.albumArtist : '') duration: model.duration imageUrl: (model.imageUrl !== undefined && model.imageUrl !== '' ? model.imageUrl : '') trackNumber: model.trackNumber discNumber: model.discNumber rating: model.rating isFirstTrackOfDisc: false isSingleDiscAlbum: model.isSingleDiscAlbum + isSelected: listView.currentIndex === index + isAlternateColor: (index % 2) === 1 onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, @@ -82,7 +84,10 @@ ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onClicked: contentDirectoryView.currentIndex = index + onClicked: { + listView.currentIndex = index + entry.forceActiveFocus() + } } Loader { diff --git a/src/qml/TracksView.qml b/src/qml/TracksView.qml --- a/src/qml/TracksView.qml +++ b/src/qml/TracksView.qml @@ -65,14 +65,16 @@ title: model.title artist: model.artist album: (model.album !== undefined && model.album !== '' ? model.album : '') - albumArtist: model.albumArtist + albumArtist: (model.albumArtist !== undefined && model.albumArtist !== '' ? model.albumArtist : '') duration: model.duration imageUrl: (model.imageUrl !== undefined && model.imageUrl !== '' ? model.imageUrl : '') trackNumber: model.trackNumber discNumber: model.discNumber rating: model.rating isFirstTrackOfDisc: false isSingleDiscAlbum: model.isSingleDiscAlbum + isSelected: listView.currentIndex === index + isAlternateColor: (index % 2) === 1 onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, @@ -82,7 +84,10 @@ ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onClicked: contentDirectoryView.currentIndex = index + onClicked: { + listView.currentIndex = index + entry.forceActiveFocus() + } } Loader { diff --git a/src/qml/ViewSelector.qml b/src/qml/ViewSelector.qml --- a/src/qml/ViewSelector.qml +++ b/src/qml/ViewSelector.qml @@ -42,48 +42,69 @@ Rectangle { anchors.fill: parent + z: 1 - color: myPalette.base - border { - color: (rootFocusScope.activeFocus ? myPalette.highlight : "transparent") - width: 1 + border.color: myPalette.base + + Behavior on border.color { + ColorAnimation { + duration: 300 + } } + } + + ScrollView { + focus: true + + anchors.fill: parent + z: 2 + + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + + ListView { + id: viewModeView - ScrollView { focus: true + activeFocusOnTab: true + keyNavigationEnabled: true - anchors.fill: parent + property bool ignoreCurrentItemChanges: false - clip: true - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + z: 2 + anchors.topMargin: elisaTheme.layoutHorizontalMargin * 2 - ListView { - id: viewModeView + model: DelegateModel { + id: pageDelegateModel - focus: true - activeFocusOnTab: true - keyNavigationEnabled: true + delegate: MouseArea { + id: itemMouseArea - property bool ignoreCurrentItemChanges: false + property var viewType: model.type - z: 2 + height: Math.round(elisaTheme.viewSelectorDelegateHeight * 1.4) + width: viewModeView.width - anchors.topMargin: elisaTheme.layoutHorizontalMargin * 2 + hoverEnabled: true + acceptedButtons: Qt.LeftButton - model: DelegateModel { - id: pageDelegateModel + Rectangle { - delegate: MouseArea { - id: itemMouseArea + border { + color: ((viewModeView.currentIndex === index && rootFocusScope.activeFocus) ? myPalette.highlight : "transparent") + width: 1 + } - property var viewType: model.type + Behavior on border.color { + ColorAnimation { + duration: 300 + } + } - height: elisaTheme.viewSelectorDelegateHeight * 1.4 - width: viewModeView.width + radius: 3 - hoverEnabled: true - acceptedButtons: Qt.LeftButton + anchors.fill: parent Loader { anchors.fill: parent @@ -185,31 +206,28 @@ } } } + } - onClicked: viewModeView.currentIndex = index + onClicked: { + rootFocusScope.focus = true + viewModeView.currentIndex = index } } + } - footer: MouseArea { - width: viewModeView.width - height: viewModeView.height - y + footer: MouseArea { + width: viewModeView.width + height: viewModeView.height - y - acceptedButtons: Qt.LeftButton + acceptedButtons: Qt.LeftButton - onClicked: - { - rootFocusScope.focus = true - } + onClicked: + { + rootFocusScope.focus = true } - - onCurrentItemChanged: if (!ignoreCurrentItemChanges) switchView(currentItem.viewType) } - } - Behavior on border.color { - ColorAnimation { - duration: 300 - } + onCurrentItemChanged: if (!ignoreCurrentItemChanges) switchView(currentItem.viewType) } }