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/config.h src/config.cpp
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:
# set_property(TARGET wallpaper_chooser APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
+3 -1
View File
@@ -4,7 +4,9 @@
"~/Pictures/116327446_p0.jpg"
],
"dirs": [
"~/.config/backgrounds"
"~/.config/backgrounds",
"/media/Beta/3-Anime/图集/绿色健康.2/绿色健康.2",
"/media/Beta/壁纸/库"
],
"excludes": [
"~/.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>
</widget>
</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>
<widget class="QWidget" name="actions" native="true">
<property name="minimumSize">
+18 -8
View File
@@ -1,7 +1,7 @@
/*
* @Author: Uyanide pywang0608@foxmail.com
* @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.
*/
#include "images_carousel.h"
@@ -46,13 +46,9 @@ ImagesCarousel::ImagesCarousel(const double itemAspectRatio,
// Load initial images
connect(this,
&ImagesCarousel::imagesLoaded,
&ImagesCarousel::loadingCompleted,
this,
[this]() {
_focusCurrImage();
// exit(0); // for speed test
disconnect(this, &ImagesCarousel::imagesLoaded, this, nullptr);
});
&ImagesCarousel::_onInitImagesLoaded);
// Auto focus when scrolling
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() {
delete ui;
// 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);
m_imageCount += paths.size();
}
emit loadingStarted(paths.size());
for (const QString& path : paths) {
ImageLoader* loader = new ImageLoader(path, this);
QThreadPool::globalInstance()->start(loader);
@@ -146,10 +152,11 @@ void ImagesCarousel::_insertImage(const ImageData* data) {
m_loadedImages.insert(inserPos, item);
m_imagesLayout->insertWidget(inserPos, item);
emit imageLoaded(m_loadedImages.size());
{
QMutexLocker countLocker(&m_imageCountMutex);
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;
_unfocusCurrImage();
m_currentIndex = index;
if (index < 0 || index >= m_loadedImages.size()) {
return; // Out of bounds
}
_focusCurrImage();
}
+5 -2
View File
@@ -1,7 +1,7 @@
/*
* @Author: Uyanide pywang0608@foxmail.com
* @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.
*/
#ifndef IMAGES_CAROUSEL_H
@@ -144,6 +144,7 @@ class ImagesCarousel : public QWidget {
void _unfocusCurrImage();
void _onScrollBarValueChanged(int value);
void _onItemClicked(int index);
void _onInitImagesLoaded();
public:
void
@@ -168,7 +169,9 @@ class ImagesCarousel : public QWidget {
signals:
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 {
+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
* @Date: 2025-08-05 00:37:58
* @LastEditTime: 2025-08-06 02:16:25
* @LastEditTime: 2025-08-07 01:08:55
* @Description: MainWindow implementation.
*/
#include "main_window.h"
@@ -33,7 +33,8 @@ MainWindow::~MainWindow() {
}
void MainWindow::_setupUI() {
// insert images carousel
// create images carousel
m_carousel = new ImagesCarousel(
m_config.getStyleAspectRatio(),
m_config.getStyleImageWidth(),
@@ -42,14 +43,40 @@ void MainWindow::_setupUI() {
m_config.isSortReverse(),
this);
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
setMinimumSize(m_config.getStyleWindowWidth(), m_config.getStyleWindowHeight());
setMaximumSize(m_config.getStyleWindowWidth(), m_config.getStyleWindowHeight());
connect(ui->confirmButton, &QPushButton::clicked, this, &MainWindow::onConfirm);
connect(ui->cancelButton, &QPushButton::clicked, this, &MainWindow::onCancel);
connect(ui->confirmButton,
&QPushButton::clicked,
this,
&MainWindow::onConfirm);
connect(ui->cancelButton,
&QPushButton::clicked,
this,
&MainWindow::onCancel);
ui->confirmButton->setFocusPolicy(Qt::NoFocus);
ui->cancelButton->setFocusPolicy(Qt::NoFocus);
@@ -110,4 +137,13 @@ void MainWindow::onCancel() {
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));
}
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);
}
+7 -2
View File
@@ -1,7 +1,7 @@
/*
* @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-05 00:37:58
* @LastEditTime: 2025-08-06 02:13:47
* @LastEditTime: 2025-08-07 01:08:12
* @Description: MainWindow implementation.
*/
#ifndef MAINWINDOW_H
@@ -11,6 +11,7 @@
#include "config.h"
#include "images_carousel.h"
#include "loading_indicator.h"
QT_BEGIN_NAMESPACE
@@ -40,10 +41,14 @@ class MainWindow : public QMainWindow {
private slots:
void _onImageFocused(const QString &path, const int index, const int count);
void _onLoadingStarted(const qsizetype amount);
void _onLoadingCompleted(const qsizetype amount);
private:
Ui::MainWindow *ui;
ImagesCarousel *m_carousel = nullptr;
ImagesCarousel *m_carousel = nullptr;
LoadingIndicator *m_loadingIndicator = nullptr;
int m_carouselIndex, m_loadingIndicatorIndex;
const Config &m_config;
};
#endif // MAINWINDOW_H