From d39e36e09691381f95d9cfebdd1e76a8dc0ae125 Mon Sep 17 00:00:00 2001 From: Uyanide Date: Sun, 5 Apr 2026 19:22:12 +0200 Subject: [PATCH] feat: add reload button to force 'reload from disk' --- CMakeLists.txt | 2 +- WallReel/Core/Config/manager.cpp | 5 +---- WallReel/Core/Config/manager.hpp | 4 ++-- WallReel/Core/Image/manager.cpp | 22 ++++++++++++++++++++++ WallReel/Core/Image/manager.hpp | 8 ++++++++ WallReel/Core/Provider/bootstrap.hpp | 3 ++- WallReel/Core/Provider/carousel.hpp | 4 ++++ WallReel/UI/CMakeLists.txt | 1 + WallReel/UI/Modules/ReloadButton.qml | 17 +++++++++++++++++ WallReel/UI/Modules/TopBar.qml | 9 +++++++++ WallReel/UI/Pages/CarouselScreen.qml | 5 +++++ 11 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 WallReel/UI/Modules/ReloadButton.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cb7a36..a3f170a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(WallReel VERSION 2.1.0 LANGUAGES CXX) +project(WallReel VERSION 2.2.0 LANGUAGES CXX) set(EXECUTABLE_NAME "wallreel") set(CORELIB_NAME "wallreel-core") diff --git a/WallReel/Core/Config/manager.cpp b/WallReel/Core/Config/manager.cpp index 6da0d2d..a8fda07 100644 --- a/WallReel/Core/Config/manager.cpp +++ b/WallReel/Core/Config/manager.cpp @@ -54,9 +54,6 @@ Manager::Manager( WR_INFO(QString("No search directories specified, using Pictures directory: %1").arg(picturesPath)); m_wallpaperConfig.dirs.append({picturesPath, true}); } - - WR_DEBUG("Loading wallpapers ..."); - _loadWallpapers(); } Manager::~Manager() { @@ -324,7 +321,7 @@ void Manager::_loadCacheConfig(const QJsonObject& root) { } } -void Manager::_loadWallpapers() { +void Manager::scanWallpapers() { m_wallpapers.clear(); // Add paths first using a set to avoid duplicates diff --git a/WallReel/Core/Config/manager.hpp b/WallReel/Core/Config/manager.hpp index 15b6b5e..3167b51 100644 --- a/WallReel/Core/Config/manager.hpp +++ b/WallReel/Core/Config/manager.hpp @@ -72,6 +72,8 @@ class Manager : public QObject { */ Q_INVOKABLE void captureState(); + void scanWallpapers(); + signals: void stateCaptured(); @@ -83,8 +85,6 @@ class Manager : public QObject { void _loadActionConfig(const QJsonObject& config); void _loadStyleConfig(const QJsonObject& config); void _loadCacheConfig(const QJsonObject& config); - // Load wallpapers - void _loadWallpapers(); // Callback for state capture results void _onCaptureResult(const QString& key, const QString& value); diff --git a/WallReel/Core/Image/manager.cpp b/WallReel/Core/Image/manager.cpp index 9cdfd89..7a0f055 100644 --- a/WallReel/Core/Image/manager.cpp +++ b/WallReel/Core/Image/manager.cpp @@ -9,10 +9,12 @@ WALLREEL_DECLARE_SENDER("ImageManager") WallReel::Core::Image::Manager::Manager( + Config::Manager& configMgr, Cache::Manager& cacheMgr, const QSize& thumbnailSize, QObject* parent) : QObject(parent), + m_configMgr(configMgr), m_cacheMgr(cacheMgr), m_thumbnailSize(thumbnailSize) { m_dataModel = new Model(this); @@ -38,6 +40,21 @@ WallReel::Core::Image::Manager::~Manager() { m_watcher.waitForFinished(); } +void WallReel::Core::Image::Manager::loadAndProcess() { + if (m_isLoading) { + WR_WARN("Already loading images. Ignoring new load request."); + return; + } + m_isLoading = true; + emit isLoadingChanged(); + + _clearData(); + + m_configMgr.scanWallpapers(); + const auto paths = m_configMgr.getWallpapers(); + return _process(paths); +} + void WallReel::Core::Image::Manager::loadAndProcess(const QStringList& paths) { if (m_isLoading) { WR_WARN("Already loading images. Ignoring new load request."); @@ -48,6 +65,10 @@ void WallReel::Core::Image::Manager::loadAndProcess(const QStringList& paths) { _clearData(); + return _process(paths); +} + +void WallReel::Core::Image::Manager::_process(const QStringList& paths) { m_processedCount = 0; m_progressUpdateTimer.start(s_ProgressUpdateIntervalMs); // These are all small objects so capturing by value should be fine @@ -75,6 +96,7 @@ void WallReel::Core::Image::Manager::stop() { void WallReel::Core::Image::Manager::_clearData() { m_dataModel->clearData(); + m_dataMap.clear(); } void WallReel::Core::Image::Manager::_onProgressValueChanged(int value) { diff --git a/WallReel/Core/Image/manager.hpp b/WallReel/Core/Image/manager.hpp index bb1a0a0..9222f46 100644 --- a/WallReel/Core/Image/manager.hpp +++ b/WallReel/Core/Image/manager.hpp @@ -8,6 +8,7 @@ #include #include "Cache/manager.hpp" +#include "Config/manager.hpp" #include "data.hpp" #include "model.hpp" @@ -20,6 +21,7 @@ class Manager : public QObject { // Constructor / Destructor Manager( + Config::Manager& configMgr, Cache::Manager& cacheMgr, const QSize& thumbnailSize, QObject* parent = nullptr); @@ -32,6 +34,8 @@ class Manager : public QObject { int processedCount() const { return m_processedCount.load(std::memory_order_relaxed); } + // Total count of processing items, NOT the count of items in the model + // (Why did I name this method like this? idk) int totalCount() const { return m_watcher.progressMaximum(); } void setSortType(Config::SortType type) { m_proxyModel->setSortType(type); } @@ -46,6 +50,8 @@ class Manager : public QObject { QString searchText() const { return m_proxyModel->getSearchText(); } + void loadAndProcess(); + void loadAndProcess(const QStringList& paths); void stop(); @@ -59,6 +65,7 @@ class Manager : public QObject { private: void _clearData(); + void _process(const QStringList& paths); signals: // Properties @@ -75,6 +82,7 @@ class Manager : public QObject { ProxyModel* m_proxyModel; QHash m_dataMap; + Config::Manager& m_configMgr; Cache::Manager& m_cacheMgr; QSize m_thumbnailSize; diff --git a/WallReel/Core/Provider/bootstrap.hpp b/WallReel/Core/Provider/bootstrap.hpp index 07b0495..ed8c195 100644 --- a/WallReel/Core/Provider/bootstrap.hpp +++ b/WallReel/Core/Provider/bootstrap.hpp @@ -36,6 +36,7 @@ class Bootstrap { } imageMgr = new Image::Manager( + *configMgr, *cacheMgr, configMgr->getFocusImageSize()); @@ -55,7 +56,7 @@ class Bootstrap { void start() { cacheMgr->evictOldEntries(); configMgr->captureState(); - imageMgr->loadAndProcess(configMgr->getWallpapers()); + imageMgr->loadAndProcess(); } bool apply(const QString& path) { diff --git a/WallReel/Core/Provider/carousel.hpp b/WallReel/Core/Provider/carousel.hpp index 72ef3a3..f6e1d2f 100644 --- a/WallReel/Core/Provider/carousel.hpp +++ b/WallReel/Core/Provider/carousel.hpp @@ -171,6 +171,10 @@ class Carousel : public QObject { } } + Q_INVOKABLE void requestReload() { + m_imageMgr->loadAndProcess(); + } + signals: void currentImageIdChanged(); void currentIndexChanged(); diff --git a/WallReel/UI/CMakeLists.txt b/WallReel/UI/CMakeLists.txt index 4fa72b4..6cfbd88 100644 --- a/WallReel/UI/CMakeLists.txt +++ b/WallReel/UI/CMakeLists.txt @@ -28,6 +28,7 @@ qt_add_qml_module(${UILIB_NAME}_Modules Modules/ColorControl.qml Modules/TopBar.qml Modules/BottomBar.qml + Modules/ReloadButton.qml ) qt_add_qml_module(${UILIB_NAME}_Components STATIC diff --git a/WallReel/UI/Modules/ReloadButton.qml b/WallReel/UI/Modules/ReloadButton.qml new file mode 100644 index 0000000..3a52c34 --- /dev/null +++ b/WallReel/UI/Modules/ReloadButton.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls + +ToolButton { + id: reloadBtn + + property bool isLoading: false + + icon.name: "view-refresh" + icon.width: 16 + icon.height: 16 + focusPolicy: Qt.NoFocus + ToolTip.visible: hovered + ToolTip.delay: 600 + ToolTip.text: "Reload from disk" + enabled: !isLoading +} diff --git a/WallReel/UI/Modules/TopBar.qml b/WallReel/UI/Modules/TopBar.qml index 0c37441..41c7ccb 100644 --- a/WallReel/UI/Modules/TopBar.qml +++ b/WallReel/UI/Modules/TopBar.qml @@ -14,10 +14,12 @@ Item { property alias availableSortTypes: sortCtrl.availableSortTypes property alias selectedSortType: sortCtrl.selectedSortType property alias isSortDescending: sortCtrl.isDescending + property alias isLoading: reloadBtn.isLoading signal sortTypeSelected(string sortType) signal sortDescendingToggled(bool descending) signal searchDismissed() + signal reloadRequested() function requestSearchFocus() { searchBar.requestFocus(); @@ -63,6 +65,13 @@ Item { } } + ReloadButton { + id: reloadBtn + + Layout.alignment: Qt.AlignVCenter + onClicked: root.reloadRequested() + } + } } diff --git a/WallReel/UI/Pages/CarouselScreen.qml b/WallReel/UI/Pages/CarouselScreen.qml index 80ab29e..7dfaa8e 100644 --- a/WallReel/UI/Pages/CarouselScreen.qml +++ b/WallReel/UI/Pages/CarouselScreen.qml @@ -32,6 +32,10 @@ Item { root.forceActiveFocus(); } + function onReloadRequested() { + CarouselProvider.requestReload(); + } + target: topBar } @@ -48,6 +52,7 @@ Item { title: carousel.currentImageName availableSortTypes: CarouselProvider.availableSortTypes isSortDescending: CarouselProvider.sortDescending + isLoading: CarouselProvider.isLoading onSortTypeSelected: (t) => { return CarouselProvider.setSortType(t); }