[vlc-commits] [Git][videolan/vlc][master] qml: keep playlist visibility across the application

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Thu Apr 28 12:06:12 UTC 2022



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
63854be2 by Pierre Lamot at 2022-04-28T11:37:22+00:00
qml: keep playlist visibility across the application

this allow to keep the playlist visible when switching between the player and
the medialibrary views, regarding the different parameters (playlist docked,
playlist visible, video embed)

this uses a hierarchical state machine to track the different states and
transitions.

- - - - -


5 changed files:

- modules/gui/qt/Makefile.am
- modules/gui/qt/player/qml/Player.qml
- + modules/gui/qt/player/qml/PlayerPlaylistVisiblityFSM.qml
- modules/gui/qt/player/qml/TopBar.qml
- modules/gui/qt/vlc.qrc


Changes:

=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -814,6 +814,7 @@ libqt_plugin_la_QML = \
 	gui/qt/player/qml/PlayerControlLayout.qml \
 	gui/qt/player/qml/PlayerMenu.qml \
 	gui/qt/player/qml/PlayerMenuItem.qml \
+	gui/qt/player/qml/PlayerPlaylistVisiblityFSM.qml \
 	gui/qt/player/qml/ResumeDialog.qml \
 	gui/qt/player/qml/SliderBar.qml \
 	gui/qt/player/qml/TopBar.qml \


=====================================
modules/gui/qt/player/qml/Player.qml
=====================================
@@ -118,6 +118,29 @@ FocusScope {
         }
     }
 
