added functionality to change app language via settings

This commit is contained in:
vladimir.kuznetsov 2023-06-30 10:40:43 +09:00
parent d0c9c1043c
commit 464d77dfb5
42 changed files with 3333 additions and 1677 deletions

View file

@ -21,13 +21,10 @@ set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "Autogen")
set(PACKAGES set(PACKAGES
Widgets Core Gui Network Xml Widgets Core Gui Network Xml
RemoteObjects Quick Svg QuickControls2 RemoteObjects Quick Svg QuickControls2
Core5Compat Concurrent Core5Compat Concurrent LinguistTools
) )
if(IOS) if(IOS)
set(PACKAGES set(PACKAGES ${PACKAGES} Multimedia)
${PACKAGES}
Multimedia
)
endif() endif()
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES}) find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
@ -38,11 +35,9 @@ set(LIBS ${LIBS}
Qt6::Quick Qt6::Svg Qt6::QuickControls2 Qt6::Quick Qt6::Svg Qt6::QuickControls2
Qt6::Core5Compat Qt6::Concurrent Qt6::Core5Compat Qt6::Concurrent
) )
if(IOS) if(IOS)
set(LIBS set(LIBS ${LIBS} Qt6::Multimedia)
${LIBS}
Qt6::Multimedia
)
endif() endif()
qt_standard_project_setup() qt_standard_project_setup()
@ -349,6 +344,7 @@ if(CMAKE_OSX_SYSROOT STREQUAL "iphoneos")
endif() endif()
qt_add_executable(${PROJECT} ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC}) qt_add_executable(${PROJECT} ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC})
qt_add_translations(${PROJECT} TS_FILES qt_add_translations(${PROJECT} TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts) ${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts)

View file

@ -3,12 +3,11 @@
#include <QClipboard> #include <QClipboard>
#include <QFontDatabase> #include <QFontDatabase>
#include <QMimeData> #include <QMimeData>
#include <QQuickStyle>
#include <QStandardPaths> #include <QStandardPaths>
#include <QTextDocument> #include <QTextDocument>
#include <QTimer> #include <QTimer>
#include <QTranslator> #include <QTranslator>
#include <QQuickStyle>
#include "core/servercontroller.h" #include "core/servercontroller.h"
#include "logger.h" #include "logger.h"
@ -88,6 +87,10 @@ void AmneziaApplication::init()
connect(m_serversModel.get(), &ServersModel::currentlyProcessedServerIndexChanged, m_containersModel.get(), connect(m_serversModel.get(), &ServersModel::currentlyProcessedServerIndexChanged, m_containersModel.get(),
&ContainersModel::setCurrentlyProcessedServerIndex); &ContainersModel::setCurrentlyProcessedServerIndex);
m_languageModel.reset(new LanguageModel(m_settings, this));
m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
connect(m_languageModel.get(), &LanguageModel::updateTranslations, this, &AmneziaApplication::updateTranslator);
m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, this)); m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, this));
m_vpnConnection.reset(new VpnConnection(m_settings, m_configurator)); m_vpnConnection.reset(new VpnConnection(m_settings, m_configurator));
@ -130,18 +133,16 @@ void AmneziaApplication::init()
// m_uiLogic->showOnStartup(); // m_uiLogic->showOnStartup();
// #endif // #endif
#endif // // TODO - fix
// #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
// TODO - fix // if (isPrimary()) {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) // QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){
if (isPrimary()) { // qDebug() << "Secondary instance started, showing this window instead";
QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){ // emit m_uiLogic->show();
qDebug() << "Secondary instance started, showing this window instead"; // emit m_uiLogic->raise();
emit m_uiLogic->show(); // });
emit m_uiLogic->raise(); // }
}); // #endif
}
#endif
// Android TextField clipboard workaround // Android TextField clipboard workaround
// https://bugreports.qt.io/browse/QTBUG-113461 // https://bugreports.qt.io/browse/QTBUG-113461
@ -195,12 +196,27 @@ void AmneziaApplication::loadFonts()
void AmneziaApplication::loadTranslator() void AmneziaApplication::loadTranslator()
{ {
auto locale = m_settings->getAppLanguage();
m_translator = new QTranslator; m_translator = new QTranslator;
if (m_translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) { if (m_translator->load(locale, QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/i18n"))) {
installTranslator(m_translator); installTranslator(m_translator);
} }
} }
void AmneziaApplication::updateTranslator(const QLocale &locale)
{
QResource::registerResource(":/translations.qrc");
if (!m_translator->isEmpty())
QCoreApplication::removeTranslator(m_translator);
if (m_translator->load(locale, QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/i18n"))) {
if (QCoreApplication::installTranslator(m_translator)) {
m_settings->setAppLanguage(locale);
}
m_engine->retranslate();
}
}
bool AmneziaApplication::parseCommands() bool AmneziaApplication::parseCommands()
{ {
m_parser.setApplicationDescription(APPLICATION_NAME); m_parser.setApplicationDescription(APPLICATION_NAME);

View file

@ -20,11 +20,11 @@
#include "ui/controllers/pageController.h" #include "ui/controllers/pageController.h"
#include "ui/controllers/settingsController.h" #include "ui/controllers/settingsController.h"
#include "ui/models/containers_model.h" #include "ui/models/containers_model.h"
#include "ui/models/languageModel.h"
#include "ui/models/servers_model.h" #include "ui/models/servers_model.h"
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance())) #define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#define AMNEZIA_BASE_CLASS QApplication #define AMNEZIA_BASE_CLASS QApplication
#else #else
@ -41,7 +41,8 @@ public:
AmneziaApplication(int &argc, char *argv[]); AmneziaApplication(int &argc, char *argv[]);
#else #else
AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false, AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false,
SingleApplication::Options options = SingleApplication::User, int timeout = 1000, const QString &userData = {} ); SingleApplication::Options options = SingleApplication::User, int timeout = 1000,
const QString &userData = {});
#endif #endif
virtual ~AmneziaApplication(); virtual ~AmneziaApplication();
@ -49,6 +50,7 @@ public:
void registerTypes(); void registerTypes();
void loadFonts(); void loadFonts();
void loadTranslator(); void loadTranslator();
void updateTranslator(const QLocale &locale);
bool parseCommands(); bool parseCommands();
QQmlApplicationEngine *qmlEngine() const; QQmlApplicationEngine *qmlEngine() const;
@ -66,6 +68,7 @@ private:
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QScopedPointer<LanguageModel> m_languageModel;
QSharedPointer<VpnConnection> m_vpnConnection; QSharedPointer<VpnConnection> m_vpnConnection;

