diff --git a/src/qml/BaseTheme.qml b/src/qml/BaseTheme.qml index 3004e078..00bd6f54 100644 --- a/src/qml/BaseTheme.qml +++ b/src/qml/BaseTheme.qml @@ -1,108 +1,106 @@ /* * Copyright 2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 Item { property string defaultAlbumImage: 'image://icon/media-optical-audio' property string defaultArtistImage: 'image://icon/view-media-artist' property string defaultBackgroundImage: 'qrc:///background.png' property string nowPlayingIcon: 'image://icon/view-media-lyrics' property string artistIcon: 'image://icon/view-media-artist' property string albumIcon: 'image://icon/view-media-album-cover' property string albumCoverIcon: 'image://icon/media-optical-audio' 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 recentlyPlayedTracksIcon: 'image://icon/media-playlist-play' property string frequentlyPlayedTracksIcon: 'image://icon/view-media-playcount' property string pausedIndicatorIcon: 'image://icon/media-playback-paused' property string playingIndicatorIcon: 'image://icon/media-playback-playing' property string ratingIcon: 'image://icon/rating' property string ratingUnratedIcon: 'image://icon/rating-unrated' property string errorIcon: 'image://icon/error' property string folderIcon: 'image://icon/document-open-folder' property int layoutHorizontalMargin: 8 property int layoutVerticalMargin: 6 property int delegateHeight: 28 // FIXME: don't hardcode these; derive them from the layouts they're used in FontMetrics { id: playListAuthorTextHeight font.weight: Font.Light } FontMetrics { id: playListAlbumTextHeight font.weight: Font.Bold font.pointSize: Math.round(fontSize.font.pointSize * 1.4) } FontMetrics { id: playListTrackTextHeight font.weight: Font.Bold } property int playListDelegateHeight: (playListTrackTextHeight.height > 28) ? playListTrackTextHeight.height : 28 property int trackDelegateHeight: elisaTheme.layoutVerticalMargin + fontSize.height * 2 // END FIXME property int playListAlbumArtSize: 70 property int coverImageSize: 180 property int contextCoverImageSize: 100 property int smallImageSize: 32 property int maximumMetadataWidth: 300 property int tooltipRadius: 3 property int shadowOffset: 2 property int delegateToolButtonSize: 34 property int smallDelegateToolButtonSize: 20 property int ratingStarSize: 15 property int mediaPlayerControlHeight: 42 property int mediaPlayerHorizontalMargin: 10 property real mediaPlayerControlOpacity: 0.6 property int smallControlButtonSize: 22 property int volumeSliderWidth: 100 property int dragDropPlaceholderHeight: 28 property int navigationBarHeight: 100 property int navigationBarFilterHeight: 44 - property real gridDelegateThumbnail: 0.85 - property int gridDelegateHeight: 170 * gridDelegateThumbnail + layoutVerticalMargin - property int gridDelegateWidth: 170 + property int gridDelegateSize: 170 property int viewSelectorDelegateHeight: 24 property int filterClearButtonMargin: layoutVerticalMargin property int headerToolbarHeight: 48 property int footerToolbarHeight: 30 property int viewSelectorSmallSizeThreshold: 800 Label { id: fontSize } } diff --git a/src/qml/FileBrowserView.qml b/src/qml/FileBrowserView.qml index 57f0bc9c..9f2db690 100644 --- a/src/qml/FileBrowserView.qml +++ b/src/qml/FileBrowserView.qml @@ -1,189 +1,188 @@ /* * Copyright 2016-2018 Matthieu Gallien * Copyright 2018 Alexander Stippich * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQml.Models 2.2 import QtQuick.Layouts 1.2 import org.kde.elisa 1.0 FocusScope { id: fileView property var viewType property bool isSubPage: false property alias expandedFilterView: navigationBar.expandedFilterView function goBack() { proxyModel.openParentFolder() } function loadFolderAndClear(data) { proxyModel.openFolder(data) navigationBar.filterText = "" } FileBrowserModel { id: realModel } FileBrowserProxyModel { id: proxyModel sourceModel: realModel playList: elisa.mediaPlayList } MouseArea { anchors.fill: parent hoverEnabled: false acceptedButtons: Qt.BackButton onClicked: proxyModel.openParentFolder() } ColumnLayout { anchors.fill: parent spacing: 0 NavigationActionBar { id: navigationBar mainTitle: i18nc("Title of the file browser view", "Files") image: elisaTheme.folderIcon secondaryTitle: proxyModel.url enableGoBack: proxyModel.canGoBack sortOrder: proxyModel.sortedAscending showRating: false Layout.fillWidth: true Binding { target: proxyModel property: 'filterText' value: navigationBar.filterText } onEnqueue: proxyModel.enqueueToPlayList() onReplaceAndPlay: proxyModel.replaceAndPlayOfPlayList() onGoBack: proxyModel.openParentFolder() onSort: proxyModel.sortModel(order) } Rectangle { color: myPalette.base Layout.fillHeight: true Layout.fillWidth: true clip: true GridView { id: contentDirectoryView anchors.fill: parent activeFocusOnTab: true keyNavigationEnabled: true ScrollBar.vertical: ScrollBar { id: scrollBar } boundsBehavior: Flickable.StopAtBounds currentIndex: -1 Accessible.role: Accessible.List Accessible.name: proxyModel.url model: proxyModel TextMetrics { id: secondaryLabelSize text: 'example' } ScrollHelper { id: scrollHelper flickable: contentDirectoryView anchors.fill: contentDirectoryView } add: Transition { PropertyAnimation { property: "opacity" from: 0 to: 1 duration: 100 } } remove: Transition { PropertyAnimation { property: "opacity" from: 0 to: 1 duration: 100 } } - cellWidth: Math.floor(availableWidth / Math.max(Math.floor(availableWidth / elisaTheme.gridDelegateWidth), 2)) - cellHeight: elisaTheme.gridDelegateHeight + - (secondaryLabelSize.boundingRect.height - secondaryLabelSize.boundingRect.y) + cellWidth: Math.floor(availableWidth / Math.max(Math.floor(availableWidth / elisaTheme.gridDelegateSize), 2)) + cellHeight: elisaTheme.gridDelegateSize + secondaryLabelSize.boundingRect.height * 2 + elisaTheme.layoutVerticalMargin * 2 delegate: GridBrowserDelegate { - width: elisaTheme.gridDelegateWidth + width: elisaTheme.gridDelegateSize height: contentDirectoryView.cellHeight focus: true isSelected: contentDirectoryView.currentIndex === index mainText: model.name delegateDisplaySecondaryText: false fileUrl: model.fileUrl entryType: ElisaUtils.FileName imageUrl: model.imageUrl showDetailsButton: !model.isDirectory && !model.isPlaylist showEnqueueButton: !model.isDirectory && !model.isPlaylist showPlayButton: !model.isDirectory showOpenButton: model.isDirectory && !model.isPlaylist onEnqueue: elisa.mediaPlayList.enqueue(url, ElisaUtils.FileName, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: { if (model.isPlaylist) { elisa.mediaPlayList.loadPlaylist(url) } else { elisa.mediaPlayList.enqueue(url, ElisaUtils.FileName, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) } } onSelected: { forceActiveFocus() contentDirectoryView.currentIndex = model.index } onActiveFocusChanged: { if (activeFocus && contentDirectoryView.currentIndex !== model.index) { contentDirectoryView.currentIndex = model.index } } onOpen: isDirectory ? loadFolderAndClear(model.fileUrl) : elisa.mediaPlayList.enqueue(model.fileUrl, ElisaUtils.FileName, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) } } } } } diff --git a/src/qml/GridBrowserDelegate.qml b/src/qml/GridBrowserDelegate.qml index a4716eed..be85e900 100644 --- a/src/qml/GridBrowserDelegate.qml +++ b/src/qml/GridBrowserDelegate.qml @@ -1,443 +1,441 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Window 2.2 import QtQml.Models 2.1 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.5 as Kirigami FocusScope { id: gridEntry property var imageUrl property bool shadowForImage property url fileUrl property var entryType property alias mainText: mainLabel.text property alias secondaryText: secondaryLabel.text property var databaseId property bool delegateDisplaySecondaryText: true property bool isPartial property bool isSelected property bool showDetailsButton: false property bool showOpenButton: true property bool showPlayButton: true property bool showEnqueueButton: true signal enqueue(var databaseId, var name, var url) signal replaceAndPlay(var databaseId, var name, var url) signal open() signal selected() Loader { id: metadataLoader active: false && gridEntry.fileUrl onLoaded: item.show() sourceComponent: MediaTrackMetadataView { fileName: gridEntry.fileUrl ? gridEntry.fileUrl : '' showImage: true modelType: gridEntry.entryType showTrackFileName: true showDeleteButton: false showApplyButton: false editableMetadata: false onRejected: metadataLoader.active = false; } } Keys.onReturnPressed: open() Keys.onEnterPressed: open() Accessible.role: Accessible.ListItem Accessible.name: mainText Rectangle { id: stateIndicator anchors.fill: parent z: 1 color: "transparent" opacity: 0.4 radius: 3 } - ColumnLayout { + MouseArea { + id: hoverHandle + anchors.fill: parent z: 2 - spacing: 0 + hoverEnabled: true + acceptedButtons: Qt.LeftButton - MouseArea { - id: hoverHandle + Layout.preferredHeight: gridEntry.height + Layout.fillWidth: true - hoverEnabled: true - acceptedButtons: Qt.LeftButton + onClicked: { + gridEntry.selected() + } - Layout.preferredHeight: gridEntry.height - Layout.fillWidth: true + onDoubleClicked: open() - onClicked: { - gridEntry.selected() - } - - onDoubleClicked: open() + TextMetrics { + id: mainLabelSize + font: mainLabel.font + text: mainLabel.text + } - TextMetrics { - id: mainLabelSize - font: mainLabel.font - text: mainLabel.text - } + TextMetrics { + id: secondaryLabelSize + font: secondaryLabel.font + text: secondaryLabel.text + } - TextMetrics { - id: secondaryLabelSize - font: secondaryLabel.font - text: secondaryLabel.text - } + ColumnLayout { + id: mainData - ColumnLayout { - id: mainData + spacing: 0 + anchors.fill: parent - spacing: 0 - anchors.fill: parent + Item { - Item { - Layout.preferredHeight: gridEntry.width * elisaTheme.gridDelegateThumbnail - Layout.preferredWidth: gridEntry.width * elisaTheme.gridDelegateThumbnail + Layout.margins: 2 * elisaTheme.layoutVerticalMargin + Layout.preferredHeight: gridEntry.width - 4 * elisaTheme.layoutVerticalMargin + Layout.preferredWidth: gridEntry.width - 4 * elisaTheme.layoutVerticalMargin - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - Loader { - id: hoverLoader - active: false + Loader { + id: hoverLoader + active: false - anchors { - bottom: parent.bottom - bottomMargin: 2 - left: parent.left - leftMargin: 2 - } + anchors { + bottom: parent.bottom + bottomMargin: 2 + left: parent.left + leftMargin: 2 + } - z: 1 + z: 1 - opacity: 0 + opacity: 0 - sourceComponent: Row { - spacing: 2 + sourceComponent: Row { + spacing: 2 - Button { - id: detailsButton - objectName: 'detailsButton' + Button { + id: detailsButton + objectName: 'detailsButton' - icon.name: 'help-about' + icon.name: 'help-about' - hoverEnabled: true - ToolTip.visible: hovered - ToolTip.delay: 1000 - ToolTip.text: i18nc("Show track metadata", "View Details") + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.delay: 1000 + ToolTip.text: i18nc("Show track metadata", "View Details") - Accessible.role: Accessible.Button - Accessible.name: ToolTip.text - Accessible.description: ToolTip.text - Accessible.onPressAction: clicked() + Accessible.role: Accessible.Button + Accessible.name: ToolTip.text + Accessible.description: ToolTip.text + Accessible.onPressAction: clicked() - onClicked: { - if (metadataLoader.active === false) { - metadataLoader.active = true - } - else { - metadataLoader.item.close(); - metadataLoader.active = false - } + onClicked: { + if (metadataLoader.active === false) { + metadataLoader.active = true + } + else { + metadataLoader.item.close(); + metadataLoader.active = false } + } - Keys.onReturnPressed: clicked() - Keys.onEnterPressed: clicked() - visible: showDetailsButton + Keys.onReturnPressed: clicked() + Keys.onEnterPressed: clicked() + visible: showDetailsButton - width: elisaTheme.delegateToolButtonSize - height: elisaTheme.delegateToolButtonSize - } + width: elisaTheme.delegateToolButtonSize + height: elisaTheme.delegateToolButtonSize + } - Button { - id: replaceAndPlayButton - objectName: 'replaceAndPlayButton' + Button { + id: replaceAndPlayButton + objectName: 'replaceAndPlayButton' - icon.name: 'media-playback-start' + icon.name: 'media-playback-start' - hoverEnabled: true - ToolTip.visible: hovered - ToolTip.delay: 1000 - ToolTip.text: i18nc("Clear play list and add whole container to play list", "Play now, replacing current playlist") + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.delay: 1000 + ToolTip.text: i18nc("Clear play list and add whole container to play list", "Play now, replacing current playlist") - Accessible.role: Accessible.Button - Accessible.name: ToolTip.text - Accessible.description: ToolTip.text - Accessible.onPressAction: onClicked + Accessible.role: Accessible.Button + Accessible.name: ToolTip.text + Accessible.description: ToolTip.text + Accessible.onPressAction: onClicked - onClicked: replaceAndPlay(databaseId, mainText, fileUrl) - Keys.onReturnPressed: replaceAndPlay(databaseId, mainText, fileUrl) - Keys.onEnterPressed: replaceAndPlay(databaseId, mainText, fileUrl) + onClicked: replaceAndPlay(databaseId, mainText, fileUrl) + Keys.onReturnPressed: replaceAndPlay(databaseId, mainText, fileUrl) + Keys.onEnterPressed: replaceAndPlay(databaseId, mainText, fileUrl) - visible: showPlayButton + visible: showPlayButton - width: elisaTheme.delegateToolButtonSize - height: elisaTheme.delegateToolButtonSize - } + width: elisaTheme.delegateToolButtonSize + height: elisaTheme.delegateToolButtonSize + } - Button { - id: enqueueButton - objectName: 'enqueueButton' + Button { + id: enqueueButton + objectName: 'enqueueButton' - icon.name: 'list-add' - hoverEnabled: true - ToolTip.visible: hovered - ToolTip.delay: 1000 - ToolTip.text: i18nc("Add whole container to play list", "Add to playlist") + icon.name: 'list-add' + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.delay: 1000 + ToolTip.text: i18nc("Add whole container to play list", "Add to playlist") - Accessible.role: Accessible.Button - Accessible.name: ToolTip.text - Accessible.description: ToolTip.text - Accessible.onPressAction: onClicked + Accessible.role: Accessible.Button + Accessible.name: ToolTip.text + Accessible.description: ToolTip.text + Accessible.onPressAction: onClicked - onClicked: enqueue(databaseId, mainText, fileUrl) - Keys.onReturnPressed: enqueue(databaseId, mainText, fileUrl) - Keys.onEnterPressed: enqueue(databaseId, mainText, fileUrl) + onClicked: enqueue(databaseId, mainText, fileUrl) + Keys.onReturnPressed: enqueue(databaseId, mainText, fileUrl) + Keys.onEnterPressed: enqueue(databaseId, mainText, fileUrl) - visible: showEnqueueButton + visible: showEnqueueButton - width: elisaTheme.delegateToolButtonSize - height: elisaTheme.delegateToolButtonSize - } + width: elisaTheme.delegateToolButtonSize + height: elisaTheme.delegateToolButtonSize + } - Button { - id: openButton - objectName: 'openButton' + Button { + id: openButton + objectName: 'openButton' - icon.name: 'go-next-view-page' - hoverEnabled: true - ToolTip.visible: hovered - ToolTip.delay: 1000 - ToolTip.text: i18nc("Open view of the container", "Open") + icon.name: 'go-next-view-page' + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.delay: 1000 + ToolTip.text: i18nc("Open view of the container", "Open") - Accessible.role: Accessible.Button - Accessible.name: ToolTip.text - Accessible.description: ToolTip.text - Accessible.onPressAction: onClicked + Accessible.role: Accessible.Button + Accessible.name: ToolTip.text + Accessible.description: ToolTip.text + Accessible.onPressAction: onClicked - onClicked: open() + onClicked: open() - visible: showOpenButton + visible: showOpenButton - width: elisaTheme.delegateToolButtonSize - height: elisaTheme.delegateToolButtonSize - } + width: elisaTheme.delegateToolButtonSize + height: elisaTheme.delegateToolButtonSize } } + } - Loader { - id: coverImageLoader + Loader { + id: coverImageLoader - active: !isPartial + active: !isPartial - anchors.fill: parent + anchors.fill: parent - sourceComponent: Image { - id: coverImage + sourceComponent: Image { + id: coverImage - anchors.fill: parent + anchors.fill: parent - sourceSize.width: parent.width - sourceSize.height: parent.height - fillMode: Image.PreserveAspectFit - smooth: true + sourceSize.width: parent.width + sourceSize.height: parent.height + fillMode: Image.PreserveAspectFit + smooth: true - source: (gridEntry.imageUrl !== undefined ? gridEntry.imageUrl : "") + source: (gridEntry.imageUrl !== undefined ? gridEntry.imageUrl : "") - asynchronous: true + asynchronous: true - layer.enabled: shadowForImage - layer.effect: DropShadow { - source: coverImage + layer.enabled: shadowForImage + layer.effect: DropShadow { + source: coverImage - radius: 10 - spread: 0.1 - samples: 21 + radius: 10 + spread: 0.1 + samples: 21 - color: myPalette.shadow - } + color: myPalette.shadow } } - Loader { - active: isPartial + } + Loader { + active: isPartial - anchors.centerIn: parent - height: Kirigami.Units.gridUnit * 5 - width: height + anchors.centerIn: parent + height: Kirigami.Units.gridUnit * 5 + width: height - sourceComponent: BusyIndicator { - anchors.centerIn: parent + sourceComponent: BusyIndicator { + anchors.centerIn: parent - running: true - } + running: true } } + } - LabelWithToolTip { - id: mainLabel + LabelWithToolTip { + id: mainLabel - level: 4 + level: 4 - color: myPalette.text + color: myPalette.text - // FIXME: Center-aligned text looks better overall, but - // sometimes results in font kerning issues - // See https://bugreports.qt.io/browse/QTBUG-49646 - horizontalAlignment: Text.AlignHCenter + // FIXME: Center-aligned text looks better overall, but + // sometimes results in font kerning issues + // See https://bugreports.qt.io/browse/QTBUG-49646 + horizontalAlignment: Text.AlignHCenter - Layout.topMargin: elisaTheme.layoutVerticalMargin * 0.5 - Layout.maximumWidth: gridEntry.width * 0.9 - Layout.minimumWidth: Layout.maximumWidth - Layout.maximumHeight: delegateDisplaySecondaryText - ? (mainLabelSize.boundingRect.height - mainLabelSize.boundingRect.y) - : (mainLabelSize.boundingRect.height - mainLabelSize.boundingRect.y) * 2 - Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom - Layout.bottomMargin: delegateDisplaySecondaryText ? 0 : elisaTheme.layoutVerticalMargin + Layout.maximumWidth: gridEntry.width * 0.9 + Layout.minimumWidth: Layout.maximumWidth + Layout.maximumHeight: delegateDisplaySecondaryText + ? (mainLabelSize.boundingRect.height - mainLabelSize.boundingRect.y) + : (mainLabelSize.boundingRect.height - mainLabelSize.boundingRect.y) * 2 + Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + Layout.bottomMargin: delegateDisplaySecondaryText ? 0 : elisaTheme.layoutVerticalMargin - wrapMode: delegateDisplaySecondaryText ? Label.NoWrap : Label.Wrap - elide: Text.ElideRight - } + wrapMode: delegateDisplaySecondaryText ? Label.NoWrap : Label.Wrap + maximumLineCount: 2 + elide: Text.ElideRight + } - LabelWithToolTip { - id: secondaryLabel + LabelWithToolTip { + id: secondaryLabel - opacity: 0.6 - color: myPalette.text + opacity: 0.6 + color: myPalette.text - // FIXME: Center-aligned text looks better overall, but - // sometimes results in font kerning issues - // See https://bugreports.qt.io/browse/QTBUG-49646 - horizontalAlignment: Text.AlignHCenter + // FIXME: Center-aligned text looks better overall, but + // sometimes results in font kerning issues + // 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 + Layout.bottomMargin: elisaTheme.layoutVerticalMargin + Layout.maximumWidth: gridEntry.width * 0.9 + Layout.minimumWidth: Layout.maximumWidth + Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom - visible: delegateDisplaySecondaryText + visible: delegateDisplaySecondaryText - elide: Text.ElideRight - } + elide: Text.ElideRight } - } - Item { - Layout.fillHeight: true + Item { + Layout.fillHeight: true + } } } states: [ State { name: 'notSelected' when: !gridEntry.activeFocus && !hoverHandle.containsMouse && !gridEntry.isSelected PropertyChanges { target: stateIndicator color: 'transparent' } PropertyChanges { target: stateIndicator opacity: 1.0 } PropertyChanges { target: hoverLoader active: false } PropertyChanges { target: hoverLoader opacity: 0.0 } }, State { name: 'hovered' when: hoverHandle.containsMouse && !gridEntry.activeFocus PropertyChanges { target: stateIndicator color: myPalette.highlight } PropertyChanges { target: stateIndicator opacity: 0.2 } PropertyChanges { target: hoverLoader active: true } PropertyChanges { target: hoverLoader opacity: 1.0 } }, State { name: 'selected' when: gridEntry.isSelected && !gridEntry.activeFocus PropertyChanges { target: stateIndicator color: myPalette.mid } PropertyChanges { target: stateIndicator opacity: 0.6 } PropertyChanges { target: hoverLoader active: false } PropertyChanges { target: hoverLoader opacity: 0. } }, State { name: 'hoveredOrSelected' when: gridEntry.activeFocus PropertyChanges { target: stateIndicator color: myPalette.highlight } PropertyChanges { target: stateIndicator opacity: 0.6 } PropertyChanges { target: hoverLoader active: true } PropertyChanges { target: hoverLoader opacity: 1.0 } } ] } diff --git a/src/qml/GridBrowserView.qml b/src/qml/GridBrowserView.qml index dc1c94d0..2d5dc81d 100644 --- a/src/qml/GridBrowserView.qml +++ b/src/qml/GridBrowserView.qml @@ -1,171 +1,169 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.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 { id: gridView property bool isSubPage: false property string mainTitle property string secondaryTitle property url image property alias contentModel: contentDirectoryView.model property alias showRating: navigationBar.showRating property bool delegateDisplaySecondaryText: true property alias expandedFilterView: navigationBar.expandedFilterView property var stackView property url defaultIcon signal enqueue(int databaseId, string name) signal replaceAndPlay(int databaseId, string name) signal open(string innerMainTitle, string innerSecondaryTitle, url innerImage, int databaseId, var dataType, var showDiscHeader) signal goBack() ColumnLayout { anchors.fill: parent spacing: 0 NavigationActionBar { id: navigationBar mainTitle: gridView.mainTitle secondaryTitle: gridView.secondaryTitle image: gridView.image enableGoBack: isSubPage sortOrder: if (contentModel) {contentModel.sortedAscending} else true Layout.fillWidth: true Loader { active: contentModel !== undefined sourceComponent: Binding { target: contentModel property: 'filterText' value: navigationBar.filterText } } Loader { active: contentModel sourceComponent: Binding { target: contentModel property: 'filterRating' value: navigationBar.filterRating } } onEnqueue: contentModel.enqueueToPlayList() onReplaceAndPlay:contentModel.replaceAndPlayOfPlayList() onGoBack: gridView.goBack() onSort: contentModel.sortModel(order) } FocusScope { Layout.fillHeight: true Layout.fillWidth: true clip: true GridView { id: contentDirectoryView property int availableWidth: width - scrollBar.width activeFocusOnTab: true keyNavigationEnabled: true anchors.fill: parent anchors.margins: elisaTheme.layoutHorizontalMargin ScrollBar.vertical: ScrollBar { id: scrollBar } boundsBehavior: Flickable.StopAtBounds currentIndex: -1 Accessible.role: Accessible.List Accessible.name: mainTitle TextMetrics { id: secondaryLabelSize text: 'example' } ScrollHelper { id: scrollHelper flickable: contentDirectoryView anchors.fill: contentDirectoryView } - cellWidth: Math.floor(availableWidth / Math.max(Math.floor(availableWidth / elisaTheme.gridDelegateWidth), 2)) - cellHeight: elisaTheme.gridDelegateHeight + - (secondaryLabelSize.boundingRect.height - secondaryLabelSize.boundingRect.y) * - (delegateDisplaySecondaryText ? 2 : 1) + cellWidth: Math.floor(availableWidth / Math.max(Math.floor(availableWidth / elisaTheme.gridDelegateSize), 2)) + cellHeight: elisaTheme.gridDelegateSize + secondaryLabelSize.boundingRect.height * 2 + elisaTheme.layoutVerticalMargin * 2 delegate: GridBrowserDelegate { - width: elisaTheme.gridDelegateWidth + width: elisaTheme.gridDelegateSize height: contentDirectoryView.cellHeight focus: true isSelected: contentDirectoryView.currentIndex === index isPartial: false mainText: model.display fileUrl: model.url secondaryText: if (gridView.delegateDisplaySecondaryText) {model.secondaryText} else {""} imageUrl: (model && model.imageUrl && model.imageUrl.toString() !== "" ? model.imageUrl : defaultIcon) shadowForImage: (model && model.imageUrl && model.imageUrl.toString() !== "" ? true : false) databaseId: model.databaseId delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText entryType: model.dataType onEnqueue: gridView.enqueue(databaseId, name) onReplaceAndPlay: gridView.replaceAndPlay(databaseId, name) onOpen: gridView.open(model.display, model.secondaryText, (model && model.imageUrl && model.imageUrl.toString() !== "" ? model.imageUrl : defaultIcon), model.databaseId, model.dataType, (model.isSingleDiscAlbum ? ViewManager.NoDiscHeaders : ViewManager.DiscHeaders)) onSelected: { forceActiveFocus() contentDirectoryView.currentIndex = model.index } onActiveFocusChanged: { if (activeFocus && contentDirectoryView.currentIndex !== model.index) { contentDirectoryView.currentIndex = model.index } } } } } } }