[vlc-commits] [Git][videolan/vlc][master] 18 commits: qt: make `UpdateModelPrivate::m_release` pointer to constant

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Sat May 30 15:09:57 UTC 2026



Felix Paul Kühne pushed to branch master at VideoLAN / VLC


Commits:
1d5f27ac by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: make `UpdateModelPrivate::m_release` pointer to constant

- - - - -
a6cc6470 by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: introduce `UPDATE_MOCK` in `help.cpp`

This is only used for debugging purposes.

- - - - -
90ac31d3 by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: add `UpdateModel::download(void)`

It does not make sense to have this in the
dialog code, so it is moved now.

- - - - -
6c507a24 by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: add `UpdateModel::resetStatus()`

- - - - -
e60160ee by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: add `UpdateModel::Status::Downloading`

This is currently not plugged to anything, introduced
because QML side is ready to respect it.

- - - - -
1bc35b6c by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: add `progress` property to `UpdateModel`

This is currently not plugged to anything, introduced
because QML side is ready to respect it.

- - - - -
2a5df657 by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: call check update directly with check for updates action

... in the help menu.

- - - - -
a102f54d by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: introduce `ProgressBarExt.qml`

Directly copied from `ScanProgressBar.qml`,
which is not a generic type.

- - - - -
4023c51e by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qml: derive `ScanProgressBar` from `ProgressBarExt`

- - - - -
44704b9c by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: move `ScanProgressBar.qml` from `widgets` to `medialibrary`

As a de facto rule, qml files that import the media library
module `VLC.MediaLibrary` are placed under the `medialibrary`
directory.

- - - - -
dc35967e by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: register qml singleton instance `UpdateModel`

- - - - -
3648d9c0 by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: introduce icon `ic_fluent_arrow_download_24_regular`

Taken from Microsoft Fluent System Icons, subject to
MIT license (see pixmaps/LICENCE)

- - - - -
b91c1bf8 by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: introduce icon `ic_fluent_arrow_sync_24_regular`

Taken from Microsoft Fluent System Icons, subject to
MIT license (see pixmaps/LICENCE)

- - - - -
675e0a2f by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: regenerate `VLCIcons.ttf`

- - - - -
de36970a by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qml: introduce `UpdatePane`

A modern alternative to the archaic update dialog.

We do not intend to remove the old update dialog,
at least for now, since it is triggered with
`INTF_DIALOG_UPDATEVLC`.

- - - - -
3e39718f by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qml: use `UpdatePane` in `MainDisplay`

Placed above the mini player (and media
library scan pane, if visible).

- - - - -
68548e5b by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: do not trigger old update dialog if modern update pane is available at start

There is a fallback mechanism to the old dialog if -for any reason- the
new update pane is not available.

- - - - -
1ee9c413 by Fatih Uzunoglu at 2026-05-30T16:32:39+02:00
qt: make the connection for update status changed at appropriate time in `MainCtx`

Not only this gets rid of the custom single shot connection, but also makes it
possible to fallback to the old dialog at all times (such as update check
triggered through the menus) in case the modern update pane is not available.

- - - - -


20 changed files:

- modules/gui/qt/Makefile.am
- modules/gui/qt/assets.qrc
- modules/gui/qt/dialogs/help/help.cpp
- modules/gui/qt/dialogs/help/help.hpp
- modules/gui/qt/maininterface/mainctx.cpp
- modules/gui/qt/maininterface/mainui.cpp
- modules/gui/qt/maininterface/qml/MainDisplay.qml
- + modules/gui/qt/maininterface/qml/UpdatePane.qml
- + modules/gui/qt/medialibrary/qml/ScanProgressBar.qml
- modules/gui/qt/menus/menus.cpp
- modules/gui/qt/menus/menus.hpp
- modules/gui/qt/menus/qml_menu_wrapper.cpp
- modules/gui/qt/meson.build
- modules/gui/qt/pixmaps/VLCIcons.json
- modules/gui/qt/pixmaps/VLCIcons.ttf
- + modules/gui/qt/pixmaps/icons/ic_fluent_arrow_download_24_regular.svg
- + modules/gui/qt/pixmaps/icons/ic_fluent_arrow_sync_24_regular.svg
- modules/gui/qt/style/VLCIcons.qml
- modules/gui/qt/widgets/qml/ScanProgressBar.qml → modules/gui/qt/widgets/qml/ProgressBarExt.qml
- po/POTFILES.in


Changes:

=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -879,6 +879,8 @@ libqt_plugin_la_RES = \
 	pixmaps/icons/window_maximize.svg \
 	pixmaps/icons/window_minimize.svg \
 	pixmaps/icons/window_restore.svg \
+	pixmaps/icons/ic_fluent_arrow_download_24_regular.svg \
+	pixmaps/icons/ic_fluent_arrow_sync_24_regular.svg \
 	pixmaps/menu/add.svg \
 	pixmaps/menu/capture-card.svg \
 	pixmaps/menu/clear.svg \
@@ -1020,6 +1022,11 @@ libqml_module_maininterface_a_QML = \
 	maininterface/qml/MainViewLoader.qml \
 	maininterface/qml/MainDisplay.qml \
 	maininterface/qml/NoMedialibHome.qml
+
+if UPDATE_CHECK
+libqml_module_maininterface_a_QML += maininterface/qml/UpdatePane.qml
+endif
+
 nodist_libqml_module_maininterface_a_SOURCES = maininterface_qmlassets.cpp
 $(libqml_module_maininterface_a_QML:.qml=.cpp) : $(builddir)/maininterface/res.qrc
 $(libqml_module_maininterface_a_QML:.qml=.cpp) : QML_CACHEGEN_ARGS=--resource=$(builddir)/maininterface/res.qrc
@@ -1067,7 +1074,8 @@ libqml_module_medialibrary_a_QML = \
 	medialibrary/qml/Bookmarks.qml \
 	medialibrary/qml/MLContextMenu.qml \
 	medialibrary/qml/MLDragItem.qml \
-	medialibrary/qml/MLTableColumns.qml
+	medialibrary/qml/MLTableColumns.qml \
+	medialibrary/qml/ScanProgressBar.qml
 nodist_libqml_module_medialibrary_a_SOURCES = medialibrary_qmlassets.cpp
 $(libqml_module_medialibrary_a_QML:.qml=.cpp) : $(builddir)/medialibrary/res.qrc
 $(libqml_module_medialibrary_a_QML:.qml=.cpp) : QML_CACHEGEN_ARGS=--resource=$(builddir)/medialibrary/res.qrc
