diff --git a/src/qml/PlayListEntry.qml b/src/qml/PlayListEntry.qml index f0ffc17a..53e7157a 100644 --- a/src/qml/PlayListEntry.qml +++ b/src/qml/PlayListEntry.qml @@ -1,454 +1,455 @@ /* * 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.7 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.2 import QtQuick.Controls 1.4 as Controls1 import QtQuick.Window 2.2 import QtGraphicalEffects 1.0 import org.kde.elisa 1.0 FocusScope { id: playListEntry property var index property bool isSingleDiscAlbum property int isPlaying property bool isSelected property bool isValid property bool isAlternateColor property bool containsMouse property bool hasAlbumHeader property string titleDisplay property alias trackData: dataHelper.trackData signal startPlayback() signal pausePlayback() signal removeFromPlaylist(var trackIndex) signal switchToTrack(var trackIndex) height: (hasAlbumHeader ? elisaTheme.delegateWithHeaderHeight : elisaTheme.delegateHeight) Controls1.Action { id: removeFromPlayList text: i18nc("Remove current track from play list", "Remove") iconName: "error" onTriggered: { playListEntry.removeFromPlaylist(playListEntry.index) } } Controls1.Action { id: playNow text: i18nc("Play now current track from play list", "Play Now") iconName: "media-playback-start" enabled: !(isPlaying === MediaPlayList.IsPlaying) && isValid onTriggered: { if (isPlaying === MediaPlayList.NotPlaying) { playListEntry.switchToTrack(playListEntry.index) } playListEntry.startPlayback() } } Controls1.Action { id: pauseNow text: i18nc("Pause current track from play list", "Pause") iconName: "media-playback-pause" enabled: isPlaying == MediaPlayList.IsPlaying && isValid onTriggered: playListEntry.pausePlayback() } Controls1.Action { id: showInfo text: i18nc("Show track metadata", "View Details") iconName: "help-about" enabled: isValid onTriggered: { if (metadataLoader.active === false) { metadataLoader.active = true } else { metadataLoader.item.close(); metadataLoader.active = false } } } TrackDataHelper { id: dataHelper } Loader { id: metadataLoader active: false onLoaded: item.show() sourceComponent: MediaTrackMetadataView { trackDataHelper: dataHelper onRejected: metadataLoader.active = false; } } Rectangle { id: entryBackground anchors.fill: parent color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) height: (hasAlbumHeader ? elisaTheme.delegateWithHeaderHeight : elisaTheme.delegateHeight) focus: true ColumnLayout { spacing: 0 anchors.fill: parent anchors.leftMargin: elisaTheme.layoutHorizontalMargin anchors.rightMargin: elisaTheme.layoutHorizontalMargin Item { Layout.fillWidth: true Layout.preferredHeight: elisaTheme.delegateWithHeaderHeight - elisaTheme.delegateHeight Layout.minimumHeight: elisaTheme.delegateWithHeaderHeight - elisaTheme.delegateHeight Layout.maximumHeight: elisaTheme.delegateWithHeaderHeight - elisaTheme.delegateHeight visible: hasAlbumHeader RowLayout { id: headerRow spacing: elisaTheme.layoutHorizontalMargin anchors.fill: parent Image { id: mainIcon source: (isValid ? (dataHelper.hasValidAlbumCover ? dataHelper.albumCover : Qt.resolvedUrl(elisaTheme.defaultAlbumImage)) : Qt.resolvedUrl(elisaTheme.errorIcon)) Layout.minimumWidth: headerRow.height - 4 Layout.maximumWidth: headerRow.height - 4 Layout.preferredWidth: headerRow.height - 4 Layout.minimumHeight: headerRow.height - 4 Layout.maximumHeight: headerRow.height - 4 Layout.preferredHeight: headerRow.height - 4 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter sourceSize.width: headerRow.height - 4 sourceSize.height: parent.height - 4 fillMode: Image.PreserveAspectFit asynchronous: true visible: isValid } BrightnessContrast { source: mainIcon cached: true visible: !isValid contrast: -0.9 Layout.minimumWidth: headerRow.height - 4 Layout.maximumWidth: headerRow.height - 4 Layout.preferredWidth: headerRow.height - 4 Layout.minimumHeight: headerRow.height - 4 Layout.maximumHeight: headerRow.height - 4 Layout.preferredHeight: headerRow.height - 4 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true spacing: 0 LabelWithToolTip { id: mainLabel text: dataHelper.albumName font.weight: Font.Bold color: myPalette.text horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true Layout.alignment: Qt.AlignCenter Layout.topMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } Item { Layout.fillHeight: true } LabelWithToolTip { id: authorLabel text: dataHelper.albumArtist font.weight: Font.Light color: myPalette.text horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true Layout.alignment: Qt.AlignCenter Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } } } } Item { Layout.fillWidth: true Layout.fillHeight: true RowLayout { id: trackRow anchors.fill: parent spacing: elisaTheme.layoutHorizontalMargin LabelWithToolTip { id: mainCompactLabel text: { if (dataHelper.hasValidTrackNumber) { if (dataHelper.hasValidDiscNumber && !isSingleDiscAlbum) return i18nc("%1: disk number. %2: track number. %3: track title", "%1 - %2 - %3", Number(dataHelper.discNumber).toLocaleString(Qt.locale(), 'f', 0), Number(dataHelper.trackNumber).toLocaleString(Qt.locale(), 'f', 0), dataHelper.title); else return i18nc("%1: track number. %2: track title", "%1 - %2", Number(dataHelper.trackNumber).toLocaleString(Qt.locale(), 'f', 0), dataHelper.title); } else { return dataHelper.title; } } font.weight: (isPlaying ? Font.Bold : Font.Normal) color: myPalette.text Layout.maximumWidth: mainCompactLabel.implicitWidth + 1 Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft visible: isValid elide: Text.ElideRight horizontalAlignment: Text.AlignLeft } LabelWithToolTip { id: mainInvalidCompactLabel text: titleDisplay font.weight: Font.Normal color: myPalette.text Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft visible: !isValid elide: Text.ElideRight } Item { Layout.fillWidth: true Layout.preferredWidth: 0 } Controls1.ToolButton { id: infoButton objectName: 'infoButton' implicitHeight: elisaTheme.smallDelegateToolButtonSize implicitWidth: elisaTheme.smallDelegateToolButtonSize opacity: 0 visible: opacity > 0.1 action: showInfo Layout.alignment: Qt.AlignVCenter | Qt.AlignRight } Controls1.ToolButton { id: playPauseButton objectName: 'playPauseButton' implicitHeight: elisaTheme.smallDelegateToolButtonSize implicitWidth: elisaTheme.smallDelegateToolButtonSize opacity: 0 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 } 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' anchors.fill: parent opacity: 0 visible: opacity > 0.1 action: removeFromPlayList } Image { id: playIcon anchors.fill: parent opacity: 0 - source: Qt.resolvedUrl(elisaTheme.playIndicatorIcon) + source: (isPlaying === MediaPlayList.IsPlaying ? + Qt.resolvedUrl(elisaTheme.playingIndicatorIcon) : Qt.resolvedUrl(elisaTheme.pausedIndicatorIcon)) 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 } } RatingStar { id: ratingWidget starRating: dataHelper.rating starSize: elisaTheme.ratingStarSize } TextMetrics { id: durationTextMetrics text: i18nc("This is used to preserve a fixed width for the duration text.", "00:00") } LabelWithToolTip { id: durationLabel text: dataHelper.duration color: myPalette.text Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.preferredWidth: durationTextMetrics.width + 1 horizontalAlignment: Text.AlignRight } } } } } states: [ State { name: 'notSelected' when: !containsMouse && (!playListEntry.activeFocus || !isSelected) PropertyChanges { target: removeButton opacity: 0 } PropertyChanges { target: infoButton opacity: 0 } PropertyChanges { target: playPauseButton opacity: 0 } PropertyChanges { target: playIcon - opacity: (isPlaying === MediaPlayList.IsPlaying ? 1.0 : 0.0) + opacity: (isPlaying === MediaPlayList.IsPlaying || isPlaying === MediaPlayList.IsPaused ? 1.0 : 0.0) } PropertyChanges { target: entryBackground color: (isAlternateColor ? myPalette.alternateBase : myPalette.base) } }, State { name: 'hoveredOrSelected' when: containsMouse || (playListEntry.activeFocus && isSelected) PropertyChanges { target: removeButton opacity: 1 } PropertyChanges { target: playPauseButton opacity: 1 } PropertyChanges { target: infoButton opacity: 1 } PropertyChanges { target: playIcon opacity: 0 } PropertyChanges { target: entryBackground color: myPalette.mid } } ] transitions: Transition { ParallelAnimation { NumberAnimation { properties: "opacity" easing.type: Easing.InOutQuad duration: 250 } ColorAnimation { properties: "color" duration: 250 } } } } diff --git a/src/qml/Theme.qml b/src/qml/Theme.qml index c1a3fcab..a1b5982d 100644 --- a/src/qml/Theme.qml +++ b/src/qml/Theme.qml @@ -1,97 +1,98 @@ /* * Copyright 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.7 import QtQuick.Controls 2.2 Item { function dp(pixel) { // 96 - common, "base" DPI value return Math.round(pixel * logicalDpi / 96); } property string defaultAlbumImage: 'image://icon/media-optical-audio' property string defaultArtistImage: 'image://icon/view-media-artist' property string defaultBackgroundImage: 'qrc:///background.png' property string artistIcon: 'image://icon/view-media-artist' property string albumIcon: 'image://icon/view-media-album-cover' property string playlistIcon: 'image://icon/view-media-playlist' property string tracksIcon: 'image://icon/view-media-track' property string genresIcon: 'image://icon/view-media-genre' property string clearIcon: 'image://icon/edit-clear' property string skipBackwardIcon: 'image://icon/media-skip-backward' property string pauseIcon: 'image://icon/media-playback-pause' property string playIcon: 'image://icon/media-playback-start' property string skipForwardIcon: 'image://icon/media-skip-forward' + property string pausedIndicatorIcon: 'image://icon/media-playback-paused' + property string playingIndicatorIcon: 'image://icon/media-playback-playing' property string playerVolumeMutedIcon: 'image://icon/player-volume-muted' property string playerVolumeIcon: 'image://icon/player-volume' property string ratingIcon: 'image://icon/rating' property string ratingUnratedIcon: 'image://icon/rating-unrated' property string errorIcon: 'image://icon/error' - property string playIndicatorIcon: 'image://icon/audio-volume-high' property string repeatIcon: 'image://icon/media-repeat-all' property string shuffleIcon: 'image://icon/media-playlist-shuffle' property string noRepeatIcon: 'image://icon/media-repeat-none' property string noShuffleIcon: 'image://icon/media-playlist-normal' property string folderIcon: 'image://icon/document-open-folder' property int layoutHorizontalMargin: dp(8) property int layoutVerticalMargin: dp(6) property int delegateHeight: dp(28) property int delegateWithHeaderHeight: dp(68) property int trackDelegateHeight: dp(45) property int coverImageSize: dp(180) property int smallImageSize: dp(32) property int trackMetadataWidth: dp(300) property int tooltipRadius: dp(3) property int shadowOffset: dp(2) property int delegateToolButtonSize: dp(34) property int smallDelegateToolButtonSize: dp(20) property int ratingStarSize: dp(15) property int mediaPlayerControlHeight: dp(42) property int mediaPlayerHorizontalMargin: dp(10) property real mediaPlayerControlOpacity: 0.6 property int smallControlButtonSize: dp(22) property int volumeSliderWidth: dp(100) property int dragDropPlaceholderHeight: dp(28) property int navigationBarHeight: dp(100) property int navigationBarFilterHeight: dp(44) property int gridDelegateHeight: dp(100) + layoutVerticalMargin + fontSize.height * 2 property int gridDelegateWidth: dp(100) property int viewSelectorDelegateHeight: dp(24) property int filterClearButtonMargin: layoutVerticalMargin property alias defaultFontPointSize: fontSize.font.pointSize Label { id: fontSize } } diff --git a/src/windows/PlatformIntegration.qml b/src/windows/PlatformIntegration.qml index e982a1cf..ab8fab62 100644 --- a/src/windows/PlatformIntegration.qml +++ b/src/windows/PlatformIntegration.qml @@ -1,70 +1,71 @@ /* * Copyright 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.0 import org.kde.elisa 1.0 import QtWinExtras 1.0 Item { id: rootItem property var playListModel property var playListControler property var audioPlayerManager property var player property var headerBarManager property var manageMediaPlayerControl signal raisePlayer() Theme { id: elisaTheme } TaskbarButton { progress.minimum: 0 progress.maximum: player.duration progress.value: player.position progress.visible: manageMediaPlayerControl.musicPlaying - overlay.iconSource: (manageMediaPlayerControl.musicPlaying ? Qt.resolvedUrl(elisaTheme.playIcon) : Qt.resolvedUrl(elisaTheme.pauseIcon)) + overlay.iconSource: (manageMediaPlayerControl.musicPlaying ? + Qt.resolvedUrl(elisaTheme.playingIndicatorIcon) : Qt.resolvedUrl(elisaTheme.pausedIndicatorIcon)) } ThumbnailToolBar { iconicThumbnailSource: (headerBarManager.image.toString() !== '' ? headerBarManager.image : Qt.resolvedUrl(elisaTheme.albumCover)) ThumbnailToolButton { iconSource: Qt.resolvedUrl(LayoutMirroring.enabled ? elisaTheme.skipForwardIcon : elisaTheme.skipBackwardIcon) onClicked: playListControler.skipPreviousTrack() enabled: manageMediaPlayerControl.skipBackwardControlEnabled } ThumbnailToolButton { iconSource: (manageMediaPlayerControl.musicPlaying ? Qt.resolvedUrl(elisaTheme.pauseIcon) : Qt.resolvedUrl(elisaTheme.playIcon)) onClicked: audioPlayerManager.playPause() enabled: manageMediaPlayerControl.playControlEnabled } ThumbnailToolButton { iconSource: Qt.resolvedUrl(LayoutMirroring.enabled ? elisaTheme.skipBackwardIcon : elisaTheme.skipForwardIcon) onClicked: playListControler.skipNextTrack() enabled: manageMediaPlayerControl.skipForwardControlEnabled } } } diff --git a/src/windows/WindowsTheme.qml b/src/windows/WindowsTheme.qml index 1c322532..71b1b93c 100644 --- a/src/windows/WindowsTheme.qml +++ b/src/windows/WindowsTheme.qml @@ -1,96 +1,98 @@ /* * Copyright 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.7 import QtQuick.Controls 1.4 Item { function dp(pixel) { // 96 - common, "base" DPI value return Math.round(pixel * logicalDpi / 96); } property string defaultAlbumImage: 'image://icon/media-optical-audio' property string defaultArtistImage: 'image://icon/view-media-artist' property string defaultBackgroundImage: 'qrc:///background.png' property string artistIcon: 'image://icon/view-media-artist' property string albumIcon: 'image://icon/view-media-album-cover' property string playlistIcon: 'image://icon/view-media-playlist' property string tracksIcon: 'image://icon/view-media-track' property string genresIcon: 'image://icon/view-media-genre' property string clearIcon: 'image://icon/edit-clear' property string skipBackwardIcon: 'image://icon/media-skip-backward' property string pauseIcon: 'image://icon/media-playback-pause' property string playIcon: 'image://icon/media-playback-start' property string skipForwardIcon: 'image://icon/media-skip-forward' + property string pausedIndicatorIcon: 'image://icon/media-playback-paused' + property string playingIndicatorIcon: 'image://icon/media-playback-playing' property string playerVolumeMutedIcon: 'image://icon/player-volume-muted' property string playerVolumeIcon: 'image://icon/player-volume' property string ratingIcon: 'image://icon/rating' property string ratingUnratedIcon: 'image://icon/rating-unrated' property string errorIcon: 'image://icon/error' property string repeatIcon: 'image://icon/media-repeat-all' property string shuffleIcon: 'image://icon/media-playlist-shuffle' property string noRepeatIcon: 'image://icon/media-repeat-none' property string noShuffleIcon: 'image://icon/media-playlist-normal' property string folderIcon: 'image://icon/document-open-folder' property int layoutHorizontalMargin: dp(8) property int layoutVerticalMargin: dp(6) property int delegateHeight: dp(28) property int delegateWithHeaderHeight: dp(68) property int trackDelegateHeight: dp(45) property int coverImageSize: dp(180) property int smallImageSize: dp(32) property int trackMetadataWidth: dp(300) property int tooltipRadius: dp(3) property int shadowOffset: dp(2) property int delegateToolButtonSize: dp(34) property int smallDelegateToolButtonSize: dp(20) property int ratingStarSize: dp(15) property int mediaPlayerControlHeight: dp(42) property int mediaPlayerHorizontalMargin: dp(10) property real mediaPlayerControlOpacity: 0.8 property int smallControlButtonSize: dp(22) property int volumeSliderWidth: dp(100) property int dragDropPlaceholderHeight: dp(28) property int navigationBarHeight: dp(100) property int navigationBarFilterHeight: dp(44) property int gridDelegateHeight: dp(100) + layoutVerticalMargin + fontSize.height * 2 property int gridDelegateWidth: dp(100) property int viewSelectorDelegateHeight: dp(24) property int filterClearButtonMargin: 1 property alias defaultFontPointSize: fontSize.font.pointSize Label { id: fontSize } }