[vlc-devel] [RFC 75/82] qml: add views to browse music indexed by the medialibrary
Pierre Lamot
pierre at videolabs.io
Fri Feb 1 14:02:19 CET 2019
---
modules/gui/qt/Makefile.am | 9 +
.../gui/qt/qml/mediacenter/ArtistGridView.qml | 61 +++++
.../gui/qt/qml/mediacenter/ArtistListView.qml | 56 ++++
.../qt/qml/mediacenter/ArtistTopBanner.qml | 100 +++++++
.../gui/qt/qml/mediacenter/MCMusicDisplay.qml | 242 ++++++++++++++++
.../qt/qml/mediacenter/MusicAlbumsDisplay.qml | 258 ++++++++++++++++++
.../MusicAlbumsGridExpandDelegate.qml | 226 +++++++++++++++
.../qml/mediacenter/MusicArtistsDisplay.qml | 252 +++++++++++++++++
.../qt/qml/mediacenter/MusicGenresDisplay.qml | 224 +++++++++++++++
.../qml/mediacenter/MusicTrackListDisplay.qml | 54 ++++
.../qt/qml/mediacenter/MusicTracksDisplay.qml | 39 +++
modules/gui/qt/vlc.qrc | 12 +
12 files changed, 1533 insertions(+)
create mode 100644 modules/gui/qt/qml/mediacenter/ArtistGridView.qml
create mode 100644 modules/gui/qt/qml/mediacenter/ArtistListView.qml
create mode 100644 modules/gui/qt/qml/mediacenter/ArtistTopBanner.qml
create mode 100644 modules/gui/qt/qml/mediacenter/MCMusicDisplay.qml
create mode 100644 modules/gui/qt/qml/mediacenter/MusicAlbumsDisplay.qml
create mode 100644 modules/gui/qt/qml/mediacenter/MusicAlbumsGridExpandDelegate.qml
create mode 100644 modules/gui/qt/qml/mediacenter/MusicArtistsDisplay.qml
create mode 100644 modules/gui/qt/qml/mediacenter/MusicGenresDisplay.qml
create mode 100644 modules/gui/qt/qml/mediacenter/MusicTrackListDisplay.qml
create mode 100644 modules/gui/qt/qml/mediacenter/MusicTracksDisplay.qml
diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 1036ee6f68..08e18ba9f3 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -561,6 +561,15 @@ libqt_plugin_la_RES = \
gui/qt/qml/menus/ToolsMenu.qml \
gui/qt/qml/menus/ViewMenu.qml \
gui/qt/qml/menus/VideoMenu.qml \
+ gui/qt/qml/mediacenter/ArtistListView.qml \
+ gui/qt/qml/mediacenter/ArtistTopBanner.qml \
+ gui/qt/qml/mediacenter/MCMusicDisplay.qml \
+ gui/qt/qml/mediacenter/MusicAlbumsDisplay.qml \
+ gui/qt/qml/mediacenter/MusicAlbumsGridExpandDelegate.qml \
+ gui/qt/qml/mediacenter/MusicArtistsDisplay.qml \
+ gui/qt/qml/mediacenter/MusicGenresDisplay.qml \
+ gui/qt/qml/mediacenter/MusicTracksDisplay.qml \
+ gui/qt/qml/mediacenter/MusicTrackListDisplay.qml \
gui/qt/qml/playlist/PlaylistListView.qml \
gui/qt/qml/playlist/PLItem.qml \
gui/qt/qml/playlist/PLItemFooter.qml \
diff --git a/modules/gui/qt/qml/mediacenter/ArtistGridView.qml b/modules/gui/qt/qml/mediacenter/ArtistGridView.qml
new file mode 100644
index 0000000000..b10100e7b6
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/ArtistGridView.qml
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * 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 "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+import org.videolan.medialib 0.1
+
+
+GridView {
+ id: artistGridView
+
+ cellWidth: (VLCStyle.cover_normal) + VLCStyle.margin_small
+ cellHeight: (VLCStyle.cover_normal + VLCStyle.fontHeight_normal) + VLCStyle.margin_small
+ clip: true
+ ScrollBar.vertical: ScrollBar { }
+
+ delegate : Utils.GridItem {
+ id: gridItem
+ width: VLCStyle.cover_normal
+ height: VLCStyle.cover_normal + VLCStyle.fontHeight_normal
+
+ cover: Utils.MultiCoverPreview {
+ albums: MLAlbumModel {
+ ml: medialib
+ parentId: model.id
+ maxItems: 4
+ }
+ }
+ name: model.name || "Unknown Artist"
+
+ onItemClicked: {
+ console.log('Clicked on details : '+model.name);
+ }
+ onPlayClicked: {
+ console.log('Clicked on play : '+model.name);
+ medialib.addAndPlay( model.id )
+ }
+ onAddToPlaylistClicked: {
+ console.log('Clicked on addToPlaylist : '+model.name);
+ medialib.addToPlaylist( model.id );
+ }
+ }
+}
diff --git a/modules/gui/qt/qml/mediacenter/ArtistListView.qml b/modules/gui/qt/qml/mediacenter/ArtistListView.qml
new file mode 100644
index 0000000000..ee0a3d9a6a
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/ArtistListView.qml
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ * 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 "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+ListView {
+ id: artistListView
+ property var onItemClicked
+
+ spacing: 2
+ delegate : Utils.ListItem {
+ height: VLCStyle.icon_normal
+ width: parent.width
+
+ cover: Image {
+ id: cover_obj
+ fillMode: Image.PreserveAspectFit
+ source: model.cover || VLCStyle.noArtCover
+ }
+ line1: model.name || qsTr("Unknown artist")
+
+
+ onItemClicked: {
+ artistListView.onItemClicked( model.id )
+ }
+
+ onPlayClicked: {
+ console.log('Clicked on play : '+model.name);
+ medialib.addAndPlay( model.id )
+ }
+ onAddToPlaylistClicked: {
+ console.log('Clicked on addToPlaylist : '+model.name);
+ medialib.addToPlaylist( model.id );
+ }
+ }
+
+ ScrollBar.vertical: ScrollBar { }
+}
diff --git a/modules/gui/qt/qml/mediacenter/ArtistTopBanner.qml b/modules/gui/qt/qml/mediacenter/ArtistTopBanner.qml
new file mode 100644
index 0000000000..1e48e14eff
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/ArtistTopBanner.qml
@@ -0,0 +1,100 @@
+/*****************************************************************************
+ * 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 QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.0
+
+import org.videolan.medialib 0.1
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+Rectangle {
+ id: root
+ property var artist: null
+ color: VLCStyle.colors.bg
+
+ property int contentY: 0
+ height: VLCStyle.heightBar_xlarge
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: VLCStyle.margin_large
+
+ Image {
+ id: artistImage
+ source: artist.cover || VLCStyle.noArtCover
+
+ Layout.leftMargin: VLCStyle.margin_large
+ Layout.preferredWidth: VLCStyle.cover_small
+ Layout.preferredHeight: VLCStyle.cover_small
+
+ layer.enabled: true
+ layer.effect: OpacityMask {
+ maskSource: Rectangle {
+ width: artistImage.width
+ height: artistImage.height
+ radius: artistImage.width
+ }
+ }
+ }
+
+ Text {
+ id: main_artist
+ text: artist.name
+ Layout.fillWidth: true
+ font.pixelSize: VLCStyle.fontSize_xxxlarge
+ font.bold: true
+ wrapMode: Text.WordWrap
+ maximumLineCount: 2
+ elide: Text.ElideRight
+ color: VLCStyle.colors.text
+ }
+
+ }
+ states: [
+ State {
+ name: "full"
+ PropertyChanges {
+ target: artistImage
+ width: VLCStyle.cover_small
+ height: VLCStyle.cover_small
+ }
+ PropertyChanges {
+ target: main_artist
+ font.pixelSize: VLCStyle.fontSize_xxxlarge
+ }
+ when: contentY < VLCStyle.heightBar_large
+ },
+ State {
+ name: "small"
+ PropertyChanges {
+ target: artistImage
+ width: VLCStyle.icon_normal
+ height: VLCStyle.icon_normal
+ }
+ PropertyChanges {
+ target: main_artist
+ font.pixelSize: VLCStyle.fontSize_large
+ anchors.leftMargin: VLCStyle.margin_small
+ }
+ when: contentY >= VLCStyle.heightBar_large
+ }
+ ]
+}
diff --git a/modules/gui/qt/qml/mediacenter/MCMusicDisplay.qml b/modules/gui/qt/qml/mediacenter/MCMusicDisplay.qml
new file mode 100644
index 0000000000..3c9d9abafc
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/MCMusicDisplay.qml
@@ -0,0 +1,242 @@
+/*****************************************************************************
+ * 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 QtQuick.Layouts 1.3
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+import org.videolan.medialib 0.1
+
+Utils.NavigableFocusScope {
+ id: root
+
+ //name and properties of the tab to be initially loaded
+ property string view: "albums"
+ property var viewProperties: ({})
+
+ Component { id: albumComp; MusicAlbumsDisplay{ } }
+ Component { id: artistComp; MusicArtistsDisplay{ } }
+ Component { id: genresComp; MusicGenresDisplay{ } }
+ Component { id: tracksComp; MusicTrackListDisplay{ } }
+
+ readonly property var pageModel: [{
+ displayText: qsTr("Albums"),
+ name: "albums",
+ component: albumComp
+ }, {
+ displayText: qsTr("Artists"),
+ name: "artists",
+ component: artistComp
+ }, {
+ displayText: qsTr("Genres"),
+ name: "genres" ,
+ component: genresComp
+ }, {
+ displayText: qsTr("Tracks"),
+ name: "tracks" ,
+ component: tracksComp
+ }
+ ]
+
+ property var tabModel: ListModel {
+ Component.onCompleted: {
+ pageModel.forEach(function(e) {
+ append({
+ displayText: e.displayText,
+ name: e.name,
+ selected: (e.name === root.view)
+ })
+ })
+ }
+ }
+
+ ColumnLayout {
+ anchors.fill : parent
+
+ Utils.NavigableFocusScope {
+ id: toobar
+
+ Layout.fillWidth: true
+ Layout.preferredHeight: VLCStyle.icon_normal + VLCStyle.margin_small
+
+ Rectangle {
+ anchors.fill: parent
+ color: VLCStyle.colors.banner
+
+ RowLayout {
+ anchors.fill: parent
+
+ TabBar {
+ id: bar
+
+ focus: true
+
+ Layout.preferredHeight: parent.height - VLCStyle.margin_small
+ Layout.alignment: Qt.AlignVCenter
+
+ background: Rectangle {
+ color: VLCStyle.colors.banner
+ }
+ Component.onCompleted: {
+ bar.contentItem.focus= true
+ }
+
+ /* List of sub-sources for Music */
+ Repeater {
+ id: model_music_id
+
+ model: tabModel
+
+ //Column {
+ TabButton {
+ id: control
+ text: model.displayText
+ font.pixelSize: VLCStyle.fontSize_normal
+ background: Rectangle {
+ color: control.hovered ? VLCStyle.colors.bannerHover : VLCStyle.colors.banner
+ }
+ contentItem: Label {
+ text: control.text
+ font: control.font
+ color: control.hovered ? VLCStyle.colors.textActiveSource : VLCStyle.colors.text
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ Rectangle {
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+ height: 2
+ visible: control.activeFocus || control.checked
+ color: control.activeFocus ? VLCStyle.colors.accent : VLCStyle.colors.bgHover
+ }
+ }
+ onClicked: {
+ stackView.replace(pageModel[index].component)
+ history.push(["mc", "music", model.name ], History.Stay)
+ stackView.focus = true
+ }
+ checked: (model.name === root.view)
+ activeFocusOnTab: true
+ Component.onCompleted: {
+ if (model.selected)
+ bar.currentIndex = index
+ }
+ }
+ }
+
+ KeyNavigation.right: searchBox
+ }
+
+ /* Spacer */
+ Item {
+ Layout.fillWidth: true
+ }
+
+ TextField {
+ Layout.preferredWidth: VLCStyle.widthSearchInput
+ Layout.preferredHeight: parent.height - VLCStyle.margin_small
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
+
+ id: searchBox
+ font.pixelSize: VLCStyle.fontSize_normal
+
+ color: VLCStyle.colors.buttonText
+ placeholderText: qsTr("filter")
+ hoverEnabled: true
+
+ background: Rectangle {
+ radius: 5 //fixme
+ color: VLCStyle.colors.button
+ border.color: {
+ if ( searchBox.text.length < 3 && searchBox.text.length !== 0 )
+ return VLCStyle.colors.alert
+ else if ( searchBox.hovered || searchBox.activeFocus )
+ return VLCStyle.colors.accent
+ else
+ return VLCStyle.colors.buttonBorder
+ }
+ }
+
+ onTextChanged: {
+ stackView.currentItem.model.searchPattern = text;
+ }
+
+ KeyNavigation.right: combo
+ }
+
+ /* Selector to choose a specific sorting operation */
+ Utils.ComboBoxExt {
+ id: combo
+
+ //Layout.fillHeight: true
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
+ Layout.preferredWidth: VLCStyle.widthSortBox
+ Layout.preferredHeight: parent.height - VLCStyle.margin_small
+ textRole: "text"
+ model: stackView.currentItem.sortModel
+ onCurrentIndexChanged: {
+ var sorting = model.get(currentIndex);
+ stackView.currentItem.model.sortCriteria = sorting.criteria
+ }
+ }
+ }
+ }
+
+ onActionLeft: root.actionLeft(index)
+ onActionRight: root.actionRight(index)
+ onActionDown: stackView.focus = true
+ onActionUp: root.actionUp( index )
+ onActionCancel: root.actionCancel( index )
+
+ Keys.priority: Keys.AfterItem
+ Keys.onPressed: {
+ if (!event.accepted)
+ defaultKeyAction(event, 0)
+ }
+ }
+
+ /* The data elements */
+ Utils.StackViewExt {
+ id: stackView
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ focus: true
+
+ Component.onCompleted: {
+ var found = stackView.loadView(root.pageModel, view, viewProperties)
+ if (!found)
+ replace(pageModel[0].component)
+ }
+ }
+
+ Connections {
+ target: stackView.currentItem
+ ignoreUnknownSignals: true
+ onActionLeft: root.actionLeft(index)
+ onActionRight: root.actionRight(index)
+ onActionDown: root.actionDown(index)
+ onActionUp: toobar.focus = true
+ onActionCancel: toobar.focus = true
+ }
+ }
+}
diff --git a/modules/gui/qt/qml/mediacenter/MusicAlbumsDisplay.qml b/modules/gui/qt/qml/mediacenter/MusicAlbumsDisplay.qml
new file mode 100644
index 0000000000..d85da2f9f5
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/MusicAlbumsDisplay.qml
@@ -0,0 +1,258 @@
+/*****************************************************************************
+ * 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 QtQuick.Layouts 1.3
+import QtQml.Models 2.2
+import org.videolan.medialib 0.1
+
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+Utils.NavigableFocusScope {
+ id: root
+
+ property var sortModel: ListModel {
+ ListElement { text: qsTr("Alphabetic"); criteria: "title";}
+ ListElement { text: qsTr("Duration"); criteria: "duration"; }
+ ListElement { text: qsTr("Date"); criteria: "release_year"; }
+ ListElement { text: qsTr("Artist"); criteria: "main_artist"; }
+ }
+
+ property alias model: delegateModel.model
+ property alias parentId: delegateModel.parentId
+ property var currentIndex: view.currentItem.currentIndex
+
+ Utils.SelectableDelegateModel {
+ id: delegateModel
+ property alias parentId: albumModelId.parentId
+
+ model: MLAlbumModel {
+ id: albumModelId
+ ml: medialib
+ }
+
+ delegate: Package {
+ id: element
+
+ Utils.GridItem {
+ Package.name: "gridTop"
+ image: model.cover || VLCStyle.noArtCover
+ title: model.title || qsTr("Unknown title")
+ subtitle: model.main_artist || qsTr("Unknown artist")
+ selected: element.DelegateModel.inSelected || view.currentItem.currentIndex === index
+ shiftX: view.currentItem.shiftX(model.index)
+
+ onItemClicked : {
+ view._switchExpandItem( index )
+ delegateModel.updateSelection( modifier , view.currentItem.currentIndex, index)
+ view.currentItem.currentIndex = index
+ view.currentItem.forceActiveFocus()
+
+ }
+ onPlayClicked: medialib.addAndPlay( model.id )
+ onAddToPlaylistClicked : medialib.addToPlaylist( model.id )
+ }
+
+ Utils.GridItem {
+ Package.name: "gridBottom"
+ image: model.cover || VLCStyle.noArtCover
+ title: model.title || qsTr("Unknown title")
+ subtitle: model.main_artist || qsTr("Unknown artist")
+ selected: element.DelegateModel.inSelected || view.currentItem.currentIndex === index
+ shiftX: view.currentItem.shiftX(model.index)
+
+ onItemClicked : {
+ view._switchExpandItem( index )
+ delegateModel.updateSelection( modifier , view.currentItem.currentIndex, index)
+ view.currentItem.currentIndex = index
+ view.currentItem.forceActiveFocus()
+ }
+ onPlayClicked: medialib.addAndPlay( model.id )
+ onAddToPlaylistClicked : medialib.addToPlaylist( model.id )
+ }
+
+ Utils.ListItem {
+ Package.name: "list"
+ width: root.width
+ height: VLCStyle.icon_normal
+
+ color: VLCStyle.colors.getBgColor(element.DelegateModel.inSelected, this.hovered, this.activeFocus)
+
+ cover: Image {
+ id: cover_obj
+ fillMode: Image.PreserveAspectFit
+ source: model.cover || VLCStyle.noArtCover
+ }
+ line1: (model.title || qsTr("Unknown title"))+" ["+model.duration+"]"
+ line2: model.main_artist || qsTr("Unknown artist")
+
+ onItemClicked : {
+ delegateModel.updateSelection( modifier, view.currentItem.currentIndex, index )
+ view.currentItem.currentIndex = index
+ this.forceActiveFocus()
+ }
+ onPlayClicked: medialib.addAndPlay( model.id )
+ onAddToPlaylistClicked : medialib.addToPlaylist( model.id )
+ }
+ }
+
+ function actionAtIndex(index) {
+ if (delegateModel.selectedGroup.count > 1) {
+ var list = []
+ for (var i = 0; i < delegateModel.selectedGroup.count; i++)
+ list.push(delegateModel.selectedGroup.get(i).model.id)
+ medialib.addAndPlay( list )
+ } else {
+ medialib.addAndPlay( delegateModel.items.get(index).model.id )
+ }
+ }
+ }
+
+ /*
+ *define the intial position/selection
+ * This is done on activeFocus rather than Component.onCompleted because delegateModel.
+ * selectedGroup update itself after this event
+ */
+ onActiveFocusChanged: {
+ if (activeFocus && delegateModel.items.count > 0 && delegateModel.selectedGroup.count === 0) {
+ var initialIndex = 0
+ if (view.currentItem.currentIndex !== -1)
+ initialIndex = view.currentItem.currentIndex
+ delegateModel.items.get(initialIndex).inSelected = true
+ view.currentItem.currentIndex = initialIndex
+ }
+ }
+
+ Component {
+ id: gridComponent
+
+ Utils.ExpandGridView {
+ id: gridView_id
+
+ activeFocusOnTab:true
+
+ cellWidth: VLCStyle.cover_normal + VLCStyle.margin_small
+ cellHeight: VLCStyle.cover_normal + VLCStyle.fontHeight_normal * 2 + VLCStyle.margin_small
+
+ expandDelegate: Rectangle {
+ id: expandDelegateId
+ height: albumDetail.implicitHeight
+ width: root.width
+ color: VLCStyle.colors.bgAlt
+ property int currentId: -1
+ property alias model : albumDetail.model
+
+ MusicAlbumsGridExpandDelegate {
+ id: albumDetail
+ anchors.fill: parent
+ visible: true
+ focus: true
+ model: delegateModel.items.get(gridView_id.expandIndex).model
+ onActionCancel: gridView_id.expandIndex = -1
+ onActionUp: gridView_id.expandIndex = -1
+ onActionDown: gridView_id.expandIndex = -1
+ onActionLeft: root.actionLeft(index)
+ onActionRight: root.actionRight(index)
+ }
+
+ Connections {
+ target: gridView_id
+ onExpandIndexChanged: {
+ if (gridView_id.expandIndex !== -1)
+ {
+ expandDelegateId.model = delegateModel.items.get(gridView_id.expandIndex).model
+ }
+ }
+ }
+ }
+
+ modelTop: delegateModel.parts.gridTop
+ modelBottom: delegateModel.parts.gridBottom
+ modelCount: delegateModel.items.count
+
+ onActionAtIndex: {
+ if (delegateModel.selectedGroup.count === 1) {
+ view._switchExpandItem(index)
+ } else {
+ delegateModel.actionAtIndex(index)
+ }
+ }
+ onSelectAll: delegateModel.selectAll()
+ onSelectionUpdated: delegateModel.updateSelection( keyModifiers, oldIndex, newIndex )
+
+ onActionLeft: root.actionLeft(index)
+ onActionRight: root.actionRight(index)
+ onActionDown: root.actionDown(index)
+ onActionUp: root.actionUp(index)
+ onActionCancel: root.actionCancel(index)
+ }
+ }
+
+ Component {
+ id: listComponent
+ /* ListView */
+ Utils.KeyNavigableListView {
+ id: listView_id
+
+ interactive: root.interactive
+
+ spacing: VLCStyle.margin_xxxsmall
+
+ model: delegateModel.parts.list
+ modelCount: delegateModel.items.count
+
+ onActionAtIndex: delegateModel.actionAtIndex(index)
+ onSelectAll: delegateModel.selectAll()
+ onSelectionUpdated: delegateModel.updateSelection( keyModifiers, oldIndex, newIndex )
+
+ onActionLeft: root.actionLeft(index)
+ onActionRight: root.actionRight(index)
+ onActionDown: root.actionDown(index)
+ onActionUp: root.actionUp(index)
+ onActionCancel: root.actionCancel(index)
+ }
+ }
+
+ Utils.StackViewExt {
+ id: view
+
+ anchors.fill: parent
+ focus: true
+
+ initialItem: medialib.gridView ? gridComponent : listComponent
+
+ Connections {
+ target: medialib
+ onGridViewChanged: {
+ if (medialib.gridView)
+ view.replace(gridComponent)
+ else
+ view.replace(listComponent)
+ }
+ }
+
+ function _switchExpandItem(index) {
+ if (view.currentItem.expandIndex === index)
+ view.currentItem.expandIndex = -1
+ else
+ view.currentItem.expandIndex = index
+ }
+ }
+}
diff --git a/modules/gui/qt/qml/mediacenter/MusicAlbumsGridExpandDelegate.qml b/modules/gui/qt/qml/mediacenter/MusicAlbumsGridExpandDelegate.qml
new file mode 100644
index 0000000000..529fe4957d
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/MusicAlbumsGridExpandDelegate.qml
@@ -0,0 +1,226 @@
+/*****************************************************************************
+ * 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 QtQuick.Layouts 1.3
+
+import org.videolan.medialib 0.1
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+Utils.NavigableFocusScope {
+ id: root
+ property var model: []
+ //color: VLCStyle.colors.bg
+ implicitHeight: layout.height
+
+ Menu {
+ id: moreactions_menu
+ MenuItem {
+ text: qsTr("view artist")
+ onTriggered: console.log("view artist checked")
+ }
+ MenuItem {
+ text: qsTr("view artist")
+ onTriggered: console.log("view artist checked")
+ }
+ MenuItem {
+ text: qsTr("view artist")
+ onTriggered: console.log("view artist checked")
+ }
+ MenuItem {
+ text: qsTr("view artist")
+ onTriggered: console.log("view artist checked")
+ }
+ }
+
+ Row {
+ id: layout
+ spacing: VLCStyle.margin_xsmall
+ width: parent.width
+ height: Math.max(expand_infos_id.height, artAndControl.height)
+
+ FocusScope {
+ id: artAndControl
+ //width: VLCStyle.cover_large + VLCStyle.margin_small * 2
+ //height: VLCStyle.cover_xsmall + VLCStyle.cover_large
+ width: artAndControlLayout.implicitWidth
+ height: artAndControlLayout.implicitHeight
+
+ Column {
+ id: artAndControlLayout
+ anchors.margins: VLCStyle.margin_small
+ spacing: VLCStyle.margin_small
+
+ Item {
+ //dummy item for margins
+ width: parent.width
+ height: 1
+ }
+
+ /* A bigger cover for the album */
+ Image {
+ id: expand_cover_id
+ height: VLCStyle.cover_large
+ width: VLCStyle.cover_large
+ source: model.cover || VLCStyle.noArtCover
+ }
+
+ RowLayout {
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+
+ Utils.IconToolButton {
+ id: addButton
+ focus: true
+
+ Layout.preferredWidth: VLCStyle.icon_normal
+ Layout.preferredHeight: VLCStyle.icon_normal
+ size: VLCStyle.icon_normal
+ Layout.alignment: Qt.AlignHCenter
+
+ text: VLCIcons.add
+
+ onClicked: medialib.addToPlaylist(model.id)
+
+ KeyNavigation.right: playButton
+ }
+ Utils.IconToolButton {
+ id: playButton
+
+ Layout.preferredWidth: VLCStyle.icon_normal
+ Layout.preferredHeight: VLCStyle.icon_normal
+ Layout.alignment: Qt.AlignHCenter
+ size: VLCStyle.icon_normal
+
+ text: VLCIcons.play
+
+ onClicked: medialib.addAndPlay(model.id)
+
+ Keys.onRightPressed: {
+ expand_track_id.focus = true
+ event.accepted = true
+ }
+ }
+ }
+
+ Item {
+ //dummy item for margins
+ width: parent.width
+ height: 1
+ }
+ }
+ }
+
+
+ Column {
+ id: expand_infos_id
+
+ spacing: VLCStyle.margin_xsmall
+ width: root.width - x
+
+ /* The title of the albums */
+ // Needs a rectangle too prevent the tracks from overlapping the title when scrolled
+ Rectangle {
+ id: expand_infos_titleRect_id
+ height: expand_infos_title_id.implicitHeight
+ anchors {
+ left: parent.left
+ right: parent.right
+ topMargin: VLCStyle.margin_small
+ leftMargin: VLCStyle.margin_small
+ rightMargin: VLCStyle.margin_small
+ }
+ color: "transparent"
+ Text {
+ id: expand_infos_title_id
+ text: "<b>"+(model.title || qsTr("Unknown title") )+"</b>"
+ font.pixelSize: VLCStyle.fontSize_xxlarge
+ color: VLCStyle.colors.text
+ }
+ }
+
+ Rectangle {
+ id: expand_infos_subtitleRect_id
+ height: expand_infos_subtitle_id.implicitHeight
+ anchors {
+ left: parent.left
+ right: parent.right
+ topMargin: VLCStyle.margin_xxsmall
+ leftMargin: VLCStyle.margin_small
+ rightMargin: VLCStyle.margin_small
+ }
+
+ color: "transparent"
+ Text {
+ id: expand_infos_subtitle_id
+ text: qsTr("By %1 - %2 - %3")
+ .arg(model.main_artist || qsTr("Unknown title"))
+ .arg(model.release_year || "")
+ .arg(model.duration || "")
+ font.pixelSize: VLCStyle.fontSize_large
+ color: VLCStyle.colors.text
+ }
+ }
+
+ /* The list of the tracks available */
+ MusicTrackListDisplay {
+ id: expand_track_id
+
+ height: expand_track_id.contentHeight
+ anchors {
+ left: parent.left
+ right: parent.right
+ topMargin: VLCStyle.margin_xxsmall
+ leftMargin: VLCStyle.margin_small
+ rightMargin: VLCStyle.margin_small
+ bottomMargin: VLCStyle.margin_small
+ }
+
+ interactive: false
+
+ parentId : root.model.id
+ sortModel: ListModel {
+ ListElement{ criteria: "track_number"; width:0.10; visible: true; text: qsTr("#"); showSection: "" }
+ ListElement{ criteria: "title"; width:0.70; visible: true; text: qsTr("TITLE"); showSection: "" }
+ ListElement{ criteria: "duration"; width:0.20; visible: true; text: qsTr("DURATION"); showSection: "" }
+ }
+ focus: true
+
+ onActionLeft: artAndControl.focus = true
+ onActionRight: root.actionRight(index)
+ onActionUp: root.actionUp(index)
+ onActionDown: root.actionDown(index)
+ onActionCancel: root.actionCancel(index)
+ }
+
+ Item {
+ //dummy item for margins
+ width: parent.width
+ height: 1
+ }
+ }
+ }
+
+
+ Keys.priority: KeyNavigation.AfterItem
+ Keys.onPressed: defaultKeyAction(event, 0)
+}
diff --git a/modules/gui/qt/qml/mediacenter/MusicArtistsDisplay.qml b/modules/gui/qt/qml/mediacenter/MusicArtistsDisplay.qml
new file mode 100644
index 0000000000..9b16d7c9c5
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/MusicArtistsDisplay.qml
@@ -0,0 +1,252 @@
+/*****************************************************************************
+ * 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.Controls 2.4
+import QtQuick 2.11
+import QtQml.Models 2.2
+import QtQuick.Layouts 1.3
+
+import org.videolan.medialib 0.1
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+Utils.NavigableFocusScope {
+ id: root
+ property alias model: delegateModel.model
+ property var sortModel: ListModel {
+ ListElement { text: qsTr("Alphabetic"); criteria: "title" }
+ }
+
+ property int currentArtistIndex: -1
+ onCurrentArtistIndexChanged: {
+ if (currentArtistIndex == -1)
+ view.replace(artistGridComponent)
+ else
+ view.replace(albumComponent)
+ }
+ property var artistId: null
+
+ Utils.SelectableDelegateModel {
+ id: delegateModel
+ model: MLArtistModel {
+ ml: medialib
+ }
+ delegate: Package {
+ id: element
+ Utils.ListItem {
+ Package.name: "list"
+ height: VLCStyle.icon_normal
+ width: parent.width
+
+ color: VLCStyle.colors.getBgColor(element.DelegateModel.inSelected, this.hovered, this.activeFocus)
+
+ cover: Image {
+ id: cover_obj
+ fillMode: Image.PreserveAspectFit
+ source: model.cover || VLCStyle.noArtCover
+ }
+ line1: model.name || qsTr("Unknown artist")
+
+ onItemClicked: {
+ currentArtistIndex = index
+ artistId = model.id
+ delegateModel.updateSelection( modifier , artistList.currentIndex, index)
+ artistList.currentIndex = index
+ artistList.forceActiveFocus()
+ }
+
+ onItemDoubleClicked: {
+ delegateModel.actionAtIndex(index)
+ }
+
+ onPlayClicked: {
+ console.log('Clicked on play : '+model.name);
+ medialib.addAndPlay( model.id )
+ }
+ onAddToPlaylistClicked: {
+ console.log('Clicked on addToPlaylist : '+model.name);
+ medialib.addToPlaylist( model.id );
+ }
+ }
+
+ Utils.GridItem {
+ Package.name: "grid"
+ id: gridItem
+
+ image: VLCStyle.noArtCover
+ title: model.name || "Unknown Artist"
+ selected: element.DelegateModel.inSelected
+
+ //shiftX: view.currentItem.shiftX(index)
+
+ onItemClicked: {
+ delegateModel.updateSelection( modifier , artistList.currentIndex, index)
+ artistList.currentIndex = index
+ artistList.forceActiveFocus()
+ }
+
+ onItemDoubleClicked: {
+ delegateModel.actionAtIndex(index)
+ }
+
+ onPlayClicked: {
+ medialib.addAndPlay( model.id )
+ }
+ onAddToPlaylistClicked: {
+ console.log('Clicked on addToPlaylist : '+model.name);
+ medialib.addToPlaylist( model.id );
+ }
+
+ //replace image with a mutlicovers preview
+ Utils.MultiCoverPreview {
+ id: multicover
+ visible: false
+ width: VLCStyle.cover_normal
+ height: VLCStyle.cover_normal
+
+ albums: MLAlbumModel {
+ ml: medialib
+ parentId: model.id
+ maxItems: 4
+ }
+ }
+ Component.onCompleted: {
+ multicover.grabToImage(function(result) {
+ gridItem.image = result.url
+ //multicover.destroy()
+ })
+ }
+ }
+ }
+
+ function actionAtIndex(index) {
+ console.log("actionAtIndex", index)
+ if (delegateModel.selectedGroup.count > 1) {
+ var list = []
+ for (var i = 0; i < delegateModel.selectedGroup.count; i++)
+ list.push(delegateModel.selectedGroup.get(i).model.id)
+ medialib.addAndPlay( list )
+ } else if (delegateModel.selectedGroup.count === 1) {
+ root.artistId = delegateModel.selectedGroup.get(0).model.id
+ root.currentArtistIndex = index
+ artistList.currentIndex = index
+ }
+ }
+ }
+
+ /*
+ *define the intial position/selection
+ * This is done on activeFocus rather than Component.onCompleted because delegateModel.
+ * selectedGroup update itself after this event
+ */
+ onActiveFocusChanged: {
+ if (activeFocus && delegateModel.items.count > 0 && delegateModel.selectedGroup.count === 0) {
+ var initialIndex = 0
+ if (view.currentItem.currentIndex !== -1)
+ initialIndex = view.currentItem.currentIndex
+ delegateModel.items.get(initialIndex).inSelected = true
+ view.currentItem.currentIndex = initialIndex
+ }
+ }
+
+ Component {
+ id: artistGridComponent
+ Utils.KeyNavigableGridView {
+ cellWidth: (VLCStyle.cover_normal) + VLCStyle.margin_small
+ cellHeight: (VLCStyle.cover_normal + VLCStyle.fontHeight_normal) + VLCStyle.margin_small
+
+ model: delegateModel.parts.grid
+ modelCount: delegateModel.items.count
+
+ onSelectAll: delegateModel.selectAll()
+ onActionAtIndex: delegateModel.actionAtIndex(index)
+ onSelectionUpdated: delegateModel.updateSelection( keyModifiers, oldIndex, newIndex )
+
+ onActionLeft: artistList.focus = true
+ onActionRight: root.actionRight(index)
+ onActionUp: root.actionUp(index)
+ onActionDown: root.actionDown(index)
+ onActionCancel: root.actionCancel(index)
+ }
+ }
+
+ Component {
+ id: albumComponent
+ // Display selected artist albums
+
+ FocusScope {
+ property alias currentIndex: albumSubView.currentIndex
+ ColumnLayout {
+ anchors.fill: parent
+ ArtistTopBanner {
+ id: artistBanner
+ Layout.fillWidth: true
+ focus: false
+ //contentY: albumsView.contentY
+ contentY: 0
+ artist: delegateModel.items.get(currentArtistIndex).model
+ }
+ MusicAlbumsDisplay {
+ id: albumSubView
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ focus: true
+ parentId: artistId
+ onActionLeft: artistList.focus = true
+
+ onActionRight: root.actionRight(index)
+ onActionUp: root.actionUp(index)
+ onActionDown: root.actionDown(index)
+ onActionCancel: root.actionCancel(index)
+ }
+ }
+ }
+ }
+
+ Row {
+ anchors.fill: parent
+ Utils.KeyNavigableListView {
+ width: parent.width * 0.25
+ height: parent.height
+
+ id: artistList
+ spacing: 2
+ model: delegateModel.parts.list
+ modelCount: delegateModel.items.count
+
+ onSelectAll: delegateModel.selectAll()
+ onSelectionUpdated: delegateModel.updateSelection( keyModifiers, oldIndex, newIndex )
+ onActionAtIndex: delegateModel.actionAtIndex(index)
+
+ onActionRight: view.focus = true
+ onActionLeft: root.actionLeft(index)
+ onActionUp: root.actionUp(index)
+ onActionDown: root.actionDown(index)
+ onActionCancel: root.actionCancel(index)
+ }
+
+ Utils.StackViewExt {
+ id: view
+ width: parent.width * 0.75
+ height: parent.height
+ focus: true
+
+ initialItem: artistGridComponent
+ }
+ }
+}
diff --git a/modules/gui/qt/qml/mediacenter/MusicGenresDisplay.qml b/modules/gui/qt/qml/mediacenter/MusicGenresDisplay.qml
new file mode 100644
index 0000000000..9ae1957b0a
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/MusicGenresDisplay.qml
@@ -0,0 +1,224 @@
+/*****************************************************************************
+ * 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.vlc 0.1
+import org.videolan.medialib 0.1
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+Utils.NavigableFocusScope {
+ id: root
+ property alias model: delegateModel.model
+ property var sortModel: ListModel {
+ ListElement { text: qsTr("Alphabetic"); criteria: "title" }
+ }
+
+ function goToView( parent ) {
+ history.push([ "mc", "music", "albums", { parentId: parent } ], History.Go)
+ }
+
+ Utils.SelectableDelegateModel {
+ id: delegateModel
+ model: MLGenreModel {
+ ml: medialib
+ }
+
+ delegate: Package {
+ id: element
+ Utils.GridItem {
+ Package.name: "grid"
+ id: gridItem
+ image: VLCStyle.noArtCover
+ title: model.name || "Unknown genre"
+ selected: element.DelegateModel.inSelected
+
+ shiftX: view.currentItem.shiftX(model.index)
+
+ onItemClicked: {
+ delegateModel.updateSelection( modifier , view.currentItem.currentIndex, index)
+ view.currentItem.currentIndex = index
+ view.currentItem.forceActiveFocus()
+ }
+ onPlayClicked: {
+ medialib.addAndPlay( model.id )
+ }
+ onItemDoubleClicked: {
+ history.push(["mc", "music", "albums", { parentId: model.id } ], History.Go)
+ }
+ onAddToPlaylistClicked: {
+ medialib.addToPlaylist( model.id );
+ }
+
+ //replace image with a mutlicovers preview
+ Utils.MultiCoverPreview {
+ id: multicover
+ visible: false
+ width: VLCStyle.cover_normal
+ height: VLCStyle.cover_normal
+
+ albums: MLAlbumModel {
+ ml: medialib
+ parentId: model.id
+ }
+ }
+
+ Component.onCompleted: {
+ multicover.grabToImage(function(result) {
+ gridItem.image = result.url
+ //multicover.destroy()
+ })
+ }
+ }
+
+ Utils.ListItem {
+ Package.name: "list"
+ width: root.width
+ height: VLCStyle.icon_normal
+
+ color: VLCStyle.colors.getBgColor(element.DelegateModel.inSelected, this.hovered, this.activeFocus)
+
+ cover: Utils.MultiCoverPreview {
+ albums: MLAlbumModel {
+ ml: medialib
+ parentId: model.id
+ }
+ }
+
+ line1: (model.name || "Unknown genre")+" - "+model.nb_tracks+" tracks"
+
+ onItemClicked: {
+ console.log("Clicked on : "+model.name);
+ delegateModel.updateSelection( modifier, view.currentItem.currentIndex, index )
+ view.currentItem.currentIndex = index
+ this.forceActiveFocus()
+ }
+ onPlayClicked: {
+ console.log('Clicked on play : '+model.name);
+ medialib.addAndPlay( model.id )
+ }
+ onItemDoubleClicked: {
+ history.push([ "mc", "music", "albums", { parentId: model.id } ], History.Go)
+ }
+ onAddToPlaylistClicked: {
+ console.log('Clicked on addToPlaylist : '+model.name);
+ medialib.addToPlaylist( model.id );
+ }
+ }
+ }
+
+ function actionAtIndex(index) {
+ if (delegateModel.selectedGroup.count > 1) {
+ var list = []
+ for (var i = 0; i < delegateModel.selectedGroup.count; i++)
+ list.push(delegateModel.selectedGroup.get(i).model.id)
+ medialib.addAndPlay( list )
+ } else if (delegateModel.selectedGroup.count === 1) {
+ goToView(delegateModel.selectedGroup.get(0).model.id)
+ }
+ }
+ }
+
+ /*
+ *define the intial position/selection
+ * This is done on activeFocus rather than Component.onCompleted because delegateModel.
+ * selectedGroup update itself after this event
+ */
+ onActiveFocusChanged: {
+ if (activeFocus && delegateModel.items.count > 0 && delegateModel.selectedGroup.count === 0) {
+ var initialIndex = 0
+ if (view.currentItem.currentIndex !== -1)
+ initialIndex = view.currentItem.currentIndex
+ delegateModel.items.get(initialIndex).inSelected = true
+ view.currentItem.currentIndex = initialIndex
+ }
+ }
+
+ /* Grid View */
+ Component {
+ id: gridComponent
+ Utils.KeyNavigableGridView {
+ id: gridView_id
+
+ model: delegateModel.parts.grid
+ modelCount: delegateModel.items.count
+
+ focus: true
+
+ cellWidth: (VLCStyle.cover_normal) + VLCStyle.margin_small
+ cellHeight: (VLCStyle.cover_normal + VLCStyle.fontHeight_normal) + VLCStyle.margin_small
+
+ onSelectAll: delegateModel.selectAll()
+ onSelectionUpdated: delegateModel.updateSelection( keyModifiers, oldIndex, newIndex )
+ onActionAtIndex: delegateModel.actionAtIndex(index)
+
+ onActionLeft: root.actionLeft(index)
+ onActionRight: root.actionRight(index)
+ onActionUp: root.actionUp(index)
+ onActionDown: root.actionDown(index)
+ onActionCancel: root.actionCancel(index)
+ }
+ }
+
+
+ Component {
+ id: listComponent
+ /* List View */
+ Utils.KeyNavigableListView {
+ id: listView_id
+
+ model: delegateModel.parts.list
+ modelCount: delegateModel.items.count
+
+ focus: true
+ spacing: VLCStyle.margin_xxxsmall
+
+ onSelectAll: delegateModel.selectAll()
+ onSelectionUpdated: delegateModel.updateSelection( keyModifiers, oldIndex, newIndex )
+ onActionAtIndex: delegateModel.actionAtIndex(index)
+
+ onActionLeft: root.actionLeft(index)
+ onActionRight: root.actionRight(index)
+ onActionUp: root.actionUp(index)
+ onActionDown: root.actionDown(index)
+ onActionCancel: root.actionCancel(index)
+ }
+ }
+
+
+ Utils.StackViewExt {
+ id: view
+
+ anchors.fill: parent
+ focus: true
+
+ initialItem: medialib.gridView ? gridComponent : listComponent
+
+ Connections {
+ target: medialib
+ onGridViewChanged: {
+ if (medialib.gridView)
+ view.replace(gridComponent)
+ else
+ view.replace(listComponent)
+ }
+ }
+ }
+}
diff --git a/modules/gui/qt/qml/mediacenter/MusicTrackListDisplay.qml b/modules/gui/qt/qml/mediacenter/MusicTrackListDisplay.qml
new file mode 100644
index 0000000000..435af625ac
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/MusicTrackListDisplay.qml
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ * 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 QtQuick.Layouts 1.3
+
+import org.videolan.medialib 0.1
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+Utils.KeyNavigableTableView {
+ id: root
+
+ sortModel: ListModel {
+ ListElement{ criteria: "track_number";width:0.15; text: qsTr("TRACK NB"); showSection: "" }
+ ListElement{ criteria: "disc_number"; width:0.15; text: qsTr("DISC NB"); showSection: "" }
+ ListElement{ criteria: "title"; width:0.15; text: qsTr("TITLE"); showSection: "title" }
+ ListElement{ criteria: "main_artist"; width:0.15; text: qsTr("ARTIST"); showSection: "main_artist" }
+ ListElement{ criteria: "album_title"; width:0.15; text: qsTr("ALBUM"); showSection: "album_title" }
+ ListElement{ criteria: "duration"; width:0.15; text: qsTr("DURATION"); showSection: "" }
+ }
+
+ model: MLAlbumTrackModel {
+ id: rootmodel
+ ml: medialib
+ }
+
+ property alias parentId: rootmodel.parentId
+
+ onActionForSelection: {
+ var list = []
+ for (var i = 0; i < selection.count; i++ ) {
+ list.push(selection.get(i).model.id)
+ }
+ medialib.addAndPlay(list)
+ }
+}
diff --git a/modules/gui/qt/qml/mediacenter/MusicTracksDisplay.qml b/modules/gui/qt/qml/mediacenter/MusicTracksDisplay.qml
new file mode 100644
index 0000000000..bee67e240a
--- /dev/null
+++ b/modules/gui/qt/qml/mediacenter/MusicTracksDisplay.qml
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * 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 org.videolan.medialib 0.1
+
+import "qrc:///utils/" as Utils
+import "qrc:///style/"
+
+Loader {
+ id: viewLoader
+ property var model: null
+
+ sourceComponent: listViewComponent_id
+
+ /* List View */
+ Component {
+ id: listViewComponent_id
+ MusicTrackListDisplay {
+ id: tracklistdisplay_id
+ model: viewLoader.model
+ }
+ }
+}
diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc
index 0255e1ee79..889409b498 100644
--- a/modules/gui/qt/vlc.qrc
+++ b/modules/gui/qt/vlc.qrc
@@ -179,6 +179,18 @@
<file alias="MenuItemExt.qml">qml/utils/MenuItemExt.qml</file>
<file alias="ExpandGridView.qml">qml/utils/ExpandGridView.qml</file>
</qresource>
+ <qresource prefix="/mediacenter">
+ <file alias="MCMusicDisplay.qml">qml/mediacenter/MCMusicDisplay.qml</file>
+ <file alias="MusicAlbumsDisplay.qml">qml/mediacenter/MusicAlbumsDisplay.qml</file>
+ <file alias="MusicAlbumsGridExpandDelegate.qml">qml/mediacenter/MusicAlbumsGridExpandDelegate.qml</file>
+ <file alias="MusicArtistsDisplay.qml">qml/mediacenter/MusicArtistsDisplay.qml</file>
+ <file alias="MusicGenresDisplay.qml">qml/mediacenter/MusicGenresDisplay.qml</file>
+ <file alias="MusicTracksDisplay.qml">qml/mediacenter/MusicTracksDisplay.qml</file>
+ <file alias="ArtistGridView.qml">qml/mediacenter/ArtistGridView.qml</file>
+ <file alias="ArtistListView.qml">qml/mediacenter/ArtistListView.qml</file>
+ <file alias="MusicTrackListDisplay.qml">qml/mediacenter/MusicTrackListDisplay.qml</file>
+ <file alias="ArtistTopBanner.qml">qml/mediacenter/ArtistTopBanner.qml</file>
+ </qresource>
<qresource prefix="/style">
<file alias="qmldir">qml/style/qmldir</file>
<file alias="VLCStyle.qml">qml/style/VLCStyle.qml</file>
--
2.19.1
More information about the vlc-devel
mailing list