New start page and AmneziaFree support (#865)
New start page and AmneziaFree support
This commit is contained in:
parent
01413e5a4c
commit
843156cf1b
443 changed files with 11759 additions and 2758 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include <QtConcurrent>
|
||||
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "core/enums/apiEnums.h"
|
||||
#include "version.h"
|
||||
|
||||
ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel,
|
||||
|
|
@ -16,7 +17,6 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
|
|||
const QSharedPointer<VpnConnection> &vpnConnection, const std::shared_ptr<Settings> &settings,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_apiController(this),
|
||||
m_serversModel(serversModel),
|
||||
m_containersModel(containersModel),
|
||||
m_clientManagementModel(clientManagementModel),
|
||||
|
|
@ -27,9 +27,7 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
|
|||
connect(this, &ConnectionController::connectToVpn, m_vpnConnection.get(), &VpnConnection::connectToVpn, Qt::QueuedConnection);
|
||||
connect(this, &ConnectionController::disconnectFromVpn, m_vpnConnection.get(), &VpnConnection::disconnectFromVpn, Qt::QueuedConnection);
|
||||
|
||||
connect(&m_apiController, &ApiController::configUpdated, this,
|
||||
static_cast<void (ConnectionController::*)(const bool, const QJsonObject &, const int)>(&ConnectionController::openConnection));
|
||||
connect(&m_apiController, qOverload<ErrorCode>(&ApiController::errorOccurred), this, qOverload<ErrorCode>(&ConnectionController::connectionErrorOccurred));
|
||||
connect(this, &ConnectionController::configFromApiUpdated, this, &ConnectionController::continueConnection);
|
||||
|
||||
m_state = Vpn::ConnectionState::Disconnected;
|
||||
}
|
||||
|
|
@ -46,14 +44,22 @@ void ConnectionController::openConnection()
|
|||
|
||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto configVersion = serverConfig.value(config_key::configVersion).toInt();
|
||||
|
||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
|
||||
|
||||
if (serverConfig.value(config_key::configVersion).toInt()
|
||||
if (configVersion == ApiConfigSources::Telegram
|
||||
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||
m_apiController.updateServerConfigFromApi(m_settings->getInstallationUuid(true), serverIndex, serverConfig);
|
||||
emit updateApiConfigFromTelegram();
|
||||
} else if (configVersion && m_serversModel->isApiKeyExpired(serverIndex)) {
|
||||
qDebug() << "attempt to update api config by end_date event";
|
||||
if (configVersion == ApiConfigSources::Telegram) {
|
||||
emit updateApiConfigFromTelegram();
|
||||
} else {
|
||||
emit updateApiConfigFromGateway();
|
||||
}
|
||||
} else {
|
||||
openConnection(false, serverConfig, serverIndex);
|
||||
continueConnection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,12 +191,11 @@ bool ConnectionController::isProtocolConfigExists(const QJsonObject &containerCo
|
|||
return true;
|
||||
}
|
||||
|
||||
void ConnectionController::openConnection(const bool updateConfig, const QJsonObject &config, const int serverIndex)
|
||||
void ConnectionController::continueConnection()
|
||||
{
|
||||
// Update config for this server as it was received from API
|
||||
if (updateConfig) {
|
||||
m_serversModel->editServer(config, serverIndex);
|
||||
}
|
||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto configVersion = serverConfig.value(config_key::configVersion).toInt();
|
||||
|
||||
if (!m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||
emit noInstalledContainers();
|
||||
|
|
@ -223,7 +228,7 @@ void ConnectionController::openConnection(const bool updateConfig, const QJsonOb
|
|||
|
||||
auto dns = m_serversModel->getDnsPair(serverIndex);
|
||||
|
||||
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, config, containerConfig, container, errorCode);
|
||||
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, serverConfig, containerConfig, container, errorCode);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit connectionErrorOccurred(tr("unable to create configuration"));
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef CONNECTIONCONTROLLER_H
|
||||
#define CONNECTIONCONTROLLER_H
|
||||
|
||||
#include "core/controllers/apiController.h"
|
||||
#include "protocols/vpnprotocol.h"
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
|
|
@ -58,13 +57,15 @@ signals:
|
|||
void connectButtonClicked();
|
||||
void preparingConfig();
|
||||
|
||||
void updateApiConfigFromGateway();
|
||||
void updateApiConfigFromTelegram();
|
||||
void configFromApiUpdated();
|
||||
|
||||
private:
|
||||
Vpn::ConnectionState getCurrentConnectionState();
|
||||
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
|
||||
|
||||
void openConnection(const bool updateConfig, const QJsonObject &config, const int serverIndex);
|
||||
|
||||
ApiController m_apiController;
|
||||
void continueConnection();
|
||||
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ ErrorCode ExportController::generateNativeConfig(const DockerContainer container
|
|||
int serverIndex = m_serversModel->getProcessedServerIndex();
|
||||
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
|
||||
auto dns = m_serversModel->getDnsPair(serverIndex);
|
||||
bool isApiConfig = qvariant_cast<bool>(m_serversModel->data(serverIndex, ServersModel::IsServerFromApiRole));
|
||||
bool isApiConfig = qvariant_cast<bool>(m_serversModel->data(serverIndex, ServersModel::IsServerFromTelegramApiRole));
|
||||
|
||||
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
|
||||
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <QRandomGenerator>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "core/controllers/apiController.h"
|
||||
#include "core/controllers/serverController.h"
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "core/networkUtilities.h"
|
||||
|
|
@ -15,14 +16,24 @@
|
|||
#include "ui/models/protocols/wireguardConfigModel.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include <AmneziaVPN-Swift.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
Logger logger("ServerController");
|
||||
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceProtocol[] = "service_protocol";
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
constexpr char serverCountryName[] = "server_country_name";
|
||||
constexpr char availableCountries[] = "available_countries";
|
||||
|
||||
constexpr char apiConfig[] = "api_config";
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
QString getNextDriverLetter()
|
||||
{
|
||||
|
|
@ -52,12 +63,14 @@ namespace
|
|||
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<ProtocolsModel> &protocolsModel,
|
||||
const QSharedPointer<ClientManagementModel> &clientManagementModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
const QSharedPointer<ApiServicesModel> &apiServicesModel, const std::shared_ptr<Settings> &settings,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_serversModel(serversModel),
|
||||
m_containersModel(containersModel),
|
||||
m_protocolModel(protocolsModel),
|
||||
m_clientManagementModel(clientManagementModel),
|
||||
m_apiServicesModel(apiServicesModel),
|
||||
m_settings(settings)
|
||||
{
|
||||
}
|
||||
|
|
@ -432,7 +445,7 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
|||
containerConfig.insert(config_key::password, password);
|
||||
} else if (protocol == Proto::Socks5Proxy) {
|
||||
QString proxyConfig = serverController->getTextFileFromContainer(container, credentials,
|
||||
protocols::socks5Proxy::proxyConfigPath, errorCode);
|
||||
protocols::socks5Proxy::proxyConfigPath, errorCode);
|
||||
|
||||
const static QRegularExpression usernameAndPasswordRegExp("users (\\w+):CL:(\\w+)");
|
||||
QRegularExpressionMatch usernameAndPasswordMatch = usernameAndPasswordRegExp.match(proxyConfig);
|
||||
|
|
@ -591,25 +604,8 @@ void InstallController::removeProcessedContainer()
|
|||
|
||||
void InstallController::removeApiConfig(const int serverIndex)
|
||||
{
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
QString vpncName = QString("%1 (%2) %3")
|
||||
.arg(serverConfig[config_key::description].toString())
|
||||
.arg(serverConfig[config_key::hostName].toString())
|
||||
.arg(serverConfig[config_key::vpnproto].toString());
|
||||
|
||||
AmneziaVPN::removeVPNC(vpncName.toStdString());
|
||||
#endif
|
||||
|
||||
serverConfig.remove(config_key::dns1);
|
||||
serverConfig.remove(config_key::dns2);
|
||||
serverConfig.remove(config_key::containers);
|
||||
serverConfig.remove(config_key::hostName);
|
||||
|
||||
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
|
||||
|
||||
m_serversModel->editServer(serverConfig, serverIndex);
|
||||
m_serversModel->removeApiConfig(serverIndex);
|
||||
emit apiConfigRemoved(tr("Api config removed"));
|
||||
}
|
||||
|
||||
void InstallController::clearCachedProfile(QSharedPointer<ServerController> serverController)
|
||||
|
|
@ -801,6 +797,110 @@ void InstallController::addEmptyServer()
|
|||
emit installServerFinished(tr("Server added successfully"));
|
||||
}
|
||||
|
||||
bool InstallController::fillAvailableServices()
|
||||
{
|
||||
ApiController apiController(m_settings->getGatewayEndpoint());
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = apiController.getServicesList(responseBody);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject data = QJsonDocument::fromJson(responseBody).object();
|
||||
m_apiServicesModel->updateModel(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InstallController::installServiceFromApi()
|
||||
{
|
||||
if (m_serversModel->isServerFromApiAlreadyExists(m_apiServicesModel->getCountryCode(), m_apiServicesModel->getSelectedServiceType(),
|
||||
m_apiServicesModel->getSelectedServiceProtocol())) {
|
||||
emit installationErrorOccurred(ErrorCode::ApiConfigAlreadyAdded);
|
||||
return false;
|
||||
}
|
||||
|
||||
ApiController apiController(m_settings->getGatewayEndpoint());
|
||||
QJsonObject serverConfig;
|
||||
|
||||
ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(),
|
||||
m_apiServicesModel->getSelectedServiceType(),
|
||||
m_apiServicesModel->getSelectedServiceProtocol(), "", serverConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto serviceInfo = m_apiServicesModel->getSelectedServiceInfo();
|
||||
QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
apiConfig.insert(configKey::serviceInfo, serviceInfo);
|
||||
apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode());
|
||||
apiConfig.insert(configKey::serviceType, m_apiServicesModel->getSelectedServiceType());
|
||||
apiConfig.insert(configKey::serviceProtocol, m_apiServicesModel->getSelectedServiceProtocol());
|
||||
|
||||
serverConfig.insert(configKey::apiConfig, apiConfig);
|
||||
|
||||
m_serversModel->addServer(serverConfig);
|
||||
emit installServerFromApiFinished(tr("%1 installed successfully.").arg(m_apiServicesModel->getSelectedServiceName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InstallController::updateServiceFromApi(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
||||
bool reloadServiceConfig)
|
||||
{
|
||||
ApiController apiController(m_settings->getGatewayEndpoint());
|
||||
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
|
||||
QJsonObject newServerConfig;
|
||||
ErrorCode errorCode =
|
||||
apiController.getConfigForService(m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(),
|
||||
apiConfig.value(configKey::serviceType).toString(),
|
||||
apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode, newServerConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
|
||||
newApiConfig.insert(configKey::serviceInfo, apiConfig.value(configKey::serviceInfo));
|
||||
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
|
||||
newApiConfig.insert(configKey::serviceType, apiConfig.value(configKey::serviceType));
|
||||
newApiConfig.insert(configKey::serviceProtocol, apiConfig.value(configKey::serviceProtocol));
|
||||
|
||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||
m_serversModel->editServer(newServerConfig, serverIndex);
|
||||
|
||||
if (reloadServiceConfig) {
|
||||
emit reloadServerFromApiFinished(tr("API config reloaded"));
|
||||
} else if (newCountryName.isEmpty()) {
|
||||
emit updateServerFromApiFinished();
|
||||
} else {
|
||||
emit changeApiCountryFinished(tr("Successfully changed the country of connection to %1").arg(newCountryName));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstallController::updateServiceFromTelegram(const int serverIndex)
|
||||
{
|
||||
ApiController *apiController = new ApiController(m_settings->getGatewayEndpoint());
|
||||
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
|
||||
apiController->updateServerConfigFromApi(m_settings->getInstallationUuid(true), serverIndex, serverConfig);
|
||||
connect(apiController, &ApiController::finished, this, [this, apiController](const QJsonObject &config, const int serverIndex) {
|
||||
m_serversModel->editServer(config, serverIndex);
|
||||
emit updateServerFromApiFinished();
|
||||
apiController->deleteLater();
|
||||
});
|
||||
connect(apiController, &ApiController::errorOccurred, this, [this, apiController](ErrorCode errorCode) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
apiController->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
bool InstallController::isUpdateDockerContainerRequired(const DockerContainer container, const QJsonObject &oldConfig,
|
||||
const QJsonObject &newConfig)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/protocols_model.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
#include "ui/models/apiServicesModel.h"
|
||||
|
||||
class InstallController : public QObject
|
||||
{
|
||||
|
|
@ -18,6 +19,7 @@ public:
|
|||
explicit InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<ProtocolsModel> &protocolsModel,
|
||||
const QSharedPointer<ClientManagementModel> &clientManagementModel,
|
||||
const QSharedPointer<ApiServicesModel> &apiServicesModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
|
||||
~InstallController();
|
||||
|
||||
|
|
@ -50,11 +52,21 @@ public slots:
|
|||
|
||||
void addEmptyServer();
|
||||
|
||||
bool fillAvailableServices();
|
||||
bool installServiceFromApi();
|
||||
bool updateServiceFromApi(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, bool reloadServiceConfig = false);
|
||||
|
||||
void updateServiceFromTelegram(const int serverIndex);
|
||||
|
||||
signals:
|
||||
void installContainerFinished(const QString &finishMessage, bool isServiceInstall);
|
||||
void installServerFinished(const QString &finishMessage);
|
||||
void installServerFromApiFinished(const QString &message);
|
||||
|
||||
void updateContainerFinished(const QString &message);
|
||||
void updateServerFromApiFinished();
|
||||
void changeApiCountryFinished(const QString &message);
|
||||
void reloadServerFromApiFinished(const QString &message);
|
||||
|
||||
void scanServerFinished(bool isInstalledContainerFound);
|
||||
|
||||
|
|
@ -77,6 +89,7 @@ signals:
|
|||
void currentContainerUpdated();
|
||||
|
||||
void cachedProfileCleared(const QString &message);
|
||||
void apiConfigRemoved(const QString &message);
|
||||
|
||||
private:
|
||||
void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
|
||||
|
|
@ -95,6 +108,8 @@ private:
|
|||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
QSharedPointer<ProtocolsModel> m_protocolModel;
|
||||
QSharedPointer<ClientManagementModel> m_clientManagementModel;
|
||||
QSharedPointer<ApiServicesModel> m_apiServicesModel;
|
||||
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
ServerCredentials m_processedServerCredentials;
|
||||
|
|
|
|||
|
|
@ -46,16 +46,16 @@ PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
|
|||
m_isTriggeredByConnectButton = false;
|
||||
}
|
||||
|
||||
QString PageController::getInitialPage()
|
||||
bool PageController::isStartPageVisible()
|
||||
{
|
||||
if (m_serversModel->getServersCount()) {
|
||||
if (m_serversModel->getDefaultServerIndex() < 0) {
|
||||
auto defaultServerIndex = m_serversModel->index(0);
|
||||
m_serversModel->setData(defaultServerIndex, true, ServersModel::Roles::IsDefaultRole);
|
||||
}
|
||||
return getPagePath(PageLoader::PageEnum::PageStart);
|
||||
return false;
|
||||
} else {
|
||||
return getPagePath(PageLoader::PageEnum::PageSetupWizardStart);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ namespace PageLoader
|
|||
PageSetupWizardTextKey,
|
||||
PageSetupWizardViewConfig,
|
||||
PageSetupWizardQrReader,
|
||||
PageSetupWizardApiServicesList,
|
||||
PageSetupWizardApiServiceInfo,
|
||||
|
||||
PageProtocolOpenVpnSettings,
|
||||
PageProtocolShadowSocksSettings,
|
||||
|
|
@ -57,7 +59,9 @@ namespace PageLoader
|
|||
PageProtocolIKev2Settings,
|
||||
PageProtocolRaw,
|
||||
|
||||
PageShareFullAccess
|
||||
PageShareFullAccess,
|
||||
|
||||
PageDevMenu
|
||||
};
|
||||
Q_ENUM_NS(PageEnum)
|
||||
|
||||
|
|
@ -75,7 +79,7 @@ public:
|
|||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
QString getInitialPage();
|
||||
bool isStartPageVisible();
|
||||
QString getPagePath(PageLoader::PageEnum page);
|
||||
|
||||
void closeWindow();
|
||||
|
|
@ -110,7 +114,6 @@ signals:
|
|||
void closePage();
|
||||
|
||||
void restorePageHomeState(bool isContainerInstalled = false);
|
||||
void replaceStartPage();
|
||||
|
||||
void showErrorMessage(amnezia::ErrorCode);
|
||||
void showErrorMessage(const QString &errorMessage);
|
||||
|
|
|
|||
|
|
@ -252,3 +252,36 @@ void SettingsController::requestNotificationPermission()
|
|||
AndroidController::instance()->requestNotificationPermission();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString SettingsController::getInstallationUuid()
|
||||
{
|
||||
return m_settings->getInstallationUuid(false);
|
||||
}
|
||||
|
||||
void SettingsController::enableDevMode()
|
||||
{
|
||||
m_isDevModeEnabled = true;
|
||||
emit devModeEnabled();
|
||||
}
|
||||
|
||||
bool SettingsController::isDevModeEnabled()
|
||||
{
|
||||
return m_isDevModeEnabled;
|
||||
}
|
||||
|
||||
void SettingsController::resetGatewayEndpoint()
|
||||
{
|
||||
m_settings->resetGatewayEndpoint();
|
||||
emit gatewayEndpointChanged(m_settings->getGatewayEndpoint());
|
||||
}
|
||||
|
||||
void SettingsController::setGatewayEndpoint(const QString &endpoint)
|
||||
{
|
||||
m_settings->setGatewayEndpoint(endpoint);
|
||||
emit gatewayEndpointChanged(endpoint);
|
||||
}
|
||||
|
||||
QString SettingsController::getGatewayEndpoint()
|
||||
{
|
||||
return m_settings->getGatewayEndpoint();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ public:
|
|||
Q_PROPERTY(bool isLoggingEnabled READ isLoggingEnabled WRITE toggleLogging NOTIFY loggingStateChanged)
|
||||
Q_PROPERTY(bool isNotificationPermissionGranted READ isNotificationPermissionGranted NOTIFY onNotificationStateChanged)
|
||||
|
||||
Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled)
|
||||
Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged)
|
||||
|
||||
public slots:
|
||||
void toggleAmneziaDns(bool enable);
|
||||
bool isAmneziaDnsEnabled();
|
||||
|
|
@ -70,6 +73,15 @@ public slots:
|
|||
bool isNotificationPermissionGranted();
|
||||
void requestNotificationPermission();
|
||||
|
||||
QString getInstallationUuid();
|
||||
|
||||
void enableDevMode();
|
||||
bool isDevModeEnabled();
|
||||
|
||||
void resetGatewayEndpoint();
|
||||
void setGatewayEndpoint(const QString &endpoint);
|
||||
QString getGatewayEndpoint();
|
||||
|
||||
signals:
|
||||
void primaryDnsChanged();
|
||||
void secondaryDnsChanged();
|
||||
|
|
@ -89,6 +101,9 @@ signals:
|
|||
|
||||
void onNotificationStateChanged();
|
||||
|
||||
void devModeEnabled();
|
||||
void gatewayEndpointChanged(const QString &endpoint);
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
|
|
@ -101,6 +116,8 @@ private:
|
|||
|
||||
QDateTime m_loggingDisableDate;
|
||||
|
||||
bool m_isDevModeEnabled = false;
|
||||
|
||||
void checkIfNeedDisableLogs();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#ifndef Q_OS_IOS
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
#include <QWidget>
|
||||
|
||||
void setDockIconVisible(bool visible);
|
||||
void fixWidget(QWidget *widget);
|
||||
|
|
|
|||
80
client/ui/models/apiCountryModel.cpp
Normal file
80
client/ui/models/apiCountryModel.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#include "apiCountryModel.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
Logger logger("ApiCountryModel");
|
||||
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
constexpr char serverCountryName[] = "server_country_name";
|
||||
}
|
||||
}
|
||||
|
||||
ApiCountryModel::ApiCountryModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int ApiCountryModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_countries.size();
|
||||
}
|
||||
|
||||
QVariant ApiCountryModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
|
||||
return QVariant();
|
||||
|
||||
QJsonObject countryInfo = m_countries.at(index.row()).toObject();
|
||||
|
||||
switch (role) {
|
||||
case CountryCodeRole: {
|
||||
return countryInfo.value(configKey::serverCountryCode).toString();
|
||||
}
|
||||
case CountryNameRole: {
|
||||
return countryInfo.value(configKey::serverCountryName).toString();
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ApiCountryModel::updateModel(const QJsonArray &data, const QString ¤tCountryCode)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
m_countries = data;
|
||||
for (int i = 0; i < m_countries.size(); i++) {
|
||||
if (m_countries.at(i).toObject().value(configKey::serverCountryCode).toString() == currentCountryCode) {
|
||||
m_currentIndex = i;
|
||||
emit currentIndexChanged(m_currentIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int ApiCountryModel::getCurrentIndex()
|
||||
{
|
||||
return m_currentIndex;
|
||||
}
|
||||
|
||||
void ApiCountryModel::setCurrentIndex(const int i)
|
||||
{
|
||||
m_currentIndex = i;
|
||||
emit currentIndexChanged(m_currentIndex);
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ApiCountryModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[CountryNameRole] = "countryName";
|
||||
roles[CountryCodeRole] = "countryCode";
|
||||
return roles;
|
||||
}
|
||||
42
client/ui/models/apiCountryModel.h
Normal file
42
client/ui/models/apiCountryModel.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef APICOUNTRYMODEL_H
|
||||
#define APICOUNTRYMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonArray>
|
||||
|
||||
class ApiCountryModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
CountryNameRole = Qt::UserRole + 1,
|
||||
CountryCodeRole
|
||||
};
|
||||
|
||||
explicit ApiCountryModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
Q_PROPERTY(int currentIndex READ getCurrentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
|
||||
|
||||
public slots:
|
||||
void updateModel(const QJsonArray &data, const QString ¤tCountryCode);
|
||||
|
||||
int getCurrentIndex();
|
||||
void setCurrentIndex(const int i);
|
||||
|
||||
signals:
|
||||
void currentIndexChanged(const int index);
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
QJsonArray m_countries;
|
||||
int m_currentIndex;
|
||||
};
|
||||
|
||||
#endif // APICOUNTRYMODEL_H
|
||||
203
client/ui/models/apiServicesModel.cpp
Normal file
203
client/ui/models/apiServicesModel.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
#include "apiServicesModel.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
Logger logger("ApiServicesModel");
|
||||
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
constexpr char services[] = "services";
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceProtocol[] = "service_protocol";
|
||||
|
||||
constexpr char name[] = "name";
|
||||
constexpr char price[] = "price";
|
||||
constexpr char speed[] = "speed";
|
||||
constexpr char timelimit[] = "timelimit";
|
||||
constexpr char region[] = "region";
|
||||
|
||||
constexpr char availableCountries[] = "available_countries";
|
||||
|
||||
constexpr char storeEndpoint[] = "store_endpoint";
|
||||
}
|
||||
|
||||
namespace serviceType
|
||||
{
|
||||
constexpr char amneziaFree[] = "amnezia-free";
|
||||
constexpr char amneziaPremium[] = "amnezia-premium";
|
||||
}
|
||||
}
|
||||
|
||||
ApiServicesModel::ApiServicesModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int ApiServicesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_services.size();
|
||||
}
|
||||
|
||||
QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
|
||||
return QVariant();
|
||||
|
||||
QJsonObject service = m_services.at(index.row()).toObject();
|
||||
QJsonObject serviceInfo = service.value(configKey::serviceInfo).toObject();
|
||||
auto serviceType = service.value(configKey::serviceType).toString();
|
||||
|
||||
switch (role) {
|
||||
case NameRole: {
|
||||
return serviceInfo.value(configKey::name).toString();
|
||||
}
|
||||
case CardDescriptionRole: {
|
||||
auto speed = serviceInfo.value(configKey::speed).toString();
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return tr("Classic VPN for comfortable work, downloading large files and watching videos. "
|
||||
"Works for any sites. Speed up to %1 MBit/s")
|
||||
.arg(speed);
|
||||
} else {
|
||||
return tr("VPN to access blocked sites in regions with high levels of Internet censorship. ");
|
||||
}
|
||||
}
|
||||
case ServiceDescriptionRole: {
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return tr("Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. "
|
||||
"It works for all websites, even in countries with the highest level of internet censorship.");
|
||||
} else {
|
||||
return tr("Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship");
|
||||
}
|
||||
}
|
||||
case SpeedRole: {
|
||||
auto speed = serviceInfo.value(configKey::speed).toString();
|
||||
return tr("%1 MBit/s").arg(speed);
|
||||
}
|
||||
case WorkPeriodRole: {
|
||||
auto timelimit = serviceInfo.value(configKey::timelimit).toString();
|
||||
if (timelimit == "0") {
|
||||
return "";
|
||||
}
|
||||
return tr("%1 days").arg(timelimit);
|
||||
}
|
||||
case RegionRole: {
|
||||
return serviceInfo.value(configKey::region).toString();
|
||||
}
|
||||
case FeaturesRole: {
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return tr("");
|
||||
} else {
|
||||
return tr("VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. "
|
||||
"Other sites will be opened from your real IP address, "
|
||||
"<a href=\"%1/free\" style=\"color: #FBB26A;\">more details on the website.</a>");
|
||||
}
|
||||
}
|
||||
case PriceRole: {
|
||||
auto price = serviceInfo.value(configKey::price).toString();
|
||||
if (price == "free") {
|
||||
return tr("Free");
|
||||
}
|
||||
return tr("%1 $/month").arg(price);
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ApiServicesModel::updateModel(const QJsonObject &data)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
m_countryCode = data.value(configKey::userCountryCode).toString();
|
||||
m_services = data.value(configKey::services).toArray();
|
||||
if (m_services.isEmpty()) {
|
||||
QJsonObject service;
|
||||
service.insert(configKey::serviceInfo, data.value(configKey::serviceInfo));
|
||||
service.insert(configKey::serviceType, data.value(configKey::serviceType));
|
||||
|
||||
m_services.push_back(service);
|
||||
m_selectedServiceIndex = 0;
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ApiServicesModel::setServiceIndex(const int index)
|
||||
{
|
||||
m_selectedServiceIndex = index;
|
||||
}
|
||||
|
||||
QJsonObject ApiServicesModel::getSelectedServiceInfo()
|
||||
{
|
||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
||||
return service.value(configKey::serviceInfo).toObject();
|
||||
}
|
||||
|
||||
QString ApiServicesModel::getSelectedServiceType()
|
||||
{
|
||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
||||
return service.value(configKey::serviceType).toString();
|
||||
}
|
||||
|
||||
QString ApiServicesModel::getSelectedServiceProtocol()
|
||||
{
|
||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
||||
return service.value(configKey::serviceProtocol).toString();
|
||||
}
|
||||
|
||||
QString ApiServicesModel::getSelectedServiceName()
|
||||
{
|
||||
auto modelIndex = index(m_selectedServiceIndex, 0);
|
||||
return data(modelIndex, ApiServicesModel::Roles::NameRole).toString();
|
||||
}
|
||||
|
||||
QJsonArray ApiServicesModel::getSelectedServiceCountries()
|
||||
{
|
||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
||||
return service.value(configKey::availableCountries).toArray();
|
||||
}
|
||||
|
||||
QString ApiServicesModel::getCountryCode()
|
||||
{
|
||||
return m_countryCode;
|
||||
}
|
||||
|
||||
QString ApiServicesModel::getStoreEndpoint()
|
||||
{
|
||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
||||
return service.value(configKey::storeEndpoint).toString();
|
||||
}
|
||||
|
||||
QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
|
||||
{
|
||||
QModelIndex modelIndex = index(m_selectedServiceIndex);
|
||||
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> ApiServicesModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[NameRole] = "name";
|
||||
roles[CardDescriptionRole] = "cardDescription";
|
||||
roles[ServiceDescriptionRole] = "serviceDescription";
|
||||
roles[SpeedRole] = "speed";
|
||||
roles[WorkPeriodRole] = "workPeriod";
|
||||
roles[RegionRole] = "region";
|
||||
roles[FeaturesRole] = "features";
|
||||
roles[PriceRole] = "price";
|
||||
|
||||
return roles;
|
||||
}
|
||||
56
client/ui/models/apiServicesModel.h
Normal file
56
client/ui/models/apiServicesModel.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef APISERVICESMODEL_H
|
||||
#define APISERVICESMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonArray>
|
||||
|
||||
class ApiServicesModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
NameRole = Qt::UserRole + 1,
|
||||
CardDescriptionRole,
|
||||
ServiceDescriptionRole,
|
||||
SpeedRole,
|
||||
WorkPeriodRole,
|
||||
RegionRole,
|
||||
FeaturesRole,
|
||||
PriceRole
|
||||
};
|
||||
|
||||
explicit ApiServicesModel(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 &data);
|
||||
|
||||
void setServiceIndex(const int index);
|
||||
|
||||
QJsonObject getSelectedServiceInfo();
|
||||
QString getSelectedServiceType();
|
||||
QString getSelectedServiceProtocol();
|
||||
QString getSelectedServiceName();
|
||||
QJsonArray getSelectedServiceCountries();
|
||||
|
||||
QString getCountryCode();
|
||||
|
||||
QString getStoreEndpoint();
|
||||
|
||||
QVariant getSelectedServiceData(const QString roleString);
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
QString m_countryCode;
|
||||
QJsonArray m_services;
|
||||
|
||||
int m_selectedServiceIndex;
|
||||
};
|
||||
|
||||
#endif // APISERVICESMODEL_H
|
||||
|
|
@ -94,6 +94,26 @@ bool ContainersModel::isServiceContainer(const int containerIndex)
|
|||
return qvariant_cast<amnezia::ServiceType>(data(index(containerIndex), ServiceTypeRole) == ServiceType::Other);
|
||||
}
|
||||
|
||||
bool ContainersModel::hasInstalledServices()
|
||||
{
|
||||
for (const auto &container : m_containers.keys()) {
|
||||
if (ContainerProps::containerService(container) == ServiceType::Other) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContainersModel::hasInstalledProtocols()
|
||||
{
|
||||
for (const auto &container : m_containers.keys()) {
|
||||
if (ContainerProps::containerService(container) == ServiceType::Vpn) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ContainersModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ public slots:
|
|||
bool isSupportedByCurrentPlatform(const int containerIndex);
|
||||
bool isServiceContainer(const int containerIndex);
|
||||
|
||||
bool hasInstalledServices();
|
||||
bool hasInstalledProtocols();
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
|
|
|
|||
|
|
@ -103,3 +103,12 @@ QString LanguageModel::getCurrentLanguageName()
|
|||
{
|
||||
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
||||
}
|
||||
|
||||
QString LanguageModel::getCurrentSiteUrl()
|
||||
{
|
||||
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
||||
switch (language) {
|
||||
case LanguageSettings::AvailableLanguageEnum::Russian: return "https://storage.googleapis.com/kldscp/amnezia.org";
|
||||
default: return "https://amnezia.org";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ public slots:
|
|||
int getCurrentLanguageIndex();
|
||||
int getLineHeightAppend();
|
||||
QString getCurrentLanguageName();
|
||||
QString getCurrentSiteUrl();
|
||||
|
||||
signals:
|
||||
void updateTranslations(const QLocale &locale);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,31 @@
|
|||
#include "servers_model.h"
|
||||
|
||||
#include "core/controllers/serverController.h"
|
||||
#include "core/enums/apiEnums.h"
|
||||
#include "core/networkUtilities.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include <AmneziaVPN-Swift.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char apiConfig[] = "api_config";
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
constexpr char availableCountries[] = "available_countries";
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
constexpr char serverCountryName[] = "server_country_name";
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceProtocol[] = "service_protocol";
|
||||
|
||||
constexpr char publicKeyInfo[] = "public_key";
|
||||
constexpr char endDate[] = "end_date";
|
||||
}
|
||||
}
|
||||
|
||||
ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings), QAbstractListModel(parent)
|
||||
{
|
||||
m_isAmneziaDnsEnabled = m_settings->useAmneziaDns();
|
||||
|
|
@ -63,6 +86,7 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
|
|||
}
|
||||
|
||||
const QJsonObject server = m_servers.at(index.row()).toObject();
|
||||
const auto apiConfig = server.value(configKey::apiConfig).toObject();
|
||||
const auto configVersion = server.value(config_key::configVersion).toInt();
|
||||
switch (role) {
|
||||
case NameRole: {
|
||||
|
|
@ -98,8 +122,23 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
|
|||
case HasInstalledContainers: {
|
||||
return serverHasInstalledContainers(index.row());
|
||||
}
|
||||
case IsServerFromApiRole: {
|
||||
return server.value(config_key::configVersion).toInt();
|
||||
case IsServerFromTelegramApiRole: {
|
||||
return server.value(config_key::configVersion).toInt() == ApiConfigSources::Telegram;
|
||||
}
|
||||
case IsServerFromGatewayApiRole: {
|
||||
return server.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway;
|
||||
}
|
||||
case ApiConfigRole: {
|
||||
return apiConfig;
|
||||
}
|
||||
case IsCountrySelectionAvailableRole: {
|
||||
return !apiConfig.value(configKey::availableCountries).toArray().isEmpty();
|
||||
}
|
||||
case ApiAvailableCountriesRole: {
|
||||
return apiConfig.value(configKey::availableCountries).toArray();
|
||||
}
|
||||
case ApiServerCountryCodeRole: {
|
||||
return apiConfig.value(configKey::serverCountryCode).toString();
|
||||
}
|
||||
case HasAmneziaDns: {
|
||||
QString primaryDns = server.value(config_key::dns1).toString();
|
||||
|
|
@ -146,10 +185,13 @@ const QString ServersModel::getDefaultServerName()
|
|||
QString ServersModel::getServerDescription(const QJsonObject &server, const int index) const
|
||||
{
|
||||
const auto configVersion = server.value(config_key::configVersion).toInt();
|
||||
const auto apiConfig = server.value(configKey::apiConfig).toObject();
|
||||
|
||||
QString description;
|
||||
|
||||
if (configVersion) {
|
||||
if (configVersion && !apiConfig.value(configKey::serverCountryCode).toString().isEmpty()) {
|
||||
return apiConfig.value(configKey::serverCountryName).toString();
|
||||
} else if (configVersion) {
|
||||
return server.value(config_key::description).toString();
|
||||
} else if (data(index, HasWriteAccessRole).toBool()) {
|
||||
if (m_isAmneziaDnsEnabled && isAmneziaDnsContainerInstalled(index)) {
|
||||
|
|
@ -208,6 +250,12 @@ void ServersModel::setProcessedServerIndex(const int index)
|
|||
{
|
||||
m_processedServerIndex = index;
|
||||
updateContainersModel();
|
||||
if (data(index, IsServerFromGatewayApiRole).toBool()) {
|
||||
if (data(index, IsCountrySelectionAvailableRole).toBool()) {
|
||||
emit updateApiLanguageModel();
|
||||
}
|
||||
emit updateApiServicesModel();
|
||||
}
|
||||
emit processedServerIndexChanged(m_processedServerIndex);
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +281,8 @@ bool ServersModel::isDefaultServerCurrentlyProcessed()
|
|||
|
||||
bool ServersModel::isDefaultServerFromApi()
|
||||
{
|
||||
return qvariant_cast<bool>(data(m_defaultServerIndex, IsServerFromApiRole));
|
||||
return data(m_defaultServerIndex, IsServerFromTelegramApiRole).toBool()
|
||||
|| data(m_defaultServerIndex, IsServerFromGatewayApiRole).toBool();
|
||||
}
|
||||
|
||||
bool ServersModel::isProcessedServerHasWriteAccess()
|
||||
|
|
@ -315,7 +364,12 @@ QHash<int, QByteArray> ServersModel::roleNames() const
|
|||
roles[DefaultContainerRole] = "defaultContainer";
|
||||
roles[HasInstalledContainers] = "hasInstalledContainers";
|
||||
|
||||
roles[IsServerFromApiRole] = "isServerFromApi";
|
||||
roles[IsServerFromTelegramApiRole] = "isServerFromTelegramApi";
|
||||
roles[IsServerFromGatewayApiRole] = "isServerFromGatewayApi";
|
||||
roles[ApiConfigRole] = "apiConfig";
|
||||
roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable";
|
||||
roles[ApiAvailableCountriesRole] = "apiAvailableCountries";
|
||||
roles[ApiServerCountryCodeRole] = "apiServerCountryCode";
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
|
@ -399,8 +453,7 @@ void ServersModel::addContainerConfig(const int containerIndex, const QJsonObjec
|
|||
|
||||
auto defaultContainer = server.value(config_key::defaultContainer).toString();
|
||||
if (ContainerProps::containerFromString(defaultContainer) == DockerContainer::None
|
||||
&& ContainerProps::containerService(container) != ServiceType::Other
|
||||
&& ContainerProps::isSupportedByCurrentPlatform(container)) {
|
||||
&& ContainerProps::containerService(container) != ServiceType::Other && ContainerProps::isSupportedByCurrentPlatform(container)) {
|
||||
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
|
||||
}
|
||||
|
||||
|
|
@ -565,7 +618,7 @@ void ServersModel::toggleAmneziaDns(bool enabled)
|
|||
|
||||
bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc)
|
||||
{
|
||||
for (const auto &server : qAsConst(m_servers)) {
|
||||
for (const auto &server : std::as_const(m_servers)) {
|
||||
if (static_cast<quint16>(server.toObject().value(config_key::crc).toInt()) == crc) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -573,6 +626,19 @@ bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ServersModel::isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType, const QString &serviceProtocol)
|
||||
{
|
||||
for (const auto &server : std::as_const(m_servers)) {
|
||||
const auto apiConfig = server.toObject().value(configKey::apiConfig).toObject();
|
||||
if (apiConfig.value(configKey::userCountryCode).toString() == userCountryCode
|
||||
&& apiConfig.value(configKey::serviceType).toString() == serviceType
|
||||
&& apiConfig.value(configKey::serviceProtocol).toString() == serviceProtocol) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServersModel::serverHasInstalledContainers(const int serverIndex) const
|
||||
{
|
||||
QJsonObject server = m_servers.at(serverIndex).toObject();
|
||||
|
|
@ -621,14 +687,89 @@ bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
|
|||
auto containers = server.value(config_key::containers).toArray();
|
||||
for (auto i = 0; i < containers.size(); i++) {
|
||||
auto container = containers.at(i).toObject();
|
||||
if (container.value(config_key::container).toString() != ContainerProps::containerToString(defaultContainer)) {
|
||||
continue;
|
||||
}
|
||||
if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
|
||||
auto containerConfig = container.value(ContainerProps::containerTypeToString(defaultContainer)).toObject();
|
||||
return !(containerConfig.value(config_key::last_config).toString().contains("AllowedIPs = 0.0.0.0/0, ::/0"));
|
||||
QJsonObject serverProtocolConfig = container.value(ContainerProps::containerTypeToString(defaultContainer)).toObject();
|
||||
QString clientProtocolConfigString = serverProtocolConfig.value(config_key::last_config).toString();
|
||||
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(clientProtocolConfigString.toUtf8()).object();
|
||||
return (clientProtocolConfigString.contains("AllowedIPs") && !clientProtocolConfigString.contains("AllowedIPs = 0.0.0.0/0, ::/0"))
|
||||
|| (!clientProtocolConfig.value(config_key::allowed_ips).toArray().isEmpty()
|
||||
&& !clientProtocolConfig.value(config_key::allowed_ips).toArray().contains("0.0.0.0/0"));
|
||||
} else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn
|
||||
|| defaultContainer == DockerContainer::ShadowSocks) {
|
||||
auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)).toObject();
|
||||
return !(containerConfig.value(config_key::last_config).toString().contains("redirect-gateway"));
|
||||
auto serverProtocolConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)).toObject();
|
||||
QString clientProtocolConfigString = serverProtocolConfig.value(config_key::last_config).toString();
|
||||
return !clientProtocolConfigString.isEmpty() && !clientProtocolConfigString.contains("redirect-gateway");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServersModel::isServerFromApi(const int serverIndex)
|
||||
{
|
||||
return data(serverIndex, IsServerFromTelegramApiRole).toBool() || data(serverIndex, IsServerFromGatewayApiRole).toBool();
|
||||
}
|
||||
|
||||
bool ServersModel::isApiKeyExpired(const int serverIndex)
|
||||
{
|
||||
auto serverConfig = m_servers.at(serverIndex).toObject();
|
||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
|
||||
auto publicKeyInfo = apiConfig.value(configKey::publicKeyInfo).toObject();
|
||||
const QString endDate = publicKeyInfo.value(configKey::endDate).toString();
|
||||
if (endDate.isEmpty()) {
|
||||
publicKeyInfo.insert(configKey::endDate, QDateTime::currentDateTimeUtc().addDays(1).toString(Qt::ISODate));
|
||||
apiConfig.insert(configKey::publicKeyInfo, publicKeyInfo);
|
||||
serverConfig.insert(configKey::apiConfig, apiConfig);
|
||||
editServer(serverConfig, serverIndex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto endDateDateTime = QDateTime::fromString(endDate, Qt::ISODate).toUTC();
|
||||
if (endDateDateTime < QDateTime::currentDateTimeUtc()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ServersModel::removeApiConfig(const int serverIndex)
|
||||
{
|
||||
auto serverConfig = getServerConfig(serverIndex);
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
QString vpncName = QString("%1 (%2) %3")
|
||||
.arg(serverConfig[config_key::description].toString())
|
||||
.arg(serverConfig[config_key::hostName].toString())
|
||||
.arg(serverConfig[config_key::vpnproto].toString());
|
||||
|
||||
AmneziaVPN::removeVPNC(vpncName.toStdString());
|
||||
#endif
|
||||
|
||||
serverConfig.remove(config_key::dns1);
|
||||
serverConfig.remove(config_key::dns2);
|
||||
serverConfig.remove(config_key::containers);
|
||||
serverConfig.remove(config_key::hostName);
|
||||
|
||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
apiConfig.remove(configKey::publicKeyInfo);
|
||||
serverConfig.insert(configKey::apiConfig, apiConfig);
|
||||
|
||||
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
|
||||
|
||||
editServer(serverConfig, serverIndex);
|
||||
}
|
||||
|
||||
const QString ServersModel::getDefaultServerImagePathCollapsed()
|
||||
{
|
||||
const auto server = m_servers.at(m_defaultServerIndex).toObject();
|
||||
const auto apiConfig = server.value(configKey::apiConfig).toObject();
|
||||
const auto countryCode = apiConfig.value(configKey::serverCountryCode).toString();
|
||||
|
||||
if (countryCode.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include "settings.h"
|
||||
#include "core/controllers/serverController.h"
|
||||
#include "settings.h"
|
||||
|
||||
class ServersModel : public QAbstractListModel
|
||||
{
|
||||
|
|
@ -30,7 +30,13 @@ public:
|
|||
DefaultContainerRole,
|
||||
|
||||
HasInstalledContainers,
|
||||
IsServerFromApiRole,
|
||||
|
||||
IsServerFromTelegramApiRole,
|
||||
IsServerFromGatewayApiRole,
|
||||
ApiConfigRole,
|
||||
IsCountrySelectionAvailableRole,
|
||||
ApiAvailableCountriesRole,
|
||||
ApiServerCountryCodeRole,
|
||||
|
||||
HasAmneziaDns
|
||||
};
|
||||
|
|
@ -49,8 +55,10 @@ public:
|
|||
Q_PROPERTY(QString defaultServerName READ getDefaultServerName NOTIFY defaultServerNameChanged)
|
||||
Q_PROPERTY(QString defaultServerDefaultContainerName READ getDefaultServerDefaultContainerName NOTIFY defaultServerDefaultContainerChanged)
|
||||
Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerDefaultContainerChanged)
|
||||
Q_PROPERTY(QString defaultServerImagePathCollapsed READ getDefaultServerImagePathCollapsed NOTIFY defaultServerDefaultContainerChanged)
|
||||
Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerDefaultContainerChanged)
|
||||
Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY defaultServerDefaultContainerChanged)
|
||||
Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY
|
||||
defaultServerDefaultContainerChanged)
|
||||
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
|
||||
|
||||
Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
|
||||
|
|
@ -60,6 +68,7 @@ public slots:
|
|||
const int getDefaultServerIndex();
|
||||
const QString getDefaultServerName();
|
||||
const QString getDefaultServerDescriptionCollapsed();
|
||||
const QString getDefaultServerImagePathCollapsed();
|
||||
const QString getDefaultServerDescriptionExpanded();
|
||||
const QString getDefaultServerDefaultContainerName();
|
||||
bool isDefaultServerCurrentlyProcessed();
|
||||
|
|
@ -101,6 +110,7 @@ public slots:
|
|||
QPair<QString, QString> getDnsPair(const int serverIndex);
|
||||
|
||||
bool isServerFromApiAlreadyExists(const quint16 crc);
|
||||
bool isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType, const QString &serviceProtocol);
|
||||
|
||||
QVariant getDefaultServerData(const QString roleString);
|
||||
|
||||
|
|
@ -108,6 +118,10 @@ public slots:
|
|||
|
||||
bool isDefaultServerDefaultContainerHasSplitTunneling();
|
||||
|
||||
bool isServerFromApi(const int serverIndex);
|
||||
bool isApiKeyExpired(const int serverIndex);
|
||||
void removeApiConfig(const int serverIndex);
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
|
|
@ -121,6 +135,9 @@ signals:
|
|||
void defaultServerContainersUpdated(const QJsonArray &containers);
|
||||
void defaultServerDefaultContainerChanged(const int containerIndex);
|
||||
|
||||
void updateApiLanguageModel();
|
||||
void updateApiServicesModel();
|
||||
|
||||
private:
|
||||
ServerCredentials serverCredentials(int index) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import Style 1.0
|
|||
Button {
|
||||
id: root
|
||||
|
||||
property string defaultButtonColor: AmneziaStyle.color.white
|
||||
property string progressButtonColor: AmneziaStyle.color.white
|
||||
property string connectedButtonColor: AmneziaStyle.color.orange
|
||||
property string defaultButtonColor: AmneziaStyle.color.paleGray
|
||||
property string progressButtonColor: AmneziaStyle.color.paleGray
|
||||
property string connectedButtonColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
implicitWidth: 190
|
||||
implicitHeight: 190
|
||||
|
|
@ -50,13 +50,13 @@ Button {
|
|||
verticalOffset: 0
|
||||
radius: 10
|
||||
samples: 25
|
||||
color: root.activeFocus ? AmneziaStyle.color.white : AmneziaStyle.color.orange
|
||||
color: root.activeFocus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.goldenApricot
|
||||
source: backgroundCircle
|
||||
}
|
||||
|
||||
ShapePath {
|
||||
fillColor: AmneziaStyle.color.transparent
|
||||
strokeColor: AmneziaStyle.color.white
|
||||
strokeColor: AmneziaStyle.color.paleGray
|
||||
strokeWidth: root.activeFocus ? 1 : 0
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ Button {
|
|||
fillColor: AmneziaStyle.color.transparent
|
||||
strokeColor: {
|
||||
if (ConnectionController.isConnectionInProgress) {
|
||||
return AmneziaStyle.color.connectionInProgress
|
||||
return AmneziaStyle.color.darkCharcoal
|
||||
} else if (ConnectionController.isConnected) {
|
||||
return connectedButtonColor
|
||||
} else {
|
||||
|
|
@ -115,7 +115,7 @@ Button {
|
|||
|
||||
ShapePath {
|
||||
fillColor: AmneziaStyle.color.transparent
|
||||
strokeColor: AmneziaStyle.color.white
|
||||
strokeColor: AmneziaStyle.color.paleGray
|
||||
strokeWidth: 3
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ DrawerType2 {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
|
||||
text: qsTr("Split tunneling on the server")
|
||||
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
||||
|
|
@ -68,7 +68,7 @@ DrawerType2 {
|
|||
}
|
||||
|
||||
DividerType {
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ DrawerType2 {
|
|||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
backgroundColor: AmneziaStyle.color.greyDark
|
||||
backgroundColor: AmneziaStyle.color.slateGray
|
||||
|
||||
textFieldPlaceholderText: qsTr("application name")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,10 +89,10 @@ DrawerType2 {
|
|||
Layout.leftMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: noButtonText
|
||||
|
|
|
|||
|
|
@ -147,8 +147,8 @@ DrawerType2 {
|
|||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
color: radioButton.hovered ? AmneziaStyle.color.greyDark : AmneziaStyle.color.blackLight
|
||||
border.color: radioButton.focus ? AmneziaStyle.color.white : AmneziaStyle.color.transparent
|
||||
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
|
||||
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
|
||||
border.width: radioButton.focus ? 1 : 0
|
||||
|
||||
Behavior on color {
|
||||
|
|
|
|||
|
|
@ -113,10 +113,10 @@ DrawerType2 {
|
|||
Layout.topMargin: 8
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Copy")
|
||||
|
|
@ -136,10 +136,10 @@ DrawerType2 {
|
|||
visible: false
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Copy config string")
|
||||
|
|
@ -155,10 +155,10 @@ DrawerType2 {
|
|||
Layout.topMargin: 24
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Show connection settings")
|
||||
|
|
@ -282,9 +282,9 @@ DrawerType2 {
|
|||
readOnly: true
|
||||
activeFocusOnTab: false
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
selectionColor: AmneziaStyle.color.brown
|
||||
selectedTextColor: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Rectangle {
|
|||
implicitWidth: transportProtoButtonGroup.implicitWidth
|
||||
implicitHeight: transportProtoButtonGroup.implicitHeight
|
||||
|
||||
color: AmneziaStyle.color.blackLight
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
radius: 16
|
||||
|
||||
onFocusChanged: {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Item {
|
|||
ImageButtonType {
|
||||
id: backButton
|
||||
image: backButtonImage
|
||||
imageColor: AmneziaStyle.color.white
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@ import "TextTypes"
|
|||
Button {
|
||||
id: root
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.whiteHovered
|
||||
property string defaultColor: AmneziaStyle.color.white
|
||||
property string disabledColor: AmneziaStyle.color.greyDisabled
|
||||
property string pressedColor: AmneziaStyle.color.grey
|
||||
property string hoveredColor: AmneziaStyle.color.lightGray
|
||||
property string defaultColor: AmneziaStyle.color.paleGray
|
||||
property string disabledColor: AmneziaStyle.color.charcoalGray
|
||||
property string pressedColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.black
|
||||
property string textColor: AmneziaStyle.color.midnightBlack
|
||||
|
||||
property string borderColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderColor: AmneziaStyle.color.paleGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderWidth: 0
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ Popup {
|
|||
|
||||
ShapePath {
|
||||
fillColor: AmneziaStyle.color.transparent
|
||||
strokeColor: AmneziaStyle.color.greyDisabled
|
||||
strokeColor: AmneziaStyle.color.charcoalGray
|
||||
strokeWidth: 3
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
|
|
|
|||
|
|
@ -11,16 +11,16 @@ RadioButton {
|
|||
property string bodyText
|
||||
property string footerText
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.blackHovered
|
||||
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
property string defaultColor: AmneziaStyle.color.transparent
|
||||
property string disabledColor: AmneziaStyle.color.transparent
|
||||
property string pressedColor: AmneziaStyle.color.blackPressed
|
||||
property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
property string selectedColor: AmneziaStyle.color.transparent
|
||||
|
||||
property string textColor: AmneziaStyle.color.black
|
||||
property string textColor: AmneziaStyle.color.midnightBlack
|
||||
|
||||
property string pressedBorderColor: Qt.rgba(251/255, 178/255, 106/255, 0.3)
|
||||
property string selectedBorderColor: AmneziaStyle.color.orange
|
||||
property string selectedBorderColor: AmneziaStyle.color.goldenApricot
|
||||
property string defaultBodredColor: AmneziaStyle.color.transparent
|
||||
property int borderWidth: 0
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ RadioButton {
|
|||
Text {
|
||||
text: root.headerText
|
||||
wrapMode: Text.WordWrap
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 25
|
||||
font.weight: 700
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
@ -99,7 +99,7 @@ RadioButton {
|
|||
Text {
|
||||
text: root.bodyText
|
||||
wrapMode: Text.WordWrap
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 16
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
@ -115,7 +115,7 @@ RadioButton {
|
|||
text: root.footerText
|
||||
wrapMode: Text.WordWrap
|
||||
visible: root.footerText !== ""
|
||||
color: AmneziaStyle.color.grey
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
font.pixelSize: 13
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
177
client/ui/qml/Controls2/CardWithIconsType.qml
Normal file
177
client/ui/qml/Controls2/CardWithIconsType.qml
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Button {
|
||||
id: root
|
||||
|
||||
property string headerText
|
||||
property string bodyText
|
||||
property string footerText
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.slateGray
|
||||
property string defaultColor: AmneziaStyle.color.onyxBlack
|
||||
|
||||
property string textColor: AmneziaStyle.color.midnightBlack
|
||||
|
||||
property string rightImageSource
|
||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string leftImageSource
|
||||
|
||||
property real textOpacity: 1.0
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
anchors.fill: parent
|
||||
radius: 16
|
||||
|
||||
color: defaultColor
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
implicitHeight: content.implicitHeight
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
Image {
|
||||
id: leftImage
|
||||
source: leftImageSource
|
||||
|
||||
visible: leftImageSource !== ""
|
||||
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
Layout.leftMargin: 24
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
ListItemTitleType {
|
||||
text: root.headerText
|
||||
visible: text !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: root.bodyText !== "" ? 0 : 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
text: root.bodyText
|
||||
visible: text !== ""
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: root.footerText !== "" ? 0 : 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
|
||||
ButtonTextType {
|
||||
text: root.footerText
|
||||
visible: text !== ""
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: rightImage
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
hoverEnabled: false
|
||||
image: rightImageSource
|
||||
imageColor: rightImageColor
|
||||
visible: rightImageSource ? true : false
|
||||
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
Rectangle {
|
||||
id: rightImageBackground
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: "transparent"
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
|
||||
onEntered: {
|
||||
backgroundRect.color = root.hoveredColor
|
||||
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.hoveredColor
|
||||
}
|
||||
root.textOpacity = 0.8
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundRect.color = root.defaultColor
|
||||
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 1
|
||||
}
|
||||
|
||||
onPressedChanged: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 0.7
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,26 +11,26 @@ CheckBox {
|
|||
id: root
|
||||
|
||||
property string descriptionText
|
||||
property string descriptionTextColor: AmneziaStyle.color.grey
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.greyDisabled
|
||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string textDisabledColor: AmneziaStyle.color.grey
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.blackHovered
|
||||
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
property string defaultColor: AmneziaStyle.color.transparent
|
||||
property string pressedColor: AmneziaStyle.color.blackPressed
|
||||
property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
|
||||
property string defaultBorderColor: AmneziaStyle.color.white
|
||||
property string checkedBorderColor: AmneziaStyle.color.orange
|
||||
property string checkedBorderDisabledColor: AmneziaStyle.color.brownDark
|
||||
property string defaultBorderColor: AmneziaStyle.color.paleGray
|
||||
property string checkedBorderColor: AmneziaStyle.color.goldenApricot
|
||||
property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string checkedImageColor: AmneziaStyle.color.orange
|
||||
property string pressedImageColor: AmneziaStyle.color.orangeDark
|
||||
property string checkedImageColor: AmneziaStyle.color.goldenApricot
|
||||
property string pressedImageColor: AmneziaStyle.color.burntOrange
|
||||
property string defaultImageColor: AmneziaStyle.color.transparent
|
||||
property string checkedDisabledImageColor: AmneziaStyle.color.brownLight
|
||||
property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown
|
||||
|
||||
property string imageSource: "qrc:/images/controls/check.svg"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ Rectangle {
|
|||
Layout.rightMargin: 16
|
||||
|
||||
height: 1
|
||||
color: AmneziaStyle.color.greyDark
|
||||
color: AmneziaStyle.color.slateGray
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ Item {
|
|||
property Component collapsedContent
|
||||
property Component expandedContent
|
||||
|
||||
property string defaultColor: AmneziaStyle.color.blackLight
|
||||
property string borderColor: AmneziaStyle.color.greyDark
|
||||
property string defaultColor: AmneziaStyle.color.onyxBlack
|
||||
property string borderColor: AmneziaStyle.color.slateGray
|
||||
|
||||
property real expandedHeight
|
||||
property real collapsedHeight: 0
|
||||
|
|
|
|||
|
|
@ -11,31 +11,31 @@ Item {
|
|||
id: root
|
||||
|
||||
property string text
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string textDisabledColor: AmneziaStyle.color.grey
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
property int textMaximumLineCount: 2
|
||||
property int textElide: Qt.ElideRight
|
||||
|
||||
property string descriptionText
|
||||
property string descriptionTextColor: AmneziaStyle.color.grey
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.greyDisabled
|
||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string headerText
|
||||
property string headerBackButtonImage
|
||||
|
||||
property var rootButtonClickedFunction
|
||||
property string rootButtonImage: "qrc:/images/controls/chevron-down.svg"
|
||||
property string rootButtonImageColor: AmneziaStyle.color.white
|
||||
property string rootButtonBackgroundColor: AmneziaStyle.color.blackLight
|
||||
property string rootButtonBackgroundHoveredColor: AmneziaStyle.color.blackLight
|
||||
property string rootButtonBackgroundPressedColor: AmneziaStyle.color.blackLight
|
||||
property string rootButtonImageColor: AmneziaStyle.color.paleGray
|
||||
property string rootButtonBackgroundColor: AmneziaStyle.color.onyxBlack
|
||||
property string rootButtonBackgroundHoveredColor: AmneziaStyle.color.onyxBlack
|
||||
property string rootButtonBackgroundPressedColor: AmneziaStyle.color.onyxBlack
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string rootButtonHoveredBorderColor: AmneziaStyle.color.greyDisabled
|
||||
property string rootButtonDefaultBorderColor: AmneziaStyle.color.greyDark
|
||||
property string rootButtonPressedBorderColor: AmneziaStyle.color.white
|
||||
property string rootButtonHoveredBorderColor: AmneziaStyle.color.charcoalGray
|
||||
property string rootButtonDefaultBorderColor: AmneziaStyle.color.slateGray
|
||||
property string rootButtonPressedBorderColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property int rootButtonTextLeftMargins: 16
|
||||
property int rootButtonTextTopMargin: 16
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ Item {
|
|||
implicitHeight: 40
|
||||
|
||||
image: root.actionButtonImage
|
||||
imageColor: AmneziaStyle.color.white
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
visible: image ? true : false
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ Item {
|
|||
|
||||
text: root.descriptionText
|
||||
|
||||
color: AmneziaStyle.color.grey
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ Item {
|
|||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
image: root.actionButtonImage
|
||||
imageColor: AmneziaStyle.color.white
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
visible: image ? true : false
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ Item {
|
|||
|
||||
text: root.descriptionText
|
||||
|
||||
color: AmneziaStyle.color.grey
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,19 +9,19 @@ import "TextTypes"
|
|||
RadioButton {
|
||||
id: root
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.blackHovered
|
||||
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
property string defaultColor: AmneziaStyle.color.transparent
|
||||
property string checkedColor: AmneziaStyle.color.transparent
|
||||
property string disabledColor: AmneziaStyle.color.transparent
|
||||
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string textDisabledColor: AmneziaStyle.color.grey
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string pressedBorderColor: AmneziaStyle.color.greyDisabled
|
||||
property string checkedBorderColor: AmneziaStyle.color.orange
|
||||
property string pressedBorderColor: AmneziaStyle.color.charcoalGray
|
||||
property string checkedBorderColor: AmneziaStyle.color.goldenApricot
|
||||
property string defaultBodredColor: AmneziaStyle.color.transparent
|
||||
property string checkedDisabledBorderColor: AmneziaStyle.color.brownLight
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string checkedDisabledBorderColor: AmneziaStyle.color.mutedBrown
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderWidth: 0
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
|
|
|
|||
|
|
@ -9,18 +9,18 @@ Button {
|
|||
|
||||
property string image
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.blackHovered
|
||||
property string hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
property string defaultColor: AmneziaStyle.color.transparent
|
||||
property string pressedColor: AmneziaStyle.color.blackPressed
|
||||
property string disableColor: AmneziaStyle.color.greyDark
|
||||
property string pressedColor: AmneziaStyle.color.sheerWhite
|
||||
property string disableColor: AmneziaStyle.color.slateGray
|
||||
|
||||
property string imageColor: AmneziaStyle.color.grey
|
||||
property string disableImageColor: AmneziaStyle.color.greyDark
|
||||
property string imageColor: AmneziaStyle.color.mutedGray
|
||||
property string disableImageColor: AmneziaStyle.color.slateGray
|
||||
|
||||
property alias backgroundColor: background.color
|
||||
property alias backgroundRadius: background.radius
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
hoverEnabled: true
|
||||
|
|
|
|||
|
|
@ -26,16 +26,16 @@ Item {
|
|||
property alias eyeButton: eyeImage
|
||||
property FlickableType parentFlickable
|
||||
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string textDisabledColor: AmneziaStyle.color.grey
|
||||
property string descriptionColor: AmneziaStyle.color.grey
|
||||
property string descriptionDisabledColor: AmneziaStyle.color.greyDisabled
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
property real textOpacity: 1.0
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string rightImageColor: AmneziaStyle.color.white
|
||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property bool descriptionOnTop: false
|
||||
property bool hideDescription: true
|
||||
|
|
|
|||
38
client/ui/qml/Controls2/LabelWithImageType.qml
Normal file
38
client/ui/qml/Controls2/LabelWithImageType.qml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
RowLayout {
|
||||
property string imageSource
|
||||
property string leftText
|
||||
property var rightText
|
||||
property bool isRightTextUndefined: rightText === undefined
|
||||
|
||||
visible: !isRightTextUndefined
|
||||
|
||||
Image {
|
||||
Layout.preferredHeight: 18
|
||||
Layout.preferredWidth: 18
|
||||
source: imageSource
|
||||
}
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
text: leftText
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
visible: rightText !== ""
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
text: isRightTextUndefined ? "" : rightText
|
||||
}
|
||||
}
|
||||
|
|
@ -105,8 +105,8 @@ ListView {
|
|||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
color: radioButton.hovered ? AmneziaStyle.color.greyDark : AmneziaStyle.color.blackLight
|
||||
border.color: radioButton.focus ? AmneziaStyle.color.white : AmneziaStyle.color.transparent
|
||||
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
|
||||
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
|
||||
border.width: radioButton.focus ? 1 : 0
|
||||
|
||||
Behavior on color {
|
||||
|
|
|
|||
|
|
@ -84,11 +84,11 @@ Popup {
|
|||
implicitHeight: 32
|
||||
|
||||
defaultColor: "white"
|
||||
hoveredColor: AmneziaStyle.color.whiteHovered
|
||||
pressedColor: AmneziaStyle.color.whiteHovered
|
||||
disabledColor: AmneziaStyle.color.greyDisabled
|
||||
hoveredColor: AmneziaStyle.color.lightGray
|
||||
pressedColor: AmneziaStyle.color.lightGray
|
||||
disabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
textColor: AmneziaStyle.color.black
|
||||
textColor: AmneziaStyle.color.midnightBlack
|
||||
borderWidth: 0
|
||||
|
||||
text: qsTr("Close")
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ ProgressBar {
|
|||
implicitHeight: 4
|
||||
|
||||
background: Rectangle {
|
||||
color: AmneziaStyle.color.brown
|
||||
color: AmneziaStyle.color.richBrown
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
Rectangle {
|
||||
width: root.visualPosition * parent.width
|
||||
height: parent.height
|
||||
color: AmneziaStyle.color.orange
|
||||
color: AmneziaStyle.color.goldenApricot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,29 +10,29 @@ Switch {
|
|||
id: root
|
||||
|
||||
property alias descriptionText: description.text
|
||||
property string descriptionTextColor: AmneziaStyle.color.grey
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.greyDisabled
|
||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string textDisabledColor: AmneziaStyle.color.grey
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string checkedIndicatorColor: AmneziaStyle.color.brown
|
||||
property string checkedIndicatorColor: AmneziaStyle.color.richBrown
|
||||
property string defaultIndicatorColor: AmneziaStyle.color.transparent
|
||||
property string checkedDisabledIndicatorColor: AmneziaStyle.color.brownDark
|
||||
property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string checkedIndicatorBorderColor: AmneziaStyle.color.brown
|
||||
property string defaultIndicatorBorderColor: AmneziaStyle.color.greyDisabled
|
||||
property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.brownDark
|
||||
property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown
|
||||
property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray
|
||||
property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string checkedInnerCircleColor: AmneziaStyle.color.orange
|
||||
property string defaultInnerCircleColor: AmneziaStyle.color.white
|
||||
property string checkedDisabledInnerCircleColor: AmneziaStyle.color.brownLight
|
||||
property string defaultDisabledInnerCircleColor: AmneziaStyle.color.greyDisabled
|
||||
property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot
|
||||
property string defaultInnerCircleColor: AmneziaStyle.color.paleGray
|
||||
property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown
|
||||
property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.blackHovered
|
||||
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite
|
||||
property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent
|
||||
|
||||
hoverEnabled: enabled ? true : false
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ import Style 1.0
|
|||
TabButton {
|
||||
id: root
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.brown
|
||||
property string defaultColor: AmneziaStyle.color.greyDark
|
||||
property string selectedColor: AmneziaStyle.color.orange
|
||||
property string hoveredColor: AmneziaStyle.color.richBrown
|
||||
property string defaultColor: AmneziaStyle.color.slateGray
|
||||
property string selectedColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property bool isSelected: false
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@ import Style 1.0
|
|||
TabButton {
|
||||
id: root
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.brown
|
||||
property string defaultColor: AmneziaStyle.color.white
|
||||
property string selectedColor: AmneziaStyle.color.orange
|
||||
property string hoveredColor: AmneziaStyle.color.richBrown
|
||||
property string defaultColor: AmneziaStyle.color.paleGray
|
||||
property string selectedColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
property string image
|
||||
|
||||
property bool isSelected: false
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property var clickedFunc
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ Rectangle {
|
|||
property alias textArea: textArea
|
||||
property alias textAreaText: textArea.text
|
||||
|
||||
property string borderHoveredColor: AmneziaStyle.color.greyDisabled
|
||||
property string borderNormalColor: AmneziaStyle.color.greyDark
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
height: 148
|
||||
color: AmneziaStyle.color.blackLight
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
border.width: 1
|
||||
border.color: getBorderColor(borderNormalColor)
|
||||
radius: 16
|
||||
|
|
@ -54,10 +54,10 @@ Rectangle {
|
|||
anchors.topMargin: 16
|
||||
anchors.bottomMargin: 16
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
selectionColor: AmneziaStyle.color.brown
|
||||
selectedTextColor: AmneziaStyle.color.white
|
||||
placeholderTextColor: AmneziaStyle.color.grey
|
||||
color: AmneziaStyle.color.paleGray
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
|
|
|
|||
183
client/ui/qml/Controls2/TextAreaWithFooterType.qml
Normal file
183
client/ui/qml/Controls2/TextAreaWithFooterType.qml
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string placeholderText
|
||||
property string text
|
||||
property string headerText
|
||||
property alias textArea: textArea
|
||||
property alias textAreaText: textArea.text
|
||||
|
||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string firstButtonImage
|
||||
property string secondButtonImage
|
||||
|
||||
property var firstButtonClickedFunc
|
||||
property var secondButtonClickedFunc
|
||||
|
||||
height: 148
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
border.width: 1
|
||||
border.color: getBorderColor(borderNormalColor)
|
||||
radius: 16
|
||||
|
||||
property FlickableType parentFlickable: null
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: parentMouse
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: textArea.forceActiveFocus()
|
||||
hoverEnabled: true
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 0
|
||||
|
||||
LabelTextType {
|
||||
Layout.fillWidth: true
|
||||
text: root.headerText
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: textArea
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
leftPadding: 0
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
color: AmneziaStyle.color.paleGray
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
font.family: "PT Root UI VF"
|
||||
|
||||
placeholderText: root.placeholderText
|
||||
text: root.text
|
||||
|
||||
|
||||
KeyNavigation.tab: firstButton
|
||||
|
||||
onCursorVisibleChanged: {
|
||||
if (textArea.cursorVisible) {
|
||||
fl.interactive = true
|
||||
} else {
|
||||
fl.interactive = false
|
||||
}
|
||||
}
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
MouseArea {
|
||||
id: textAreaMouse
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
fl.interactive = true
|
||||
contextMenu.open()
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
ContextMenuType {
|
||||
id: contextMenu
|
||||
textObj: textArea
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: -8
|
||||
spacing: 0
|
||||
ImageButtonType {
|
||||
id: firstButton
|
||||
visible: root.firstButtonImage !== ""
|
||||
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
image: root.firstButtonImage
|
||||
onClicked: function() {
|
||||
if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") {
|
||||
root.firstButtonClickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: secondButton
|
||||
visible: root.secondButtonImage !== ""
|
||||
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
image: root.secondButtonImage
|
||||
onClicked: function() {
|
||||
if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") {
|
||||
root.secondButtonClickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: resetButton
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
visible: root.textAreaText !== ""
|
||||
image: "qrc:/images/controls/close.svg"
|
||||
|
||||
onClicked: function() {
|
||||
root.textAreaText = ""
|
||||
textArea.focus = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
root.border.color = getBorderColor(borderFocusedColor)
|
||||
}
|
||||
|
||||
onExited: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
root.border.color = getBorderColor(borderHoveredColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getBorderColor(noneFocusedColor) {
|
||||
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
||||
}
|
||||
}
|
||||
|
|
@ -10,8 +10,8 @@ Item {
|
|||
id: root
|
||||
|
||||
property string headerText
|
||||
property string headerTextDisabledColor: AmneziaStyle.color.greyDisabled
|
||||
property string headerTextColor: AmneziaStyle.color.grey
|
||||
property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
property string headerTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property alias errorText: errorField.text
|
||||
property bool checkEmptyText: false
|
||||
|
|
@ -23,18 +23,18 @@ Item {
|
|||
|
||||
property alias textField: textField
|
||||
property alias textFieldText: textField.text
|
||||
property string textFieldTextColor: AmneziaStyle.color.white
|
||||
property string textFieldTextDisabledColor: AmneziaStyle.color.grey
|
||||
property string textFieldTextColor: AmneziaStyle.color.paleGray
|
||||
property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string textFieldPlaceholderText
|
||||
property bool textFieldEditable: true
|
||||
|
||||
property string borderColor: AmneziaStyle.color.greyDark
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string backgroundColor: AmneziaStyle.color.blackLight
|
||||
property string backgroundColor: AmneziaStyle.color.onyxBlack
|
||||
property string backgroundDisabledColor: AmneziaStyle.color.transparent
|
||||
property string bgBorderHoveredColor: AmneziaStyle.color.greyDisabled
|
||||
property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
|
@ -92,10 +92,10 @@ Item {
|
|||
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
|
||||
|
||||
placeholderText: root.textFieldPlaceholderText
|
||||
placeholderTextColor: AmneziaStyle.color.greyDisabled
|
||||
placeholderTextColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
selectionColor: AmneziaStyle.color.brown
|
||||
selectedTextColor: AmneziaStyle.color.white
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: 400
|
||||
|
|
@ -149,7 +149,9 @@ Item {
|
|||
|
||||
text: root.errorText
|
||||
visible: root.errorText !== ""
|
||||
color: AmneziaStyle.color.red
|
||||
color: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Text {
|
|||
lineHeight: 24
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 16
|
||||
font.weight: 600
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Text {
|
|||
lineHeight: 16 + LanguageModel.getLineHeightAppend()
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.black
|
||||
color: AmneziaStyle.color.midnightBlack
|
||||
font.pixelSize: 13
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Text {
|
|||
lineHeight: 38 + LanguageModel.getLineHeightAppend()
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 32
|
||||
font.weight: 700
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Text {
|
|||
lineHeight: 30 + LanguageModel.getLineHeightAppend()
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 25
|
||||
font.weight: 700
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Text {
|
|||
lineHeight: 16 + LanguageModel.getLineHeightAppend()
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.grey
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
font.pixelSize: 13
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Text {
|
|||
lineHeight: 21.6 + LanguageModel.getLineHeightAppend()
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 18
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Text {
|
|||
lineHeight: 24 + LanguageModel.getLineHeightAppend()
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 16
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Text {
|
|||
lineHeight: 20 + LanguageModel.getLineHeightAppend()
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 14
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Popup {
|
|||
id: button
|
||||
|
||||
image: "qrc:/images/svg/close_black_24dp.svg"
|
||||
imageColor: AmneziaStyle.color.white
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
|
|
|||
|
|
@ -14,15 +14,15 @@ RadioButton {
|
|||
property int textElide: Qt.ElideRight
|
||||
property string descriptionText
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.blackHovered
|
||||
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
property string defaultColor: AmneziaStyle.color.transparent
|
||||
property string disabledColor: AmneziaStyle.color.transparent
|
||||
property string selectedColor: AmneziaStyle.color.transparent
|
||||
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string selectedTextColor: AmneziaStyle.color.orange
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string selectedTextColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.white
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string imageSource
|
||||
|
|
@ -139,7 +139,7 @@ RadioButton {
|
|||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
color: AmneziaStyle.color.grey
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
text: root.descriptionText
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import "TextTypes"
|
|||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string textColor: AmneziaStyle.color.white
|
||||
property string backGroundColor: AmneziaStyle.color.blackLight
|
||||
property string imageColor: AmneziaStyle.color.white
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string backGroundColor: AmneziaStyle.color.onyxBlack
|
||||
property string imageColor: AmneziaStyle.color.paleGray
|
||||
property string textString
|
||||
property int textFormat: Text.PlainText
|
||||
|
||||
|
|
|
|||
|
|
@ -5,22 +5,22 @@ import QtQuick
|
|||
QtObject {
|
||||
property QtObject color: QtObject {
|
||||
readonly property color transparent: 'transparent'
|
||||
readonly property color white: '#D7D8DB'
|
||||
readonly property color whiteHovered: '#C1C2C5'
|
||||
readonly property color grey: '#878B91'
|
||||
readonly property color greyDisabled: '#494B50'
|
||||
readonly property color greyDark: '#2C2D30'
|
||||
readonly property color blackLight: '#1C1D21'
|
||||
readonly property color blackHovered: '#01010114'
|
||||
readonly property color blackPressed: '#0101011f'
|
||||
readonly property color black: '#0E0E11'
|
||||
readonly property color orange: '#FBB26A'
|
||||
readonly property color orangeDark: '#A85809'
|
||||
readonly property color brownLight: '#84603D'
|
||||
readonly property color brown: '#633303'
|
||||
readonly property color brownDark: '#402102'
|
||||
readonly property color red: '#EB5757'
|
||||
|
||||
readonly property color connectionInProgress: '#261E1A'
|
||||
readonly property color paleGray: '#D7D8DB'
|
||||
readonly property color lightGray: '#C1C2C5'
|
||||
readonly property color mutedGray: '#878B91'
|
||||
readonly property color charcoalGray: '#494B50'
|
||||
readonly property color slateGray: '#2C2D30'
|
||||
readonly property color onyxBlack: '#1C1D21'
|
||||
readonly property color midnightBlack: '#0E0E11'
|
||||
readonly property color goldenApricot: '#FBB26A'
|
||||
readonly property color burntOrange: '#A85809'
|
||||
readonly property color mutedBrown: '#84603D'
|
||||
readonly property color richBrown: '#633303'
|
||||
readonly property color deepBrown: '#402102'
|
||||
readonly property color vibrantRed: '#EB5757'
|
||||
readonly property color darkCharcoal: '#261E1A'
|
||||
readonly property color sheerWhite: Qt.rgba(1, 1, 1, 0.12)
|
||||
readonly property color translucentWhite: Qt.rgba(1, 1, 1, 0.08)
|
||||
readonly property color barelyTranslucentWhite: Qt.rgba(1, 1, 1, 0.05)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
94
client/ui/qml/Pages2/PageDevMenu.qml
Normal file
94
client/ui/qml/Pages2/PageDevMenu.qml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
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
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
// KeyNavigation.tab: removeButton
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: "Dev menu"
|
||||
}
|
||||
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: passwordTextField
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
parentFlickable: fl
|
||||
|
||||
headerText: qsTr("Gateway endpoint")
|
||||
textFieldText: SettingsController.gatewayEndpoint
|
||||
|
||||
buttonImageSource: textFieldText !== "" ? "qrc:/images/controls/refresh-cw.svg" : ""
|
||||
|
||||
clickedFunc: function() {
|
||||
SettingsController.resetGatewayEndpoint()
|
||||
}
|
||||
|
||||
textField.onEditingFinished: {
|
||||
textFieldText = textField.text.replace(/^\s+|\s+$/g, '')
|
||||
if (textFieldText !== SettingsController.gatewayEndpoint) {
|
||||
SettingsController.gatewayEndpoint = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
// KeyNavigation.tab: saveButton
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -57,10 +57,10 @@ PageType {
|
|||
implicitHeight: 36
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.grey
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.mutedGray
|
||||
borderWidth: 0
|
||||
|
||||
visible: isLoggingEnabled ? true : false
|
||||
|
|
@ -94,10 +94,10 @@ PageType {
|
|||
implicitHeight: 36
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.grey
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.mutedGray
|
||||
leftImageColor: AmneziaStyle.color.transparent
|
||||
borderWidth: 0
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ PageType {
|
|||
buttonTextLabel.font.weight: 500
|
||||
|
||||
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
|
||||
(ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi"))
|
||||
ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
|
||||
text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
|
||||
|
||||
|
|
@ -243,7 +243,7 @@ PageType {
|
|||
|
||||
hoverEnabled: false
|
||||
image: "qrc:/images/controls/chevron-down.svg"
|
||||
imageColor: AmneziaStyle.color.white
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
icon.width: 18
|
||||
icon.height: 18
|
||||
|
|
@ -265,11 +265,21 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
LabelTextType {
|
||||
id: collapsedServerMenuDescription
|
||||
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
|
||||
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
|
||||
spacing: 0
|
||||
|
||||
Image {
|
||||
Layout.rightMargin: 8
|
||||
visible: source !== ""
|
||||
source: ServersModel.defaultServerImagePathCollapsed
|
||||
}
|
||||
|
||||
LabelTextType {
|
||||
id: collapsedServerMenuDescription
|
||||
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,8 +314,8 @@ PageType {
|
|||
DropDownType {
|
||||
id: containersDropDown
|
||||
|
||||
rootButtonImageColor: AmneziaStyle.color.black
|
||||
rootButtonBackgroundColor: AmneziaStyle.color.white
|
||||
rootButtonImageColor: AmneziaStyle.color.midnightBlack
|
||||
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
|
||||
rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
|
||||
rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
|
||||
rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
|
||||
|
|
@ -314,7 +324,7 @@ PageType {
|
|||
rootButtonTextBottomMargin: 8
|
||||
|
||||
text: ServersModel.defaultServerDefaultContainerName
|
||||
textColor: AmneziaStyle.color.black
|
||||
textColor: AmneziaStyle.color.midnightBlack
|
||||
headerText: qsTr("VPN protocol")
|
||||
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
|
||||
|
|
@ -505,7 +515,7 @@ PageType {
|
|||
ImageButtonType {
|
||||
id: serverInfoButton
|
||||
image: "qrc:/images/controls/settings.svg"
|
||||
imageColor: AmneziaStyle.color.white
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.preferredHeight: checkboxLayout.implicitHeight
|
||||
color: AmneziaStyle.color.blackLight
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
radius: 16
|
||||
|
||||
Connections {
|
||||
|
|
|
|||
|
|
@ -192,9 +192,9 @@ PageType {
|
|||
leftPadding: 0
|
||||
height: 24
|
||||
|
||||
color: AmneziaStyle.color.white
|
||||
selectionColor: AmneziaStyle.color.brown
|
||||
selectedTextColor: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
|
|
@ -224,7 +224,7 @@ PageType {
|
|||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
clickedFunction: function() {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import SortFilterProxyModel 0.2
|
|||
|
||||
import PageEnum 1.0
|
||||
import ContainerEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ PageType {
|
|||
width: parent.width
|
||||
|
||||
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: root.lastItemTabClicked()
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.white
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(descriptionText)
|
||||
|
|
@ -139,7 +139,7 @@ PageType {
|
|||
KeyNavigation.tab: usernameLabel.rightButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.white
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(descriptionText)
|
||||
|
|
@ -163,7 +163,7 @@ PageType {
|
|||
KeyNavigation.tab: passwordLabel.eyeButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.white
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(descriptionText)
|
||||
|
|
@ -194,7 +194,7 @@ PageType {
|
|||
}
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.white
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
||||
|
||||
|
|
@ -218,10 +218,10 @@ PageType {
|
|||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
parentFlickable: fl
|
||||
|
|
@ -282,10 +282,10 @@ PageType {
|
|||
implicitHeight: 32
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.orange
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
text: qsTr("Detailed instructions")
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import SortFilterProxyModel 0.2
|
|||
|
||||
import PageEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
@ -106,7 +107,7 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: "#D7D8DB"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(descriptionText)
|
||||
|
|
@ -130,7 +131,7 @@ PageType {
|
|||
KeyNavigation.tab: usernameLabel.rightButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: "#D7D8DB"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(descriptionText)
|
||||
|
|
@ -154,7 +155,7 @@ PageType {
|
|||
KeyNavigation.tab: passwordLabel.eyeButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: "#D7D8DB"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(descriptionText)
|
||||
|
|
@ -179,7 +180,7 @@ PageType {
|
|||
rightButton.KeyNavigation.tab: changeSettingsButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: "#D7D8DB"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
||||
|
||||
|
|
|
|||
|
|
@ -83,10 +83,10 @@ PageType {
|
|||
}
|
||||
|
||||
descriptionOnTop: true
|
||||
textColor: AmneziaStyle.color.orange
|
||||
textColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.white
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import QtQuick.Layouts
|
|||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
@ -128,6 +129,26 @@ PageType {
|
|||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: devConsole
|
||||
visible: SettingsController.isDevModeEnabled
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Dev console")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/bug.svg"
|
||||
|
||||
// Keys.onTabPressed: lastItemTabClicked(header)
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageDevMenu)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: SettingsController.isDevModeEnabled
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: close
|
||||
visible: GC.isDesktop()
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ PageType {
|
|||
font.pixelSize: 14
|
||||
|
||||
text: qsTr("Amnezia is a free and open-source application. You can support the developers if you like it.")
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
|
|
@ -163,7 +163,7 @@ PageType {
|
|||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
Qt.openUrlExternally(qsTr("https://amnezia.org"))
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -177,7 +177,19 @@ PageType {
|
|||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: qsTr("Software version: %1").arg(SettingsController.getAppVersion())
|
||||
color: AmneziaStyle.color.grey
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
MouseArea {
|
||||
property int clickCount: 0
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (clickCount > 10) {
|
||||
SettingsController.enableDevMode()
|
||||
} else {
|
||||
clickCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -188,10 +200,10 @@ PageType {
|
|||
implicitHeight: 32
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.orange
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
text: qsTr("Check for updates")
|
||||
|
||||
|
|
@ -211,10 +223,10 @@ PageType {
|
|||
implicitHeight: 25
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.orange
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
text: qsTr("Privacy Policy")
|
||||
|
||||
|
|
@ -222,7 +234,7 @@ PageType {
|
|||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
Qt.openUrlExternally("https://amnezia.org/en/policy")
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
103
client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
Normal file
103
client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
ListView {
|
||||
id: menuContent
|
||||
|
||||
property var selectedText
|
||||
|
||||
width: parent.width
|
||||
height: menuContent.contentItem.height
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
model: ApiCountryModel
|
||||
|
||||
ButtonGroup {
|
||||
id: containersRadioButtonGroup
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
VerticalRadioButton {
|
||||
id: containerRadioButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
|
||||
text: countryName
|
||||
|
||||
ButtonGroup.group: containersRadioButtonGroup
|
||||
|
||||
imageSource: "qrc:/images/controls/download.svg"
|
||||
|
||||
checked: index === ApiCountryModel.currentIndex
|
||||
|
||||
onClicked: {
|
||||
if (index !== ApiCountryModel.currentIndex) {
|
||||
PageController.showBusyIndicator(true)
|
||||
var prevIndex = ApiCountryModel.currentIndex
|
||||
ApiCountryModel.currentIndex = index
|
||||
if (!InstallController.updateServiceFromApi(ServersModel.defaultIndex, countryCode, countryName)) {
|
||||
ApiCountryModel.currentIndex = prevIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: containerRadioButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (checkable) {
|
||||
checked = true
|
||||
}
|
||||
containerRadioButton.clicked()
|
||||
}
|
||||
Keys.onReturnPressed: {
|
||||
if (checkable) {
|
||||
checked = true
|
||||
}
|
||||
containerRadioButton.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
Layout.rightMargin: 32
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
source: "qrc:/countriesFlags/images/flagKit/" + countryCode + ".svg"
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
208
client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
Normal file
208
client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
// KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/map-pin.svg"
|
||||
leftText: qsTr("For the region")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("region")
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/tag.svg"
|
||||
leftText: qsTr("Price")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("price")
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/history.svg"
|
||||
leftText: qsTr("Work period")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("workPeriod")
|
||||
|
||||
visible: rightText !== ""
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/gauge.svg"
|
||||
leftText: qsTr("Speed")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("speed")
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: supportUuid
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Support tag")
|
||||
descriptionText: SettingsController.getInstallationUuid()
|
||||
|
||||
descriptionOnTop: true
|
||||
|
||||
// parentFlickable: fl
|
||||
// KeyNavigation.tab: passwordLabel.eyeButton
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: resetButton
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 16
|
||||
Layout.leftMargin: 8
|
||||
implicitHeight: 32
|
||||
|
||||
defaultColor: "transparent"
|
||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
||||
pressedColor: Qt.rgba(1, 1, 1, 0.12)
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
text: qsTr("Reload API config")
|
||||
|
||||
// Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
var headerText = qsTr("Reload API config?")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||
PageController.showNotificationMessage(qsTr("Cannot reload API config during active connection"))
|
||||
} else {
|
||||
PageController.showBusyIndicator(true)
|
||||
InstallController.updateServiceFromApi(ServersModel.processedIndex, "", "", true)
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
removeButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: removeButton
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.bottomMargin: 16
|
||||
Layout.leftMargin: 8
|
||||
implicitHeight: 32
|
||||
|
||||
defaultColor: "transparent"
|
||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
||||
pressedColor: Qt.rgba(1, 1, 1, 0.12)
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
text: qsTr("Remove from application")
|
||||
|
||||
// Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
var headerText = qsTr("Remove from application?")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
||||
} else {
|
||||
PageController.showBusyIndicator(true)
|
||||
InstallController.removeProcessedServer()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
removeButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ PageType {
|
|||
|
||||
text: appPath
|
||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||
rightImageColor: AmneziaStyle.color.white
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove ") + appPath + "?"
|
||||
|
|
@ -242,7 +242,7 @@ PageType {
|
|||
Rectangle {
|
||||
anchors.fill: addAppButton
|
||||
anchors.bottomMargin: -24
|
||||
color: AmneziaStyle.color.black
|
||||
color: AmneziaStyle.color.midnightBlack
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ PageType {
|
|||
|
||||
text: qsTr("Reset settings and remove all data from the application")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked()
|
||||
parentFlickable: fl
|
||||
|
|
@ -241,7 +241,7 @@ PageType {
|
|||
} else
|
||||
{
|
||||
SettingsController.clearSettings()
|
||||
PageController.replaceStartPage()
|
||||
PageController.goToPageHome()
|
||||
}
|
||||
|
||||
if (!GC.isMobile()) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ PageType {
|
|||
|
||||
function onRestoreBackupFinished() {
|
||||
PageController.showNotificationMessage(qsTr("Settings restored from backup file"))
|
||||
//goToStartPage()
|
||||
PageController.goToPageHome()
|
||||
}
|
||||
|
||||
|
|
@ -122,10 +121,10 @@ PageType {
|
|||
Layout.topMargin: -8
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Restore from backup")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import QtQuick.Controls
|
|||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ PageType {
|
|||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
|
||||
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
|
||||
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
|
||||
|
||||
enabled: !isServerFromApi
|
||||
|
||||
|
|
@ -103,10 +103,10 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Restore default")
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ disabled after 14 days, and all log files will be deleted.")
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Open folder with logs")
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ disabled after 14 days, and all log files will be deleted.")
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Save logs to file")
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ disabled after 14 days, and all log files will be deleted.")
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Clear logs")
|
||||
color: AmneziaStyle.color.white
|
||||
color: AmneziaStyle.color.paleGray
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ PageType {
|
|||
|
||||
function onRemoveProcessedServerFinished(finishedMessage) {
|
||||
if (!ServersModel.getServersCount()) {
|
||||
PageController.replaceStartPage()
|
||||
PageController.goToPageHome()
|
||||
} else {
|
||||
PageController.goToStartPage()
|
||||
PageController.goToPage(PageEnum.PageSettingsServersList)
|
||||
|
|
@ -119,7 +119,7 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Reboot server")
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
KeyNavigation.tab: labelWithButton3
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Remove server from application")
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (content.isServerWithWriteAccess) {
|
||||
|
|
@ -208,7 +208,7 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Clear server from Amnezia software")
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: labelWithButton5.visible ?
|
||||
labelWithButton5.forceActiveFocus() :
|
||||
|
|
@ -247,11 +247,11 @@ PageType {
|
|||
|
||||
LabelWithButtonType {
|
||||
id: labelWithButton5
|
||||
visible: ServersModel.getProcessedServerData("isServerFromApi")
|
||||
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Reset API config")
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: root.lastItemTabClickedSignal()
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ PageType {
|
|||
}
|
||||
|
||||
DividerType {
|
||||
visible: ServersModel.getProcessedServerData("isServerFromApi")
|
||||
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,19 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
property int pageSettingsServerProtocols: 0
|
||||
property int pageSettingsServerServices: 1
|
||||
property int pageSettingsServerData: 2
|
||||
property int pageSettingsApiServerInfo: 3
|
||||
property int pageSettingsApiLanguageList: 4
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Connections {
|
||||
target: PageController
|
||||
|
||||
function onGoToPageSettingsServerServices() {
|
||||
tabBar.currentIndex = 1
|
||||
tabBar.currentIndex = root.pageSettingsServerServices
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +76,15 @@ PageType {
|
|||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: headerContent.actionButton
|
||||
|
||||
backButtonFunction: function() {
|
||||
if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo &&
|
||||
ServersModel.getProcessedServerData("isCountrySelectionAvailable")) {
|
||||
nestedStackView.currentIndex = root.pageSettingsApiLanguageList
|
||||
} else {
|
||||
PageController.closePage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -78,11 +93,15 @@ PageType {
|
|||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
actionButtonImage: "qrc:/images/controls/edit-3.svg"
|
||||
actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg" : "qrc:/images/controls/edit-3.svg"
|
||||
|
||||
headerText: name
|
||||
descriptionText: {
|
||||
if (ServersModel.isProcessedServerHasWriteAccess()) {
|
||||
if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
|
||||
return ApiServicesModel.getSelectedServiceData("serviceDescription")
|
||||
} else if (ServersModel.getProcessedServerData("isServerFromTelegramApi")) {
|
||||
return serverDescription
|
||||
} else if (ServersModel.isProcessedServerHasWriteAccess()) {
|
||||
return credentialsLogin + " · " + hostName
|
||||
} else {
|
||||
return hostName
|
||||
|
|
@ -92,7 +111,11 @@ PageType {
|
|||
KeyNavigation.tab: tabBar
|
||||
|
||||
actionButtonFunction: function() {
|
||||
serverNameEditDrawer.open()
|
||||
if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
|
||||
nestedStackView.currentIndex = root.pageSettingsApiServerInfo
|
||||
} else {
|
||||
serverNameEditDrawer.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,13 +195,16 @@ PageType {
|
|||
|
||||
Layout.fillWidth: true
|
||||
|
||||
currentIndex: (ServersModel.getProcessedServerData("isServerFromApi")
|
||||
&& !ServersModel.getProcessedServerData("hasInstalledContainers")) ? 2 : 0
|
||||
currentIndex: (ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||
&& !ServersModel.getProcessedServerData("hasInstalledContainers")) ?
|
||||
root.pageSettingsServerData : root.pageSettingsServerProtocols
|
||||
|
||||
background: Rectangle {
|
||||
color: AmneziaStyle.color.transparent
|
||||
}
|
||||
|
||||
visible: !ServersModel.getProcessedServerData("isServerFromGatewayApi")
|
||||
|
||||
activeFocusOnTab: true
|
||||
onFocusChanged: {
|
||||
if (activeFocus) {
|
||||
|
|
@ -190,45 +216,53 @@ PageType {
|
|||
id: protocolsTab
|
||||
visible: protocolsPage.installedProtocolsCount
|
||||
width: protocolsPage.installedProtocolsCount ? undefined : 0
|
||||
isSelected: tabBar.currentIndex === 0
|
||||
isSelected: tabBar.currentIndex === root.pageSettingsServerProtocols
|
||||
text: qsTr("Protocols")
|
||||
|
||||
KeyNavigation.tab: servicesTab
|
||||
Keys.onReturnPressed: tabBar.currentIndex = 0
|
||||
Keys.onEnterPressed: tabBar.currentIndex = 0
|
||||
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerProtocols
|
||||
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerProtocols
|
||||
}
|
||||
|
||||
TabButtonType {
|
||||
id: servicesTab
|
||||
visible: servicesPage.installedServicesCount
|
||||
width: servicesPage.installedServicesCount ? undefined : 0
|
||||
isSelected: tabBar.currentIndex === 1
|
||||
isSelected: tabBar.currentIndex === root.pageSettingsServerServices
|
||||
text: qsTr("Services")
|
||||
|
||||
KeyNavigation.tab: dataTab
|
||||
Keys.onReturnPressed: tabBar.currentIndex = 1
|
||||
Keys.onEnterPressed: tabBar.currentIndex = 1
|
||||
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerServices
|
||||
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerServices
|
||||
}
|
||||
|
||||
TabButtonType {
|
||||
id: dataTab
|
||||
isSelected: tabBar.currentIndex === 2
|
||||
isSelected: tabBar.currentIndex === root.pageSettingsServerData
|
||||
text: qsTr("Management")
|
||||
|
||||
Keys.onReturnPressed: tabBar.currentIndex = 2
|
||||
Keys.onEnterPressed: tabBar.currentIndex = 2
|
||||
KeyNavigation.tab: stackView.currentIndex === 0 ?
|
||||
protocolsPage :
|
||||
stackView.currentIndex === 1 ?
|
||||
servicesPage :
|
||||
dataPage
|
||||
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerData
|
||||
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerData
|
||||
Keys.onTabPressed: function() {
|
||||
if (nestedStackView.currentIndex === root.pageSettingsServerProtocols) {
|
||||
return protocolsPage
|
||||
} else if (nestedStackView.currentIndex === root.pageSettingsServerProtocols) {
|
||||
return servicesPage
|
||||
} else {
|
||||
return dataPage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: stackView
|
||||
id: nestedStackView
|
||||
Layout.preferredWidth: root.width
|
||||
Layout.preferredHeight: root.height - tabBar.implicitHeight - header.implicitHeight
|
||||
|
||||
currentIndex: tabBar.currentIndex
|
||||
currentIndex: ServersModel.getProcessedServerData("isServerFromGatewayApi") ?
|
||||
(ServersModel.getProcessedServerData("isCountrySelectionAvailable") ?
|
||||
root.pageSettingsApiLanguageList : root.pageSettingsApiServerInfo) : tabBar.currentIndex
|
||||
|
||||
PageSettingsServerProtocols {
|
||||
id: protocolsPage
|
||||
|
|
@ -236,18 +270,34 @@ PageType {
|
|||
|
||||
onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
|
||||
}
|
||||
|
||||
PageSettingsServerServices {
|
||||
id: servicesPage
|
||||
stackView: root.stackView
|
||||
|
||||
onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
|
||||
}
|
||||
|
||||
PageSettingsServerData {
|
||||
id: dataPage
|
||||
stackView: root.stackView
|
||||
|
||||
onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
|
||||
}
|
||||
|
||||
PageSettingsApiServerInfo {
|
||||
id: apiInfoPage
|
||||
stackView: root.stackView
|
||||
|
||||
// onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
|
||||
}
|
||||
|
||||
PageSettingsApiLanguageList {
|
||||
id: apiLanguageListPage
|
||||
stackView: root.stackView
|
||||
|
||||
// onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ PageType {
|
|||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
||||
textColor: AmneziaStyle.color.red
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import PageEnum 1.0
|
|||
import ProtocolEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import ContainersModelFilters 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import PageEnum 1.0
|
|||
import ProtocolEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import ContainersModelFilters 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import SortFilterProxyModel 0.2
|
|||
import PageEnum 1.0
|
||||
import ProtocolEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
@ -119,7 +120,11 @@ PageType {
|
|||
servicesNameString += servicesName[i] + " · "
|
||||
}
|
||||
|
||||
return servicesNameString + hostName
|
||||
if (ServersModel.isServerFromApi(index)) {
|
||||
return servicesNameString + serverDescription
|
||||
} else {
|
||||
return servicesNameString + hostName
|
||||
}
|
||||
}
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
|
||||
property var isServerFromTelegramApi: ServersModel.getDefaultServerData("isServerFromTelegramApi")
|
||||
|
||||
defaultActiveFocusItem: searchField.textField
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ PageType {
|
|||
if (ConnectionController.isConnected) {
|
||||
PageController.showNotificationMessage(qsTr("Cannot change split tunneling settings during active connection"))
|
||||
root.pageEnabled = false
|
||||
} else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && isServerFromApi) {
|
||||
} else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling) {
|
||||
PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function"))
|
||||
root.pageEnabled = false
|
||||
} else {
|
||||
|
|
@ -266,7 +266,7 @@ PageType {
|
|||
text: url
|
||||
descriptionText: ip
|
||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||
rightImageColor: AmneziaStyle.color.white
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove ") + url + "?"
|
||||
|
|
@ -300,7 +300,7 @@ PageType {
|
|||
Rectangle {
|
||||
anchors.fill: addSiteButton
|
||||
anchors.bottomMargin: -24
|
||||
color: AmneziaStyle.color.black
|
||||
color: AmneziaStyle.color.midnightBlack
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ PageType {
|
|||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/more-vertical.svg"
|
||||
imageColor: AmneziaStyle.color.white
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
onClicked: function () {
|
||||
moreActionsDrawer.open()
|
||||
|
|
|
|||
154
client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml
Normal file
154
client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
Layout.topMargin: 20
|
||||
// KeyNavigation.tab: fileButton.rightButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 32
|
||||
|
||||
headerText: ApiServicesModel.getSelectedServiceData("name")
|
||||
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/map-pin.svg"
|
||||
leftText: qsTr("For the region")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("region")
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/tag.svg"
|
||||
leftText: qsTr("Price")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("price")
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/history.svg"
|
||||
leftText: qsTr("Work period")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("workPeriod")
|
||||
|
||||
visible: rightText !== ""
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/gauge.svg"
|
||||
leftText: qsTr("Speed")
|
||||
rightText: ApiServicesModel.getSelectedServiceData("speed")
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: "qrc:/images/controls/info.svg"
|
||||
leftText: qsTr("Features")
|
||||
rightText: ""
|
||||
}
|
||||
|
||||
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")
|
||||
return text.replace("%1", LanguageModel.getCurrentSiteUrl())
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: continueButton
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
anchors.topMargin: 32
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
anchors.bottomMargin: 32
|
||||
|
||||
text: qsTr("Connect")
|
||||
|
||||
clickedFunc: function() {
|
||||
var endpoint = ApiServicesModel.getStoreEndpoint()
|
||||
if (endpoint !== undefined && endpoint !== "") {
|
||||
Qt.openUrlExternally(endpoint)
|
||||
PageController.closePage()
|
||||
PageController.closePage()
|
||||
} else {
|
||||
PageController.showBusyIndicator(true)
|
||||
InstallController.installServiceFromApi()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
Normal file
100
client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
Layout.topMargin: 20
|
||||
// KeyNavigation.tab: fileButton.rightButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 32
|
||||
|
||||
headerText: qsTr("VPN by Amnezia")
|
||||
descriptionText: qsTr("Choose a VPN service that suits your needs.")
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: containers
|
||||
width: parent.width
|
||||
height: containers.contentItem.height
|
||||
spacing: 16
|
||||
|
||||
currentIndex: 1
|
||||
interactive: false
|
||||
model: ApiServicesModel
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: containers.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
CardWithIconsType {
|
||||
id: card
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: name
|
||||
bodyText: cardDescription
|
||||
footerText: price
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
onClicked: {
|
||||
ApiServicesModel.setServiceIndex(index)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import QtQuick.Layouts
|
|||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
@ -17,7 +18,9 @@ PageType {
|
|||
target: ImportController
|
||||
|
||||
function onQrDecodingFinished() {
|
||||
PageController.closePage()
|
||||
if (Qt.platform.os === "ios") {
|
||||
PageController.closePage()
|
||||
}
|
||||
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
}
|
||||
}
|
||||
|
|
@ -41,46 +44,163 @@ PageType {
|
|||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
KeyNavigation.tab: textKey.textField
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
Layout.topMargin: 20
|
||||
KeyNavigation.tab: fileButton.rightButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.topMargin: 24
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Server connection")
|
||||
descriptionText: qsTr("Do not use connection codes from untrusted sources, as they may be created to intercept your data.")
|
||||
headerText: qsTr("Connection")
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
text: qsTr("Insert the key, add a configuration file or scan the QR-code")
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: textKey
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 48
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
text: qsTr("What do you have?")
|
||||
headerText: qsTr("Insert key")
|
||||
buttonText: qsTr("Insert")
|
||||
|
||||
clickedFunc: function() {
|
||||
textField.text = ""
|
||||
textField.paste()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: continueButton
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: fileButton
|
||||
BasicButtonType {
|
||||
id: continueButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
visible: textKey.textFieldText !== ""
|
||||
|
||||
text: qsTr("Continue")
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
if (ImportController.extractConfigFromData(textKey.textFieldText)) {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
color: AmneziaStyle.color.charcoalGray
|
||||
text: qsTr("Other connection options")
|
||||
}
|
||||
|
||||
CardWithIconsType {
|
||||
id: apiInstalling
|
||||
|
||||
visible: false
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
headerText: qsTr("VPN by Amnezia")
|
||||
bodyText: qsTr("Connect to classic paid and free VPN services from Amnezia")
|
||||
|
||||
text: !ServersModel.getServersCount() ? qsTr("File with connection settings or backup") : qsTr("File with connection settings")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/folder-open.svg"
|
||||
leftImageSource: "qrc:/images/controls/amnezia.svg"
|
||||
|
||||
KeyNavigation.tab: qrButton.visible ? qrButton.rightButton : textButton.rightButton
|
||||
onClicked: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
var result = InstallController.fillAvailableServices()
|
||||
PageController.showBusyIndicator(false)
|
||||
if (result) {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardApiServicesList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
CardWithIconsType {
|
||||
id: manualInstalling
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
headerText: qsTr("Self-hosted VPN")
|
||||
bodyText: qsTr("Configure Amnezia VPN on your own server")
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/server.svg"
|
||||
|
||||
onClicked: {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
|
||||
}
|
||||
}
|
||||
|
||||
CardWithIconsType {
|
||||
id: backupRestore
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: PageController.isStartPageVisible()
|
||||
|
||||
headerText: qsTr("Restore from backup")
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/archive-restore.svg"
|
||||
|
||||
onClicked: {
|
||||
var filePath = SystemController.getFileName(qsTr("Open backup file"),
|
||||
qsTr("Backup files (*.backup)"))
|
||||
if (filePath !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SettingsController.restoreAppConfig(filePath)
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CardWithIconsType {
|
||||
id: openFile
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
headerText: qsTr("File with connection settings")
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/folder-search-2.svg"
|
||||
|
||||
onClicked: {
|
||||
var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" :
|
||||
"Config files (*.vpn *.ovpn *.conf *.json)"
|
||||
var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter)
|
||||
|
|
@ -92,20 +212,22 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
CardWithIconsType {
|
||||
id: scanQr
|
||||
|
||||
LabelWithButtonType {
|
||||
id: qrButton
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: SettingsController.isCameraPresent()
|
||||
|
||||
text: qsTr("QR code")
|
||||
headerText: qsTr("QR code")
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/qr-code.svg"
|
||||
leftImageSource: "qrc:/images/controls/scan-line.svg"
|
||||
|
||||
KeyNavigation.tab: textButton.rightButton
|
||||
|
||||
clickedFunction: function() {
|
||||
onClicked: {
|
||||
ImportController.startDecodingQr()
|
||||
if (Qt.platform.os === "ios") {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardQrReader)
|
||||
|
|
@ -113,26 +235,25 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: SettingsController.isCameraPresent()
|
||||
}
|
||||
CardWithIconsType {
|
||||
id: siteLink
|
||||
|
||||
LabelWithButtonType {
|
||||
id: textButton
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: PageController.isStartPageVisible()
|
||||
|
||||
headerText: qsTr("I have nothing")
|
||||
|
||||
text: qsTr("Key as text")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/text-cursor.svg"
|
||||
leftImageSource: "qrc:/images/controls/help-circle.svg"
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardTextKey)
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import QtQuick.Controls
|
|||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
@ -142,6 +143,23 @@ PageType {
|
|||
|
||||
text: qsTr("All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties")
|
||||
}
|
||||
|
||||
CardWithIconsType {
|
||||
id: siteLink
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
headerText: qsTr("How to run your VPN server")
|
||||
bodyText: qsTr("Where to get connection data, step-by-step instructions for buying a VPS")
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/help-circle.svg"
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/starter-guide")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,10 +187,10 @@ PageType {
|
|||
anchors.bottomMargin: 24
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.blackHovered
|
||||
pressedColor: AmneziaStyle.color.blackPressed
|
||||
disabledColor: AmneziaStyle.color.grey
|
||||
textColor: AmneziaStyle.color.white
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
|
|
@ -46,14 +47,7 @@ PageType {
|
|||
ServersModel.processedIndex = ServersModel.defaultIndex
|
||||
}
|
||||
|
||||
PageController.goToStartPage()
|
||||
if (stackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageSetupWizardStart)) {
|
||||
PageController.replaceStartPage()
|
||||
}
|
||||
if (stackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageHome)) {
|
||||
PageController.goToPageHome()
|
||||
}
|
||||
|
||||
PageController.goToPageHome()
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue