From 2adcd4f24eca2fa529c42fc1165319bcc4ea179e Mon Sep 17 00:00:00 2001 From: Victor Tran Date: Thu, 12 Jul 2018 18:12:14 +1000 Subject: Initial commit --- installer/background.svg | 153 +++++++ installer/fadestackedwidget.cpp | 57 +++ installer/fadestackedwidget.h | 29 ++ installer/icon-bp.svg | 133 ++++++ installer/icon.svg | 133 ++++++ installer/installer.pro | 53 +++ installer/main.cpp | 35 ++ installer/mainwindow.cpp | 228 ++++++++++ installer/mainwindow.h | 67 +++ installer/mainwindow.ui | 807 ++++++++++++++++++++++++++++++++++++ installer/process/installworker.cpp | 78 ++++ installer/process/installworker.h | 35 ++ installer/resources.qrc | 8 + installer/translations/vi_VN.qm | Bin 0 -> 1522 bytes 14 files changed, 1816 insertions(+) create mode 100644 installer/background.svg create mode 100644 installer/fadestackedwidget.cpp create mode 100644 installer/fadestackedwidget.h create mode 100644 installer/icon-bp.svg create mode 100644 installer/icon.svg create mode 100644 installer/installer.pro create mode 100644 installer/main.cpp create mode 100644 installer/mainwindow.cpp create mode 100644 installer/mainwindow.h create mode 100644 installer/mainwindow.ui create mode 100644 installer/process/installworker.cpp create mode 100644 installer/process/installworker.h create mode 100644 installer/resources.qrc create mode 100644 installer/translations/vi_VN.qm (limited to 'installer') diff --git a/installer/background.svg b/installer/background.svg new file mode 100644 index 0000000..4c7bf3f --- /dev/null +++ b/installer/background.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Application Name + + + + diff --git a/installer/fadestackedwidget.cpp b/installer/fadestackedwidget.cpp new file mode 100644 index 0000000..e925c99 --- /dev/null +++ b/installer/fadestackedwidget.cpp @@ -0,0 +1,57 @@ +#include "fadestackedwidget.h" + +FadeStackedWidget::FadeStackedWidget(QWidget *parent) : QStackedWidget(parent) +{ + +} + +void FadeStackedWidget::setCurrentIndex(int index) { + //Do some checks before setting the current index. + if (currentIndex() != index) { + doSetCurrentIndex(index); + } +} + +void FadeStackedWidget::doSetCurrentIndex(int index) { + QWidget* currentWidget = widget(currentIndex()); + QWidget* nextWidget = widget(index); + if (nextWidget == nullptr) { + QStackedWidget::setCurrentIndex(index); + } else { + if (doingNewAnimation) { + anim->stop(); + anim->deleteLater(); + } + + doingNewAnimation = true; + QGraphicsOpacityEffect* currentOpacity = new QGraphicsOpacityEffect(); + QGraphicsOpacityEffect* nextOpacity = new QGraphicsOpacityEffect(); + currentWidget->setGraphicsEffect(currentOpacity); + nextWidget->setGraphicsEffect(nextOpacity); + + anim = new QVariantAnimation(); + anim->setStartValue((float) 1); + anim->setEndValue((float) 0); + anim->setDuration(500); + anim->setEasingCurve(QEasingCurve::InCubic); + connect(anim, &QVariantAnimation::finished, [=] { + if (anim->direction() == QVariantAnimation::Forward) { + anim->setDirection(QVariantAnimation::Backward); + QStackedWidget::setCurrentIndex(index); + anim->start(); + } else { + doingNewAnimation = false; + anim->deleteLater(); + anim = nullptr; + } + }); + connect(anim, &QVariantAnimation::valueChanged, [=](QVariant value) { + if (anim->direction() == QVariantAnimation::Forward) { + currentOpacity->setOpacity(value.toFloat()); + } else { + nextOpacity->setOpacity(value.toFloat()); + } + }); + anim->start(); + } +} diff --git a/installer/fadestackedwidget.h b/installer/fadestackedwidget.h new file mode 100644 index 0000000..9f43ba2 --- /dev/null +++ b/installer/fadestackedwidget.h @@ -0,0 +1,29 @@ +#ifndef FADESTACKEDWIDGET_H +#define FADESTACKEDWIDGET_H + +#include +#include +#include +#include +#include + +class FadeStackedWidget : public QStackedWidget +{ + Q_OBJECT +public: + explicit FadeStackedWidget(QWidget *parent = nullptr); + +signals: + +public slots: + void setCurrentIndex(int index); + +private slots: + void doSetCurrentIndex(int index); + +private: + bool doingNewAnimation = false; + QVariantAnimation* anim; +}; + +#endif // FADESTACKEDWIDGET_H diff --git a/installer/icon-bp.svg b/installer/icon-bp.svg new file mode 100644 index 0000000..0184f82 --- /dev/null +++ b/installer/icon-bp.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/installer/icon.svg b/installer/icon.svg new file mode 100644 index 0000000..b70191e --- /dev/null +++ b/installer/icon.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/installer/installer.pro b/installer/installer.pro new file mode 100644 index 0000000..2725738 --- /dev/null +++ b/installer/installer.pro @@ -0,0 +1,53 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-07-10T19:50:12 +# +#------------------------------------------------- + +QT += core gui network svg +CONFIG += static + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = installer +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +#DEFINES += INSTALLER_METADATA_URL=\\\"http://localhost:8000/installer.json\\\" +DEFINES += INSTALLER_METADATA_URL=\\\"http://vicr123.com/theslate/theinstaller/installer.json\\\" + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + fadestackedwidget.cpp \ + process/installworker.cpp + +HEADERS += \ + mainwindow.h \ + fadestackedwidget.h \ + process/installworker.h + +FORMS += \ + mainwindow.ui + +TRANSLATIONS += \ + translations/vi_VN.ts + +win32 { + #CONFIG += embed_manifest_exe + #QMAKE_LFLAGS_WINDOWS += /MANIFESTUAC:level=\'requireAdministrator\' +} + +RESOURCES += \ + resources.qrc + diff --git a/installer/main.cpp b/installer/main.cpp new file mode 100644 index 0000000..4b62834 --- /dev/null +++ b/installer/main.cpp @@ -0,0 +1,35 @@ +#include "mainwindow.h" +#include "process/installworker.h" +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QTranslator qtTranslator; + qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + a.installTranslator(&qtTranslator); + + QTranslator myappTranslator; + myappTranslator.load(QLocale::system().name(), ":/translations/"); + //myappTranslator.load("vi_VN", ":/translations/"); + a.installTranslator(&myappTranslator); + + qsrand(QDateTime::currentMSecsSinceEpoch()); + + if (a.arguments().contains("--install")) { + //Installer mode + InstallWorker worker; + if (!worker.startWork()) return 1; + + a.setQuitOnLastWindowClosed(false); + return a.exec(); + } + + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/installer/mainwindow.cpp b/installer/mainwindow.cpp new file mode 100644 index 0000000..9bdb6d4 --- /dev/null +++ b/installer/mainwindow.cpp @@ -0,0 +1,228 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + this->setFixedSize(this->size()); + backgroundImage = QIcon(":/background.svg").pixmap(this->size()); + + //ui->appIcon->setPixmap(QIcon(":/icon.svg").pixmap(128, 128)); + ui->installButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_VistaShield)); + ui->installButton_2->setIcon(QApplication::style()->standardIcon(QStyle::SP_VistaShield)); + + getInstallerMetadata(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::getInstallerMetadata() { + ui->stack->setCurrentIndex(0); + + QTimer::singleShot(1000, [=] { + QNetworkRequest req(QUrl(INSTALLER_METADATA_URL)); + req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + QNetworkReply* reply = mgr.get(req); + connect(reply, &QNetworkReply::finished, [=] { + if (reply->error() != QNetworkReply::NoError) return; + + QJsonDocument doc = QJsonDocument::fromJson(reply->readAll()); + if (!doc.isObject()) { + ui->metadataErrorLabel->setText(tr("Invalid metadata was received")); + ui->stack->setCurrentIndex(1); + return; + } + + QJsonObject obj = doc.object(); + if (!obj.contains("name") || !obj.contains("vendor")) { + ui->metadataErrorLabel->setText(tr("Application name not in metadata")); + ui->stack->setCurrentIndex(1); + return; + } + + if (!obj.contains("blueprint")) { + ui->streamLabel->setVisible(false); + ui->streamContainer->setVisible(false); + } + + ui->openCheckbox->setText(tr("Open %1").arg(obj.value("name").toString())); + this->setWindowTitle(tr("Install %1").arg(obj.value("name").toString())); + + this->metadata = obj; + setInstallPath(); + + ui->stack->setCurrentIndex(2); + }); + connect(reply, QOverload::of(&QNetworkReply::error), [=](QNetworkReply::NetworkError code) { + ui->metadataErrorLabel->setText(tr("Couldn't retrieve metadata")); + ui->stack->setCurrentIndex(1); + }); + connect(reply, &QNetworkReply::sslErrors, [=](QList errors) { + ui->metadataErrorLabel->setText(tr("Couldn't connect securely to the server")); + ui->stack->setCurrentIndex(1); + }); + }); +} + +void MainWindow::setInstallPath() { + QString tail = metadata.value("vendor").toString() + "\\" + metadata.value("name").toString() + "\\"; + if (ui->installEveryone->isChecked()) { + ui->installPathLineEdit->setText(qgetenv("PROGRAMFILES") + "\\" + tail); + ui->installButton_2->setIcon(QApplication::style()->standardIcon(QStyle::SP_VistaShield)); + } else { + ui->installPathLineEdit->setText(qgetenv("LOCALAPPDATA") + "\\Programs\\" + tail); + ui->installButton_2->setIcon(QIcon()); + } +} + +void MainWindow::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.drawPixmap(0, 0, backgroundImage); +} + +void MainWindow::on_installOptions_clicked() +{ + ui->stack->setCurrentIndex(3); +} + +void MainWindow::on_cancelMetadataButton_clicked() +{ + this->close(); +} + +void MainWindow::on_retryMetadataButton_clicked() +{ + getInstallerMetadata(); +} + +void MainWindow::on_installEveryone_toggled(bool checked) +{ + setInstallPath(); +} + +void MainWindow::on_installButton_clicked() +{ + this->setWindowFlag(Qt::WindowCloseButtonHint, false); + this->show(); + + ui->stack->setCurrentIndex(4); + ui->statusLabel->setText(tr("Getting ready to install %1...").arg(metadata.value("name").toString())); + + QLocalServer* socketServer = new QLocalServer(); + + QString serverNumber = QString::number(qrand()); + if (QApplication::arguments().contains("--server-only")) { + serverNumber = QApplication::arguments().at(QApplication::arguments().indexOf("--server-only") + 1); + } + + socketServer->listen("theinstaller." + metadata.value("vendor").toString() + "." + metadata.value("name").toString() + "." + serverNumber); + connect(socketServer, &QLocalServer::newConnection, [=] { + QLocalSocket* sock = socketServer->nextPendingConnection(); + + connect(sock, &QLocalSocket::readyRead, [=] { + QStringList lines = QString(sock->readAll()).split("\n"); + for (QString line : lines) { + QStringList parts = line.split(" "); + if (parts.at(0) == "PING") { + QMessageBox::warning(this, "Ping!", "Ping received", QMessageBox::Ok, QMessageBox::Ok); + } else if (parts.at(0) == "STATUS") { + parts.takeFirst(); + ui->statusLabel->setText(parts.join(" ")); + } else if (parts.at(0) == "PROGRESS") { + ui->installProgress->setMaximum(parts.at(2).toLongLong()); + ui->installProgress->setValue(parts.at(1).toLongLong()); + } else if (parts.at(0) == "DEBUG") { + parts.takeFirst(); + qDebug() << parts.join(" "); + } + } + }); + connect(sock, &QLocalSocket::disconnected, [=] { + this->setWindowFlag(Qt::WindowCloseButtonHint, true); + this->show(); + ui->stack->setCurrentIndex(6); + }); + + socketServer->close(); + }); + + if (QApplication::arguments().contains("--server-only")) { + QMessageBox::warning(this, "Socket Server", socketServer->serverName(), QMessageBox::Ok, QMessageBox::Ok); + } else { + QStringList args; + args.append("\"--install\""); + args.append("\"--socket " + socketServer->serverName() + "\""); + args.append("\"--vendor " + metadata.value("vendor").toString() + "\""); + args.append("\"--name " + metadata.value("name").toString() + "\""); + + QString destdir = ui->installPathLineEdit->text(); + if (destdir.endsWith("\\")) { + destdir.append("\\"); + } + args.append("\"--destdir \"\"" + destdir + "\"\"\""); + + if (ui->stableStream->isChecked()) { + args.append("\"--stable\""); + args.append("\"--url " + metadata.value("stable").toObject().value("packageUrl").toString() + "\""); + } else { + args.append("\"--blueprint\""); + args.append("\"--url " + metadata.value("blueprint").toObject().value("packageUrl").toString() + "\""); + } + + if (ui->installEveryone->isChecked()) { + args.append("\"--global\""); + } else { + args.append("\"--local\""); + } + + QStringList psArgs; + psArgs.append("-FilePath \"" + QApplication::applicationFilePath() + "\""); + psArgs.append("-ArgumentList (" + args.join(",") + ")"); + psArgs.append("-Verb runAs"); + psArgs.append("-PassThru"); + psArgs.append("-Wait"); + + QString encodedCommand = "Start-Process " + psArgs.join(" ") + ""; + QProcess* proc = new QProcess(); + proc->setProcessChannelMode(QProcess::ForwardedChannels); + + QString command = "powershell -EncodedCommand " + QByteArray::fromRawData((const char*) encodedCommand.utf16(), encodedCommand.size() * 2).toBase64(); + qDebug() << "PowerShell Command: " + encodedCommand; + qDebug() << "Executing " + command; + proc->start(command); + connect(proc, QOverload::of(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus) { + this->setWindowFlag(Qt::WindowCloseButtonHint, true); + this->show(); + if (!socketServer->isListening()) { + socketServer->close(); + socketServer->deleteLater(); + + ui->stack->setCurrentIndex(5); + } else { + ui->stack->setCurrentIndex(6); + } + proc->deleteLater(); + }); + } +} + +void MainWindow::on_installButton_2_clicked() +{ + on_installButton_clicked(); +} + +void MainWindow::on_exitButton_clicked() +{ + this->close(); +} + +void MainWindow::on_retryInstallButton_clicked() +{ + getInstallerMetadata(); +} diff --git a/installer/mainwindow.h b/installer/mainwindow.h new file mode 100644 index 0000000..dcfd34f --- /dev/null +++ b/installer/mainwindow.h @@ -0,0 +1,67 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void on_installOptions_clicked(); + + void getInstallerMetadata(); + + void setInstallPath(); + + void on_cancelMetadataButton_clicked(); + + void on_retryMetadataButton_clicked(); + + void on_installEveryone_toggled(bool checked); + + void on_installButton_clicked(); + + void on_installButton_2_clicked(); + + void on_exitButton_clicked(); + + void on_retryInstallButton_clicked(); + +private: + Ui::MainWindow *ui; + + void paintEvent(QPaintEvent* event); + + QNetworkAccessManager mgr; + QPixmap backgroundImage; + QJsonObject metadata; +}; + +#endif // MAINWINDOW_H diff --git a/installer/mainwindow.ui b/installer/mainwindow.ui new file mode 100644 index 0000000..722e7df --- /dev/null +++ b/installer/mainwindow.ui @@ -0,0 +1,807 @@ + + + MainWindow + + + + 0 + 0 + 600 + 420 + + + + theInstaller + + + + :/icon.svg:/icon.svg + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 270 + + + + + + + + Getting ready... + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 250 + + + + + + + + + 20 + + + + This shouldn't be happening... + + + Qt::AlignCenter + + + + + + + Invalid metadata was received from the server + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel Installation + + + + + + + Retry + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 280 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 15 + + + + Install Now + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Install Options + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 150 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Install To + + + + + + + + + + Install for + + + + + + + Stream + + + + + + + Browse... + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Everyone + + + true + + + + + + + + 0 + 0 + + + + This user only + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Stable + + + true + + + + + + + + 0 + 0 + + + + Blueprint + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Install Now + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 127 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 270 + + + + + + + + Getting ready to install... + + + Qt::AlignCenter + + + + + + + 30 + + + 30 + + + + + 0 + + + -1 + + + false + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 270 + + + + + + + + Installation is complete. + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Open Application Name + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Finish + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 250 + + + + + + + + Installation failed. + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Exit + + + + + + + Try Again + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + FadeStackedWidget + QStackedWidget +
fadestackedwidget.h
+ 1 +
+
+ + + + +
diff --git a/installer/process/installworker.cpp b/installer/process/installworker.cpp new file mode 100644 index 0000000..48c7c10 --- /dev/null +++ b/installer/process/installworker.cpp @@ -0,0 +1,78 @@ +#include "installworker.h" + +InstallWorker::InstallWorker(QObject *parent) : QObject(parent) +{ +} + +bool InstallWorker::startWork() { + QLocalSocket* sock = new QLocalSocket(); + QString vendor, name, url, destPath; + bool isStableStream = true, isGlobalInstall = true; + + QString previousToken; + for (QString arg : QApplication::arguments()) { + if (previousToken != "") { + if (previousToken == "--socket") { + sock->setServerName(arg); + } else if (previousToken == "--vendor") { + vendor = arg; + } else if (previousToken == "--name") { + name = arg; + } else if (previousToken == "--url") { + url = arg; + } else if (previousToken == "--destdir") { + destPath = arg; + } + previousToken = ""; + } else { + if (arg == "--socket" || arg == "--vendor" || arg == "--name" || arg == "--url" || arg == "--destdir") { + previousToken = arg; + } else if (arg == "--blueprint") { + isStableStream = false; + } else if (arg == "--stable") { + isStableStream = true; + } else if (arg == "--local") { + isGlobalInstall = false; + } else if (arg == "--global") { + isGlobalInstall = true; + } + } + } + + if (sock->serverName() == "") { + qDebug() << "Required argument --socket missing"; + return false; + } + + qDebug() << "Connecting to socket server..."; + sock->connectToServer(); + if (!sock->waitForConnected()) { + qDebug() << "Failed to connect to socket server"; + return false; + } + connect(sock, &QLocalSocket::disconnected, [=] { + qDebug() << "Socket closed"; + QApplication::exit(1); + }); + + if (!packageFile.open() || !packageTemporaryDir.isValid()) { + return false; + } + sock->write(QString("STATUS ").append(tr("Downloading %1...").arg(name)).append("\n").toUtf8()); + sock->write(QString("DEBUG %1").arg(packageFile.fileName()).toUtf8()); + + QNetworkRequest req(QUrl((QString) url)); + req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + req.setHeader(QNetworkRequest::UserAgentHeader, "theInstaller/1.0"); + QNetworkReply* reply = mgr.get(req); + connect(reply, &QNetworkReply::finished, [=] { + sock->write(QString("STATUS ").append(tr("Unpacking %1...").arg(name)).append("\n").toUtf8()); + sock->write("PROGRESS 0 0\n"); + sock->write(QString("DEBUG %1").arg(packageTemporaryDir.path()).toUtf8()); + }); + connect(reply, &QNetworkReply::downloadProgress, [=](qint64 bytesReceived, qint64 bytesTotal) { + sock->write(QString("PROGRESS %1 %2\n").arg(QString::number(bytesReceived), QString::number(bytesTotal)).toUtf8()); + }); + + return true; +} diff --git a/installer/process/installworker.h b/installer/process/installworker.h new file mode 100644 index 0000000..84cbc48 --- /dev/null +++ b/installer/process/installworker.h @@ -0,0 +1,35 @@ +#ifndef INSTALLWORKER_H +#define INSTALLWORKER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class InstallWorker : public QObject +{ + Q_OBJECT +public: + explicit InstallWorker(QObject *parent = nullptr); + +signals: + +public slots: + bool startWork(); + +private: + QNetworkAccessManager mgr; + QTemporaryFile packageFile; + QTemporaryDir packageTemporaryDir; +}; + +#endif // INSTALLWORKER_H diff --git a/installer/resources.qrc b/installer/resources.qrc new file mode 100644 index 0000000..661ed75 --- /dev/null +++ b/installer/resources.qrc @@ -0,0 +1,8 @@ + + + icon.svg + icon-bp.svg + background.svg + translations/vi_VN.qm + + diff --git a/installer/translations/vi_VN.qm b/installer/translations/vi_VN.qm new file mode 100644 index 0000000..39207f8 Binary files /dev/null and b/installer/translations/vi_VN.qm differ -- cgit v1.2.3