View file

@ -1,6 +1,5 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>translations/amneziavpn_ru.qm</file>
<file>images/close.png</file> <file>images/close.png</file>
<file>images/settings.png</file> <file>images/settings.png</file>
<file>images/favorites_disabled.png</file> <file>images/favorites_disabled.png</file>
@ -270,6 +269,6 @@
<file>images/controls/telegram.svg</file> <file>images/controls/telegram.svg</file>
<file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file> <file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file>
<file>ui/qml/Filters/ContainersModelFilters.qml</file> <file>ui/qml/Filters/ContainersModelFilters.qml</file>
<file>ui/qml/Components/ShowDetailsDrawer.qml</file> <file>ui/qml/Components/SelectLanguageDrawer.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -2,15 +2,15 @@
#define SETTINGS_H #define SETTINGS_H
#include <QObject> #include <QObject>
#include <QString>
#include <QSettings> #include <QSettings>
#include <QString>
#include <QJsonDocument>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include "core/defs.h"
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
#include "core/defs.h"
#include "secure_qsettings.h" #include "secure_qsettings.h"
using namespace amnezia; using namespace amnezia;
@ -27,8 +27,14 @@ public:
ServerCredentials defaultServerCredentials() const; ServerCredentials defaultServerCredentials() const;
ServerCredentials serverCredentials(int index) const; ServerCredentials serverCredentials(int index) const;
QJsonArray serversArray() const { return QJsonDocument::fromJson(m_settings.value("Servers/serversList").toByteArray()).array(); } QJsonArray serversArray() const
void setServersArray(const QJsonArray &servers) { m_settings.setValue("Servers/serversList", QJsonDocument(servers).toJson()); } {
return QJsonDocument::fromJson(m_settings.value("Servers/serversList").toByteArray()).array();
}
void setServersArray(const QJsonArray &servers)
{
m_settings.setValue("Servers/serversList", QJsonDocument(servers).toJson());
}
// Servers section // Servers section
int serversCount() const; int serversCount() const;
@ -37,9 +43,18 @@ public:
void removeServer(int index); void removeServer(int index);
bool editServer(int index, const QJsonObject &server); bool editServer(int index, const QJsonObject &server);
int defaultServerIndex() const { return m_settings.value("Servers/defaultServerIndex", 0).toInt(); } int defaultServerIndex() const
void setDefaultServer(int index) { m_settings.setValue("Servers/defaultServerIndex", index); } {
QJsonObject defaultServer() const { return server(defaultServerIndex()); } return m_settings.value("Servers/defaultServerIndex", 0).toInt();
}
void setDefaultServer(int index)
{
m_settings.setValue("Servers/defaultServerIndex", index);
}
QJsonObject defaultServer() const
{
return server(defaultServerIndex());
}
void setDefaultContainer(int serverIndex, DockerContainer container); void setDefaultContainer(int serverIndex, DockerContainer container);
DockerContainer defaultContainer(int serverIndex) const; DockerContainer defaultContainer(int serverIndex) const;
@ -61,13 +76,28 @@ public:
QString nextAvailableServerName() const; QString nextAvailableServerName() const;
// App settings section // App settings section
bool isAutoConnect() const { return m_settings.value("Conf/autoConnect", false).toBool(); } bool isAutoConnect() const
void setAutoConnect(bool enabled) { m_settings.setValue("Conf/autoConnect", enabled); } {
return m_settings.value("Conf/autoConnect", false).toBool();
}
void setAutoConnect(bool enabled)
{
m_settings.setValue("Conf/autoConnect", enabled);
}
bool isStartMinimized() const { return m_settings.value("Conf/startMinimized", false).toBool(); } bool isStartMinimized() const
void setStartMinimized(bool enabled) { m_settings.setValue("Conf/startMinimized", enabled); } {
return m_settings.value("Conf/startMinimized", false).toBool();
}
void setStartMinimized(bool enabled)
{
m_settings.setValue("Conf/startMinimized", enabled);
}
bool isSaveLogs() const { return m_settings.value("Conf/saveLogs", false).toBool(); } bool isSaveLogs() const
{
return m_settings.value("Conf/saveLogs", false).toBool();
}
void setSaveLogs(bool enabled); void setSaveLogs(bool enabled);
enum RouteMode { enum RouteMode {
@ -79,11 +109,24 @@ public:
QString routeModeString(RouteMode mode) const; QString routeModeString(RouteMode mode) const;
RouteMode routeMode() const { return static_cast<RouteMode>(m_settings.value("Conf/routeMode", 0).toInt()); } RouteMode routeMode() const
void setRouteMode(RouteMode mode) { m_settings.setValue("Conf/routeMode", mode); } {
return static_cast<RouteMode>(m_settings.value("Conf/routeMode", 0).toInt());
}
void setRouteMode(RouteMode mode)
{
m_settings.setValue("Conf/routeMode", mode);
}
QVariantMap vpnSites(RouteMode mode) const { return m_settings.value("Conf/" + routeModeString(mode)).toMap(); } QVariantMap vpnSites(RouteMode mode) const
void setVpnSites(RouteMode mode, const QVariantMap &sites) { m_settings.setValue("Conf/"+ routeModeString(mode), sites); m_settings.sync(); } {
return m_settings.value("Conf/" + routeModeString(mode)).toMap();
}
void setVpnSites(RouteMode mode, const QVariantMap &sites)
{
m_settings.setValue("Conf/" + routeModeString(mode), sites);
m_settings.sync();
}
void addVpnSite(RouteMode mode, const QString &site, const QString &ip = ""); void addVpnSite(RouteMode mode, const QString &site, const QString &ip = "");
void addVpnSites(RouteMode mode, const QMap<QString, QString> &sites); // map <site, ip> void addVpnSites(RouteMode mode, const QMap<QString, QString> &sites); // map <site, ip>
QStringList getVpnIps(RouteMode mode) const; QStringList getVpnIps(RouteMode mode) const;
@ -92,17 +135,29 @@ public:
void addVpnIps(RouteMode mode, const QStringList &ip); void addVpnIps(RouteMode mode, const QStringList &ip);
void removeVpnSites(RouteMode mode, const QStringList &sites); void removeVpnSites(RouteMode mode, const QStringList &sites);
bool useAmneziaDns() const { return m_settings.value("Conf/useAmneziaDns", true).toBool(); } bool useAmneziaDns() const
void setUseAmneziaDns(bool enabled) { m_settings.setValue("Conf/useAmneziaDns", enabled); } {
return m_settings.value("Conf/useAmneziaDns", true).toBool();
}
void setUseAmneziaDns(bool enabled)
{
m_settings.setValue("Conf/useAmneziaDns", enabled);
}
QString primaryDns() const; QString primaryDns() const;
QString secondaryDns() const; QString secondaryDns() const;
// QString primaryDns() const { return m_primaryDns; } // QString primaryDns() const { return m_primaryDns; }
void setPrimaryDns(const QString &primaryDns) { m_settings.setValue("Conf/primaryDns", primaryDns); } void setPrimaryDns(const QString &primaryDns)
{
m_settings.setValue("Conf/primaryDns", primaryDns);
}
// QString secondaryDns() const { return m_secondaryDns; } // QString secondaryDns() const { return m_secondaryDns; }
void setSecondaryDns(const QString &secondaryDns) { m_settings.setValue("Conf/secondaryDns", secondaryDns); } void setSecondaryDns(const QString &secondaryDns)
{
m_settings.setValue("Conf/secondaryDns", secondaryDns);
}
static const char cloudFlareNs1[]; static const char cloudFlareNs1[];
static const char cloudFlareNs2[]; static const char cloudFlareNs2[];
@ -110,15 +165,29 @@ public:
// static constexpr char openNicNs5[] = "94.103.153.176"; // static constexpr char openNicNs5[] = "94.103.153.176";
// static constexpr char openNicNs13[] = "144.76.103.143"; // static constexpr char openNicNs13[] = "144.76.103.143";
QByteArray backupAppConfig() const { return m_settings.backupAppConfig(); } QByteArray backupAppConfig() const
bool restoreAppConfig(const QByteArray &cfg) { return m_settings.restoreAppConfig(cfg); } {
return m_settings.backupAppConfig();
}
bool restoreAppConfig(const QByteArray &cfg)
{
return m_settings.restoreAppConfig(cfg);
}
QLocale getAppLanguage()
{
return m_settings.value("Conf/appLanguage", QLocale()).toLocale();
};
void setAppLanguage(QLocale locale)
{
m_settings.setValue("Conf/appLanguage", locale);
};
signals: signals:
void saveLogsChanged(); void saveLogsChanged();
private: private:
SecureQSettings m_settings; SecureQSettings m_settings;
}; };
#endif // SETTINGS_H #endif // SETTINGS_H

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -2,9 +2,9 @@
#include <QStandardPaths> #include <QStandardPaths>
#include "defines.h"
#include "logger.h" #include "logger.h"
#include "utilities.h" #include "utilities.h"
#include "version.h"
SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel, SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, const QSharedPointer<ContainersModel> &containersModel,

