Merge branch 'dev' into ios-wireguard

This commit is contained in:
pokamest 2021-11-30 21:51:06 +03:00
commit bf8b3c3b2f
45 changed files with 1063 additions and 522 deletions

View file

@ -0,0 +1,124 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <QDebug>
#include "notificationhandler.h"
#if defined(Q_OS_IOS)
# include "platforms/ios/iosnotificationhandler.h"
#elif defined(Q_OS_ANDROID)
# include "platforms/android/android_notificationhandler.h"
#else
# if defined(Q_OS_LINUX)
# include "platforms/linux/linuxsystemtraynotificationhandler.h"
# endif
# include "systemtray_notificationhandler.h"
#endif
// static
NotificationHandler* NotificationHandler::create(QObject* parent) {
#if defined(Q_OS_IOS)
return new IOSNotificationHandler(parent);
#elif defined(Q_OS_ANDROID)
return new AndroidNotificationHandler(parent);
#else
# if defined(Q_OS_LINUX)
if (LinuxSystemTrayNotificationHandler::requiredCustomImpl()) {
return new LinuxSystemTrayNotificationHandler(parent);
}
# endif
return new SystemTrayNotificationHandler(parent);
#endif
}
namespace {
NotificationHandler* s_instance = nullptr;
} // namespace
// static
NotificationHandler* NotificationHandler::instance() {
Q_ASSERT(s_instance);
return s_instance;
}
NotificationHandler::NotificationHandler(QObject* parent) : QObject(parent) {
Q_ASSERT(!s_instance);
s_instance = this;
}
NotificationHandler::~NotificationHandler() {
Q_ASSERT(s_instance == this);
s_instance = nullptr;
}
void NotificationHandler::setConnectionState(VpnProtocol::VpnConnectionState state)
{
if (state != VpnProtocol::Connected && state != VpnProtocol::Disconnected) {
return;
}
QString title;
QString message;
switch (state) {
case VpnProtocol::VpnConnectionState::Connected:
m_connected = true;
title = tr("AmneziaVPN");
message = tr("VPN Connected");
break;
case VpnProtocol::VpnConnectionState::Disconnected:
if (m_connected) {
m_connected = false;
title = tr("AmneziaVPN");
message = tr("VPN Disconnected");
}
break;
default:
break;
}
Q_ASSERT(title.isEmpty() == message.isEmpty());
if (!title.isEmpty()) {
notifyInternal(VpnState, title, message, 2000);
}
}
void NotificationHandler::unsecuredNetworkNotification(const QString& networkName) {
qDebug() << "Unsecured network notification shown";
QString title = tr("AmneziaVPN notification");
QString message = tr("Unsucured network detected: ") + networkName;
notifyInternal(UnsecuredNetwork, title, message, 2000);
}
void NotificationHandler::notifyInternal(Message type, const QString& title,
const QString& message,
int timerMsec) {
m_lastMessage = type;
emit notificationShown(title, message);
notify(type, title, message, timerMsec);
}
void NotificationHandler::messageClickHandle() {
qDebug() << "Message clicked";
if (m_lastMessage == VpnState) {
qCritical() << "Random message clicked received";
return;
}
emit notificationClicked(m_lastMessage);
m_lastMessage = VpnState;
}

View file

@ -0,0 +1,64 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef NOTIFICATIONHANDLER_H
#define NOTIFICATIONHANDLER_H
#include <QObject>
#include "protocols/vpnprotocol.h"
class QMenu;
class NotificationHandler : public QObject {
Q_OBJECT
Q_DISABLE_COPY_MOVE(NotificationHandler)
public:
enum Message {
VpnState,
UnsecuredNetwork
};
static NotificationHandler* create(QObject* parent);
static NotificationHandler* instance();
virtual ~NotificationHandler();
void unsecuredNetworkNotification(const QString& networkName);
void messageClickHandle();
public slots:
virtual void setConnectionState(VpnProtocol::VpnConnectionState state);
signals:
void notificationShown(const QString& title, const QString& message);
void notificationClicked(Message message);
void raiseRequested();
void connectRequested();
void disconnectRequested();
protected:
explicit NotificationHandler(QObject* parent);
virtual void notify(Message type, const QString& title,
const QString& message, int timerMsec) = 0;
private:
virtual void notifyInternal(Message type, const QString& title,
const QString& message, int timerMsec);
protected:
Message m_lastMessage = VpnState;
private:
// We want to show a 'disconnected' notification only if we were actually
// connected.
bool m_connected = false;
};
#endif // NOTIFICATIONHANDLER_H

