add loading screen; make RestClient a QObject

This commit is contained in:
mrbesen 2023-08-27 16:51:02 +02:00
parent e7a10f2921
commit 01e9a42482
Signed by untrusted user: MrBesen
GPG Key ID: 596B2350DCD67504
13 changed files with 226 additions and 42 deletions

View File

@ -8,6 +8,8 @@
#include "position.h"
class BlitzAPI : public RestClient {
Q_OBJECT
public:
BlitzAPI();

View File

@ -10,6 +10,8 @@
#include "runestyle.h"
class ClientAPI : public RestClient {
Q_OBJECT
public:
enum class ReadyCheckState : uint32_t {
INVALID = 0,

View File

@ -5,7 +5,6 @@
#include <mutex>
#include <set>
#include <QString>
#include <thread>
#include <vector>
#include <QPixmap>
@ -15,7 +14,11 @@
#include "memoryimagecache.h"
#include "restclient.h"
class QThread;
class DataDragon : public RestClient {
Q_OBJECT
public:
using notifyImgfunc_t = std::function<void(QPixmap)>;
@ -56,7 +59,20 @@ public:
std::vector<uint32_t> resolveChampIDs(const std::vector<QString>& champnames);
void startThread();
static const ChampData EMPTYCHAMP;
public slots:
void stop();
signals:
// loading progress in 0.0 - 1.0
void loading(float);
// which champion is currently prefretched
void fetchingChamp(QString);
protected:
QString getImageUrl(const QString& champid, ImageType type);
QString getCDNString() const;
@ -64,7 +80,6 @@ protected:
void prefetchChampImage(const QString& champid, ImageType imgtype = ImageType::SQUARE);
void getVersionInternal();
void getChampsInternal();
void startThread();
void stopThread();
void stopAndJoinThread();
void threadLoop();
@ -90,7 +105,7 @@ private:
std::list<Task> tasks;
std::mutex tasksmutex;
std::condition_variable tasksnotemptycv;
std::thread bgthread;
QThread* bgthread;
bool shouldrun = true;
};

36
include/loadingwindow.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef LOADINGWINDOW_H
#define LOADINGWINDOW_H
#include <QWidget>
class QCloseEvent;
namespace Ui {
class LoadingWindow;
}
class LoadingWindow : public QWidget {
Q_OBJECT
public:
explicit LoadingWindow( QWidget* parent = nullptr );
~LoadingWindow();
public slots:
void setChampion(QString championName);
void setText(QString text);
// should be 0.0 to 1.0
void setProgress(float val);
signals:
void closed();
protected:
virtual void closeEvent(QCloseEvent*) override;
private:
Ui::LoadingWindow* ui;
};
#endif // LOADINGWINDOW_H

View File

@ -14,6 +14,8 @@ QT_END_NAMESPACE
class QTimer;
class LoadingWindow;
class MainWindow : public QMainWindow {
Q_OBJECT
@ -32,6 +34,8 @@ public slots:
void resetSaveTimer();
private slots:
void loadingStatus(float);
void toggleMainswitch(bool);
void aatoggled(bool);
void smitewarntoggled(bool);
@ -52,11 +56,11 @@ private:
bool loading;
Ui::MainWindow *ui;
QTimer* saveTimer;
QTimer* initDoneTimer;
std::thread lolaathread;
DataDragon dd;
Config conf;
LolAutoAccept lolaa;
LoadingWindow* lwin;
};
#endif // MAINWINDOW_H

View File

@ -1,15 +1,19 @@
#pragma once
#include <QString>
#include <QJsonDocument>
#include <curl/curl.h>
#include <QObject>
#include <QJsonDocument>
#include <QString>
#ifdef Q_OS_WIN
#undef DELETE
#endif
class RestClient {
class RestClient : public QObject {
Q_OBJECT
public:
RestClient(const QString& base);
RestClient(const RestClient&) = delete;

View File

@ -49,6 +49,7 @@ SOURCES += \
src/datadragonimagecache.cpp \
src/files.cpp \
src/json.cpp \
src/loadingwindow.cpp \
src/lolautoaccept.cpp \
src/main.cpp \
src/mainwindow.cpp \
@ -84,6 +85,7 @@ HEADERS += \
include/defer.h \
include/files.h \
include/json.h \
include/loadingwindow.h \
include/lolautoaccept.h \
include/mainwindow.h \
include/memoryimagecache.h \
@ -102,6 +104,7 @@ HEADERS += \
FORMS += \
ui/championsearch.ui \
ui/clipboardpopup.ui \
ui/loadingwindow.ui \
ui/mainwindow.ui \
ui/runeaspektbutton.ui \
ui/runedisplay.ui \

View File

@ -6,8 +6,10 @@
#include <curl/easy.h>
#include <Log.h>
#include <QEventLoop>
#include <QJsonArray>
#include <QJsonObject>
#include <QThread>
#include <algorithm> // std::max, champ matching
@ -17,7 +19,7 @@ static const QString BASEURL = "https://ddragon.leagueoflegends.com/";
const DataDragon::ChampData DataDragon::EMPTYCHAMP;
DataDragon::DataDragon(const QString& locale) : RestClient(BASEURL), locale(locale), cache({{"square", ".png"}, {"loading", "_0.jpg"}, {"splash", "_0.jpg"}}) {
startThread();
this->setObjectName("DataDragon");
}
DataDragon::~DataDragon() {
@ -220,6 +222,23 @@ std::vector<uint32_t> DataDragon::resolveChampIDs(const std::vector<QString>& ch
return out;
}
void DataDragon::startThread() {
shouldrun = true;
bgthread = QThread::create(&DataDragon::threadLoop, this);
bgthread->setObjectName("DataDragonThread");
bgthread->start();
this->moveToThread(bgthread);
}
void DataDragon::stop() {
qDebug() << "stop DataDragon";
shouldrun = false;
std::unique_lock lock(tasksmutex);
tasks.clear();
notDownloadedImages.clear(); // this is a possible race condition!
}
QString DataDragon::getImageUrl(const QString& champid, ImageType type) {
switch(type) {
case ImageType::SQUARE: {
@ -317,11 +336,6 @@ void DataDragon::getChampsInternal() {
cachedatacv.notify_all();
}
void DataDragon::startThread() {
shouldrun = true;
bgthread = std::thread(&DataDragon::threadLoop, this);
}
void DataDragon::stopThread() {
shouldrun = false;
tasksnotemptycv.notify_all();
@ -330,11 +344,12 @@ void DataDragon::stopThread() {
void DataDragon::stopAndJoinThread() {
stopThread();
if(bgthread.joinable())
bgthread.join();
bgthread->wait();
}
void DataDragon::threadLoop() {
QEventLoop loop;
// init version and champ list
getVersionInternal();
getChampsInternal();
@ -350,7 +365,7 @@ void DataDragon::threadLoop() {
} else {
Log::note << "DataDragon background thread is idleing - prefetching champion images TODO: " << notDownloadedImages.size();
while(!notDownloadedImages.empty() && tasks.empty()) {
while(shouldrun && !notDownloadedImages.empty() && tasks.empty()) {
lock.unlock();
auto it = notDownloadedImages.begin();
@ -359,6 +374,9 @@ void DataDragon::threadLoop() {
prefetchChampImage(champid, ImageType::SQUARE);
emit this->loading(1.0 - (notDownloadedImages.size() / (float) champs.size()));
emit this->fetchingChamp(champid);
lock.lock();
}
@ -368,23 +386,28 @@ void DataDragon::threadLoop() {
if(!once) {
once = true;
Log::note << "all champs are prefetched now";
emit this->loading( 1.0 );
}
tasksnotemptycv.wait(lock);
}
}
}
if(tasks.empty()) continue;
t = tasks.front();
tasks.pop_front();
}
loop.processEvents();
QPixmap img = getImage(t.champid, t.type);
t.func(img);
}
}
qDebug() << "DataDragon Thread terminated";
}
std::ostream& operator<<(std::ostream& str, const DataDragon::ChampData& cd) {
return str << "[n: " << cd.name.toStdString() << " " << " k: " << cd.key << " id: " << cd.id.toStdString() << "]";

27
src/loadingwindow.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "loadingwindow.h"
#include "ui_loadingwindow.h"
LoadingWindow::LoadingWindow(QWidget* parent) : QWidget(parent), ui(new Ui::LoadingWindow) {
ui->setupUi(this);
}
LoadingWindow::~LoadingWindow() {
delete ui;
}
void LoadingWindow::setChampion(QString championName) {
this->setText(LoadingWindow::tr("Loading Champion: %0").arg(championName));
}
void LoadingWindow::setText(QString text) {
ui->label->setText(text);
}
void LoadingWindow::setProgress(float val) {
ui->progressBar->setValue(val * 100);
}
void LoadingWindow::closeEvent(QCloseEvent* event) {
QWidget::closeEvent(event);
emit this->closed();
}

View File

@ -11,9 +11,9 @@
#include <QDebug>
#include "arg.h"
#include "mainwindow.h"
#include "clientaccess.h"
#include "clientapi.h"
#include "mainwindow.h"
int main(int argc, char** argv) {
Log::init();
@ -40,10 +40,7 @@ int main(int argc, char** argv) {
qWarning() << "translation not found";
}
MainWindow win;
QIcon icon(":/lolautoaccept.png");
win.setWindowIcon(icon);
win.show();
int ret = app.exec();
Log::stop();

View File

@ -1,14 +1,24 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QTimer>
#include <Log.h>
#include "loadingwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), loading(true), ui(new Ui::MainWindow), saveTimer(new QTimer(this)), dd(QLocale().name()),
lolaa(conf.getConfig(), dd) {
lolaa(conf.getConfig(), dd), lwin(new LoadingWindow(nullptr)) {
ui->setupUi(this);
QObject::connect(&dd, &DataDragon::fetchingChamp, lwin, &LoadingWindow::setChampion);
QObject::connect(&dd, &DataDragon::loading, lwin, &LoadingWindow::setProgress);
QObject::connect(&dd, &DataDragon::loading, this, &MainWindow::loadingStatus);
QObject::connect(lwin, &LoadingWindow::closed, &dd, &DataDragon::stop);
QObject::connect(lwin, &LoadingWindow::closed, qApp, &QCoreApplication::quit, Qt::ConnectionType::QueuedConnection);
dd.startThread();
QObject::connect(&lolaa, &LolAutoAccept::statusChanged, this, &MainWindow::lolaaStatusChanged);
QObject::connect(&lolaa, &LolAutoAccept::positionChanged, this, &MainWindow::onPosChange);
@ -19,19 +29,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), loading(true), ui
ui->copyrightlabel->setText(ui->copyrightlabel->text().arg(LOLAA_VERSION));
conf.load();
// for all tabs - set their config and datadragon
Config::RootConfig& rc = conf.getConfig();
for(int32_t tabnr = 0; tabnr < ui->tabWidget->count(); ++tabnr) {
SettingsTab* tab = (SettingsTab*) ui->tabWidget->widget(tabnr);
tab->setup(*rc.getPositionConfig(tab->getPosition()), &dd);
QObject::connect(tab, &SettingsTab::changed, this, &MainWindow::tabchanged);
QObject::connect(tab, &SettingsTab::toggled, this, &MainWindow::tabtoggled);
}
ui->runesPage->setDataDragon(dd);
ui->runesPage->setConfig(conf);
ui->enableAll->setChecked(rc.enabledAutoAccept);
lolaa.setEnabled(rc.enabledAutoAccept, LolAutoAccept::State::LOBBY);
@ -45,12 +43,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), loading(true), ui
resizeEvent(nullptr);
// a timer to delay the loading flag a short time until all other signals are processed
initDoneTimer = new QTimer(this);
initDoneTimer->setSingleShot(true);
initDoneTimer->setInterval(std::chrono::milliseconds(1)); // schedule for first event loop
QObject::connect(initDoneTimer, &QTimer::timeout, this, &MainWindow::initDone, Qt::QueuedConnection);
initDoneTimer->start();
lwin->show();
}
MainWindow::~MainWindow() {
@ -70,6 +63,35 @@ void MainWindow::resetSaveTimer() {
qDebug() << "resetTimer";
}
void MainWindow::loadingStatus(float f) {
if(f >= 1.0 && lwin) {
// loading complete
// for all tabs - set their config and datadragon
Config::RootConfig& rc = conf.getConfig();
for(int32_t tabnr = 0; tabnr < ui->tabWidget->count(); ++tabnr) {
SettingsTab* tab = (SettingsTab*) ui->tabWidget->widget(tabnr);
tab->setup(*rc.getPositionConfig(tab->getPosition()), &dd);
QObject::connect(tab, &SettingsTab::changed, this, &MainWindow::tabchanged);
QObject::connect(tab, &SettingsTab::toggled, this, &MainWindow::tabtoggled);
}
// load runepage images
ui->runesPage->setDataDragon(dd);
ui->runesPage->setConfig(conf);
// switch from loading window to main window
lwin->hide();
this->show();
lwin->deleteLater();
lwin = nullptr;
// a timer to delay the loading flag a short time until all other signals are processed
QTimer::singleShot(std::chrono::milliseconds(1), this, &MainWindow::initDone);
}
}
void MainWindow::toggleMainswitch(bool state) {
qDebug() << "mainswitch toggled: " << state;
@ -156,8 +178,6 @@ void MainWindow::saveConfig() {
void MainWindow::initDone() {
loading = false;
initDoneTimer->deleteLater();
initDoneTimer = nullptr;
qDebug() << "loading done";
}

47
ui/loadingwindow.ui Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoadingWindow</class>
<widget class="QWidget" name="LoadingWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>739</width>
<height>176</height>
</rect>
</property>
<property name="windowTitle">
<string>LoL-Auto-Accept</string>
</property>
<property name="windowIcon">
<iconset resource="../resources/res.qrc">
<normaloff>:/lolautoaccept.svg</normaloff>:/lolautoaccept.svg</iconset>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -19,6 +19,10 @@
<property name="windowTitle">
<string>LoL-Auto-Accept</string>
</property>
<property name="windowIcon">
<iconset resource="../resources/res.qrc">
<normaloff>:/lolautoaccept.svg</normaloff>:/lolautoaccept.svg</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="centralGridLayout">
<property name="sizeConstraint">