View file

@ -0,0 +1,62 @@
#include "languageModel.h"
LanguageModel::LanguageModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent)
{
QMetaEnum metaEnum = QMetaEnum::fromType<LanguageSettings::AvailableLanguageEnum>();
for (int i = 0; i < metaEnum.keyCount(); i++) {
m_availableLanguages.push_back(
LanguageModelData { metaEnum.valueToKey(i), static_cast<LanguageSettings::AvailableLanguageEnum>(i) });
}
}
int LanguageModel::rowCount(const QModelIndex &parent) const
{
return static_cast<int>(m_availableLanguages.size());
}
QVariant LanguageModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_availableLanguages.size())) {
return QVariant();
}
switch (role) {
case NameRole: {
return m_availableLanguages[index.row()].name;
break;
}
case IndexRole: {
return static_cast<int>(m_availableLanguages[index.row()].index);
break;
}
}
return QVariant();
}
QHash<int, QByteArray> LanguageModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "languageName";
roles[IndexRole] = "languageIndex";
return roles;
}
void LanguageModel::changeLanguage(const LanguageSettings::AvailableLanguageEnum language)
{
switch (language) {
case LanguageSettings::AvailableLanguageEnum::English: emit updateTranslations(QLocale::English); break;
case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break;
default: emit updateTranslations(QLocale::English); break;
}
}
int LanguageModel::getCurrentLanguageIndex()
{
auto locale = m_settings->getAppLanguage();
switch (locale.language()) {
case QLocale::English: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
case QLocale::Russian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Russian); break;
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
}
}

