feat: loading indicator
This commit is contained in:
@@ -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
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user