diff --git a/storybook/CMakeLists.txt b/storybook/CMakeLists.txt index d15f0bfe14..c0d8ac14ef 100644 --- a/storybook/CMakeLists.txt +++ b/storybook/CMakeLists.txt @@ -20,14 +20,15 @@ find_package( COMPONENTS Core Quick QuickControls2 REQUIRED) -file(GLOB_RECURSE QML_FILES "stubs/*.qml" "mocks/*.qml" "Storybook/*.qml" "../ui/StatusQ/*.qml" "../ui/app/*.qml") +file(GLOB_RECURSE QML_FILES "stubs/*.qml" "mocks/*.qml" "pages/*.qml" "src/*.qml" "src/qmldir" "../ui/StatusQ/*.qml" "../ui/app/*.qml") file(GLOB_RECURSE JS_FILES "../ui/StatusQ/*.js" "../ui/app/*.js") add_executable( ${PROJECT_NAME} main.cpp - qml.qrc - ${QML_FILES} + cachecleaner.cpp cachecleaner.h + directorieswatcher.cpp directorieswatcher.h + ${QML_FILES} main.qml ${JS_FILES} ) @@ -37,7 +38,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick Qt5::QuickControls2 SortFilterProxyModel) -set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR} CACHE STRING "" FORCE) +set(QML_IMPORT_PATH "${CMAKE_SOURCE_DIR}/src" CACHE STRING "" FORCE) if (APPLE) find_library(AppKit AppKit) diff --git a/storybook/cachecleaner.cpp b/storybook/cachecleaner.cpp new file mode 100644 index 0000000000..15c0a442e9 --- /dev/null +++ b/storybook/cachecleaner.cpp @@ -0,0 +1,12 @@ +#include "cachecleaner.h" + +#include + +CacheCleaner::CacheCleaner(QQmlEngine* engine) + : engine(engine) +{ +} + +void CacheCleaner::clearComponentCache() const { + engine->clearComponentCache(); +} diff --git a/storybook/cachecleaner.h b/storybook/cachecleaner.h new file mode 100644 index 0000000000..349d2b35ef --- /dev/null +++ b/storybook/cachecleaner.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +class QQmlEngine; + +class CacheCleaner : public QObject +{ + Q_OBJECT +public: + explicit CacheCleaner(QQmlEngine* engine); + Q_INVOKABLE void clearComponentCache() const; + +private: + QQmlEngine* engine; +}; diff --git a/storybook/directorieswatcher.cpp b/storybook/directorieswatcher.cpp new file mode 100644 index 0000000000..8a8b56bdc4 --- /dev/null +++ b/storybook/directorieswatcher.cpp @@ -0,0 +1,29 @@ +#include "directorieswatcher.h" + +#include +#include + +DirectoriesWatcher::DirectoriesWatcher(QObject *parent) + : QObject{parent}, fsWatcher(new QFileSystemWatcher(this)) +{ + connect(fsWatcher, &QFileSystemWatcher::directoryChanged, + this, &DirectoriesWatcher::changed); +} + +void DirectoriesWatcher::addPaths(const QStringList &paths) +{ + for (auto& path : paths) { + QDirIterator it(path, QDir::AllDirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + + while (it.hasNext()) { + const auto& subpath = it.filePath(); + + if (!subpath.isEmpty()) + fsWatcher->addPath(subpath); + + it.next(); + } + + fsWatcher->addPath(path); + } +} diff --git a/storybook/directorieswatcher.h b/storybook/directorieswatcher.h new file mode 100644 index 0000000000..e23cbc730f --- /dev/null +++ b/storybook/directorieswatcher.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +class QFileSystemWatcher; + +class DirectoriesWatcher : public QObject +{ + Q_OBJECT +public: + explicit DirectoriesWatcher(QObject *parent = nullptr); + void addPaths(const QStringList &paths); + +signals: + void changed(); + +private: + QFileSystemWatcher* fsWatcher; +}; diff --git a/storybook/main.cpp b/storybook/main.cpp index 375c299354..086da4baf4 100644 --- a/storybook/main.cpp +++ b/storybook/main.cpp @@ -1,6 +1,10 @@ #include #include +#include +#include +#include +#include int main(int argc, char *argv[]) { @@ -14,14 +18,36 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; - engine.addImportPath(QStringLiteral(":/")); - engine.addImportPath(SRC_DIR + QStringLiteral("/../ui/StatusQ/src")); - engine.addImportPath(SRC_DIR + QStringLiteral("/../ui/app")); - engine.addImportPath(SRC_DIR + QStringLiteral("/../ui/imports")); - engine.addImportPath(SRC_DIR + QStringLiteral("/stubs")); - engine.addImportPath(SRC_DIR + QStringLiteral("/mocks")); + QStringList additionalImportPaths { + SRC_DIR + QStringLiteral("/../ui/StatusQ/src"), + SRC_DIR + QStringLiteral("/../ui/app"), + SRC_DIR + QStringLiteral("/../ui/imports"), + SRC_DIR + QStringLiteral("/src"), + SRC_DIR + QStringLiteral("/pages"), + SRC_DIR + QStringLiteral("/stubs"), + SRC_DIR + QStringLiteral("/mocks"), + }; - const QUrl url(QStringLiteral("qrc:/main.qml")); + for (auto& path : additionalImportPaths) + engine.addImportPath(path); + + auto watcherFactory = [additionalImportPaths](QQmlEngine*, QJSEngine*) { + auto watcher = new DirectoriesWatcher(); + watcher->addPaths(additionalImportPaths); + return watcher; + }; + + qmlRegisterSingletonType( + "Storybook", 1, 0, "SourceWatcher", watcherFactory); + + auto cleanerFactory = [](QQmlEngine* engine, QJSEngine*) { + return new CacheCleaner(engine); + }; + + qmlRegisterSingletonType( + "Storybook", 1, 0, "CacheCleaner", cleanerFactory); + + const QUrl url(SRC_DIR + QStringLiteral("/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) diff --git a/storybook/main.qml b/storybook/main.qml index 85a7a0e3b5..6fca539964 100644 --- a/storybook/main.qml +++ b/storybook/main.qml @@ -18,6 +18,13 @@ ApplicationWindow { font.pixelSize: 13 + HotReloader { + loader: viewLoader + enabled: hotReloadingCheckBox.checked + + onReloaded: reloadingAnimation.restart() + } + ListModel { id: pagesModel @@ -63,6 +70,31 @@ ApplicationWindow { } } + CheckBox { + id: hotReloadingCheckBox + + Layout.fillWidth: true + + text: "Hot reloading" + + Rectangle { + anchors.fill: parent + border.color: "red" + border.width: 2 + opacity: 0 + + OpacityAnimator on opacity { + id: reloadingAnimation + + running: false + from: 1 + to: 0 + duration: 500 + easing.type: Easing.InQuad + } + } + } + Pane { Layout.fillWidth: true Layout.fillHeight: true @@ -87,7 +119,7 @@ ApplicationWindow { anchors.fill: parent clip: true - source: Qt.resolvedUrl(`./pages/${root.currentPage}Page.qml`) + source: `pages/${root.currentPage}Page.qml` asynchronous: loadAsyncCheckBox.checked visible: status === Loader.Ready @@ -109,5 +141,6 @@ ApplicationWindow { property alias currentPage: root.currentPage property alias loadAsynchronously: loadAsyncCheckBox.checked property alias darkMode: darkModeCheckBox.checked + property alias hotReloading: hotReloadingCheckBox.checked } } diff --git a/storybook/qml.qrc b/storybook/qml.qrc deleted file mode 100644 index e0823d2e86..0000000000 --- a/storybook/qml.qrc +++ /dev/null @@ -1,17 +0,0 @@ - - - Storybook/ImageSelectPopup.qml - Storybook/Logs.qml - Storybook/LogsAndControlsPanel.qml - Storybook/LogsView.qml - Storybook/PagesList.qml - Storybook/StorybookUtils.qml - Storybook/qmldir - main.qml - pages/CommunitiesPortalDummyModel.qml - pages/CommunitiesPortalLayoutPage.qml - pages/CommunitiesPortalModelEditor.qml - pages/LoginViewPage.qml - pages/AboutViewPage.qml - - diff --git a/storybook/Storybook/ImageSelectPopup.qml b/storybook/src/Storybook/ImageSelectPopup.qml similarity index 100% rename from storybook/Storybook/ImageSelectPopup.qml rename to storybook/src/Storybook/ImageSelectPopup.qml diff --git a/storybook/Storybook/Logs.qml b/storybook/src/Storybook/Logs.qml similarity index 100% rename from storybook/Storybook/Logs.qml rename to storybook/src/Storybook/Logs.qml diff --git a/storybook/Storybook/LogsAndControlsPanel.qml b/storybook/src/Storybook/LogsAndControlsPanel.qml similarity index 100% rename from storybook/Storybook/LogsAndControlsPanel.qml rename to storybook/src/Storybook/LogsAndControlsPanel.qml diff --git a/storybook/Storybook/LogsView.qml b/storybook/src/Storybook/LogsView.qml similarity index 100% rename from storybook/Storybook/LogsView.qml rename to storybook/src/Storybook/LogsView.qml diff --git a/storybook/Storybook/PagesList.qml b/storybook/src/Storybook/PagesList.qml similarity index 100% rename from storybook/Storybook/PagesList.qml rename to storybook/src/Storybook/PagesList.qml diff --git a/storybook/Storybook/StorybookUtils.qml b/storybook/src/Storybook/StorybookUtils.qml similarity index 100% rename from storybook/Storybook/StorybookUtils.qml rename to storybook/src/Storybook/StorybookUtils.qml diff --git a/storybook/Storybook/qmldir b/storybook/src/Storybook/qmldir similarity index 86% rename from storybook/Storybook/qmldir rename to storybook/src/Storybook/qmldir index e4f6e61526..f5076f977e 100644 --- a/storybook/Storybook/qmldir +++ b/storybook/src/Storybook/qmldir @@ -1,3 +1,4 @@ +HotReloader 1.0 HotReloader.qml ImageSelectPopup 1.0 ImageSelectPopup.qml Logs 1.0 Logs.qml LogsAndControlsPanel 1.0 LogsAndControlsPanel.qml