View file

@ -0,0 +1,62 @@
#ifndef LANGUAGEMODEL_H
#define LANGUAGEMODEL_H
#include <QAbstractListModel>
#include <QQmlEngine>
#include "settings.h"
namespace LanguageSettings
{
Q_NAMESPACE
enum class AvailableLanguageEnum {
English,
Russian
};
Q_ENUM_NS(AvailableLanguageEnum)
static void declareQmlAvailableLanguageEnum()
{
qmlRegisterUncreatableMetaObject(LanguageSettings::staticMetaObject, "AvailableLanguageEnum", 1, 0,
"AvailableLanguageEnum", QString());
}
}
struct LanguageModelData
{
QString name;
LanguageSettings::AvailableLanguageEnum index;
};
class LanguageModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
NameRole = Qt::UserRole + 1,
IndexRole
};
LanguageModel(std::shared_ptr<Settings> settings, 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 changeLanguage(const LanguageSettings::AvailableLanguageEnum language);
int getCurrentLanguageIndex();
signals:
void updateTranslations(const QLocale &locale);
protected:
QHash<int, QByteArray> roleNames() const override;
private:
QVector<LanguageModelData> m_availableLanguages;
std::shared_ptr<Settings> m_settings;
};
#endif // LANGUAGEMODEL_H