@@ -1296,7 +1304,6 @@ libqml_module_widgets_a_QML = \
 	widgets/qml/PlayCover.qml \
 	widgets/qml/RoundButtonExt.qml \
 	widgets/qml/ScaledImage.qml \
-	widgets/qml/ScanProgressBar.qml \
 	widgets/qml/TextAutoScroller.qml \
 	widgets/qml/SearchBox.qml \
 	widgets/qml/SliderExt.qml \
@@ -1331,7 +1338,8 @@ libqml_module_widgets_a_QML = \
 	widgets/qml/RoundedRectangleShadow.qml \
 	widgets/qml/VoronoiSnow.qml \
 	widgets/qml/DualKawaseBlur.qml \
-	widgets/qml/CheckBoxExt.qml
+	widgets/qml/CheckBoxExt.qml \
+	widgets/qml/ProgressBarExt.qml
 nodist_libqml_module_widgets_a_SOURCES = widgets_qmlassets.cpp
 $(libqml_module_widgets_a_QML:.qml=.cpp) : $(builddir)/widgets/res.qrc
 $(libqml_module_widgets_a_QML:.qml=.cpp) : QML_CACHEGEN_ARGS=--resource=$(builddir)/widgets/res.qrc


=====================================
modules/gui/qt/assets.qrc
=====================================
@@ -10,6 +10,8 @@
     </qresource>
     <qresource prefix="/icons">
         <file alias="atob.svg">pixmaps/icons/atob.svg</file>
+        <file alias="ic_fluent_arrow_download_24_regular.svg">pixmaps/icons/ic_fluent_arrow_download_24_regular.svg</file>
+        <file alias="ic_fluent_arrow_sync_24_regular.svg">pixmaps/icons/ic_fluent_arrow_sync_24_regular.svg</file>
     </qresource>
     <qresource prefix="/menu">
         <file alias="add.svg">pixmaps/menu/add.svg</file>


=====================================
modules/gui/qt/dialogs/help/help.cpp
=====================================
@@ -46,6 +46,12 @@
 
 #include <cassert>
 
+#ifndef NDEBUG
+// Uncomment the following line to make use a mock update for debugging purposes,
+// it is only applicable when there is no new release found:
+// #define UPDATE_MOCK
+#endif
+
 HelpDialog::HelpDialog( qt_intf_t *_p_intf ) : QVLCFrame( _p_intf )
 
 {
@@ -192,7 +198,7 @@ public:
 
     update_t* m_update = nullptr;
 
-    update_release_t* m_release = nullptr;
+    const update_release_t* m_release = nullptr;
     UpdateModel::Status m_status = UpdateModel::Unchecked;
 
     UpdateModel* q_ptr = nullptr;
@@ -212,8 +218,42 @@ static void UpdateCallback(void *data, bool b_ret)
             bool needUpdate = update_NeedUpgrade( that->m_update );
             if (!needUpdate)
             {
-                that->m_status = UpdateModel::UpToDate;
-                that->m_release = nullptr;
+#if defined(UPDATE_MOCK) && !defined(NDEBUG)
+               static const update_release_t updateReleaseMock = {
+                   9,
+                   0,
+                   99,
+                   999,
+                   "",
+                   // Lorem ipsum with some "Security" to see if red coloring works:
+                   "Lorem ipsum dolor sit amet, security consectetur adipiscing elit. Sed vitae ante lobortis," \
+                   "condimentum sem et, auctor libero. Aliquam eget mi justo. <br /> <br /> Class aptent taciti sociosqu" \
+                   "ad litora Security torquent per conubia nostra, per inceptos himenaeos. Nulla id pretium ante. Nam" \
+                   "eu blandit lacus. Proin faucibus in risus quis condimentum. <br /> <br /> Pellentesque a tellus vitae" \
+                   "massa tristique cursus. Phasellus fermentum euismod mauris, at ultricies ipsum volutpat eu." \
+                   "Praesent arcu lacus, laoreet at lacinia quis, rhoncus at lectus. " \
+                   // Repeat:
+                   "Lorem ipsum dolor sit amet, security consectetur adipiscing elit. Sed vitae ante lobortis," \
+                   "condimentum sem et, auctor libero. Aliquam eget mi justo. <br /> <br /> Class aptent taciti sociosqu" \
+                   "ad litora Security torquent per conubia nostra, per inceptos himenaeos. Nulla id pretium ante. Nam" \
+                   "eu blandit lacus. Proin faucibus in risus quis condimentum. <br /> <br /> Pellentesque a tellus vitae" \
+                   "massa tristique cursus. Phasellus fermentum euismod mauris, at ultricies ipsum volutpat eu." \
+                   "Praesent arcu lacus, laoreet at lacinia quis, rhoncus at lectus. " \
+                   // Repeat:
+                   "Lorem ipsum dolor sit amet, security consectetur adipiscing elit. Sed vitae ante lobortis," \
+                   "condimentum sem et, auctor libero. Aliquam eget mi justo. <br /> <br /> Class aptent taciti sociosqu" \
+                   "ad litora Security torquent per conubia nostra, per inceptos himenaeos. Nulla id pretium ante. Nam" \
+                   "eu blandit lacus. Proin faucibus in risus quis condimentum. <br /> <br /> Pellentesque a tellus vitae" \
+                   "massa tristique cursus. Phasellus fermentum euismod mauris, at ultricies ipsum volutpat eu." \
+                   "Praesent arcu lacus, laoreet at lacinia quis, rhoncus at lectus. " \
+               };
+
+               that->m_release = &updateReleaseMock;
+               that->m_status = UpdateModel::NeedUpdate;
+#else
+               that->m_status = UpdateModel::UpToDate;
+               that->m_release = nullptr;
+#endif
             }
             else
             {
@@ -258,6 +298,27 @@ bool UpdateModel::download(QString destDir)
     return true;
 }
 
+bool UpdateModel::download()
+{
+    QString dest_dir = QDir::tempPath();
+    if (Q_UNLIKELY(dest_dir.isEmpty()))
+        return false;
+
+    dest_dir = toNativeSepNoSlash( std::move(dest_dir) ) + DIR_SEP;
+    qDebug() << "Downloading to folder:" << qtu( dest_dir );
+
+    return download(dest_dir);
+}
+
+void UpdateModel::resetStatus()
+{
+    Q_D(UpdateModel);
+    if (d->m_status == Unchecked)
+        return;
+    d->m_status = Unchecked;
+    emit updateStatusChanged();
+}
+
 UpdateModel::Status UpdateModel::updateStatus() const
 {
     Q_D(const UpdateModel);
@@ -301,6 +362,12 @@ QString UpdateModel::getUrl() const
     return qfu( d->m_release->psz_desc );
 }
 
+double UpdateModel::getProgress() const
+{
+    // TODO: Stub
+    return 0.0;
+}
+
 
 
 /*****************************************************************************
@@ -360,15 +427,8 @@ void UpdateDialog::checkOrDownload()
     }
     case UpdateModel::NeedUpdate:
     {
-        QString dest_dir = QDir::tempPath();
-        if( !dest_dir.isEmpty() )
-        {
-            dest_dir = toNativeSepNoSlash( std::move(dest_dir) ) + DIR_SEP;
-            msg_Dbg( p_intf, "Downloading to folder: %s", qtu( dest_dir ) );
+        if (m_model->download())
             toggleVisible();
-            m_model->download(dest_dir);
-            /* FIXME: We should trigger a change to another dialog here ! */
-        }
         break;
     }
     default: // Checking


