feat: loading indicator

This commit is contained in:
2025-08-07 01:12:03 +02:00
parent 44f2753ae9
commit 289db0cbd8
10 changed files with 197 additions and 18 deletions
+1
View File
@@ -29,6 +29,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
src/images_carousel.h src/images_carousel.cpp src/designer/images_carousel.ui src/images_carousel.h src/images_carousel.cpp src/designer/images_carousel.ui
src/config.h src/config.cpp src/config.h src/config.cpp
src/logger.h src/logger.h
src/loading_indicator.h src/loading_indicator.cpp src/designer/loading_indicator.ui
) )
# Define target properties for Android with Qt 6 as: # Define target properties for Android with Qt 6 as:
# set_property(TARGET wallpaper_chooser APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR # set_property(TARGET wallpaper_chooser APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
+3 -1
View File
@@ -4,7 +4,9 @@
"~/Pictures/116327446_p0.jpg" "~/Pictures/116327446_p0.jpg"
], ],
"dirs": [ "dirs": [
"~/.config/backgrounds" "~/.config/backgrounds",
"/media/Beta/3-Anime/图集/绿色健康.2/绿色健康.2",
"/media/Beta/壁纸/库"
], ],
"excludes": [ "excludes": [
"~/.config/backgrounds/nao-stars-crop-adjust-flop.jpg", "~/.config/backgrounds/nao-stars-crop-adjust-flop.jpg",
+63
View File
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoadingIndicator</class>
<widget class="QWidget" name="LoadingIndicator">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>795</width>
<height>653</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QProgressBar" name="progressBar">
<property name="maximumSize">
<size>
<width>500</width>
<height>16777215</height>
</size>
</property>
<property name="value">
<number>24</number>
</property>
<property name="textVisible">
<bool>true</bool>
</property>
<property name="format">
<string>%v/%m</string>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+10
View File
@@ -68,6 +68,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item> <item>
<widget class="QWidget" name="actions" native="true"> <widget class="QWidget" name="actions" native="true">
<property name="minimumSize"> <property name="minimumSize">
+18 -8
View File
@@ -1,7 +1,7 @@
/* /*
* @Author: Uyanide pywang0608@foxmail.com * @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-05 01:22:53 * @Date: 2025-08-05 01:22:53
* @LastEditTime: 2025-08-07 00:22:29 * @LastEditTime: 2025-08-07 00:50:11
* @Description: Animated carousel widget for displaying and selecting images. * @Description: Animated carousel widget for displaying and selecting images.
*/ */
#include "images_carousel.h" #include "images_carousel.h"
@@ -46,13 +46,9 @@ ImagesCarousel::ImagesCarousel(const double itemAspectRatio,
// Load initial images // Load initial images
connect(this, connect(this,
&ImagesCarousel::imagesLoaded, &ImagesCarousel::loadingCompleted,
this, this,
[this]() { &ImagesCarousel::_onInitImagesLoaded);
_focusCurrImage();
// exit(0); // for speed test
disconnect(this, &ImagesCarousel::imagesLoaded, this, nullptr);
});
// Auto focus when scrolling // Auto focus when scrolling
m_scrollDebounceTimer = new QTimer(this); m_scrollDebounceTimer = new QTimer(this);
@@ -76,6 +72,15 @@ ImagesCarousel::ImagesCarousel(const double itemAspectRatio,
}); });
} }
void ImagesCarousel::_onInitImagesLoaded() {
disconnect(this, &ImagesCarousel::loadingCompleted, this, &ImagesCarousel::_onInitImagesLoaded);
if (m_loadedImages.isEmpty()) {
return;
}
m_currentIndex = 0;
_focusCurrImage();
}
ImagesCarousel::~ImagesCarousel() { ImagesCarousel::~ImagesCarousel() {
delete ui; delete ui;
// memory of items in m_loadedImages managed by Qt parent-child system // memory of items in m_loadedImages managed by Qt parent-child system
@@ -91,6 +96,7 @@ void ImagesCarousel::appendImages(const QStringList& paths) {
QMutexLocker locker(&m_imageCountMutex); QMutexLocker locker(&m_imageCountMutex);
m_imageCount += paths.size(); m_imageCount += paths.size();
} }
emit loadingStarted(paths.size());
for (const QString& path : paths) { for (const QString& path : paths) {
ImageLoader* loader = new ImageLoader(path, this); ImageLoader* loader = new ImageLoader(path, this);
QThreadPool::globalInstance()->start(loader); QThreadPool::globalInstance()->start(loader);
@@ -146,10 +152,11 @@ void ImagesCarousel::_insertImage(const ImageData* data) {
m_loadedImages.insert(inserPos, item); m_loadedImages.insert(inserPos, item);
m_imagesLayout->insertWidget(inserPos, item); m_imagesLayout->insertWidget(inserPos, item);
emit imageLoaded(m_loadedImages.size());
{ {
QMutexLocker countLocker(&m_imageCountMutex); QMutexLocker countLocker(&m_imageCountMutex);
if (m_loadedImages.size() >= m_imageCount) { if (m_loadedImages.size() >= m_imageCount) {
emit imagesLoaded(); emit loadingCompleted(m_loadedImages.size());
} }
} }
} }
@@ -266,6 +273,9 @@ void ImagesCarousel::_onItemClicked(int index) {
// if (m_suppressAutoFocus) return; // if (m_suppressAutoFocus) return;
_unfocusCurrImage(); _unfocusCurrImage();
m_currentIndex = index; m_currentIndex = index;
if (index < 0 || index >= m_loadedImages.size()) {
return; // Out of bounds
}
_focusCurrImage(); _focusCurrImage();
} }
+5 -2
View File
@@ -1,7 +1,7 @@
/* /*
* @Author: Uyanide pywang0608@foxmail.com * @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-05 01:22:53 * @Date: 2025-08-05 01:22:53
* @LastEditTime: 2025-08-07 00:27:03 * @LastEditTime: 2025-08-07 00:52:14
* @Description: Animated carousel widget for displaying and selecting images. * @Description: Animated carousel widget for displaying and selecting images.
*/ */
#ifndef IMAGES_CAROUSEL_H #ifndef IMAGES_CAROUSEL_H
@@ -144,6 +144,7 @@ class ImagesCarousel : public QWidget {
void _unfocusCurrImage(); void _unfocusCurrImage();
void _onScrollBarValueChanged(int value); void _onScrollBarValueChanged(int value);
void _onItemClicked(int index); void _onItemClicked(int index);
void _onInitImagesLoaded();
public: public:
void void
@@ -168,7 +169,9 @@ class ImagesCarousel : public QWidget {
signals: signals:
void imageFocused(const QString& path, const int index, const int count); void imageFocused(const QString& path, const int index, const int count);
void imagesLoaded(); void loadingStarted(const qsizetype amount);
void loadingCompleted(const qsizetype amount);
void imageLoaded(const qsizetype count);
}; };
class ImagesCarouselScrollArea : public QScrollArea { class ImagesCarouselScrollArea : public QScrollArea {
+16
View File
@@ -0,0 +1,16 @@
/*
* @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-07 00:32:25
* @LastEditTime: 2025-08-07 01:09:49
* @Description: A loading indicator widget with a progress bar.
*/
#include "loading_indicator.h"
LoadingIndicator::LoadingIndicator(QWidget *parent) : QWidget(parent),
ui(new Ui::LoadingIndicator) {
ui->setupUi(this);
}
LoadingIndicator::~LoadingIndicator() {
delete ui;
}
+33
View File
@@ -0,0 +1,33 @@
/*
* @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-07 00:32:25
* @LastEditTime: 2025-08-07 01:00:29
* @Description: LoadingIndicator implementation.
*/
#ifndef LOADING_INDICATOR_H
#define LOADING_INDICATOR_H
#include <QWidget>
#include "ui_loading_indicator.h"
namespace Ui {
class LoadingIndicator;
}
class LoadingIndicator : public QWidget {
Q_OBJECT
public:
explicit LoadingIndicator(QWidget *parent = nullptr);
~LoadingIndicator();
void setMaximum(int max) { ui->progressBar->setMaximum(max); }
void setValue(int value) { ui->progressBar->setValue(value); }
private:
Ui::LoadingIndicator *ui;
};
#endif // LOADING_INDICATOR_H
+41 -5
View File
@@ -1,7 +1,7 @@
/* /*
* @Author: Uyanide pywang0608@foxmail.com * @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-05 00:37:58 * @Date: 2025-08-05 00:37:58
* @LastEditTime: 2025-08-06 02:16:25 * @LastEditTime: 2025-08-07 01:08:55
* @Description: MainWindow implementation. * @Description: MainWindow implementation.
*/ */
#include "main_window.h" #include "main_window.h"
@@ -33,7 +33,8 @@ MainWindow::~MainWindow() {
} }
void MainWindow::_setupUI() { void MainWindow::_setupUI() {
// insert images carousel
// create images carousel
m_carousel = new ImagesCarousel( m_carousel = new ImagesCarousel(
m_config.getStyleAspectRatio(), m_config.getStyleAspectRatio(),
m_config.getStyleImageWidth(), m_config.getStyleImageWidth(),
@@ -42,14 +43,40 @@ void MainWindow::_setupUI() {
m_config.isSortReverse(), m_config.isSortReverse(),
this); this);
ui->mainLayout->insertWidget(2, m_carousel); ui->mainLayout->insertWidget(2, m_carousel);
connect(m_carousel, &ImagesCarousel::imageFocused, this, &MainWindow::_onImageFocused); connect(m_carousel,
&ImagesCarousel::imageFocused,
this,
&MainWindow::_onImageFocused);
m_carouselIndex = ui->stackedWidget->addWidget(m_carousel);
// create loading indicator
m_loadingIndicator = new LoadingIndicator(this);
connect(m_carousel,
&ImagesCarousel::loadingStarted,
this,
&MainWindow::_onLoadingStarted);
connect(m_carousel,
&ImagesCarousel::loadingCompleted,
this,
&MainWindow::_onLoadingCompleted);
connect(m_carousel,
&ImagesCarousel::imageLoaded,
m_loadingIndicator,
&LoadingIndicator::setValue);
m_loadingIndicatorIndex = ui->stackedWidget->addWidget(m_loadingIndicator);
// set window size // set window size
setMinimumSize(m_config.getStyleWindowWidth(), m_config.getStyleWindowHeight()); setMinimumSize(m_config.getStyleWindowWidth(), m_config.getStyleWindowHeight());
setMaximumSize(m_config.getStyleWindowWidth(), m_config.getStyleWindowHeight()); setMaximumSize(m_config.getStyleWindowWidth(), m_config.getStyleWindowHeight());
connect(ui->confirmButton, &QPushButton::clicked, this, &MainWindow::onConfirm); connect(ui->confirmButton,
connect(ui->cancelButton, &QPushButton::clicked, this, &MainWindow::onCancel); &QPushButton::clicked,
this,
&MainWindow::onConfirm);
connect(ui->cancelButton,
&QPushButton::clicked,
this,
&MainWindow::onCancel);
ui->confirmButton->setFocusPolicy(Qt::NoFocus); ui->confirmButton->setFocusPolicy(Qt::NoFocus);
ui->cancelButton->setFocusPolicy(Qt::NoFocus); ui->cancelButton->setFocusPolicy(Qt::NoFocus);
@@ -111,3 +138,12 @@ void MainWindow::onCancel() {
void MainWindow::_onImageFocused(const QString &path, const int index, const int count) { void MainWindow::_onImageFocused(const QString &path, const int index, const int count) {
ui->topLabel->setText(QString("%1 (%2/%3)").arg(splitNameFromPath(path)).arg(index + 1).arg(count)); ui->topLabel->setText(QString("%1 (%2/%3)").arg(splitNameFromPath(path)).arg(index + 1).arg(count));
} }
void MainWindow::_onLoadingStarted(const qsizetype amount) {
m_loadingIndicator->setMaximum(amount);
ui->stackedWidget->setCurrentIndex(m_loadingIndicatorIndex);
}
void MainWindow::_onLoadingCompleted(const qsizetype amount) {
ui->stackedWidget->setCurrentIndex(m_carouselIndex);
}
+6 -1
View File
@@ -1,7 +1,7 @@
/* /*
* @Author: Uyanide pywang0608@foxmail.com * @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-05 00:37:58 * @Date: 2025-08-05 00:37:58
* @LastEditTime: 2025-08-06 02:13:47 * @LastEditTime: 2025-08-07 01:08:12
* @Description: MainWindow implementation. * @Description: MainWindow implementation.
*/ */
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
@@ -11,6 +11,7 @@
#include "config.h" #include "config.h"
#include "images_carousel.h" #include "images_carousel.h"
#include "loading_indicator.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -40,10 +41,14 @@ class MainWindow : public QMainWindow {
private slots: private slots:
void _onImageFocused(const QString &path, const int index, const int count); void _onImageFocused(const QString &path, const int index, const int count);
void _onLoadingStarted(const qsizetype amount);
void _onLoadingCompleted(const qsizetype amount);
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
ImagesCarousel *m_carousel = nullptr; ImagesCarousel *m_carousel = nullptr;
LoadingIndicator *m_loadingIndicator = nullptr;
int m_carouselIndex, m_loadingIndicatorIndex;
const Config &m_config; const Config &m_config;
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H