View file

@ -18,12 +18,14 @@ DrawerType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
spacing: 0
Header2TextType { Header2TextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.bottomMargin: 32
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: "Данные для подключения" text: "Данные для подключения"

View file

@ -0,0 +1,137 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType {
id: root
width: parent.width
height: parent.height * 0.9
ColumnLayout {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
}
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
ColumnLayout {
id: content
anchors.fill: parent
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Choose language")
}
ListView {
id: listView
Layout.fillWidth: true
height: listView.contentItem.height
clip: true
interactive: false
model: LanguageModel
currentIndex: LanguageModel.getCurrentLanguageIndex()
ButtonGroup {
id: buttonGroup
}
delegate: Item {
implicitWidth: root.width
implicitHeight: content.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
RadioButton {
id: radioButton
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
hoverEnabled: true
indicator: Rectangle {
anchors.fill: parent
color: radioButton.hovered ? "#2C2D30" : "#1C1D21"
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
RowLayout {
id: radioButtonContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
z: 1
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
width: 24
height: 24
Layout.rightMargin: 8
}
}
ButtonGroup.group: buttonGroup
checked: listView.currentIndex === index
onClicked: {
listView.currentIndex = index
LanguageModel.changeLanguage(languageIndex)
}
}
}
}
}
}
}
}

View file

