From 882c3ea0da2a6dc231987ac13d3f03866331c4ff Mon Sep 17 00:00:00 2001 From: Aleksey Kuznetsov <Aleksey.Kuznetsov@noveogroup.com> Date: Wed, 30 Dec 2020 16:18:57 +0700 Subject: [PATCH] qml: medialib: Continue watching video section added to the section "Video" "Continue watching" section with list of videos the user started playing added at the top of the "Video" section. Scrolling the "Video" page is performed on all area vertically. Scrolling the "Continue watching" section is horizontal. In order to preserve loading items on scrolling the content the Continue watching video section inserted at the top as header of grid view and of list view. Signed-off-by: Pierre Lamot <pierre@videolabs.io> --- modules/gui/qt/Makefile.am | 1 + .../gui/qt/medialibrary/qml/VideoDisplay.qml | 70 ++++++-- .../qml/VideoDisplayRecentVideos.qml | 157 ++++++++++++++++++ modules/gui/qt/style/VLCStyle.qml | 9 +- modules/gui/qt/vlc.qrc | 1 + po/POTFILES.in | 1 + 6 files changed, 226 insertions(+), 13 deletions(-) create mode 100644 modules/gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am index 90a81e9e091c..37984f3a95a4 100644 --- a/modules/gui/qt/Makefile.am +++ b/modules/gui/qt/Makefile.am @@ -642,6 +642,7 @@ libqt_plugin_la_QML = \ gui/qt/medialibrary/qml/MusicTracksDisplay.qml \ gui/qt/medialibrary/qml/UrlListDisplay.qml \ gui/qt/medialibrary/qml/VideoDisplay.qml \ + gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml \ gui/qt/medialibrary/qml/VideoGridItem.qml \ gui/qt/medialibrary/qml/VideoInfoExpandPanel.qml \ gui/qt/medialibrary/qml/VideoListDisplay.qml \ diff --git a/modules/gui/qt/medialibrary/qml/VideoDisplay.qml b/modules/gui/qt/medialibrary/qml/VideoDisplay.qml index 6718e1b5dce1..9a9e36e0c669 100644 --- a/modules/gui/qt/medialibrary/qml/VideoDisplay.qml +++ b/modules/gui/qt/medialibrary/qml/VideoDisplay.qml @@ -30,10 +30,11 @@ import "qrc:///style/" Widgets.NavigableFocusScope { id: root readonly property var currentIndex: view.currentItem.currentIndex + property Item headerItem: view.currentItem.headerItem //the index to "go to" when the view is loaded property var initialIndex: 0 - property alias contentModel: videoModel ; + property alias contentModel: videoModel navigationCancel: function() { if (view.currentItem.currentIndex <= 0) { @@ -52,9 +53,8 @@ Widgets.NavigableFocusScope { onContentModelChanged: resetFocus() function resetFocus() { - if (videoModel.count === 0) { + if (videoModel.count === 0) return - } var initialIndex = root.initialIndex if (initialIndex >= videoModel.count) initialIndex = 0 @@ -89,6 +89,52 @@ Widgets.NavigableFocusScope { model: videoModel } + MLRecentsVideoModel { + id: recentVideoModel + ml: medialib + } + + property Component header: Column { + id: videoHeader + + width: root.width + + property Item focusItem: recentVideosViewLoader.item.focusItem + + topPadding: VLCStyle.margin_normal + spacing: VLCStyle.margin_normal + + Loader { + id: recentVideosViewLoader + width: parent.width + height: item.implicitHeight + active: recentVideoModel.count > 0 + visible: recentVideoModel.count > 0 + focus: true + + sourceComponent: VideoDisplayRecentVideos { + id: recentVideosView + + width: parent.width + + model: recentVideoModel + focus: true + navigationParent: root + navigationDown: function() { + recentVideosView.focus = false + view.currentItem.setCurrentItemFocus() + } + } + } + + Widgets.SubtitleLabel { + id: videosLabel + leftPadding: VLCStyle.margin_xlarge + bottomPadding: VLCStyle.margin_xsmall + width: root.width + text: i18n.qtr("Videos") + } + } Component { id: gridComponent @@ -101,13 +147,7 @@ Widgets.NavigableFocusScope { delegateModel: selectionModel model: videoModel - headerDelegate: Widgets.SubtitleLabel { - text: i18n.qtr("Videos") - leftPadding: videosGV.rowX - topPadding: VLCStyle.margin_large - bottomPadding: VLCStyle.margin_normal - width: root.width - } + headerDelegate: root.header delegate: VideoGridItem { id: videoGridItem @@ -141,6 +181,7 @@ Widgets.NavigableFocusScope { } navigationParent: root + navigationUpItem: headerItem.focusItem /* *define the intial position/selection @@ -168,7 +209,6 @@ Widgets.NavigableFocusScope { } - Component { id: listComponent VideoListDisplay { @@ -177,7 +217,11 @@ Widgets.NavigableFocusScope { model: videoModel dragItem: videoDragItem navigationParent: root + navigationUpItem: headerItem.focusItem + + header: root.header headerTopPadding: VLCStyle.margin_normal + headerPositioning: ListView.InlineHeader selectionDelegateModel: selectionModel @@ -185,6 +229,9 @@ Widgets.NavigableFocusScope { onRightClick: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos ) + function setCurrentItemFocus() { + currentItem.forceActiveFocus() + } } } @@ -225,7 +272,6 @@ Widgets.NavigableFocusScope { view.replace(listComponent) } } - } EmptyLabel { diff --git a/modules/gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml b/modules/gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml new file mode 100644 index 000000000000..afb1901ebd07 --- /dev/null +++ b/modules/gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml @@ -0,0 +1,157 @@ +/***************************************************************************** + * Copyright (C) 2019 VLC authors and VideoLAN + * + * 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 QtQuick.Controls 2.4 +import QtQml.Models 2.2 + +import org.videolan.medialib 0.1 + +import "qrc:///widgets/" as Widgets +import "qrc:///util/" as Util +import "qrc:///style/" + +Widgets.NavigableFocusScope { + id: root + + property Item focusItem: recentVideosListView + implicitHeight: recentVideosColumn.height + + property int leftPadding: VLCStyle.margin_xlarge + property int rightPadding: VLCStyle.margin_xlarge + + property int currentIndex: -1 + + property var model: undefined; + + onCurrentIndexChanged: { + recentVideoListView.currentIndex = _currentIndex + } + + function _actionAtIndex(index, model, selectionModel) { + g_mainDisplay.showPlayer() + medialib.addAndPlay( model.getIdsForIndexes( selectionModel.selectedIndexes ) ) + } + + onFocusChanged: { + if (activeFocus && root.currentIndex === -1 && root.model.count > 0) + root.currentIndex = 0 + } + + + Util.SelectableDelegateModel { + id: recentVideoSelection + model: root.model + } + + Column { + id: recentVideosColumn + + width: root.width + spacing: VLCStyle.margin_xsmall + + Widgets.SubtitleLabel { + id: continueWatchingLabel + leftPadding: VLCStyle.margin_xlarge + width: parent.width + text: i18n.qtr("Continue Watching") + } + + Widgets.KeyNavigableListView { + id: recentVideosListView + + width: parent.width + implicitHeight: VLCStyle.gridItem_video_height_large + spacing: VLCStyle.column_margin_width + orientation: ListView.Horizontal + + focus: true + navigationParent: root + navigationDown: function() { + recentVideosListView.focus = false + view.currentItem.setCurrentItemFocus() + } + + model: root.model + + header: Item { + width: VLCStyle.margin_xlarge + } + + delegate: Widgets.GridItem { + id: recentVideoGridItem + + focus: true + + image: model.thumbnail || VLCStyle.noArtCover + title: model.title || i18n.qtr("Unknown title") + subtitle: model.duration || "" + labels: [ + model.resolution_name || "", + model.channel || "" + ].filter(function(a) { return a !== "" } ) + progress: model.progress > 0 ? model.progress : 0 + pictureWidth: VLCStyle.gridCover_video_width_large + pictureHeight: VLCStyle.gridCover_video_height_large + playCoverBorder.width: VLCStyle.gridCover_video_border + titleMargin: VLCStyle.margin_xxsmall + showNewIndicator: true + onItemDoubleClicked: { + if ( model.id !== undefined ) { + g_mainDisplay.showPlayer() + medialib.addAndPlay( model.id ) + } + } + + onPlayClicked: { + if ( model.id !== undefined ) { + g_mainDisplay.showPlayer() + medialib.addAndPlay( model.id ) + } + } + + onItemClicked: { + recentVideoSelection.updateSelection( modifier , root.model.currentIndex, index ) + recentVideosListView.currentIndex = index + recentVideosListView.forceActiveFocus() + } + + Connections { + target: recentVideoSelection + + onSelectionChanged: selected = recentVideoSelection.isSelected(root.model.index(index, 0)) + } + + Behavior on opacity { + NumberAnimation { + duration: 100 + } + } + } + + footer: Item { + width: VLCStyle.margin_xlarge + } + + onSelectionUpdated: recentVideoSelection.updateSelection( keyModifiers, oldIndex, newIndex ) + onActionAtIndex: { + g_mainDisplay.showPlayer() + medialib.addAndPlay( model.getIdsForIndexes( recentVideoSelection.selectedIndexes ) ) + } + } + } +} diff --git a/modules/gui/qt/style/VLCStyle.qml b/modules/gui/qt/style/VLCStyle.qml index 376fec87ac4f..ff630430c50f 100644 --- a/modules/gui/qt/style/VLCStyle.qml +++ b/modules/gui/qt/style/VLCStyle.qml @@ -159,6 +159,9 @@ Item { property int gridCover_video_height: ( gridCover_video_width * 10.0 ) / 16 property int gridCover_video_border: dp(3, scale) + property int gridCover_video_width_large: dp(406, scale) + property int gridCover_video_height_large: ( gridCover_video_width_large * 10.0 ) / 16 + property int expandCover_music_height: dp(171, scale) property int expandCover_music_width: dp(171, scale) @@ -174,13 +177,17 @@ Item { property int gridItem_video_width: VLCStyle.gridCover_video_width property int gridItem_video_height: VLCStyle.gridCover_video_height + VLCStyle.margin_xxsmall + VLCStyle.fontHeight_normal + VLCStyle.fontHeight_small + property int gridItem_video_width_large: VLCStyle.gridCover_video_width_large + property int gridItem_video_height_large: VLCStyle.gridCover_video_height_large + VLCStyle.margin_xxsmall + VLCStyle.fontHeight_large + + VLCStyle.margin_xxsmall + VLCStyle.fontHeight_normal + property int column_width: dp(114, scale) property int column_margin_width: dp(32, scale) property int table_cover_border: dp(2, scale) property int artistBanner_height: dp(200, scale) - + //global application size, updated by the root widget property int appWidth: 0 property int appHeight: 0 diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc index 10193b2e5513..70a72ac09ec3 100644 --- a/modules/gui/qt/vlc.qrc +++ b/modules/gui/qt/vlc.qrc @@ -279,6 +279,7 @@ <file alias="VideoListDisplay.qml">medialibrary/qml/VideoListDisplay.qml</file> <file alias="VideoGridItem.qml">medialibrary/qml/VideoGridItem.qml</file> <file alias="AudioGridItem.qml">medialibrary/qml/AudioGridItem.qml</file> + <file alias="VideoDisplayRecentVideos.qml">medialibrary/qml/VideoDisplayRecentVideos.qml</file> </qresource> <qresource prefix="/style"> <file alias="qmldir">style/qmldir</file> diff --git a/po/POTFILES.in b/po/POTFILES.in index 317d9d8033ef..d39a436aff35 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -814,6 +814,7 @@ modules/gui/qt/medialibrary/qml/MusicTrackListDisplay.qml modules/gui/qt/medialibrary/qml/MusicTracksDisplay.qml modules/gui/qt/medialibrary/qml/UrlListDisplay.qml modules/gui/qt/medialibrary/qml/VideoDisplay.qml +modules/gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml modules/gui/qt/medialibrary/qml/VideoGridItem.qml modules/gui/qt/medialibrary/qml/VideoInfoExpandPanel.qml modules/gui/qt/medialibrary/qml/VideoListDisplay.qml -- GitLab