From fb3dfdbd1c5f104fa21a30dfac83d6f546089d54 Mon Sep 17 00:00:00 2001 From: FullGreaM Date: Fri, 6 Mar 2026 18:36:13 +0300 Subject: [PATCH] fix progressbar add autobuild i2p for Linux (needed add for Win64) --- CMakeLists.txt | 8 ++ fs-tools.cpp | 72 +++++++++++++++ fs-tools.h | 20 ++++ i2p-controller.cpp | 89 ++++++++++++++++++ i2p-controller.h | 24 +++++ install-i2p.cpp | 201 +++++++++++++++++++++++++++++++++++++++++ install-i2p.h | 23 +++++ install-java.cpp | 80 ++++++---------- install-java.h | 3 +- loading-worker.cpp | 61 +++++++++---- loading-worker.h | 10 +- loading.cpp | 48 +++++++++- loading.h | 12 ++- loading.ui | 19 ++++ locales.cpp | 4 + network-downloader.cpp | 39 ++++---- network-downloader.h | 2 +- personal-account.cpp | 14 +++ personal-account.h | 22 +++++ personal-account.ui | 19 ++++ prog-constains.cpp | 7 ++ prog-constains.h | 14 +++ welcome.cpp | 6 +- welcome.h | 2 +- welcome.ui | 9 ++ 25 files changed, 704 insertions(+), 104 deletions(-) create mode 100644 fs-tools.cpp create mode 100644 fs-tools.h create mode 100644 i2p-controller.cpp create mode 100644 i2p-controller.h create mode 100644 install-i2p.cpp create mode 100644 install-i2p.h create mode 100644 personal-account.cpp create mode 100644 personal-account.h create mode 100644 personal-account.ui create mode 100644 prog-constains.cpp create mode 100644 prog-constains.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a6308b..9594dc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,14 @@ else() install-java.cpp network-downloader.h network-downloader.cpp + fs-tools.cpp + fs-tools.h + prog-constains.h + prog-constains.cpp + install-i2p.h + install-i2p.cpp + i2p-controller.h i2p-controller.cpp + personal-account.h personal-account.cpp personal-account.ui ) endif() endif() diff --git a/fs-tools.cpp b/fs-tools.cpp new file mode 100644 index 0000000..ba9eb92 --- /dev/null +++ b/fs-tools.cpp @@ -0,0 +1,72 @@ +#include "fs-tools.h" + +void emptyFolder(const QString& path) +{ + QDir dir(path); + + if (!dir.exists()) { + dir.mkpath("."); + return; + } + + QFileInfoList entries = dir.entryInfoList( + QDir::NoDotAndDotDot | + QDir::AllEntries + ); + + for (const QFileInfo &entry : entries) { + if (entry.isDir()) { + QDir(entry.absoluteFilePath()).removeRecursively(); + } else { + QFile::remove(entry.absoluteFilePath()); + } + } +} + +QString checkFileHash(QString pathname) +{ + QFile file(pathname); + + if (!file.open(QFile::ReadOnly)) + return QString(); + + QCryptographicHash hash(QCryptographicHash::Sha256); + + while (!file.atEnd()) + hash.addData(file.read(8192)); + + return hash.result().toHex(); +} + +QString checkDirHash(QString path) { + QCryptographicHash hash(QCryptographicHash::Sha256); + QDir dir(path); + + if (!dir.exists()) { + qDebug() << "Directory not exists:" << path; + return QString(); + } + + QFileInfoList fileList = dir.entryInfoList( + QDir::Files | QDir::NoSymLinks | QDir::AllDirs | QDir::NoDotAndDotDot, + QDir::Name | QDir::DirsFirst + ); + + for (const QFileInfo &info : fileList) { + if (info.isDir()) { + QString subHash = checkDirHash(info.absoluteFilePath()); + hash.addData(subHash.toUtf8()); + } else if (info.isFile()) { + QFile file(info.absoluteFilePath()); + if (file.open(QIODevice::ReadOnly)) { + while (!file.atEnd()) { + QByteArray chunk = file.read(8192); + hash.addData(chunk); + } + file.close(); + } + } + } + + return QString(hash.result().toHex()); +} diff --git a/fs-tools.h b/fs-tools.h new file mode 100644 index 0000000..8910fff --- /dev/null +++ b/fs-tools.h @@ -0,0 +1,20 @@ +#ifndef FS_TOOLS_H +#define FS_TOOLS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void emptyFolder(const QString& path); +QString checkDirHash(QString path); +QString checkFileHash(QString pathname); + +#endif // FS_TOOLS_H diff --git a/i2p-controller.cpp b/i2p-controller.cpp new file mode 100644 index 0000000..a9eebb4 --- /dev/null +++ b/i2p-controller.cpp @@ -0,0 +1,89 @@ +#include "i2p-controller.h" +#include "prog-constains.h" + +I2PController::I2PController(QObject *parent) + : QObject(parent) +{ +} + +void I2PController::start() { + if (i2p.state() != QProcess::NotRunning) + { + qDebug() << "i2pd already running"; + return; + } + + QStringList args; + #if defined(Q_OS_WIN) + this->i2p.start(QDir(I2P_INSTALL_PATH).filePath("i2pd.exe"), args); + #elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + QString configsFolder = QDir(I2P_INSTALL_PATH).filePath("configs"); + QString logsFolder = QDir(I2P_INSTALL_PATH).filePath("logs"); + + args << "--datadir" << QDir(I2P_INSTALL_PATH).filePath("data") + << "--conf" << QDir(configsFolder).filePath("i2pd.conf") + << "--tunconf" << QDir(configsFolder).filePath("tunnels.conf") + << "--log" << QDir(logsFolder).filePath("i2pd.log"); + + this->i2p.start(QDir(I2P_INSTALL_PATH).filePath("i2pd"), args); + #else + #endif + +} + +void I2PController::onProcessError(QProcess::ProcessError error) +{ + qDebug() << "I2P process error:" << error; + + switch (error) + { + case QProcess::FailedToStart: + qCritical() << "i2pd failed to start"; + emit fatalError("Failed to start i2pd"); + break; + + case QProcess::Crashed: + qWarning() << "i2pd crashed"; + restartI2P(); + break; + + default: + break; + } +} + +void I2PController::onProcessFinished(int exitCode, QProcess::ExitStatus status) +{ + qDebug() << "i2pd finished" << exitCode << status; + + if (status == QProcess::CrashExit) + { + qWarning() << "i2pd crashed, restarting..."; + restartI2P(); + return; + } + + if (exitCode != 0) + { + qWarning() << "i2pd exited with error"; + restartI2P(); + } +} + +void I2PController::restartI2P() +{ + static int restartCount = 0; + + if (restartCount > 5) + { + qCritical() << "i2pd crashed too many times"; + emit fatalError("i2pd keeps crashing"); + return; + } + + restartCount++; + + QTimer::singleShot(3000, [this]() { + start(); + }); +} diff --git a/i2p-controller.h b/i2p-controller.h new file mode 100644 index 0000000..429529d --- /dev/null +++ b/i2p-controller.h @@ -0,0 +1,24 @@ +#ifndef I2P_CONTROLLER_H +#define I2P_CONTROLLER_H + +#include +#include +#include + +class I2PController : public QObject +{ + Q_OBJECT +public: + I2PController(QObject *parent = nullptr); + void start(); +private: + QProcess i2p; + void restartI2P(); +public slots: + void onProcessError(QProcess::ProcessError error); + void onProcessFinished(int exitCode, QProcess::ExitStatus status); +signals: + void fatalError(QString); +}; + +#endif // I2P_CONTROLLER_H diff --git a/install-i2p.cpp b/install-i2p.cpp new file mode 100644 index 0000000..a7eb6c5 --- /dev/null +++ b/install-i2p.cpp @@ -0,0 +1,201 @@ +#include "install-i2p.h" +#include "fs-tools.h" +#include "network-downloader.h" +#include "prog-constains.h" + +void addI2PDconfig (QString i2pdConf, QString tunnelsConf) { + #if defined(Q_OS_WIN) + #elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + #else + #endif +} + +void configCheckAndMake () { + QString configsFolder = QDir(I2P_INSTALL_PATH).filePath("configs"); + + QString i2pdConf = QDir(configsFolder).filePath("i2pd.confconf"); + QString tunnelsConf = QDir(configsFolder).filePath("tunnels.conf"); + if ( + !QFile(i2pdConf).exists() || + !QFile(tunnelsConf).exists() + ) { + qDebug() << "Configs not found. Creating new"; + emptyFolder(configsFolder); + addI2PDconfig(i2pdConf, tunnelsConf); + } +} + +bool checkI2P () { + QString I2P_VERSION = "i2pd version 2.59.0 (0.9.68)"; + + QProcess p; + p.start(QDir(I2P_INSTALL_PATH).filePath("i2pd"), {"--version"}); + p.waitForFinished(); + + QString version = p.readAllStandardOutput(); + bool isNeededVersion = version.contains(I2P_VERSION); + + if (!isNeededVersion) + qDebug() << "current i2pd version:" << version; + return isNeededVersion; +} + +bool installI2P(std::function logCallback = nullptr) { + // Detect OS and architecture + QString i2pUrl; // https://github.com/PurpleI2P/i2pd/releases/tag/2.59.0 + QString archiveType = "zip"; + + #if defined(Q_OS_WIN) + i2pUrl = "https://github.com/PurpleI2P/i2pd/releases/download/2.59.0/i2pd_2.59.0_win64_mingw.zip"; + archiveType = "zip"; + #elif defined(Q_OS_LINUX) + i2pUrl = "https://github.com/PurpleI2P/i2pd/archive/refs/tags/2.59.0.tar.gz"; + archiveType = "tar.gz"; + #elif defined(Q_OS_MACOS) + i2pUrl = "https://github.com/PurpleI2P/i2pd/releases/download/2.59.0/i2pd_2.59.0_osx.tar.gz"; + archiveType = "tar.gz"; + #endif + + if (logCallback) logCallback("Creating directories...", 0, 0); + QDir tempDir(TEMP_PATH); + if (!tempDir.exists()) tempDir.mkpath("."); + QDir i2pDir(I2P_INSTALL_PATH); + if (!i2pDir.exists()) i2pDir.mkpath("."); + QString archivePath = tempDir.filePath(QFileInfo(QUrl(i2pUrl).path()).fileName()); + + // Download archive + bool isDownloaded = downloadFromUrl(i2pUrl, archivePath, logCallback); + if (!isDownloaded) return false; + + // Extract archive + if (logCallback) logCallback("Extracting I2P archive...", 0, 0); + + #if defined(Q_OS_WIN) + // TODO: Make it later + #elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + // Extract to temp folder first + QString tempExtractDir = QDir(TEMP_PATH).filePath("i2p_extract"); + QDir().mkpath(tempExtractDir); + QProcess proc; + + if (archiveType == "tar.gz") { + proc.start("tar", {"-xzf", archivePath, "-C", tempExtractDir}); + } else if (archiveType == "zip") { + proc.start("unzip", {archivePath, "-d", tempExtractDir}); + } else { + if (logCallback) logCallback("Unknown archive format", 0, 0); + return false; + } + proc.waitForFinished(-1); + + // ### Build i2pd + if (logCallback) logCallback("Searching source directory...", 0, 4); + + // Find extracted source dir (archive contains nested folder with Makefile) + QDir extractDir(tempExtractDir); + QString sourceDir; + + for (const QFileInfo &entry : extractDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + QDir sub(entry.absoluteFilePath()); + if (sub.exists("Makefile")) { + sourceDir = entry.absoluteFilePath(); + break; + } + } + + if (sourceDir.isEmpty()) { + if (logCallback) logCallback("Failed to find source directory (Makefile missing)", 0, 0); + return false; + } + + // ---- BUILD ---- + if (logCallback) logCallback("Building i2pd...", 1, 4); + + QProcess procBuild; + procBuild.setWorkingDirectory(sourceDir); + procBuild.setProcessChannelMode(QProcess::MergedChannels); + + int cpuCount = QThread::idealThreadCount(); + + procBuild.start("bash", {"-c", QString("make -j%1").arg(cpuCount)}); + + if (!procBuild.waitForStarted()) { + if (logCallback) logCallback("Failed to start make", 0, 0); + return false; + } + + while (procBuild.state() == QProcess::Running) { + procBuild.waitForReadyRead(100); + + QByteArray out = procBuild.readAll(); + if (!out.isEmpty() && logCallback) { + QString text = QString::fromLocal8Bit(out).trimmed(); + if (!text.isEmpty()) + logCallback(text, 1, 4); + } + } + + procBuild.waitForFinished(-1); + + if (procBuild.exitStatus() != QProcess::NormalExit || procBuild.exitCode() != 0) { + QString err = QString::fromLocal8Bit(procBuild.readAll()); + if (logCallback) logCallback("Build failed: " + err + ", visit: " + WIKI_URL + "Build-I2P-on-Linux", 0, 0); + return false; + } + + // ---- FIND BINARY ---- + if (logCallback) logCallback("Locating built binary...", 2, 4); + + QString binaryPath; + + QDirIterator it(sourceDir, QDirIterator::Subdirectories); + while (it.hasNext()) { + QString path = it.next(); + QFileInfo fi(path); + + if (fi.isFile() && fi.fileName() == "i2pd") { + binaryPath = fi.absoluteFilePath(); + break; + } + } + + if (binaryPath.isEmpty()) { + if (logCallback) logCallback("Built binary not found", 0, 0); + return false; + } + + // ---- MOVE BINARY ---- + if (logCallback) logCallback("Installing binary...", 3, 4); + + QString destPath = QDir(I2P_INSTALL_PATH).filePath("i2pd"); + + QFile::remove(destPath); + + if (!QFile::copy(binaryPath, destPath)) { + if (logCallback) logCallback("Failed to copy binary", 0, 0); + return false; + } + + QFile::setPermissions(destPath, + QFile::permissions(destPath) | + QFileDevice::ExeOwner | + QFileDevice::ExeGroup | + QFileDevice::ExeOther); + + if (logCallback) logCallback("I2P installation complete", 4, 4); + #endif + + // ---- ADD CONFIGS ---- + QString i2pdConfigsFolder = QDir(I2P_INSTALL_PATH).filePath("configs"); + + emptyFolder(QDir(I2P_INSTALL_PATH).filePath("data")); + emptyFolder(QDir(I2P_INSTALL_PATH).filePath("logs")); + emptyFolder(i2pdConfigsFolder); + + addI2PDconfig(QDir(i2pdConfigsFolder).filePath("i2pd.conf"), QDir(i2pdConfigsFolder).filePath("tunnels.conf")); + + // Check hash + QString hash = checkFileHash(QDir(I2P_INSTALL_PATH).filePath("i2pd")); + if (logCallback) logCallback("Total I2P installation hash: " + hash, 0, 0); + return true; +} diff --git a/install-i2p.h b/install-i2p.h new file mode 100644 index 0000000..ca3325a --- /dev/null +++ b/install-i2p.h @@ -0,0 +1,23 @@ +#ifndef INSTALL_I2P_H +#define INSTALL_I2P_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool installI2P(std::function logCallback); +bool checkI2P (); +void configCheckAndMake (); + +#endif // INSTALL_I2P_H diff --git a/install-java.cpp b/install-java.cpp index 92b3d8e..ded94c6 100644 --- a/install-java.cpp +++ b/install-java.cpp @@ -1,38 +1,7 @@ #include "install-java.h" #include "network-downloader.h" - -QString checkDirHash(QString path) { - QCryptographicHash hash(QCryptographicHash::Sha256); - QDir dir(path); - - if (!dir.exists()) { - qDebug() << "Directory not exists:" << path; - return QString(); - } - - QFileInfoList fileList = dir.entryInfoList( - QDir::Files | QDir::NoSymLinks | QDir::AllDirs | QDir::NoDotAndDotDot, - QDir::Name | QDir::DirsFirst - ); - - for (const QFileInfo &info : fileList) { - if (info.isDir()) { - QString subHash = checkDirHash(info.absoluteFilePath()); - hash.addData(subHash.toUtf8()); - } else if (info.isFile()) { - QFile file(info.absoluteFilePath()); - if (file.open(QIODevice::ReadOnly)) { - while (!file.atEnd()) { - QByteArray chunk = file.read(8192); - hash.addData(chunk); - } - file.close(); - } - } - } - - return QString(hash.result().toHex()); -} +#include "fs-tools.h" +#include "prog-constains.h" bool checkJava () { QString JAVA_HASH = "null"; @@ -45,22 +14,22 @@ bool checkJava () { #endif #elif defined(Q_OS_LINUX) #if defined(Q_PROCESSOR_X86_64) - //JAVA_HASH = "6268e94a0d6f37390fd33325725eb2991f9b26eb739baf2506064bfe3ea33075"; + JAVA_HASH = "916b3a45f8f405ff2227b68e4225574b57e582585c47fd090b00d944af7c790c"; #elif defined(Q_PROCESSOR_ARM_64) #else //JAVA_HASH = "null"; #endif #endif - QString hash = checkDirHash("./java"); + QString hash = checkDirHash(JAVA_INSTALL_PATH); if (JAVA_HASH == "null" || hash != JAVA_HASH) - qDebug() << "Java hash:" << hash; + qDebug() << "Java dir hash:" << hash; return hash == JAVA_HASH; } -void installJava(std::function logCallback = nullptr) { +bool installJava(std::function logCallback = nullptr) { // Detect OS and architecture - QString javaUrl; + QString javaUrl; // https://github.com/bell-sw/Liberica/releases/tag/17.0.18%2B11 QString archiveType = "zip"; #if defined(Q_OS_WIN) @@ -69,19 +38,19 @@ void installJava(std::function logCallback = nullptr) { #elif defined(Q_PROCESSOR_X86) javaUrl = "https://example.com/java-windows-x86.zip"; #else - if (logCallback) logCallback("Unsupported Windows architecture"); + if (logCallback) logCallback("Unsupported Windows architecture", 0, 0); return; #endif #elif defined(Q_OS_LINUX) #if defined(Q_PROCESSOR_X86_64) - javaUrl = ""; + javaUrl = "https://github.com/bell-sw/Liberica/releases/download/17.0.18%2B11/bellsoft-jdk17.0.18+11-linux-amd64-crac.tar.gz"; archiveType = "tar.gz"; #elif defined(Q_PROCESSOR_ARM_64) javaUrl = ""; archiveType = "tar.gz"; #else - if (logCallback) logCallback("Unsupported Linux architecture"); + if (logCallback) logCallback("Unsupported Linux architecture", 0, 0); return; #endif @@ -91,7 +60,7 @@ void installJava(std::function logCallback = nullptr) { #elif defined(Q_PROCESSOR_ARM_64) javaUrl = "https://example.com/java-macos-arm64.tar.gz"; #else - if (logCallback) logCallback("Unsupported macOS architecture"); + if (logCallback) logCallback("Unsupported macOS architecture", 0, 0); return; #endif @@ -100,23 +69,24 @@ void installJava(std::function logCallback = nullptr) { return; #endif - if (logCallback) logCallback("Creating directories..."); - QDir tempDir("./temp"); + if (logCallback) logCallback("Creating directories...", 0, 0); + QDir tempDir(TEMP_PATH); if (!tempDir.exists()) tempDir.mkpath("."); - QDir javaDir("./java"); + QDir javaDir(JAVA_INSTALL_PATH); if (!javaDir.exists()) javaDir.mkpath("."); QString archivePath = tempDir.filePath(QFileInfo(QUrl(javaUrl).path()).fileName()); // Download archive - downloadFromUrl(javaUrl, archivePath, logCallback); + bool isDownloaded = downloadFromUrl(javaUrl, archivePath, logCallback); + if (!isDownloaded) return false; // Extract archive - if (logCallback) logCallback("Extracting Java archive..."); + if (logCallback) logCallback("Extracting Java archive...", 0, 0); #if defined(Q_OS_WIN) // Unzip and move contents up one level QProcess proc; - QString tempExtractDir = "./temp/java_extract"; + QString tempExtractDir = QDir(TEMP_PATH).filePath("java_extract"); QDir().mkpath(tempExtractDir); proc.start("powershell", {"-Command", QString("Expand-Archive -Force -Path '%1' -DestinationPath '%2'").arg(archivePath).arg(tempExtractDir)}); proc.waitForFinished(-1); @@ -136,7 +106,7 @@ void installJava(std::function logCallback = nullptr) { #elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) // Extract to temp folder first - QString tempExtractDir = "./temp/java_extract"; + QString tempExtractDir = QDir(TEMP_PATH).filePath("java_extract"); QDir().mkpath(tempExtractDir); QProcess proc; @@ -145,8 +115,8 @@ void installJava(std::function logCallback = nullptr) { } else if (archiveType == "zip") { proc.start("unzip", {archivePath, "-d", tempExtractDir}); } else { - if (logCallback) logCallback("Unknown archive format"); - return; + if (logCallback) logCallback("Unknown archive format", 0, 0); + return false; } proc.waitForFinished(-1); @@ -164,9 +134,11 @@ void installJava(std::function logCallback = nullptr) { QDir(tempExtractDir).removeRecursively(); #endif - if (logCallback) logCallback("Extraction complete."); + if (logCallback) logCallback("Extraction complete.", 0, 0); // Check hash - QString hash = checkDirHash("./java"); - if (logCallback) logCallback("Java installation hash: " + hash); + QString hash = checkDirHash(JAVA_INSTALL_PATH); + if (logCallback) logCallback("Total Java installation hash: " + hash, 0, 0); + + return true; } diff --git a/install-java.h b/install-java.h index 6d7401e..9ab7e87 100644 --- a/install-java.h +++ b/install-java.h @@ -13,8 +13,7 @@ #include #include -void installJava(std::function logCallback); +bool installJava(std::function logCallback); bool checkJava (); -QString checkDirHash(QString path); #endif // INSTALL_JAVA_H diff --git a/loading-worker.cpp b/loading-worker.cpp index 1ee7226..4323dd3 100644 --- a/loading-worker.cpp +++ b/loading-worker.cpp @@ -1,15 +1,17 @@ #include "loading-worker.h" +#include "install-i2p.h" #include "locales.h" #include "install-java.h" -#include +#include "fs-tools.h" +#include "prog-constains.h" +#include #include #include #include #include -LoadingWorker::LoadingWorker(Loading *loading, QObject *parent) { - this->loading = loading; +LoadingWorker::LoadingWorker(QObject *parent) { } LoadingWorker::~LoadingWorker () { @@ -23,36 +25,63 @@ void LoadingWorker::process() { } LocaleMap* localeMap = locales[locale]; + emptyFolder(TEMP_PATH); + // Checking updates - this->loading->changeStep(localeMap->at("loading.checkUpdates")); + emit changeStep(QString::fromStdString(localeMap->at("loading.checkUpdates"))); // TODO: Add it later // Checking: Is java installed - this->loading->changeStep(localeMap->at("loading.isJavaInst")); + emit changeStep(QString::fromStdString(localeMap->at("loading.isJavaInst"))); if (!checkJava()) { // Let's we install the java - installJava([this, localeMap](QString msg){ - qDebug() << msg; - this->loading->changeStep(localeMap->at("loading.installJava") + ": " + msg.toStdString()); + + emptyFolder(JAVA_INSTALL_PATH); + bool isDownloaded = installJava([this, localeMap](QString msg, unsigned int current, unsigned int total){ + //qDebug() << "Java install:" << msg; + emit changeStep(QString::fromStdString(localeMap->at("loading.installJava") + ": " + msg.toStdString())); + if (total != 0) { + emit progressBar(current, total); + } }); + if (!isDownloaded) return; } + // Start I2P - this->loading->changeStep(localeMap->at("loading.i2p")); - // TODO: Add it later + emit changeStep(QString::fromStdString(localeMap->at("loading.i2p"))); + if (!checkI2P()) { + // Let's we install i2p + + emptyFolder(I2P_INSTALL_PATH); + bool isDownloaded = installI2P([this, localeMap](QString msg, unsigned int current, unsigned int total){ + qDebug() << "I2P install:" << msg; + emit changeStep(QString::fromStdString(localeMap->at("loading.installI2P") + ": " + msg.toStdString())); + if (total != 0) { + emit progressBar(current, total); + } + }); + if (!isDownloaded) return; + } + configCheckAndMake(); + emit startI2P(); + + // Checking: Is minecraft installed + emit changeStep(QString::fromStdString(localeMap->at("loading.isMinecraftInst"))); // Getting endpoint API - this->loading->changeStep(localeMap->at("loading.gettingEndpoint")); + emit changeStep(QString::fromStdString(localeMap->at("loading.gettingEndpoint"))); std::string endpointAPI = "TODO: Add it later"; // Handle data - this->loading->changeStep(localeMap->at("loading.logging")); + emit changeStep(QString::fromStdString(localeMap->at("loading.logging"))); // TODO: Add it later // Setup current locale for welcome form - this->loading->changeStep(localeMap->at("loading.setupLocale")); - this->loading->setupWelcomeLocale(locale); + emit changeStep(QString::fromStdString(localeMap->at("loading.setupLocale"))); + emit setupWelcomeLocale(QString::fromStdString(locale)); - this->loading->changeStep(localeMap->at("loading.end")); + emit changeStep(QString::fromStdString(localeMap->at("loading.end"))); + + emptyFolder(TEMP_PATH); emit finished(); - this->loading->finishWorker(); } diff --git a/loading-worker.h b/loading-worker.h index 03be473..df74625 100644 --- a/loading-worker.h +++ b/loading-worker.h @@ -1,21 +1,25 @@ #ifndef LOADING_WORKER_H #define LOADING_WORKER_H -#include "loading.h" +//#include "loading.h" #include class LoadingWorker : public QObject { Q_OBJECT public: - explicit LoadingWorker (Loading *loading, QObject *parent = nullptr); + explicit LoadingWorker (QObject *parent = nullptr); ~LoadingWorker(); private: - Loading *loading; + //Loading *loading; public slots: void process(); signals: void finished(); void progress(int value); + void progressBar(int value, int max); + void changeStep(QString text); + void setupWelcomeLocale(QString locale); + void startI2P(); }; #endif // LOADING_WORKER_H diff --git a/loading.cpp b/loading.cpp index 9a0d0a6..37aa1ce 100644 --- a/loading.cpp +++ b/loading.cpp @@ -1,8 +1,8 @@ #include "loading.h" #include "loading-worker.h" -#include "locales.h" #include "ui_loading.h" #include +#include Loading::Loading(QWidget *parent) : QWidget(parent) @@ -10,6 +10,7 @@ Loading::Loading(QWidget *parent) { ui->setupUi(this); this->setWindowFlags(Qt::FramelessWindowHint); + this->ui->progressBar->hide(); this->startLoading(); } @@ -18,11 +19,11 @@ Loading::~Loading() delete ui; } -void Loading::changeStep(std::string text) { - this->ui->condition->setText(QString::fromStdString(text)); +void Loading::changeStep(QString text) { + this->ui->condition->setText(text); } -void Loading::setupWelcomeLocale(std::string locale) { +void Loading::setupWelcomeLocale(QString locale) { this->welcome.setupWelcomeLocale(locale); } @@ -31,10 +32,30 @@ void Loading::finishWorker() { this->welcome.show(); } +void Loading::setupProgressBar(unsigned int current, unsigned int max) { + if (this->ui->progressBar->isHidden() && (max != 0)) + this->ui->progressBar->show(); + else if (!this->ui->progressBar->isHidden() && (max == 0)) + this->ui->progressBar->hide(); + + if (max != 0) { + // TODO: Fix displayed progressBar + if (this->ui->progressBar->maximum() != max) + this->ui->progressBar->setRange(0, max); + if (this->ui->progressBar->value() != current) + this->ui->progressBar->setValue(current); + } +} + +void Loading::startI2P() { + qDebug() << "Starting I2P..."; + this->i2p.start(); +} + void Loading::startLoading() { QThread* thread = new QThread; - LoadingWorker* worker = new LoadingWorker(this); + LoadingWorker* worker = new LoadingWorker; worker->moveToThread(thread); @@ -50,5 +71,22 @@ void Loading::startLoading() connect(thread, &QThread::finished, thread, &QObject::deleteLater); + // Connection between loading and worker + connect(worker, &LoadingWorker::progressBar, + this, &Loading::setupProgressBar); + + connect(worker, &LoadingWorker::changeStep, + this, &Loading::changeStep); + + connect(worker, &LoadingWorker::setupWelcomeLocale, + this, &Loading::setupWelcomeLocale); + + connect(worker, &LoadingWorker::finished, + this, &Loading::finishWorker); + + // I2P + connect(worker, &LoadingWorker::startI2P, + this, &Loading::startI2P); + thread->start(); } diff --git a/loading.h b/loading.h index fe704cc..af334bb 100644 --- a/loading.h +++ b/loading.h @@ -2,6 +2,7 @@ #define LOADING_H #include "welcome.h" +#include "i2p-controller.h" #include namespace Ui { @@ -15,14 +16,19 @@ class Loading : public QWidget public: explicit Loading(QWidget *parent = nullptr); ~Loading(); - void changeStep(std::string text); - void setupWelcomeLocale(std::string locale); - void finishWorker(); private: Ui::Loading *ui; void startLoading(); Welcome welcome; + I2PController i2p; + +public slots: + void setupProgressBar(unsigned int current, unsigned int max); + void changeStep(QString text); + void setupWelcomeLocale(QString locale); + void finishWorker(); + void startI2P(); }; #endif // LOADING_H diff --git a/loading.ui b/loading.ui index 8300a23..46d76f3 100644 --- a/loading.ui +++ b/loading.ui @@ -55,6 +55,25 @@ <html><head/><body><p align="center"><span style=" font-size:16pt; font-weight:700;">Conan Craft</span></p></body></html> + + + + 0 + 390 + 301 + 20 + + + + 100 + + + 24 + + + false + + diff --git a/locales.cpp b/locales.cpp index 53c3aa8..490badd 100644 --- a/locales.cpp +++ b/locales.cpp @@ -16,6 +16,8 @@ LocaleMap ru_RU = { {"loading.logging", "Обрабатываем данные лаунчера"}, {"loading.setupLocale", "Устанавливаем язык лаунчера"}, {"loading.end", "Закончили. Приятной игры"}, + {"loading.installI2P", "Установка I2P"}, + {"loading.isMinecraftInst", "Проверим установлен ли Майнкрафт"}, // Welcome {"welcome.main", "Главная"}, {"welcome.settings", "Настройки"}, @@ -39,6 +41,8 @@ LocaleMap en_US = { {"loading.logging", "Handle the launcher data"}, {"loading.setupLocale", "Setup the launcher's language"}, {"loading.end", "Finished. Let's start"}, + {"loading.installI2P", "Installing I2P"}, + {"loading.isMinecraftInst", "Checking Is Minecraft installed"}, // Welcome {"welcome.main", "Home"}, {"welcome.settings", "Settings"}, diff --git a/network-downloader.cpp b/network-downloader.cpp index f8fea05..9dfd8f8 100644 --- a/network-downloader.cpp +++ b/network-downloader.cpp @@ -1,18 +1,24 @@ #include "network-downloader.h" -void downloadFromUrl(const QString &url, const QString &installPath, std::function logCallback = nullptr) { - if (QFile::exists(installPath)) { - if (logCallback) logCallback("File already exists: " + installPath); - return; + +bool downloadFromUrl(const QString &url, const QString &installPath, std::function logCallback = nullptr) { + if (url == "") { + if (logCallback) logCallback("Empty download URL", 0, 0); + return false; } - if (logCallback) logCallback("Downloading from url..."); + if (QFile::exists(installPath)) { + if (logCallback) logCallback("File already exists: " + installPath, 0, 0); + return true; + } + + if (logCallback) logCallback("Downloading from url...", 0, 0); QNetworkAccessManager manager; QNetworkRequest request((QUrl(url))); QEventLoop loop; QNetworkReply *reply = manager.get(request); QObject::connect(reply, &QNetworkReply::downloadProgress, [&](qint64 received, qint64 total){ - if (logCallback) logCallback(QString("Download progress: %1/%2 bytes").arg(received).arg(total)); + if (logCallback) logCallback(QString("Download progress: %1/%2 bytes").arg(received).arg(total), received, total); }); QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); @@ -21,36 +27,37 @@ void downloadFromUrl(const QString &url, const QString &installPath, std::functi QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); if (!statusCode.isValid()) { - if (logCallback) logCallback("Download failed: Invalid Status code"); + if (logCallback) logCallback("Download failed: Invalid Status code", 0, 0); reply->deleteLater(); - return; + return false; } if (reply->error() != QNetworkReply::NoError) { - if (logCallback) logCallback("Download failed: " + reply->errorString()); + if (logCallback) logCallback("Download failed: " + reply->errorString(), 0, 0); reply->deleteLater(); - return; + return false; } if (statusCode.toInt() == 302 || statusCode.toInt() == 301) { QVariant redir = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); if (!redir.isValid()) { - if (logCallback) logCallback("Download failed: Invalid redirect"); + if (logCallback) logCallback("Download failed: Invalid redirect", 0, 0); reply->deleteLater(); - return; + return false; } QUrl newUrl = redir.toUrl(); - downloadFromUrl(newUrl.toString(), installPath, logCallback); - return; + return downloadFromUrl(newUrl.toString(), installPath, logCallback); } QFile file(installPath); if (file.open(QIODevice::WriteOnly)) { file.write(reply->readAll()); file.close(); - if (logCallback) logCallback("Download complete: " + installPath); + if (logCallback) logCallback("Download complete: " + installPath, 0, 0); } else { - if (logCallback) logCallback("Cannot write file: " + installPath); + if (logCallback) logCallback("Cannot write file: " + installPath, 0, 0); } reply->deleteLater(); + + return true; } diff --git a/network-downloader.h b/network-downloader.h index 0b7c290..8126c58 100644 --- a/network-downloader.h +++ b/network-downloader.h @@ -13,6 +13,6 @@ #include #include -void downloadFromUrl(const QString &url, const QString &installPath, std::function logCallback); +bool downloadFromUrl(const QString &url, const QString &installPath, std::function logCallback); #endif // NETWORK_DOWNLOADER_H diff --git a/personal-account.cpp b/personal-account.cpp new file mode 100644 index 0000000..1765e3d --- /dev/null +++ b/personal-account.cpp @@ -0,0 +1,14 @@ +#include "personal-account.h" +#include "ui_personal-account.h" + +PersonalAccount::PersonalAccount(QWidget *parent) + : QWidget(parent) + , ui(new Ui::PersonalAccount) +{ + ui->setupUi(this); +} + +PersonalAccount::~PersonalAccount() +{ + delete ui; +} diff --git a/personal-account.h b/personal-account.h new file mode 100644 index 0000000..2eef84d --- /dev/null +++ b/personal-account.h @@ -0,0 +1,22 @@ +#ifndef PERSONAL_ACCOUNT_H +#define PERSONAL_ACCOUNT_H + +#include + +namespace Ui { +class PersonalAccount; +} + +class PersonalAccount : public QWidget +{ + Q_OBJECT + +public: + explicit PersonalAccount(QWidget *parent = nullptr); + ~PersonalAccount(); + +private: + Ui::PersonalAccount *ui; +}; + +#endif // PERSONAL_ACCOUNT_H diff --git a/personal-account.ui b/personal-account.ui new file mode 100644 index 0000000..f768daa --- /dev/null +++ b/personal-account.ui @@ -0,0 +1,19 @@ + + + PersonalAccount + + + + 0 + 0 + 580 + 440 + + + + Form + + + + + diff --git a/prog-constains.cpp b/prog-constains.cpp new file mode 100644 index 0000000..73d4e70 --- /dev/null +++ b/prog-constains.cpp @@ -0,0 +1,7 @@ +#include "prog-constains.h" + +const QString __dirname = QCoreApplication::applicationFilePath(); +const QString JAVA_INSTALL_PATH = QDir(__dirname).filePath("java"); +const QString I2P_INSTALL_PATH = QDir(__dirname).filePath("i2p"); +const QString TEMP_PATH = QDir(__dirname).filePath("temp"); +const QString WIKI_URL = "https://git.fullgream.tech/Conan-Craft/launcher/wiki/"; diff --git a/prog-constains.h b/prog-constains.h new file mode 100644 index 0000000..0517393 --- /dev/null +++ b/prog-constains.h @@ -0,0 +1,14 @@ +#ifndef PROG_CONSTAINS_H +#define PROG_CONSTAINS_H + +#include +#include +#include + +extern const QString __dirname; +extern const QString JAVA_INSTALL_PATH; +extern const QString TEMP_PATH; +extern const QString I2P_INSTALL_PATH; +extern const QString WIKI_URL; + +#endif // PROG_CONSTAINS_H diff --git a/welcome.cpp b/welcome.cpp index 5d3a137..6a42f4f 100644 --- a/welcome.cpp +++ b/welcome.cpp @@ -14,11 +14,11 @@ Welcome::~Welcome() delete ui; } -void Welcome::setupWelcomeLocale(std::string locale) { - if (locales.find(locale) == locales.end()) { +void Welcome::setupWelcomeLocale(QString locale) { + if (locales.find(locale.toStdString()) == locales.end()) { locale = "en_US"; } - LocaleMap* localeMap = locales[locale]; + LocaleMap* localeMap = locales[locale.toStdString()]; this->ui->authForm->setTitle(QString::fromStdString(localeMap->at("welcome.authorise"))); diff --git a/welcome.h b/welcome.h index e54daa4..b3a0315 100644 --- a/welcome.h +++ b/welcome.h @@ -16,7 +16,7 @@ class Welcome : public QMainWindow public: Welcome(QWidget *parent = nullptr); ~Welcome(); - void setupWelcomeLocale(std::string locale); + void setupWelcomeLocale(QString locale); private: Ui::Welcome *ui; diff --git a/welcome.ui b/welcome.ui index a2107ae..72ecc30 100644 --- a/welcome.ui +++ b/welcome.ui @@ -27,7 +27,16 @@ 551 + + + + + 0 + + + + welcome.main