View file

@ -88,8 +88,6 @@ void VpnLogic::onConnectionStateChanged(VpnProtocol::VpnConnectionState state)
bool pbConnectVisible = false;
set_labelStateText(VpnProtocol::textConnectionState(state));
uiLogic()->setTrayState(state);
switch (state) {
case VpnProtocol::Disconnected:
onBytesChanged(0,0);

View file

@ -0,0 +1,181 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <QDebug>
#include "systemtray_notificationhandler.h"
#ifdef Q_OS_MACOS
# include "platforms/macos/macosutils.h"
#endif
#include <QApplication>
#include <QDesktopServices>
#include <QIcon>
#include <QWindow>
#include "defines.h"
SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) :
NotificationHandler(parent),
m_systemTrayIcon(parent)
{
m_systemTrayIcon.show();
connect(&m_systemTrayIcon, &QSystemTrayIcon::activated, this, &SystemTrayNotificationHandler::onTrayActivated);
m_menu.addAction(QIcon(":/images/tray/application.png"), tr("Show") + " " + APPLICATION_NAME, this, [this](){
emit raiseRequested();
});
m_menu.addSeparator();
m_trayActionConnect = m_menu.addAction(tr("Connect"), this, [this](){ emit connectRequested(); });
m_trayActionDisconnect = m_menu.addAction(tr("Disconnect"), this, [this](){ emit disconnectRequested(); });
m_menu.addSeparator();
m_menu.addAction(QIcon(":/images/tray/link.png"), tr("Visit Website"), [&](){
QDesktopServices::openUrl(QUrl("https://amnezia.org"));
});
m_menu.addAction(QIcon(":/images/tray/cancel.png"), tr("Quit") + " " + APPLICATION_NAME, this, [&](){
qApp->quit();
});
m_systemTrayIcon.setContextMenu(&m_menu);
setTrayState(VpnProtocol::Disconnected);
// m_preferencesAction = m_menu.addAction("", vpn, &MozillaVPN::requestSettings);
// m_menu.addSeparator();
// m_quitAction = m_menu.addAction("", vpn->controller(), &Controller::quit);
// m_systemTrayIcon.setContextMenu(&m_menu);
// updateIcon(vpn->statusIcon()->iconString());
// connect(QmlEngineHolder::instance()->window(), &QWindow::visibleChanged, this,
// &SystemTrayNotificationHandler::updateContextMenu);
// connect(&m_systemTrayIcon, &QSystemTrayIcon::activated, this,
// &SystemTrayNotificationHandler::maybeActivated);
// connect(&m_systemTrayIcon, &QSystemTrayIcon::messageClicked, this,
// &SystemTrayNotificationHandler::messageClickHandle);
// retranslate();
// m_systemTrayIcon.show();
}
SystemTrayNotificationHandler::~SystemTrayNotificationHandler() {
}
void SystemTrayNotificationHandler::setConnectionState(VpnProtocol::VpnConnectionState state)
{
setTrayState(state);
NotificationHandler::setConnectionState(state);
}
void SystemTrayNotificationHandler::setTrayIcon(const QString &iconPath)
{
QIcon trayIconMask(QPixmap(iconPath).scaled(128,128));
trayIconMask.setIsMask(true);
m_systemTrayIcon.setIcon(trayIconMask);
}
void SystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
#ifndef Q_OS_MAC
if(reason == QSystemTrayIcon::DoubleClick || reason == QSystemTrayIcon::Trigger) {
emit raiseRequested();
}
#endif
}
void SystemTrayNotificationHandler::setTrayState(VpnProtocol::VpnConnectionState state)
{
qDebug() << "SystemTrayNotificationHandler::setTrayState" << state;
QString resourcesPath = ":/images/tray/%1";
switch (state) {
case VpnProtocol::Disconnected:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(true);
m_trayActionDisconnect->setEnabled(false);
break;
case VpnProtocol::Preparing:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Connecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Connected:
setTrayIcon(QString(resourcesPath).arg(ConnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Disconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Reconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Error:
setTrayIcon(QString(resourcesPath).arg(ErrorTrayIconName));
m_trayActionConnect->setEnabled(true);
m_trayActionDisconnect->setEnabled(false);
break;
case VpnProtocol::Unknown:
default:
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
}
//#ifdef Q_OS_MAC
// // Get theme from current user (note, this app can be launched as root application and in this case this theme can be different from theme of real current user )
// bool darkTaskBar = MacOSFunctions::instance().isMenuBarUseDarkTheme();
// darkTaskBar = forceUseBrightIcons ? true : darkTaskBar;
// resourcesPath = ":/images_mac/tray_icon/%1";
// useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png");
//#endif
}
void SystemTrayNotificationHandler::notify(NotificationHandler::Message type,
const QString& title,
const QString& message,
int timerMsec) {
Q_UNUSED(type);
QIcon icon(ConnectedTrayIconName);
m_systemTrayIcon.showMessage(title, message, icon, timerMsec);
}
void SystemTrayNotificationHandler::showHideWindow() {
// QmlEngineHolder* engine = QmlEngineHolder::instance();
// if (engine->window()->isVisible()) {
// engine->hideWindow();
//#ifdef MVPN_MACOS
// MacOSUtils::hideDockIcon();
//#endif
// } else {
// engine->showWindow();
//#ifdef MVPN_MACOS
// MacOSUtils::showDockIcon();
//#endif
// }
}

View file

@ -0,0 +1,49 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SYSTEMTRAY_NOTIFICATIONHANDLER_H
#define SYSTEMTRAY_NOTIFICATIONHANDLER_H
#include "notificationhandler.h"
#include <QMenu>
#include <QSystemTrayIcon>
class SystemTrayNotificationHandler : public NotificationHandler {
Q_OBJECT
public:
explicit SystemTrayNotificationHandler(QObject* parent);
~SystemTrayNotificationHandler();
void setConnectionState(VpnProtocol::VpnConnectionState state) override;
protected:
virtual void notify(Message type, const QString& title,
const QString& message, int timerMsec) override;
private:
void showHideWindow();
void setTrayState(VpnProtocol::VpnConnectionState state);
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
void setTrayIcon(const QString &iconPath);
private:
QMenu m_menu;
QSystemTrayIcon m_systemTrayIcon;
QAction* m_trayActionConnect = nullptr;
QAction* m_trayActionDisconnect = nullptr;
QAction* m_preferencesAction = nullptr;
QAction* m_statusLabel = nullptr;
QAction* m_separator = nullptr;
const QString ConnectedTrayIconName = "active.png";
const QString DisconnectedTrayIconName = "default.png";
const QString ErrorTrayIconName = "error.png";
};
#endif // SYSTEMTRAY_NOTIFICATIONHANDLER_H

View file

@ -44,6 +44,10 @@
#include "ui/macos_util.h"
#endif
#ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
#endif
#include "pages_logic/AppSettingsLogic.h"
#include "pages_logic/GeneralSettingsLogic.h"
#include "pages_logic/NetworkSettingsLogic.h"
@ -94,7 +98,7 @@ UiLogic::UiLogic(QObject *parent) :
m_protocolLogicMap.insert(Proto::OpenVpn, new OpenVpnLogic(this));
m_protocolLogicMap.insert(Proto::ShadowSocks, new ShadowSocksLogic(this));
m_protocolLogicMap.insert(Proto::Cloak, new CloakLogic(this));
//m_protocolLogicMap->insert(Protocol::WireGuard, new WireguardLogic(this));
//m_protocolLogicMap->insert(Proto::WireGuard, new WireguardLogic(this));
m_protocolLogicMap.insert(Proto::Dns, new OtherProtocolsLogic(this));
m_protocolLogicMap.insert(Proto::Sftp, new OtherProtocolsLogic(this));
@ -104,8 +108,6 @@ UiLogic::UiLogic(QObject *parent) :
UiLogic::~UiLogic()
{
m_tray = nullptr;
emit hide();
if (m_vpnConnection->connectionState() != VpnProtocol::VpnConnectionState::Disconnected) {
@ -128,9 +130,22 @@ UiLogic::~UiLogic()
void UiLogic::initalizeUiLogic()
{
qDebug() << "UiLogic::initalizeUiLogic()";
setupTray();
#ifdef Q_OS_ANDROID
if (!AndroidController::instance()->initialize()) {
qDebug() << QString("Init failed") ;
emit VpnProtocol::Error;
return;
}
#endif
qDebug() << "UiLogic::initalizeUiLogic()";
m_notificationHandler = NotificationHandler::create(qmlRoot());
connect(m_vpnConnection, &VpnConnection::connectionStateChanged, m_notificationHandler, &NotificationHandler::setConnectionState);
connect(m_notificationHandler, &NotificationHandler::raiseRequested, this, &UiLogic::raise);
connect(m_notificationHandler, &NotificationHandler::connectRequested, vpnLogic(), &VpnLogic::onConnect);
connect(m_notificationHandler, &NotificationHandler::disconnectRequested, vpnLogic(), &VpnLogic::onDisconnect);
// if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::Windows7) {
// needToHideCustomTitlebar = true;
@ -161,7 +176,7 @@ void UiLogic::initalizeUiLogic()
selectedServerIndex = m_settings.defaultServerIndex();
//goToPage(Page::ServerContainers, true, false);
//goToPage(Page::NewServerProtocols, true, false);
//onGotoProtocolPage(Protocol::OpenVpn);
//onGotoProtocolPage(Proto::OpenVpn);
//ui->pushButton_general_settings_exit->hide();
@ -600,27 +615,8 @@ ErrorCode UiLogic::doInstallAction(const std::function<ErrorCode()> &action,
return ErrorCode::NoError;
}
void UiLogic::setupTray()
PageProtocolLogicBase *UiLogic::protocolLogic(Proto p)
{
m_tray = new QSystemTrayIcon(qmlRoot());
setTrayState(VpnProtocol::Disconnected);
m_tray->show();
connect(m_tray, &QSystemTrayIcon::activated, this, &UiLogic::onTrayActivated);
}
void UiLogic::setTrayIcon(const QString &iconPath)
{
if (m_tray) m_tray->setIcon(QIcon(QPixmap(iconPath).scaled(128,128)));
}
void UiLogic::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
emit raise();
}
PageProtocolLogicBase *UiLogic::protocolLogic(Proto p) {
PageProtocolLogicBase *logic = m_protocolLogicMap.value(p);
if (logic) return logic;
else {
@ -639,57 +635,23 @@ void UiLogic::setQmlRoot(QObject *newQmlRoot)
m_qmlRoot = newQmlRoot;
}
NotificationHandler *UiLogic::notificationHandler() const
{
return m_notificationHandler;
}
PageEnumNS::Page UiLogic::currentPage()
{
return static_cast<PageEnumNS::Page>(currentPageValue());
}
void UiLogic::setTrayState(VpnProtocol::VpnConnectionState state)
{
QString resourcesPath = ":/images/tray/%1";
switch (state) {
case VpnProtocol::Disconnected:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
break;
case VpnProtocol::Preparing:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
break;
case VpnProtocol::Connecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
break;
case VpnProtocol::Connected:
setTrayIcon(QString(resourcesPath).arg(ConnectedTrayIconName));
break;
case VpnProtocol::Disconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
break;
case VpnProtocol::Reconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
break;
case VpnProtocol::Error:
setTrayIcon(QString(resourcesPath).arg(ErrorTrayIconName));
break;
case VpnProtocol::Unknown:
default:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
}
//#ifdef Q_OS_MAC
// // Get theme from current user (note, this app can be launched as root application and in this case this theme can be different from theme of real current user )
// bool darkTaskBar = MacOSFunctions::instance().isMenuBarUseDarkTheme();
// darkTaskBar = forceUseBrightIcons ? true : darkTaskBar;
// resourcesPath = ":/images_mac/tray_icon/%1";
// useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png");
//#endif
}
bool UiLogic::saveTextFile(const QString& desc, const QString& ext, const QString& data)
{
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext);
if (fileName.isEmpty()) return false;
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(data.toUtf8());
@ -705,6 +667,8 @@ bool UiLogic::saveBinaryFile(const QString &desc, const QString &ext, const QStr
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext);
if (fileName.isEmpty()) return false;
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(QByteArray::fromBase64(data.toUtf8()));

View file

@ -6,7 +6,6 @@
#include <functional>
#include <QKeyEvent>
#include <QThread>
#include <QSystemTrayIcon>
#include "property_helper.h"
#include "pages.h"
@ -16,6 +15,7 @@
#include "models/containers_model.h"
#include "models/protocols_model.h"
#include "notificationhandler.h"
#include "settings.h"
class AppSettingsLogic;
@ -107,12 +107,8 @@ public:
void setDialogConnectErrorText(const QString &dialogConnectErrorText);
signals:
void trayIconUrlChanged();
void trayActionDisconnectEnabledChanged();
void trayActionConnectEnabledChanged();
void dialogConnectErrorTextChanged();
void goToPage(PageEnumNS::Page page, bool reset = true, bool slide = true);
void goToProtocolPage(Proto protocol, bool reset = true, bool slide = true);
void goToShareProtocolPage(Proto protocol, bool reset = true, bool slide = true);
@ -126,17 +122,12 @@ signals:
void raise();
private:
QSystemTrayIcon *m_tray;
QString m_dialogConnectErrorText;
private slots:
// containers - INOUT arg
void installServer(QMap<DockerContainer, QJsonObject> &containers);
void setTrayState(VpnProtocol::VpnConnectionState state);
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
private:
PageEnumNS::Page currentPage();
struct ProgressFunc {
@ -171,9 +162,6 @@ private:
const ButtonFunc& button,
const LabelFunc& info);
void setupTray();
void setTrayIcon(const QString &iconPath);
public:
AppSettingsLogic *appSettingsLogic() { return m_appSettingsLogic; }
@ -195,6 +183,8 @@ public:
QObject *qmlRoot() const;
void setQmlRoot(QObject *newQmlRoot);
NotificationHandler *notificationHandler() const;
private:
QObject *m_qmlRoot{nullptr};
@ -218,6 +208,8 @@ private:
QThread m_vpnConnectionThread;
Settings m_settings;
NotificationHandler* m_notificationHandler;
// QRegExpValidator m_ipAddressValidator;
// QRegExpValidator m_ipAddressPortValidator;
@ -230,10 +222,6 @@ private:
// void showEvent(QShowEvent *event) override;
// void hideEvent(QHideEvent *event) override;
const QString ConnectedTrayIconName = "active.png";
const QString DisconnectedTrayIconName = "default.png";
const QString ErrorTrayIconName = "error.png";
// QStack<Page> pagesStack;
int selectedServerIndex = -1; // server index to use when proto settings page opened