[vlc-devel] [PATCH] qml: medialib: Continue watching video section added to the section "Video"

Aleksey Kuznetsov Aleksey.Kuznetsov at noveogroup.com
Wed Dec 30 09:18:57 UTC 2020


"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.
---
 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 90a81e9e09..37984f3a95 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 6718e1b5dc..9a9e36e0c6 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 0000000000..afb1901ebd
--- /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 376fec87ac..ff630430c5 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 10193b2e55..70a72ac09e 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 317d9d8033..d39a436aff 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
-- 
2.25.1



More information about the vlc-devel mailing list