+    PlayerPlaylistVisiblityFSM {
+        id: playlistVisibility
+
+        onShowPlaylist: {
+            rootPlayer.lockUnlockAutoHide(true, playlistVisibility)
+            MainCtx.playlistVisible = true
+        }
+
+        onHidePlaylist: {
+            rootPlayer.lockUnlockAutoHide(false, playlistVisibility)
+            MainCtx.playlistVisible = false
+        }
+    }
+
+    Connections {
+        target: MainCtx
+
+        //playlist
+        onPlaylistDockedChanged: playlistVisibility.updatePlaylistDocked()
+        onPlaylistVisibleChanged: playlistVisibility.updatePlaylistVisible()
+        onHasEmbededVideoChanged: playlistVisibility.updateVideoEmbed()
+    }
+
     VideoSurface {
         id: videoSurface
 
@@ -354,12 +377,7 @@ FocusScope {
                 Navigation.parentItem: rootPlayer
                 Navigation.downItem: playlistpopup.showPlaylist ? playlistpopup : (audioControls.visible ? audioControls : controlBarView)
 
-                onTooglePlaylistVisibility: {
-                    if (MainCtx.playlistDocked)
-                        playlistpopup.showPlaylist = !playlistpopup.showPlaylist
-                    else
-                        MainCtx.playlistVisible = !MainCtx.playlistVisible
-                }
+                onTogglePlaylistVisibility: playlistVisibility.togglePlaylistVisibility()
 
                 onRequestLockUnlockAutoHide: {
                     rootPlayer.lockUnlockAutoHide(lock, source)
@@ -576,7 +594,7 @@ FocusScope {
         }
         focus: false
         edge: Widgets.DrawerExt.Edges.Right
-        state: showPlaylist && MainCtx.playlistDocked ? "visible" : "hidden"
+        state: playlistVisibility.isPlaylistVisible ? "visible" : "hidden"
         component: Rectangle {
             color: rootPlayer.colors.setColorAlpha(rootPlayer.colors.topBanner, 0.8)
             width: (rootPlayer.width + playlistView.rightPadding) / 4
@@ -599,7 +617,7 @@ FocusScope {
                 Navigation.cancelAction: closePlaylist
 
                 function closePlaylist() {
-                    playlistpopup.showPlaylist = false
+                    playlistVisibility.togglePlaylistVisibility()
                     if (audioControls.visible)
                         audioControls.forceActiveFocus()
                     else


=====================================
modules/gui/qt/player/qml/PlayerPlaylistVisiblityFSM.qml
=====================================
@@ -0,0 +1,230 @@
+/*****************************************************************************
+ * Copyright (C) 2022 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.0
+import org.videolan.vlc 0.1
+
+/**
+ * playlist visibility state machine
+ *
+ * @startuml
+ * state Floating {
+ * }
+ * state Docked {
+ *   state FollowVisible {
+ *      state Visible {
+ *      }
+ *      state Hidden {
+ *      }
+ *   }
+ *   state ForceHidden {
+ *   }
+ * }
+ * @enduml
+ *
+ */
+Item {
+    id: fsm
+
+    //incoming signals
+    signal togglePlaylistVisibility()
+    signal updatePlaylistVisible()
+    signal updatePlaylistDocked()
+    signal updateVideoEmbed()
+
+    //outcoming signals
+    signal showPlaylist()
+    signal hidePlaylist()
+
+    //exposed internal states
+    property alias isPlaylistVisible: fsmVisible.enabled
+
+    property var _substate: undefined
+
+    function setState(state, substate) {
+        //callLater is used to avoid Connections on a signal to be immediatly
+        //re-trigered on the new state
+        Qt.callLater(function() {
+            if (state._substate === substate)
+                return;
+
+            if (state._substate !== undefined) {
+                if (state._substate.exited) {
+                    state._substate.exited()
+                }
+                state._substate.enabled = false
+            }
+
+            state._substate = substate
+
+            if (state._substate !== undefined) {
+                state._substate.enabled = true
+                if (state._substate.entered) {
+                    state._substate.entered()
+                }
+            }
+        })
+    }
+
+    //initial state
+    Component.onCompleted: {
+        if (MainCtx.playlistDocked)
+            fsm.setState(fsm, fsmDocked)
+        else
+            fsm.setState(fsm, fsmFloating)
+    }
+
+    Item {
+        id: fsmFloating
+        enabled: false
+
+        Connections {
+            target: fsm
+            //explicitly bind on parent enabled, as Connections doens't behave as Item
+            //regarding enabled propagation on children, ditto bellow
+            enabled: fsmFloating.enabled
+
+            onTogglePlaylistVisibility: {
+                MainCtx.playlistVisible = !MainCtx.playlistVisible
+            }
+
+            onUpdatePlaylistDocked: {
+                if (MainCtx.playlistDocked) {
+                    fsm.setState(fsm, fsmDocked)
+                }
+            }
+        }
+    }
+
+    Item {
+        id: fsmDocked
+        enabled: false
+
+        property var _substate: undefined
+
+        function entered() {
+            if(MainCtx.hasEmbededVideo) {
+                fsm.setState(fsmDocked, fsmForceHidden)
+            } else {
+                fsm.setState(fsmDocked, fsmFollowVisible)
+            }
+        }
+
+        function exited() {
+            fsm.setState(fsmDocked, undefined)
+        }
+
+        Item {
+            id: fsmFollowVisible
+            enabled: false
+
+            property var _substate: undefined
+
+            function entered() {
+                if(MainCtx.playlistVisible)
+                    fsm.setState(this, fsmVisible)
+                else
+                    fsm.setState(this, fsmHidden)
+            }
+
+            function exited() {
+                fsm.setState(this, undefined)
+            }
+
+            Connections {
+                target: fsm
+                enabled: fsmFollowVisible.enabled
+
+                onUpdatePlaylistDocked: {
+                    if (!MainCtx.playlistDocked) {
+                        fsm.setState(fsm, fsmFloating)
+                    }
+                }
+
+                onUpdateVideoEmbed: {
+                    if (MainCtx.hasEmbededVideo) {
+                        fsm.setState(fsmDocked, fsmForceHidden)
+                    }
+                }
+            }
+
+            Item {
+                id: fsmVisible
+                enabled: false
+
+                function entered() {
+                    fsm.showPlaylist()
+                }
+
+                function exited() {
+                    fsm.hidePlaylist()
+                }
+
+                Connections {
+                    target: fsm
+                    enabled: fsmVisible.enabled
+
+                    onUpdatePlaylistVisible: {
+                        if (!MainCtx.playlistVisible)
+                            fsm.setState(fsmFollowVisible, fsmHidden)
+                    }
+
+                    onTogglePlaylistVisibility: fsm.setState(fsmFollowVisible, fsmHidden)
+                }
+            }
+
+            Item {
+                id: fsmHidden
+                enabled: false
+
+                Connections {
+                    target: fsm
+                    enabled: fsmHidden.enabled
+
+                    onUpdatePlaylistVisible: {
+                        if (MainCtx.playlistVisible)
+                            fsm.setState(fsmFollowVisible, fsmVisible)
+                    }
+
+                    onTogglePlaylistVisibility: fsm.setState(fsmFollowVisible, fsmVisible)
+                }
+            }
+
+        }
+
+        Item {
+            id: fsmForceHidden
+            enabled: false
+
+            Connections {
+                target: fsm
+                enabled: fsmForceHidden.enabled
+
+                onUpdateVideoEmbed: {
+                    if (!MainCtx.hasEmbededVideo) {
+                        fsm.setState(fsmDocked, fsmFollowVisible)
+                    }
+                }
+
+                onTogglePlaylistVisibility: {
+                    MainCtx.playlistVisible = true
+                    fsm.setState(fsmDocked, fsmFollowVisible)
+                }
+            }
+        }
+    }
+}


=====================================
modules/gui/qt/player/qml/TopBar.qml
=====================================
@@ -40,7 +40,7 @@ FocusScope{
     property int groupAlignment: TopBar.GroupAlignment.Vertical
     property Item _currentTitleText: null
 
-    signal tooglePlaylistVisibility()
+    signal togglePlaylistVisibility()
     signal requestLockUnlockAutoHide(bool lock, var source)
 
     implicitHeight: topcontrollerMouseArea.implicitHeight
@@ -284,7 +284,7 @@ FocusScope{
 
             Navigation.parentItem: topFocusScope
             Navigation.leftItem: menuSelector
-            onClicked: tooglePlaylistVisibility()
+            onClicked: togglePlaylistVisibility()
         }
     }
 }


=====================================
modules/gui/qt/vlc.qrc
=====================================
@@ -354,6 +354,7 @@
         <file alias="LanguageMenu.qml">player/qml/LanguageMenu.qml</file>
         <file alias="ControlLayout.qml">player/qml/ControlLayout.qml</file>
         <file alias="PlaybackSpeed.qml">player/qml/PlaybackSpeed.qml</file>
+        <file alias="PlayerPlaylistVisiblityFSM.qml">player/qml/PlayerPlaylistVisiblityFSM.qml</file>
     </qresource>
     <qresource prefix="/player/controlbarcontrols">
         <file alias="HighResolutionTimeWidget.qml">player/qml/controlbarcontrols/HighResolutionTimeWidget.qml</file>



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/63854be249954d23c804b116a3df39c50bcf4ac2

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/63854be249954d23c804b116a3df39c50bcf4ac2
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list