diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,9 +62,10 @@ MediaAllTracksView.qml MediaTrackDelegate.qml MediaAlbumTrackDelegate.qml + MediaTrackMetadataView.qml GridBrowserView.qml GridBrowserDelegate.qml - + ViewSelector.qml ) diff --git a/src/MediaAlbumView.qml b/src/MediaAlbumView.qml --- a/src/MediaAlbumView.qml +++ b/src/MediaAlbumView.qml @@ -130,46 +130,49 @@ mediaTrack.isAlternateColor: (index % 2) === 1 mediaTrack.title: if (model != undefined && model.title !== undefined) - model.title - else - '' + model.title + else + '' mediaTrack.artist: if (model != undefined && model.artist !== undefined) - model.artist - else - '' + model.artist + else + '' mediaTrack.albumArtist: if (model != undefined && model.albumArtist !== undefined) - model.albumArtist - else - '' + model.albumArtist + else + '' mediaTrack.duration: if (model != undefined && model.duration !== undefined) - model.duration - else - '' + model.duration + else + '' mediaTrack.trackNumber: if (model != undefined && model.trackNumber !== undefined) - model.trackNumber - else - '' + model.trackNumber + else + '' mediaTrack.discNumber: if (model != undefined && model.discNumber !== undefined) - model.discNumber - else - '' + model.discNumber + else + '' mediaTrack.rating: if (model != undefined && model.rating !== undefined) - model.rating - else - 0 + model.rating + else + 0 mediaTrack.trackData: if (model != undefined && model.trackData !== undefined) - model.trackData - else - '' + model.trackData + else + '' mediaTrack.isFirstTrackOfDisc: if (model != undefined && model.isFirstTrackOfDisc !== undefined) - model.isFirstTrackOfDisc - else - false + model.isFirstTrackOfDisc + else + false mediaTrack.isSingleDiscAlbum: if (model != undefined && model.isSingleDiscAlbum !== undefined) - model.isSingleDiscAlbum - else - true - + model.isSingleDiscAlbum + else + true + mediaTrack.trackResource: if (model != undefined && model.trackResource !== undefined) + model.trackResource + else + '' mediaTrack.onClearPlaylist: topListing.clearPlayList() diff --git a/src/MediaAllTracksView.qml b/src/MediaAllTracksView.qml --- a/src/MediaAllTracksView.qml +++ b/src/MediaAllTracksView.qml @@ -106,13 +106,13 @@ else '' albumName: if (model != undefined && model.album !== undefined) - model.album + model.album + else + '' + albumArtist: if (model != undefined && model.albumArtist !== undefined) + model.albumArtist else '' - albumArtist: if (model != undefined && model.albumArtist !== undefined) - model.albumArtist - else - '' duration: if (model != undefined && model.duration !== undefined) model.duration else @@ -122,13 +122,13 @@ else '' discNumber: if (model != undefined && model.discNumber !== undefined) - model.discNumber - else - '' + model.discNumber + else + '' rating: if (model != undefined && model.rating !== undefined) - model.rating - else - 0 + model.rating + else + 0 trackData: if (model != undefined && model.trackData !== undefined) model.trackData else diff --git a/src/MediaPlayListView.qml b/src/MediaPlayListView.qml --- a/src/MediaPlayListView.qml +++ b/src/MediaPlayListView.qml @@ -316,6 +316,10 @@ model.rating else 0 + trackResource: if (model != undefined && model.trackResource !== undefined) + model.trackResource + else + '' isValid: model.isValid isPlaying: model.isPlaying isSelected: playListView.currentIndex === index diff --git a/src/MediaTrackDelegate.qml b/src/MediaTrackDelegate.qml --- a/src/MediaTrackDelegate.qml +++ b/src/MediaTrackDelegate.qml @@ -67,9 +67,44 @@ onTriggered: enqueueToPlaylist(trackData) } + Action { + id: showInfo + text: i18nc("Show track metadata", "View Details") + iconName: "help-about" + onTriggered: { + if (metadataLoader.active === false) { + metadataLoader.active = true + } + else { + metadataLoader.item.close(); + metadataLoader.active = false + } + } + } + Keys.onReturnPressed: enqueueToPlaylist(trackData) Keys.onEnterPressed: enqueueToPlaylist(trackData) + Loader { + id: metadataLoader + active: false + onLoaded: item.open() + + sourceComponent: MediaTrackMetadataView { + trackTitle: mediaTrack.title + artist: mediaTrack.artist + albumArtist: mediaTrack.albumArtist + albumName: mediaTrack.albumName + duration: mediaTrack.duration + resource: mediaTrack.trackResource + rating: mediaTrack.rating + trackNumber: mediaTrack.trackNumber + discNumber: mediaTrack.discNumber + + onRejected: metadataLoader.active = false; + } + } + Rectangle { id: rowRoot @@ -227,6 +262,15 @@ sourceComponent: Row { anchors.centerIn: parent + ToolButton { + id: infoButton + + height: elisaTheme.delegateHeight + width:elisaTheme.delegateHeight + + action: showInfo + } + ToolButton { id: enqueueButton diff --git a/src/MediaTrackMetadataView.qml b/src/MediaTrackMetadataView.qml new file mode 100644 --- /dev/null +++ b/src/MediaTrackMetadataView.qml @@ -0,0 +1,177 @@ +/* + * Copyright 2017 Alexander Stippich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQml.Models 2.2 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 +import QtGraphicalEffects 1.0 + +Dialog { + id: trackMetadata + + property string trackTitle + property string artist + property string albumArtist + property string albumName + property string composer + property string duration + property string genre + property string resource + property int year + property int rating: -1 + property int trackNumber + property int discNumber + property bool isSingleDiscAlbum + + title: i18nc("Window title for track metadata", "View Details") + modality: Qt.NonModal + + standardButtons: StandardButton.Close + + Component.onCompleted: { + if (trackTitle.length !== 0) + trackList.append({"name": i18nc("Track title for track metadata view", "Title:"), "content": trackTitle}) + if (artist.length !== 0) + trackList.append({"name": i18nc("Track artist for track metadata view", "Artist:"), "content": artist}) + if (albumName.length !== 0) + trackList.append({"name": i18nc("Album name for track metadata view", "Album:"), "content": albumName}) + if (composer.length !== 0) + trackList.append({"name": i18nc("Composer name for track metadata view", "Composer:"), "content": composer}) + if (trackNumber !== 0) + trackList.append({"name": i18nc("Track number for track metadata view", "Track Number:"), "content": trackNumber + ""}) + if (discNumber !== 0) + trackList.append({"name": i18nc("Disc number for track metadata view", "Disc Number:"), "content": discNumber + ""}) + if (albumArtist.length !== 0) + trackList.append({"name": i18nc("Album artist for track metadata view", "Album Artist:"), "content": albumArtist}) + if (duration.length !== 0) + trackList.append({"name": i18nc("Duration label for track metadata view", "Duration:"), "content": duration}) + if (year !== 0) + trackList.append({"name": i18nc("Year label for track metadata view", "Year:"), "content": year}) + if (genre.length !== 0) + trackList.append({"name": i18nc("Genre label for track metadata view", "Genre:"), "content": genre}) + trackData.Layout.preferredHeight = textSize.height * trackData.count + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + ListView { + id: trackData + + interactive: false + Layout.fillWidth: true + + model: ListModel { + id: trackList + } + + delegate: RowLayout { + id: delegateRow + spacing: 0 + + Text { + text: name + color: myPalette.text + horizontalAlignment: Text.AlignRight + + Layout.preferredWidth: trackData.width * 0.3 + Layout.minimumHeight: textSize.height + Layout.rightMargin: elisaTheme.layoutHorizontalMargin + } + + Text { + text: content + color: myPalette.text + + horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + + Layout.preferredWidth: trackData.width * 0.66 + Layout.fillWidth: true + Layout.minimumHeight: textSize.height + } + } + } + + RowLayout { + anchors.margins: 0 + spacing: 0 + + visible: rating > -1 + + Layout.minimumHeight: textSize.height + + Text { + id: ratingText + text: i18nc("Rating label for information panel", "Rating:") + color: myPalette.text + + horizontalAlignment: Text.AlignRight + Layout.preferredWidth: trackData.width * 0.3 + Layout.rightMargin: elisaTheme.layoutHorizontalMargin + } + + TextMetrics { + id: textSize + font: ratingText.font + text: ratingText.text + } + + RatingStar { + id: ratingWidget + starRating: rating + readOnly: true + + starSize: elisaTheme.ratingStarSize + + Layout.fillWidth: true + } + + ColorOverlay { + source: ratingWidget + + z: 2 + anchors.fill: ratingWidget + + color: myPalette.text + } + } + + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + + Text { + id: trackResource + text: trackMetadata.resource + color: myPalette.text + font.italic: true + + elide: Text.ElideLeft + + Layout.minimumHeight: textSize.height + Layout.preferredWidth: elisaTheme.trackMetadataWidth + Layout.fillWidth: true + } + } +} diff --git a/src/PlayListEntry.qml b/src/PlayListEntry.qml --- a/src/PlayListEntry.qml +++ b/src/PlayListEntry.qml @@ -44,6 +44,7 @@ property bool isAlternateColor property bool containsMouse property bool hasAlbumHeader + property string trackResource signal startPlayback() signal pausePlayback() @@ -80,6 +81,41 @@ onTriggered: playListEntry.pausePlayback() } + Action { + id: showInfo + text: i18nc("Show track metadata", "View Details") + iconName: "help-about" + onTriggered: { + if (metadataLoader.active === false) { + metadataLoader.active = true + } + else { + metadataLoader.item.close(); + metadataLoader.active = false + } + } + } + + Loader { + id: metadataLoader + active: false + onLoaded: item.open() + + sourceComponent: MediaTrackMetadataView { + trackTitle: playListEntry.title + artist: playListEntry.artist + albumArtist: playListEntry.albumArtist + albumName: playListEntry.album + duration: playListEntry.duration + resource: playListEntry.trackResource + rating: playListEntry.rating + trackNumber: playListEntry.trackNumber + discNumber: playListEntry.discNumber + + onRejected: metadataLoader.active = false; + } + } + Rectangle { id: entryBackground @@ -248,6 +284,21 @@ Layout.preferredWidth: 0 } + + ToolButton { + id: infoButton + + implicitHeight: elisaTheme.smallDelegateToolButtonSize + implicitWidth: elisaTheme.smallDelegateToolButtonSize + + opacity: 0 + + visible: opacity > 0.1 + + action: showInfo + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ToolButton { id: playPauseButton @@ -366,6 +417,10 @@ target: removeButton opacity: 0 } + PropertyChanges { + target: infoButton + opacity: 0 + } PropertyChanges { target: playPauseButton opacity: 0 @@ -386,6 +441,10 @@ target: playPauseButton opacity: 1 } + PropertyChanges { + target: infoButton + opacity: 1 + } PropertyChanges { target: entryBackground color: myPalette.mid diff --git a/src/Theme.qml b/src/Theme.qml --- a/src/Theme.qml +++ b/src/Theme.qml @@ -49,6 +49,8 @@ property int coverImageSize: 180 property int smallImageSize: 32 + property int trackMetadataWidth: 360 + property int tooltipRadius: 3 property int shadowOffset: 2 diff --git a/src/mediaplaylist.cpp b/src/mediaplaylist.cpp --- a/src/mediaplaylist.cpp +++ b/src/mediaplaylist.cpp @@ -333,6 +333,7 @@ roles[static_cast(ColumnsRoles::SecondaryTextRole)] = "secondaryText"; roles[static_cast(ColumnsRoles::ImageUrlRole)] = "imageUrl"; roles[static_cast(ColumnsRoles::ShadowForImageRole)] = "shadowForImage"; + roles[static_cast(ColumnsRoles::ResourceRole)] = "trackResource"; return roles; } diff --git a/src/upnpControl.qrc b/src/upnpControl.qrc --- a/src/upnpControl.qrc +++ b/src/upnpControl.qrc @@ -23,6 +23,7 @@ FilterBar.qml MediaTrackDelegate.qml MediaAlbumTrackDelegate.qml + MediaTrackMetadataView.qml GridBrowserView.qml GridBrowserDelegate.qml background.png diff --git a/src/windows/WindowsTheme.qml b/src/windows/WindowsTheme.qml --- a/src/windows/WindowsTheme.qml +++ b/src/windows/WindowsTheme.qml @@ -49,6 +49,8 @@ property int coverImageSize: 180 property int smallImageSize: 32 + property int trackMetadataWidth: 360 + property int tooltipRadius: 3 property int shadowOffset: 2