moved the platform-specific android code for the new ui
This commit is contained in:
parent
5b8a0881b7
commit
0a1359ed16
31 changed files with 854 additions and 764 deletions
|
@ -293,6 +293,7 @@ if(ANDROID)
|
|||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/android_notificationhandler.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidutils.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidvpnactivity.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/authResultReceiver.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/android_vpnprotocol.h
|
||||
)
|
||||
|
||||
|
@ -301,6 +302,7 @@ if(ANDROID)
|
|||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/android_notificationhandler.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidutils.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidvpnactivity.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/android/authResultReceiver.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/android_vpnprotocol.cpp
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <QFontDatabase>
|
||||
#include <QMimeData>
|
||||
#include <QQuickStyle>
|
||||
#include <QResource>
|
||||
#include <QStandardPaths>
|
||||
#include <QTextDocument>
|
||||
#include <QTimer>
|
||||
|
@ -14,9 +15,12 @@
|
|||
#include "version.h"
|
||||
|
||||
#include "platforms/ios/QRCodeReaderBase.h"
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#include "ui/pages.h"
|
||||
#include "protocols/qml_register_protocols.h"
|
||||
#include "ui/pages.h"
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
||||
|
@ -33,7 +37,7 @@ AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecond
|
|||
setQuitOnLastWindowClosed(false);
|
||||
|
||||
// Fix config file permissions
|
||||
#ifdef Q_OS_LINUX && !defined(Q_OS_ANDROID)
|
||||
#if defined Q_OS_LINUX && !defined(Q_OS_ANDROID)
|
||||
{
|
||||
QSettings s(ORGANIZATION_NAME, APPLICATION_NAME);
|
||||
s.setValue("permFixed", true);
|
||||
|
@ -87,16 +91,35 @@ void AmneziaApplication::init()
|
|||
initModels();
|
||||
initControllers();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
connect(AndroidController::instance(), &AndroidController::initialized, this,
|
||||
[this](bool status, bool connected, const QDateTime &connectionDate) {
|
||||
if (connected) {
|
||||
m_connectionController->onConnectionStateChanged(Vpn::ConnectionState::Connected);
|
||||
if (m_vpnConnection)
|
||||
m_vpnConnection->restoreConnection();
|
||||
}
|
||||
});
|
||||
if (!AndroidController::instance()->initialize()) {
|
||||
qCritical() << QString("Init failed");
|
||||
if (m_vpnConnection)
|
||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, m_importController.get(),
|
||||
&ImportController::extractConfigFromData);
|
||||
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, m_pageController.get(),
|
||||
&PageController::goToPageViewConfig);
|
||||
#endif
|
||||
|
||||
m_notificationHandler.reset(NotificationHandler::create(nullptr));
|
||||
|
||||
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
|
||||
&NotificationHandler::setConnectionState);
|
||||
|
||||
void openConnection();
|
||||
void closeConnection();
|
||||
|
||||
connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(),
|
||||
&PageController::raise);
|
||||
&PageController::raiseMainWindow);
|
||||
connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
|
||||
&ConnectionController::openConnection);
|
||||
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
||||
|
|
|
@ -13,17 +13,16 @@
|
|||
|
||||
#include "android_controller.h"
|
||||
#include "private/qandroidextras_p.h"
|
||||
#include "ui/pages_logic/StartPageLogic.h"
|
||||
|
||||
#include "androidvpnactivity.h"
|
||||
#include "androidutils.h"
|
||||
#include "androidvpnactivity.h"
|
||||
|
||||
namespace {
|
||||
AndroidController* s_instance = nullptr;
|
||||
namespace
|
||||
{
|
||||
AndroidController *s_instance = nullptr;
|
||||
|
||||
constexpr auto PERMISSIONHELPER_CLASS =
|
||||
"org/amnezia/vpn/qt/VPNPermissionHelper";
|
||||
} // namespace
|
||||
constexpr auto PERMISSIONHELPER_CLASS = "org/amnezia/vpn/qt/VPNPermissionHelper";
|
||||
} // namespace
|
||||
|
||||
AndroidController::AndroidController() : QObject()
|
||||
{
|
||||
|
@ -33,109 +32,127 @@ AndroidController::AndroidController() : QObject()
|
|||
|
||||
auto activity = AndroidVPNActivity::instance();
|
||||
|
||||
connect(activity, &AndroidVPNActivity::serviceConnected, this, []() {
|
||||
qDebug() << "Transact: service connected";
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, "");
|
||||
}, Qt::QueuedConnection);
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::serviceConnected, this,
|
||||
[]() {
|
||||
qDebug() << "Transact: service connected";
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, "");
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventInitialized, this,
|
||||
[this](const QString& parcelBody) {
|
||||
// We might get multiple Init events as widgets, or fragments
|
||||
// might query this.
|
||||
if (m_init) {
|
||||
return;
|
||||
}
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::eventInitialized, this,
|
||||
[this](const QString &parcelBody) {
|
||||
// We might get multiple Init events as widgets, or fragments
|
||||
// might query this.
|
||||
if (m_init) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Transact: init";
|
||||
qDebug() << "Transact: init";
|
||||
|
||||
m_init = true;
|
||||
m_init = true;
|
||||
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
qlonglong time = doc.object()["time"].toVariant().toLongLong();
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
qlonglong time = doc.object()["time"].toVariant().toLongLong();
|
||||
|
||||
isConnected = doc.object()["connected"].toBool();
|
||||
isConnected = doc.object()["connected"].toBool();
|
||||
|
||||
if (isConnected) {
|
||||
emit scheduleStatusCheckSignal();
|
||||
}
|
||||
if (isConnected) {
|
||||
emit scheduleStatusCheckSignal();
|
||||
}
|
||||
|
||||
emit initialized(
|
||||
true, isConnected,
|
||||
time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime());
|
||||
emit initialized(true, isConnected, time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime());
|
||||
|
||||
setFallbackConnectedNotification();
|
||||
}, Qt::QueuedConnection);
|
||||
setFallbackConnectedNotification();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventConnected, this,
|
||||
[this](const QString& parcelBody) {
|
||||
Q_UNUSED(parcelBody);
|
||||
qDebug() << "Transact: connected";
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::eventConnected, this,
|
||||
[this](const QString &parcelBody) {
|
||||
Q_UNUSED(parcelBody);
|
||||
qDebug() << "Transact: connected";
|
||||
|
||||
if (!isConnected) {
|
||||
emit scheduleStatusCheckSignal();
|
||||
}
|
||||
if (!isConnected) {
|
||||
emit scheduleStatusCheckSignal();
|
||||
}
|
||||
|
||||
isConnected = true;
|
||||
isConnected = true;
|
||||
|
||||
emit connectionStateChanged(VpnProtocol::Connected);
|
||||
}, Qt::QueuedConnection);
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventDisconnected, this,
|
||||
[this]() {
|
||||
qDebug() << "Transact: disconnected";
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::eventDisconnected, this,
|
||||
[this]() {
|
||||
qDebug() << "Transact: disconnected";
|
||||
|
||||
isConnected = false;
|
||||
isConnected = false;
|
||||
|
||||
emit connectionStateChanged(VpnProtocol::Disconnected);
|
||||
}, Qt::QueuedConnection);
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventStatisticUpdate, this,
|
||||
[this](const QString& parcelBody) {
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::eventStatisticUpdate, this,
|
||||
[this](const QString &parcelBody) {
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
|
||||
QString rx = doc.object()["rx_bytes"].toString();
|
||||
QString tx = doc.object()["tx_bytes"].toString();
|
||||
QString endpoint = doc.object()["endpoint"].toString();
|
||||
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
|
||||
QString rx = doc.object()["rx_bytes"].toString();
|
||||
QString tx = doc.object()["tx_bytes"].toString();
|
||||
QString endpoint = doc.object()["endpoint"].toString();
|
||||
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
|
||||
|
||||
emit statusUpdated(rx, tx, endpoint, deviceIPv4);
|
||||
}, Qt::QueuedConnection);
|
||||
emit statusUpdated(rx, tx, endpoint, deviceIPv4);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventBackendLogs, this,
|
||||
[this](const QString& parcelBody) {
|
||||
qDebug() << "Transact: backend logs";
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::eventBackendLogs, this,
|
||||
[this](const QString &parcelBody) {
|
||||
qDebug() << "Transact: backend logs";
|
||||
|
||||
QString buffer = parcelBody.toUtf8();
|
||||
if (m_logCallback) {
|
||||
m_logCallback(buffer);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
QString buffer = parcelBody.toUtf8();
|
||||
if (m_logCallback) {
|
||||
m_logCallback(buffer);
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventActivationError, this,
|
||||
[this](const QString& parcelBody) {
|
||||
Q_UNUSED(parcelBody)
|
||||
qDebug() << "Transact: error";
|
||||
emit connectionStateChanged(VpnProtocol::Error);
|
||||
}, Qt::QueuedConnection);
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::eventActivationError, this,
|
||||
[this](const QString &parcelBody) {
|
||||
Q_UNUSED(parcelBody)
|
||||
qDebug() << "Transact: error";
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventConfigImport, this,
|
||||
[this](const QString& parcelBody) {
|
||||
qDebug() << "Transact: config import";
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::eventConfigImport, this,
|
||||
[this](const QString &parcelBody) {
|
||||
qDebug() << "Transact: config import";
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
|
||||
QString buffer = doc.object()["config"].toString();
|
||||
qDebug() << "Transact: config string" << buffer;
|
||||
importConfig(buffer);
|
||||
}, Qt::QueuedConnection);
|
||||
QString buffer = doc.object()["config"].toString();
|
||||
qDebug() << "Transact: config string" << buffer;
|
||||
importConfigFromOutside(buffer);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::serviceDisconnected, this,
|
||||
[this]() {
|
||||
qDebug() << "Transact: service disconnected";
|
||||
m_serviceConnected = false;
|
||||
}, Qt::QueuedConnection);
|
||||
connect(
|
||||
activity, &AndroidVPNActivity::serviceDisconnected, this,
|
||||
[this]() {
|
||||
qDebug() << "Transact: service disconnected";
|
||||
m_serviceConnected = false;
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
AndroidController* AndroidController::instance() {
|
||||
AndroidController *AndroidController::instance()
|
||||
{
|
||||
if (!s_instance) {
|
||||
s_instance = new AndroidController();
|
||||
}
|
||||
|
@ -143,16 +160,13 @@ AndroidController* AndroidController::instance() {
|
|||
return s_instance;
|
||||
}
|
||||
|
||||
bool AndroidController::initialize(StartPageLogic *startPageLogic)
|
||||
bool AndroidController::initialize()
|
||||
{
|
||||
qDebug() << "Initializing";
|
||||
|
||||
m_startPageLogic = startPageLogic;
|
||||
|
||||
// Hook in the native implementation for startActivityForResult into the JNI
|
||||
JNINativeMethod methods[]{{"startActivityForResult",
|
||||
"(Landroid/content/Intent;)V",
|
||||
reinterpret_cast<void*>(startActivityForResult)}};
|
||||
JNINativeMethod methods[] { { "startActivityForResult", "(Landroid/content/Intent;)V",
|
||||
reinterpret_cast<void *>(startActivityForResult) } };
|
||||
QJniObject javaClass(PERMISSIONHELPER_CLASS);
|
||||
QJniEnvironment env;
|
||||
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
|
||||
|
@ -168,11 +182,9 @@ ErrorCode AndroidController::start()
|
|||
{
|
||||
qDebug() << "Prompting for VPN permission";
|
||||
QJniObject activity = AndroidUtils::getActivity();
|
||||
auto appContext = activity.callObjectMethod(
|
||||
"getApplicationContext", "()Landroid/content/Context;");
|
||||
QJniObject::callStaticMethod<void>(
|
||||
PERMISSIONHELPER_CLASS, "startService", "(Landroid/content/Context;)V",
|
||||
appContext.object());
|
||||
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
|
||||
QJniObject::callStaticMethod<void>(PERMISSIONHELPER_CLASS, "startService", "(Landroid/content/Context;)V",
|
||||
appContext.object());
|
||||
|
||||
QJsonDocument doc(m_vpnConfig);
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_ACTIVATE, doc.toJson());
|
||||
|
@ -180,7 +192,8 @@ ErrorCode AndroidController::start()
|
|||
return NoError;
|
||||
}
|
||||
|
||||
void AndroidController::stop() {
|
||||
void AndroidController::stop()
|
||||
{
|
||||
qDebug() << "AndroidController::stop";
|
||||
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_DEACTIVATE, QString());
|
||||
|
@ -188,16 +201,16 @@ void AndroidController::stop() {
|
|||
|
||||
// Activates the tunnel that is currently set
|
||||
// in the VPN Service
|
||||
void AndroidController::resumeStart() {
|
||||
void AndroidController::resumeStart()
|
||||
{
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_RESUME_ACTIVATE, QString());
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the current notification text that is shown
|
||||
*/
|
||||
void AndroidController::setNotificationText(const QString& title,
|
||||
const QString& message,
|
||||
int timerSec) {
|
||||
void AndroidController::setNotificationText(const QString &title, const QString &message, int timerSec)
|
||||
{
|
||||
QJsonObject args;
|
||||
args["title"] = title;
|
||||
args["message"] = message;
|
||||
|
@ -207,7 +220,8 @@ void AndroidController::setNotificationText(const QString& title,
|
|||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_TEXT, doc.toJson());
|
||||
}
|
||||
|
||||
void AndroidController::shareConfig(const QString& configContent, const QString& suggestedName) {
|
||||
void AndroidController::shareConfig(const QString &configContent, const QString &suggestedName)
|
||||
{
|
||||
AndroidVPNActivity::saveFileAs(configContent, suggestedName);
|
||||
}
|
||||
|
||||
|
@ -216,7 +230,8 @@ void AndroidController::shareConfig(const QString& configContent, const QString&
|
|||
* switches into the Connected state without the app open
|
||||
* e.g via always-on vpn
|
||||
*/
|
||||
void AndroidController::setFallbackConnectedNotification() {
|
||||
void AndroidController::setFallbackConnectedNotification()
|
||||
{
|
||||
QJsonObject args;
|
||||
args["title"] = tr("AmneziaVPN");
|
||||
//% "Ready for you to connect"
|
||||
|
@ -227,11 +242,13 @@ void AndroidController::setFallbackConnectedNotification() {
|
|||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_FALLBACK, doc.toJson());
|
||||
}
|
||||
|
||||
void AndroidController::checkStatus() {
|
||||
void AndroidController::checkStatus()
|
||||
{
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, QString());
|
||||
}
|
||||
|
||||
void AndroidController::getBackendLogs(std::function<void(const QString&)>&& a_callback) {
|
||||
void AndroidController::getBackendLogs(std::function<void(const QString &)> &&a_callback)
|
||||
{
|
||||
qDebug() << "get logs";
|
||||
|
||||
m_logCallback = std::move(a_callback);
|
||||
|
@ -239,16 +256,13 @@ void AndroidController::getBackendLogs(std::function<void(const QString&)>&& a_c
|
|||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_GET_LOG, QString());
|
||||
}
|
||||
|
||||
void AndroidController::cleanupBackendLogs() {
|
||||
void AndroidController::cleanupBackendLogs()
|
||||
{
|
||||
qDebug() << "cleanup logs";
|
||||
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_CLEANUP_LOG, QString());
|
||||
}
|
||||
|
||||
void AndroidController::importConfig(const QString& data){
|
||||
m_startPageLogic->importAnyFile(data);
|
||||
}
|
||||
|
||||
const QJsonObject &AndroidController::vpnConfig() const
|
||||
{
|
||||
return m_vpnConfig;
|
||||
|
@ -285,31 +299,29 @@ void AndroidController::startActivityForResult(JNIEnv *env, jobject, jobject int
|
|||
qDebug() << "start vpnPermissionHelper";
|
||||
Q_UNUSED(env);
|
||||
|
||||
QtAndroidPrivate::startActivity(intent, 1337,
|
||||
[](int receiverRequestCode, int resultCode,
|
||||
const QJniObject& data) {
|
||||
// Currently this function just used in
|
||||
// VPNService.kt::checkPermissions. So the result
|
||||
// we're getting is if the User gave us the
|
||||
// Vpn.bind permission. In case of NO we should
|
||||
// abort.
|
||||
Q_UNUSED(receiverRequestCode);
|
||||
Q_UNUSED(data);
|
||||
QtAndroidPrivate::startActivity(intent, 1337, [](int receiverRequestCode, int resultCode, const QJniObject &data) {
|
||||
// Currently this function just used in
|
||||
// VPNService.kt::checkPermissions. So the result
|
||||
// we're getting is if the User gave us the
|
||||
// Vpn.bind permission. In case of NO we should
|
||||
// abort.
|
||||
Q_UNUSED(receiverRequestCode);
|
||||
Q_UNUSED(data);
|
||||
|
||||
AndroidController* controller = AndroidController::instance();
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
AndroidController *controller = AndroidController::instance();
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (resultCode == ACTIVITY_RESULT_OK) {
|
||||
qDebug() << "VPN PROMPT RESULT - Accepted";
|
||||
controller->resumeStart();
|
||||
return;
|
||||
}
|
||||
// If the request got rejected abort the current
|
||||
// connection.
|
||||
qWarning() << "VPN PROMPT RESULT - Rejected";
|
||||
emit controller->connectionStateChanged(VpnProtocol::Disconnected);
|
||||
});
|
||||
if (resultCode == ACTIVITY_RESULT_OK) {
|
||||
qDebug() << "VPN PROMPT RESULT - Accepted";
|
||||
controller->resumeStart();
|
||||
return;
|
||||
}
|
||||
// If the request got rejected abort the current
|
||||
// connection.
|
||||
qWarning() << "VPN PROMPT RESULT - Rejected";
|
||||
emit controller->connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -8,36 +8,32 @@
|
|||
#include <QJniEnvironment>
|
||||
#include <QJniObject>
|
||||
|
||||
#include "ui/pages_logic/StartPageLogic.h"
|
||||
|
||||
#include "protocols/vpnprotocol.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
|
||||
class AndroidController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AndroidController();
|
||||
static AndroidController* instance();
|
||||
static AndroidController *instance();
|
||||
|
||||
virtual ~AndroidController() override = default;
|
||||
|
||||
bool initialize(StartPageLogic *startPageLogic);
|
||||
bool initialize();
|
||||
|
||||
ErrorCode start();
|
||||
void stop();
|
||||
void resumeStart();
|
||||
|
||||
void checkStatus();
|
||||
void setNotificationText(const QString& title, const QString& message, int timerSec);
|
||||
void shareConfig(const QString& data, const QString& suggestedName);
|
||||
void setNotificationText(const QString &title, const QString &message, int timerSec);
|
||||
void shareConfig(const QString &data, const QString &suggestedName);
|
||||
void setFallbackConnectedNotification();
|
||||
void getBackendLogs(std::function<void(const QString&)>&& callback);
|
||||
void getBackendLogs(std::function<void(const QString &)> &&callback);
|
||||
void cleanupBackendLogs();
|
||||
void importConfig(const QString& data);
|
||||
|
||||
const QJsonObject &vpnConfig() const;
|
||||
void setVpnConfig(const QJsonObject &newVpnConfig);
|
||||
|
@ -45,18 +41,20 @@ public:
|
|||
void startQrReaderActivity();
|
||||
|
||||
signals:
|
||||
void connectionStateChanged(VpnProtocol::VpnConnectionState state);
|
||||
void connectionStateChanged(Vpn::ConnectionState state);
|
||||
|
||||
// This signal is emitted when the controller is initialized. Note that the
|
||||
// VPN tunnel can be already active. In this case, "connected" should be set
|
||||
// to true and the "connectionDate" should be set to the activation date if
|
||||
// known.
|
||||
// If "status" is set to false, the backend service is considered unavailable.
|
||||
void initialized(bool status, bool connected, const QDateTime& connectionDate);
|
||||
void initialized(bool status, bool connected, const QDateTime &connectionDate);
|
||||
|
||||
void statusUpdated(QString totalRx, QString totalTx, QString endpoint, QString deviceIPv4);
|
||||
void scheduleStatusCheckSignal();
|
||||
|
||||
void importConfigFromOutside(QString &data);
|
||||
|
||||
protected slots:
|
||||
void scheduleStatusCheckSlot();
|
||||
|
||||
|
@ -65,12 +63,10 @@ private:
|
|||
|
||||
QJsonObject m_vpnConfig;
|
||||
|
||||
StartPageLogic *m_startPageLogic;
|
||||
|
||||
bool m_serviceConnected = false;
|
||||
std::function<void(const QString&)> m_logCallback;
|
||||
std::function<void(const QString &)> m_logCallback;
|
||||
|
||||
static void startActivityForResult(JNIEnv* env, jobject /*thiz*/, jobject intent);
|
||||
static void startActivityForResult(JNIEnv *env, jobject /*thiz*/, jobject intent);
|
||||
|
||||
bool isConnected = false;
|
||||
|
||||
|
|
16
client/platforms/android/authResultReceiver.cpp
Normal file
16
client/platforms/android/authResultReceiver.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "authResultReceiver.h"
|
||||
|
||||
AuthResultReceiver::AuthResultReceiver(QSharedPointer<AuthResultNotifier> ¬ifier) : m_notifier(notifier)
|
||||
{
|
||||
}
|
||||
|
||||
void AuthResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data)
|
||||
{
|
||||
qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode;
|
||||
|
||||
if (resultCode == -1) { // ResultOK
|
||||
emit m_notifier->authSuccessful();
|
||||
} else {
|
||||
emit m_notifier->authFailed();
|
||||
}
|
||||
}
|
32
client/platforms/android/authResultReceiver.h
Normal file
32
client/platforms/android/authResultReceiver.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef AUTHRESULTRECEIVER_H
|
||||
#define AUTHRESULTRECEIVER_H
|
||||
|
||||
#include <QJniObject>
|
||||
|
||||
#include <private/qandroidextras_p.h>
|
||||
|
||||
class AuthResultNotifier : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AuthResultNotifier(QObject *parent = nullptr) : QObject(parent) {};
|
||||
|
||||
signals:
|
||||
void authFailed();
|
||||
void authSuccessful();
|
||||
};
|
||||
|
||||
/* Auth result handler for Android */
|
||||
class AuthResultReceiver final : public QAndroidActivityResultReceiver
|
||||
{
|
||||
public:
|
||||
AuthResultReceiver(QSharedPointer<AuthResultNotifier> ¬ifier);
|
||||
|
||||
void handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data) override;
|
||||
|
||||
private:
|
||||
QSharedPointer<AuthResultNotifier> m_notifier;
|
||||
};
|
||||
|
||||
#endif // AUTHRESULTRECEIVER_H
|
|
@ -5,27 +5,28 @@
|
|||
#include <QThread>
|
||||
|
||||
#include "logger.h"
|
||||
#include "wireguardprotocol.h"
|
||||
#include "utilities.h"
|
||||
#include "wireguardprotocol.h"
|
||||
|
||||
#include "mozilla/localsocketcontroller.h"
|
||||
|
||||
WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject* parent) : VpnProtocol(configuration, parent)
|
||||
WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *parent)
|
||||
: VpnProtocol(configuration, parent)
|
||||
{
|
||||
m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
|
||||
writeWireguardConfiguration(configuration);
|
||||
|
||||
// MZ
|
||||
#if defined(MZ_LINUX)
|
||||
//m_impl.reset(new LinuxController());
|
||||
// m_impl.reset(new LinuxController());
|
||||
#elif defined(MZ_MACOS) // || defined(MZ_WINDOWS)
|
||||
m_impl.reset(new LocalSocketController());
|
||||
connect(m_impl.get(), &ControllerImpl::connected, this, [this](const QString& pubkey, const QDateTime& connectionTimestamp) {
|
||||
emit connectionStateChanged(VpnProtocol::Connected);
|
||||
});
|
||||
connect(m_impl.get(), &ControllerImpl::disconnected, this, [this](){
|
||||
emit connectionStateChanged(VpnProtocol::Disconnected);
|
||||
});
|
||||
connect(m_impl.get(), &ControllerImpl::connected, this,
|
||||
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
||||
});
|
||||
connect(m_impl.get(), &ControllerImpl::disconnected, this,
|
||||
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
|
||||
m_impl->initialize(nullptr, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
@ -74,9 +75,10 @@ void WireguardProtocol::stop()
|
|||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
});
|
||||
|
||||
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::stateChanged, this, [this](QProcess::ProcessState newState) {
|
||||
qDebug() << "WireguardProtocol::WireguardProtocol Stop stateChanged" << newState;
|
||||
});
|
||||
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::stateChanged, this,
|
||||
[this](QProcess::ProcessState newState) {
|
||||
qDebug() << "WireguardProtocol::WireguardProtocol Stop stateChanged" << newState;
|
||||
});
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
if (IpcClient::Interface()) {
|
||||
|
@ -143,8 +145,8 @@ void WireguardProtocol::writeWireguardConfiguration(const QJsonObject &configura
|
|||
m_isConfigLoaded = true;
|
||||
|
||||
qDebug().noquote() << QString("Set config data") << configPath();
|
||||
qDebug().noquote() << QString("Set config data") << configuration.value(ProtocolProps::key_proto_config_data(Proto::WireGuard)).toString().toUtf8();
|
||||
|
||||
qDebug().noquote() << QString("Set config data")
|
||||
<< configuration.value(ProtocolProps::key_proto_config_data(Proto::WireGuard)).toString().toUtf8();
|
||||
}
|
||||
|
||||
QString WireguardProtocol::configPath() const
|
||||
|
@ -156,7 +158,8 @@ void WireguardProtocol::updateRouteGateway(QString line)
|
|||
{
|
||||
// TODO: fix for macos
|
||||
line = line.split("ROUTE_GATEWAY", Qt::SkipEmptyParts).at(1);
|
||||
if (!line.contains("/")) return;
|
||||
if (!line.contains("/"))
|
||||
return;
|
||||
m_routeGateway = line.split("/", Qt::SkipEmptyParts).first();
|
||||
m_routeGateway.replace(" ", "");
|
||||
qDebug() << "Set VPN route gateway" << m_routeGateway;
|
||||
|
@ -216,13 +219,13 @@ ErrorCode WireguardProtocol::start()
|
|||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
});
|
||||
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::stateChanged, this, [this](QProcess::ProcessState newState) {
|
||||
qDebug() << "WireguardProtocol::WireguardProtocol stateChanged" << newState;
|
||||
});
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::stateChanged, this,
|
||||
[this](QProcess::ProcessState newState) {
|
||||
qDebug() << "WireguardProtocol::WireguardProtocol stateChanged" << newState;
|
||||
});
|
||||
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this, [this]() {
|
||||
setConnectionState(Vpn::ConnectionState::Connected);
|
||||
});
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this,
|
||||
[this]() { setConnectionState(Vpn::ConnectionState::Connected); });
|
||||
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyRead, this, [this]() {
|
||||
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAll();
|
||||
|
@ -250,7 +253,6 @@ ErrorCode WireguardProtocol::start()
|
|||
|
||||
void WireguardProtocol::updateVpnGateway(const QString &line)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString WireguardProtocol::serviceName() const
|
||||
|
@ -261,9 +263,9 @@ QString WireguardProtocol::serviceName() const
|
|||
QStringList WireguardProtocol::stopArgs()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return {"--remove", configPath()};
|
||||
return { "--remove", configPath() };
|
||||
#elif defined Q_OS_LINUX
|
||||
return {"down", "wg99"};
|
||||
return { "down", "wg99" };
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
|
@ -272,11 +274,10 @@ QStringList WireguardProtocol::stopArgs()
|
|||
QStringList WireguardProtocol::startArgs()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return {"--add", configPath()};
|
||||
return { "--add", configPath() };
|
||||
#elif defined Q_OS_LINUX
|
||||
return {"up", "wg99"};
|
||||
return { "up", "wg99" };
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -194,7 +194,6 @@
|
|||
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
|
||||
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
|
||||
<file>ui/qml/Controls2/SwitcherType.qml</file>
|
||||
<file>ui/qml/Pages2/PageTest.qml</file>
|
||||
<file>ui/qml/Controls2/TabButtonType.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
|
||||
|
@ -278,5 +277,6 @@
|
|||
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
|
||||
<file>images/controls/copy.svg</file>
|
||||
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -11,9 +11,12 @@
|
|||
|
||||
#include "configurators/openvpn_configurator.h"
|
||||
#include "configurators/wireguard_configurator.h"
|
||||
#include "qrcodegen.hpp"
|
||||
|
||||
#include "core/errorstrings.h"
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#include "platforms/android/androidutils.h"
|
||||
#endif
|
||||
#include "qrcodegen.hpp"
|
||||
|
||||
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
|
@ -25,6 +28,14 @@ ExportController::ExportController(const QSharedPointer<ServersModel> &serversMo
|
|||
m_settings(settings),
|
||||
m_configurator(configurator)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
m_authResultNotifier.reset(new AuthResultNotifier);
|
||||
m_authResultReceiver.reset(new AuthResultReceiver(m_authResultNotifier));
|
||||
connect(m_authResultNotifier.get(), &AuthResultNotifier::authFailed, this,
|
||||
[this]() { emit exportErrorOccurred(tr("Access error!")); });
|
||||
connect(m_authResultNotifier.get(), &AuthResultNotifier::authSuccessful, this,
|
||||
&ExportController::generateFullAccessConfig);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExportController::generateFullAccessConfig()
|
||||
|
@ -44,6 +55,27 @@ void ExportController::generateFullAccessConfig()
|
|||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
void ExportController::generateFullAccessConfigAndroid()
|
||||
{
|
||||
/* We use builtin keyguard for ssh key export protection on Android */
|
||||
QJniObject activity = AndroidUtils::getActivity();
|
||||
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
|
||||
if (appContext.isValid()) {
|
||||
auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent",
|
||||
"(Landroid/content/Context;)Landroid/content/Intent;",
|
||||
appContext.object());
|
||||
if (intent.isValid()) {
|
||||
if (intent.object<jobject>() != nullptr) {
|
||||
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, m_authResultReceiver.get());
|
||||
}
|
||||
} else {
|
||||
generateFullAccessConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ExportController::generateConnectionConfig()
|
||||
{
|
||||
clearPreviousConfig();
|
||||
|
@ -194,6 +226,35 @@ void ExportController::saveFile()
|
|||
QDesktopServices::openUrl(fi.absoluteDir().absolutePath());
|
||||
}
|
||||
|
||||
void ExportController::shareFile()
|
||||
{
|
||||
#if defined Q_OS_IOS
|
||||
ext.replace("*", "");
|
||||
QString fileName = QDir::tempPath() + "/" + suggestedName;
|
||||
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
if (!fileName.endsWith(ext))
|
||||
fileName.append(ext);
|
||||
|
||||
QFile::remove(fileName);
|
||||
|
||||
QFile save(fileName);
|
||||
save.open(QIODevice::WriteOnly);
|
||||
save.write(data.toUtf8());
|
||||
save.close();
|
||||
|
||||
QStringList filesToSend;
|
||||
filesToSend.append(fileName);
|
||||
MobileUtils::shareText(filesToSend);
|
||||
return;
|
||||
#endif
|
||||
#if defined Q_OS_ANDROID
|
||||
AndroidController::instance()->shareConfig(m_config, "amnezia_config");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &data)
|
||||
{
|
||||
double k = 850;
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
#include "configurators/vpn_configurator.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/authResultReceiver.h"
|
||||
#endif
|
||||
|
||||
class ExportController : public QObject
|
||||
{
|
||||
|
@ -22,6 +25,9 @@ public:
|
|||
|
||||
public slots:
|
||||
void generateFullAccessConfig();
|
||||
#if defined(Q_OS_ANDROID)
|
||||
void generateFullAccessConfigAndroid();
|
||||
#endif
|
||||
void generateConnectionConfig();
|
||||
void generateOpenVpnConfig();
|
||||
void generateWireGuardConfig();
|
||||
|
@ -30,6 +36,7 @@ public slots:
|
|||
QList<QString> getQrCodes();
|
||||
|
||||
void saveFile();
|
||||
void shareFile();
|
||||
|
||||
signals:
|
||||
void generateConfig(int type);
|
||||
|
@ -52,6 +59,11 @@ private:
|
|||
|
||||
QString m_config;
|
||||
QList<QString> m_qrCodes;
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
QSharedPointer<AuthResultNotifier> m_authResultNotifier;
|
||||
QSharedPointer<QAndroidActivityResultReceiver> m_authResultReceiver;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // EXPORTCONTROLLER_H
|
||||
|
|
|
@ -2,8 +2,15 @@
|
|||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "core/errorstrings.h"
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "../../platforms/android/android_controller.h"
|
||||
#include "../../platforms/android/androidutils.h"
|
||||
#include <QJniObject>
|
||||
#endif
|
||||
#include "utilities.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -41,33 +48,58 @@ ImportController::ImportController(const QSharedPointer<ServersModel> &serversMo
|
|||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_settings(settings)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
// Set security screen for Android app
|
||||
AndroidUtils::runOnAndroidThreadSync([]() {
|
||||
QJniObject activity = AndroidUtils::getActivity();
|
||||
QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
|
||||
if (window.isValid()) {
|
||||
const int FLAG_SECURE = 8192;
|
||||
window.callMethod<void>("addFlags", "(I)V", FLAG_SECURE);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImportController::extractConfigFromFile(const QUrl &fileUrl)
|
||||
void ImportController::extractConfigFromFile()
|
||||
{
|
||||
QFile file(fileUrl.toLocalFile());
|
||||
QString fileName = Utils::getFileName(Q_NULLPTR, tr("Open config file"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
|
||||
"*.vpn *.ovpn *.conf");
|
||||
QFile file(fileName);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QString data = file.readAll();
|
||||
|
||||
auto configFormat = checkConfigFormat(data);
|
||||
if (configFormat == ConfigTypes::OpenVpn) {
|
||||
m_config = extractOpenVpnConfig(data);
|
||||
} else if (configFormat == ConfigTypes::WireGuard) {
|
||||
m_config = extractWireGuardConfig(data);
|
||||
} else {
|
||||
m_config = extractAmneziaConfig(data);
|
||||
}
|
||||
|
||||
extractConfigFromData(data);
|
||||
m_configFileName = QFileInfo(file.fileName()).fileName();
|
||||
}
|
||||
}
|
||||
|
||||
void ImportController::extractConfigFromData(QString &data)
|
||||
{
|
||||
auto configFormat = checkConfigFormat(data);
|
||||
if (configFormat == ConfigTypes::OpenVpn) {
|
||||
m_config = extractOpenVpnConfig(data);
|
||||
} else if (configFormat == ConfigTypes::WireGuard) {
|
||||
m_config = extractWireGuardConfig(data);
|
||||
} else {
|
||||
m_config = extractAmneziaConfig(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportController::extractConfigFromCode(QString code)
|
||||
{
|
||||
m_config = extractAmneziaConfig(code);
|
||||
m_configFileName = "";
|
||||
}
|
||||
|
||||
void ImportController::extractConfigFromQr()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->startQrReaderActivity();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ImportController::getConfig()
|
||||
{
|
||||
return QJsonDocument(m_config).toJson(QJsonDocument::Indented);
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/defs.h"
|
||||
#include "containers/containers_defs.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
#include "core/defs.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
|
||||
class ImportController : public QObject
|
||||
{
|
||||
|
@ -14,13 +14,14 @@ class ImportController : public QObject
|
|||
public:
|
||||
explicit ImportController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const std::shared_ptr<Settings> &settings,
|
||||
QObject *parent = nullptr);
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void importConfig();
|
||||
void extractConfigFromFile(const QUrl &fileUrl);
|
||||
void extractConfigFromFile();
|
||||
void extractConfigFromData(QString &data);
|
||||
void extractConfigFromCode(QString code);
|
||||
void extractConfigFromQr();
|
||||
QString getConfig();
|
||||
QString getConfigFileName();
|
||||
|
||||
|
@ -39,7 +40,6 @@ private:
|
|||
|
||||
QJsonObject m_config;
|
||||
QString m_configFileName;
|
||||
|
||||
};
|
||||
|
||||
#endif // IMPORTCONTROLLER_H
|
||||
|
|
|
@ -8,6 +8,34 @@
|
|||
#include "core/servercontroller.h"
|
||||
#include "utilities.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
QString getNextDriverLetter()
|
||||
{
|
||||
QProcess drivesProc;
|
||||
drivesProc.start("wmic logicaldisk get caption");
|
||||
drivesProc.waitForFinished();
|
||||
QString drives = drivesProc.readAll();
|
||||
qDebug() << drives;
|
||||
|
||||
QString letters = "CFGHIJKLMNOPQRSTUVWXYZ";
|
||||
QString letter;
|
||||
for (int i = letters.size() - 1; i > 0; i--) {
|
||||
letter = letters.at(i);
|
||||
if (!drives.contains(letter + ":"))
|
||||
break;
|
||||
}
|
||||
if (letter == "C:") {
|
||||
// set err info
|
||||
qDebug() << "Can't find free drive letter";
|
||||
return "";
|
||||
}
|
||||
return letter;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
|
@ -15,6 +43,17 @@ InstallController::InstallController(const QSharedPointer<ServersModel> &servers
|
|||
{
|
||||
}
|
||||
|
||||
InstallController::~InstallController()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
for (QSharedPointer<QProcess> process : m_sftpMountProcesses) {
|
||||
Utils::signalCtrl(process->processId(), CTRL_C_EVENT);
|
||||
process->kill();
|
||||
process->waitForFinished();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void InstallController::install(DockerContainer container, int port, TransportProto transportProto)
|
||||
{
|
||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||
|
|
|
@ -16,6 +16,7 @@ public:
|
|||
explicit InstallController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
|
||||
~InstallController();
|
||||
|
||||
public slots:
|
||||
void install(DockerContainer container, int port, TransportProto transportProto);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "pageController.h"
|
||||
|
||||
PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
|
||||
QObject *parent) : QObject(parent), m_serversModel(serversModel)
|
||||
#include <QApplication>
|
||||
|
||||
PageController::PageController(const QSharedPointer<ServersModel> &serversModel, QObject *parent)
|
||||
: QObject(parent), m_serversModel(serversModel)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -24,3 +26,24 @@ QString PageController::getPagePath(PageLoader::PageEnum page)
|
|||
QString pageName = metaEnum.valueToKey(static_cast<int>(page));
|
||||
return "qrc:/ui/qml/Pages2/" + pageName + ".qml";
|
||||
}
|
||||
|
||||
void PageController::closeWindow()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
qApp->quit();
|
||||
#else
|
||||
if (m_serversModel->getServersCount() == 0) {
|
||||
qApp->quit();
|
||||
} else {
|
||||
emit hideMainWindow();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PageController::keyPressEvent(Qt::Key key)
|
||||
{
|
||||
switch (key) {
|
||||
case Qt::Key_Back: emit closePage();
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace PageLoader
|
|||
PageSetupWizardConfigSource,
|
||||
PageSetupWizardTextKey,
|
||||
PageSetupWizardViewConfig,
|
||||
PageSetupWizardQrReader,
|
||||
|
||||
PageProtocolOpenVpnSettings,
|
||||
PageProtocolShadowSocksSettings,
|
||||
|
@ -67,15 +68,25 @@ public slots:
|
|||
QString getInitialPage();
|
||||
QString getPagePath(PageLoader::PageEnum page);
|
||||
|
||||
void closeWindow();
|
||||
void keyPressEvent(Qt::Key key);
|
||||
|
||||
signals:
|
||||
void goToPageHome();
|
||||
void goToPageSettings();
|
||||
void goToPageViewConfig();
|
||||
void closePage();
|
||||
|
||||
void restorePageHomeState(bool isContainerInstalled = false);
|
||||
void replaceStartPage();
|
||||
|
||||
void showErrorMessage(QString errorMessage);
|
||||
void showInfoMessage(QString message);
|
||||
|
||||
void showBusyIndicator(bool visible);
|
||||
void raise();
|
||||
|
||||
void hideMainWindow();
|
||||
void raiseMainWindow();
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
|
|
|
@ -6,20 +6,21 @@
|
|||
#include "VpnLogic.h"
|
||||
|
||||
#include "core/errorstrings.h"
|
||||
#include <core/servercontroller.h>
|
||||
#include <QTimer>
|
||||
#include <core/servercontroller.h>
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include "../../platforms/android/androidutils.h"
|
||||
#include "../../platforms/android/androidutils.h"
|
||||
#endif
|
||||
|
||||
ServerSettingsLogic::ServerSettingsLogic(UiLogic *logic, QObject *parent):
|
||||
PageLogicBase(logic, parent),
|
||||
m_labelWaitInfoVisible{true},
|
||||
m_pushButtonClearClientCacheVisible{true},
|
||||
m_pushButtonShareFullVisible{true},
|
||||
m_pushButtonClearClientCacheText{tr("Clear client cached profile")}
|
||||
{ }
|
||||
ServerSettingsLogic::ServerSettingsLogic(UiLogic *logic, QObject *parent)
|
||||
: PageLogicBase(logic, parent),
|
||||
m_labelWaitInfoVisible { true },
|
||||
m_pushButtonClearClientCacheVisible { true },
|
||||
m_pushButtonShareFullVisible { true },
|
||||
m_pushButtonClearClientCacheText { tr("Clear client cached profile") }
|
||||
{
|
||||
}
|
||||
|
||||
void ServerSettingsLogic::onUpdatePage()
|
||||
{
|
||||
|
@ -33,11 +34,11 @@ void ServerSettingsLogic::onUpdatePage()
|
|||
const QString &userName = server.value(config_key::userName).toString();
|
||||
const QString &hostName = server.value(config_key::hostName).toString();
|
||||
QString name = QString("%1%2%3%4%5")
|
||||
.arg(userName)
|
||||
.arg(userName.isEmpty() ? "" : "@")
|
||||
.arg(hostName)
|
||||
.arg(port.isEmpty() ? "" : ":")
|
||||
.arg(port);
|
||||
.arg(userName)
|
||||
.arg(userName.isEmpty() ? "" : "@")
|
||||
.arg(hostName)
|
||||
.arg(port.isEmpty() ? "" : ":")
|
||||
.arg(port);
|
||||
|
||||
set_labelServerText(name);
|
||||
set_lineEditDescriptionText(server.value(config_key::description).toString());
|
||||
|
@ -49,15 +50,15 @@ void ServerSettingsLogic::onUpdatePage()
|
|||
|
||||
void ServerSettingsLogic::onPushButtonForgetServer()
|
||||
{
|
||||
if (m_settings->defaultServerIndex() == uiLogic()->m_selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) {
|
||||
if (m_settings->defaultServerIndex() == uiLogic()->m_selectedServerIndex
|
||||
&& uiLogic()->m_vpnConnection->isConnected()) {
|
||||
uiLogic()->pageLogic<VpnLogic>()->onDisconnect();
|
||||
}
|
||||
m_settings->removeServer(uiLogic()->m_selectedServerIndex);
|
||||
|
||||
if (m_settings->defaultServerIndex() == uiLogic()->m_selectedServerIndex) {
|
||||
m_settings->setDefaultServer(0);
|
||||
}
|
||||
else if (m_settings->defaultServerIndex() > uiLogic()->m_selectedServerIndex) {
|
||||
} else if (m_settings->defaultServerIndex() > uiLogic()->m_selectedServerIndex) {
|
||||
m_settings->setDefaultServer(m_settings->defaultServerIndex() - 1);
|
||||
}
|
||||
|
||||
|
@ -65,14 +66,12 @@ void ServerSettingsLogic::onPushButtonForgetServer()
|
|||
m_settings->setDefaultServer(-1);
|
||||
}
|
||||
|
||||
|
||||
uiLogic()->m_selectedServerIndex = -1;
|
||||
uiLogic()->onUpdateAllPages();
|
||||
|
||||
if (m_settings->serversCount() == 0) {
|
||||
uiLogic()->setStartPage(Page::Start);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
uiLogic()->closePage();
|
||||
}
|
||||
}
|
||||
|
@ -86,9 +85,7 @@ void ServerSettingsLogic::onPushButtonClearClientCacheClicked()
|
|||
m_settings->clearLastConnectionConfig(uiLogic()->m_selectedServerIndex, container);
|
||||
}
|
||||
|
||||
QTimer::singleShot(3000, this, [this]() {
|
||||
set_pushButtonClearClientCacheText(tr("Clear client cached profile"));
|
||||
});
|
||||
QTimer::singleShot(3000, this, [this]() { set_pushButtonClearClientCacheText(tr("Clear client cached profile")); });
|
||||
}
|
||||
|
||||
void ServerSettingsLogic::onLineEditDescriptionEditingFinished()
|
||||
|
@ -111,7 +108,7 @@ void authResultReceiver::handleActivityResult(int receiverRequestCode, int resul
|
|||
{
|
||||
qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode;
|
||||
|
||||
if (resultCode == -1) { //ResultOK
|
||||
if (resultCode == -1) { // ResultOK
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(m_serverIndex, DockerContainer::None);
|
||||
emit uiLogic()->goToShareProtocolPage(Proto::Any);
|
||||
}
|
||||
|
@ -121,26 +118,27 @@ void authResultReceiver::handleActivityResult(int receiverRequestCode, int resul
|
|||
void ServerSettingsLogic::onPushButtonShareFullClicked()
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
/* We use builtin keyguard for ssh key export protection on Android */
|
||||
/* We use builtin keyguard for ssh key export protection on Android */
|
||||
QJniObject activity = AndroidUtils::getActivity();
|
||||
auto appContext = activity.callObjectMethod(
|
||||
"getApplicationContext", "()Landroid/content/Context;");
|
||||
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
|
||||
if (appContext.isValid()) {
|
||||
QAndroidActivityResultReceiver *receiver = new authResultReceiver(uiLogic(), uiLogic()->m_selectedServerIndex);
|
||||
auto intent = QJniObject::callStaticObjectMethod(
|
||||
"org/amnezia/vpn/AuthHelper", "getAuthIntent",
|
||||
"(Landroid/content/Context;)Landroid/content/Intent;", appContext.object());
|
||||
auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent",
|
||||
"(Landroid/content/Context;)Landroid/content/Intent;",
|
||||
appContext.object());
|
||||
if (intent.isValid()) {
|
||||
if (intent.object<jobject>() != nullptr) {
|
||||
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, receiver);
|
||||
}
|
||||
} else {
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex, DockerContainer::None);
|
||||
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, receiver);
|
||||
}
|
||||
} else {
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex,
|
||||
DockerContainer::None);
|
||||
emit uiLogic()->goToShareProtocolPage(Proto::Any);
|
||||
}
|
||||
}
|
||||
#else
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex, DockerContainer::None);
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex,
|
||||
DockerContainer::None);
|
||||
emit uiLogic()->goToShareProtocolPage(Proto::Any);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,68 +1,69 @@
|
|||
#include "StartPageLogic.h"
|
||||
#include "ViewConfigLogic.h"
|
||||
|
||||
#include "core/errorstrings.h"
|
||||
#include "../uilogic.h"
|
||||
#include "configurators/ssh_configurator.h"
|
||||
#include "configurators/vpn_configurator.h"
|
||||
#include "../uilogic.h"
|
||||
#include "utilities.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "core/servercontroller.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QFileDialog>
|
||||
#include <QStandardPaths>
|
||||
#include <QEventLoop>
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QJniObject>
|
||||
#include "../../platforms/android/androidutils.h"
|
||||
#include "../../platforms/android/android_controller.h"
|
||||
#include "../../platforms/android/android_controller.h"
|
||||
#include "../../platforms/android/androidutils.h"
|
||||
#include <QJniObject>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
enum class ConfigTypes {
|
||||
Amnezia,
|
||||
OpenVpn,
|
||||
WireGuard
|
||||
};
|
||||
|
||||
ConfigTypes checkConfigFormat(const QString &config)
|
||||
namespace
|
||||
{
|
||||
const QString openVpnConfigPatternCli = "client";
|
||||
const QString openVpnConfigPatternProto1 = "proto tcp";
|
||||
const QString openVpnConfigPatternProto2 = "proto udp";
|
||||
const QString openVpnConfigPatternDriver1 = "dev tun";
|
||||
const QString openVpnConfigPatternDriver2 = "dev tap";
|
||||
enum class ConfigTypes {
|
||||
Amnezia,
|
||||
OpenVpn,
|
||||
WireGuard
|
||||
};
|
||||
|
||||
const QString wireguardConfigPatternSectionInterface = "[Interface]";
|
||||
const QString wireguardConfigPatternSectionPeer = "[Peer]";
|
||||
ConfigTypes checkConfigFormat(const QString &config)
|
||||
{
|
||||
const QString openVpnConfigPatternCli = "client";
|
||||
const QString openVpnConfigPatternProto1 = "proto tcp";
|
||||
const QString openVpnConfigPatternProto2 = "proto udp";
|
||||
const QString openVpnConfigPatternDriver1 = "dev tun";
|
||||
const QString openVpnConfigPatternDriver2 = "dev tap";
|
||||
|
||||
if (config.contains(openVpnConfigPatternCli) &&
|
||||
(config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) &&
|
||||
(config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
|
||||
return ConfigTypes::OpenVpn;
|
||||
} else if (config.contains(wireguardConfigPatternSectionInterface) &&
|
||||
config.contains(wireguardConfigPatternSectionPeer))
|
||||
return ConfigTypes::WireGuard;
|
||||
return ConfigTypes::Amnezia;
|
||||
}
|
||||
const QString wireguardConfigPatternSectionInterface = "[Interface]";
|
||||
const QString wireguardConfigPatternSectionPeer = "[Peer]";
|
||||
|
||||
if (config.contains(openVpnConfigPatternCli)
|
||||
&& (config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2))
|
||||
&& (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
|
||||
return ConfigTypes::OpenVpn;
|
||||
} else if (config.contains(wireguardConfigPatternSectionInterface)
|
||||
&& config.contains(wireguardConfigPatternSectionPeer))
|
||||
return ConfigTypes::WireGuard;
|
||||
return ConfigTypes::Amnezia;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent):
|
||||
PageLogicBase(logic, parent),
|
||||
m_pushButtonConnectEnabled{true},
|
||||
m_pushButtonConnectText{tr("Connect")},
|
||||
m_pushButtonConnectKeyChecked{false},
|
||||
m_labelWaitInfoVisible{true},
|
||||
m_pushButtonBackFromStartVisible{true},
|
||||
m_ipAddressPortRegex{Utils::ipAddressPortRegExp()}
|
||||
StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent)
|
||||
: PageLogicBase(logic, parent),
|
||||
m_pushButtonConnectEnabled { true },
|
||||
m_pushButtonConnectText { tr("Connect") },
|
||||
m_pushButtonConnectKeyChecked { false },
|
||||
m_labelWaitInfoVisible { true },
|
||||
m_pushButtonBackFromStartVisible { true },
|
||||
m_ipAddressPortRegex { Utils::ipAddressPortRegExp() }
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
// Set security screen for Android app
|
||||
AndroidUtils::runOnAndroidThreadSync([]() {
|
||||
QJniObject activity = AndroidUtils::getActivity();
|
||||
QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
|
||||
if (window.isValid()){
|
||||
if (window.isValid()) {
|
||||
const int FLAG_SECURE = 8192;
|
||||
window.callMethod<void>("addFlags", "(I)V", FLAG_SECURE);
|
||||
}
|
||||
|
@ -89,17 +90,13 @@ void StartPageLogic::onUpdatePage()
|
|||
|
||||
void StartPageLogic::onPushButtonConnect()
|
||||
{
|
||||
if (pushButtonConnectKeyChecked()){
|
||||
if (lineEditIpText().isEmpty() ||
|
||||
lineEditLoginText().isEmpty() ||
|
||||
textEditSshKeyText().isEmpty() ) {
|
||||
if (pushButtonConnectKeyChecked()) {
|
||||
if (lineEditIpText().isEmpty() || lineEditLoginText().isEmpty() || textEditSshKeyText().isEmpty()) {
|
||||
set_labelWaitInfoText(tr("Please fill in all fields"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (lineEditIpText().isEmpty() ||
|
||||
lineEditLoginText().isEmpty() ||
|
||||
lineEditPasswordText().isEmpty() ) {
|
||||
if (lineEditIpText().isEmpty() || lineEditLoginText().isEmpty() || lineEditPasswordText().isEmpty()) {
|
||||
set_labelWaitInfoText(tr("Please fill in all fields"));
|
||||
return;
|
||||
}
|
||||
|
@ -174,7 +171,8 @@ void StartPageLogic::onPushButtonConnect()
|
|||
set_pushButtonConnectText(tr("Connect"));
|
||||
|
||||
uiLogic()->m_installCredentials = serverCredentials;
|
||||
if (ok) emit uiLogic()->goToPage(Page::NewServer);
|
||||
if (ok)
|
||||
emit uiLogic()->goToPage(Page::NewServer);
|
||||
}
|
||||
|
||||
void StartPageLogic::onPushButtonImport()
|
||||
|
@ -185,8 +183,10 @@ void StartPageLogic::onPushButtonImport()
|
|||
void StartPageLogic::onPushButtonImportOpenFile()
|
||||
{
|
||||
QString fileName = UiLogic::getOpenFileName(Q_NULLPTR, tr("Open config file"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.vpn *.ovpn *.conf");
|
||||
if (fileName.isEmpty()) return;
|
||||
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
|
||||
"*.vpn *.ovpn *.conf");
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(fileName);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
@ -226,8 +226,7 @@ bool StartPageLogic::importConnection(const QJsonObject &profile)
|
|||
// check config
|
||||
uiLogic()->pageLogic<ViewConfigLogic>()->set_configJson(profile);
|
||||
emit uiLogic()->goToPage(Page::ViewConfig);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
qDebug() << "Failed to import profile";
|
||||
qDebug().noquote() << QJsonDocument(profile).toJson();
|
||||
return false;
|
||||
|
@ -298,7 +297,6 @@ bool StartPageLogic::importConnectionFromOpenVpnConfig(const QString &config)
|
|||
o[config_key::defaultContainer] = "amnezia-openvpn";
|
||||
o[config_key::description] = m_settings->nextAvailableServerName();
|
||||
|
||||
|
||||
const static QRegularExpression dnsRegExp("dhcp-option DNS (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
|
||||
QRegularExpressionMatchIterator dnsMatch = dnsRegExp.globalMatch(config);
|
||||
if (dnsMatch.hasNext()) {
|
||||
|
@ -345,7 +343,9 @@ bool StartPageLogic::importConnectionFromWireguardConfig(const QString &config)
|
|||
o[config_key::defaultContainer] = "amnezia-wireguard";
|
||||
o[config_key::description] = m_settings->nextAvailableServerName();
|
||||
|
||||
const static QRegularExpression dnsRegExp("DNS = (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
|
||||
const static QRegularExpression dnsRegExp(
|
||||
"DNS = "
|
||||
"(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
|
||||
QRegularExpressionMatch dnsMatch = dnsRegExp.match(config);
|
||||
if (dnsMatch.hasMatch()) {
|
||||
o[config_key::dns1] = dnsMatch.captured(1);
|
||||
|
|
|
@ -54,10 +54,10 @@ DrawerType {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Save connection code")
|
||||
text: Qt.platform.os === "android" ? qsTr("Share") : qsTr("Save connection code")
|
||||
|
||||
onClicked: {
|
||||
ExportController.saveFile()
|
||||
Qt.platform.os === "android" ? ExportController.shareFile() : ExportController.saveFile()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ CheckBox {
|
|||
hoverEnabled: true
|
||||
|
||||
indicator: Rectangle {
|
||||
id: checkBoxBackground
|
||||
id: background
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
@ -57,7 +57,6 @@ CheckBox {
|
|||
radius: 4
|
||||
|
||||
Image {
|
||||
id: indicator
|
||||
anchors.centerIn: parent
|
||||
|
||||
source: root.pressed ? imageSource : root.checked ? imageSource : ""
|
||||
|
@ -71,31 +70,38 @@ CheckBox {
|
|||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 8 + checkBoxBackground.width
|
||||
contentItem: Item {
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
spacing: 4
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8 + background.width
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
// Layout.topMargin: 16
|
||||
// Layout.bottomMargin: description.visible ? 0 : 16
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
text: root.text
|
||||
}
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
spacing: 4
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 16
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.descriptionText
|
||||
color: "#878b91"
|
||||
text: root.text
|
||||
}
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.descriptionText
|
||||
color: "#878b91"
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ Item {
|
|||
if (root.stackView.depth <= 1) {
|
||||
return
|
||||
}
|
||||
|
||||
root.stackView.pop()
|
||||
}
|
||||
|
||||
|
|
|
@ -85,44 +85,50 @@ RadioButton {
|
|||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: content
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
contentItem: Item {
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8 + background.width
|
||||
|
||||
spacing: 4
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
ListItemTitleType {
|
||||
text: root.text
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
color: {
|
||||
if (root.checked) {
|
||||
return selectedTextColor
|
||||
spacing: 4
|
||||
|
||||
ListItemTitleType {
|
||||
text: root.text
|
||||
|
||||
color: {
|
||||
if (root.checked) {
|
||||
return selectedTextColor
|
||||
}
|
||||
return textColor
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
return textColor
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: description.visible ? 0 : 16
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
color: "#878B91"
|
||||
text: root.descriptionText
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
color: "#878B91"
|
||||
text: root.descriptionText
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 16
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
|
|
@ -43,8 +43,8 @@ PageType {
|
|||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.preferredWidth: 344
|
||||
Layout.preferredHeight: 279
|
||||
Layout.preferredWidth: 291
|
||||
Layout.preferredHeight: 224
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
|
@ -100,7 +100,7 @@ And if you don't like the app, all the more support it - the donation will be us
|
|||
|
||||
text: qsTr("Show other methods on Github")
|
||||
|
||||
onClicked: Qt.openUrlExternally("https://github.com/amnezia-vpn/amnezia-client")
|
||||
onClicked: Qt.openUrlExternally("https://github.com/amnezia-vpn/amnezia-client#donate")
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
|
|
|
@ -61,16 +61,18 @@ PageType {
|
|||
leftImageSource: "qrc:/images/controls/folder-open.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
onClicked: fileDialog.open()
|
||||
// onClicked: fileDialog.open()
|
||||
ImportController.extractConfigFromFile()
|
||||
goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
onAccepted: {
|
||||
ImportController.extractConfigFromFile(selectedFile)
|
||||
goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
}
|
||||
}
|
||||
// FileDialog {
|
||||
// id: fileDialog
|
||||
// onAccepted: {
|
||||
// ImportController.extractConfigFromFile(selectedFile)
|
||||
// goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
@ -84,6 +86,8 @@ PageType {
|
|||
leftImageSource: "qrc:/images/controls/qr-code.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
ImportController.extractConfigFromQr()
|
||||
// goToPage(PageEnum.PageSetupWizardQrReader)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
52
client/ui/qml/Pages2/PageSetupWizardQrReader.qml
Normal file
52
client/ui/qml/Pages2/PageSetupWizardQrReader.qml
Normal file
|
@ -0,0 +1,52 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import QRCodeReader 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
spacing: 0
|
||||
|
||||
BackButtonType {
|
||||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Point the camera at the QR code and hold for a couple of seconds.")
|
||||
}
|
||||
|
||||
ProgressBarType {
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
QRCodeReader {
|
||||
id: qrCodeReader
|
||||
Component.onCompleted: {
|
||||
qrCodeReader.setCameraSize(Qt.rect(parent.x,
|
||||
parent.y,
|
||||
parent.width,
|
||||
parent.height))
|
||||
qrCodeReader.startReading()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,6 +20,10 @@ PageType {
|
|||
popupErrorMessage.popupErrorMessageText = errorMessage
|
||||
popupErrorMessage.open()
|
||||
}
|
||||
|
||||
function onGoToPageViewConfig() {
|
||||
goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
|
@ -18,7 +18,7 @@ PageType {
|
|||
|
||||
enum ConfigType {
|
||||
AmneziaConnection,
|
||||
AmenziaFullAccess,
|
||||
AmneziaFullAccess,
|
||||
OpenVpn,
|
||||
WireGuard
|
||||
}
|
||||
|
@ -33,7 +33,14 @@ PageType {
|
|||
|
||||
switch (type) {
|
||||
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(); break;
|
||||
case PageShare.ConfigType.AmenziaFullAccess: ExportController.generateFullAccessConfig(); break;
|
||||
case PageShare.ConfigType.AmneziaFullAccess: {
|
||||
if (Qt.platform.os === "android") {
|
||||
ExportController.generateFullAccessConfigAndroid();
|
||||
} else {
|
||||
ExportController.generateFullAccessConfig();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PageShare.ConfigType.OpenVpn: ExportController.generateOpenVpnConfig(); break;
|
||||
case PageShare.ConfigType.WireGuard: ExportController.generateWireGuardConfig(); break;
|
||||
}
|
||||
|
@ -48,6 +55,8 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
property string fullConfigServerSelectorText
|
||||
property string connectionServerSelectorText
|
||||
property bool showContent: false
|
||||
property bool shareButtonEnabled: false
|
||||
property list<QtObject> connectionTypesModel: [
|
||||
|
@ -118,6 +127,7 @@ PageType {
|
|||
|
||||
onClicked: {
|
||||
accessTypeSelector.currentIndex = 0
|
||||
serverSelector.text = root.connectionServerSelectorText
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,6 +139,7 @@ PageType {
|
|||
|
||||
onClicked: {
|
||||
accessTypeSelector.currentIndex = 1
|
||||
serverSelector.text = root.fullConfigServerSelectorText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,14 +187,24 @@ PageType {
|
|||
currentIndex: 0
|
||||
|
||||
clickedFunction: function() {
|
||||
serverSelector.text = selectedText
|
||||
ServersModel.currentlyProcessedIndex = currentIndex
|
||||
protocolSelector.visible = true
|
||||
root.shareButtonEnabled = false
|
||||
handler()
|
||||
|
||||
if (accessTypeSelector.currentIndex === 0) {
|
||||
protocolSelector.visible = true
|
||||
root.shareButtonEnabled = false
|
||||
} else {
|
||||
serverSelector.menuVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
handler()
|
||||
}
|
||||
|
||||
function handler() {
|
||||
serverSelector.text = selectedText
|
||||
root.fullConfigServerSelectorText = selectedText
|
||||
root.connectionServerSelectorText = selectedText
|
||||
ServersModel.currentlyProcessedIndex = currentIndex
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +281,9 @@ PageType {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
handler()
|
||||
if (accessTypeSelector.currentIndex === 0) {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
||||
function handler() {
|
||||
|
@ -272,6 +295,8 @@ PageType {
|
|||
}
|
||||
|
||||
serverSelector.text += ", " + selectedText
|
||||
root.connectionServerSelectorText = serverSelector.text
|
||||
|
||||
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex))
|
||||
|
|
|
@ -25,6 +25,11 @@ PageType {
|
|||
tabBarStackView.goToTabBarPage(PageController.getPagePath(PageEnum.PageSettings))
|
||||
}
|
||||
|
||||
function onGoToPageViewConfig() {
|
||||
var pagePath = PageController.getPagePath(PageEnum.PageSetupWizardViewConfig)
|
||||
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
|
||||
}
|
||||
|
||||
function onShowErrorMessage(errorMessage) {
|
||||
popupErrorMessage.popupErrorMessageText = errorMessage
|
||||
popupErrorMessage.open()
|
||||
|
@ -35,6 +40,13 @@ PageType {
|
|||
tabBarStackView.enabled = !visible
|
||||
tabBar.enabled = !visible
|
||||
}
|
||||
|
||||
function onClosePage() {
|
||||
if (tabBarStackView.depth <= 1) {
|
||||
return
|
||||
}
|
||||
tabBarStackView.pop()
|
||||
}
|
||||
}
|
||||
|
||||
StackViewType {
|
||||
|
|
|
@ -1,282 +0,0 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import PageEnum 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Config"
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 32
|
||||
Layout.fillWidth: true
|
||||
|
||||
backButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
headerText: "Server 1"
|
||||
descriptionText: "root 192.168.111.111"
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
left: parent.left
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
TabButtonType {
|
||||
id: bb
|
||||
isSelected: tabBar.currentIndex === 0
|
||||
text: qsTr("Протоколы")
|
||||
}
|
||||
TabButtonType {
|
||||
isSelected: tabBar.currentIndex === 1
|
||||
text: qsTr("Сервисы")
|
||||
}
|
||||
TabButtonType {
|
||||
isSelected: tabBar.currentIndex === 2
|
||||
text: qsTr("Данные")
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: stackLayout
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
anchors.top: tabBar.bottom
|
||||
anchors.topMargin: 16
|
||||
|
||||
width: parent.width
|
||||
height: root.height - header.implicitHeight - tabBar.implicitHeight - 100
|
||||
|
||||
Item {
|
||||
id: protocolsTab
|
||||
|
||||
FlickableType {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: protocolsTabContent.height
|
||||
|
||||
ColumnLayout {
|
||||
id: protocolsTabContent
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: qsTr("Forget this server")
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: "transparent"
|
||||
hoveredColor: Qt.rgba(255, 255, 255, 0.08)
|
||||
pressedColor: Qt.rgba(255, 255, 255, 0.12)
|
||||
disabledColor: "#878B91"
|
||||
textColor: "#D7D8DB"
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Forget this server")
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
headerText: "Server IP adress [:port]"
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: ip
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: "IP, логин и пароль от сервера"
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
height: 1
|
||||
color: "#2C2D30"
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: "QR-код, ключ или файл настроек"
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
height: 1
|
||||
color: "#2C2D30"
|
||||
}
|
||||
|
||||
CardType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: "Высокий"
|
||||
bodyText: "Многие иностранные сайты и VPN-провайдеры заблокированы"
|
||||
footerText: "футер"
|
||||
}
|
||||
|
||||
CardType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: "Высокий"
|
||||
bodyText: "Многие иностранные сайты и VPN-провайдеры заблокированы"
|
||||
footerText: "футер"
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: "IP, логин и пароль от сервера"
|
||||
descriptionText: "IP, логин и пароль от сервера"
|
||||
|
||||
menuModel: [
|
||||
qsTr("SHA512"),
|
||||
qsTr("SHA384"),
|
||||
qsTr("SHA256"),
|
||||
qsTr("SHA3-512"),
|
||||
qsTr("SHA3-384"),
|
||||
qsTr("SHA3-256"),
|
||||
qsTr("whirlpool"),
|
||||
qsTr("BLAKE2b512"),
|
||||
qsTr("BLAKE2s256"),
|
||||
qsTr("SHA1")
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: servicesTab
|
||||
|
||||
FlickableType {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: servicesTabContent.height
|
||||
|
||||
ColumnLayout {
|
||||
id: servicesTabContent
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
CheckBoxType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Auto-negotiate encryption")
|
||||
}
|
||||
CheckBoxType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Auto-negotiate encryption")
|
||||
descriptionText: qsTr("Auto-negotiate encryption")
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
implicitWidth: buttonGroup.implicitWidth
|
||||
implicitHeight: buttonGroup.implicitHeight
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
color: "#1C1D21"
|
||||
radius: 16
|
||||
|
||||
RowLayout {
|
||||
id: buttonGroup
|
||||
|
||||
spacing: 0
|
||||
|
||||
HorizontalRadioButton {
|
||||
implicitWidth: (root.width - 32) / 2
|
||||
text: "UDP"
|
||||
}
|
||||
|
||||
HorizontalRadioButton {
|
||||
implicitWidth: (root.width - 32) / 2
|
||||
text: "TCP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VerticalRadioButton {
|
||||
text: "Раздельное туннелирование"
|
||||
descriptionText: "Позволяет подключаться к одним сайтам через защищенное соединение, а к другим в обход него"
|
||||
checked: true
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
}
|
||||
|
||||
VerticalRadioButton {
|
||||
text: "Раздельное туннелирование"
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
text: "Auto-negotiate encryption"
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,10 +18,9 @@ Window {
|
|||
|
||||
color: "#0E0E11"
|
||||
|
||||
// todo
|
||||
onClosing: function() {
|
||||
console.debug("QML onClosing signal")
|
||||
UiLogic.onCloseWindow()
|
||||
PageController.closeWindow()
|
||||
}
|
||||
|
||||
title: "AmneziaVPN"
|
||||
|
@ -36,6 +35,11 @@ Window {
|
|||
var pagePath = PageController.getInitialPage()
|
||||
rootStackView.push(pagePath, { "objectName" : pagePath })
|
||||
}
|
||||
|
||||
Keys.onPressed: function(event) {
|
||||
PageController.keyPressEvent(event.key)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
@ -49,10 +53,14 @@ Window {
|
|||
rootStackView.replace(pagePath, { "objectName" : pagePath })
|
||||
}
|
||||
|
||||
function onRaise() {
|
||||
function onRaiseMainWindow() {
|
||||
root.show()
|
||||
root.raise()
|
||||
root.requestActivate()
|
||||
}
|
||||
|
||||
function onHideMainWindow() {
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,79 +10,76 @@
|
|||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QMetaEnum>
|
||||
#include <QMetaObject>
|
||||
#include <QQmlFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QSysInfo>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QQmlFile>
|
||||
#include <QMetaObject>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "amnezia_application.h"
|
||||
|
||||
#include "configurators/cloak_configurator.h"
|
||||
#include "configurators/vpn_configurator.h"
|
||||
#include "configurators/openvpn_configurator.h"
|
||||
#include "configurators/shadowsocks_configurator.h"
|
||||
#include "configurators/ssh_configurator.h"
|
||||
#include "configurators/vpn_configurator.h"
|
||||
|
||||
#include "core/servercontroller.h"
|
||||
#include "core/server_defs.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "core/server_defs.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
#include "ui/qautostart.h"
|
||||
|
||||
#include "logger.h"
|
||||
#include "version.h"
|
||||
#include "uilogic.h"
|
||||
#include "utilities.h"
|
||||
#include "version.h"
|
||||
#include "vpnconnection.h"
|
||||
#include <functional>
|
||||
|
||||
#if defined Q_OS_MAC || defined Q_OS_LINUX
|
||||
#include "ui/macos_util.h"
|
||||
#include "ui/macos_util.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#include "platforms/ios/MobileUtils.h"
|
||||
|
||||
#include "pages_logic/AdvancedServerSettingsLogic.h"
|
||||
#include "pages_logic/AppSettingsLogic.h"
|
||||
#include "pages_logic/ClientInfoLogic.h"
|
||||
#include "pages_logic/ClientManagementLogic.h"
|
||||
#include "pages_logic/GeneralSettingsLogic.h"
|
||||
#include "pages_logic/NetworkSettingsLogic.h"
|
||||
#include "pages_logic/NewServerProtocolsLogic.h"
|
||||
#include "pages_logic/QrDecoderLogic.h"
|
||||
#include "pages_logic/ServerConfiguringProgressLogic.h"
|
||||
#include "pages_logic/ServerContainersLogic.h"
|
||||
#include "pages_logic/ServerListLogic.h"
|
||||
#include "pages_logic/ServerSettingsLogic.h"
|
||||
#include "pages_logic/ServerContainersLogic.h"
|
||||
#include "pages_logic/ShareConnectionLogic.h"
|
||||
#include "pages_logic/SitesLogic.h"
|
||||
#include "pages_logic/StartPageLogic.h"
|
||||
#include "pages_logic/ViewConfigLogic.h"
|
||||
#include "pages_logic/VpnLogic.h"
|
||||
#include "pages_logic/WizardLogic.h"
|
||||
#include "pages_logic/AdvancedServerSettingsLogic.h"
|
||||
#include "pages_logic/ClientManagementLogic.h"
|
||||
#include "pages_logic/ClientInfoLogic.h"
|
||||
|
||||
#include "pages_logic/protocols/CloakLogic.h"
|
||||
#include "pages_logic/protocols/OpenVpnLogic.h"
|
||||
#include "pages_logic/protocols/ShadowSocksLogic.h"
|
||||
#include "pages_logic/protocols/OtherProtocolsLogic.h"
|
||||
#include "pages_logic/protocols/ShadowSocksLogic.h"
|
||||
#include "pages_logic/protocols/WireGuardLogic.h"
|
||||
|
||||
using namespace amnezia;
|
||||
using namespace PageEnumNS;
|
||||
|
||||
UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigurator> configurator,
|
||||
QObject *parent) :
|
||||
QObject(parent),
|
||||
m_settings(settings),
|
||||
m_configurator(configurator)
|
||||
UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigurator> configurator, QObject *parent)
|
||||
: QObject(parent), m_settings(settings), m_configurator(configurator)
|
||||
{
|
||||
m_protocolsModel = new ProtocolsModel(settings, this);
|
||||
m_clientManagementModel = new ClientManagementModel(this);
|
||||
|
@ -90,7 +87,6 @@ UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigur
|
|||
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
|
||||
m_vpnConnectionThread.start();
|
||||
|
||||
|
||||
m_protocolLogicMap.insert(Proto::OpenVpn, new OpenVpnLogic(this));
|
||||
m_protocolLogicMap.insert(Proto::ShadowSocks, new ShadowSocksLogic(this));
|
||||
m_protocolLogicMap.insert(Proto::Cloak, new CloakLogic(this));
|
||||
|
@ -99,7 +95,6 @@ UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigur
|
|||
m_protocolLogicMap.insert(Proto::Dns, new OtherProtocolsLogic(this));
|
||||
m_protocolLogicMap.insert(Proto::Sftp, new OtherProtocolsLogic(this));
|
||||
m_protocolLogicMap.insert(Proto::TorWebSite, new OtherProtocolsLogic(this));
|
||||
|
||||
}
|
||||
|
||||
UiLogic::~UiLogic()
|
||||
|
@ -129,33 +124,37 @@ UiLogic::~UiLogic()
|
|||
void UiLogic::initializeUiLogic()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
connect(AndroidController::instance(), &AndroidController::initialized, [this](bool status, bool connected, const QDateTime& connectionDate) {
|
||||
if (connected) {
|
||||
pageLogic<VpnLogic>()->onConnectionStateChanged(Vpn::ConnectionState::Connected);
|
||||
if (m_vpnConnection) m_vpnConnection->restoreConnection();
|
||||
}
|
||||
});
|
||||
if (!AndroidController::instance()->initialize(pageLogic<StartPageLogic>())) {
|
||||
qCritical() << QString("Init failed");
|
||||
if (m_vpnConnection) m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
return;
|
||||
}
|
||||
connect(AndroidController::instance(), &AndroidController::initialized,
|
||||
[this](bool status, bool connected, const QDateTime &connectionDate) {
|
||||
if (connected) {
|
||||
pageLogic<VpnLogic>()->onConnectionStateChanged(Vpn::ConnectionState::Connected);
|
||||
if (m_vpnConnection)
|
||||
m_vpnConnection->restoreConnection();
|
||||
}
|
||||
});
|
||||
// if (!AndroidController::instance()->initialize(pageLogic<StartPageLogic>())) {
|
||||
// qCritical() << QString("Init failed");
|
||||
// if (m_vpnConnection) m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
// return;
|
||||
// }
|
||||
#endif
|
||||
|
||||
m_notificationHandler = NotificationHandler::create(qmlRoot());
|
||||
|
||||
connect(m_vpnConnection, &VpnConnection::connectionStateChanged, m_notificationHandler, &NotificationHandler::setConnectionState);
|
||||
connect(m_vpnConnection, &VpnConnection::connectionStateChanged, m_notificationHandler,
|
||||
&NotificationHandler::setConnectionState);
|
||||
connect(m_notificationHandler, &NotificationHandler::raiseRequested, this, &UiLogic::raise);
|
||||
connect(m_notificationHandler, &NotificationHandler::connectRequested, pageLogic<VpnLogic>(), &VpnLogic::onConnect);
|
||||
connect(m_notificationHandler, &NotificationHandler::disconnectRequested, pageLogic<VpnLogic>(), &VpnLogic::onDisconnect);
|
||||
connect(m_notificationHandler, &NotificationHandler::disconnectRequested, pageLogic<VpnLogic>(),
|
||||
&VpnLogic::onDisconnect);
|
||||
|
||||
// if (m_settings->serversCount() > 0) {
|
||||
// if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0);
|
||||
// emit goToPage(Page::PageStart, true, false);
|
||||
// }
|
||||
// else {
|
||||
// emit goToPage(Page::PageSetupWizardStart, true, false);
|
||||
// }
|
||||
// if (m_settings->serversCount() > 0) {
|
||||
// if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0);
|
||||
// emit goToPage(Page::PageStart, true, false);
|
||||
// }
|
||||
// else {
|
||||
// emit goToPage(Page::PageSetupWizardStart, true, false);
|
||||
// }
|
||||
|
||||
m_selectedServerIndex = m_settings->defaultServerIndex();
|
||||
|
||||
|
@ -165,14 +164,13 @@ void UiLogic::initializeUiLogic()
|
|||
|
||||
void UiLogic::showOnStartup()
|
||||
{
|
||||
if (! m_settings->isStartMinimized()) {
|
||||
if (!m_settings->isStartMinimized()) {
|
||||
emit show();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
#ifdef Q_OS_WIN
|
||||
emit hide();
|
||||
#elif defined Q_OS_MACX
|
||||
// TODO: fix: setDockIconVisible(false);
|
||||
// TODO: fix: setDockIconVisible(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +178,7 @@ void UiLogic::showOnStartup()
|
|||
void UiLogic::onUpdateAllPages()
|
||||
{
|
||||
for (auto logic : m_logicMap) {
|
||||
if (dynamic_cast<ClientInfoLogic*>(logic) || dynamic_cast<ClientManagementLogic*>(logic)) {
|
||||
if (dynamic_cast<ClientInfoLogic *>(logic) || dynamic_cast<ClientManagementLogic *>(logic)) {
|
||||
continue;
|
||||
}
|
||||
logic->onUpdatePage();
|
||||
|
@ -191,57 +189,50 @@ void UiLogic::keyPressEvent(Qt::Key key)
|
|||
{
|
||||
switch (key) {
|
||||
case Qt::Key_AsciiTilde:
|
||||
case Qt::Key_QuoteLeft: emit toggleLogPanel();
|
||||
break;
|
||||
case Qt::Key_L: Logger::openLogsFolder();
|
||||
break;
|
||||
case Qt::Key_K: Logger::openServiceLogsFolder();
|
||||
break;
|
||||
case Qt::Key_QuoteLeft: emit toggleLogPanel(); break;
|
||||
case Qt::Key_L: Logger::openLogsFolder(); break;
|
||||
case Qt::Key_K: Logger::openServiceLogsFolder(); break;
|
||||
#ifdef QT_DEBUG
|
||||
case Qt::Key_Q:
|
||||
qApp->quit();
|
||||
break;
|
||||
case Qt::Key_Q: qApp->quit(); break;
|
||||
case Qt::Key_H:
|
||||
m_selectedServerIndex = m_settings->defaultServerIndex();
|
||||
m_selectedDockerContainer = m_settings->defaultContainer(m_selectedServerIndex);
|
||||
|
||||
//updateSharingPage(selectedServerIndex, m_settings->serverCredentials(selectedServerIndex), selectedDockerContainer);
|
||||
// updateSharingPage(selectedServerIndex, m_settings->serverCredentials(selectedServerIndex), selectedDockerContainer);
|
||||
emit goToPage(Page::ShareConnection);
|
||||
break;
|
||||
#endif
|
||||
case Qt::Key_C:
|
||||
qDebug().noquote() << "Def server" << m_settings->defaultServerIndex() << m_settings->defaultContainerName(m_settings->defaultServerIndex());
|
||||
qDebug().noquote() << "Def server" << m_settings->defaultServerIndex()
|
||||
<< m_settings->defaultContainerName(m_settings->defaultServerIndex());
|
||||
qDebug().noquote() << QJsonDocument(m_settings->defaultServer()).toJson();
|
||||
break;
|
||||
case Qt::Key_A:
|
||||
emit goToPage(Page::Start);
|
||||
break;
|
||||
case Qt::Key_A: emit goToPage(Page::Start); break;
|
||||
case Qt::Key_S:
|
||||
m_selectedServerIndex = m_settings->defaultServerIndex();
|
||||
emit goToPage(Page::ServerSettings);
|
||||
break;
|
||||
case Qt::Key_P:
|
||||
onGotoCurrentProtocolsPage();
|
||||
break;
|
||||
case Qt::Key_P: onGotoCurrentProtocolsPage(); break;
|
||||
case Qt::Key_T:
|
||||
m_configurator->sshConfigurator->openSshTerminal(m_settings->serverCredentials(m_settings->defaultServerIndex()));
|
||||
break;
|
||||
case Qt::Key_Escape:
|
||||
if (currentPage() == Page::Vpn) break;
|
||||
if (currentPage() == Page::ServerConfiguringProgress) break;
|
||||
if (currentPage() == Page::Vpn)
|
||||
break;
|
||||
if (currentPage() == Page::ServerConfiguringProgress)
|
||||
break;
|
||||
case Qt::Key_Back:
|
||||
|
||||
// if (currentPage() == Page::Start && pagesStack.size() < 2) break;
|
||||
// if (currentPage() == Page::Sites &&
|
||||
// ui->tableView_sites->selectionModel()->selection().indexes().size() > 0) {
|
||||
// ui->tableView_sites->clearSelection();
|
||||
// break;
|
||||
// }
|
||||
// if (currentPage() == Page::Start && pagesStack.size() < 2) break;
|
||||
// if (currentPage() == Page::Sites &&
|
||||
// ui->tableView_sites->selectionModel()->selection().indexes().size() > 0) {
|
||||
// ui->tableView_sites->clearSelection();
|
||||
// break;
|
||||
// }
|
||||
|
||||
emit closePage();
|
||||
emit closePage();
|
||||
//}
|
||||
default:
|
||||
;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,8 +241,7 @@ void UiLogic::onCloseWindow()
|
|||
#ifdef Q_OS_ANDROID
|
||||
qApp->quit();
|
||||
#else
|
||||
if (m_settings->serversCount() == 0)
|
||||
{
|
||||
if (m_settings->serversCount() == 0) {
|
||||
qApp->quit();
|
||||
} else {
|
||||
emit hide();
|
||||
|
@ -267,7 +257,6 @@ QString UiLogic::containerName(int container)
|
|||
QString UiLogic::containerDesc(int container)
|
||||
{
|
||||
return ContainerProps::containerDescriptions().value(static_cast<DockerContainer>(container));
|
||||
|
||||
}
|
||||
|
||||
void UiLogic::onGotoCurrentProtocolsPage()
|
||||
|
@ -286,50 +275,50 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
|
|||
qApp->processEvents();
|
||||
|
||||
ServerConfiguringProgressLogic::PageFunc pageFunc;
|
||||
pageFunc.setEnabledFunc = [this] (bool enabled) -> void {
|
||||
pageFunc.setEnabledFunc = [this](bool enabled) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_pageEnabled(enabled);
|
||||
};
|
||||
|
||||
ServerConfiguringProgressLogic::ButtonFunc noButton;
|
||||
|
||||
ServerConfiguringProgressLogic::LabelFunc waitInfoFunc;
|
||||
waitInfoFunc.setTextFunc = [this] (const QString& text) -> void {
|
||||
waitInfoFunc.setTextFunc = [this](const QString &text) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_labelWaitInfoText(text);
|
||||
};
|
||||
waitInfoFunc.setVisibleFunc = [this] (bool visible) -> void {
|
||||
waitInfoFunc.setVisibleFunc = [this](bool visible) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_labelWaitInfoVisible(visible);
|
||||
};
|
||||
|
||||
ServerConfiguringProgressLogic::ProgressFunc progressBarFunc;
|
||||
progressBarFunc.setVisibleFunc = [this] (bool visible) -> void {
|
||||
progressBarFunc.setVisibleFunc = [this](bool visible) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarVisible(visible);
|
||||
};
|
||||
progressBarFunc.setValueFunc = [this] (int value) -> void {
|
||||
progressBarFunc.setValueFunc = [this](int value) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarValue(value);
|
||||
};
|
||||
progressBarFunc.getValueFunc = [this] (void) -> int {
|
||||
progressBarFunc.getValueFunc = [this](void) -> int {
|
||||
return pageLogic<ServerConfiguringProgressLogic>()->progressBarValue();
|
||||
};
|
||||
progressBarFunc.getMaximumFunc = [this] (void) -> int {
|
||||
progressBarFunc.getMaximumFunc = [this](void) -> int {
|
||||
return pageLogic<ServerConfiguringProgressLogic>()->progressBarMaximum();
|
||||
};
|
||||
progressBarFunc.setTextVisibleFunc = [this] (bool visible) -> void {
|
||||
progressBarFunc.setTextVisibleFunc = [this](bool visible) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarTextVisible(visible);
|
||||
};
|
||||
progressBarFunc.setTextFunc = [this] (const QString& text) -> void {
|
||||
progressBarFunc.setTextFunc = [this](const QString &text) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarText(text);
|
||||
};
|
||||
|
||||
ServerConfiguringProgressLogic::LabelFunc busyInfoFunc;
|
||||
busyInfoFunc.setTextFunc = [this] (const QString& text) -> void {
|
||||
busyInfoFunc.setTextFunc = [this](const QString &text) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_labelServerBusyText(text);
|
||||
};
|
||||
busyInfoFunc.setVisibleFunc = [this] (bool visible) -> void {
|
||||
busyInfoFunc.setVisibleFunc = [this](bool visible) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_labelServerBusyVisible(visible);
|
||||
};
|
||||
|
||||
ServerConfiguringProgressLogic::ButtonFunc cancelButtonFunc;
|
||||
cancelButtonFunc.setVisibleFunc = [this] (bool visible) -> void {
|
||||
cancelButtonFunc.setVisibleFunc = [this](bool visible) -> void {
|
||||
pageLogic<ServerConfiguringProgressLogic>()->set_pushButtonCancelVisible(visible);
|
||||
};
|
||||
|
||||
|
@ -338,13 +327,12 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
|
|||
if (errorCode == ErrorCode::NoError) {
|
||||
if (!isContainerAlreadyAddedToGui(container.first)) {
|
||||
progressBarFunc.setTextFunc(QString("Installing %1").arg(ContainerProps::containerToString(container.first)));
|
||||
auto installAction = [&] () {
|
||||
auto installAction = [&]() {
|
||||
ServerController serverController(m_settings);
|
||||
return serverController.setupContainer(m_installCredentials, container.first, container.second);
|
||||
};
|
||||
errorCode = pageLogic<ServerConfiguringProgressLogic>()->doInstallAction(installAction, pageFunc, progressBarFunc,
|
||||
noButton, waitInfoFunc,
|
||||
busyInfoFunc, cancelButtonFunc);
|
||||
errorCode = pageLogic<ServerConfiguringProgressLogic>()->doInstallAction(
|
||||
installAction, pageFunc, progressBarFunc, noButton, waitInfoFunc, busyInfoFunc, cancelButtonFunc);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
if (!isServerCreated) {
|
||||
QJsonObject server;
|
||||
|
@ -354,7 +342,7 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
|
|||
server.insert(config_key::port, m_installCredentials.port);
|
||||
server.insert(config_key::description, m_settings->nextAvailableServerName());
|
||||
|
||||
server.insert(config_key::containers, QJsonArray{container.second});
|
||||
server.insert(config_key::containers, QJsonArray { container.second });
|
||||
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container.first));
|
||||
|
||||
m_settings->addServer(server);
|
||||
|
@ -371,22 +359,23 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
|
|||
}
|
||||
} else {
|
||||
onUpdateAllPages();
|
||||
emit showWarningMessage("Attention! The container you are trying to install is already installed on the server. "
|
||||
"All installed containers have been added to the application ");
|
||||
emit showWarningMessage(
|
||||
"Attention! The container you are trying to install is already installed on the server. "
|
||||
"All installed containers have been added to the application ");
|
||||
emit setStartPage(Page::Vpn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
emit showWarningMessage(tr("Error occurred while configuring server.") + "\n" +
|
||||
tr("Error message: ") + errorString(errorCode) + "\n" +
|
||||
tr("See logs for details."));
|
||||
emit showWarningMessage(tr("Error occurred while configuring server.") + "\n" + tr("Error message: ")
|
||||
+ errorString(errorCode) + "\n" + tr("See logs for details."));
|
||||
emit closePage();
|
||||
}
|
||||
|
||||
PageProtocolLogicBase *UiLogic::protocolLogic(Proto p)
|
||||
{
|
||||
PageProtocolLogicBase *logic = m_protocolLogicMap.value(p);
|
||||
if (logic) return logic;
|
||||
if (logic)
|
||||
return logic;
|
||||
else {
|
||||
qCritical() << "UiLogic::protocolLogic Warning: logic missing for" << p;
|
||||
return new PageProtocolLogicBase(this);
|
||||
|
@ -418,7 +407,7 @@ PageEnumNS::Page UiLogic::currentPage()
|
|||
return static_cast<PageEnumNS::Page>(currentPageValue());
|
||||
}
|
||||
|
||||
void UiLogic::saveTextFile(const QString& desc, const QString& suggestedName, QString ext, const QString& data)
|
||||
void UiLogic::saveTextFile(const QString &desc, const QString &suggestedName, QString ext, const QString &data)
|
||||
{
|
||||
#ifdef Q_OS_IOS
|
||||
shareTempFile(suggestedName, ext, data);
|
||||
|
@ -429,17 +418,19 @@ void UiLogic::saveTextFile(const QString& desc, const QString& suggestedName, QS
|
|||
QString docDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
QUrl fileName;
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
fileName = QFileDialog::getSaveFileUrl(nullptr, desc,
|
||||
QUrl::fromLocalFile(docDir + "/" + suggestedName), "*" + ext);
|
||||
if (fileName.isEmpty()) return;
|
||||
if (!fileName.toString().endsWith(ext)) fileName = QUrl(fileName.toString() + ext);
|
||||
fileName = QFileDialog::getSaveFileUrl(nullptr, desc, QUrl::fromLocalFile(docDir + "/" + suggestedName), "*" + ext);
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
if (!fileName.toString().endsWith(ext))
|
||||
fileName = QUrl(fileName.toString() + ext);
|
||||
#elif defined Q_OS_ANDROID
|
||||
qDebug() << "UiLogic::shareConfig" << data;
|
||||
AndroidController::instance()->shareConfig(data, suggestedName);
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (fileName.isEmpty()) return;
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
QFile save(fileName.toLocalFile());
|
||||
|
@ -458,11 +449,13 @@ void UiLogic::saveTextFile(const QString& desc, const QString& suggestedName, QS
|
|||
void UiLogic::saveBinaryFile(const QString &desc, QString ext, const QString &data)
|
||||
{
|
||||
ext.replace("*", "");
|
||||
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
|
||||
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*" + ext);
|
||||
QString fileName = QFileDialog::getSaveFileName(
|
||||
nullptr, desc, QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*" + ext);
|
||||
|
||||
if (fileName.isEmpty()) return;
|
||||
if (!fileName.endsWith(ext)) fileName.append(ext);
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
if (!fileName.endsWith(ext))
|
||||
fileName.append(ext);
|
||||
|
||||
QFile save(fileName);
|
||||
save.open(QIODevice::WriteOnly);
|
||||
|
@ -478,12 +471,15 @@ void UiLogic::copyToClipboard(const QString &text)
|
|||
qApp->clipboard()->setText(text);
|
||||
}
|
||||
|
||||
void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QString& data) {
|
||||
void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QString &data)
|
||||
{
|
||||
ext.replace("*", "");
|
||||
QString fileName = QDir::tempPath() + "/" + suggestedName;
|
||||
|
||||
if (fileName.isEmpty()) return;
|
||||
if (!fileName.endsWith(ext)) fileName.append(ext);
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
if (!fileName.endsWith(ext))
|
||||
fileName.append(ext);
|
||||
|
||||
QFile::remove(fileName);
|
||||
|
||||
|
@ -497,14 +493,14 @@ void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QSt
|
|||
MobileUtils::shareText(filesToSend);
|
||||
}
|
||||
|
||||
QString UiLogic::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
|
||||
const QString &filter, QString *selectedFilter, QFileDialog::Options options)
|
||||
QString UiLogic::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter,
|
||||
QString *selectedFilter, QFileDialog::Options options)
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
// patch for files containing spaces etc
|
||||
const QString sep {"raw%3A%2F"};
|
||||
const QString sep { "raw%3A%2F" };
|
||||
if (fileName.startsWith("content://") && fileName.contains(sep)) {
|
||||
QString contentUrl = fileName.split(sep).at(0);
|
||||
QString rawUrl = fileName.split(sep).at(1);
|
||||
|
@ -590,7 +586,8 @@ ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool &isServerCreated)
|
|||
}
|
||||
|
||||
if (createNewServer) {
|
||||
server.insert(config_key::defaultContainer, ContainerProps::containerToString(installedContainers.firstKey()));
|
||||
server.insert(config_key::defaultContainer,
|
||||
ContainerProps::containerToString(installedContainers.firstKey()));
|
||||
m_settings->addServer(server);
|
||||
m_settings->setDefaultServer(m_settings->serversCount() - 1);
|
||||
isServerCreated = true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue