Skip to content

Commit

Permalink
added changelog drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
Nethius committed May 25, 2024
1 parent 53746f2 commit 871037f
Show file tree
Hide file tree
Showing 13 changed files with 384 additions and 51 deletions.
8 changes: 8 additions & 0 deletions client/amnezia_application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,4 +406,12 @@ void AmneziaApplication::initControllers()

m_systemController.reset(new SystemController(m_settings));
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());

m_updateController.reset(new UpdateController(m_settings));
m_engine->rootContext()->setContextProperty("UpdateController", m_updateController.get());
m_updateController->checkForUpdates();

connect(m_updateController.get(), &UpdateController::updateFound, this, [this]() {
QTimer::singleShot(1000, this, [this]() { m_pageController->showChangelogDrawer(); });
});
}
2 changes: 2 additions & 0 deletions client/amnezia_application.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "ui/controllers/sitesController.h"
#include "ui/controllers/systemController.h"
#include "ui/controllers/appSplitTunnelingController.h"
#include "ui/controllers/updateController.h"
#include "ui/models/containers_model.h"
#include "ui/models/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h"
Expand Down Expand Up @@ -130,6 +131,7 @@ class AmneziaApplication : public AMNEZIA_BASE_CLASS
QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
QScopedPointer<UpdateController> m_updateController;

QNetworkAccessManager *m_nam;
};
Expand Down
2 changes: 1 addition & 1 deletion client/core/controllers/apiController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c

QByteArray requestBody = QJsonDocument(apiPayload).toJson();

QNetworkReply *reply = amnApp->manager()->post(request, requestBody); // ??
QNetworkReply *reply = amnApp->manager()->post(request, requestBody);

QObject::connect(reply, &QNetworkReply::finished, [this, reply, protocol, apiPayloadData, serverIndex, serverConfig]() mutable {
if (reply->error() == QNetworkReply::NoError) {
Expand Down
3 changes: 2 additions & 1 deletion client/resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@
<file>ui/qml/Pages2/PageProtocolOpenVpnSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
Expand Down Expand Up @@ -239,5 +239,6 @@
<file>images/controls/alert-circle.svg</file>
<file>images/controls/file-check-2.svg</file>
<file>ui/qml/Controls2/WarningType.qml</file>
<file>ui/qml/Components/ChangelogDrawer.qml</file>
</qresource>
</RCC>
2 changes: 2 additions & 0 deletions client/ui/controllers/pageController.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ public slots:
void forceTabBarActiveFocus();
void forceStackActiveFocus();

void showChangelogDrawer();

private:
QSharedPointer<ServersModel> m_serversModel;

Expand Down
2 changes: 1 addition & 1 deletion client/ui/controllers/systemController.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class SystemController : public QObject
{
Q_OBJECT
public:
explicit SystemController(const std::shared_ptr<Settings> &setting, QObject *parent = nullptr);
explicit SystemController(const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);

static void saveFile(QString fileName, const QString &data);

Expand Down
149 changes: 149 additions & 0 deletions client/ui/controllers/updateController.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include "updateController.h"

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QVersionNumber>
#include <QtConcurrent>

#include "amnezia_application.h"
#include "core/errorstrings.h"
#include "version.h"

namespace {
#ifdef Q_OS_MACOS
const QString installerPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.dmg";
#elif defined Q_OS_WINDOWS
const QString installerPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.exe";
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
const QString installerPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.tar.zip";
#endif
}

UpdateController::UpdateController(const std::shared_ptr<Settings> &settings, QObject *parent) : QObject(parent), m_settings(settings)
{
}

QString UpdateController::getHeaderText()
{
return tr("New version released: %1 (%2)").arg(m_version, m_releaseDate);
}

QString UpdateController::getChangelogText()
{
return m_changelogText;
}

void UpdateController::checkForUpdates()
{
QNetworkRequest request;
request.setTransferTimeout(7000);
QString endpoint = "https://api.github.com/repos/amnezia-vpn/amnezia-client/releases/latest";
request.setUrl(endpoint);

QNetworkReply *reply = amnApp->manager()->get(request);

QObject::connect(reply, &QNetworkReply::finished, [this, reply]() {
if (reply->error() == QNetworkReply::NoError) {
QString contents = QString::fromUtf8(reply->readAll());
QJsonObject data = QJsonDocument::fromJson(contents.toUtf8()).object();
m_version = data.value("tag_name").toString();

auto currentVersion = QVersionNumber::fromString(QString(APP_VERSION));
qDebug() << currentVersion;
auto newVersion = QVersionNumber::fromString(m_version);
if (newVersion > currentVersion) {
m_changelogText = data.value("body").toString();

QString dateString = data.value("published_at").toString();
QDateTime dateTime = QDateTime::fromString(dateString, "yyyy-MM-ddTHH:mm:ssZ");
m_releaseDate = dateTime.toString("MMM dd yyyy");

QJsonArray assets = data.value("assets").toArray();

for (auto asset : assets) {
QJsonObject assetObject = asset.toObject();
if (assetObject.value("name").toString().contains(".dmg")) {
m_downloadUrl = assetObject.value("browser_download_url").toString();
}
}

emit updateFound();
}
} else {
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) {
qDebug() << errorString(ErrorCode::ApiConfigTimeoutError);
} else {
QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll());
qDebug() << reply->error();
qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
qDebug() << errorString(ErrorCode::ApiConfigDownloadError);
}
}

reply->deleteLater();
});

QObject::connect(reply, &QNetworkReply::errorOccurred,
[this, reply](QNetworkReply::NetworkError error) { qDebug() << reply->errorString() << error; });
connect(reply, &QNetworkReply::sslErrors, [this, reply](const QList<QSslError> &errors) {
qDebug().noquote() << errors;
qDebug() << errorString(ErrorCode::ApiConfigSslError);
});
}

void UpdateController::runInstaller()
{
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setUrl(m_downloadUrl);

QNetworkReply *reply = amnApp->manager()->get(request);

QObject::connect(reply, &QNetworkReply::finished, [this, reply]() {
if (reply->error() == QNetworkReply::NoError) {
QFile file(installerPath);
if (file.open(QIODevice::WriteOnly)) {
file.write(reply->readAll());
file.close();

QFutureWatcher<int> watcher;
QFuture<int> future = QtConcurrent::run([this]() {
QString t = installerPath;
QRemoteObjectPendingReply<int> ipcReply = IpcClient::Interface()->mountDmg(t, true);
ipcReply.waitForFinished();
QProcess::execute("/Volumes/AmneziaVPN/AmneziaVPN.app/Contents/MacOS/AmneziaVPN");
ipcReply = IpcClient::Interface()->mountDmg(t, false);
ipcReply.waitForFinished();
return ipcReply.returnValue();
});

QEventLoop wait;
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
watcher.setFuture(future);
wait.exec();

qDebug() << future.result();

// emit errorOccured("");
}
} else {
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) {
qDebug() << errorString(ErrorCode::ApiConfigTimeoutError);
} else {
QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll());
qDebug() << reply->error();
qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
qDebug() << errorString(ErrorCode::ApiConfigDownloadError);
}
}

reply->deleteLater();
});

}
34 changes: 34 additions & 0 deletions client/ui/controllers/updateController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef UPDATECONTROLLER_H
#define UPDATECONTROLLER_H

