[vlc-devel] [PATCH 10/12] qml: Create MediaGroupList
Benjamin Arnaud
benjamin.arnaud at videolabs.io
Wed Apr 14 08:05:57 UTC 2021
---
modules/gui/qt/Makefile.am | 1 +
.../qt/medialibrary/qml/MediaGroupList.qml | 393 ++++++++++++++++++
.../qt/medialibrary/qml/VideoListDisplay.qml | 20 +-
modules/gui/qt/vlc.qrc | 1 +
po/POTFILES.in | 1 +
5 files changed, 413 insertions(+), 3 deletions(-)
create mode 100644 modules/gui/qt/medialibrary/qml/MediaGroupList.qml
diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 2f121cfb54..1f61393224 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -671,6 +671,7 @@ libqt_plugin_la_QML = \
gui/qt/medialibrary/qml/ArtistTopBanner.qml \
gui/qt/medialibrary/qml/AudioGridItem.qml \
gui/qt/medialibrary/qml/EmptyLabel.qml \
+ gui/qt/medialibrary/qml/MediaGroupList.qml \
gui/qt/medialibrary/qml/MusicAlbums.qml \
gui/qt/medialibrary/qml/MusicAlbumsDisplay.qml \
gui/qt/medialibrary/qml/MusicAlbumsGridExpandDelegate.qml \
diff --git a/modules/gui/qt/medialibrary/qml/MediaGroupList.qml b/modules/gui/qt/medialibrary/qml/MediaGroupList.qml
new file mode 100644
index 0000000000..df030f1a89
--- /dev/null
+++ b/modules/gui/qt/medialibrary/qml/MediaGroupList.qml
@@ -0,0 +1,393 @@
+/*****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * Authors: Benjamin Arnaud <bunjee at omega.gg>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+import QtQuick 2.11
+
+import org.videolan.medialib 0.1
+
+import "qrc:///widgets/" as Widgets
+import "qrc:///main/" as MainInterface
+import "qrc:///util/" as Util
+import "qrc:///style/"
+
+Widgets.NavigableFocusScope {
+ id: root
+
+ //---------------------------------------------------------------------------------------------
+ // Properties
+ //---------------------------------------------------------------------------------------------
+
+ readonly property int currentIndex: currentItem.currentIndex
+
+ property int initialIndex: 0
+
+ property var sortModel: [
+ { text: i18n.qtr("Alphabetic"), criteria: "name" },
+ { text: i18n.qtr("Date"), criteria: "date" }
+ ]
+
+ //---------------------------------------------------------------------------------------------
+ // Alias
+ //---------------------------------------------------------------------------------------------
+
+ property alias model: model
+
+ property alias currentItem: view.currentItem
+
+ //---------------------------------------------------------------------------------------------
+ // Signals
+ //---------------------------------------------------------------------------------------------
+
+ signal showList(variant model)
+
+ //---------------------------------------------------------------------------------------------
+ // Settings
+ //---------------------------------------------------------------------------------------------
+
+ navigationCancel: function() {
+ if (currentItem.currentIndex > 0) {
+ currentItem.currentIndex = 0;
+
+ currentItem.positionViewAtIndex(0, ItemView.Contain);
+ } else {
+ defaultNavigationCancel();
+ }
+ }
+
+ //---------------------------------------------------------------------------------------------
+ // Events
+ //---------------------------------------------------------------------------------------------
+
+ onModelChanged: resetFocus()
+
+ onInitialIndexChanged: resetFocus()
+
+ //---------------------------------------------------------------------------------------------
+ // Connections
+ //---------------------------------------------------------------------------------------------
+
+ Connections {
+ target: mainInterface
+
+ onGridViewChanged: {
+ if (mainInterface.gridView) view.replace(grid);
+ else view.replace(list);
+ }
+ }
+
+ //---------------------------------------------------------------------------------------------
+ // Functions
+ //---------------------------------------------------------------------------------------------
+
+ function setCurrentItemFocus() { listView.currentItem.forceActiveFocus() }
+
+ function resetFocus() {
+ if (model.count === 0) return;
+
+ var initialIndex = root.initialIndex;
+
+ if (initialIndex >= model.count)
+ initialIndex = 0;
+
+ modelSelect.select(model.index(initialIndex, 0), ItemSelectionModel.ClearAndSelect);
+
+ if (currentItem)
+ currentItem.positionViewAtIndex(initialIndex, ItemView.Contain);
+ }
+
+ //---------------------------------------------------------------------------------------------
+ // Private
+
+ function _actionAtIndex() {
+ if (modelSelect.selectedIndexes.length > 1) {
+ _play(model.getIdsForIndexes(modelSelect.selectedIndexes));
+ } else if (modelSelect.selectedIndexes.length === 1) {
+ var index = modelSelect.selectedIndexes[0];
+ _showList(model.getDataAt(index));
+ }
+ }
+
+ function _play(ids) {
+ g_mainDisplay.showPlayer();
+
+ medialib.addAndPlay(ids);
+ }
+
+ function _showList(model)
+ {
+ // NOTE: If the count is 1 we consider the group is a media.
+ if (model.count == 1)
+ _play(model.id);
+ else
+ showList(model);
+ }
+
+ //---------------------------------------------------------------------------------------------
+
+ function _getLabels(model, string)
+ {
+ var count = model.count;
+
+ if (count === 1) {
+ return [
+ model.resolution_name || "",
+ model.channel || ""
+ ].filter(function(a) { return a !== "" });
+ } else return [
+ string.arg(count)
+ ];
+ }
+
+ //---------------------------------------------------------------------------------------------
+ // Childs
+ //---------------------------------------------------------------------------------------------
+
+ MLGroupListModel {
+ id: model
+
+ ml: medialib
+
+ onCountChanged: {
+ if (count === 0 || modelSelect.hasSelection) return;
+
+ resetFocus();
+ }
+ }
+
+ Util.SelectableDelegateModel {
+ id: modelSelect
+
+ model: root.model
+ }
+
+ Widgets.StackViewExt {
+ id: view
+
+ anchors.fill: parent
+
+ initialItem: (mainInterface.gridView) ? grid : list
+
+ focus: (model.count !== 0)
+ }
+
+ GroupListContextMenu {
+ id: contextMenu
+
+ model: root.model
+ }
+
+ Widgets.DragItem {
+ id: dragItem
+
+ function updateComponents(maxCovers) {
+ var items = modelSelect.selectedIndexes.slice(0, maxCovers).map(function (x){
+ return model.getDataAt(x.row);
+ })
+
+ var covers = items.map(function (item) {
+ return { artwork: item.thumbnail || VLCStyle.noArtCover }
+ });
+
+ var title = items.map(function (item) {
+ return item.title
+ }).join(", ");
+
+ return {
+ covers: covers,
+ title: title,
+ count: modelSelect.selectedIndexes.length
+ }
+ }
+
+ function getSelectedInputItem() {
+ return model.getItemsForIndexes(modelSelect.selectedIndexes);
+ }
+ }
+
+ //---------------------------------------------------------------------------------------------
+ // Components
+
+ Component {
+ id: grid
+
+ MainInterface.MainGridView {
+ id: gridView
+
+ //-------------------------------------------------------------------------------------
+ // Settings
+
+ cellWidth : VLCStyle.gridItem_video_width
+ cellHeight: VLCStyle.gridItem_video_height
+
+ topMargin: VLCStyle.margin_large
+
+ model: root.model
+
+ delegateModel: modelSelect
+
+ activeFocusOnTab: true
+
+ navigationParent: root
+
+ expandDelegate: VideoInfoExpandPanel {
+ width: gridView.width
+
+ x: 0
+
+ navigationParent: gridView
+
+ navigationUp : function() { gridView.retract() }
+ navigationDown : function() { gridView.retract() }
+ navigationCancel: function() { gridView.retract() }
+
+ onRetract: gridView.retract()
+ }
+
+ delegate: VideoGridItem {
+ id: gridItem
+
+ //---------------------------------------------------------------------------------
+ // Settings
+
+ opacity: (gridView.expandIndex !== -1
+ &&
+ gridView.expandIndex !== gridItem.index) ? 0.7 : 1
+
+ title: (model.name) ? model.name
+ : i18n.qtr("Unknown title")
+
+ labels: _getLabels(model, i18n.qtr("%1 Medias"))
+
+ // NOTE: We don't want to show the indicator for a group.
+ showNewIndicator: (model.count === 1)
+
+ dragItem: root.dragItem
+
+ //---------------------------------------------------------------------------------
+ // Events
+
+ onItemClicked: gridView.leftClickOnItem(modifier, index)
+
+ onItemDoubleClicked: _showList(model)
+
+ onContextMenuButtonClicked: {
+ gridView.rightClickOnItem(index);
+
+ contextMenu.popup(modelSelect.selectedIndexes, globalMousePos,
+ { "information" : index });
+ }
+
+ //---------------------------------------------------------------------------------
+ // Animations
+
+ Behavior on opacity { NumberAnimation { duration: 100 } }
+ }
+
+ //-------------------------------------------------------------------------------------
+ // Events
+
+ // NOTE: Define the initial position and selection. This is done on activeFocus rather
+ // than Component.onCompleted because modelSelect.selectedGroup update itself
+ // after this event.
+ onActiveFocusChanged: {
+ if (activeFocus == false || model.count === 0 || modelSelect.hasSelection) return;
+
+ modelSelect.select(model.index(0,0), ItemSelectionModel.ClearAndSelect)
+ }
+
+ onSelectAll: modelSelect.selectAll()
+
+ onSelectionUpdated: modelSelect.updateSelection(keyModifiers, oldIndex, newIndex)
+
+ onActionAtIndex: _actionAtIndex()
+
+ //-------------------------------------------------------------------------------------
+ // Connections
+
+ Connections {
+ target: contextMenu
+
+ onShowMediaInformation: gridView.switchExpandItem(index)
+ }
+ }
+ }
+
+ Component {
+ id: list
+
+ VideoListDisplay
+ {
+ id: listView
+
+ //-------------------------------------------------------------------------------------
+ // Settings
+
+ model: root.model
+
+ mainCriteria: "name"
+
+ selectionDelegateModel: modelSelect
+
+ dragItem: root.dragItem
+
+ header: root.header
+
+ headerTopPadding: VLCStyle.margin_normal
+
+ headerPositioning: ListView.InlineHeader
+
+ navigationParent: root
+
+ //-------------------------------------------------------------------------------------
+ // Events
+
+ onActionForSelection: _actionAtIndex()
+
+ onContextMenuButtonClicked: contextMenu.popup(modelSelect.selectedIndexes,
+ menuParent.mapToGlobal(0,0))
+
+ onRightClick: contextMenu.popup(modelSelect.selectedIndexes, globalMousePos)
+
+ //-------------------------------------------------------------------------------------
+ // Functions
+
+ function onLabels(model) {
+ return _getLabels(model, "%1");
+ }
+ }
+ }
+
+ EmptyLabel {
+ anchors.fill: parent
+
+ coverWidth : VLCStyle.dp(182, VLCStyle.scale)
+ coverHeight: VLCStyle.dp(114, VLCStyle.scale)
+
+ visible: (model.count === 0)
+
+ text: i18n.qtr("No video found\nPlease try adding sources, by going to the Network tab")
+
+ cover: VLCStyle.noArtVideoCover
+
+ navigationParent: root
+
+ focus: visible
+ }
+}
diff --git a/modules/gui/qt/medialibrary/qml/VideoListDisplay.qml b/modules/gui/qt/medialibrary/qml/VideoListDisplay.qml
index 0e24c0d618..e7943ed952 100644
--- a/modules/gui/qt/medialibrary/qml/VideoListDisplay.qml
+++ b/modules/gui/qt/medialibrary/qml/VideoListDisplay.qml
@@ -99,6 +99,22 @@ MainInterface.MainTableView {
}
}
+ //---------------------------------------------------------------------------------------------
+ // Functions
+ //---------------------------------------------------------------------------------------------
+ // Events
+
+ function onLabels(model)
+ {
+ if (model === null)
+ return [];
+
+ return [
+ model.resolution_name || "",
+ model.channel || ""
+ ].filter(function(a) { return a !== "" });
+ }
+
//---------------------------------------------------------------------------------------------
// Childs
//---------------------------------------------------------------------------------------------
@@ -112,9 +128,7 @@ MainInterface.MainTableView {
titleCover_radius: VLCStyle.listAlbumCover_radius
function titlecoverLabels(model) {
- return [!model ? "" : model.resolution_name
- , model ? "" : model.channel
- ].filter(function(a) { return a !== "" })
+ return listView_id.onLabels(model);
}
}
}
diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc
index b2458b6e08..8b0ea2826a 100644
--- a/modules/gui/qt/vlc.qrc
+++ b/modules/gui/qt/vlc.qrc
@@ -269,6 +269,7 @@
</qresource>
<qresource prefix="/medialibrary">
<file alias="EmptyLabel.qml">medialibrary/qml/EmptyLabel.qml</file>
+ <file alias="MediaGroupList.qml">medialibrary/qml/MediaGroupList.qml</file>
<file alias="MusicAlbums.qml">medialibrary/qml/MusicAlbums.qml</file>
<file alias="MusicDisplay.qml">medialibrary/qml/MusicDisplay.qml</file>
<file alias="MusicGenres.qml">medialibrary/qml/MusicGenres.qml</file>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0293b48792..75528d9bb8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -818,6 +818,7 @@ modules/gui/qt/maininterface/qml/MainInterface.qml
modules/gui/qt/maininterface/qml/NoMedialibHome.qml
modules/gui/qt/medialibrary/qml/ArtistTopBanner.qml
modules/gui/qt/medialibrary/qml/AudioGridItem.qml
+modules/gui/qt/medialibrary/qml/MediaGroupList.qml
modules/gui/qt/medialibrary/qml/MusicAlbums.qml
modules/gui/qt/medialibrary/qml/MusicAlbumsDisplay.qml
modules/gui/qt/medialibrary/qml/MusicAlbumsGridExpandDelegate.qml
--
2.25.1
More information about the vlc-devel
mailing list