=====================================
modules/gui/qt/dialogs/help/help.hpp
=====================================
@@ -82,17 +82,19 @@ public:
         Checking,
         UpToDate,
         NeedUpdate,
-        CheckFailed
+        CheckFailed,
+        Downloading // TODO
     };
     Q_ENUM(Status)
 
-    Q_PROPERTY(Status updateStatus READ updateStatus NOTIFY updateStatusChanged FINAL)
+    Q_PROPERTY(Status updateStatus READ updateStatus RESET resetStatus NOTIFY updateStatusChanged FINAL)
     Q_PROPERTY(int major READ getMajor NOTIFY updateStatusChanged FINAL)
     Q_PROPERTY(int minor READ getMinor NOTIFY updateStatusChanged FINAL)
     Q_PROPERTY(int revision READ getRevision NOTIFY updateStatusChanged FINAL)
     Q_PROPERTY(int extra READ getExtra NOTIFY updateStatusChanged FINAL)
     Q_PROPERTY(QString description READ getDescription NOTIFY updateStatusChanged FINAL)
     Q_PROPERTY(QString url READ getUrl NOTIFY updateStatusChanged FINAL)
+    Q_PROPERTY(double progress READ getProgress NOTIFY progressChanged FINAL) // TODO
 
 public:
     explicit UpdateModel(qt_intf_t * p_intf);
@@ -101,6 +103,9 @@ public:
     Q_INVOKABLE void checkUpdate();
 
     Q_INVOKABLE bool download(QString destDir);
+    Q_INVOKABLE bool download();
+
+    Q_INVOKABLE void resetStatus();
 
     Status updateStatus() const;
     int getMajor() const;
@@ -109,9 +114,11 @@ public:
     int getExtra() const;
     QString getDescription() const;
     QString getUrl() const;
+    double getProgress() const;
 
 signals:
     void updateStatusChanged();
+    void progressChanged();
 
 private:
     Q_DECLARE_PRIVATE(UpdateModel)


=====================================
modules/gui/qt/maininterface/mainctx.cpp
=====================================
@@ -275,24 +275,7 @@ MainCtx::MainCtx(qt_intf_t *_p_intf)
             getSettings()->value( "updatedate" ).toDate().addDays( interval ) )
         {
             /* check for update at startup */
-            m_updateModel = std::make_unique<UpdateModel>(p_intf);
-            connect(m_updateModel.get(), &UpdateModel::updateStatusChanged, this, [this](){
-                switch (m_updateModel->updateStatus())
-                {
-                case UpdateModel::Checking:
-                case UpdateModel::Unchecked:
-                    break;
-                case UpdateModel::NeedUpdate:
-                    qWarning() << "Need Udpate";
-                    THEDP->updateDialog();
-                    [[fallthrough]];
-                case UpdateModel::UpToDate:
-                case UpdateModel::CheckFailed:
-                    disconnect(m_updateModel.get(), nullptr, this, nullptr);
-                    break;
-                }
-            });
-            m_updateModel->checkUpdate();
+            getUpdateModel()->checkUpdate();
             getSettings()->setValue( "updatedate", QDate::currentDate() );
         }
     }
@@ -1211,7 +1194,51 @@ void MainCtx::setArtistAlbumsWidthFactor(double newArtistAlbumsWidthFactor)
 UpdateModel* MainCtx::getUpdateModel() const
 {
     if (!m_updateModel)
+    {
         m_updateModel = std::make_unique<UpdateModel>(p_intf);
+
+        connect(m_updateModel.get(), &UpdateModel::updateStatusChanged, this, [this](){
+            switch (m_updateModel->updateStatus())
+            {
+            case UpdateModel::NeedUpdate:
+                qWarning() << "Need update";
+
+                // No-op, modern update pane opens itself automatically when status changes.
+                // However, the old update dialog is used as fallback in case for any reason
+                // the modern pane is not available.
+
+                {
+                    // Fallback:
+
+                    if (Q_LIKELY(p_intf &&
+                                 p_intf->p_compositor &&
+                                 p_intf->p_compositor->quickWindow() &&
+                                 p_intf->p_compositor->quickWindow()->contentItem()))
+                    {
+                        const auto target = p_intf->p_compositor->quickWindow()->contentItem();
+                        QMetaObject::invokeMethod(target, [target]() {
+                            const auto updatePaneLoader = target->findChild<QQuickItem*>(QStringLiteral("updatePaneLoader"));
+                            if (!updatePaneLoader || (updatePaneLoader->property("status").toInt() != 1 /* Loader.Ready */))
+                            {
+                                qDebug("No acknowledgement from the modern update loader, falling back to the old update dialog.");
+                                THEDP->updateDialog();
+                            }
+                        }, Qt::QueuedConnection);
+                    }
+                    else
+                    {
+                        qDebug("Compositor is not available, falling back to the old update dialog.");
+                        THEDP->updateDialog();
+                    }
+                }
+
+                break;
+            default:
+                break;
+            }
+        });
+    }
+
     return m_updateModel.get();
 }
 #endif


=====================================
modules/gui/qt/maininterface/mainui.cpp
=====================================
@@ -56,6 +56,9 @@
 #include "dialogs/help/aboutmodel.hpp"
 #include "dialogs/dialogs_provider.hpp"
 #include "dialogs/dialogs/dialogmodel.hpp"
+#ifdef UPDATE_CHECK
+#include "dialogs/help/help.hpp" // UpdateModel
+#endif
 #include "util/vlchotkeyconverter.hpp"
 
 #include "network/networkmediamodel.hpp"
