From afc7be6f129504088b51af13fb9067b214d22118 Mon Sep 17 00:00:00 2001 From: FullGreaM Date: Thu, 5 Mar 2026 15:48:24 +0300 Subject: [PATCH] Add first files of the launcher --- .gitignore | 83 ++++++++++++++++++++ CMakeLists.txt | 82 ++++++++++++++++++++ install-java.cpp | 172 +++++++++++++++++++++++++++++++++++++++++ install-java.h | 20 +++++ loading-worker.cpp | 58 ++++++++++++++ loading-worker.h | 21 +++++ loading.cpp | 54 +++++++++++++ loading.h | 28 +++++++ loading.ui | 63 +++++++++++++++ locales.cpp | 56 ++++++++++++++ locales.h | 11 +++ main.cpp | 15 ++++ network-downloader.cpp | 56 ++++++++++++++ network-downloader.h | 18 +++++ source.qrc | 7 ++ sources/icons/16.png | Bin 0 -> 368 bytes sources/icons/32.png | Bin 0 -> 677 bytes sources/icons/96.png | Bin 0 -> 1795 bytes welcome.cpp | 33 ++++++++ welcome.h | 24 ++++++ welcome.ui | 114 +++++++++++++++++++++++++++ 21 files changed, 915 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 install-java.cpp create mode 100644 install-java.h create mode 100644 loading-worker.cpp create mode 100644 loading-worker.h create mode 100644 loading.cpp create mode 100644 loading.h create mode 100644 loading.ui create mode 100644 locales.cpp create mode 100644 locales.h create mode 100644 main.cpp create mode 100644 network-downloader.cpp create mode 100644 network-downloader.h create mode 100644 source.qrc create mode 100644 sources/icons/16.png create mode 100644 sources/icons/32.png create mode 100644 sources/icons/96.png create mode 100644 welcome.cpp create mode 100644 welcome.h create mode 100644 welcome.ui diff --git a/.gitignore b/.gitignore index 5c70465..1ba4f14 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,86 @@ compile_commands.json *.out *.app +# From Qt +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* +*.qbs.user* +CMakeLists.txt.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + +# Directories with generated files +.moc/ +.obj/ +.pch/ +.rcc/ +.uic/ +/build*/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2a6308b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,82 @@ +cmake_minimum_required(VERSION 3.16) + +project(ConanCraft-Launcher VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network) + +set(PROJECT_SOURCES + main.cpp + welcome.cpp + welcome.h + welcome.ui +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(ConanCraft-Launcher + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET ConanCraft-Launcher APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(ConanCraft-Launcher SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(ConanCraft-Launcher + ${PROJECT_SOURCES} + loading.h loading.cpp loading.ui + source.qrc + loading-worker.h loading-worker.cpp + locales.h + locales.cpp + install-java.h + install-java.cpp + network-downloader.h + network-downloader.cpp + ) + endif() +endif() + +target_link_libraries(ConanCraft-Launcher PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Network +) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +if(${QT_VERSION} VERSION_LESS 6.1.0) + set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.ConanCraft-Launcher) +endif() +set_target_properties(ConanCraft-Launcher PROPERTIES + ${BUNDLE_ID_OPTION} + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +include(GNUInstallDirs) +install(TARGETS ConanCraft-Launcher + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(ConanCraft-Launcher) +endif() diff --git a/install-java.cpp b/install-java.cpp new file mode 100644 index 0000000..92b3d8e --- /dev/null +++ b/install-java.cpp @@ -0,0 +1,172 @@ +#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()); +} + +bool checkJava () { + QString JAVA_HASH = "null"; + + #if defined(Q_OS_WIN) + #if defined(Q_PROCESSOR_X86_64) + //JAVA_HASH = "null"; + #elif defined(Q_PROCESSOR_ARM_64) + //JAVA_HASH = "null"; + #endif + #elif defined(Q_OS_LINUX) + #if defined(Q_PROCESSOR_X86_64) + //JAVA_HASH = "6268e94a0d6f37390fd33325725eb2991f9b26eb739baf2506064bfe3ea33075"; + #elif defined(Q_PROCESSOR_ARM_64) + #else + //JAVA_HASH = "null"; + #endif + #endif + QString hash = checkDirHash("./java"); + if (JAVA_HASH == "null" || hash != JAVA_HASH) + qDebug() << "Java hash:" << hash; + + return hash == JAVA_HASH; +} + +void installJava(std::function logCallback = nullptr) { + // Detect OS and architecture + QString javaUrl; + QString archiveType = "zip"; + + #if defined(Q_OS_WIN) + #if defined(Q_PROCESSOR_X86_64) + javaUrl = "https://example.com/java-windows-x64.zip"; + #elif defined(Q_PROCESSOR_X86) + javaUrl = "https://example.com/java-windows-x86.zip"; + #else + if (logCallback) logCallback("Unsupported Windows architecture"); + return; + #endif + + #elif defined(Q_OS_LINUX) + #if defined(Q_PROCESSOR_X86_64) + javaUrl = ""; + archiveType = "tar.gz"; + #elif defined(Q_PROCESSOR_ARM_64) + javaUrl = ""; + archiveType = "tar.gz"; + #else + if (logCallback) logCallback("Unsupported Linux architecture"); + return; + #endif + + #elif defined(Q_OS_MACOS) + #if defined(Q_PROCESSOR_X86_64) + javaUrl = "https://example.com/java-macos-x64.tar.gz"; + #elif defined(Q_PROCESSOR_ARM_64) + javaUrl = "https://example.com/java-macos-arm64.tar.gz"; + #else + if (logCallback) logCallback("Unsupported macOS architecture"); + return; + #endif + + #else + if (logCallback) logCallback("Unsupported OS"); + return; + #endif + + if (logCallback) logCallback("Creating directories..."); + QDir tempDir("./temp"); + if (!tempDir.exists()) tempDir.mkpath("."); + QDir javaDir("./java"); + if (!javaDir.exists()) javaDir.mkpath("."); + + QString archivePath = tempDir.filePath(QFileInfo(QUrl(javaUrl).path()).fileName()); + + // Download archive + downloadFromUrl(javaUrl, archivePath, logCallback); + + // Extract archive + if (logCallback) logCallback("Extracting Java archive..."); +#if defined(Q_OS_WIN) + // Unzip and move contents up one level + QProcess proc; + QString tempExtractDir = "./temp/java_extract"; + QDir().mkpath(tempExtractDir); + proc.start("powershell", {"-Command", QString("Expand-Archive -Force -Path '%1' -DestinationPath '%2'").arg(archivePath).arg(tempExtractDir)}); + proc.waitForFinished(-1); + + // Move contents from subfolder to ./java + QDir extracted(tempExtractDir); + QStringList entries = extracted.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + for (const QString &e : entries) { + QString srcPath = extracted.filePath(e); + QString dstPath = javaDir.filePath(e); + if (!QFile::rename(srcPath, dstPath)) { + QDir srcDir(srcPath); + srcDir.rename(srcPath, dstPath); + } + } + QDir(tempExtractDir).removeRecursively(); + +#elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + // Extract to temp folder first + QString tempExtractDir = "./temp/java_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"); + return; + } + proc.waitForFinished(-1); + + // Move contents of the inner folder to ./java + QDir extracted(tempExtractDir); + QStringList folders = extracted.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + QString rootFolder = folders.isEmpty() ? "" : folders.first(); + QDir rootDir(tempExtractDir + "/" + rootFolder); + QStringList items = rootDir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + for (const QString &item : items) { + QString src = rootDir.filePath(item); + QString dst = javaDir.filePath(item); + QFile::rename(src, dst); + } + QDir(tempExtractDir).removeRecursively(); +#endif + + if (logCallback) logCallback("Extraction complete."); + + // Check hash + QString hash = checkDirHash("./java"); + if (logCallback) logCallback("Java installation hash: " + hash); +} diff --git a/install-java.h b/install-java.h new file mode 100644 index 0000000..6d7401e --- /dev/null +++ b/install-java.h @@ -0,0 +1,20 @@ +#ifndef INSTALL_JAVA_H +#define INSTALL_JAVA_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void installJava(std::function logCallback); +bool checkJava (); +QString checkDirHash(QString path); + +#endif // INSTALL_JAVA_H diff --git a/loading-worker.cpp b/loading-worker.cpp new file mode 100644 index 0000000..1ee7226 --- /dev/null +++ b/loading-worker.cpp @@ -0,0 +1,58 @@ +#include "loading-worker.h" +#include "locales.h" +#include "install-java.h" +#include + +#include +#include +#include +#include + +LoadingWorker::LoadingWorker(Loading *loading, QObject *parent) { + this->loading = loading; +} + +LoadingWorker::~LoadingWorker () { + //delete this->loading; +} + +void LoadingWorker::process() { + std::string locale = (QLocale::system()).name().toStdString(); + if (locales.find(locale) == locales.end()) { + locale = "en_US"; + } + LocaleMap* localeMap = locales[locale]; + + // Checking updates + this->loading->changeStep(localeMap->at("loading.checkUpdates")); + // TODO: Add it later + + // Checking: Is java installed + this->loading->changeStep(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()); + }); + } + // Start I2P + this->loading->changeStep(localeMap->at("loading.i2p")); + // TODO: Add it later + + // Getting endpoint API + this->loading->changeStep(localeMap->at("loading.gettingEndpoint")); + std::string endpointAPI = "TODO: Add it later"; + + // Handle data + this->loading->changeStep(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); + + this->loading->changeStep(localeMap->at("loading.end")); + emit finished(); + this->loading->finishWorker(); +} diff --git a/loading-worker.h b/loading-worker.h new file mode 100644 index 0000000..03be473 --- /dev/null +++ b/loading-worker.h @@ -0,0 +1,21 @@ +#ifndef LOADING_WORKER_H +#define LOADING_WORKER_H + +#include "loading.h" +#include +class LoadingWorker : public QObject +{ + Q_OBJECT +public: + explicit LoadingWorker (Loading *loading, QObject *parent = nullptr); + ~LoadingWorker(); +private: + Loading *loading; +public slots: + void process(); +signals: + void finished(); + void progress(int value); +}; + +#endif // LOADING_WORKER_H diff --git a/loading.cpp b/loading.cpp new file mode 100644 index 0000000..9a0d0a6 --- /dev/null +++ b/loading.cpp @@ -0,0 +1,54 @@ +#include "loading.h" +#include "loading-worker.h" +#include "locales.h" +#include "ui_loading.h" +#include + +Loading::Loading(QWidget *parent) + : QWidget(parent) + , ui(new Ui::Loading) +{ + ui->setupUi(this); + this->setWindowFlags(Qt::FramelessWindowHint); + this->startLoading(); +} + +Loading::~Loading() +{ + delete ui; +} + +void Loading::changeStep(std::string text) { + this->ui->condition->setText(QString::fromStdString(text)); +} + +void Loading::setupWelcomeLocale(std::string locale) { + this->welcome.setupWelcomeLocale(locale); +} + +void Loading::finishWorker() { + this->hide(); + this->welcome.show(); +} + +void Loading::startLoading() +{ + QThread* thread = new QThread; + LoadingWorker* worker = new LoadingWorker(this); + + worker->moveToThread(thread); + + connect(thread, &QThread::started, + worker, &LoadingWorker::process); + + connect(worker, &LoadingWorker::finished, + thread, &QThread::quit); + + connect(worker, &LoadingWorker::finished, + worker, &QObject::deleteLater); + + connect(thread, &QThread::finished, + thread, &QObject::deleteLater); + + thread->start(); +} diff --git a/loading.h b/loading.h new file mode 100644 index 0000000..fe704cc --- /dev/null +++ b/loading.h @@ -0,0 +1,28 @@ +#ifndef LOADING_H +#define LOADING_H + +#include "welcome.h" +#include + +namespace Ui { +class Loading; +} + +class Loading : public QWidget +{ + Q_OBJECT + +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; +}; + +#endif // LOADING_H diff --git a/loading.ui b/loading.ui new file mode 100644 index 0000000..8300a23 --- /dev/null +++ b/loading.ui @@ -0,0 +1,63 @@ + + + Loading + + + + 0 + 0 + 300 + 450 + + + + + 300 + 450 + + + + + 300 + 450 + + + + ConanCraft + + + + :/icons/sources/icons/96.png:/icons/sources/icons/96.png + + + + + 10 + 410 + 281 + 31 + + + + Getting system language information... + + + + + + 0 + 0 + 301 + 411 + + + + <html><head/><body><p align="center"><span style=" font-size:16pt; font-weight:700;">Conan Craft</span></p></body></html> + + + + + + + + diff --git a/locales.cpp b/locales.cpp new file mode 100644 index 0000000..53c3aa8 --- /dev/null +++ b/locales.cpp @@ -0,0 +1,56 @@ +#include "locales.h" + +std::map locales; + +// Russian +LocaleMap ru_RU = { + // Locale Info + {"locale.name", "Русский"}, + {"locale.fullname", "Русский (Russian)"}, + // Loading + {"loading.checkUpdates", "Проверяем обновления"}, + {"loading.i2p", "Запускаем i2p"}, + {"loading.isJavaInst", "Проверка установки Java"}, + {"loading.installJava", "Установка Java"}, + {"loading.gettingEndpoint", "Получаем Endpoint API"}, + {"loading.logging", "Обрабатываем данные лаунчера"}, + {"loading.setupLocale", "Устанавливаем язык лаунчера"}, + {"loading.end", "Закончили. Приятной игры"}, + // Welcome + {"welcome.main", "Главная"}, + {"welcome.settings", "Настройки"}, + {"welcome.authorise", "Авторизация"}, + {"welcome.showPassword", "Показать пароль"}, + {"welcome.logIn", "Войти"}, + {"welcome.register", "Зарегистрироваться"}, +}; + +// English +LocaleMap en_US = { + // Locale Info + {"locale.name", "English"}, + {"locale.fullname", "English (English)"}, + // Loading + {"loading.checkUpdates", "Checking updates"}, + {"loading.i2p", "Starting i2p"}, + {"loading.isJavaInst", "Checking Is Java installed"}, + {"loading.installJava", "Java installation"}, + {"loading.gettingEndpoint", "Getting Endpoint API"}, + {"loading.logging", "Handle the launcher data"}, + {"loading.setupLocale", "Setup the launcher's language"}, + {"loading.end", "Finished. Let's start"}, + // Welcome + {"welcome.main", "Home"}, + {"welcome.settings", "Settings"}, + {"welcome.authorise", "Authorization"}, + {"welcome.showPassword", "Show the password"}, + {"welcome.logIn", "LogIn"}, + {"welcome.register", "Registration"}, +}; + +void initLocales () { + locales["ru_RU"] = &ru_RU; + locales["ru_UA"] = &ru_RU; + locales["en_US"] = &en_US; + //locales["en_UK"] = &en_US; +} diff --git a/locales.h b/locales.h new file mode 100644 index 0000000..00a6ad4 --- /dev/null +++ b/locales.h @@ -0,0 +1,11 @@ +#ifndef LOCALES_H +#define LOCALES_H + +#include +#include + +using LocaleMap = std::map; +extern std::map locales; +extern void initLocales (); + +#endif // LOCALES_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..9ad6251 --- /dev/null +++ b/main.cpp @@ -0,0 +1,15 @@ +#include "loading.h" +#include "locales.h" +//#include "welcome.h" + +#include + +int main(int argc, char *argv[]) +{ + initLocales(); + QApplication a(argc, argv); + Loading w; + //w.setWindowFlags(Qt::FramelessWindowHint); + w.show(); + return a.exec(); +} diff --git a/network-downloader.cpp b/network-downloader.cpp new file mode 100644 index 0000000..f8fea05 --- /dev/null +++ b/network-downloader.cpp @@ -0,0 +1,56 @@ +#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; + } + + if (logCallback) logCallback("Downloading from url..."); + 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)); + }); + + QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + + QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + + if (!statusCode.isValid()) { + if (logCallback) logCallback("Download failed: Invalid Status code"); + reply->deleteLater(); + return; + } + + if (reply->error() != QNetworkReply::NoError) { + if (logCallback) logCallback("Download failed: " + reply->errorString()); + reply->deleteLater(); + return; + } + + if (statusCode.toInt() == 302 || statusCode.toInt() == 301) { + QVariant redir = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (!redir.isValid()) { + if (logCallback) logCallback("Download failed: Invalid redirect"); + reply->deleteLater(); + return; + } + QUrl newUrl = redir.toUrl(); + downloadFromUrl(newUrl.toString(), installPath, logCallback); + return; + } + + QFile file(installPath); + if (file.open(QIODevice::WriteOnly)) { + file.write(reply->readAll()); + file.close(); + if (logCallback) logCallback("Download complete: " + installPath); + } else { + if (logCallback) logCallback("Cannot write file: " + installPath); + } + reply->deleteLater(); +} diff --git a/network-downloader.h b/network-downloader.h new file mode 100644 index 0000000..0b7c290 --- /dev/null +++ b/network-downloader.h @@ -0,0 +1,18 @@ +#ifndef NETWORK_DOWNLOADER_H +#define NETWORK_DOWNLOADER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void downloadFromUrl(const QString &url, const QString &installPath, std::function logCallback); + +#endif // NETWORK_DOWNLOADER_H diff --git a/source.qrc b/source.qrc new file mode 100644 index 0000000..1c6a891 --- /dev/null +++ b/source.qrc @@ -0,0 +1,7 @@ + + + sources/icons/96.png + sources/icons/32.png + sources/icons/16.png + + diff --git a/sources/icons/16.png b/sources/icons/16.png new file mode 100644 index 0000000000000000000000000000000000000000..71cf0149f4c62f9e13af724480821121d4d84380 GIT binary patch literal 368 zcmV-$0gwKPP)I=l|4Jy&|7!tiBuXc8@`JFulN;V zQ*`X)t56WeZn0kxNH4?xt3mSrulU~sn+65-p`mP5q3#JsPrdvP!WE$&@gOm{<_oUe z|F8Jn|9{0tj^Y3RQ0D(v{h$B8>c98@wLqO!oqp<7VIEg1Lp}bl-~RCbhV2jjgVU;h89|9=pkTj2%P0KzaA!1(hjyufOpxD4T+ z{q`*XulUb>eb5iC7~KUh{Q8jJe~?;`9*ltL&UBuU=5G5RhG8y176Yll88t^wy#(93 z`@mB$Ub6NM7{mA=IglFK8GsI8USJ>>969ykBM6gkz{wYuAWXIabO8X4fDTT}##yWY O0000eZBCViUh|pqELJqNPW&+-9irQ%PVEwrD$xM>{-e!q3 z0m*|uEN|Yt|8M5)t|Sd&5RxQ8O+5}YcCu%FEO81bIc5P+E&x+*^bPd>3C$wvFHbcT+oB$e;8yO-$(I&@7e9dd|F`($T z@Y0pj=0cqu28Mr%1&Tg^o)~p*PEUlcW{AA25t*9_(^vT|p%y?(;U8%t$6e-nVpQ}N z2SvNw(_TQ)LhBZq1r*(fTI?+7%1CxfPH9BmGfkQRGqV*TJAlw$cIwJB-z$1h^uRb^ z^N#3?C6TsBRJc7HEw&n(aV+1zcyDr10H^|kmIe#_eJtK;joW;325m)md09^Cw zh})dv=lg#m3~jWF8>`5(aexsR`nqPh1&S;14j=UeFd^_V-|#jU-50?7CA6zBA8VU0 zbu_mIFa^&|hrZuNj~iQsHm>Pb+m3H!okTCoi1`FF67H>UfW?%!>{KFD<{` zgcmED9qYKd2AG+x7<0}&eJ{kHxpDH=s!$uky8bf1WxSyO2JkotK>gqViv1cvr#Ntf zPB8!|mK*C9fc2gOtZaNfQYde)ar07XXGrQtluA28eKQ}#e-nQJ?mWM$T<0_o00000 LNkvXXu0mjf;fE#j literal 0 HcmV?d00001 diff --git a/sources/icons/96.png b/sources/icons/96.png new file mode 100644 index 0000000000000000000000000000000000000000..10ae404874504eaae7e53ab5ec4bac66f6c6d13e GIT binary patch literal 1795 zcmai#X*AReAIJa07$e4#eHaW+_RzJ4GPW2+ldX(svP)42*&0K0Ge(w2WgUiF4MLVd z*1^eK*@i5)Av1K5lU<2y*S+W57tgEb#pm}q=llA1&LE;ribSORzLJt6==Q2cK|Kz^YN06^$y8%x)i!j=3xwKB1Azr(&_c9Klz>uX*0W7^ zp4KVk1#GFhL(Vf=&{4oPmL2jV)-0~o?8h&ie;&<;>+cP0Ee{Q?zAm-@&&gC9<*a`d z4p(BIMmelXRjGIardtXN8g{%n{NQtoeb+rl->~~1AcYv{6E8C%GVSKiNixG ze^n6C`*9W#iIjggWGLsq^LWd4QGLe@R#4 zRz2r2w?06Ha5b(%haVtJ!XT`k5vUi54?omHA%vWB%YBEk`wlMo($od$utRJbzWTr* zTJZeYx1-v8_V(#pb!D+un-^Zu3qHfe+WMsF9#G7_f7^3*`aTHrE!y-ok-Qzja4G%X z-IqOu=XTDuEn69%g))Sw-eTmeU=YUDqL=xBJ=iCAh|#-u$(r!+k*|Iz2JGX90d7~E zk=83qFfVhQ^W=LsDMvz)$tQqG?9OCZCod^hyP9C3gpGZ!3?u~1CbxkMf|AOW8@f|j zMW_+JG$65oBVdV;Lc9^3&^UkPmE<|NhDe*-2v2*<%kaEm5`Bb@%BU_Mq)R@^*m)rb z{W(2qMw(iQw%QgPwu#JWq3KOpvGNYp_d z@4-aEJH}zNhWSS5$+4$dn~aC4mm>55eQ?z4@cXvDZe2FUy^J=1;6(oFp(gxsZC#zh z13oYd{dM{LJ&DU`+n8jjT=)nNld0dI1`unAj1gkq@O1He8Ay9wN1*Vee`pP!n~XN~ zM@CvVe7mXEt>SO{pyef{$v4Lh2r;^EO{?Q$O-o&CUCJo~1~f(Xy(`Nvo5=D;Qp-_# zwX+{UheN)tKA)rITh*?os3&GERt0-`=+Q!wE;c&WLGiLTFfD`HuJjKNfLbl8MX6-P z^{}%7iG1p-^^0Q6&_8IARcl`+#`(a*7q>ggs;vem`^V2KBu8fO%3QDWc8EIlrWRzm zmBjsTW5P{^3q2xt`Ed%FbD!ivLT-wfZ-$sLM${O7PK~OyFH_k_r#|>z&wH@HK=Ty} z_#iBpl-IePCh@XFY+TQC#jK$tW;N5>B`z>XRkY2-NOgLRk@4xtfHAMqY#>6ORi~rK ze6u-TqT(Bw5!&repPN_Oj~FOAQy^(uU&N0ax=)*eAw3I7h=S5R8K5#OKkd_*Vn??q zqno|3B;wr)t5{Fbv0-O@ReZ|{$=E2Ovq*{l0Hw`^9~yd3(+7{+;TkTwWauaX?urv& z#}y4QH-1%792K~OjCi|*vj0|zc^~kFhX*&_{%+O{wO)K%atR9rKqZF5m5D{@JUGLy zM*6JzUe-dz?o}(LodgABU^Mb7nbjVD(#hFk<-+k#$N3ztN9)AYd!6AJNykY6;Rluj zEsdQ_x-z?PvqCKxTH?hk@i4%SH6=Jk7Qub&F8LH3SQe&O3o`JANhFw4N^W#Sg#8>z zh&}1#y7)t_fXLEZNY!0n@>ym*!ySnWS8Ht;06o7JtYhd^y684Ga`qM{JwuQx$Ptui zdLq^2?{RMe{D$7Qd7dTQVDh3JJc)}?G!w^jXOKz79UeJ`px4!iT6uq8KVL^?#xrV} z-!D^pesN`vy5M?M{QP*=AJ6BOlNqMhGE2Qv;KJAjl7ci@1O&=<$ zkQMu;mv%ExgIt}4#Sg1Aj6>yczXLm&pdFza%RFy~79?BL8p7ppqnDQ+_0HRIcWw6u zuyxCNw>je~yzBk@j|}&4Ll@&dlMWhv!)ksetupUi(this); +} + +Welcome::~Welcome() +{ + delete ui; +} + +void Welcome::setupWelcomeLocale(std::string locale) { + if (locales.find(locale) == locales.end()) { + locale = "en_US"; + } + LocaleMap* localeMap = locales[locale]; + + this->ui->authForm->setTitle(QString::fromStdString(localeMap->at("welcome.authorise"))); + + this->ui->tabWidget->setTabText(0, QString::fromStdString(localeMap->at("welcome.main"))); + this->ui->tabWidget->setTabText(1, QString::fromStdString(localeMap->at("welcome.settings"))); + + this->ui->showPassword->setText(QString::fromStdString(localeMap->at("welcome.showPassword"))); + this->ui->loginBtn->setText(QString::fromStdString(localeMap->at("welcome.logIn"))); + this->ui->registerBtn->setText(QString::fromStdString(localeMap->at("welcome.register"))); + + this->ui->tabWidget->setCurrentIndex(0); +} diff --git a/welcome.h b/welcome.h new file mode 100644 index 0000000..e54daa4 --- /dev/null +++ b/welcome.h @@ -0,0 +1,24 @@ +#ifndef WELCOME_H +#define WELCOME_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class Welcome; +} +QT_END_NAMESPACE + +class Welcome : public QMainWindow +{ + Q_OBJECT + +public: + Welcome(QWidget *parent = nullptr); + ~Welcome(); + void setupWelcomeLocale(std::string locale); + +private: + Ui::Welcome *ui; +}; +#endif // WELCOME_H diff --git a/welcome.ui b/welcome.ui new file mode 100644 index 0000000..a2107ae --- /dev/null +++ b/welcome.ui @@ -0,0 +1,114 @@ + + + Welcome + + + + 0 + 0 + 800 + 600 + + + + Welcome + + + + :/icons/sources/icons/96.png:/icons/sources/icons/96.png + + + + + + 0 + 0 + 801 + 551 + + + + + welcome.main + + + + + 240 + 130 + 331 + 291 + + + + welcome.authorise + + + + + 10 + 30 + 311 + 251 + + + + + + + + + + QLineEdit::Password + + + + + + + welcome.showPassword + + + + + + + welcome.logIn + + + + + + + welcome.register + + + + + + + + + + welcome.settings + + + + + + + + 0 + 0 + 800 + 23 + + + + + + + + + +