diff --git a/src/MediaAlbumDelegate.qml b/src/MediaAlbumDelegate.qml index 678d346e..63fdbc31 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.preferredHeight: mediaServerEntry.width * 0.85 + 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 + height: mediaServerEntry.width * 0.85 + 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.preferredHeight: mediaServerEntry.width * 0.85 + Layout.preferredWidth: mediaServerEntry.width * 0.85 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 + sourceSize.width: parent.width + sourceSize.height: parent.height fillMode: Image.PreserveAspectFit smooth: true source: (mediaServerEntry.image ? mediaServerEntry.image : Qt.resolvedUrl(elisaTheme.albumCover)) asynchronous: 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.preferredWidth: mediaServerEntry.width * 0.85 Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom elide: Text.ElideRight } LabelWithToolTip { id: artistLabel - font.weight: Font.Normal + font.weight: Font.Light color: myPalette.text horizontalAlignment: Text.AlignLeft - Layout.preferredWidth: mediaServerEntry.width * 0.9 + Layout.preferredWidth: mediaServerEntry.width * 0.85 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/MediaAllAlbumView.qml b/src/MediaAllAlbumView.qml index e50ff463..2282bfe1 100644 --- a/src/MediaAllAlbumView.qml +++ b/src/MediaAllAlbumView.qml @@ -1,142 +1,142 @@ /* * 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.5 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 var rootIndex property StackView stackView property MediaPlayList playListModel property var musicListener property var playerControl property var contentDirectoryModel signal showArtist(var name) id: rootElement SystemPalette { id: myPalette colorGroup: SystemPalette.Active } Theme { id: elisaTheme } ColumnLayout { anchors.fill: parent spacing: 0 FilterBar { id: filterBar labelText: i18nc("Title of the view of all albums", "Albums") height: elisaTheme.navigationBarHeight Layout.preferredHeight: height Layout.minimumHeight: height Layout.maximumHeight: height Layout.fillWidth: true } Rectangle { color: myPalette.base Layout.fillHeight: true Layout.fillWidth: true ScrollView { focus: true anchors.fill: parent flickableItem.boundsBehavior: Flickable.StopAtBounds GridView { id: contentDirectoryView focus: true TextMetrics { id: textLineHeight text: 'Album' } cellWidth: elisaTheme.gridDelegateWidth - cellHeight: elisaTheme.gridDelegateWidth + elisaTheme.layoutVerticalMargin * 3 + textLineHeight.height * 2 + cellHeight: elisaTheme.gridDelegateWidth + elisaTheme.layoutVerticalMargin + textLineHeight.height * 2 model: DelegateModel { id: delegateContentModel model: AlbumFilterProxyModel { sourceModel: rootElement.contentDirectoryModel filterText: filterBar.filterText filterRating: filterBar.filterRating } delegate: MediaAlbumDelegate { width: contentDirectoryView.cellWidth height: contentDirectoryView.cellHeight focus: true musicListener: rootElement.musicListener image: model.image title: if (model.title) model.title else "" artist: if (model.artist) model.artist else "" trackNumber: if (model.count !== undefined) i18np("1 track", "%1 tracks", model.count) else i18nc("Number of tracks for an album", "0 track") isSingleDiscAlbum: model.isSingleDiscAlbum albumData: model.albumData albumId: model.albumId stackView: rootElement.stackView playListModel: rootElement.playListModel playerControl: rootElement.playerControl onAlbumClicked: contentDirectoryView.currentIndex = index onShowArtist: rootElement.showArtist(name) } } } } } } } diff --git a/src/MediaAllArtistView.qml b/src/MediaAllArtistView.qml index 2742cf7b..cbc9d5a8 100644 --- a/src/MediaAllArtistView.qml +++ b/src/MediaAllArtistView.qml @@ -1,155 +1,155 @@ /* * 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.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 var playerControl property var playListModel property var artistsModel property var stackView property var contentDirectoryModel property var musicListener id: rootElement SystemPalette { id: myPalette colorGroup: SystemPalette.Active } Theme { id: elisaTheme } ColumnLayout { anchors.fill: parent spacing: 0 FilterBar { id: filterBar labelText: i18nc("Title of the view of all artists", "Artists") showRating: false height: elisaTheme.navigationBarHeight Layout.preferredHeight: height Layout.minimumHeight: height Layout.maximumHeight: height Layout.fillWidth: true } Rectangle { color: myPalette.base Layout.fillHeight: true Layout.fillWidth: true ScrollView { focus: true anchors.fill: parent flickableItem.boundsBehavior: Flickable.StopAtBounds GridView { id: contentDirectoryView focus: true TextMetrics { id: textLineHeight text: 'Artist' } cellWidth: elisaTheme.gridDelegateWidth - cellHeight: elisaTheme.gridDelegateWidth + elisaTheme.layoutVerticalMargin * 2 + textLineHeight.height + cellHeight: elisaTheme.gridDelegateWidth + elisaTheme.layoutVerticalMargin + textLineHeight.height * 2 model: DelegateModel { id: delegateContentModel model: SortFilterProxyModel { sourceModel: artistsModel filterRole: AllArtistsModel.NameRole filterRegExp: new RegExp(filterBar.filterText, 'i') } delegate: MediaArtistDelegate { width: contentDirectoryView.cellWidth height: contentDirectoryView.cellHeight focus: true musicListener: rootElement.musicListener image: if (model.image) model.image else "" name: if (model.name) model.name else "" stackView: rootElement.stackView playListModel: rootElement.playListModel playerControl: rootElement.playerControl contentDirectoryModel: rootElement.contentDirectoryModel onArtistClicked: contentDirectoryView.currentIndex = index onOpenArtist: showArtistsAlbums(name) } } } } } } Component { id: oneArtistView MediaArtistAlbumView { playListModel: rootElement.playListModel contentDirectoryModel: rootElement.contentDirectoryModel playerControl: rootElement.playerControl stackView: rootElement.stackView musicListener: rootElement.musicListener onShowArtist: showArtistsAlbums(name) } } function showArtistsAlbums(name){ if (stackView.depth === 3) { stackView.pop() } else { stackView.push(oneArtistView, {artistName: name}) } } } diff --git a/src/MediaArtistDelegate.qml b/src/MediaArtistDelegate.qml index b7f71c3c..31362866 100644 --- a/src/MediaArtistDelegate.qml +++ b/src/MediaArtistDelegate.qml @@ -1,249 +1,247 @@ /* * 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.preferredHeight: mediaServerEntry.width * 0.85 + 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 + height: mediaServerEntry.width * 0.85 + 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.preferredWidth: mediaServerEntry.width * 0.85 + Layout.preferredHeight: mediaServerEntry.width * 0.85 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 + sourceSize.width: parent.width + sourceSize.height: parent.height fillMode: Image.PreserveAspectFit smooth: true asynchronous: 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.preferredWidth: mediaServerEntry.width * 0.85 + Layout.topMargin: elisaTheme.layoutVerticalMargin * 0.5 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/Theme.qml b/src/Theme.qml index f3431d3b..3cef7704 100644 --- a/src/Theme.qml +++ b/src/Theme.qml @@ -1,76 +1,76 @@ /* * 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 { property string albumCover: 'image://icon/media-optical-audio' property string artistImage: 'image://icon/view-media-artist' 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 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 int layoutHorizontalMargin: 8 property int layoutVerticalMargin: 6 property int delegateHeight: 28 property int delegateWithHeaderHeight: 68 property int trackDelegateHeight: 45 property int coverImageSize: 180 property int smallImageSize: 32 property int tooltipRadius: 3 property int shadowOffset: 2 property int delegateToolButtonSize: 34 property int smallDelegateToolButtonSize: 20 property int ratingStarSize: 15 property int mediaPlayerControlHeight: 48 property int smallControlButtonHeight: 32 property int bigControlButtonHeight: 44 property int volumeSliderWidth: 140 property int dragDropPlaceholderHeight: 28 property int navigationBarHeight: 100 property int gridDelegateHeight: 168 - property int gridDelegateWidth: 112 + property int gridDelegateWidth: 100 property int viewSelectorDelegateHeight: 32 property int filterClearButtonMargin: layoutVerticalMargin property alias defaultFontPixelSize: fontSize.font.pixelSize Label { id: fontSize } }