@@ -237,6 +240,10 @@ void MainUI::registerQMLTypes()
         qmlRegisterUncreatableType<CSDButtonModel>(uri, versionMajor, versionMinor, "CSDButtonModel", "has CSD buttons and provides for communicating CSD events between UI and backend");
         qmlRegisterTypesAndRevisions<CSDMenu>( uri, versionMajor);
         qmlRegisterUncreatableType<NavigationAttached>( uri, versionMajor, versionMinor, "Navigation", "Navigation is only available via attached properties");
+#ifdef UPDATE_CHECK
+        qmlRegisterSingletonInstance<UpdateModel>( uri, versionMajor, versionMinor, "UpdateModel", m_mainCtx->getUpdateModel() );
+#endif
+
         qmlRegisterModule(uri, versionMajor, versionMinor);
         qmlProtectModule(uri, versionMajor);
     }


=====================================
modules/gui/qt/maininterface/qml/MainDisplay.qml
=====================================
@@ -36,7 +36,9 @@ FocusScope {
     property bool hasMiniPlayer: miniPlayer.visible
 
     // NOTE: The main view must be above the indexing bar and the mini player.
-    property real displayMargin: (height - miniPlayer.y) + (loaderProgress.active ? loaderProgress.height : 0)
+    property real displayMargin: (height - miniPlayer.y) +
+                                 (loaderProgress.active ? loaderProgress.height : 0) +
+                                 (loaderUpdatePane.active ? loaderUpdatePane.height : 0)
 
     //MainDisplay behave as a PageLoader
     property alias pagePrefix: stackView.pagePrefix
@@ -286,7 +288,7 @@ FocusScope {
 
                 layer.enabled: MainCtx.backdropBlurRequested() &&
                                (GraphicsInfo.shaderType === GraphicsInfo.RhiShader) &&
-                               (miniPlayer.visible || !!loaderProgress.item?.visible)
+                               (miniPlayer.visible || !!loaderProgress.item?.visible || !!loaderUpdatePane.item?.visible)
 
                 // Blurring requires to access neighbour pixels, thus the source texture should be bigger than
                 // the effect so that the effect have access to the neighbor pixels for the pixels near the
@@ -351,7 +353,7 @@ FocusScope {
                     effectRect: Qt.rect(0,
                                         stackView.height - stackViewParent.edgeExtension,
                                         stackViewParent.width,
-                                        loaderProgress.height + miniPlayer.height + 2 * stackViewParent.edgeExtension)
+                                        loaderProgress.height + loaderUpdatePane.height + miniPlayer.height + 2 * stackViewParent.edgeExtension)
 
                     // WARNING: We are not using `sourceVisualRect` because it is not trivial to guarantee that
                     //          the visual (`ShaderEffect`) scene graph sizing and sub-texturing are synchronized.
@@ -423,7 +425,7 @@ FocusScope {
                     Navigation.parentItem: mainColumn
                     Navigation.upItem: sourcesBanner
                     Navigation.rightItem: playlistLoader
-                    Navigation.downItem:  miniPlayer.visible ? miniPlayer : null
+                    Navigation.downItem: loaderUpdatePane
                 }
 
                 Rectangle {
@@ -525,7 +527,7 @@ FocusScope {
 
                     Navigation.parentItem: mainColumn
                     Navigation.upItem: sourcesBanner
-                    Navigation.downItem: miniPlayer.visible ? miniPlayer : null
+                    Navigation.downItem: loaderUpdatePane
 
                     Navigation.leftAction: function() {
                         stackView.currentItem.setCurrentItemFocus(Qt.TabFocusReason);
@@ -601,6 +603,78 @@ FocusScope {
         }
     }
 
+    Loader {
+        id: loaderUpdatePane
+
+        // WARNING: Object name is used from C++ side to acknowledge the modern update pane is loaded,
+        //          if C++ side does not get this acknowledgement, the old update dialog is shown as
+        //          fallback.
+        objectName: "updatePaneLoader"
+
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.bottom: loaderProgress.top
+
+        active: !!UpdateModel && (shouldShow || height > 0.0)
+
+        focus: !!item
+
+        readonly property bool shouldShow: !!UpdateModel && (UpdateModel.updateStatus !== UpdateModel.Unchecked)
+
+        // This property can be used to enable/disable the animation:
+        property alias toggleAnimation: heightBehavior.enabled
+
+        function dismiss() {
+            height = 0.0
+        }
+
+        onShouldShowChanged: {
+            if (shouldShow)
+                height = Qt.binding(() => { return implicitHeight })
+        }
+
+        onActiveChanged: {
+            console.assert(!!UpdateModel)
+            if (!active)
+                UpdateModel.resetStatus()
+        }
+
+        clip: (height < implicitHeight)
+
+        Behavior on height {
+            id: heightBehavior
+
+            NumberAnimation {
+                easing.type: Easing.InOutSine
+                duration: VLCStyle.duration_long
+            }
+        }
+
+        source: "qrc:///qt/qml/VLC/MainInterface/UpdatePane.qml"
+
+        Navigation.parentItem: mainColumn
+        Navigation.upItem: mainRow
+        Navigation.downItem: miniPlayer
+
+        onLoaded: {            
+            item.background.visible = Qt.binding(function() { return !stackViewParent.layer.enabled })
+
+            item.leftPadding = Qt.binding(function() { return VLCStyle.margin_large + VLCStyle.applicationHorizontalMargin })
+            item.rightPadding = Qt.binding(function() { return VLCStyle.margin_large + VLCStyle.applicationHorizontalMargin })
+            item.bottomPadding = Qt.binding(function() { return VLCStyle.margin_small + ((miniPlayer.visible || loaderProgress.visible) ? 0
+                                                                                                                                        : VLCStyle.applicationVerticalMargin) })
+
+            item.dismissRequested.connect(loaderUpdatePane, loaderUpdatePane.dismiss)
+
+            // We have height animation here, we don't want animation inside the item in addition to that:
+            item.animations = Qt.binding(function() { return !loaderUpdatePane.toggleAnimation })
+
+            item.Navigation.parentItem = loaderUpdatePane
+
+            item.focus = true // Loader itself is a focus scope, so we need this
+        }
+    }
+
 
     Loader {
         id: loaderProgress
@@ -613,7 +687,7 @@ FocusScope {
 
         height: active ? implicitHeight : 0
 
-        source: "qrc:///qt/qml/VLC/Widgets/ScanProgressBar.qml"
+        source: "qrc:///qt/qml/VLC/MediaLibrary/ScanProgressBar.qml"
 
         onLoaded: {
             item.background.visible = Qt.binding(function() { return !stackViewParent.layer.enabled })
@@ -699,7 +773,7 @@ FocusScope {
         background.visible: !stackViewParent.layer.enabled
 
         Navigation.parentItem: mainColumn
-        Navigation.upItem: mainRow
+        Navigation.upItem: loaderUpdatePane
         Navigation.cancelItem:sourcesBanner
         onVisibleChanged: {
             if (!visible && miniPlayer.activeFocus)


=====================================
modules/gui/qt/maininterface/qml/UpdatePane.qml
=====================================
@@ -0,0 +1,352 @@
+/*****************************************************************************
+ * Copyright (C) 2026 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
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+import VLC.MainInterface
+import VLC.Widgets as Widgets
+import VLC.Style
+import VLC.Util
+
+T.Pane {
+    id: root
+
+    implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+                            implicitContentWidth + leftPadding + rightPadding)
+    implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+                             implicitContentHeight + topPadding + bottomPadding)
+
+    horizontalPadding: VLCStyle.margin_large
+    verticalPadding: VLCStyle.margin_small
+
+    property bool animations: true
+
+    signal dismissRequested()
+
+    readonly property ColorContext colorContext: ColorContext {
+        id: theme
+        colorSet: ColorContext.Window // ###
+
+        focused: root.activeFocus
+        hovered: root.hovered
+        enabled: root.enabled
+    }
+
+    background: Rectangle {
+        color: theme.bg.primary
+    }
+
+    contentItem: Column {
+        spacing: VLCStyle.margin_xsmall
+
+        RowLayout {
+            id: rowLayout
+
+            anchors.left: parent.left
+            anchors.right: parent.right
+
+            spacing: VLCStyle.margin_small
+
+            readonly property bool collapseText: (width < VLCStyle.colWidth(5))
+
+            Image {
+                id: cone
+
+                sourceSize: Qt.size(VLCStyle.icon_normal, VLCStyle.icon_normal)
+                source: SVGColorImage.colorize("qrc:///misc/cone.svg").accent(theme.accent).uri()
+            }
+
+            Widgets.LabelExt {
+                id: titleLabel
+
+                Layout.fillWidth: true
+
+                text: {
+                    switch (UpdateModel.updateStatus) {
+                        case UpdateModel.NeedUpdate:
+                            const extra = UpdateModel.extra
+                            return qsTr("A new version of VLC (%1.%2.%3%4) is available.").arg(UpdateModel.major)
+                                                                                          .arg(UpdateModel.minor)
+                                                                                          .arg(UpdateModel.revision)
+                                                                                          .arg(extra === 0 ? "" : "." + extra)
+                        case UpdateModel.UpToDate:
+                            return qsTr("You have the latest version of VLC media player.")
+                        case UpdateModel.CheckFailed:
+                            return qsTr("An error occurred while checking for updates...")
+                        case UpdateModel.Checking:
+                            return qsTr("Checking for updates...")
+                        default:
+                            return qsTr("N/A")
+                    }
+                }
+
+                elide: Text.ElideRight
+
+                font.pixelSize: VLCStyle.fontSize_large
+
+                color: theme.fg.primary
+            }
+
+            Widgets.ActionButtonOverlay {
+                id: revealDetailsButton
+
+                iconTxt: VLCIcons.chevron_up
+                iconRotation: descriptionFlickable.revealed ? 180 : 0
+
+                Behavior on iconRotation {
+                    // WARNING: Can't use `RotationAnimator` because it expects property to be "rotation".
+                    RotationAnimation {
+                        easing.type: Easing.InOutSine
+                        duration: heightAnimation.duration
+                    }
+                }
+
+                text: qsTr("Details")
+                showText: !rowLayout.collapseText
+
+                // Do not assume that description would be available depending on specific update status.
+                // This button must be available at any time if the model provides description.
+                visible: (descriptionLabel.text.length > 0)
+
+                onClicked: {
+                    descriptionFlickable.revealed = !descriptionFlickable.revealed
+                }
+
+                Navigation.parentItem: root
+                Navigation.rightItem: recheckButton
+            }
+
+            component Separator : Rectangle {
+                id: separator
+
+                implicitWidth: 1
+                implicitHeight: titleLabel.height
+
+                color: theme.border
+            }
+
+            Separator {
+                visible: revealDetailsButton.visible
+            }
+
+            Widgets.ActionButtonOverlay {
+                id: recheckButton
+
+                iconTxt: VLCIcons.ic_fluent_arrow_sync_24_regular
+                text: qsTr("Re-check")
+                showText: !rowLayout.collapseText
+
+                visible: (UpdateModel.updateStatus !== UpdateModel.Checking)
+
+                onClicked: {
+                    descriptionFlickable.revealed = false
+                    UpdateModel.checkUpdate()
+                }
+
+                Navigation.parentItem: root
+                Navigation.leftItem: revealDetailsButton
+                Navigation.rightItem: downloadButton
+            }
+
+            Widgets.ActionButtonPrimary {
+                id: downloadButton
+
+                visible: (UpdateModel.updateStatus === UpdateModel.NeedUpdate)
+
+                iconTxt: VLCIcons.ic_fluent_arrow_download_24_regular
+                text: qsTr("Download")
+                showText: !rowLayout.collapseText
+
+                onVisibleChanged: {
+                    if (visible)
+                        focus = true // Request focus here by default
+                }
+
+                onClicked: {
+                    if (!UpdateModel.download())
+                        console.error("UpdateModel::download() failed!")
+
+                    // Since downloading dialog is still a separate one, we
+                    // should request dismissing this pane. In the future
+                    // we can get rid of the separate dialog and represent
+                    // the download status here.
+                    if (UpdateModel.updateStatus !== UpdateModel.Downloading)
+                        root.dismissRequested()
+                }
+
+                Navigation.parentItem: root
+                Navigation.leftItem: recheckButton
+                Navigation.rightItem: dismissButton
+            }
+
+            Separator {
+                visible: recheckButton.visible || downloadButton.visible
+            }
+
+            Widgets.ActionButtonOverlay {
+                id: dismissButton
+
+                iconTxt: VLCIcons.close
+                text: qsTr("Dismiss")
+                showText: false // Always collapsed
+
+                onVisibleChanged: {
+                    if (visible) {
+                        if (!downloadButton.visible || !downloadButton.focus)
+                            focus = true // Second chance for focus
+                    }
+                }
+
+                Component.onCompleted: {
+                    clicked.connect(root, dismissRequested)
+                }
+
+                Navigation.parentItem: root
+                Navigation.leftItem: downloadButton
+            }
+        }
+
+        Widgets.ProgressBarExt {
+            anchors.left: parent.left
+            anchors.right: parent.right
+
+            horizontalPadding: 0
+
+            from: 0
+            to: 1
+
+            indeterminate: (UpdateModel.updateStatus === UpdateModel.Checking)
+
+            value: {
+                switch (UpdateModel.updateStatus) {
+                case UpdateModel.Checking:
+                case UpdateModel.Downloading:
+                    return UpdateModel.progress
+                case UpdateModel.UpToDate:
+                    return 1.0
+                case UpdateModel.NeedUpdate:
+                default:
+                    return 0.0
+                }
+            }
+
+            visible: {
+                switch (UpdateModel.updateStatus) {
+                case UpdateModel.Checking:
+                case UpdateModel.Downloading:
+                    return true
+                case UpdateModel.UpToDate:
+                case UpdateModel.NeedUpdate:
+                default:
+                    return false
+                }
+            }
+
+            background: null
+        }
+
+        Flickable {
+            id: descriptionFlickable
+
+            anchors.left: parent.left
+            anchors.right: parent.right
+
+            implicitWidth: contentWidth
+            implicitHeight: contentHeight
+
+            contentWidth: width
+            contentHeight: descriptionLabel.height
+
+            interactive: height < descriptionLabel.height
+
+            clip: !fadingEdge.effectCompatible && (height < implicitHeight)
+            visible: height > 0.1
+
+            property bool revealed: false
+
+            height: revealed ? Math.min(implicitHeight, VLCStyle.dp(256, VLCStyle.scale)) : 0.1 // We want 0.0, but Qt 6.2.4 is bugged
+
+            boundsBehavior: Flickable.StopAtBounds
+
+            Behavior on height {
+                enabled: root.animations
+
+                NumberAnimation {
+                    id: heightAnimation
+
+                    easing.type: Easing.InOutSine
+                    duration: VLCStyle.duration_long
+                }
+            }
+
+            T.ScrollBar.vertical: Widgets.ScrollBarExt {}
+
+            Widgets.LabelExt {
+                id: descriptionLabel
+
+                width: parent.width
+
+                font.pixelSize: VLCStyle.fontSize_normal
+
+                color: theme.fg.primary
+
+                // Highlight "security", like the old check for updates dialog.
+                // ES6 does not have replaceAll(), but this works too with regex, which we need to use
+                // anyway to match case insensitive:
+                text: UpdateModel.description.replace(/security/gi,
+                                                      (match) => { return "<font color=\"red\">" + match + "</font>" })
+
+                wrapMode: Text.WordWrap
+
+                padding: VLCStyle.margin_xxsmall
+
+                style: Text.Raised
+                styleColor: Qt.rgba(0.0, 0.0, 0.0, 0.2)
+            }
+
+            Widgets.FadingEdge {
+                id: fadingEdge
+
+                parent: descriptionFlickable
+
+                anchors.fill: parent
+
+                backgroundColor: (root.background?.visible && root.background.color.a >= 1.0) ? root.background.color
+                                                                                              : "transparent"
+
+                sourceItem: descriptionFlickable.contentItem
+
+                sourceX: descriptionFlickable.contentX
+                sourceY: descriptionFlickable.contentY
+
+                orientation: Qt.Vertical
+
+                Binding on enableBeginningFade {
+                    when: descriptionFlickable.atYBeginning
+                    value: false
+                }
+
+                Binding on enableEndFade {
+                    when: descriptionFlickable.atYEnd
+                    value: false
+                }
+            }
+        }
+    }
+}


=====================================
modules/gui/qt/medialibrary/qml/ScanProgressBar.qml
=====================================
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ * 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
+import QtQuick.Controls
+import QtQuick.Templates as T
+
+import VLC.Widgets
+import VLC.MediaLibrary
+import VLC.Style
+
+ProgressBarExt {
+    id: control
+
+    value: MediaLib.parsingProgress
+
+    indeterminate: MediaLib.discoveryPending
+
+    SubtitleLabel {
+        parent: control.contentItem
+
+        anchors.left: parent.left
+        anchors.right: parent.right
+
+        text: (MediaLib.discoveryPending) ? qsTr("Scanning %1")
+                                            .arg(MediaLib.discoveryEntryPoint)
+                                          : qsTr("Indexing Medias (%1%)")
+                                            .arg(MediaLib.parsingProgress)
+
+        elide: Text.ElideMiddle
+
+        font.pixelSize: VLCStyle.fontSize_large
+        font.weight: Font.Normal
+        color: theme.fg.primary
+    }
+}


=====================================
modules/gui/qt/menus/menus.cpp
=====================================
@@ -39,6 +39,7 @@
 
 #include "maininterface/mainctx.hpp"                     /* View modifications */
 #include "dialogs/dialogs_provider.hpp"                   /* Dialogs display */
+#include "dialogs/help/help.hpp"
 #include "player/player_controller.hpp"                      /* Input Management */
 #include "playlist/playlist_controller.hpp"
 #include "dialogs/extensions/extensions_manager.hpp"                 /* Extensions menu */
@@ -548,13 +549,20 @@ void VLCMenuBar::RebuildNavigMenu( qt_intf_t *p_intf, QMenu *menu )
 /**
  * Help/About Menu
 **/
-void VLCMenuBar::HelpMenu( QMenu *menu )
+void VLCMenuBar::HelpMenu(qt_intf_t *p_intf, QMenu *menu )
 {
     addDPStaticEntry( menu, qtr( "&Help" ) ,
         ":/menu/help.svg", &DialogsProvider::helpDialog, "F1" );
 #ifdef UPDATE_CHECK
     addDPStaticEntry( menu, qtr( "Check for &Updates..." ) , "",
-                      &DialogsProvider::updateDialog);
+                     [ctx = QPointer(p_intf->p_mi)]() {
+        if (Q_LIKELY(ctx))
+        {
+            const auto updateModel = ctx->getUpdateModel();
+            assert(updateModel);
+            updateModel->checkUpdate();
+        }
+    });
 #endif
     menu->addSeparator();
     addDPStaticEntry( menu, qfut( I_MENU_ABOUT ), ":/menu/info.svg",
@@ -849,7 +857,7 @@ QMenu* VLCMenuBar::PopupMenu( qt_intf_t *p_intf, bool show )
         menu->addSeparator();
 
         QMenu* helpmenu = new QMenu( qtr( "Help" ), menu );
-        HelpMenu( helpmenu );
+        HelpMenu( p_intf, helpmenu );
         menu->addMenu( helpmenu );
 
         addDPStaticEntry( menu, qtr( "Quit" ), ":/menu/exit.svg",


=====================================
modules/gui/qt/menus/menus.hpp
=====================================
@@ -94,7 +94,7 @@ public:
 
     static void AudioMenu( qt_intf_t *, QMenu * );
 
-    static void HelpMenu( QMenu *menu );
+    static void HelpMenu( qt_intf_t *, QMenu *menu );
 
     /* Popups Menus */
     static void PopupMenuStaticEntries( QMenu *menu );


=====================================
modules/gui/qt/menus/qml_menu_wrapper.cpp
=====================================
@@ -286,7 +286,7 @@ void QmlGlobalMenu::popup(QPoint pos)
     ViewMenu( p_intf, submenu );
 
     submenu = m_menu->addMenu(qtr( "&Help" ));
-    HelpMenu(submenu);
+    HelpMenu( p_intf, submenu );
 
     m_menu->popup(pos);
 }
@@ -410,7 +410,7 @@ void QmlMenuBar::setupMenuEntry(QMenu* menu, MenuEntry entry)
         ViewMenu( p_intf, menu );
         break;
     case HELP:
-        HelpMenu( menu );
+        HelpMenu( p_intf, menu );
         break;
     default:
         vlc_assert_unreachable();
@@ -478,8 +478,9 @@ void QmlMenuBar::popupViewMenu(QQuickItem* button )
 
 void QmlMenuBar::popupHelpMenu( QQuickItem* button )
 {
-    popupMenuCommon(button, [](QMenu* menu) {
-        HelpMenu(menu);
+    popupMenuCommon(button, [this](QMenu* menu) {
+        qt_intf_t* p_intf = m_ctx->getIntf();
+        HelpMenu( p_intf, menu );
     });
 }
 


=====================================
modules/gui/qt/meson.build
=====================================
@@ -612,6 +612,13 @@ qml_modules += {
     ),
 }
 
+qml_maininterface_extra_files = []
+
+if get_option('update-check').allowed() and gcrypt_dep.found()
+    qt_extra_flags += '-DUPDATE_CHECK'
+    qml_maininterface_extra_files += 'maininterface/qml/UpdatePane.qml'
+endif
+
 qml_modules += {
     'name' : 'VLC.MainInterface',
     'target' : 'maininterface',
@@ -621,7 +628,8 @@ qml_modules += {
         'maininterface/qml/MainInterface.qml',
         'maininterface/qml/MainViewLoader.qml',
         'maininterface/qml/MainDisplay.qml',
-        'maininterface/qml/NoMedialibHome.qml'
+        'maininterface/qml/NoMedialibHome.qml',
+        qml_maininterface_extra_files,
     ),
 }
 qml_modules += {
@@ -668,6 +676,7 @@ qml_modules += {
         'medialibrary/qml/MLContextMenu.qml',
         'medialibrary/qml/MLDragItem.qml',
         'medialibrary/qml/MLTableColumns.qml',
+        'medialibrary/qml/ScanProgressBar.qml',
     ),
 }
 
@@ -887,7 +896,6 @@ qml_modules += {
         'widgets/qml/PlayCover.qml',
         'widgets/qml/RoundButtonExt.qml',
         'widgets/qml/ScaledImage.qml',
-        'widgets/qml/ScanProgressBar.qml',
         'widgets/qml/TextAutoScroller.qml',
         'widgets/qml/SearchBox.qml',
         'widgets/qml/SliderExt.qml',
@@ -923,6 +931,7 @@ qml_modules += {
         'widgets/qml/VoronoiSnow.qml',
         'widgets/qml/DualKawaseBlur.qml',
         'widgets/qml/CheckBoxExt.qml',
+        'widgets/qml/ProgressBarExt.qml',
     ),
 }
 
@@ -1218,11 +1227,6 @@ if qt6_dep.found()
         endif
     endif
 
-    if get_option('update-check').allowed() and gcrypt_dep.found()
-        qt_extra_flags += '-DUPDATE_CHECK'
-    endif
-
-
     vlc_modules += {
         'name' : 'qt_x11',
         'include_directories' : qt_include_dir,


=====================================
modules/gui/qt/pixmaps/VLCIcons.json
=====================================
@@ -90,6 +90,8 @@
         {"key":"window_minimize", "path": "./icons/window_minimize.svg" },
         {"key":"window_restore", "path": "./icons/window_restore.svg" },
         {"key":"ic_fluent_document_add_24_regular", "path": "./icons/ic_fluent_document_add_24_regular.svg"},
-        {"key":"ic_fluent_document_copy_24_regular", "path": "./icons/ic_fluent_document_copy_24_regular.svg"}
+        {"key":"ic_fluent_document_copy_24_regular", "path": "./icons/ic_fluent_document_copy_24_regular.svg"},
+        {"key":"ic_fluent_arrow_download_24_regular", "path": "./icons/ic_fluent_arrow_download_24_regular.svg"},
+        {"key":"ic_fluent_arrow_sync_24_regular", "path": "./icons/ic_fluent_arrow_sync_24_regular.svg"}
     ]
 }


=====================================
modules/gui/qt/pixmaps/VLCIcons.ttf
=====================================
Binary files a/modules/gui/qt/pixmaps/VLCIcons.ttf and b/modules/gui/qt/pixmaps/VLCIcons.ttf differ


=====================================
modules/gui/qt/pixmaps/icons/ic_fluent_arrow_download_24_regular.svg
=====================================
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.2498 20.5009C18.664 20.5008 19 20.8365 19 21.2507C19 21.6649 18.6644 22.0008 18.2502 22.0009L5.25022 22.0047C4.836 22.0048 4.5 21.6691 4.5 21.2549C4.5 20.8407 4.83557 20.5048 5.24978 20.5047L18.2498 20.5009ZM11.6482 2.01271L11.75 2.00586C12.1297 2.00586 12.4435 2.28801 12.4932 2.65409L12.5 2.75586L12.499 16.4409L16.2208 12.7205C16.4871 12.4543 16.9038 12.4301 17.1974 12.648L17.2815 12.7206C17.5477 12.9869 17.5719 13.4036 17.354 13.6972L17.2814 13.7813L12.2837 18.7779C12.0176 19.044 11.6012 19.0683 11.3076 18.8507L11.2235 18.7782L6.22003 13.7816C5.92694 13.4889 5.92661 13.014 6.21931 12.7209C6.48539 12.4545 6.90204 12.43 7.1958 12.6477L7.27997 12.7202L10.999 16.4339L11 2.75586C11 2.37616 11.2822 2.06237 11.6482 2.01271L11.75 2.00586L11.6482 2.01271Z" fill="#212121"/>
+</svg>


=====================================
modules/gui/qt/pixmaps/icons/ic_fluent_arrow_sync_24_regular.svg
=====================================
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M16.2506 5.18011C15.9994 5.50947 16.0627 5.9801 16.3921 6.23128C18.1804 7.59515 19.25 9.70821 19.25 12C19.25 15.736 16.4242 18.812 12.7933 19.2071L13.4697 18.5303C13.7626 18.2374 13.7626 17.7626 13.4697 17.4697C13.2034 17.2034 12.7867 17.1792 12.4931 17.3971L12.409 17.4697L10.409 19.4697C10.1427 19.7359 10.1185 20.1526 10.3364 20.4462L10.409 20.5303L12.409 22.5303C12.7019 22.8232 13.1768 22.8232 13.4697 22.5303C13.7359 22.2641 13.7601 21.8474 13.5423 21.5538L13.4697 21.4697L12.7194 20.7208C17.2154 20.355 20.75 16.5903 20.75 12C20.75 9.23526 19.4582 6.68321 17.3017 5.03856C16.9724 4.78738 16.5017 4.85075 16.2506 5.18011ZM10.5303 1.46967C10.2374 1.76256 10.2374 2.23744 10.5303 2.53033L11.2796 3.27923C6.78409 3.6456 3.25 7.41008 3.25 12C3.25 14.6445 4.43126 17.0974 6.43081 18.7491C6.75016 19.0129 7.22289 18.9679 7.48669 18.6485C7.75048 18.3292 7.70545 17.8564 7.3861 17.5926C5.72793 16.2229 4.75 14.1922 4.75 12C4.75 8.26436 7.57532 5.18861 11.2057 4.79301L10.5303 5.46967C10.2374 5.76256 10.2374 6.23744 10.5303 6.53033C10.8232 6.82322 11.2981 6.82322 11.591 6.53033L13.591 4.53033C13.8839 4.23744 13.8839 3.76256 13.591 3.46967L11.591 1.46967C11.2981 1.17678 10.8232 1.17678 10.5303 1.46967Z" fill="#212121"/>
+</svg>


=====================================
modules/gui/qt/style/VLCIcons.qml
=====================================
@@ -98,7 +98,9 @@ QtObject {
     readonly property string window_maximize : "\ue052"
     readonly property string window_minimize : "\ue053"
     readonly property string window_restore : "\ue054"
-    readonly property string ic_fluent_document_add_24_regular: "\ue055"
-    readonly property string ic_fluent_document_copy_24_regular: "\ue056"
+    readonly property string ic_fluent_document_add_24_regular : "\ue055"
+    readonly property string ic_fluent_document_copy_24_regular : "\ue056"
+    readonly property string ic_fluent_arrow_download_24_regular : "\ue057"
+    readonly property string ic_fluent_arrow_sync_24_regular : "\ue058"
 
 }


=====================================
modules/gui/qt/widgets/qml/ScanProgressBar.qml → modules/gui/qt/widgets/qml/ProgressBarExt.qml
=====================================
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (C) 2019 VLC authors and VideoLAN
+ * Copyright (C) 2026 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
@@ -15,13 +15,10 @@
  * 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
 import QtQuick.Controls
 import QtQuick.Templates as T
 
-import VLC.MediaLibrary
-
 import VLC.Style
 
 T.ProgressBar {
@@ -38,15 +35,11 @@ T.ProgressBar {
     from: 0
     to: 100
 
-    value: MediaLib.parsingProgress
-
     readonly property ColorContext colorContext: ColorContext {
         id: theme
         colorSet: ColorContext.Window
     }
 
-    indeterminate: MediaLib.discoveryPending
-
     background: Rectangle {
         color: theme.bg.primary
     }
@@ -132,21 +125,5 @@ T.ProgressBar {
                 }
             }
         }
-
-        SubtitleLabel {
-            anchors.left: parent.left
-            anchors.right: parent.right
-
-            text: (MediaLib.discoveryPending) ? qsTr("Scanning %1")
-                                                .arg(MediaLib.discoveryEntryPoint)
-                                              : qsTr("Indexing Medias (%1%)")
-                                                .arg(MediaLib.parsingProgress)
-
-            elide: Text.ElideMiddle
-
-            font.pixelSize: VLCStyle.fontSize_large
-            font.weight: Font.Normal
-            color: theme.fg.primary
-        }
     }
-}
+}
\ No newline at end of file


=====================================
po/POTFILES.in
=====================================
@@ -751,6 +751,7 @@ modules/gui/qt/maininterface/qml/BannerSources.qml
 modules/gui/qt/maininterface/qml/MainDisplay.qml
 modules/gui/qt/maininterface/qml/MainInterface.qml
 modules/gui/qt/maininterface/qml/NoMedialibHome.qml
+modules/gui/qt/maininterface/qml/UpdatePane.qml
 modules/gui/qt/widgets/qml/EmptyLabelButton.qml
 modules/gui/qt/widgets/qml/EmptyLabel.qml
 modules/gui/qt/medialibrary/mlbookmarkmodel.cpp
@@ -806,6 +807,7 @@ modules/gui/qt/medialibrary/qml/VideoPlaylistsDisplay.qml
 modules/gui/qt/medialibrary/qml/VideoGridDisplay.qml
 modules/gui/qt/medialibrary/qml/MusicAlbumSectionDelegate.qml
 modules/gui/qt/medialibrary/qml/MLContextMenu.qml
+modules/gui/qt/medialibrary/qml/ScanProgressBar.qml
 modules/gui/qt/menus/custom_menus.cpp
 modules/gui/qt/menus/custom_menus.hpp
 modules/gui/qt/menus/menus.cpp
@@ -913,7 +915,6 @@ modules/gui/qt/widgets/native/qvlcframe.hpp
 modules/gui/qt/widgets/native/searchlineedit.cpp
 modules/gui/qt/widgets/native/searchlineedit.hpp
 modules/gui/qt/widgets/qml/DragItem.qml
-modules/gui/qt/widgets/qml/ScanProgressBar.qml
 modules/gui/qt/widgets/qml/SearchBox.qml
 modules/gui/qt/widgets/qml/SortControl.qml
 modules/gui/qt/widgets/qml/TableColumns.qml



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ecadeffefefd5f9a33bfa06c1d49dca48adf6dc4...1ee9c4139eacf5ac562795f089ffc5aec1c500ad

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ecadeffefefd5f9a33bfa06c1d49dca48adf6dc4...1ee9c4139eacf5ac562795f089ffc5aec1c500ad
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help




More information about the vlc-commits mailing list