[vlc-commits] [Git][videolan/vlc][master] 14 commits: qml/Group(s): Remove dedicated group views
Hugo Beauzée-Luyssen (@chouquette)
gitlab at videolan.org
Mon Jan 10 13:41:01 UTC 2022
Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC
Commits:
6ee9299c by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml/Group(s): Remove dedicated group views
After this, groups will be hidden until we bring them back in VideoAllDisplay.
- - - - -
0e29029e by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qt/mainctx: Add the 'grouping' property
And save it in settings.
- - - - -
a3ed3d9c by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qt/mlvideomodel: Remove the 'id' sorting criteria
- - - - -
c369be64 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qt/mlgroup(s): Update 'name' to 'title' and fix MLGroup model
- - - - -
c1b85224 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qt/mlgrouplistmodel: Add the GROUP_IS_VIDEO role
- - - - -
4ad03d08 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qt/qml_menu_wrapper: Update the GroupListContextMenu implementation
- - - - -
8e461377 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qt/qml_menu_wrapper: Create SortMenuVideo
- - - - -
685a8e6b by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml/SortControl: Add the 'sortMenu' property
And refactor the implementation
- - - - -
ebd6f412 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml/BannerSources: Add sortMenu alias and refactor SortControl
- - - - -
298f4e4b by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml/MainDisplay: Let the view provide a custom 'sortMenu'
And refactor the 'loadView' function.
- - - - -
4fc5b8f8 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml/MediaGroupDisplay: Update 'name' to 'title'
- - - - -
62112b14 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml: Create VideoAllSubDisplay
- - - - -
be184c0b by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml/VideoAll(s): Add grouping support
- - - - -
454b57b7 by Benjamin Arnaud at 2022-01-10T13:21:47+00:00
qml/VideoDisplay: Add the 'sortMenu' property
- - - - -
23 changed files:
- modules/gui/qt/Makefile.am
- modules/gui/qt/maininterface/mainctx.cpp
- modules/gui/qt/maininterface/mainctx.hpp
- modules/gui/qt/maininterface/mainui.cpp
- modules/gui/qt/maininterface/qml/BannerSources.qml
- modules/gui/qt/maininterface/qml/MainDisplay.qml
- modules/gui/qt/medialibrary/mlgroup.cpp
- modules/gui/qt/medialibrary/mlgroup.hpp
- modules/gui/qt/medialibrary/mlgrouplistmodel.cpp
- modules/gui/qt/medialibrary/mlgrouplistmodel.hpp
- modules/gui/qt/medialibrary/mlvideomodel.cpp
- modules/gui/qt/medialibrary/qml/MediaGroupDisplay.qml
- − modules/gui/qt/medialibrary/qml/MediaGroupList.qml
- modules/gui/qt/medialibrary/qml/VideoAll.qml
- modules/gui/qt/medialibrary/qml/VideoAllDisplay.qml
- + modules/gui/qt/medialibrary/qml/VideoAllSubDisplay.qml
- modules/gui/qt/medialibrary/qml/VideoDisplay.qml
- − modules/gui/qt/medialibrary/qml/VideoGroupsDisplay.qml
- modules/gui/qt/menus/qml_menu_wrapper.cpp
- modules/gui/qt/menus/qml_menu_wrapper.hpp
- modules/gui/qt/vlc.qrc
- modules/gui/qt/widgets/qml/SortControl.qml
- po/POTFILES.in
Changes:
=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -737,7 +737,6 @@ libqt_plugin_la_QML = \
gui/qt/medialibrary/qml/AudioGridItem.qml \
gui/qt/medialibrary/qml/EmptyLabel.qml \
gui/qt/medialibrary/qml/MediaGroupDisplay.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 \
@@ -756,7 +755,7 @@ libqt_plugin_la_QML = \
gui/qt/medialibrary/qml/VideoDisplay.qml \
gui/qt/medialibrary/qml/VideoAll.qml \
gui/qt/medialibrary/qml/VideoAllDisplay.qml \
- gui/qt/medialibrary/qml/VideoGroupsDisplay.qml \
+ gui/qt/medialibrary/qml/VideoAllSubDisplay.qml \
gui/qt/medialibrary/qml/PlaylistMediaList.qml \
gui/qt/medialibrary/qml/PlaylistMedia.qml \
gui/qt/medialibrary/qml/PlaylistMediaDelegate.qml \
=====================================
modules/gui/qt/maininterface/mainctx.cpp
=====================================
@@ -217,6 +217,8 @@ MainCtx::~MainCtx()
settings->setValue( "playlist-width-factor", playlistWidthFactor);
settings->setValue( "grid-view", m_gridView );
+ settings->setValue( "grouping", m_grouping );
+
settings->setValue( "color-scheme", m_colorScheme->currentScheme() );
/* Save the stackCentralW sizes */
settings->endGroup();
@@ -322,6 +324,8 @@ void MainCtx::loadFromSettingsImpl(const bool callSignals)
loadFromSettings(m_gridView, "MainWindow/grid-view", true, &MainCtx::gridViewChanged);
+ loadFromSettings(m_grouping, "MainWindow/grouping", GROUPING_NONE, &MainCtx::groupingChanged);
+
loadFromSettings(m_showRemainingTime, "MainWindow/ShowRemainingTime", false, &MainCtx::showRemainingTimeChanged);
loadFromSettings(m_pinVideoControls, "MainWindow/pin-video-controls", false, &MainCtx::pinVideoControlsChanged);
@@ -481,6 +485,13 @@ void MainCtx::setGridView(bool asGrid)
emit gridViewChanged( asGrid );
}
+void MainCtx::setGrouping(Grouping grouping)
+{
+ m_grouping = grouping;
+
+ emit groupingChanged(grouping);
+}
+
void MainCtx::setInterfaceAlwaysOnTop( bool on_top )
{
b_interfaceOnTop = on_top;
=====================================
modules/gui/qt/maininterface/mainctx.hpp
=====================================
@@ -160,6 +160,7 @@ class MainCtx : public QObject
Q_PROPERTY(bool mediaLibraryAvailable READ hasMediaLibrary CONSTANT FINAL)
Q_PROPERTY(MediaLib* mediaLibrary READ getMediaLibrary CONSTANT FINAL)
Q_PROPERTY(bool gridView READ hasGridView WRITE setGridView NOTIFY gridViewChanged FINAL)
+ Q_PROPERTY(Grouping grouping READ grouping WRITE setGrouping NOTIFY groupingChanged FINAL)
Q_PROPERTY(ColorSchemeModel* colorScheme READ getColorScheme CONSTANT FINAL)
Q_PROPERTY(bool hasVLM READ hasVLM CONSTANT FINAL)
Q_PROPERTY(bool clientSideDecoration READ useClientSideDecoration NOTIFY useClientSideDecorationChanged FINAL)
@@ -211,6 +212,16 @@ public:
RAISE_AUDIO,
RAISE_AUDIOVIDEO,
};
+
+ enum Grouping
+ {
+ GROUPING_NONE,
+ GROUPING_NAME,
+ GROUPING_FOLDER
+ };
+
+ Q_ENUM(Grouping)
+
inline bool isInterfaceFullScreen() const { return m_windowVisibility == QWindow::FullScreen; }
inline bool isInterfaceVisible() const { return m_windowVisibility != QWindow::Hidden; }
bool isPlaylistDocked() { return b_playlistDocked; }
@@ -227,6 +238,7 @@ public:
inline bool hasMediaLibrary() const { return b_hasMedialibrary; }
inline MediaLib* getMediaLibrary() const { return m_medialib; }
inline bool hasGridView() const { return m_gridView; }
+ inline Grouping grouping() const { return m_grouping; }
inline ColorSchemeModel* getColorScheme() const { return m_colorScheme; }
bool hasVLM() const;
bool useClientSideDecoration() const;
@@ -304,6 +316,7 @@ protected:
bool b_hasMedialibrary = false;
MediaLib* m_medialib = nullptr;
bool m_gridView = false;
+ Grouping m_grouping = GROUPING_NONE;
ColorSchemeModel* m_colorScheme = nullptr;
bool m_windowTitlebar = true;
bool m_hasToolbarMenu = false;
@@ -337,6 +350,7 @@ public slots:
void setInterfaceAlwaysOnTop( bool );
void setShowRemainingTime( bool );
void setGridView( bool );
+ void setGrouping( Grouping );
void incrementIntfUserScaleFactor( bool increment);
void setIntfUserScaleFactor( double );
void setPinVideoControls( bool );
@@ -380,6 +394,7 @@ signals:
void hasEmbededVideoChanged(bool);
void showRemainingTimeChanged(bool);
void gridViewChanged( bool );
+ void groupingChanged( Grouping );
void colorSchemeChanged( QString );
void useClientSideDecorationChanged();
void hasToolbarMenuChanged();
=====================================
modules/gui/qt/maininterface/mainui.cpp
=====================================
@@ -286,6 +286,7 @@ void MainUI::registerQMLTypes()
qmlRegisterType<StringListMenu>( uri, versionMajor, versionMinor, "StringListMenu" );
qmlRegisterType<SortMenu>( uri, versionMajor, versionMinor, "SortMenu" );
+ qmlRegisterType<SortMenuVideo>( uri, versionMajor, versionMinor, "SortMenuVideo" );
qmlRegisterType<QmlGlobalMenu>( uri, versionMajor, versionMinor, "QmlGlobalMenu" );
qmlRegisterType<QmlMenuBar>( uri, versionMajor, versionMinor, "QmlMenuBar" );
qmlRegisterType<NetworkMediaContextMenu>( uri, versionMajor, versionMinor, "NetworkMediaContextMenu" );
=====================================
modules/gui/qt/maininterface/qml/BannerSources.qml
=====================================
@@ -42,6 +42,7 @@ FocusScope {
signal itemClicked(int index)
+ property alias sortMenu: sortControl.menu
property alias sortModel: sortControl.model
property var contentModel
property alias isViewMultiView: list_grid_btn.visible
@@ -262,30 +263,32 @@ FocusScope {
Widgets.SortControl {
id: sortControl
- textRole: "text"
- criteriaRole: "criteria"
-
width: VLCStyle.bannerButton_width
height: VLCStyle.bannerButton_height
+
iconSize: VLCStyle.banner_icon_size
visible: root.sortModel !== undefined && root.sortModel.length > 1
+
enabled: visible
+ textRole: "text"
+ criteriaRole: "criteria"
+
+ sortKey: contentModel ? contentModel.sortCriteria
+ : PlaylistControllerModel.SORT_KEY_NONE
+
+ sortOrder: contentModel ? contentModel.sortOrder : undefined
+
onSortSelected: {
- if (contentModel !== undefined) {
+ if (contentModel !== undefined)
contentModel.sortCriteria = type
- }
}
onSortOrderSelected: {
- if (contentModel !== undefined) {
+ if (contentModel !== undefined)
contentModel.sortOrder = type
- }
}
-
- sortKey: contentModel ? contentModel.sortCriteria : PlaylistControllerModel.SORT_KEY_NONE
- sortOrder: contentModel ? contentModel.sortOrder : undefined
}
}
=====================================
modules/gui/qt/maininterface/qml/MainDisplay.qml
=====================================
@@ -59,29 +59,48 @@ FocusScope {
function loadView() {
var found = stackView.loadView(root.pageModel, root.view.name, root.view.properties)
- stackView.currentItem.Navigation.parentItem = medialibId
- stackView.currentItem.Navigation.upItem = sourcesBanner
- stackView.currentItem.Navigation.rightItem = playlistColumn
- stackView.currentItem.Navigation.downItem = Qt.binding(function() {
+ var item = stackView.currentItem
+
+ item.Navigation.parentItem = medialibId
+ item.Navigation.upItem = sourcesBanner
+ item.Navigation.rightItem = playlistColumn
+
+ item.Navigation.downItem = Qt.binding(function() {
return miniPlayer.visible ? miniPlayer : medialibId
})
- sourcesBanner.localMenuDelegate = Qt.binding(function () { return !!stackView.currentItem.localMenuDelegate ? stackView.currentItem.localMenuDelegate : null })
- sourcesBanner.sortModel = Qt.binding(function () { return stackView.currentItem.sortModel })
- sourcesBanner.contentModel = Qt.binding(function () { return stackView.currentItem.contentModel })
- sourcesBanner.extraLocalActions = Qt.binding(function () { return stackView.currentItem.extraLocalActions })
+ sourcesBanner.localMenuDelegate = Qt.binding(function () {
+ return !!item.localMenuDelegate ? item.localMenuDelegate : null
+ })
+
+ // NOTE: sortMenu is declared with the SortMenu type, so when it's undefined we have to
+ // return null to avoid a QML warning.
+ sourcesBanner.sortMenu = Qt.binding(function () {
+ if (item.sortMenu)
+ return item.sortMenu
+ else
+ return null
+ })
+
+ sourcesBanner.sortModel = Qt.binding(function () { return item.sortModel })
+ sourcesBanner.contentModel = Qt.binding(function () { return item.contentModel })
+
+ sourcesBanner.extraLocalActions = Qt.binding(function () { return item.extraLocalActions })
+
sourcesBanner.isViewMultiView = Qt.binding(function () {
- return stackView.currentItem.isViewMultiView === undefined || stackView.currentItem.isViewMultiView
+ return item.isViewMultiView === undefined || item.isViewMultiView
})
+
// Restore sourcesBanner state
sourcesBanner.selectedIndex = pageModel.filter(function (e) {
- return e.listed;
+ return e.listed
}).findIndex(function (e) {
return e.name === root.view
})
- if (stackView.currentItem.pageModel !== undefined)
- sourcesBanner.subSelectedIndex = stackView.currentItem.pageModel.findIndex(function (e) {
- return e.name === stackView.currentItem.view
+
+ if (item.pageModel !== undefined)
+ sourcesBanner.subSelectedIndex = item.pageModel.findIndex(function (e) {
+ return e.name === item.view
})
if (Player.hasVideoOutput && MainCtx.hasEmbededVideo)
=====================================
modules/gui/qt/medialibrary/mlgroup.cpp
=====================================
@@ -29,7 +29,7 @@
MLGroup::MLGroup(const vlc_ml_group_t * data)
: MLItemCover(MLItemId(data->i_id, VLC_ML_PARENT_GROUP))
- , m_name(qfu(data->psz_name))
+ , m_title(qfu(data->psz_name))
, m_duration(data->i_duration)
, m_date(data->i_creation_date)
, m_count(data->i_nb_total_media)
@@ -41,9 +41,9 @@ MLGroup::MLGroup(const vlc_ml_group_t * data)
// Interface
//-------------------------------------------------------------------------------------------------
-QString MLGroup::getName() const
+QString MLGroup::getTitle() const
{
- return m_name;
+ return m_title;
}
//-------------------------------------------------------------------------------------------------
=====================================
modules/gui/qt/medialibrary/mlgroup.hpp
=====================================
@@ -34,7 +34,7 @@ public:
MLGroup(const vlc_ml_group_t * data);
public: // Interface
- QString getName() const;
+ QString getTitle() const;
int64_t getDuration() const;
@@ -43,7 +43,7 @@ public: // Interface
unsigned int getCount() const;
private:
- QString m_name;
+ QString m_title;
int64_t m_duration;
=====================================
modules/gui/qt/medialibrary/mlgrouplistmodel.cpp
=====================================
@@ -44,7 +44,7 @@ static const int MLGROUPLISTMODEL_COVER_HEIGHT = 320 * 2;
static const QHash<QByteArray, vlc_ml_sorting_criteria_t> criterias =
{
- { "name", VLC_ML_SORTING_ALPHA },
+ { "title", VLC_ML_SORTING_ALPHA },
{ "duration", VLC_ML_SORTING_DURATION },
{ "date", VLC_ML_SORTING_INSERTIONDATE }
};
@@ -64,21 +64,22 @@ QHash<int, QByteArray> MLGroupListModel::roleNames() const /* override */
{
return
{
+ { GROUP_IS_VIDEO, "isVideo" },
{ GROUP_ID, "id" },
- { GROUP_NAME, "name" },
+ { GROUP_TITLE, "title" },
{ GROUP_THUMBNAIL, "thumbnail" },
{ GROUP_DURATION, "duration" },
{ GROUP_DATE, "date" },
{ GROUP_COUNT, "count" },
// NOTE: Media specific.
{ GROUP_IS_NEW, "isNew" },
- { GROUP_TITLE, "title" },
+ { GROUP_FILENAME, "fileName" },
+ { GROUP_PROGRESS, "progress" },
+ { GROUP_PLAYCOUNT, "playcount" },
{ GROUP_RESOLUTION, "resolution_name" },
{ GROUP_CHANNEL, "channel" },
{ GROUP_MRL, "mrl" },
{ GROUP_MRL_DISPLAY, "display_mrl" },
- { GROUP_PROGRESS, "progress" },
- { GROUP_PLAYCOUNT, "playcount" },
{ GROUP_VIDEO_TRACK, "videoDesc" },
{ GROUP_AUDIO_TRACK, "audioDesc" },
{ GROUP_TITLE_FIRST_SYMBOL, "title_first_symbol" }
@@ -98,12 +99,14 @@ QVariant MLGroupListModel::itemRoleData(MLItem *item, const int role) const /* o
{
// NOTE: This is the condition for QWidget view(s).
case Qt::DisplayRole:
- return QVariant::fromValue(group->getName());
+ return QVariant::fromValue(group->getTitle());
// NOTE: These are the conditions for QML view(s).
+ case GROUP_IS_VIDEO:
+ return false;
case GROUP_ID:
return QVariant::fromValue(group->getId());
- case GROUP_NAME:
- return QVariant::fromValue(group->getName());
+ case GROUP_TITLE:
+ return QVariant::fromValue(group->getTitle());
case GROUP_THUMBNAIL:
return getCover(group);
case GROUP_DURATION:
@@ -124,9 +127,11 @@ QVariant MLGroupListModel::itemRoleData(MLItem *item, const int role) const /* o
{
case Qt::DisplayRole:
return QVariant::fromValue(video->getTitle());
+ case GROUP_IS_VIDEO:
+ return true;
case GROUP_ID:
return QVariant::fromValue(video->getId());
- case GROUP_NAME:
+ case GROUP_TITLE:
return QVariant::fromValue(video->getTitle());
case GROUP_THUMBNAIL:
{
@@ -147,8 +152,12 @@ QVariant MLGroupListModel::itemRoleData(MLItem *item, const int role) const /* o
// NOTE: Media specific.
case GROUP_IS_NEW:
return QVariant::fromValue(video->isNew());
- case GROUP_TITLE:
- return QVariant::fromValue(video->getTitle());
+ case GROUP_FILENAME:
+ return QVariant::fromValue(video->getFileName());
+ case GROUP_PROGRESS:
+ return QVariant::fromValue(video->getProgress());
+ case GROUP_PLAYCOUNT:
+ return QVariant::fromValue(video->getPlayCount());
case GROUP_RESOLUTION:
return QVariant::fromValue(video->getResolutionName());
case GROUP_CHANNEL:
@@ -157,10 +166,6 @@ QVariant MLGroupListModel::itemRoleData(MLItem *item, const int role) const /* o
return QVariant::fromValue(video->getMRL());
case GROUP_MRL_DISPLAY:
return QVariant::fromValue(video->getDisplayMRL());
- case GROUP_PROGRESS:
- return QVariant::fromValue(video->getProgress());
- case GROUP_PLAYCOUNT:
- return QVariant::fromValue(video->getPlayCount());
case GROUP_VIDEO_TRACK:
return QVariant::fromValue(video->getVideoDesc());
case GROUP_AUDIO_TRACK:
@@ -181,7 +186,7 @@ vlc_ml_sorting_criteria_t MLGroupListModel::roleToCriteria(int role) const /* ov
{
switch (role)
{
- case GROUP_NAME:
+ case GROUP_TITLE:
return VLC_ML_SORTING_ALPHA;
case GROUP_DURATION:
return VLC_ML_SORTING_DURATION;
=====================================
modules/gui/qt/medialibrary/mlgrouplistmodel.hpp
=====================================
@@ -35,29 +35,32 @@ class MLGroupListModel : public MLBaseModel
public:
enum Roles
{
- GROUP_ID = Qt::UserRole + 1,
- GROUP_NAME,
+ GROUP_IS_VIDEO = Qt::UserRole + 1,
+ GROUP_ID,
+ GROUP_TITLE,
GROUP_THUMBNAIL,
GROUP_DURATION,
GROUP_DATE,
GROUP_COUNT,
// NOTE: Media specific.
GROUP_IS_NEW,
- GROUP_TITLE,
+ GROUP_FILENAME,
+ GROUP_PROGRESS,
+ GROUP_PLAYCOUNT,
GROUP_RESOLUTION,
GROUP_CHANNEL,
GROUP_MRL,
GROUP_MRL_DISPLAY,
- GROUP_PROGRESS,
- GROUP_PLAYCOUNT,
GROUP_VIDEO_TRACK,
GROUP_AUDIO_TRACK,
+
GROUP_TITLE_FIRST_SYMBOL
};
public:
explicit MLGroupListModel(QObject * parent = nullptr);
+
public: // QAbstractItemModel implementation
QHash<int, QByteArray> roleNames() const override;
=====================================
modules/gui/qt/medialibrary/mlvideomodel.cpp
=====================================
@@ -32,7 +32,6 @@ QVariantList getVariantList(const QList<T> & desc)
}
QHash<QByteArray, vlc_ml_sorting_criteria_t> MLVideoModel::M_names_to_criteria = {
- {"id", VLC_ML_SORTING_DEFAULT},
{"title", VLC_ML_SORTING_ALPHA},
{"duration", VLC_ML_SORTING_DURATION},
{"playcount", VLC_ML_SORTING_PLAYCOUNT},
=====================================
modules/gui/qt/medialibrary/qml/MediaGroupDisplay.qml
=====================================
@@ -28,36 +28,32 @@ import "qrc:///style/"
VideoAll {
id: root
- //---------------------------------------------------------------------------------------------
// Properties
- //---------------------------------------------------------------------------------------------
- property int initialIndex: 0
- property MLItemId initialId
- property string initialName
+ property int initialIndex: 0
+ property MLItemId initialId
+ property string initialName
- //---------------------------------------------------------------------------------------------
// Aliases
- //---------------------------------------------------------------------------------------------
// NOTE: This is used to determine which media(s) shall be displayed..
- property alias parentId: modelGroup.parentId
+ property alias parentId: modelVideo.parentId
- // NOTE: The name of the group.
- property string name: initialName
+ // NOTE: The title of the group.
+ property string title: initialTitle
- //---------------------------------------------------------------------------------------------
- // Childs
- //---------------------------------------------------------------------------------------------
+ // Children
model: MLVideoModel {
- id: modelGroup
+ id: modelVideo
ml: MediaLib
parentId: initialId
}
+ contextMenu: VideoContextMenu { model: modelVideo }
+
header: Column {
width: root.width
@@ -71,7 +67,7 @@ VideoAll {
// NOTE: We want this to be properly aligned with the grid items.
anchors.leftMargin: contentMargin + VLCStyle.margin_normal
- text: root.name
+ text: root.title
}
}
}
=====================================
modules/gui/qt/medialibrary/qml/MediaGroupList.qml deleted
=====================================
@@ -1,402 +0,0 @@
-/*****************************************************************************
- * 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 QtQml.Models 2.11
-
-import org.videolan.medialib 0.1
-import org.videolan.vlc 0.1
-
-import "qrc:///widgets/" as Widgets
-import "qrc:///main/" as MainInterface
-import "qrc:///util/" as Util
-import "qrc:///style/"
-
-FocusScope {
- 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("Duration"), criteria: "duration" },
- { text: I18n.qtr("Date"), criteria: "date" }
- ]
-
- //---------------------------------------------------------------------------------------------
- // Alias
- //---------------------------------------------------------------------------------------------
-
- property alias model: model
-
- // Private
-
- property alias _currentView: view.currentItem
-
- //---------------------------------------------------------------------------------------------
- // Signals
- //---------------------------------------------------------------------------------------------
-
- signal showList(var model, int reason)
-
- //---------------------------------------------------------------------------------------------
- // Events
- //---------------------------------------------------------------------------------------------
-
- onModelChanged: resetFocus()
-
- onInitialIndexChanged: resetFocus()
-
- //---------------------------------------------------------------------------------------------
- // Connections
- //---------------------------------------------------------------------------------------------
-
- Connections {
- target: MainCtx
-
- onGridViewChanged: {
- if (MainCtx.gridView) view.replace(grid);
- else view.replace(list);
- }
- }
-
- //---------------------------------------------------------------------------------------------
- // Functions
- //---------------------------------------------------------------------------------------------
-
- function setCurrentItemFocus(reason) {
- _currentView.setCurrentItemFocus(reason);
- }
-
- 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 (_currentView)
- _currentView.positionViewAtIndex(initialIndex, ItemView.Contain);
- }
-
- //---------------------------------------------------------------------------------------------
- // Private
-
- function _actionAtIndex() {
- if (modelSelect.selectedIndexes.length > 1) {
- g_mainDisplay.play(MediaLib, model.getIdsForIndexes(modelSelect.selectedIndexes));
- } else if (modelSelect.selectedIndexes.length === 1) {
- var index = modelSelect.selectedIndexes[0];
- _showList(model.getDataAt(index), Qt.TabFocusReason);
- }
- }
-
- function _showList(model, reason)
- {
- // NOTE: If the count is 1 we consider the group is a media.
- if (model.count == 1)
- g_mainDisplay.play(MediaLib, model.id);
- else
- showList(model, reason);
- }
-
- function _onNavigationCancel() {
- if (_currentView.currentIndex > 0) {
- _currentView.currentIndex = 0;
-
- _currentView.positionViewAtIndex(0, ItemView.Contain);
- } else {
- root.Navigation.defaultNavigationCancel();
- }
- }
-
- function _getLabels(model, string)
- {
- var count = model.count;
-
- if (count === 1) {
- return [
- model.resolution_name || "",
- model.channel || ""
- ].filter(function(a) { return a !== "" });
- } else {
- if (count < 100)
- return [ string.arg(count) ];
- else
- return [ string.arg("99+") ];
- }
- }
-
- //---------------------------------------------------------------------------------------------
- // 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: (MainCtx.gridView) ? grid : list
-
- focus: (model.count !== 0)
- }
-
- GroupListContextMenu {
- id: contextMenu
-
- model: root.model
- }
-
- Widgets.MLDragItem {
- id: dragItemGroup
-
- mlModel: model
-
- indexes: modelSelect.selectedIndexes
-
- coverRole: "thumbnail"
-
- titleRole: "name"
- }
-
- //---------------------------------------------------------------------------------------------
- // 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
-
- selectionDelegateModel: modelSelect
-
- activeFocusOnTab: true
-
- Navigation.parentItem: root
- //cancelAction takes a *function* pass it directly
- Navigation.cancelAction: root._onNavigationCancel
-
- expandDelegate: VideoInfoExpandPanel {
- width: gridView.width
-
- x: 0
-
- model: root.model
-
- Navigation.parentItem: gridView
-
- Navigation.upAction : function() { gridView.retract() }
- Navigation.downAction : function() { gridView.retract() }
- Navigation.cancelAction: function() { gridView.retract() }
-
- onRetract: gridView.retract()
- }
-
- delegate: VideoGridItem {
- id: gridItem
-
- //---------------------------------------------------------------------------------
- // properties required by ExpandGridView
-
- property var model: ({})
- property int index: -1
-
- //---------------------------------------------------------------------------------
- // 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 Videos"))
-
- // NOTE: We don't want to show the indicator for a group..
- // FIXME: Sometimes MLBaseModel::getDataAt returns {} so we use 'isNew === true'.
- showNewIndicator: (model.count === 1 && model.isNew === true)
-
- dragItem: dragItemGroup
-
- selectedUnderlay : shadows.selected
- unselectedUnderlay: shadows.unselected
-
- //---------------------------------------------------------------------------------
- // Events
-
- onItemClicked: gridView.leftClickOnItem(modifier, index)
-
- onItemDoubleClicked: _showList(model, Qt.MouseFocusReason)
-
- onContextMenuButtonClicked: {
- gridView.rightClickOnItem(index);
-
- contextMenu.popup(modelSelect.selectedIndexes, globalMousePos,
- { "information" : index });
- }
-
- //---------------------------------------------------------------------------------
- // Animations
-
- Behavior on opacity { NumberAnimation { duration: VLCStyle.duration_faster } }
- }
-
- //-------------------------------------------------------------------------------------
- // 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)
- }
-
- onActionAtIndex: _actionAtIndex()
-
- //-------------------------------------------------------------------------------------
- // Connections
-
- Connections {
- target: contextMenu
-
- // FIXME: We need to implement this in qml_menu_wrapper.
- //onShowMediaInformation: gridView.switchExpandItem(index)
- }
-
- //-------------------------------------------------------------------------------------
- // Childs
-
- Widgets.GridShadows {
- id: shadows
-
- coverWidth : VLCStyle.gridCover_video_width
- coverHeight: VLCStyle.gridCover_video_height
- }
- }
- }
-
- Component {
- id: list
-
- VideoListDisplay
- {
- id: listView
-
- //-------------------------------------------------------------------------------------
- // Settings
-
- model: root.model
-
- mainCriteria: "name"
-
- selectionDelegateModel: modelSelect
-
- dragItem: dragItemGroup
-
- headerTopPadding: VLCStyle.margin_normal
-
- headerPositioning: ListView.InlineHeader
-
- Navigation.parentItem: root
- //cancelAction takes a *function* pass it directly
- Navigation.cancelAction: root._onNavigationCancel
-
- //-------------------------------------------------------------------------------------
- // Events
-
- onActionForSelection: _actionAtIndex()
-
- // NOTE: We make sure we're double clicking on a group.
- onItemDoubleClicked: if (model.count > 1) showList(model, Qt.MouseFocusReason)
-
- onContextMenuButtonClicked: contextMenu.popup(modelSelect.selectedIndexes,
- globalMousePos)
-
- 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
-
- Navigation.parentItem: root
-
- focus: visible
- }
-}
=====================================
modules/gui/qt/medialibrary/qml/VideoAll.qml
=====================================
@@ -34,9 +34,8 @@ FocusScope {
// Properties
- readonly property int contentMargin: (MainCtx.gridView
- &&
- _currentView) ? _currentView.contentMargin : 0
+ readonly property int contentMargin: (_currentView.contentMargin) ? _currentView.contentMargin
+ : 0
// NOTE: Specify an optional header for the view.
property Component header: undefined
@@ -47,7 +46,10 @@ FocusScope {
property int initialIndex: 0
- property MLVideoModel model: MLVideoModel { ml: MediaLib }
+ /* required */ property var model
+
+ // NOTE: The ContextMenu depends on the model so we have to provide it too.
+ /* required */ property var contextMenu
property var sortModel: [
{ text: I18n.qtr("Alphabetic"), criteria: "title" },
@@ -74,8 +76,8 @@ FocusScope {
target: MainCtx
onGridViewChanged: {
- if (MainCtx.gridView) view.replace(grid);
- else view.replace(list);
+ if (MainCtx.gridView) view.replace(grid)
+ else view.replace(list)
}
}
@@ -110,34 +112,51 @@ FocusScope {
_currentView.positionViewAtIndex(initialIndex, ItemView.Contain)
}
- // Private
-
- function _actionAtIndex() {
- g_mainDisplay.showPlayer();
+ function getLabel(model) {
+ if (!model) return ""
- MediaLib.addAndPlay(model.getIdsForIndexes(modelSelect.selectedIndexes));
+ return [
+ model.resolution_name || "",
+ model.channel || ""
+ ].filter(function(a) { return a !== "" })
}
// Events
+ function onAction(indexes) {
+ g_mainDisplay.showPlayer()
+
+ MediaLib.addAndPlay(model.getIdsForIndexes(indexes))
+ }
+
+ function onDoubleClick(object) {
+ g_mainDisplay.play(MediaLib, object.id)
+ }
+
+ function onLabelGrid(object) { return getLabel(object) }
+ function onLabelList(object) { return getLabel(object) }
+
+ // Private events
+
function _onNavigationUp() {
- if (headerItem && headerItem.focus)
- headerItem.setCurrentItemFocus(Qt.TabFocusReason);
+ // NOTE: We are calling the header focus function when we have one.
+ if (headerItem && (typeof headerItem.setCurrentItemFocus === "function"))
+ headerItem.setCurrentItemFocus(Qt.TabFocusReason)
else
- Navigation.defaultNavigationUp();
+ Navigation.defaultNavigationUp()
}
function _onNavigationCancel() {
if (_currentView.currentIndex <= 0) {
- Navigation.defaultNavigationCancel();
+ Navigation.defaultNavigationCancel()
} else {
- _currentView.currentIndex = 0;
+ _currentView.currentIndex = 0
- _currentView.positionViewAtIndex(0, ItemView.Contain);
+ _currentView.positionViewAtIndex(0, ItemView.Contain)
}
}
- // Childs
+ // Children
Widgets.StackViewExt {
id: view
@@ -165,12 +184,6 @@ FocusScope {
model: root.model
}
- VideoContextMenu {
- id: contextMenu
-
- model: root.model
- }
-
Component {
id: grid
@@ -194,29 +207,15 @@ FocusScope {
activeFocusOnTab: true
+ // Navigation
+
Navigation.parentItem: root
Navigation.upAction: _onNavigationUp
- //cancelAction takes a *function* pass it directly
+ // NOTE: cancelAction takes a function, we pass it directly.
Navigation.cancelAction: root._onNavigationCancel
- expandDelegate: VideoInfoExpandPanel {
- width: gridView.width
-
- x: 0
-
- model: root.model
-
- Navigation.parentItem: gridView
-
- Navigation.cancelAction: function() { gridView.retract() }
- Navigation.upAction : function() { gridView.retract() }
- Navigation.downAction : function() { gridView.retract() }
-
- onRetract: gridView.retract()
- }
-
// Events
// NOTE: Define the initial position and selection. This is done on activeFocus rather
@@ -229,17 +228,17 @@ FocusScope {
modelSelect.select(model.index(0,0), ItemSelectionModel.ClearAndSelect);
}
- onActionAtIndex: _actionAtIndex()
+ onActionAtIndex: root.onAction(modelSelect.selectedIndexes)
// Connections
Connections {
- target: contextMenu
+ target: root.contextMenu
onShowMediaInformation: gridView.switchExpandItem(index)
}
- // Childs
+ // Children
Widgets.GridShadows {
id: shadows
@@ -262,6 +261,8 @@ FocusScope {
&&
gridView.expandIndex !== gridItem.index) ? 0.7 : 1
+ labels: root.onLabelGrid(model)
+
// FIXME: Sometimes MLBaseModel::getDataAt returns {} so we use 'isNew === true'.
showNewIndicator: (model.isNew === true)
@@ -274,19 +275,35 @@ FocusScope {
onItemClicked: gridView.leftClickOnItem(modifier, index)
- onItemDoubleClicked: g_mainDisplay.play(MediaLib, model.id)
+ onItemDoubleClicked: root.onDoubleClick(model)
onContextMenuButtonClicked: {
gridView.rightClickOnItem(index);
- contextMenu.popup(modelSelect.selectedIndexes, globalMousePos,
- { "information" : index });
+ root.contextMenu.popup(modelSelect.selectedIndexes, globalMousePos,
+ { "information" : index });
}
// Animations
Behavior on opacity { NumberAnimation { duration: VLCStyle.duration_faster } }
}
+
+ expandDelegate: VideoInfoExpandPanel {
+ width: gridView.width
+
+ x: 0
+
+ model: root.model
+
+ Navigation.parentItem: gridView
+
+ Navigation.cancelAction: function() { gridView.retract() }
+ Navigation.upAction : function() { gridView.retract() }
+ Navigation.downAction : function() { gridView.retract() }
+
+ onRetract: gridView.retract()
+ }
}
}
@@ -313,6 +330,8 @@ FocusScope {
activeFocusOnTab: true
+ // Navigation
+
Navigation.parentItem: root
Navigation.upAction: _onNavigationUp
@@ -322,14 +341,18 @@ FocusScope {
// Events
- onActionForSelection: _actionAtIndex()
+ onActionForSelection: root.onAction(modelSelect.selectedIndexes)
+
+ onItemDoubleClicked: root.onDoubleClick(model)
- onItemDoubleClicked: g_mainDisplay.play(MediaLib, model.id)
+ onContextMenuButtonClicked: root.contextMenu.popup(modelSelect.selectedIndexes,
+ menuParent.mapToGlobal(0,0))
- onContextMenuButtonClicked: contextMenu.popup(modelSelect.selectedIndexes,
- globalMousePos)
+ onRightClick: root.contextMenu.popup(modelSelect.selectedIndexes, globalMousePos)
- onRightClick: contextMenu.popup(modelSelect.selectedIndexes, globalMousePos)
+ // Functions
+
+ function onLabels(model) { return root.onLabelList(model); }
}
}
@@ -341,12 +364,12 @@ FocusScope {
visible: (model.count === 0)
+ focus: visible
+
text: I18n.qtr("No video found\nPlease try adding sources, by going to the Network tab")
cover: VLCStyle.noArtVideoCover
Navigation.parentItem: root
-
- focus: visible
}
}
=====================================
modules/gui/qt/medialibrary/qml/VideoAllDisplay.qml
=====================================
@@ -25,102 +25,83 @@ import org.videolan.vlc 0.1
import org.videolan.medialib 0.1
import "qrc:///widgets/" as Widgets
-import "qrc:///main/" as MainInterface
-import "qrc:///util/" as Util
import "qrc:///style/"
-VideoAll {
+Widgets.PageLoader {
id: root
- // Events
+ // Properties
- onCurrentIndexChanged: {
- History.update([ "mc", "video", { "initialIndex": currentIndex }])
- }
+ property var model
+ property var sortMenu
+ property var sortModel
- // Functions
+ // Settings
- function setCurrentItemFocus(reason) {
- if (modelRecent.count)
- headerItem.setCurrentItemFocus(reason);
- else
- _currentView.setCurrentItemFocus(reason);
- }
+ defaultPage: "base"
- // Children
+ pageModel: [{
+ name: "base",
+ component: componentBase
+ }, {
+ name: "group",
+ component: componentGroup
+ }]
- MLRecentsVideoModel {
- id: modelRecent
+ // Events
- ml: MediaLib
+ onCurrentItemChanged: {
+ model = currentItem.model
+ sortMenu = currentItem.sortMenu
+ sortModel = currentItem.sortModel
}
+ // Functions private
- header: Column {
- property Item focusItem: (loader.status === Loader.Ready) ? loader.item.focusItem : null
-
- property alias loader: loader
-
- width: root.width
-
- topPadding: VLCStyle.margin_normal
- bottomPadding: VLCStyle.margin_normal
-
- // NOTE: We want the header to be visible when we have at least one media visible.
- // Otherwise it overlaps the default caption.
- visible: (model.count)
-
- // NOTE: Making sure this item will be focused by VideoAll::_onNavigationUp().
- focus: true
-
- function setCurrentItemFocus(reason) {
- var item = loader.item;
-
- if (item)
- item.setCurrentItemFocus(reason);
- }
-
- Loader {
- id: loader
-
- anchors.left : parent.left
- anchors.right: parent.right
-
- anchors.margins: root.contentMargin
-
- height: (status === Loader.Ready) ? item.implicitHeight : 0
-
- active: (modelRecent.count)
+ function _updateHistoryAll(index) {
+ History.update(["mc", "video", "all", "base", { "initialIndex": index }])
+ }
- visible: active
+ function _updateHistoryGroup(group) {
+ History.update(["mc", "video", "all", "group", {
+ "initialIndex": group.currentIndex,
+ "initialId" : group.parentId,
+ "initialTitle": group.title
+ }])
+ }
- sourceComponent: VideoDisplayRecentVideos {
- id: component
+ // Children
- width: parent.width
+ Component {
+ id: componentBase
- // NOTE: We want grid items to be visible on the sides.
- displayMargins: root.contentMargin
+ VideoAllSubDisplay {
+ // Events
- model: modelRecent
+ onShowList: {
+ History.push(["mc", "video", "all", "group",
+ { parentId: model.id, title: model.title }])
- focus: true
+ root.stackView.currentItem.setCurrentItemFocus(reason)
+ }
- Navigation.parentItem: root
+ // NOTE: The model can change over time.
+ onModelChanged: root.model = model
- Navigation.downAction: function() {
- _currentView.setCurrentItemFocus(Qt.TabFocusReason);
- }
- }
+ onCurrentIndexChanged: root._updateHistoryAll(currentIndex)
}
+ }
+
+ Component {
+ id: componentGroup
- Widgets.SubtitleLabel {
- anchors.left: loader.left
- anchors.right: loader.right
+ MediaGroupDisplay {
+ id: group
- // NOTE: We want this to be properly aligned with the grid items.
- anchors.leftMargin: VLCStyle.margin_normal
+ anchors.fill: parent
- text: I18n.qtr("Videos")
+ onCurrentIndexChanged: root._updateHistoryGroup(group)
+ onParentIdChanged : root._updateHistoryGroup(group)
+ onTitleChanged : root._updateHistoryGroup(group)
}
}
}
=====================================
modules/gui/qt/medialibrary/qml/VideoAllSubDisplay.qml
=====================================
@@ -0,0 +1,230 @@
+/*****************************************************************************
+ * 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.vlc 0.1
+import org.videolan.medialib 0.1
+
+import "qrc:///widgets/" as Widgets
+import "qrc:///style/"
+
+VideoAll {
+ id: root
+
+ // Properties
+
+ // NOTE: We are exposing a custom SortMenu with grouping options.
+ property SortMenuVideo sortMenu: SortMenuVideo {
+ ctx: MainCtx
+
+ onGrouping: MainCtx.grouping = grouping
+ }
+
+ // Private
+
+ property var _meta: (MainCtx.grouping === MainCtx.GROUPING_NONE) ? metaVideo
+ : metaGroup
+
+ // Signals
+
+ signal showList(var model, int reason)
+
+ // Settings
+
+ anchors.fill: parent
+
+ model: _meta.model
+
+ contextMenu: _meta.contextMenu
+
+ // Functions
+
+ function getLabelGroup(model, string) {
+ if (!model) return ""
+
+ var count = model.count
+
+ if (count === 1) {
+ return getLabel(model)
+ } else {
+ if (count < 100)
+ return [ string.arg(count) ]
+ else
+ return [ string.arg("99+") ]
+ }
+ }
+
+ // VideoAll reimplementation
+
+ function setCurrentItemFocus(reason) {
+ if (modelRecent.count)
+ headerItem.setCurrentItemFocus(reason)
+ else
+ _currentView.setCurrentItemFocus(reason)
+ }
+
+ // VideoAll events reimplementation
+
+ function onAction(indexes) { _meta.onAction(indexes) }
+
+ function onDoubleClick(object) { _meta.onDoubleClick(object) }
+
+ function onLabelGrid(object) { return _meta.onLabelGrid(object) }
+ function onLabelList(object) { return _meta.onLabelList(object) }
+
+ // Children
+
+ QtObject {
+ id: metaVideo
+
+ property var model: MLVideoModel { ml: MediaLib }
+
+ property var contextMenu: VideoContextMenu { model: metaVideo.model }
+
+ function onAction(indexes) {
+ g_mainDisplay.showPlayer()
+
+ MediaLib.addAndPlay(model.getIdsForIndexes(indexes))
+ }
+
+ function onDoubleClick(object) { g_mainDisplay.play(MediaLib, object.id) }
+
+ function onLabelGrid(object) { return root.getLabel(object) }
+ function onLabelList(object) { return root.getLabel(object) }
+ }
+
+ QtObject {
+ id: metaGroup
+
+ property var model: MLGroupListModel { ml: MediaLib }
+
+ property var contextMenu: GroupListContextMenu { model: metaGroup.model }
+
+ function onAction(indexes) {
+ var index = indexes[0]
+
+ var object = model.getDataAt(index);
+
+ if (object.isVideo) {
+ g_mainDisplay.showPlayer()
+
+ MediaLib.addAndPlay(model.getIdsForIndexes(indexes))
+
+ return
+ }
+
+ root.showList(object, Qt.TabFocusReason)
+ }
+
+ function onDoubleClick(object) {
+ if (object.isVideo) {
+ g_mainDisplay.play(MediaLib, object.id)
+
+ return
+ }
+
+ root.showList(object, Qt.MouseFocusReason)
+ }
+
+ function onLabelGrid(object) {
+ return root.getLabelGroup(object, I18n.qtr("%1 Videos"))
+ }
+
+ function onLabelList(object) {
+ return root.getLabelGroup(object, I18n.qtr("%1"))
+ }
+ }
+
+ // Children
+
+ MLRecentsVideoModel {
+ id: modelRecent
+
+ ml: MediaLib
+ }
+
+ header: Column {
+ property Item focusItem: (loader.status === Loader.Ready) ? loader.item.focusItem
+ : null
+
+ property alias loader: loader
+
+ width: root.width
+
+ topPadding: VLCStyle.margin_normal
+ bottomPadding: VLCStyle.margin_normal
+
+ // NOTE: We want the header to be visible when we have at least one media visible.
+ // Otherwise it overlaps the default caption.
+ visible: (root.model.count)
+
+ function setCurrentItemFocus(reason) {
+ var item = loader.item;
+
+ if (item)
+ item.setCurrentItemFocus(reason);
+ }
+
+ Loader {
+ id: loader
+
+ anchors.left : parent.left
+ anchors.right: parent.right
+
+ anchors.margins: root.contentMargin
+
+ height: (status === Loader.Ready) ? item.implicitHeight : 0
+
+ active: (modelRecent.count)
+
+ visible: active
+
+ sourceComponent: VideoDisplayRecentVideos {
+ id: component
+
+ width: parent.width
+
+ // NOTE: We want grid items to be visible on the sides.
+ displayMargins: root.contentMargin
+
+ model: modelRecent
+
+ focus: true
+
+ Navigation.parentItem: root
+
+ Navigation.downAction: function() {
+ _currentView.setCurrentItemFocus(Qt.TabFocusReason);
+ }
+ }
+ }
+
+ Widgets.SubtitleLabel {
+ anchors.left: loader.left
+ anchors.right: loader.right
+
+ // NOTE: We want this to be properly aligned with the grid items.
+ anchors.leftMargin: VLCStyle.margin_normal
+
+ text: I18n.qtr("Videos")
+ }
+ }
+}
=====================================
modules/gui/qt/medialibrary/qml/VideoDisplay.qml
=====================================
@@ -37,6 +37,8 @@ Widgets.PageLoader {
property bool isViewMultiView: true
property var contentModel
+
+ property var sortMenu
property var sortModel
property ListModel tabModel: ListModel {
@@ -68,10 +70,6 @@ Widgets.PageLoader {
name: "all",
displayText: I18n.qtr("All"),
url: "qrc:///medialibrary/VideoAllDisplay.qml"
- },{
- name: "groups",
- displayText: I18n.qtr("Groups"),
- url: "qrc:///medialibrary/VideoGroupsDisplay.qml"
},{
name: "playlists",
displayText: I18n.qtr("Playlists"),
@@ -84,8 +82,10 @@ Widgets.PageLoader {
||
currentItem.isViewMultiView);
- contentModel = currentItem.model;
- sortModel = currentItem.sortModel;
+ // NOTE: We need bindings because the VideoAll model can change over time.
+ contentModel = Qt.binding(function () { return currentItem.model; })
+ sortMenu = Qt.binding(function () { return currentItem.sortMenu; })
+ sortModel = Qt.binding(function () { return currentItem.sortModel; })
}
//---------------------------------------------------------------------------------------------
=====================================
modules/gui/qt/medialibrary/qml/VideoGroupsDisplay.qml deleted
=====================================
@@ -1,122 +0,0 @@
-/*****************************************************************************
- * 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 QtQuick.Controls 2.4
-import QtQuick.Layouts 1.11
-import QtQml.Models 2.2
-
-import org.videolan.vlc 0.1
-import org.videolan.medialib 0.1
-
-import "qrc:///widgets/" as Widgets
-import "qrc:///style/"
-
-Widgets.PageLoader {
- id: root
-
- //---------------------------------------------------------------------------------------------
- // Aliases
- //---------------------------------------------------------------------------------------------
-
- property bool isViewMultiView: true
-
- property var model
- property var sortModel
-
- //---------------------------------------------------------------------------------------------
- // Settings
- //---------------------------------------------------------------------------------------------
-
- defaultPage: "all"
-
- pageModel: [{
- name: "all",
- component: componentAll
- }, {
- name: "list",
- component: componentList
- }]
-
- //---------------------------------------------------------------------------------------------
- // Events
- //---------------------------------------------------------------------------------------------
-
- onCurrentItemChanged: {
- model = currentItem.model;
- sortModel = currentItem.sortModel;
-
- isViewMultiView = (currentItem.isViewMultiView === undefined
- ||
- currentItem.isViewMultiView);
- }
-
- //---------------------------------------------------------------------------------------------
- // Functions
- //---------------------------------------------------------------------------------------------
- // Private
-
- function _updateHistoryAll(index) {
- History.update(["mc", "video", "groups", "all", { "initialIndex": index }]);
- }
-
- function _updateHistoryList(list) {
- History.update(["mc", "video", "groups", "list", {
- "initialIndex": list.currentIndex,
- "initialId" : list.parentId,
- "initialName" : list.name
- }]);
- }
-
- //---------------------------------------------------------------------------------------------
- // Childs
- //---------------------------------------------------------------------------------------------
-
- Component {
- id: componentAll
-
- MediaGroupList {
- anchors.fill: parent
-
- onCurrentIndexChanged: _updateHistoryAll(currentIndex)
-
- onShowList: {
- History.push(["mc", "video", "groups", "list",
- { parentId: model.id, name: model.name }]);
-
- stackView.currentItem.setCurrentItemFocus(reason);
- }
- }
- }
-
- Component {
- id: componentList
-
- MediaGroupDisplay {
- id: list
-
- anchors.fill: parent
-
- onCurrentIndexChanged: _updateHistoryList(list)
- onParentIdChanged : _updateHistoryList(list)
- onNameChanged : _updateHistoryList(list)
- }
- }
-}
=====================================
modules/gui/qt/menus/qml_menu_wrapper.cpp
=====================================
@@ -32,8 +32,6 @@
#include "playlist/playlist_controller.hpp"
#include "playlist/playlist_model.hpp"
#include "dialogs/dialogs_provider.hpp"
-#include "maininterface/mainctx.hpp"
-
#include <QSignalMapper>
@@ -84,12 +82,16 @@ void StringListMenu::popup(const QPoint &point, const QVariantList &stringList)
m->popup(point);
}
+// SortMenu
+
SortMenu::~SortMenu()
{
if (m_menu)
delete m_menu;
}
+// Functions
+
void SortMenu::popup(const QPoint &point, const bool popupAbovePoint, const QVariantList &model)
{
if (m_menu)
@@ -117,6 +119,8 @@ void SortMenu::popup(const QPoint &point, const bool popupAbovePoint, const QVar
});
}
+ onPopup(m_menu);
+
// m_menu->height() returns invalid height until initial popup call
// so in case of 'popupAbovePoint', first show the menu and then reposition it
m_menu->popup(point);
@@ -133,6 +137,57 @@ void SortMenu::close()
m_menu->close();
}
+// Protected functions
+
+/* virtual */ void SortMenu::onPopup(QMenu *) {}
+
+// SortMenuVideo
+
+// Protected SortMenu reimplementation
+
+void SortMenuVideo::onPopup(QMenu * menu) /* override */
+{
+ if (!m_ctx)
+ return;
+
+ menu->addSeparator();
+
+ struct
+ {
+ const char * title;
+
+ MainCtx::Grouping grouping;
+ }
+ entries[] =
+ {
+ { N_("Do not group videos"), MainCtx::GROUPING_NONE },
+ { N_("Group by name"), MainCtx::GROUPING_NAME },
+ };
+
+ QActionGroup * group = new QActionGroup(this);
+
+ int index = m_ctx->grouping();
+
+ for (size_t i = 0; i < ARRAY_SIZE(entries); i++)
+ {
+ QAction * action = menu->addAction(qtr(entries[i].title));
+
+ action->setCheckable(true);
+
+ MainCtx::Grouping grouping = entries[i].grouping;
+
+ connect(action, &QAction::triggered, this, [this, grouping]()
+ {
+ emit this->grouping(grouping);
+ });
+
+ group->addAction(action);
+
+ if (index == grouping)
+ action->setChecked(true);
+ }
+}
+
QmlGlobalMenu::QmlGlobalMenu(QObject *parent)
: VLCMenuBar(parent)
{
@@ -498,7 +553,7 @@ GroupListContextMenu::~GroupListContextMenu() /* override */
delete m_menu;
}
-void GroupListContextMenu::popup(const QModelIndexList & selected, QPoint pos, QVariantMap)
+void GroupListContextMenu::popup(const QModelIndexList & selected, QPoint pos, QVariantMap options)
{
if (m_model == nullptr)
return;
@@ -508,8 +563,8 @@ void GroupListContextMenu::popup(const QModelIndexList & selected, QPoint pos, Q
QVariantList ids;
- for (const QModelIndex & modelIndex : selected)
- ids.push_back(m_model->data(modelIndex, MLGroupListModel::GROUP_ID));
+ for (const QModelIndex & index : selected)
+ ids.push_back(m_model->data(index, MLGroupListModel::GROUP_ID));
m_menu = new QMenu();
@@ -517,16 +572,60 @@ void GroupListContextMenu::popup(const QModelIndexList & selected, QPoint pos, Q
QAction * action = m_menu->addAction(qtr("Add and play"));
- connect(action, &QAction::triggered, [ml, ids]() {
- ml->addAndPlay(ids);
+ connect(action, &QAction::triggered, [ml, ids, options]()
+ {
+ ml->addAndPlay(ids, options["player-options"].toStringList());
});
action = m_menu->addAction(qtr("Enqueue"));
- connect(action, &QAction::triggered, [ml, ids]() {
+ connect(action, &QAction::triggered, [ml, ids]()
+ {
ml->addToPlaylist(ids);
});
+ action = m_menu->addAction(qtr("Add to playlist"));
+
+ connect(action, &QAction::triggered, [ids]()
+ {
+ DialogsProvider::getInstance()->playlistsDialog(ids);
+ });
+
+ action = m_menu->addAction(qtr("Play as audio"));
+
+ connect(action, &QAction::triggered, [ml, ids, options]()
+ {
+ QStringList list = options["player-options"].toStringList();
+
+ list.prepend(":no-video");
+
+ ml->addAndPlay(ids, list);
+ });
+
+ // NOTE: At the moment informations are only available for single video(s).
+ if (selected.count() == 1
+ &&
+ m_model->data(selected.first(), MLGroupListModel::GROUP_IS_VIDEO) == true
+ &&
+ options.contains("information") && options["information"].type() == QVariant::Int)
+ {
+ action = m_menu->addAction(qtr("Information"));
+
+ QSignalMapper * mapper = new QSignalMapper(m_menu);
+
+ mapper->setMapping(action, options["information"].toInt());
+
+ connect(action, &QAction::triggered, mapper, QOverload<>::of(&QSignalMapper::map));
+
+#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
+ connect(mapper, &QSignalMapper::mappedInt,
+ this, &GroupListContextMenu::showMediaInformation);
+#else
+ connect(mapper, QOverload<int>::of(&QSignalMapper::mapped),
+ this, &GroupListContextMenu::showMediaInformation);
+#endif
+ }
+
m_menu->popup(pos);
}
=====================================
modules/gui/qt/menus/qml_menu_wrapper.hpp
=====================================
@@ -24,6 +24,7 @@
#include <QPoint>
#include <QQuickItem>
#include "menus.hpp"
+#include "maininterface/mainctx.hpp"
class MediaLib;
class MLAlbumModel;
@@ -82,6 +83,9 @@ public:
Q_INVOKABLE void close();
+protected:
+ virtual void onPopup(QMenu * menu);
+
signals:
void selected(int index);
@@ -89,6 +93,18 @@ private:
QMenu *m_menu = nullptr;
};
+class SortMenuVideo : public SortMenu
+{
+ Q_OBJECT
+
+ SIMPLE_MENU_PROPERTY(MainCtx *, ctx, nullptr)
+
+protected: // SortMenu reimplementation
+ void onPopup(QMenu * menu) override;
+
+signals:
+ void grouping(MainCtx::Grouping grouping);
+};
//inherit VLCMenuBar so we can access menu creation functions
class QmlGlobalMenu : public VLCMenuBar
@@ -264,15 +280,22 @@ private:
class GroupListContextMenu : public QObject {
Q_OBJECT
+
SIMPLE_MENU_PROPERTY(MLGroupListModel *, model, nullptr)
+
public:
GroupListContextMenu(QObject * parent = nullptr);
+
~GroupListContextMenu() /* override */;
public slots:
void popup(const QModelIndexList & selected, QPoint pos, QVariantMap options = {});
+
+signals:
+ void showMediaInformation(int index);
+
private:
- QMenu* m_menu = nullptr;
+ QMenu * m_menu = nullptr;
};
//-------------------------------------------------------------------------------------------------
=====================================
modules/gui/qt/vlc.qrc
=====================================
@@ -282,14 +282,13 @@
<qresource prefix="/medialibrary">
<file alias="EmptyLabel.qml">medialibrary/qml/EmptyLabel.qml</file>
<file alias="MediaGroupDisplay.qml">medialibrary/qml/MediaGroupDisplay.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>
<file alias="VideoDisplay.qml">medialibrary/qml/VideoDisplay.qml</file>
<file alias="VideoAll.qml">medialibrary/qml/VideoAll.qml</file>
<file alias="VideoAllDisplay.qml">medialibrary/qml/VideoAllDisplay.qml</file>
- <file alias="VideoGroupsDisplay.qml">medialibrary/qml/VideoGroupsDisplay.qml</file>
+ <file alias="VideoAllSubDisplay.qml">medialibrary/qml/VideoAllSubDisplay.qml</file>
<file alias="PlaylistMediaList.qml">medialibrary/qml/PlaylistMediaList.qml</file>
<file alias="PlaylistMedia.qml">medialibrary/qml/PlaylistMedia.qml</file>
<file alias="PlaylistMediaDelegate.qml">medialibrary/qml/PlaylistMediaDelegate.qml</file>
=====================================
modules/gui/qt/widgets/qml/SortControl.qml
=====================================
@@ -15,9 +15,8 @@
* 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 QtQuick.Layouts 1.11
import org.videolan.vlc 0.1
@@ -27,50 +26,105 @@ import "qrc:///widgets/" as Widgets
FocusScope {
id: root
- // when height/width is explicitly set (force size), implicit values will not be used.
- // when height/width is not explicitly set, IconToolButton will set its ...
- // height and width to these implicit counterparts because ...
- // height and width will be set to implicit values when they are not ...
- // explicitly set.
- implicitWidth: button.implicitWidth
- implicitHeight: button.implicitHeight
+ // Properties
property var model: []
+
property string textRole
property string criteriaRole
- // provided for convenience:
- property alias titleRole: root.textRole
- property alias keyRole: root.criteriaRole
property bool popupAbove: false
property real listWidth: VLCStyle.widthSortBox
- property alias focusPolicy: button.focusPolicy
- property alias iconSize: button.size
property VLCColors colors: VLCStyle.colors
+ // NOTE: This allows us provide a custom menu and override sortMenu.
+ property SortMenu menu
+
// properties that should be handled by parent
// if they are not updated, tick mark and order mark will not be shown
property var sortKey: undefined
property var sortOrder: undefined
+ // Private
+
+ property SortMenu _menu: (menu) ? menu
+ : sortMenu
+
+ // Aliases
+
+ property alias focusPolicy: button.focusPolicy
+ property alias iconSize: button.size
+
+ // Signals
+
// sortSelected is triggered with new sorting key when a different sorting key is selected
// sortOrderSelected is triggered with Qt.AscendingOrder when different sorting key is selected
// sortOrderSelected is triggered with Qt.AscendingOrder or Qt.DescendingOrder when the same sorting key is selected
signal sortSelected(int type)
signal sortOrderSelected(int type)
- onVisibleChanged: {
- if (!visible)
- popup.close()
+ // Settings
+
+ // when height/width is explicitly set (force size), implicit values will not be used.
+ // when height/width is not explicitly set, IconToolButton will set its ...
+ // height and width to these implicit counterparts because ...
+ // height and width will be set to implicit values when they are not ...
+ // explicitly set.
+ implicitWidth: button.implicitWidth
+ implicitHeight: button.implicitHeight
+
+ // Events
+
+ onVisibleChanged: if (!visible) _menu.close()
+ onEnabledChanged: if (!enabled) _menu.close()
+
+ // Connections
+
+ Connections {
+ target: (_menu) ? _menu : null
+
+ onSelected: {
+ var selectedSortKey = root.model[index][root.criteriaRole]
+
+ if (root.sortKey !== selectedSortKey) {
+ root.sortSelected(selectedSortKey)
+ root.sortOrderSelected(Qt.AscendingOrder)
+ } else {
+ root.sortOrderSelected(root.sortOrder === Qt.AscendingOrder ? Qt.DescendingOrder
+ : Qt.AscendingOrder)
+ }
+ }
}
- onEnabledChanged: {
- if (!enabled)
- popup.close()
+ // Functions
+
+ function show() {
+ var model = root.model.map(function(modelData) {
+ var checked = modelData[root.criteriaRole] === sortKey
+ var order = checked ? root.sortOrder : undefined
+ return {
+ "text": modelData[root.textRole],
+ "checked": checked,
+ "order": order
+ }
+ })
+
+ var point
+
+ if (root.popupAbove)
+ point = root.mapToGlobal(0, - VLCStyle.margin_xxsmall)
+ else
+ point = root.mapToGlobal(0, root.height + VLCStyle.margin_xxsmall)
+
+ root._menu.popup(point, root.popupAbove, model)
}
+ // Children
+
+ SortMenu { id: sortMenu }
+
Widgets.IconToolButton {
id: button
@@ -80,50 +134,18 @@ FocusScope {
width: root.width
size: VLCStyle.icon_normal
- iconText: VLCIcons.topbar_sort
- text: I18n.qtr("Sort")
focus: true
- onClicked: popup.show()
+ text: I18n.qtr("Sort")
+
+ iconText: VLCIcons.topbar_sort
Navigation.parentItem: root
+
Keys.priority: Keys.AfterItem
Keys.onPressed: Navigation.defaultKeyAction(event)
- }
-
- SortMenu {
- id: popup
-
- function show() {
- var model = root.model.map(function(modelData) {
- var checked = modelData[root.criteriaRole] === sortKey
- var order = checked ? root.sortOrder : undefined
- return {
- "text": modelData[root.textRole],
- "checked": checked,
- "order": order
- }
- })
-
- var point
-
- if (root.popupAbove)
- point = root.mapToGlobal(0, - VLCStyle.margin_xxsmall)
- else
- point = root.mapToGlobal(0, root.height + VLCStyle.margin_xxsmall)
-
- popup.popup(point, root.popupAbove, model)
- }
- onSelected: {
- var selectedSortKey = root.model[index][root.criteriaRole]
- if (root.sortKey !== selectedSortKey) {
- root.sortSelected(selectedSortKey)
- root.sortOrderSelected(Qt.AscendingOrder)
- } else {
- root.sortOrderSelected(root.sortOrder === Qt.AscendingOrder ? Qt.DescendingOrder : Qt.AscendingOrder)
- }
- }
+ onClicked: root.show()
}
}
=====================================
po/POTFILES.in
=====================================
@@ -824,7 +824,6 @@ 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/MediaGroupDisplay.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
@@ -847,7 +846,7 @@ modules/gui/qt/medialibrary/qml/VideoInfoExpandPanel.qml
modules/gui/qt/medialibrary/qml/VideoListDisplay.qml
modules/gui/qt/medialibrary/qml/VideoAll.qml
modules/gui/qt/medialibrary/qml/VideoAllDisplay.qml
-modules/gui/qt/medialibrary/qml/VideoGroupsDisplay.qml
+modules/gui/qt/medialibrary/qml/VideoAllSubDisplay.qml
modules/gui/qt/medialibrary/qml/PlaylistMediaList.qml
modules/gui/qt/medialibrary/qml/PlaylistMedia.qml
modules/gui/qt/medialibrary/qml/PlaylistMediaDelegate.qml
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e663ebb034288f48235d3d06b5466f4197183c81...454b57b76a64516b0f9175909dd9571cd294baf7
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e663ebb034288f48235d3d06b5466f4197183c81...454b57b76a64516b0f9175909dd9571cd294baf7
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list