diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am index 90a81e9e091cf1fa7653ed88020f53ca5755b312..37984f3a95a4b0e5d3ec72d4eeb505aa018a99c7 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 6718e1b5dce117ac909856666f797cbb543e768e..9a9e36e0c669d473a7c0584868b6a1047ef240b3 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 0000000000000000000000000000000000000000..afb1901ebd0782b71b25428358a4946eb60e042c --- /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 376fec87ac4f9e3e50b108979b06a04510d35176..ff630430c50f65af29501f47d82273cab5ed2b20 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 10193b2e5513e388c3ee38768d29b08ebeee203c..70a72ac09ec37e2291cbb17fb25c088853e6c633 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 317d9d8033ef3db24622a7f00ef7af8d75dac4aa..d39a436aff35a3d1ca3bbeb7fec41d4a6c3b33d1 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