From 2ef53c6df9b7d520058dd075c2fb013292ada48a Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Fri, 23 Jun 2023 15:24:40 +0900 Subject: [PATCH] added separation for read/write and readonly servers for pageSettingsServerProtocols, PageSettingsServerServices, PageSettingsServerData - added fields validations for pageSetupWizardCredentials --- client/amnezia_application.cpp | 94 +++++------ client/resources.qrc | 1 + client/ui/controllers/exportController.cpp | 55 +++---- client/ui/controllers/importController.cpp | 70 ++++---- client/ui/controllers/installController.cpp | 3 +- client/ui/models/containers_model.cpp | 2 +- client/ui/models/containers_model.h | 7 +- client/ui/models/servers_model.cpp | 30 ++-- client/ui/models/servers_model.h | 23 ++- client/ui/pages_logic/ServerListLogic.cpp | 38 +++-- .../qml/Controls2/TextFieldWithHeaderType.qml | 151 ++++++++++-------- .../ui/qml/Filters/ContainersModelFilters.qml | 47 ++++++ client/ui/qml/Pages2/PageHome.qml | 46 ++---- .../ui/qml/Pages2/PageSettingsServerData.qml | 29 +++- .../ui/qml/Pages2/PageSettingsServerInfo.qml | 14 +- .../Pages2/PageSettingsServerProtocols.qml | 40 +++-- .../qml/Pages2/PageSettingsServerServices.qml | 40 +++-- .../ui/qml/Pages2/PageSettingsServersList.qml | 3 +- .../qml/Pages2/PageSetupWizardCredentials.qml | 29 ++++ .../qml/Pages2/PageSetupWizardInstalling.qml | 2 +- client/ui/qml/Pages2/PageShare.qml | 40 +++-- client/ui/qml/Pages2/PageStart.qml | 27 +++- 22 files changed, 466 insertions(+), 325 deletions(-) create mode 100644 client/ui/qml/Filters/ContainersModelFilters.qml diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index b9aa0f74..b89e5ba9 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -1,29 +1,28 @@ #include "amnezia_application.h" #include +#include #include #include #include -#include -#include "logger.h" #include "defines.h" +#include "logger.h" #include "platforms/ios/QRCodeReaderBase.h" #include "ui/pages.h" #if defined(Q_OS_IOS) -#include "platforms/ios/QtAppDelegate-C-Interface.h" + #include "platforms/ios/QtAppDelegate-C-Interface.h" #endif #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - AmneziaApplication::AmneziaApplication(int &argc, char *argv[]): - AMNEZIA_BASE_CLASS(argc, argv) +AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv) #else - AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary, - SingleApplication::Options options, int timeout, const QString &userData): - SingleApplication(argc, argv, allowSecondary, options, timeout, userData) +AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary, SingleApplication::Options options, + int timeout, const QString &userData) + : SingleApplication(argc, argv, allowSecondary, options, timeout, userData) #endif { setQuitOnLastWindowClosed(false); @@ -51,12 +50,14 @@ AmneziaApplication::~AmneziaApplication() { if (m_engine) { - QObject::disconnect(m_engine, 0,0,0); + QObject::disconnect(m_engine, 0, 0, 0); delete m_engine; } - if (m_protocolProps) delete m_protocolProps; - if (m_containerProps) delete m_containerProps; + if (m_protocolProps) + delete m_protocolProps; + if (m_containerProps) + delete m_containerProps; } void AmneziaApplication::init() @@ -64,11 +65,13 @@ void AmneziaApplication::init() m_engine = new QQmlApplicationEngine; const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml")); - QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated, - this, [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, Qt::QueuedConnection); + QObject::connect( + m_engine, &QQmlApplicationEngine::objectCreated, this, + [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, + Qt::QueuedConnection); m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance()); @@ -78,6 +81,8 @@ void AmneziaApplication::init() m_serversModel.reset(new ServersModel(m_settings, this)); m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get()); + connect(m_serversModel.get(), &ServersModel::currentlyProcessedServerIndexChanged, m_containersModel.get(), + &ContainersModel::setCurrentlyProcessedServerIndex); m_configurator = std::shared_ptr(new VpnConfigurator(m_settings, this)); m_vpnConnection.reset(new VpnConnection(m_settings, m_configurator)); @@ -94,21 +99,19 @@ void AmneziaApplication::init() m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings)); m_engine->rootContext()->setContextProperty("ImportController", m_importController.get()); - m_exportController.reset( - new ExportController(m_serversModel, m_containersModel, m_settings, m_configurator)); + m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_settings, m_configurator)); m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get()); - m_settingsController.reset( - new SettingsController(m_serversModel, m_containersModel, m_settings)); + m_settingsController.reset(new SettingsController(m_serversModel, m_containersModel, m_settings)); m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get()); // m_engine->load(url); -// if (m_engine->rootObjects().size() > 0) { -// m_uiLogic->setQmlRoot(m_engine->rootObjects().at(0)); -// } + // if (m_engine->rootObjects().size() > 0) { + // m_uiLogic->setQmlRoot(m_engine->rootObjects().at(0)); + // } if (m_settings->isSaveLogs()) { if (!Logger::init()) { @@ -116,24 +119,23 @@ void AmneziaApplication::init() } } -//#ifdef Q_OS_WIN -// if (m_parser.isSet("a")) m_uiLogic->showOnStartup(); -// else emit m_uiLogic->show(); -//#else -// m_uiLogic->showOnStartup(); -//#endif - -// // TODO - fix -//#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -// if (isPrimary()) { -// QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){ -// qDebug() << "Secondary instance started, showing this window instead"; -// emit m_uiLogic->show(); -// emit m_uiLogic->raise(); -// }); -// } -//#endif + // #ifdef Q_OS_WIN + // if (m_parser.isSet("a")) m_uiLogic->showOnStartup(); + // else emit m_uiLogic->show(); + // #else + // m_uiLogic->showOnStartup(); + // #endif + // // TODO - fix + // #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + // if (isPrimary()) { + // QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){ + // qDebug() << "Secondary instance started, showing this window instead"; + // emit m_uiLogic->show(); + // emit m_uiLogic->raise(); + // }); + // } + // #endif } void AmneziaApplication::registerTypes() @@ -156,6 +158,9 @@ void AmneziaApplication::registerTypes() m_protocolProps = new ProtocolProps; qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps); + qmlRegisterSingletonType(QUrl("qrc:/ui/qml/Filters/ContainersModelFilters.qml"), "ContainersModelFilters", 1, 0, + "ContainersModelFilters"); + // Vpn::declareQmlVpnConnectionStateEnum(); PageLoader::declareQmlPageEnum(); @@ -182,19 +187,17 @@ bool AmneziaApplication::parseCommands() m_parser.addHelpOption(); m_parser.addVersionOption(); - QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"}; + QCommandLineOption c_autostart { { "a", "autostart" }, "System autostart" }; m_parser.addOption(c_autostart); - QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"}; + QCommandLineOption c_cleanup { { "c", "cleanup" }, "Cleanup logs" }; m_parser.addOption(c_cleanup); m_parser.process(*this); if (m_parser.isSet(c_cleanup)) { Logger::cleanUp(); - QTimer::singleShot(100, this, [this]{ - quit(); - }); + QTimer::singleShot(100, this, [this] { quit(); }); exec(); return false; } @@ -205,4 +208,3 @@ QQmlApplicationEngine *AmneziaApplication::qmlEngine() const { return m_engine; } - diff --git a/client/resources.qrc b/client/resources.qrc index 5b5fd593..9aba0a6b 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -269,5 +269,6 @@ images/controls/mail.svg images/controls/telegram.svg ui/qml/Controls2/TextTypes/SmallTextType.qml + ui/qml/Filters/ContainersModelFilters.qml diff --git a/client/ui/controllers/exportController.cpp b/client/ui/controllers/exportController.cpp index b6cd7abb..04264624 100644 --- a/client/ui/controllers/exportController.cpp +++ b/client/ui/controllers/exportController.cpp @@ -16,14 +16,14 @@ ExportController::ExportController(const QSharedPointer &serversModel, const QSharedPointer &containersModel, const std::shared_ptr &settings, - const std::shared_ptr &configurator, - QObject *parent) - : QObject(parent) - , m_serversModel(serversModel) - , m_containersModel(containersModel) - , m_settings(settings) - , m_configurator(configurator) -{} + const std::shared_ptr &configurator, QObject *parent) + : QObject(parent), + m_serversModel(serversModel), + m_containersModel(containersModel), + m_settings(settings), + m_configurator(configurator) +{ +} void ExportController::generateFullAccessConfig() { @@ -33,8 +33,8 @@ void ExportController::generateFullAccessConfig() QByteArray compressedConfig = QJsonDocument(config).toJson(); compressedConfig = qCompress(compressedConfig, 8); m_amneziaCode = QString("vpn://%1") - .arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding - | QByteArray::OmitTrailingEquals))); + .arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding + | QByteArray::OmitTrailingEquals))); m_qrCodes = generateQrCodeImageSeries(compressedConfig); emit exportConfigChanged(); @@ -43,25 +43,21 @@ void ExportController::generateFullAccessConfig() void ExportController::generateConnectionConfig() { int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); - ServerCredentials credentials = qvariant_cast( - m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); + ServerCredentials credentials = + qvariant_cast(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); - DockerContainer container = static_cast( - m_containersModel->getCurrentlyProcessedContainerIndex()); + DockerContainer container = static_cast(m_containersModel->getCurrentlyProcessedContainerIndex()); QModelIndex containerModelIndex = m_containersModel->index(container); - QJsonObject containerConfig = qvariant_cast( - m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole)); + QJsonObject containerConfig = + qvariant_cast(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole)); containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); ErrorCode errorCode = ErrorCode::NoError; for (Proto protocol : ContainerProps::protocolsForContainer(container)) { QJsonObject protocolConfig = m_settings->protocolConfig(serverIndex, container, protocol); - QString vpnConfig = m_configurator->genVpnProtocolConfig(credentials, - container, - containerConfig, - protocol, - &errorCode); + QString vpnConfig = + m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol, &errorCode); if (errorCode) { emit exportErrorOccurred(errorString(errorCode)); return; @@ -75,7 +71,7 @@ void ExportController::generateConnectionConfig() config.remove(config_key::userName); config.remove(config_key::password); config.remove(config_key::port); - config.insert(config_key::containers, QJsonArray{containerConfig}); + config.insert(config_key::containers, QJsonArray { containerConfig }); config.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); auto dns = m_configurator->getDnsForConfig(serverIndex); @@ -86,8 +82,8 @@ void ExportController::generateConnectionConfig() QByteArray compressedConfig = QJsonDocument(config).toJson(); compressedConfig = qCompress(compressedConfig, 8); m_amneziaCode = QString("vpn://%1") - .arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding - | QByteArray::OmitTrailingEquals))); + .arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding + | QByteArray::OmitTrailingEquals))); m_qrCodes = generateQrCodeImageSeries(compressedConfig); emit exportConfigChanged(); @@ -108,10 +104,8 @@ void ExportController::saveFile() QString fileExtension = ".vpn"; QString docDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); QUrl fileName; - fileName = QFileDialog::getSaveFileUrl(nullptr, - tr("Save AmneziaVPN config"), - QUrl::fromLocalFile(docDir + "/" + "amnezia_config"), - "*" + fileExtension); + fileName = QFileDialog::getSaveFileUrl(nullptr, tr("Save AmneziaVPN config"), + QUrl::fromLocalFile(docDir + "/" + "amnezia_config"), "*" + fileExtension); if (fileName.isEmpty()) return; if (!fileName.toString().endsWith(fileExtension)) { @@ -139,10 +133,9 @@ QList ExportController::generateQrCodeImageSeries(const QByteArray &dat for (int i = 0; i < data.size(); i = i + k) { QByteArray chunk; QDataStream s(&chunk, QIODevice::WriteOnly); - s << amnezia::qrMagicCode << chunksCount << (quint8) std::round(i / k) << data.mid(i, k); + s << amnezia::qrMagicCode << chunksCount << (quint8)std::round(i / k) << data.mid(i, k); - QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding - | QByteArray::OmitTrailingEquals); + QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba, qrcodegen::QrCode::Ecc::LOW); QString svg = QString::fromStdString(toSvgString(qr, 0)); diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index 99de3131..5b4b7a83 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -5,40 +5,42 @@ #include "core/errorstrings.h" -namespace { -enum class ConfigTypes { Amnezia, OpenVpn, WireGuard }; - -ConfigTypes checkConfigFormat(const QString &config) +namespace { - const QString openVpnConfigPatternCli = "client"; - const QString openVpnConfigPatternProto1 = "proto tcp"; - const QString openVpnConfigPatternProto2 = "proto udp"; - const QString openVpnConfigPatternDriver1 = "dev tun"; - const QString openVpnConfigPatternDriver2 = "dev tap"; + enum class ConfigTypes { + Amnezia, + OpenVpn, + WireGuard + }; - const QString wireguardConfigPatternSectionInterface = "[Interface]"; - const QString wireguardConfigPatternSectionPeer = "[Peer]"; + ConfigTypes checkConfigFormat(const QString &config) + { + const QString openVpnConfigPatternCli = "client"; + const QString openVpnConfigPatternProto1 = "proto tcp"; + const QString openVpnConfigPatternProto2 = "proto udp"; + const QString openVpnConfigPatternDriver1 = "dev tun"; + const QString openVpnConfigPatternDriver2 = "dev tap"; - if (config.contains(openVpnConfigPatternCli) - && (config.contains(openVpnConfigPatternProto1) - || config.contains(openVpnConfigPatternProto2)) - && (config.contains(openVpnConfigPatternDriver1) - || config.contains(openVpnConfigPatternDriver2))) { - return ConfigTypes::OpenVpn; - } else if (config.contains(wireguardConfigPatternSectionInterface) - && config.contains(wireguardConfigPatternSectionPeer)) { - return ConfigTypes::WireGuard; + const QString wireguardConfigPatternSectionInterface = "[Interface]"; + const QString wireguardConfigPatternSectionPeer = "[Peer]"; + + if (config.contains(openVpnConfigPatternCli) + && (config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) + && (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) { + return ConfigTypes::OpenVpn; + } else if (config.contains(wireguardConfigPatternSectionInterface) + && config.contains(wireguardConfigPatternSectionPeer)) { + return ConfigTypes::WireGuard; + } + return ConfigTypes::Amnezia; } - return ConfigTypes::Amnezia; -} } // namespace ImportController::ImportController(const QSharedPointer &serversModel, const QSharedPointer &containersModel, - const std::shared_ptr &settings, - QObject *parent) : QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_settings(settings) + const std::shared_ptr &settings, QObject *parent) + : QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_settings(settings) { - } void ImportController::extractConfigFromFile(const QUrl &fileUrl) @@ -88,8 +90,7 @@ void ImportController::importConfig() m_serversModel->addServer(m_config); if (!m_config.value(config_key::containers).toArray().isEmpty()) { - auto newServerIndex = m_serversModel->index(m_serversModel->getServersCount() - 1); - m_serversModel->setData(newServerIndex, true, ServersModel::Roles::IsDefaultRole); + m_serversModel->setDefaultServerIndex(m_serversModel->getServersCount() - 1); } emit importFinished(); @@ -116,12 +117,12 @@ QJsonObject ImportController::extractAmneziaConfig(QString &data) return QJsonDocument::fromJson(ba).object(); } -//bool ImportController::importConnectionFromQr(const QByteArray &data) +// bool ImportController::importConnectionFromQr(const QByteArray &data) //{ -// QJsonObject dataObj = QJsonDocument::fromJson(data).object(); -// if (!dataObj.isEmpty()) { -// return importConnection(dataObj); -// } +// QJsonObject dataObj = QJsonDocument::fromJson(data).object(); +// if (!dataObj.isEmpty()) { +// return importConnection(dataObj); +// } // QByteArray ba_uncompressed = qUncompress(data); // if (!ba_uncompressed.isEmpty()) { @@ -159,7 +160,6 @@ QJsonObject ImportController::extractOpenVpnConfig(const QString &data) config[config_key::defaultContainer] = "amnezia-openvpn"; config[config_key::description] = m_settings->nextAvailableServerName(); - const static QRegularExpression dnsRegExp("dhcp-option DNS (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)"); QRegularExpressionMatchIterator dnsMatch = dnsRegExp.globalMatch(data); if (dnsMatch.hasNext()) { @@ -206,7 +206,9 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) config[config_key::defaultContainer] = "amnezia-wireguard"; config[config_key::description] = m_settings->nextAvailableServerName(); - const static QRegularExpression dnsRegExp("DNS = (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)"); + const static QRegularExpression dnsRegExp( + "DNS = " + "(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)"); QRegularExpressionMatch dnsMatch = dnsRegExp.match(data); if (dnsMatch.hasMatch()) { config[config_key::dns1] = dnsMatch.captured(1); diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp index 5d3bfc2f..1809e082 100644 --- a/client/ui/controllers/installController.cpp +++ b/client/ui/controllers/installController.cpp @@ -67,8 +67,7 @@ void InstallController::installServer(DockerContainer container, QJsonObject &co server.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); m_serversModel->addServer(server); - auto newServerIndex = m_serversModel->index(m_serversModel->getServersCount() - 1); - m_serversModel->setData(newServerIndex, true, ServersModel::Roles::IsDefaultRole); + m_serversModel->setDefaultServerIndex(m_serversModel->getServersCount() - 1); emit installServerFinished(isInstalledContainerFound); return; diff --git a/client/ui/models/containers_model.cpp b/client/ui/models/containers_model.cpp index f095dd02..7a6946f5 100644 --- a/client/ui/models/containers_model.cpp +++ b/client/ui/models/containers_model.cpp @@ -78,7 +78,7 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const return QVariant(); } -void ContainersModel::setCurrentlyProcessedServerIndex(int index) +void ContainersModel::setCurrentlyProcessedServerIndex(const int index) { beginResetModel(); m_currentlyProcessedServerIndex = index; diff --git a/client/ui/models/containers_model.h b/client/ui/models/containers_model.h index 7bb58755..ebf47497 100644 --- a/client/ui/models/containers_model.h +++ b/client/ui/models/containers_model.h @@ -3,11 +3,11 @@ #include #include -#include #include +#include -#include "settings.h" #include "containers/containers_defs.h" +#include "settings.h" class ContainersModel : public QAbstractListModel { @@ -44,7 +44,7 @@ public slots: DockerContainer getDefaultContainer(); QString getDefaultContainerName(); - void setCurrentlyProcessedServerIndex(int index); + void setCurrentlyProcessedServerIndex(const int index); void setCurrentlyProcessedContainerIndex(int index); int getCurrentlyProcessedContainerIndex(); @@ -57,7 +57,6 @@ protected: private: QMap m_containers; - int m_currentlyProcessedServerIndex; int m_currentlyProcessedContainerIndex; DockerContainer m_defaultContainerIndex; diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index 94267ed1..9df243fe 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -5,6 +5,7 @@ ServersModel::ServersModel(std::shared_ptr settings, QObject *parent) { m_servers = m_settings->serversArray(); m_defaultServerIndex = m_settings->defaultServerIndex(); + m_currenlyProcessedServerIndex = m_defaultServerIndex; } int ServersModel::rowCount(const QModelIndex &parent) const @@ -28,10 +29,6 @@ bool ServersModel::setData(const QModelIndex &index, const QVariant &value, int m_servers.replace(index.row(), server); break; } - case IsDefaultRole: { - setDefaultServerIndex(index.row()); - break; - } default: { return true; } @@ -62,6 +59,10 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const case CredentialsLoginRole: return m_settings->serverCredentials(index.row()).userName; case IsDefaultRole: return index.row() == m_defaultServerIndex; case IsCurrentlyProcessedRole: return index.row() == m_currenlyProcessedServerIndex; + case HasWriteAccess: { + auto credentials = m_settings->serverCredentials(index.row()); + return (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty()); + } } return QVariant(); @@ -73,6 +74,13 @@ QVariant ServersModel::data(const int index, int role) const return data(modelIndex, role); } +void ServersModel::setDefaultServerIndex(const int index) +{ + m_settings->setDefaultServer(index); + m_defaultServerIndex = m_settings->defaultServerIndex(); + emit defaultServerIndexChanged(); +} + const int ServersModel::getDefaultServerIndex() { return m_defaultServerIndex; @@ -83,10 +91,10 @@ const int ServersModel::getServersCount() return m_servers.count(); } -void ServersModel::setCurrentlyProcessedServerIndex(int index) +void ServersModel::setCurrentlyProcessedServerIndex(const int index) { m_currenlyProcessedServerIndex = index; - emit currentlyProcessedServerIndexChanged(); + emit currentlyProcessedServerIndexChanged(m_currenlyProcessedServerIndex); } int ServersModel::getCurrentlyProcessedServerIndex() @@ -101,8 +109,7 @@ bool ServersModel::isDefaultServerCurrentlyProcessed() bool ServersModel::isCurrentlyProcessedServerHasWriteAccess() { - auto credentials = m_settings->serverCredentials(m_currenlyProcessedServerIndex); - return (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty()); + return qvariant_cast(data(m_currenlyProcessedServerIndex, HasWriteAccess)); } void ServersModel::addServer(const QJsonObject &server) @@ -140,11 +147,6 @@ QHash ServersModel::roleNames() const roles[CredentialsLoginRole] = "credentialsLogin"; roles[IsDefaultRole] = "isDefault"; roles[IsCurrentlyProcessedRole] = "isCurrentlyProcessed"; + roles[HasWriteAccess] = "hasWriteAccess"; return roles; } - -void ServersModel::setDefaultServerIndex(const int index) -{ - m_settings->setDefaultServer(index); - m_defaultServerIndex = m_settings->defaultServerIndex(); -} diff --git a/client/ui/models/servers_model.h b/client/ui/models/servers_model.h index 891d6ad1..6cb9859e 100644 --- a/client/ui/models/servers_model.h +++ b/client/ui/models/servers_model.h @@ -5,13 +5,6 @@ #include "settings.h" -struct ServerModelContent -{ - QString desc; - QString address; - bool isDefault; -}; - class ServersModel : public QAbstractListModel { Q_OBJECT @@ -22,7 +15,8 @@ public: CredentialsRole, CredentialsLoginRole, IsDefaultRole, - IsCurrentlyProcessedRole + IsCurrentlyProcessedRole, + HasWriteAccess }; ServersModel(std::shared_ptr settings, QObject *parent = nullptr); @@ -33,14 +27,20 @@ public: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant data(const int index, int role = Qt::DisplayRole) const; + Q_PROPERTY(int defaultIndex READ getDefaultServerIndex WRITE setDefaultServerIndex NOTIFY defaultServerIndexChanged) + Q_PROPERTY(int currentlyProcessedIndex READ getCurrentlyProcessedServerIndex WRITE setCurrentlyProcessedServerIndex + NOTIFY currentlyProcessedServerIndexChanged) + public slots: + void setDefaultServerIndex(const int index); const int getDefaultServerIndex(); bool isDefaultServerCurrentlyProcessed(); + bool isCurrentlyProcessedServerHasWriteAccess(); const int getServersCount(); - void setCurrentlyProcessedServerIndex(int index); + void setCurrentlyProcessedServerIndex(const int index); int getCurrentlyProcessedServerIndex(); void addServer(const QJsonObject &server); @@ -50,11 +50,10 @@ protected: QHash roleNames() const override; signals: - void currentlyProcessedServerIndexChanged(); + void currentlyProcessedServerIndexChanged(const int index); + void defaultServerIndexChanged(); private: - void setDefaultServerIndex(const int index); - QJsonArray m_servers; std::shared_ptr m_settings; diff --git a/client/ui/pages_logic/ServerListLogic.cpp b/client/ui/pages_logic/ServerListLogic.cpp index 56a682b8..16775bc0 100644 --- a/client/ui/pages_logic/ServerListLogic.cpp +++ b/client/ui/pages_logic/ServerListLogic.cpp @@ -1,14 +1,12 @@ #include "ServerListLogic.h" -#include "vpnconnection.h" #include "../models/servers_model.h" #include "../uilogic.h" +#include "vpnconnection.h" -ServerListLogic::ServerListLogic(UiLogic *logic, QObject *parent): - PageLogicBase(logic, parent), - m_serverListModel{new ServersModel(m_settings, this)} +ServerListLogic::ServerListLogic(UiLogic *logic, QObject *parent) + : PageLogicBase(logic, parent), m_serverListModel { new ServersModel(m_settings, this) } { - } void ServerListLogic::onServerListPushbuttonDefaultClicked(int index) @@ -31,19 +29,19 @@ int ServerListLogic::currServerIdx() const void ServerListLogic::onUpdatePage() { - const QJsonArray &servers = m_settings->serversArray(); - int defaultServer = m_settings->defaultServerIndex(); - QVector serverListContent; - for(int i = 0; i < servers.size(); i++) { - ServerModelContent c; - auto server = servers.at(i).toObject(); - c.desc = server.value(config_key::description).toString(); - c.address = server.value(config_key::hostName).toString(); - if (c.desc.isEmpty()) { - c.desc = c.address; - } - c.isDefault = (i == defaultServer); - serverListContent.push_back(c); - } -// qobject_cast(m_serverListModel)->setContent(serverListContent); + // const QJsonArray &servers = m_settings->serversArray(); + // int defaultServer = m_settings->defaultServerIndex(); + // QVector serverListContent; + // for(int i = 0; i < servers.size(); i++) { + // ServerModelContent c; + // auto server = servers.at(i).toObject(); + // c.desc = server.value(config_key::description).toString(); + // c.address = server.value(config_key::hostName).toString(); + // if (c.desc.isEmpty()) { + // c.desc = c.address; + // } + // c.isDefault = (i == defaultServer); + // serverListContent.push_back(c); + // } + // qobject_cast(m_serverListModel)->setContent(serverListContent); } diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml index 8ad92d54..85d651ef 100644 --- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml +++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml @@ -8,96 +8,115 @@ Item { id: root property string headerText - property string textFieldPlaceholderText - property bool textFieldEditable: true + property alias errorText: errorField.text property string buttonText property var clickedFunc property alias textField: textField property alias textFieldText: textField.text + property string textFieldPlaceholderText + property bool textFieldEditable: true - implicitHeight: 74 + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight - Rectangle { - id: backgroud + ColumnLayout { + id: content anchors.fill: parent - color: "#1c1d21" - radius: 16 - border.color: textField.focus ? "#d7d8db" : "#2C2D30" - border.width: 1 - Behavior on border.color { - PropertyAnimation { duration: 200 } - } - } + Rectangle { + id: backgroud + Layout.fillWidth: true + Layout.preferredHeight: 74 + color: "#1c1d21" + radius: 16 + border.color: textField.focus ? "#d7d8db" : "#2C2D30" + border.width: 1 - RowLayout { - anchors.fill: backgroud - ColumnLayout { - - LabelTextType { - text: root.headerText - color: "#878b91" - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.topMargin: 16 + Behavior on border.color { + PropertyAnimation { duration: 200 } } - TextField { - id: textField + RowLayout { + anchors.fill: backgroud + ColumnLayout { + LabelTextType { + text: root.headerText + color: "#878b91" - enabled: root.textFieldEditable - color: "#d7d8db" + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + } - placeholderText: textFieldPlaceholderText - placeholderTextColor: "#494B50" + TextField { + id: textField - selectionColor: "#412102" - selectedTextColor: "#D7D8DB" + enabled: root.textFieldEditable + color: "#d7d8db" - font.pixelSize: 16 - font.weight: 400 - font.family: "PT Root UI VF" + placeholderText: textFieldPlaceholderText + placeholderTextColor: "#494B50" - height: 24 - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: 16 - topPadding: 0 - rightPadding: 0 - leftPadding: 0 - bottomPadding: 0 + selectionColor: "#412102" + selectedTextColor: "#D7D8DB" - background: Rectangle { - anchors.fill: parent - color: "#1c1d21" + font.pixelSize: 16 + font.weight: 400 + font.family: "PT Root UI VF" + + height: 24 + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + bottomPadding: 0 + + background: Rectangle { + anchors.fill: parent + color: "#1c1d21" + } + + onTextChanged: { + root.errorText = "" + } + } + } + + BasicButtonType { + visible: root.buttonText !== "" + + defaultColor: "transparent" + hoveredColor: Qt.rgba(1, 1, 1, 0.08) + pressedColor: Qt.rgba(1, 1, 1, 0.12) + disabledColor: "#878B91" + textColor: "#D7D8DB" + borderWidth: 0 + + text: buttonText + + Layout.rightMargin: 24 + + onClicked: { + if (clickedFunc && typeof clickedFunc === "function") { + clickedFunc() + } + } } } } - BasicButtonType { - visible: root.buttonText !== "" + SmallTextType { + id: errorField - defaultColor: "transparent" - hoveredColor: Qt.rgba(1, 1, 1, 0.08) - pressedColor: Qt.rgba(1, 1, 1, 0.12) - disabledColor: "#878B91" - textColor: "#D7D8DB" - borderWidth: 0 - - text: buttonText - - Layout.rightMargin: 24 - - onClicked: { - if (clickedFunc && typeof clickedFunc === "function") { - clickedFunc() - } - } + text: root.errorText + visible: root.errorText !== "" + color: "#EB5757" } } } diff --git a/client/ui/qml/Filters/ContainersModelFilters.qml b/client/ui/qml/Filters/ContainersModelFilters.qml new file mode 100644 index 00000000..fa8bd83b --- /dev/null +++ b/client/ui/qml/Filters/ContainersModelFilters.qml @@ -0,0 +1,47 @@ +pragma Singleton + +import QtQuick 2.15 + +import SortFilterProxyModel 0.2 + +import ProtocolEnum 1.0 + +Item { + ValueFilter { + id: vpnTypeFilter + roleName: "serviceType" + value: ProtocolEnum.Vpn + } + + ValueFilter { + id: serviceTypeFilter + roleName: "serviceType" + value: ProtocolEnum.Other + } + + ValueFilter { + id: supportedFilter + roleName: "isSupported" + value: true + } + + ValueFilter { + id: installedFilter + roleName: "isInstalled" + value: true + } + + function getWriteAccessProtocolsListFilters() { + return [vpnTypeFilter, supportedFilter] + } + function getReadAccessProtocolsListFilters() { + return [vpnTypeFilter, supportedFilter, installedFilter] + } + + function getWriteAccessServicesListFilters() { + return [serviceTypeFilter, supportedFilter] + } + function getReadAccessServicesListFilters() { + return [serviceTypeFilter, supportedFilter, installedFilter] + } +} diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml index a4e90117..9f121273 100644 --- a/client/ui/qml/Pages2/PageHome.qml +++ b/client/ui/qml/Pages2/PageHome.qml @@ -7,6 +7,7 @@ import SortFilterProxyModel 0.2 import PageEnum 1.0 import ProtocolEnum 1.0 import ContainerProps 1.0 +import ContainersModelFilters 1.0 import "./" import "../Controls2" @@ -161,10 +162,7 @@ PageType { headerBackButtonImage: "qrc:/images/controls/arrow-left.svg" rootButtonClickedFunction: function() { - // todo check if server index changed before set Currently processed - // todo make signal slot for change server index in containersModel - ServersModel.setCurrentlyProcessedServerIndex(serversMenuContent.currentIndex) - ContainersModel.setCurrentlyProcessedServerIndex(serversMenuContent.currentIndex) + ServersModel.currentlyProcessedIndex = serversMenuContent.currentIndex containersDropDown.menuVisible = true } @@ -177,39 +175,22 @@ PageType { function onCurrentlyProcessedServerIndexChanged() { updateContainersModelFilters() } + } - function updateContainersModelFilters() { - if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { - proxyContainersModel.filters = [serviceTypeFilter, supportedFilter] - } else { - proxyContainersModel.filters = installedFilter - } + function updateContainersModelFilters() { + if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { + proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters() + } else { + proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters() } } - ValueFilter { - id: serviceTypeFilter - roleName: "serviceType" - value: ProtocolEnum.Vpn - } - ValueFilter { - id: supportedFilter - roleName: "isSupported" - value: true - } - ValueFilter { - id: installedFilter - roleName: "isInstalled" - value: true - } - model: SortFilterProxyModel { id: proxyContainersModel sourceModel: ContainersModel - - Component.onCompleted: updateContainersModelFilters() } + Component.onCompleted: updateContainersModelFilters() currentIndex: ContainersModel.getDefaultContainer() } } @@ -267,7 +248,7 @@ PageType { height: serversMenuContent.contentItem.height model: ServersModel - currentIndex: ServersModel.getDefaultServerIndex() + currentIndex: ServersModel.defaultIndex clip: true interactive: false @@ -305,8 +286,8 @@ PageType { onClicked: { serversMenuContent.currentIndex = index - isDefault = true - ContainersModel.setCurrentlyProcessedServerIndex(index) + ServersModel.currentlyProcessedIndex = index + ServersModel.defaultIndex = index root.currentServerName = name root.currentServerHostName = hostName @@ -328,8 +309,7 @@ PageType { z: 1 onClicked: function() { - ServersModel.setCurrentlyProcessedServerIndex(index) - ContainersModel.setCurrentlyProcessedServerIndex(index) + ServersModel.currentlyProcessedIndex = index goToPage(PageEnum.PageSettingsServerInfo) menu.visible = false } diff --git a/client/ui/qml/Pages2/PageSettingsServerData.qml b/client/ui/qml/Pages2/PageSettingsServerData.qml index b98d2b8c..319399dc 100644 --- a/client/ui/qml/Pages2/PageSettingsServerData.qml +++ b/client/ui/qml/Pages2/PageSettingsServerData.qml @@ -29,6 +29,14 @@ PageType { } } + Connections { + target: ServersModel + + function onCurrentlyProcessedServerIndexChanged() { + content.isServerWithWriteAccess = ServersModel.isCurrentlyProcessedServerHasWriteAccess() + } + } + FlickableType { id: fl anchors.top: parent.top @@ -42,7 +50,10 @@ PageType { anchors.left: parent.left anchors.right: parent.right + property bool isServerWithWriteAccess: ServersModel.isCurrentlyProcessedServerHasWriteAccess() //todo make it property? + LabelWithButtonType { + visible: content.isServerWithWriteAccess Layout.fillWidth: true text: qsTr("Clear Amnezia cache") @@ -65,9 +76,12 @@ PageType { } } - DividerType {} + DividerType { + visible: content.isServerWithWriteAccess + } LabelWithButtonType { + visible: content.isServerWithWriteAccess Layout.fillWidth: true text: qsTr("Проверить сервер на наличие ранее установленных сервисов Amnezia") @@ -78,12 +92,14 @@ PageType { } } - DividerType {} + DividerType { + visible: content.isServerWithWriteAccess + } LabelWithButtonType { Layout.fillWidth: true - text: "Remove server from application" + text: qsTr("Remove server from application") textColor: "#EB5757" clickedFunction: function() { @@ -115,9 +131,10 @@ PageType { DividerType {} LabelWithButtonType { + visible: content.isServerWithWriteAccess Layout.fillWidth: true - text: "Clear server from Amnezia software" + text: qsTr("Clear server from Amnezia software") textColor: "#EB5757" clickedFunction: function() { @@ -142,7 +159,9 @@ PageType { } } - DividerType {} + DividerType { + visible: content.isServerWithWriteAccess + } QuestionDrawer { id: questionDrawer diff --git a/client/ui/qml/Pages2/PageSettingsServerInfo.qml b/client/ui/qml/Pages2/PageSettingsServerInfo.qml index 3f2562da..aa882aa5 100644 --- a/client/ui/qml/Pages2/PageSettingsServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsServerInfo.qml @@ -54,7 +54,13 @@ PageType { actionButtonImage: "qrc:/images/controls/edit-3.svg" headerText: name - descriptionText: credentialsLogin + " · " + hostName + descriptionText: { + if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { + return credentialsLogin + " · " + hostName + } else { + return hostName + } + } actionButtonFunction: function() { serverNameEditDrawer.visible = true @@ -123,10 +129,14 @@ PageType { } TabButtonType { + visible: protocolsPage.installedProtocolsCount + width: protocolsPage.installedProtocolsCount ? undefined : 0 isSelected: tabBar.currentIndex === 0 text: qsTr("Protocols") } TabButtonType { + visible: servicesPage.installedServicesCount + width: servicesPage.installedServicesCount ? undefined : 0 isSelected: tabBar.currentIndex === 1 text: qsTr("Services") } @@ -143,9 +153,11 @@ PageType { currentIndex: tabBar.currentIndex PageSettingsServerProtocols { + id: protocolsPage stackView: root.stackView } PageSettingsServerServices { + id: servicesPage stackView: root.stackView } PageSettingsServerData { diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocols.qml b/client/ui/qml/Pages2/PageSettingsServerProtocols.qml index e93aa528..1d806d07 100644 --- a/client/ui/qml/Pages2/PageSettingsServerProtocols.qml +++ b/client/ui/qml/Pages2/PageSettingsServerProtocols.qml @@ -7,6 +7,7 @@ import SortFilterProxyModel 0.2 import PageEnum 1.0 import ProtocolEnum 1.0 import ContainerProps 1.0 +import ContainersModelFilters 1.0 import "./" import "../Controls2" @@ -17,22 +18,31 @@ import "../Components" PageType { id: root - SortFilterProxyModel { - id: containersProxyModel - sourceModel: ContainersModel - filters: [ - ValueFilter { - roleName: "serviceType" - value: ProtocolEnum.Vpn - }, - ValueFilter { - roleName: "isSupported" - value: true - } - ] - } + property var installedProtocolsCount SettingsContainersListView { - model: containersProxyModel + Connections { + target: ServersModel + + function onCurrentlyProcessedServerIndexChanged() { + updateContainersModelFilters() + } + } + + function updateContainersModelFilters() { + if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { + proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters() + } else { + proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters() + } + root.installedProtocolsCount = proxyContainersModel.count + } + + model: SortFilterProxyModel { + id: proxyContainersModel + sourceModel: ContainersModel + } + + Component.onCompleted: updateContainersModelFilters() } } diff --git a/client/ui/qml/Pages2/PageSettingsServerServices.qml b/client/ui/qml/Pages2/PageSettingsServerServices.qml index 7351f585..1e3d8722 100644 --- a/client/ui/qml/Pages2/PageSettingsServerServices.qml +++ b/client/ui/qml/Pages2/PageSettingsServerServices.qml @@ -7,6 +7,7 @@ import SortFilterProxyModel 0.2 import PageEnum 1.0 import ProtocolEnum 1.0 import ContainerProps 1.0 +import ContainersModelFilters 1.0 import "./" import "../Controls2" @@ -17,22 +18,31 @@ import "../Components" PageType { id: root - SortFilterProxyModel { - id: containersProxyModel - sourceModel: ContainersModel - filters: [ - ValueFilter { - roleName: "serviceType" - value: ProtocolEnum.Other - }, - ValueFilter { - roleName: "isSupported" - value: true - } - ] - } + property var installedServicesCount SettingsContainersListView { - model: containersProxyModel + Connections { + target: ServersModel + + function onCurrentlyProcessedServerIndexChanged() { + updateContainersModelFilters() + } + } + + function updateContainersModelFilters() { + if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { + proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters() + } else { + proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters() + } + root.installedServicesCount = proxyContainersModel.count + } + + model: SortFilterProxyModel { + id: proxyContainersModel + sourceModel: ContainersModel + } + + Component.onCompleted: updateContainersModelFilters() } } diff --git a/client/ui/qml/Pages2/PageSettingsServersList.qml b/client/ui/qml/Pages2/PageSettingsServersList.qml index a601199a..7f2b1688 100644 --- a/client/ui/qml/Pages2/PageSettingsServersList.qml +++ b/client/ui/qml/Pages2/PageSettingsServersList.qml @@ -89,8 +89,7 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" clickedFunction: function() { - ServersModel.setCurrentlyProcessedServerIndex(index) - ContainersModel.setCurrentlyProcessedServerIndex(index) + ServersModel.currentlyProcessedIndex = index goToPage(PageEnum.PageSettingsServerInfo) } } diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index fa6b1f92..fc8bf9ae 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -79,6 +79,10 @@ PageType { text: qsTr("Set up a server the easy way") onClicked: function() { + if (!isCredentialsFilled()) { + return + } + InstallController.setShouldCreateServer(true) InstallController.setCurrentlyInstalledServerCredentials(hostname.textField.text, username.textField.text, secretData.textField.text) @@ -100,6 +104,10 @@ PageType { text: qsTr("Select protocol to install") onClicked: function() { + if (!isCredentialsFilled()) { + return + } + InstallController.setShouldCreateServer(true) InstallController.setCurrentlyInstalledServerCredentials(hostname.textField.text, username.textField.text, secretData.textField.text) @@ -108,4 +116,25 @@ PageType { } } } + + function isCredentialsFilled() { + var hasEmptyField = false + + if (hostname.textFieldText === "") { + hostname.errorText = qsTr("ip address cannot be empty") + hasEmptyField = true + } else if (!hostname.textField.acceptableInput) { + hostname.errorText = qsTr("Enter the address in the format 255.255.255.255:88") + } + + if (username.textFieldText === "") { + username.errorText = qsTr("login cannot be empty") + hasEmptyField = true + } + if (secretData.textFieldText === "") { + secretData.errorText = qsTr("password/private key cannot be empty") + hasEmptyField = true + } + return !hasEmptyField + } } diff --git a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml index d0fdeabd..f1f5324e 100644 --- a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml +++ b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml @@ -61,7 +61,7 @@ PageType { function onServerAlreadyExists(serverIndex) { goToStartPage() - ServersModel.setCurrentlyProcessedServerIndex(serverIndex) + ServersModel.currentlyProcessedIndex = serverIndex goToPage(PageEnum.PageSettingsServerInfo, false) PageController.showErrorMessage(qsTr("The server has already been added to the application")) diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 504b0cb1..30430073 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -147,18 +147,28 @@ PageType { imageSource: "qrc:/images/controls/chevron-right.svg" - model: ServersModel - currentIndex: ServersModel.getDefaultServerIndex() + model: SortFilterProxyModel { + id: proxyServersModel + sourceModel: ServersModel + filters: [ + ValueFilter { + roleName: "hasWriteAccess" + value: true + } + ] + } + + currentIndex: 0 clickedFunction: function() { serverSelector.text = selectedText - ContainersModel.setCurrentlyProcessedServerIndex(currentIndex) + ServersModel.currentlyProcessedIndex = currentIndex protocolSelector.visible = true } Component.onCompleted: { serverSelector.text = selectedText - ContainersModel.setCurrentlyProcessedServerIndex(currentIndex) + ServersModel.currentlyProcessedIndex = currentIndex } } @@ -169,7 +179,7 @@ PageType { height: parent.height * 0.5 ColumnLayout { - id: header + id: protocolSelectorHeader anchors.top: parent.top anchors.left: parent.left @@ -187,12 +197,12 @@ PageType { } FlickableType { - anchors.top: header.bottom + anchors.top: protocolSelectorHeader.bottom anchors.topMargin: 16 - contentHeight: col.implicitHeight + contentHeight: protocolSelectorContent.implicitHeight Column { - id: col + id: protocolSelectorContent anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right @@ -265,7 +275,7 @@ PageType { } DropDownType { - id: connectionTypeSelector + id: exportTypeSelector property int currentIndex @@ -283,8 +293,6 @@ PageType { headerText: qsTr("Connection format") listView: ListViewType { - id: connectionTypeSelectorListView - rootWidth: root.width dividerVisible: true @@ -294,14 +302,14 @@ PageType { currentIndex: 0 clickedFunction: function() { - connectionTypeSelector.text = selectedText - connectionTypeSelector.currentIndex = currentIndex - connectionTypeSelector.menuVisible = false + exportTypeSelector.text = selectedText + exportTypeSelector.currentIndex = currentIndex + exportTypeSelector.menuVisible = false } Component.onCompleted: { - connectionTypeSelector.text = selectedText - connectionTypeSelector.currentIndex = currentIndex + exportTypeSelector.text = selectedText + exportTypeSelector.currentIndex = currentIndex } } } diff --git a/client/ui/qml/Pages2/PageStart.qml b/client/ui/qml/Pages2/PageStart.qml index 1307ee05..e2b83056 100644 --- a/client/ui/qml/Pages2/PageStart.qml +++ b/client/ui/qml/Pages2/PageStart.qml @@ -50,8 +50,7 @@ PageType { Component.onCompleted: { var pagePath = PageController.getPagePath(PageEnum.PageHome) - ServersModel.setCurrentlyProcessedServerIndex(ServersModel.getDefaultServerIndex()) - ContainersModel.setCurrentlyProcessedServerIndex(ServersModel.getDefaultServerIndex()) + ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex tabBarStackView.push(pagePath, { "objectName" : pagePath }) } } @@ -65,8 +64,8 @@ PageType { topPadding: 8 bottomPadding: 8//34 - leftPadding: 96 - rightPadding: 96 + leftPadding: shareTabButton.visible ? 96 : 128 + rightPadding: shareTabButton.visible ? 96 : 128 background: Rectangle { border.width: 1 @@ -78,11 +77,25 @@ PageType { isSelected: tabBar.currentIndex === 0 image: "qrc:/images/controls/home.svg" onClicked: { - ContainersModel.setCurrentlyProcessedServerIndex(ServersModel.getDefaultServerIndex()) + ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex tabBarStackView.goToTabBarPage(PageEnum.PageHome) } } TabImageButtonType { + id: shareTabButton + + Connections { + target: ServersModel + + function onDefaultServerIndexChanged() { + shareTabButton.visible = ServersModel.isCurrentlyProcessedServerHasWriteAccess() + shareTabButton.width = ServersModel.isCurrentlyProcessedServerHasWriteAccess() ? undefined : 0 + } + } + + visible: ServersModel.isCurrentlyProcessedServerHasWriteAccess() + width: visible ? undefined : 0 + isSelected: tabBar.currentIndex === 1 image: "qrc:/images/controls/share-2.svg" onClicked: { @@ -100,8 +113,8 @@ PageType { MouseArea { anchors.fill: tabBar - anchors.leftMargin: 96 - anchors.rightMargin: 96 + anchors.leftMargin: shareTabButton.visible ? 96 : 128 + anchors.rightMargin: shareTabButton.visible ? 96 : 128 cursorShape: Qt.PointingHandCursor enabled: false }