#include <QObject>

#include "settings.h"

class UpdateController : public QObject
{
Q_OBJECT
public:
explicit UpdateController(const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);

Q_PROPERTY(QString changelogText READ getChangelogText NOTIFY updateFound)
Q_PROPERTY(QString headerText READ getHeaderText NOTIFY updateFound)
public slots:
QString getHeaderText();
QString getChangelogText();

void checkForUpdates();
void runInstaller();
signals:
void updateFound();
void errorOccured(const QString &errorMessage);
private:
std::shared_ptr<Settings> m_settings;

QString m_changelogText;
QString m_version;
QString m_releaseDate;
QString m_downloadUrl;
};

#endif // UPDATECONTROLLER_H
119 changes: 119 additions & 0 deletions client/ui/qml/Components/ChangelogDrawer.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

import "../Controls2"
import "../Controls2/TextTypes"

import "../Config"

DrawerType2 {
id: root

anchors.fill: parent
expandedHeight: parent.height * 0.9

expandedContent: Item {
implicitHeight: root.expandedHeight

Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}

Header2TextType {
id: header
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16

text: UpdateController.headerText
}

FlickableType {
anchors.top: header.bottom
anchors.bottom: updateButton.top
contentHeight: changelog.height + 32

ParagraphTextType {
id: changelog
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 48
anchors.rightMargin: 16
anchors.leftMargin: 16

HoverHandler {
enabled: parent.hoveredLink
cursorShape: Qt.PointingHandCursor
}

onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}

text: UpdateController.changelogText
textFormat: Text.MarkdownText
}
}

Item {
id: focusItem
KeyNavigation.tab: updateButton
}

BasicButtonType {
id: updateButton
anchors.bottom: skipButton.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.bottomMargin: 8
anchors.rightMargin: 16
anchors.leftMargin: 16

text: qsTr("Update")

clickedFunc: function() {
PageController.showBusyIndicator(true)
UpdateController.runInstaller()
PageController.showBusyIndicator(false)
root.close()
}

KeyNavigation.tab: skipButton
}

BasicButtonType {
id: skipButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16

defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
disabledColor: "#878B91"
textColor: "#D7D8DB"
borderWidth: 1

text: qsTr("Skip this version")

clickedFunc: function() {
root.close()
}

KeyNavigation.tab: focusItem
}
}
}
Loading

0 comments on commit 871037f

Please sign in to comment.