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/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
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
</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
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
* @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);
|
||||||
|
|
||||||
@@ -110,4 +137,13 @@ 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);
|
||||||
}
|
}
|
||||||
+7
-2
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user