From fadfa140b2431b3af7a858f35eb6c0a3df2f6b27 Mon Sep 17 00:00:00 2001 From: Gabriel Bolbotina Date: Wed, 25 Feb 2026 13:34:16 +0200 Subject: [PATCH 1/3] Fixed hot reload --- gallery/hotreload.cpp | 83 +++++++++++++++++++++++++++---------------- gallery/hotreload.h | 2 ++ 2 files changed, 54 insertions(+), 31 deletions(-) diff --git a/gallery/hotreload.cpp b/gallery/hotreload.cpp index a6025c2d4..27a244c03 100644 --- a/gallery/hotreload.cpp +++ b/gallery/hotreload.cpp @@ -17,15 +17,12 @@ // TODO: not needed to sync dirs every second, just when a file was changed QString HotReload::syncScript() const { - return "#!/bin/sh \n\ -echo running hot reload sync directories ... \n\ -while true; do \n\ - rsync -ra " GALLERY_SOURCE_DIR "/qml/ HotReload/qml/ \n\ - rsync -ra " GALLERY_SOURCE_DIR "/../app/qml/ HotReload/app/qml/ \n\ - sleep 1 \n\ -done"; + return QString("#!/bin/sh \n" + "echo 'Syncing modified files...' \n" + "rsync -rau \"%1/qml/\" HotReload/qml/ \n" + "rsync -rau \"%1/../app/qml/\" HotReload/app/qml/ \n") + .arg(GALLERY_SOURCE_DIR); } - HotReload::HotReload( QQmlApplicationEngine &engine, QObject *parent ): _engine( engine ) { @@ -66,28 +63,52 @@ void HotReload::clearCache() void HotReload::startHotReload() { - _watcher = new QFileSystemWatcher( this ); - _watcher->addPath( "HotReload/qml" ); - _watcher->addPath( "HotReload/qml/Pages" ); - _watcher->addPath( "HotReload/app/qml/account" ); - _watcher->addPath( "HotReload/app/qml/account/components" ); - _watcher->addPath( "HotReload/app/qml/components" ); - _watcher->addPath( "HotReload/app/qml/dialogs" ); - _watcher->addPath( "HotReload/app/qml/form" ); - _watcher->addPath( "HotReload/app/qml/form/components" ); - _watcher->addPath( "HotReload/app/qml/form/editors" ); - _watcher->addPath( "HotReload/app/qml/gps" ); - _watcher->addPath( "HotReload/app/qml/inputs" ); - _watcher->addPath( "HotReload/app/qml/layers" ); - _watcher->addPath( "HotReload/app/qml/map" ); - _watcher->addPath( "HotReload/app/qml/project" ); - _watcher->addPath( "HotReload/app/qml/project/components" ); - _watcher->addPath( "HotReload/app/qml/settings" ); - _watcher->addPath( "HotReload/app/qml/settings/components" ); + _debounceTimer = new QTimer(this); + _debounceTimer->setSingleShot(true); + _debounceTimer->setInterval(300); - // send signal for hot reloading - connect( _watcher, &QFileSystemWatcher::directoryChanged, this, [this]( const QString & path ) - { - emit watchedSourceChanged(); - } ); + // When the timer fires, run the sync script ONCE, then reload + connect(_debounceTimer, &QTimer::timeout, this, [this]() { + // Run the sync synchronously so it finishes before reloading + QProcess::execute("./syncGallery.sh"); + emit watchedSourceChanged(); + }); + + _watcher = new QFileSystemWatcher( this ); + + // Set up base paths for your source code + QString gallerySrc = QString(GALLERY_SOURCE_DIR) + "/qml"; + QString appSrc = QString(GALLERY_SOURCE_DIR) + "/../app/qml"; + + // Watch the SOURCE directories instead of the destination + _watcher->addPath( gallerySrc ); + _watcher->addPath( gallerySrc + "/Pages" ); + + _watcher->addPath( appSrc + "/account" ); + _watcher->addPath( appSrc + "/account/components" ); + _watcher->addPath( appSrc + "/components" ); + _watcher->addPath( appSrc + "/dialogs" ); + _watcher->addPath( appSrc + "/form" ); + _watcher->addPath( appSrc + "/form/components" ); + _watcher->addPath( appSrc + "/form/editors" ); + _watcher->addPath( appSrc + "/gps" ); + _watcher->addPath( appSrc + "/inputs" ); + _watcher->addPath( appSrc + "/layers" ); + _watcher->addPath( appSrc + "/map" ); + _watcher->addPath( appSrc + "/project" ); + _watcher->addPath( appSrc + "/project/components" ); + _watcher->addPath( appSrc + "/settings" ); + _watcher->addPath( appSrc + "/settings/components" ); + + // When you save a file in your IDE, start the debounce timer + connect( _watcher, &QFileSystemWatcher::directoryChanged, this, [this]( const QString & path ) + { + _debounceTimer->start(); + } ); + + // Connect fileChanged as well, just in case macOS watches specific files instead of dirs + connect( _watcher, &QFileSystemWatcher::fileChanged, this, [this]( const QString & path ) + { + _debounceTimer->start(); + } ); } diff --git a/gallery/hotreload.h b/gallery/hotreload.h index b1cecc0f6..224bb9039 100644 --- a/gallery/hotreload.h +++ b/gallery/hotreload.h @@ -12,6 +12,7 @@ #include #include +#include class QFileSystemWatcher; @@ -34,6 +35,7 @@ class HotReload : public QObject private: QFileSystemWatcher *_watcher; QQmlApplicationEngine &_engine; + QTimer* _debounceTimer = nullptr; }; #endif // HOTRELOAD_H From b25dfb0e78b2bfd3a621bd403df0cbcf64804ab6 Mon Sep 17 00:00:00 2001 From: Gabriel Bolbotina Date: Wed, 25 Feb 2026 14:34:59 +0200 Subject: [PATCH 2/3] Formatted code --- gallery/hotreload.cpp | 93 +++++++++++++++++++++---------------------- gallery/hotreload.h | 2 +- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/gallery/hotreload.cpp b/gallery/hotreload.cpp index 27a244c03..2089630cf 100644 --- a/gallery/hotreload.cpp +++ b/gallery/hotreload.cpp @@ -14,14 +14,13 @@ #include #include -// TODO: not needed to sync dirs every second, just when a file was changed QString HotReload::syncScript() const { - return QString("#!/bin/sh \n" - "echo 'Syncing modified files...' \n" - "rsync -rau \"%1/qml/\" HotReload/qml/ \n" - "rsync -rau \"%1/../app/qml/\" HotReload/app/qml/ \n") - .arg(GALLERY_SOURCE_DIR); + return QString( "#!/bin/sh \n" + "echo 'Syncing modified files...' \n" + "rsync -rau \"%1/qml/\" HotReload/qml/ \n" + "rsync -rau \"%1/../app/qml/\" HotReload/app/qml/ \n" ) + .arg( GALLERY_SOURCE_DIR ); } HotReload::HotReload( QQmlApplicationEngine &engine, QObject *parent ): _engine( engine ) @@ -63,52 +62,52 @@ void HotReload::clearCache() void HotReload::startHotReload() { - _debounceTimer = new QTimer(this); - _debounceTimer->setSingleShot(true); - _debounceTimer->setInterval(300); + _debounceTimer = new QTimer( this ); + _debounceTimer->setSingleShot( true ); + _debounceTimer->setInterval( 300 ); - // When the timer fires, run the sync script ONCE, then reload - connect(_debounceTimer, &QTimer::timeout, this, [this]() { - // Run the sync synchronously so it finishes before reloading - QProcess::execute("./syncGallery.sh"); - emit watchedSourceChanged(); - }); + // when the timer starts, run the sync script ONCE, then reload + connect( _debounceTimer, &QTimer::timeout, this, [this]() + { + // run the sync synchronously so it finishes before reloading + QProcess::execute( "./syncGallery.sh" ); + emit watchedSourceChanged(); + } ); - _watcher = new QFileSystemWatcher( this ); + _watcher = new QFileSystemWatcher( this ); - // Set up base paths for your source code - QString gallerySrc = QString(GALLERY_SOURCE_DIR) + "/qml"; - QString appSrc = QString(GALLERY_SOURCE_DIR) + "/../app/qml"; + // Set up base paths for your source code + QString gallerySrc = QString( GALLERY_SOURCE_DIR ) + "/qml"; + QString appSrc = QString( GALLERY_SOURCE_DIR ) + "/../app/qml"; - // Watch the SOURCE directories instead of the destination - _watcher->addPath( gallerySrc ); - _watcher->addPath( gallerySrc + "/Pages" ); + // Watch the SOURCE directories instead of the destination + _watcher->addPath( gallerySrc ); + _watcher->addPath( gallerySrc + "/Pages" ); - _watcher->addPath( appSrc + "/account" ); - _watcher->addPath( appSrc + "/account/components" ); - _watcher->addPath( appSrc + "/components" ); - _watcher->addPath( appSrc + "/dialogs" ); - _watcher->addPath( appSrc + "/form" ); - _watcher->addPath( appSrc + "/form/components" ); - _watcher->addPath( appSrc + "/form/editors" ); - _watcher->addPath( appSrc + "/gps" ); - _watcher->addPath( appSrc + "/inputs" ); - _watcher->addPath( appSrc + "/layers" ); - _watcher->addPath( appSrc + "/map" ); - _watcher->addPath( appSrc + "/project" ); - _watcher->addPath( appSrc + "/project/components" ); - _watcher->addPath( appSrc + "/settings" ); - _watcher->addPath( appSrc + "/settings/components" ); + _watcher->addPath( appSrc + "/account" ); + _watcher->addPath( appSrc + "/account/components" ); + _watcher->addPath( appSrc + "/components" ); + _watcher->addPath( appSrc + "/dialogs" ); + _watcher->addPath( appSrc + "/form" ); + _watcher->addPath( appSrc + "/form/components" ); + _watcher->addPath( appSrc + "/form/editors" ); + _watcher->addPath( appSrc + "/gps" ); + _watcher->addPath( appSrc + "/inputs" ); + _watcher->addPath( appSrc + "/layers" ); + _watcher->addPath( appSrc + "/map" ); + _watcher->addPath( appSrc + "/project" ); + _watcher->addPath( appSrc + "/project/components" ); + _watcher->addPath( appSrc + "/settings" ); + _watcher->addPath( appSrc + "/settings/components" ); - // When you save a file in your IDE, start the debounce timer - connect( _watcher, &QFileSystemWatcher::directoryChanged, this, [this]( const QString & path ) - { - _debounceTimer->start(); - } ); + // when you save the file, start the debounce timer + connect( _watcher, &QFileSystemWatcher::directoryChanged, this, [this]( const QString & path ) + { + _debounceTimer->start(); + } ); - // Connect fileChanged as well, just in case macOS watches specific files instead of dirs - connect( _watcher, &QFileSystemWatcher::fileChanged, this, [this]( const QString & path ) - { - _debounceTimer->start(); - } ); + connect( _watcher, &QFileSystemWatcher::fileChanged, this, [this]( const QString & path ) + { + _debounceTimer->start(); + } ); } diff --git a/gallery/hotreload.h b/gallery/hotreload.h index 224bb9039..fa8b62628 100644 --- a/gallery/hotreload.h +++ b/gallery/hotreload.h @@ -35,7 +35,7 @@ class HotReload : public QObject private: QFileSystemWatcher *_watcher; QQmlApplicationEngine &_engine; - QTimer* _debounceTimer = nullptr; + QTimer *_debounceTimer = nullptr; }; #endif // HOTRELOAD_H From 2164925389896798f84456dfeb12da6b0acb2244 Mon Sep 17 00:00:00 2001 From: Gabriel Bolbotina Date: Mon, 2 Mar 2026 09:03:15 +0200 Subject: [PATCH 3/3] Added timer to delete cache and hot reload --- gallery/qml/Main.qml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/gallery/qml/Main.qml b/gallery/qml/Main.qml index 878a1bf5e..78d05319c 100644 --- a/gallery/qml/Main.qml +++ b/gallery/qml/Main.qml @@ -25,15 +25,29 @@ ApplicationWindow { property string currentPageSource: "InitialGalleryPage.qml" + Timer { + id: reloadTimer + interval: 50 + onTriggered: { + // delete the cache after 50ms + _hotReload.clearCache() + + mainLoader.source = Qt.binding(function () { + return (__isMobile ? "qrc:/qml/pages/" : ("file://" + _qmlWrapperPath)) + window.currentPageSource + }) + mainLoader.active = true + + console.log(new Date().toLocaleTimeString().split(' ')[0] + " ------ App reloaded 🔥 ------ ") + } + } Connections { target: __isMobile ? null : _hotReload enabled: !__isMobile function onWatchedSourceChanged() { mainLoader.active = false + mainLoader.setSource("") _hotReload.clearCache() - mainLoader.setSource("file:///" + _qmlWrapperPath + currentPageSource) - mainLoader.active = true - console.log( new Date().toLocaleTimeString().split(' ')[0] + " ------ App reloaded 🔥 ------ ") + reloadTimer.start() } }