diff --git a/src/MediaAlbumDelegate.qml b/src/MediaAlbumDelegate.qml index 5494fa7e..678d346e 100644 --- a/src/MediaAlbumDelegate.qml +++ b/src/MediaAlbumDelegate.qml @@ -1,305 +1,305 @@ /* * Copyright 2016-2017 Matthieu Gallien * * 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.4 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.2 import QtQuick.Window 2.2 import QtQml.Models 2.1 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 import org.kde.elisa 1.0 FocusScope { property StackView stackView property MediaPlayList playListModel property var musicListener property var playerControl property var image property alias title: titleLabel.text property alias artist: artistLabel.text property string trackNumber property bool isSingleDiscAlbum property var albumData property var albumId signal showArtist(var name) signal albumClicked() id: mediaServerEntry Action { id: enqueueAction text: i18nc("Add whole album to play list", "Enqueue") iconName: 'media-track-add-amarok' onTriggered: mediaServerEntry.playListModel.enqueue(mediaServerEntry.albumData) } Action { id: openAction text: i18nc("Open album view", "Open Album") iconName: 'document-open-folder' onTriggered: showAlbumTracks() } Action { id: enqueueAndPlayAction text: i18nc("Clear play list and add whole album to play list", "Play Now and Replace Play List") iconName: 'media-playback-start' onTriggered: { mediaServerEntry.playListModel.clearAndEnqueue(mediaServerEntry.albumData) mediaServerEntry.playerControl.ensurePlay() } } Component { id: albumViewComponent MediaAlbumView { stackView: mediaServerEntry.stackView playListModel: mediaServerEntry.playListModel musicListener: mediaServerEntry.musicListener playerControl: mediaServerEntry.playerControl albumArtUrl: image albumName: title artistName: artist tracksCount: count isSingleDiscAlbum: mediaServerEntry.isSingleDiscAlbum albumData: mediaServerEntry.albumData albumId: mediaServerEntry.albumId onShowArtist: mediaServerEntry.showArtist(name) } } function showAlbumTracks() { stackView.push(albumViewComponent) } ColumnLayout { anchors.fill: parent spacing: 0 MouseArea { id: hoverHandle hoverEnabled: true acceptedButtons: Qt.LeftButton focus: true Layout.preferredHeight: mediaServerEntry.width * 0.9 + elisaTheme.layoutVerticalMargin * 0.5 + titleSize.height + artistSize.height Layout.fillWidth: true onClicked: { hoverHandle.forceActiveFocus() albumClicked() } onDoubleClicked: showAlbumTracks() TextMetrics { id: titleSize font: titleLabel.font text: titleLabel.text } TextMetrics { id: artistSize font: artistLabel.font text: artistLabel.text } Loader { id: hoverLoader active: false z: 2 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right height: mediaServerEntry.width * 0.9 + elisaTheme.layoutVerticalMargin sourceComponent: Item { GaussianBlur { id: hoverLayer radius: 4 samples: 16 deviation: 5 anchors.fill: parent source: ShaderEffectSource { sourceItem: mainData sourceRect: Qt.rect(0, 0, hoverLayer.width, hoverLayer.height) } Rectangle { color: myPalette.light opacity: 0.5 anchors.fill: parent } } Row { anchors.centerIn: parent ToolButton { id: enqueueButton action: enqueueAction focus: true width: elisaTheme.delegateToolButtonSize height: elisaTheme.delegateToolButtonSize } ToolButton { id: openButton action: openAction focus: true width: elisaTheme.delegateToolButtonSize height: elisaTheme.delegateToolButtonSize } ToolButton { id: enqueueAndPlayButton action: enqueueAndPlayAction focus: true width: elisaTheme.delegateToolButtonSize height: elisaTheme.delegateToolButtonSize } } } } ColumnLayout { id: mainData spacing: 0 anchors.fill: parent z: 1 Item { Layout.preferredHeight: mediaServerEntry.width * 0.9 Layout.preferredWidth: mediaServerEntry.width * 0.9 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter focus: true Image { id: coverImage anchors.fill: parent sourceSize.width: mediaServerEntry.width * 0.9 sourceSize.height: mediaServerEntry.width * 0.9 fillMode: Image.PreserveAspectFit smooth: true source: (mediaServerEntry.image ? mediaServerEntry.image : Qt.resolvedUrl(elisaTheme.albumCover)) asynchronous: true - layer.enabled: true + layer.enabled: image == undefined ? false : true layer.effect: DropShadow { horizontalOffset: mediaServerEntry.width * 0.02 verticalOffset: mediaServerEntry.width * 0.02 source: coverImage radius: 5.0 samples: 11 color: myPalette.shadow } } } LabelWithToolTip { id: titleLabel font.weight: Font.Bold color: myPalette.text horizontalAlignment: Text.AlignLeft Layout.topMargin: elisaTheme.layoutVerticalMargin * 0.5 Layout.preferredWidth: mediaServerEntry.width * 0.9 Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom elide: Text.ElideRight } LabelWithToolTip { id: artistLabel font.weight: Font.Normal color: myPalette.text horizontalAlignment: Text.AlignLeft Layout.preferredWidth: mediaServerEntry.width * 0.9 Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom elide: Text.ElideRight } } } Item { Layout.fillHeight: true } } states: [ State { name: 'default' PropertyChanges { target: hoverLoader active: false } }, State { name: 'active' when: mediaServerEntry.activeFocus || hoverHandle.containsMouse PropertyChanges { target: hoverLoader active: true } } ] } diff --git a/src/MediaArtistDelegate.qml b/src/MediaArtistDelegate.qml index fa3be9fd..b7f71c3c 100644 --- a/src/MediaArtistDelegate.qml +++ b/src/MediaArtistDelegate.qml @@ -1,249 +1,249 @@ /* * Copyright 2016-2017 Matthieu Gallien * * 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.4 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.2 import QtQuick.Window 2.2 import QtQml.Models 2.1 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 import org.kde.elisa 1.0 FocusScope { property StackView stackView property MediaPlayList playListModel property var musicListener property var playerControl property var contentDirectoryModel property var image property alias name: nameLabel.text signal artistClicked() signal openArtist(var name) id: mediaServerEntry SystemPalette { id: myPalette colorGroup: SystemPalette.Active } Theme { id: elisaTheme } Action { id: enqueueAction text: i18nc("Add all tracks from artist to play list", "Enqueue") iconName: "media-track-add-amarok" onTriggered: mediaServerEntry.playListModel.enqueue(mediaServerEntry.name) } Action { id: openAction text: i18nc("Open artist view", "Open Artist") iconName: 'document-open-folder' onTriggered: openArtist(name) } Action { id: enqueueAndPlayAction text: i18nc("Clear play list and add all tracks from artist to play list", "Play Now and Replace Play List") iconName: "media-playback-start" onTriggered: { mediaServerEntry.playListModel.clearAndEnqueue(mediaServerEntry.name) mediaServerEntry.playerControl.ensurePlay() } } ColumnLayout { anchors.fill: parent spacing: 0 MouseArea { id: hoverHandle hoverEnabled: true acceptedButtons: Qt.LeftButton focus: true Layout.preferredHeight: mediaServerEntry.width * 0.9 + elisaTheme.layoutVerticalMargin * 0.5 + nameSize.height Layout.fillWidth: true onClicked: { hoverHandle.forceActiveFocus() artistClicked() } onDoubleClicked: openArtist(name) TextMetrics { id: nameSize font: nameLabel.font text: nameLabel.text } Loader { id: hoverLoader active: false z: 2 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right height: mediaServerEntry.width * 0.9 + elisaTheme.layoutVerticalMargin sourceComponent: Rectangle { id: hoverLayer anchors.fill: parent color: myPalette.light opacity: 0.85 Row { anchors.centerIn: parent ToolButton { id: enqueueButton action: enqueueAction width: elisaTheme.delegateToolButtonSize height: elisaTheme.delegateToolButtonSize } ToolButton { id: openButton action: openAction width: elisaTheme.delegateToolButtonSize height: elisaTheme.delegateToolButtonSize } ToolButton { id: enqueueAndPlayButton action: enqueueAndPlayAction width: elisaTheme.delegateToolButtonSize height: elisaTheme.delegateToolButtonSize } } } } ColumnLayout { id: mainData spacing: 0 anchors.fill: parent z: 1 Item { Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.preferredWidth: mediaServerEntry.width * 0.9 Layout.preferredHeight: mediaServerEntry.width * 0.9 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Image { id: artistDecoration source: Qt.resolvedUrl(elisaTheme.artistImage) anchors.fill: parent sourceSize.width: mediaServerEntry.width * 0.9 sourceSize.height: mediaServerEntry.width * 0.9 fillMode: Image.PreserveAspectFit smooth: true asynchronous: true - layer.enabled: true + layer.enabled: image == '' ? false : true layer.effect: DropShadow { horizontalOffset: mediaServerEntry.width * 0.02 verticalOffset: mediaServerEntry.width * 0.02 radius: 5.0 samples: 11 color: myPalette.shadow } } } LabelWithToolTip { id: nameLabel font.weight: Font.Bold color: myPalette.text horizontalAlignment: Text.AlignLeft Layout.preferredWidth: mediaServerEntry.width * 0.9 Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom elide: Text.ElideRight } } } Item { Layout.fillHeight: true } } states: [ State { name: 'default' PropertyChanges { target: hoverLoader active: false } }, State { name: 'active' when: mediaServerEntry.activeFocus || hoverHandle.containsMouse PropertyChanges { target: hoverLoader active: true } } ] } diff --git a/src/MediaTracksDelegate.qml b/src/MediaTracksDelegate.qml index d357a912..f0ddb564 100644 --- a/src/MediaTracksDelegate.qml +++ b/src/MediaTracksDelegate.qml @@ -1,279 +1,279 @@ /* * Copyright 2016-2017 Matthieu Gallien * * 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.4 import QtQuick.Layouts 1.2 import QtQuick.Controls 1.2 import QtQuick.Window 2.2 import QtGraphicalEffects 1.0 import org.kde.elisa 1.0 FocusScope { id: viewTrackDelegate property string title property var coverImage property string artist property string albumName property alias duration: durationLabel.text property int trackNumber property int discNumber property alias rating: ratingWidget.starRating property var databaseId property var playList property var playerControl property bool isAlternateColor property var trackData signal clicked() Action { id: clearAndEnqueue text: i18nc("Clear play list and enqueue current track", "Play Now and Replace Play List") iconName: "media-playback-start" onTriggered: { playList.clearAndEnqueue(trackData) playerControl.ensurePlay() } } Action { id: enqueue text: i18nc("Enqueue current track", "Enqueue") iconName: "media-track-add-amarok" onTriggered: { playList.enqueue(trackData) } } Rectangle { id: highlightMarker anchors.fill: parent color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) MouseArea { id: hoverArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton onClicked: { hoverArea.forceActiveFocus() viewTrackDelegate.clicked() } onDoubleClicked: playList.enqueue(trackData) RowLayout { anchors.fill: parent spacing: 0 Item { Layout.preferredHeight: viewTrackDelegate.height * 0.9 Layout.preferredWidth: viewTrackDelegate.height * 0.9 Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Image { id: coverImageElement anchors.fill: parent sourceSize.width: viewTrackDelegate.height * 0.9 sourceSize.height: viewTrackDelegate.height * 0.9 fillMode: Image.PreserveAspectFit smooth: true source: (coverImage ? coverImage : Qt.resolvedUrl(elisaTheme.albumCover)) asynchronous: true - layer.enabled: true + layer.enabled: image == undefined ? false : true layer.effect: DropShadow { horizontalOffset: viewTrackDelegate.height * 0.02 verticalOffset: viewTrackDelegate.height * 0.02 source: coverImageElement radius: 5.0 samples: 11 color: myPalette.shadow } } } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignLeft spacing: 0 LabelWithToolTip { id: mainLabel text: trackNumber + ' - ' + title horizontalAlignment: Text.AlignLeft 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 elide: "ElideRight" } Item { Layout.fillHeight: true } LabelWithToolTip { id: artistLabel text: artist + ' - ' + albumName horizontalAlignment: Text.AlignLeft 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 elide: "ElideRight" } } ToolButton { id: enqueueButton Layout.preferredHeight: elisaTheme.trackDelegateHeight * 0.75 Layout.preferredWidth: elisaTheme.trackDelegateHeight * 0.75 opacity: 0 visible: opacity > 0.1 action: enqueue Layout.alignment: Qt.AlignVCenter | Qt.AlignRight } ToolButton { id: clearAndEnqueueButton Layout.preferredHeight: elisaTheme.trackDelegateHeight * 0.75 Layout.preferredWidth: elisaTheme.trackDelegateHeight * 0.75 opacity: 0 visible: opacity > 0.1 action: clearAndEnqueue Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 } RatingStar { id: ratingWidget starSize: elisaTheme.ratingStarSize Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.leftMargin: elisaTheme.layoutHorizontalMargin Layout.rightMargin: elisaTheme.layoutHorizontalMargin } LabelWithToolTip { id: durationLabel text: duration font.weight: Font.Light color: myPalette.text elide: "ElideRight" 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 && !viewTrackDelegate.activeFocus PropertyChanges { target: clearAndEnqueueButton opacity: 0 } PropertyChanges { target: enqueueButton opacity: 0 } PropertyChanges { target: highlightMarker color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) } }, State { name: 'hoveredAndNotSelected' when: hoverArea.containsMouse || viewTrackDelegate.activeFocus PropertyChanges { target: clearAndEnqueueButton opacity: 1 } PropertyChanges { target: enqueueButton opacity: 1 } PropertyChanges { target: highlightMarker color: myPalette.mid } } ] transitions: Transition { ParallelAnimation { NumberAnimation { properties: "height, opacity" easing.type: Easing.InOutQuad duration: 50 } ColorAnimation { properties: "color" duration: 200 } } } }