@ -105,8 +105,6 @@ DrawerType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 16 anchors.topMargin: 16
backButtonFunction: function() { backButtonFunction: function() {

View file

@ -1,10 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
Item {
}

View file

@ -17,6 +17,7 @@ Item {
id: content id: content
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 8
ImageButtonType { ImageButtonType {
image: backButtonImage image: backButtonImage

View file

@ -1,6 +1,8 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import "TextTypes"
Button { Button {
id: root id: root
@ -46,12 +48,8 @@ Button {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }
contentItem: Text { contentItem: ButtonTextType {
anchors.fill: background anchors.fill: background
font.family: "PT Root UI VF"
font.styleName: "normal"
font.weight: 400
font.pixelSize: 16
color: textColor color: textColor
text: root.text text: root.text
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter

View file

@ -3,6 +3,10 @@ import QtQuick.Layouts
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
height: 1 height: 1
color: "#2C2D30" color: "#2C2D30"
} }

View file

@ -146,8 +146,6 @@ Item {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 16 anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
BackButtonType { BackButtonType {
backButtonImage: root.headerBackButtonImage backButtonImage: root.headerBackButtonImage

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
Text { Text {
height: 24 lineHeight: 24
lineHeightMode: Text.FixedHeight
color: "#D7D8DB" color: "#D7D8DB"
font.pixelSize: 16 font.pixelSize: 16
font.weight: Font.Medium font.weight: 500
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
wrapMode: Text.WordWrap wrapMode: Text.WordWrap

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
Text { Text {
height: 16 lineHeight: 16
lineHeightMode: Text.FixedHeight
color: "#0E0E11" color: "#0E0E11"
font.pixelSize: 13 font.pixelSize: 13
font.weight: Font.Normal font.weight: 400
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
font.letterSpacing: 0.02 font.letterSpacing: 0.02

View file

@ -1,13 +1,14 @@
import QtQuick import QtQuick
Text { Text {
height: 38 lineHeight: 38
lineHeightMode: Text.FixedHeight
color: "#D7D8DB" color: "#D7D8DB"
font.pixelSize: 36 font.pixelSize: 36
font.weight: Font.Bold font.weight: 700
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
font.letterSpacing: -0.03 font.letterSpacing: -1.08
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
Text { Text {
height: 30 lineHeight: 30
lineHeightMode: Text.FixedHeight
color: "#D7D8DB" color: "#D7D8DB"
font.pixelSize: 25 font.pixelSize: 25
font.weight: Font.Bold font.weight: 700
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
wrapMode: Text.WordWrap wrapMode: Text.WordWrap

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
Text { Text {
height: 16 lineHeight: 16
lineHeightMode: Text.FixedHeight
color: "#878B91" color: "#878B91"
font.pixelSize: 13 font.pixelSize: 13
font.weight: Font.Normal font.weight: 400
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
font.letterSpacing: 0.02 font.letterSpacing: 0.02

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
Text { Text {
height: 21.6 lineHeight: 21.6
lineHeightMode: Text.FixedHeight
color: "#D7D8DB" color: "#D7D8DB"
font.pixelSize: 18 font.pixelSize: 18
font.weight: Font.Normal font.weight: 400
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
wrapMode: Text.WordWrap wrapMode: Text.WordWrap

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
Text { Text {
height: 24 lineHeight: 24
lineHeightMode: Text.FixedHeight
color: "#D7D8DB" color: "#D7D8DB"
font.pixelSize: 16 font.pixelSize: 16
font.weight: Font.Normal font.weight: 400
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
wrapMode: Text.WordWrap wrapMode: Text.WordWrap

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
Text { Text {
height: 20 lineHeight: 20
lineHeightMode: Text.FixedHeight
color: "#D7D8DB" color: "#D7D8DB"
font.pixelSize: 14 font.pixelSize: 14
font.weight: Font.Normal font.weight: 400
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
wrapMode: Text.WordWrap wrapMode: Text.WordWrap

View file

@ -19,8 +19,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }

View file

@ -8,6 +8,7 @@ import "./"
import "../Controls2" import "../Controls2"
import "../Config" import "../Config"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Components"
PageType { PageType {
id: root id: root
@ -18,8 +19,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }
@ -52,10 +51,14 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() { clickedFunction: function() {
selectLanguageDrawer.open()
} }
} }
DividerType {} SelectLanguageDrawer {
id: selectLanguageDrawer
}
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true

View file

@ -18,8 +18,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }

View file

@ -17,8 +17,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }

View file

@ -18,8 +18,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }

View file

@ -42,14 +42,14 @@ PageType {
id: content id: content
Layout.topMargin: 20 Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
BackButtonType { BackButtonType {
} }
HeaderType { HeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
actionButtonImage: "qrc:/images/controls/edit-3.svg" actionButtonImage: "qrc:/images/controls/edit-3.svg"

View file

@ -25,14 +25,14 @@ PageType {
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
anchors.leftMargin: 16
anchors.rightMargin: 16
BackButtonType { BackButtonType {
} }
HeaderType { HeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
actionButtonImage: "qrc:/images/controls/plus.svg" actionButtonImage: "qrc:/images/controls/plus.svg"

View file

@ -26,19 +26,18 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
spacing: 0
BackButtonType { BackButtonType {
Layout.topMargin: 20 Layout.topMargin: 20
Layout.rightMargin: 16
Layout.leftMargin: 16
} }
HeaderType { HeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 8
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
headerText: "Подключение к серверу" headerText: "Подключение к серверу"
descriptionText: "Не используйте код подключения из публичных источников. Его могли создать, чтобы перехватывать ваши данные.\n descriptionText: "Не используйте код подключения из публичных источников. Его могли создать, чтобы перехватывать ваши данные.\n
Всё в порядке, если код передал друг." Всё в порядке, если код передал друг."
@ -46,7 +45,7 @@ PageType {
Header2TextType { Header2TextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 48
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16

View file

@ -18,8 +18,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }

View file

@ -36,8 +36,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }

View file

@ -63,6 +63,8 @@ PageType {
id: backButton id: backButton
Layout.topMargin: 20 Layout.topMargin: 20
Layout.rightMargin: -16
Layout.leftMargin: -16
} }
HeaderType { HeaderType {
@ -107,8 +109,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 16 anchors.topMargin: 16
backButtonFunction: function() { backButtonFunction: function() {

View file

@ -42,8 +42,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
spacing: 16 spacing: 16
@ -52,12 +50,24 @@ PageType {
width: parent.width width: parent.width
} }
Item {
width: parent.width
height: header.implicitHeight
HeaderType { HeaderType {
id: header
anchors.fill: parent
anchors.leftMargin: 16
anchors.rightMargin: 16
width: parent.width width: parent.width
headerText: "Протокол подключения" headerText: "Протокол подключения"
descriptionText: "Выберите более приоритетный для вас. Позже можно будет установить остальные протоколы и доп сервисы, вроде DNS-прокси и SFTP." descriptionText: "Выберите более приоритетный для вас. Позже можно будет установить остальные протоколы и доп сервисы, вроде DNS-прокси и SFTP."
} }
}
ListView { ListView {
id: containers id: containers
@ -78,8 +88,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: -16
anchors.leftMargin: -16
LabelWithButtonType { LabelWithButtonType {
id: container id: container

View file

@ -34,6 +34,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
spacing: 0
Image { Image {
id: image id: image

View file

@ -24,8 +24,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 16 spacing: 16
@ -35,6 +33,8 @@ PageType {
HeaderType { HeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Connection key") headerText: qsTr("Connection key")
descriptionText: qsTr("A line that starts with vpn://...") descriptionText: qsTr("A line that starts with vpn://...")
@ -45,6 +45,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Key") headerText: qsTr("Key")
textFieldPlaceholderText: "vpn://" textFieldPlaceholderText: "vpn://"

View file

@ -42,8 +42,6 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20 anchors.topMargin: 20
} }

View file

@ -185,8 +185,6 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 16 anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
BackButtonType { BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg" backButtonImage: "qrc:/images/controls/arrow-left.svg"