feature: added pages for subscription settings feature

This commit is contained in:
vladimir.kuznetsov 2025-02-06 15:26:47 +07:00
parent 3f55f6a629
commit b183a3b232
27 changed files with 856 additions and 287 deletions

View file

@ -57,8 +57,7 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
endif() endif()
qt_standard_project_setup() qt_standard_project_setup()
qt_add_executable(${PROJECT} MANUAL_FINALIZATION qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
core/controllers/gatewayController.h core/controllers/gatewayController.cpp)
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep) qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
@ -111,8 +110,8 @@ if(IS_CI)
endif() endif()
endif() endif()
include(${CMAKE_CURRENT_LIST_DIR}/cmake/3rdparty.cmake) include(${CMAKE_CURRENT_LIST_DIR}/cmake/3rdparty.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/sources.cmake)
include_directories( include_directories(
${CMAKE_CURRENT_LIST_DIR}/../ipc ${CMAKE_CURRENT_LIST_DIR}/../ipc
@ -121,167 +120,22 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
) )
configure_file(${CMAKE_CURRENT_LIST_DIR}/../version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/migrations.h
${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc.h
${CMAKE_CURRENT_LIST_DIR}/amnezia_application.h
${CMAKE_CURRENT_LIST_DIR}/containers/containers_defs.h
${CMAKE_CURRENT_LIST_DIR}/core/defs.h
${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.h
${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.h
${CMAKE_CURRENT_LIST_DIR}/core/server_defs.h
${CMAKE_CURRENT_LIST_DIR}/core/controllers/apiController.h
${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.h
${CMAKE_CURRENT_LIST_DIR}/core/controllers/vpnConfigurationController.h
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h
${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.h
${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
${CMAKE_CURRENT_BINARY_DIR}/version.h
${CMAKE_CURRENT_LIST_DIR}/core/sshclient.h
${CMAKE_CURRENT_LIST_DIR}/core/networkUtilities.h
${CMAKE_CURRENT_LIST_DIR}/core/serialization/serialization.h
${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h
${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.h
${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.h
)
# Mozilla headres
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/mozilla/models/server.h
${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/ipaddress.h
${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/leakdetector.h
${CMAKE_CURRENT_LIST_DIR}/mozilla/controllerimpl.h
${CMAKE_CURRENT_LIST_DIR}/mozilla/localsocketcontroller.h
)
include_directories(mozilla) include_directories(mozilla)
include_directories(mozilla/shared) include_directories(mozilla/shared)
include_directories(mozilla/models) include_directories(mozilla/models)
if(NOT IOS) configure_file(${CMAKE_CURRENT_LIST_DIR}/../version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.h
)
endif()
if(NOT ANDROID)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h
)
endif()
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/migrations.cpp
${CMAKE_CURRENT_LIST_DIR}/amnezia_application.cpp
${CMAKE_CURRENT_LIST_DIR}/containers/containers_defs.cpp
${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.cpp
${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.cpp
${CMAKE_CURRENT_LIST_DIR}/core/server_defs.cpp
${CMAKE_CURRENT_LIST_DIR}/core/controllers/apiController.cpp
${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.cpp
${CMAKE_CURRENT_LIST_DIR}/core/controllers/vpnConfigurationController.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/core/sshclient.cpp
${CMAKE_CURRENT_LIST_DIR}/core/networkUtilities.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/outbound.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/inbound.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/ss.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/ssd.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vless.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/trojan.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.cpp
${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.cpp
)
# Mozilla sources
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mozilla/models/server.cpp
${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/ipaddress.cpp
${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/leakdetector.cpp
${CMAKE_CURRENT_LIST_DIR}/mozilla/localsocketcontroller.cpp
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(${PROJECT} PRIVATE "MZ_DEBUG") target_compile_definitions(${PROJECT} PRIVATE "MZ_DEBUG")
endif() endif()
if(NOT IOS)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.cpp
)
endif()
if(NOT ANDROID)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp
)
endif()
file(GLOB COMMON_FILES_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/*.h)
file(GLOB COMMON_FILES_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
file(GLOB_RECURSE PAGE_LOGIC_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/pages_logic/*.h)
file(GLOB_RECURSE PAGE_LOGIC_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/pages_logic/*.cpp)
file(GLOB CONFIGURATORS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.h)
file(GLOB CONFIGURATORS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.cpp)
file(GLOB UI_MODELS_H CONFIGURE_DEPENDS
${CMAKE_CURRENT_LIST_DIR}/ui/models/*.h
${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.h
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.h
)
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
${CMAKE_CURRENT_LIST_DIR}/ui/models/*.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp
)
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h)
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp)
set(HEADERS ${HEADERS}
${COMMON_FILES_H}
${PAGE_LOGIC_H}
${CONFIGURATORS_H}
${UI_MODELS_H}
${UI_CONTROLLERS_H}
)
set(SOURCES ${SOURCES}
${COMMON_FILES_CPP}
${PAGE_LOGIC_CPP}
${CONFIGURATORS_CPP}
${UI_MODELS_CPP}
${UI_CONTROLLERS_CPP}
)
if(WIN32) if(WIN32)
configure_file( configure_file(
${CMAKE_CURRENT_LIST_DIR}/platforms/windows/amneziavpn.rc.in ${CMAKE_CURRENT_LIST_DIR}/platforms/windows/amneziavpn.rc.in
${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc ${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc
) )
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h
)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
)
set(RESOURCES ${RESOURCES}
${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc
)
set(LIBS ${LIBS} set(LIBS ${LIBS}
user32 user32
rasapi32 rasapi32
@ -325,30 +179,6 @@ endif()
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
message("Client desktop build") message("Client desktop build")
add_compile_definitions(AMNEZIA_DESKTOP) add_compile_definitions(AMNEZIA_DESKTOP)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/core/ipcclient.h
${CMAKE_CURRENT_LIST_DIR}/core/privileged_process.h
${CMAKE_CURRENT_LIST_DIR}/ui/systemtray_notificationhandler.h
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/xrayprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.h
)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/ipcclient.cpp
${CMAKE_CURRENT_LIST_DIR}/core/privileged_process.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/systemtray_notificationhandler.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/xrayprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.cpp
)
endif() endif()
if(ANDROID) if(ANDROID)

View file

@ -378,6 +378,9 @@ void AmneziaApplication::initModels()
}); });
connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this, connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this,
[this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); }); [this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); });
m_apiAccountInfoModel.reset(new ApiAccountInfoModel(this));
m_engine->rootContext()->setContextProperty("ApiAccountInfoModel", m_apiAccountInfoModel.get());
} }
void AmneziaApplication::initControllers() void AmneziaApplication::initControllers()
@ -463,4 +466,7 @@ void AmneziaApplication::initControllers()
m_systemController.reset(new SystemController(m_settings)); m_systemController.reset(new SystemController(m_settings));
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get()); m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
m_apiSettingsController.reset(new ApiSettingsController(m_serversModel, m_apiAccountInfoModel, m_settings));
m_engine->rootContext()->setContextProperty("ApiSettingsController", m_apiSettingsController.get());
} }

View file

@ -25,6 +25,8 @@
#include "ui/controllers/sitesController.h" #include "ui/controllers/sitesController.h"
#include "ui/controllers/systemController.h" #include "ui/controllers/systemController.h"
#include "ui/controllers/appSplitTunnelingController.h" #include "ui/controllers/appSplitTunnelingController.h"
// #include "ui/controllers/api/importController.h"
#include "ui/controllers/api/apiSettingsController.h"
#include "ui/models/containers_model.h" #include "ui/models/containers_model.h"
#include "ui/models/languageModel.h" #include "ui/models/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h" #include "ui/models/protocols/cloakConfigModel.h"
@ -48,6 +50,7 @@
#include "ui/models/appSplitTunnelingModel.h" #include "ui/models/appSplitTunnelingModel.h"
#include "ui/models/apiServicesModel.h" #include "ui/models/apiServicesModel.h"
#include "ui/models/apiCountryModel.h" #include "ui/models/apiCountryModel.h"
#include "ui/models/api/apiAccountInfoModel.h"
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance())) #define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
@ -104,6 +107,7 @@ private:
QSharedPointer<ClientManagementModel> m_clientManagementModel; QSharedPointer<ClientManagementModel> m_clientManagementModel;
QSharedPointer<ApiServicesModel> m_apiServicesModel; QSharedPointer<ApiServicesModel> m_apiServicesModel;
QSharedPointer<ApiCountryModel> m_apiCountryModel; QSharedPointer<ApiCountryModel> m_apiCountryModel;
QSharedPointer<ApiAccountInfoModel> m_apiAccountInfoModel;
QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel; QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel;
QScopedPointer<ShadowSocksConfigModel> m_shadowSocksConfigModel; QScopedPointer<ShadowSocksConfigModel> m_shadowSocksConfigModel;
@ -114,7 +118,6 @@ private:
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
QScopedPointer<Ikev2ConfigModel> m_ikev2ConfigModel; QScopedPointer<Ikev2ConfigModel> m_ikev2ConfigModel;
#endif #endif
QScopedPointer<SftpConfigModel> m_sftpConfigModel; QScopedPointer<SftpConfigModel> m_sftpConfigModel;
QScopedPointer<Socks5ProxyConfigModel> m_socks5ConfigModel; QScopedPointer<Socks5ProxyConfigModel> m_socks5ConfigModel;
@ -135,6 +138,8 @@ private:
QScopedPointer<SystemController> m_systemController; QScopedPointer<SystemController> m_systemController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController; QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
QScopedPointer<ApiSettingsController> m_apiSettingsController;
QNetworkAccessManager *m_nam; QNetworkAccessManager *m_nam;
QMetaObject::Connection m_reloadConfigErrorOccurredConnection; QMetaObject::Connection m_reloadConfigErrorOccurredConnection;

189
client/cmake/sources.cmake Normal file
View file

@ -0,0 +1,189 @@
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/migrations.h
${CLIENT_ROOT_DIR}/../ipc/ipc.h
${CLIENT_ROOT_DIR}/amnezia_application.h
${CLIENT_ROOT_DIR}/containers/containers_defs.h
${CLIENT_ROOT_DIR}/core/defs.h
${CLIENT_ROOT_DIR}/core/errorstrings.h
${CLIENT_ROOT_DIR}/core/scripts_registry.h
${CLIENT_ROOT_DIR}/core/server_defs.h
${CLIENT_ROOT_DIR}/core/controllers/apiController.h
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.h
${CLIENT_ROOT_DIR}/core/controllers/serverController.h
${CLIENT_ROOT_DIR}/core/controllers/vpnConfigurationController.h
${CLIENT_ROOT_DIR}/protocols/protocols_defs.h
${CLIENT_ROOT_DIR}/protocols/qml_register_protocols.h
${CLIENT_ROOT_DIR}/ui/pages.h
${CLIENT_ROOT_DIR}/ui/qautostart.h
${CLIENT_ROOT_DIR}/protocols/vpnprotocol.h
${CMAKE_CURRENT_BINARY_DIR}/version.h
${CLIENT_ROOT_DIR}/core/sshclient.h
${CLIENT_ROOT_DIR}/core/networkUtilities.h
${CLIENT_ROOT_DIR}/core/serialization/serialization.h
${CLIENT_ROOT_DIR}/core/serialization/transfer.h
${CLIENT_ROOT_DIR}/core/enums/apiEnums.h
${CLIENT_ROOT_DIR}/../common/logger/logger.h
${CLIENT_ROOT_DIR}/utils/qmlUtils.h
${CLIENT_ROOT_DIR}/core/api/apiUtils.h
)
# Mozilla headres
set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/mozilla/models/server.h
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.h
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.h
${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
)
if(NOT IOS)
set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.h
)
endif()
if(NOT ANDROID)
set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/ui/notificationhandler.h
)
endif()
set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/migrations.cpp
${CLIENT_ROOT_DIR}/amnezia_application.cpp
${CLIENT_ROOT_DIR}/containers/containers_defs.cpp
${CLIENT_ROOT_DIR}/core/errorstrings.cpp
${CLIENT_ROOT_DIR}/core/scripts_registry.cpp
${CLIENT_ROOT_DIR}/core/server_defs.cpp
${CLIENT_ROOT_DIR}/core/controllers/apiController.cpp
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.cpp
${CLIENT_ROOT_DIR}/core/controllers/serverController.cpp
${CLIENT_ROOT_DIR}/core/controllers/vpnConfigurationController.cpp
${CLIENT_ROOT_DIR}/protocols/protocols_defs.cpp
${CLIENT_ROOT_DIR}/ui/qautostart.cpp
${CLIENT_ROOT_DIR}/protocols/vpnprotocol.cpp
${CLIENT_ROOT_DIR}/core/sshclient.cpp
${CLIENT_ROOT_DIR}/core/networkUtilities.cpp
${CLIENT_ROOT_DIR}/core/serialization/outbound.cpp
${CLIENT_ROOT_DIR}/core/serialization/inbound.cpp
${CLIENT_ROOT_DIR}/core/serialization/ss.cpp
${CLIENT_ROOT_DIR}/core/serialization/ssd.cpp
${CLIENT_ROOT_DIR}/core/serialization/vless.cpp
${CLIENT_ROOT_DIR}/core/serialization/trojan.cpp
${CLIENT_ROOT_DIR}/core/serialization/vmess.cpp
${CLIENT_ROOT_DIR}/core/serialization/vmess_new.cpp
${CLIENT_ROOT_DIR}/../common/logger/logger.cpp
${CLIENT_ROOT_DIR}/utils/qmlUtils.cpp
${CLIENT_ROOT_DIR}/core/api/apiUtils.cpp
)
# Mozilla sources
set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.cpp
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
)
if(NOT IOS)
set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp
)
endif()
if(NOT ANDROID)
set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/ui/notificationhandler.cpp
)
endif()
file(GLOB COMMON_FILES_H CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/*.h)
file(GLOB COMMON_FILES_CPP CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/*.cpp)
file(GLOB_RECURSE PAGE_LOGIC_H CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/ui/pages_logic/*.h)
file(GLOB_RECURSE PAGE_LOGIC_CPP CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/ui/pages_logic/*.cpp)
file(GLOB CONFIGURATORS_H CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/configurators/*.h)
file(GLOB CONFIGURATORS_CPP CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/configurators/*.cpp)
file(GLOB UI_MODELS_H CONFIGURE_DEPENDS
${CLIENT_ROOT_DIR}/ui/models/*.h
${CLIENT_ROOT_DIR}/ui/models/protocols/*.h
${CLIENT_ROOT_DIR}/ui/models/services/*.h
${CLIENT_ROOT_DIR}/ui/models/api/*.h
)
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
${CLIENT_ROOT_DIR}/ui/models/*.cpp
${CLIENT_ROOT_DIR}/ui/models/protocols/*.cpp
${CLIENT_ROOT_DIR}/ui/models/services/*.cpp
${CLIENT_ROOT_DIR}/ui/models/api/*.cpp
)
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS
${CLIENT_ROOT_DIR}/ui/controllers/*.h
${CLIENT_ROOT_DIR}/ui/controllers/api/*.h
)
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS
${CLIENT_ROOT_DIR}/ui/controllers/*.cpp
${CLIENT_ROOT_DIR}/ui/controllers/api/*.cpp
)
set(HEADERS ${HEADERS}
${COMMON_FILES_H}
${PAGE_LOGIC_H}
${CONFIGURATORS_H}
${UI_MODELS_H}
${UI_CONTROLLERS_H}
)
set(SOURCES ${SOURCES}
${COMMON_FILES_CPP}
${PAGE_LOGIC_CPP}
${CONFIGURATORS_CPP}
${UI_MODELS_CPP}
${UI_CONTROLLERS_CPP}
)
if(WIN32)
set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.h
)
set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
)
set(RESOURCES ${RESOURCES}
${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc
)
endif()
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
message("Client desktop build")
add_compile_definitions(AMNEZIA_DESKTOP)
set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/core/ipcclient.h
${CLIENT_ROOT_DIR}/core/privileged_process.h
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.h
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.h
${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.h
${CLIENT_ROOT_DIR}/protocols/shadowsocksvpnprotocol.h
${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.h
${CLIENT_ROOT_DIR}/protocols/xrayprotocol.h
${CLIENT_ROOT_DIR}/protocols/awgprotocol.h
)
set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/core/ipcclient.cpp
${CLIENT_ROOT_DIR}/core/privileged_process.cpp
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp
${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.cpp
${CLIENT_ROOT_DIR}/protocols/shadowsocksvpnprotocol.cpp
${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.cpp
${CLIENT_ROOT_DIR}/protocols/xrayprotocol.cpp
${CLIENT_ROOT_DIR}/protocols/awgprotocol.cpp
)
endif()

View file

@ -0,0 +1,10 @@
#include "apiUtils.h"
#include <QDateTime>
bool ApiUtils::isSubscriptionExpired(const QString &subscriptionEndDate)
{
QDateTime now = QDateTime::currentDateTime();
QDateTime endDate = QDateTime::fromString(subscriptionEndDate, Qt::ISODateWithMs);
return endDate < now;
}

View file

@ -0,0 +1,11 @@
#ifndef APIUTILS_H
#define APIUTILS_H
#include <QObject>
namespace ApiUtils
{
bool isSubscriptionExpired(const QString &subscriptionEndDate);
}
#endif // APIUTILS_H

View file

@ -8,8 +8,8 @@
#include "amnezia_application.h" #include "amnezia_application.h"
#include "configurators/wireguard_configurator.h" #include "configurators/wireguard_configurator.h"
#include "core/enums/apiEnums.h" #include "core/enums/apiEnums.h"
#include "version.h"
#include "gatewayController.h" #include "gatewayController.h"
#include "version.h"
namespace namespace
{ {
@ -213,10 +213,29 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
} }
} }
ErrorCode ApiController::getAccountInfo(const QString &userCountryCode, const QString &serviceType, const QJsonObject &authData,
QByteArray &responseBody)
{
GatewayController gatewayController(m_gatewayEndpoint, m_isDevEnvironment, requestTimeoutMsecs);
QJsonObject apiPayload;
apiPayload[configKey::userCountryCode] = userCountryCode;
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::authData] = authData;
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
return errorCode;
}
ErrorCode ApiController::getServicesList(QByteArray &responseBody) ErrorCode ApiController::getServicesList(QByteArray &responseBody)
{ {
GatewayController gatewayController(m_gatewayEndpoint, m_isDevEnvironment, requestTimeoutMsecs); GatewayController gatewayController(m_gatewayEndpoint, m_isDevEnvironment, requestTimeoutMsecs);
ErrorCode errorCode = gatewayController.get("%1v1/services", responseBody);
QJsonObject apiPayload;
apiPayload[configKey::osVersion] = QSysInfo::productType();
ErrorCode errorCode = gatewayController.post(QString("%1v1/services"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
if (!responseBody.contains("services")) { if (!responseBody.contains("services")) {
return ErrorCode::ApiServicesMissingError; return ErrorCode::ApiServicesMissingError;
@ -254,3 +273,24 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
return errorCode; return errorCode;
} }
ErrorCode ApiController::getNativeConfig(const QString &userCountryCode, const QString &serviceType, const QString &protocol,
const QString &serverCountryCode, const QJsonObject &authData, QString &nativeConfig)
{
GatewayController gatewayController(m_gatewayEndpoint, m_isDevEnvironment, requestTimeoutMsecs);
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
apiPayload[configKey::userCountryCode] = userCountryCode;
apiPayload[configKey::serverCountryCode] = serverCountryCode;
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::authData] = authData;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/country_config"), apiPayload, responseBody);
nativeConfig = responseBody;
return errorCode;
}

View file

@ -19,9 +19,14 @@ public:
public slots: public slots:
void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig); void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
ErrorCode getAccountInfo(const QString &userCountryCode, const QString &serviceType, const QJsonObject &authData,
QByteArray &responseBody);
ErrorCode getServicesList(QByteArray &responseBody); ErrorCode getServicesList(QByteArray &responseBody);
ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType, ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData, QJsonObject &serverConfig); const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData,
QJsonObject &serverConfig);
ErrorCode getNativeConfig(const QString &userCountryCode, const QString &serviceType, const QString &protocol,
const QString &serverCountryCode, const QJsonObject &authData, QString &nativeConfig);
signals: signals:
void errorOccurred(ErrorCode errorCode); void errorOccurred(ErrorCode errorCode);

View file

@ -225,6 +225,9 @@
<file>ui/qml/Pages2/PageShareFullAccess.qml</file> <file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>ui/qml/Pages2/PageStart.qml</file> <file>ui/qml/Pages2/PageStart.qml</file>
<file>ui/qml/Components/RenameServerDrawer.qml</file> <file>ui/qml/Components/RenameServerDrawer.qml</file>
<file>ui/qml/Controls2/ListViewType.qml</file>
<file>ui/qml/Pages2/PageSettingsApiSupport.qml</file>
<file>ui/qml/Pages2/PageSettingsApiInstructions.qml</file>
</qresource> </qresource>
<qresource prefix="/countriesFlags"> <qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file> <file>images/flagKit/ZW.svg</file>

View file

@ -0,0 +1,57 @@
#include "apiSettingsController.h"
#include "core/controllers/gatewayController.h"
namespace
{
namespace configKey
{
constexpr char userCountryCode[] = "user_country_code";
constexpr char serverCountryCode[] = "server_country_code";
constexpr char serviceType[] = "service_type";
constexpr char serviceInfo[] = "service_info";
constexpr char apiConfig[] = "api_config";
constexpr char authData[] = "auth_data";
}
const int requestTimeoutMsecs = 12 * 1000; // 12 secs
}
ApiSettingsController::ApiSettingsController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ApiAccountInfoModel> &apiAccountInfoModel, const std::shared_ptr<Settings> &settings,
QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_apiAccountInfoModel(apiAccountInfoModel), m_settings(settings)
{
}
ApiSettingsController::~ApiSettingsController()
{
}
bool ApiSettingsController::getAccountInfo()
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), requestTimeoutMsecs);
auto processedIndex = m_serversModel->getProcessedServerIndex();
auto serverConfig = m_serversModel->getServerConfig(processedIndex);
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
auto authData = serverConfig.value(configKey::authData).toObject();
QJsonObject apiPayload;
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
apiPayload[configKey::serviceType] = apiConfig.value(configKey::serviceType).toString();
apiPayload[configKey::authData] = authData;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) {
// emit errorOccured(errorCode);
return false;
}
QJsonObject accountInfo = QJsonDocument::fromJson(responseBody).object();
m_apiAccountInfoModel->updateModel(accountInfo, serverConfig);
return true;
}

View file

@ -0,0 +1,27 @@
#ifndef APISETTINGSCONTROLLER_H
#define APISETTINGSCONTROLLER_H
#include <QObject>
#include "ui/models/api/apiAccountInfoModel.h"
#include "ui/models/servers_model.h"
class ApiSettingsController : public QObject
{
Q_OBJECT
public:
ApiSettingsController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ApiAccountInfoModel> &apiAccountInfoModel,
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
~ApiSettingsController();
public slots:
bool getAccountInfo();
private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ApiAccountInfoModel> m_apiAccountInfoModel;
std::shared_ptr<Settings> m_settings;
};
#endif // APISETTINGSCONTROLLER_H

View file

@ -0,0 +1,2 @@
#include "importController.h"

View file

@ -0,0 +1,24 @@
#ifndef IMPORTCONTROLLER_H
#define IMPORTCONTROLLER_H
#include <QObject>
#include "ui/models/api/apiAccountInfoModel.h"
#include "ui/models/servers_model.h"
// namespace api
// {
// class ImportController : public QObject
// {
// Q_OBJECT
// public:
// ImportController(const QSharedPointer<ServersModel> &serversModel, QSharedPointer<AccountInfoModel> &accountInfoModel);
// ~ImportController();
// private:
// QSharedPointer<ServersModel> m_serversModel;
// QSharedPointer<AccountInfoModel> m_accountInfoModel;
// };
// }
#endif // IMPORTCONTROLLER_H

View file

@ -832,6 +832,7 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
auto authData = serverConfig.value(configKey::authData).toObject(); auto authData = serverConfig.value(configKey::authData).toObject();
QJsonObject newServerConfig; QJsonObject newServerConfig;
ErrorCode errorCode = apiController.getConfigForService( ErrorCode errorCode = apiController.getConfigForService(
m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(), m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(),
apiConfig.value(configKey::serviceType).toString(), apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode, apiConfig.value(configKey::serviceType).toString(), apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode,

View file

@ -33,6 +33,8 @@ namespace PageLoader
PageSettingsAppSplitTunneling, PageSettingsAppSplitTunneling,
PageSettingsApiServerInfo, PageSettingsApiServerInfo,
PageSettingsApiAvailableCountries, PageSettingsApiAvailableCountries,
PageSettingsApiSupport,
PageSettingsApiInstructions,
PageServiceSftpSettings, PageServiceSftpSettings,
PageServiceTorWebsiteSettings, PageServiceTorWebsiteSettings,
@ -55,7 +57,7 @@ namespace PageLoader
PageProtocolOpenVpnSettings, PageProtocolOpenVpnSettings,
PageProtocolShadowSocksSettings, PageProtocolShadowSocksSettings,
PageProtocolCloakSettings, PageProtocolCloakSettings,
PageProtocolXraySettings, PageProtocolXraySettings,
PageProtocolWireGuardSettings, PageProtocolWireGuardSettings,
PageProtocolAwgSettings, PageProtocolAwgSettings,
PageProtocolIKev2Settings, PageProtocolIKev2Settings,
@ -106,7 +108,7 @@ public slots:
int incrementDrawerDepth(); int incrementDrawerDepth();
int decrementDrawerDepth(); int decrementDrawerDepth();
private slots: private slots:
void onShowErrorMessage(amnezia::ErrorCode errorCode); void onShowErrorMessage(amnezia::ErrorCode errorCode);
signals: signals:

View file

@ -0,0 +1,105 @@
#include "apiAccountInfoModel.h"
#include <QJsonObject>
#include "core/api/apiUtils.h"
#include "logger.h"
namespace
{
Logger logger("AccountInfoModel");
namespace configKey
{
constexpr char availableCountries[] = "available_countries";
constexpr char serverCountryCode[] = "server_country_code";
constexpr char serverCountryName[] = "server_country_name";
constexpr char lastUpdated[] = "last_updated";
constexpr char activeDeviceCount[] = "active_device_count";
constexpr char maxDeviceCount[] = "max_device_count";
constexpr char subscriptionEndDate[] = "subscription_end_date";
}
}
ApiAccountInfoModel::ApiAccountInfoModel(QObject *parent) : QAbstractListModel(parent)
{
}
int ApiAccountInfoModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 1;
}
QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
return QVariant();
switch (role) {
case SubscriptionStatusRole: {
return ApiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate) ? tr("Inactive") : tr("Active");
}
case EndDateRole: {
return QDateTime::fromString(m_accountInfoData.subscriptionEndDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy");
}
case ConnectedDevicesRole: {
return tr("%1 out of %2").arg(m_accountInfoData.activeDeviceCount).arg(m_accountInfoData.maxDeviceCount);
}
// case ServiceDescriptionRole: {
// return apiServiceData.serviceInfo.name;
// }
}
return QVariant();
}
void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, const QJsonObject &serverConfig)
{
beginResetModel();
AccountInfoData accountInfoData;
auto availableCountries = accountInfoObject.value(configKey::availableCountries).toArray();
for (const auto &country : availableCountries) {
auto countryObject = country.toObject();
CountryInfo countryInfo;
countryInfo.serverCountryCode = countryObject.value(configKey::serverCountryCode).toString();
countryInfo.serverCountryName = countryObject.value(configKey::serverCountryName).toString();
countryInfo.lastUpdated = countryObject.value(configKey::lastUpdated).toString();
accountInfoData.AvailableCountries.push_back(countryInfo);
}
accountInfoData.activeDeviceCount = accountInfoObject.value(configKey::activeDeviceCount).toInt();
accountInfoData.maxDeviceCount = accountInfoObject.value(configKey::maxDeviceCount).toInt();
accountInfoData.subscriptionEndDate = accountInfoObject.value(configKey::subscriptionEndDate).toString();
m_accountInfoData = accountInfoData;
endResetModel();
}
QVariant ApiAccountInfoModel::data(const QString &roleString)
{
QModelIndex modelIndex = index(0);
auto roles = roleNames();
for (auto it = roles.begin(); it != roles.end(); it++) {
if (QString(it.value()) == roleString) {
return data(modelIndex, it.key());
}
}
return {};
}
QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[SubscriptionStatusRole] = "subscriptionStatus";
roles[EndDateRole] = "endDate";
roles[ConnectedDevicesRole] = "connectedDevices";
roles[ServiceDescriptionRole] = "serviceDescription";
return roles;
}

View file

@ -0,0 +1,55 @@
#ifndef APIACCOUNTINFOMODEL_H
#define APIACCOUNTINFOMODEL_H
#include <QAbstractListModel>
#include <QJsonArray>
#include <QJsonObject>
class ApiAccountInfoModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
SubscriptionStatusRole = Qt::UserRole + 1,
ConnectedDevicesRole,
ServiceDescriptionRole,
EndDateRole
};
explicit ApiAccountInfoModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
public slots:
void updateModel(const QJsonObject &accountInfoObject, const QJsonObject &serverConfig);
QVariant data(const QString &roleString);
protected:
QHash<int, QByteArray> roleNames() const override;
private:
struct CountryInfo
{
QString serverCountryCode;
QString serverCountryName;
QString lastUpdated;
};
struct AccountInfoData
{
QString subscriptionEndDate;
int activeDeviceCount;
int maxDeviceCount;
QString vpnKey;
QVector<CountryInfo> AvailableCountries;
};
AccountInfoData m_accountInfoData;
};
#endif // APIACCOUNTINFOMODEL_H

View file

@ -112,9 +112,10 @@ ListView {
ServersModel.processedIndex = index ServersModel.processedIndex = index
if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) { if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
ApiSettingsController.getAccountInfo()
if (ServersModel.getProcessedServerData("isCountrySelectionAvailable")) { if (ServersModel.getProcessedServerData("isCountrySelectionAvailable")) {
PageController.goToPage(PageEnum.PageSettingsApiAvailableCountries) PageController.goToPage(PageEnum.PageSettingsApiAvailableCountries)
} else { } else {
PageController.goToPage(PageEnum.PageSettingsApiServerInfo) PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
} }

View file

@ -0,0 +1,38 @@
import QtQuick
import QtQuick.Controls
ListView {
id: root
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
clip: true
reuseItems: true
snapMode: ListView.SnapToItem
}

View file

@ -299,9 +299,10 @@ PageType {
ServersModel.processedIndex = ServersModel.defaultIndex ServersModel.processedIndex = ServersModel.defaultIndex
if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) { if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
ApiSettingsController.getAccountInfo()
if (ServersModel.getProcessedServerData("isCountrySelectionAvailable")) { if (ServersModel.getProcessedServerData("isCountrySelectionAvailable")) {
PageController.goToPage(PageEnum.PageSettingsApiAvailableCountries) PageController.goToPage(PageEnum.PageSettingsApiAvailableCountries)
} else { } else {
PageController.goToPage(PageEnum.PageSettingsApiServerInfo) PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
} }

View file

@ -47,8 +47,7 @@ PageType {
readonly property string description: qsTr("For reviews and bug reports") readonly property string description: qsTr("For reviews and bug reports")
readonly property string imageSource: "qrc:/images/controls/mail.svg" readonly property string imageSource: "qrc:/images/controls/mail.svg"
readonly property var handler: function() { readonly property var handler: function() {
GC.copyToClipBoard(title) Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
PageController.showNotificationMessage(qsTr("Copied"))
} }
} }

View file

@ -0,0 +1,87 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
QtObject {
id: windows
readonly property string title: qsTr("Windows")
readonly property string imageSource: "qrc:/images/controls/external-link.svg"
readonly property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
QtObject {
id: linux
readonly property string title: qsTr("Windows")
readonly property string imageSource: "qrc:/images/controls/external-link.svg"
readonly property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
property list<QtObject> instructionsModel: [
windows,
linux
]
ListViewType {
id: listView
anchors.fill: parent
model: instructionsModel
header: ColumnLayout {
width: listView.width
BackButtonType {
id: backButton
}
HeaderType {
id: header
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: "Support"
descriptionText: qsTr("Our technical support specialists are ready to help you at any time")
}
}
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType {
id: telegramButton
Layout.fillWidth: true
Layout.topMargin: 6
text: title
leftImageSource: imageSource
clickedFunction: handler
}
DividerType {}
}
}
}

View file

@ -18,28 +18,19 @@ PageType {
id: root id: root
property list<QtObject> labelsModel: [ property list<QtObject> labelsModel: [
regionObject, statusObject,
priceObject,
endDateObject, endDateObject,
speedObject deviceCountObject
] ]
QtObject { QtObject {
id: regionObject id: statusObject
readonly property string title: qsTr("For the region") readonly property string title: qsTr("Subscription status")
readonly property string contentKey: "region" readonly property string contentKey: "subscriptionStatus"
readonly property string objectImageSource: "qrc:/images/controls/map-pin.svg" readonly property string objectImageSource: "qrc:/images/controls/map-pin.svg"
} }
QtObject {
id: priceObject
readonly property string title: qsTr("Price")
readonly property string contentKey: "price"
readonly property string objectImageSource: "qrc:/images/controls/tag.svg"
}
QtObject { QtObject {
id: endDateObject id: endDateObject
@ -49,10 +40,10 @@ PageType {
} }
QtObject { QtObject {
id: speedObject id: deviceCountObject
readonly property string title: qsTr("Speed") readonly property string title: qsTr("Connected devices")
readonly property string contentKey: "speed" readonly property string contentKey: "connectedDevices"
readonly property string objectImageSource: "qrc:/images/controls/gauge.svg" readonly property string objectImageSource: "qrc:/images/controls/gauge.svg"
} }
@ -83,43 +74,11 @@ PageType {
} }
} }
ListView { ListViewType {
id: listView id: listView
property bool isFocusable: true
anchors.fill: parent anchors.fill: parent
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
clip: true
reuseItems: true
snapMode: ListView.SnapToItem
model: labelsModel model: labelsModel
header: ColumnLayout { header: ColumnLayout {
@ -175,7 +134,7 @@ PageType {
imageSource: objectImageSource imageSource: objectImageSource
leftText: title leftText: title
rightText: ApiServicesModel.getSelectedServiceData(contentKey) rightText: ApiAccountInfoModel.data(contentKey)
visible: rightText !== "" visible: rightText !== ""
} }
@ -185,53 +144,61 @@ PageType {
width: listView.width width: listView.width
spacing: 0 spacing: 0
ParagraphTextType {
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
textFormat: Text.RichText
text: {
var text = ApiServicesModel.getSelectedServiceData("features")
if (text === undefined) {
return ""
}
return text.replace("%1", LanguageModel.getCurrentSiteUrl())
}
visible: text !== ""
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
LabelWithButtonType { LabelWithButtonType {
id: supportUuid
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32
text: qsTr("Support tag") visible: false
descriptionText: SettingsController.getInstallationUuid()
descriptionOnTop: true text: qsTr("Subscription key")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Configuration files")
descriptionText: qsTr("To connect the router")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Support")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsApiSupport)
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("How to connect on another devicey")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsApiInstructions)
}
}
DividerType {}
BasicButtonType { BasicButtonType {
id: resetButton id: resetButton
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter

View file

@ -0,0 +1,107 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType {
id: backButton
}
HeaderType {
id: header
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: "Support"
descriptionText: qsTr("Our technical support specialists are ready to help you at any time")
}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Telegram")
descriptionText: qsTr("@amnezia_premium_support_bot")
rightImageSource: "qrc:/images/controls/external-link.svg"
clickedFunction: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_premium_support_bot"))
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Mail")
descriptionText: qsTr("support@amnezia.org")
rightImageSource: "qrc:/images/controls/external-link.svg"
clickedFunction: function() {
Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Site")
descriptionText: qsTr("amnezia.org")
rightImageSource: "qrc:/images/controls/external-link.svg"
clickedFunction: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
DividerType {}
LabelWithButtonType {
id: supportUuid
Layout.fillWidth: true
text: qsTr("Support tag")
descriptionText: SettingsController.getInstallationUuid()
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
}
}

View file

@ -36,16 +36,6 @@ PageType {
PageController.showErrorMessage(message) PageController.showErrorMessage(message)
} }
function onRemoveProcessedServerFinished(finishedMessage) {
if (!ServersModel.getServersCount()) {
PageController.goToPageHome()
} else {
PageController.goToStartPage()
PageController.goToPage(PageEnum.PageSettingsServersList)
}
PageController.showNotificationMessage(finishedMessage)
}
function onRebootProcessedServerFinished(finishedMessage) { function onRebootProcessedServerFinished(finishedMessage) {
PageController.showNotificationMessage(finishedMessage) PageController.showNotificationMessage(finishedMessage)
} }

View file

@ -95,12 +95,9 @@ PageType {
ServersModel.processedIndex = index ServersModel.processedIndex = index
if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) { if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
if (ServersModel.getProcessedServerData("isCountrySelectionAvailable")) { ApiSettingsController.getAccountInfo()
PageController.goToPage(PageEnum.PageSettingsApiAvailableCountries)
} else { PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
}
} else { } else {
PageController.goToPage(PageEnum.PageSettingsServerInfo) PageController.goToPage(PageEnum.PageSettingsServerInfo)
} }

View file

@ -154,6 +154,16 @@ PageType {
PageController.goToPageHome() PageController.goToPageHome()
PageController.showNotificationMessage(message) PageController.showNotificationMessage(message)
} }
function onRemoveProcessedServerFinished(finishedMessage) {
if (!ServersModel.getServersCount()) {
PageController.goToPageHome()
} else {
PageController.goToStartPage()
PageController.goToPage(PageEnum.PageSettingsServersList)
}
PageController.showNotificationMessage(finishedMessage)
}
} }
Connections { Connections {