Merge branch 'improve_navigation_cpp' into feature/android-tv
This commit is contained in:
commit
c72d76aec7
88 changed files with 3939 additions and 3369 deletions
|
|
@ -404,6 +404,9 @@ void AmneziaApplication::initControllers()
|
|||
m_pageController.reset(new PageController(m_serversModel, m_settings));
|
||||
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
|
||||
|
||||
m_focusController.reset(new FocusController(m_engine, this));
|
||||
m_engine->rootContext()->setContextProperty("FocusController", m_focusController.get());
|
||||
|
||||
m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_clientManagementModel,
|
||||
m_apiServicesModel, m_settings));
|
||||
m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "ui/controllers/exportController.h"
|
||||
#include "ui/controllers/importController.h"
|
||||
#include "ui/controllers/installController.h"
|
||||
#include "ui/controllers/focusController.h"
|
||||
#include "ui/controllers/pageController.h"
|
||||
#include "ui/controllers/settingsController.h"
|
||||
#include "ui/controllers/sitesController.h"
|
||||
|
|
@ -124,6 +125,7 @@ private:
|
|||
#endif
|
||||
|
||||
QScopedPointer<ConnectionController> m_connectionController;
|
||||
QScopedPointer<FocusController> m_focusController;
|
||||
QScopedPointer<PageController> m_pageController;
|
||||
QScopedPointer<InstallController> m_installController;
|
||||
QScopedPointer<ImportController> m_importController;
|
||||
|
|
|
|||
|
|
@ -1,225 +1,226 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>fonts/pt-root-ui_vf.ttf</file>
|
||||
<file>images/amneziaBigLogo.png</file>
|
||||
<file>images/AmneziaVPN.png</file>
|
||||
<file>images/controls/alert-circle.svg</file>
|
||||
<file>images/controls/amnezia.svg</file>
|
||||
<file>images/controls/app.svg</file>
|
||||
<file>images/controls/archive-restore.svg</file>
|
||||
<file>images/controls/arrow-left.svg</file>
|
||||
<file>images/controls/arrow-right.svg</file>
|
||||
<file>images/controls/bug.svg</file>
|
||||
<file>images/controls/check.svg</file>
|
||||
<file>images/controls/chevron-down.svg</file>
|
||||
<file>images/controls/chevron-right.svg</file>
|
||||
<file>images/controls/chevron-up.svg</file>
|
||||
<file>images/controls/close.svg</file>
|
||||
<file>images/controls/copy.svg</file>
|
||||
<file>images/controls/delete.svg</file>
|
||||
<file>images/controls/download.svg</file>
|
||||
<file>images/controls/edit-3.svg</file>
|
||||
<file>images/controls/eye-off.svg</file>
|
||||
<file>images/controls/eye.svg</file>
|
||||
<file>images/controls/file-check-2.svg</file>
|
||||
<file>images/controls/file-cog-2.svg</file>
|
||||
<file>images/controls/folder-open.svg</file>
|
||||
<file>images/controls/folder-search-2.svg</file>
|
||||
<file>images/controls/gauge.svg</file>
|
||||
<file>images/controls/github.svg</file>
|
||||
<file>images/controls/help-circle.svg</file>
|
||||
<file>images/controls/history.svg</file>
|
||||
<file>images/controls/home.svg</file>
|
||||
<file>images/controls/info.svg</file>
|
||||
<file>images/controls/mail.svg</file>
|
||||
<file>images/controls/map-pin.svg</file>
|
||||
<file>images/controls/more-vertical.svg</file>
|
||||
<file>images/controls/plus.svg</file>
|
||||
<file>images/controls/qr-code.svg</file>
|
||||
<file>images/controls/radio-button-inner-circle-pressed.png</file>
|
||||
<file>images/controls/radio-button-inner-circle.png</file>
|
||||
<file>images/controls/radio-button-pressed.svg</file>
|
||||
<file>images/controls/radio-button.svg</file>
|
||||
<file>images/controls/radio.svg</file>
|
||||
<file>images/controls/refresh-cw.svg</file>
|
||||
<file>images/controls/save.svg</file>
|
||||
<file>images/controls/scan-line.svg</file>
|
||||
<file>images/controls/search.svg</file>
|
||||
<file>images/controls/server.svg</file>
|
||||
<file>images/controls/settings-2.svg</file>
|
||||
<file>images/controls/settings.svg</file>
|
||||
<file>images/controls/share-2.svg</file>
|
||||
<file>images/controls/split-tunneling.svg</file>
|
||||
<file>images/controls/tag.svg</file>
|
||||
<file>images/controls/telegram.svg</file>
|
||||
<file>images/controls/text-cursor.svg</file>
|
||||
<file>images/controls/trash.svg</file>
|
||||
<file>images/controls/x-circle.svg</file>
|
||||
<file>images/tray/active.png</file>
|
||||
<file>images/tray/default.png</file>
|
||||
<file>images/tray/error.png</file>
|
||||
<file>images/AmneziaVPN.png</file>
|
||||
<file>server_scripts/remove_container.sh</file>
|
||||
<file>server_scripts/setup_host_firewall.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/Dockerfile</file>
|
||||
<file>server_scripts/awg/configure_container.sh</file>
|
||||
<file>server_scripts/awg/Dockerfile</file>
|
||||
<file>server_scripts/awg/run_container.sh</file>
|
||||
<file>server_scripts/awg/start.sh</file>
|
||||
<file>server_scripts/awg/template.conf</file>
|
||||
<file>server_scripts/build_container.sh</file>
|
||||
<file>server_scripts/check_connection.sh</file>
|
||||
<file>server_scripts/check_server_is_busy.sh</file>
|
||||
<file>server_scripts/check_user_in_sudo.sh</file>
|
||||
<file>server_scripts/dns/configure_container.sh</file>
|
||||
<file>server_scripts/dns/Dockerfile</file>
|
||||
<file>server_scripts/dns/run_container.sh</file>
|
||||
<file>server_scripts/install_docker.sh</file>
|
||||
<file>server_scripts/ipsec/configure_container.sh</file>
|
||||
<file>server_scripts/ipsec/Dockerfile</file>
|
||||
<file>server_scripts/ipsec/mobileconfig.plist</file>
|
||||
<file>server_scripts/ipsec/run_container.sh</file>
|
||||
<file>server_scripts/ipsec/start.sh</file>
|
||||
<file>server_scripts/ipsec/strongswan.profile</file>
|
||||
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/Dockerfile</file>
|
||||
<file>server_scripts/openvpn_cloak/run_container.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/start.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/template.ovpn</file>
|
||||
<file>server_scripts/install_docker.sh</file>
|
||||
<file>server_scripts/build_container.sh</file>
|
||||
<file>server_scripts/prepare_host.sh</file>
|
||||
<file>server_scripts/check_connection.sh</file>
|
||||
<file>server_scripts/remove_all_containers.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/run_container.sh</file>
|
||||
<file>server_scripts/openvpn/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn/run_container.sh</file>
|
||||
<file>server_scripts/openvpn/template.ovpn</file>
|
||||
<file>server_scripts/openvpn/Dockerfile</file>
|
||||
<file>server_scripts/openvpn/start.sh</file>
|
||||
<file>server_scripts/openvpn_shadowsocks/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn_shadowsocks/Dockerfile</file>
|
||||
<file>server_scripts/openvpn_shadowsocks/run_container.sh</file>
|
||||
<file>server_scripts/openvpn_shadowsocks/start.sh</file>
|
||||
<file>server_scripts/openvpn_shadowsocks/template.ovpn</file>
|
||||
<file>server_scripts/openvpn/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn/Dockerfile</file>
|
||||
<file>server_scripts/openvpn/run_container.sh</file>
|
||||
<file>server_scripts/openvpn/start.sh</file>
|
||||
<file>server_scripts/openvpn/template.ovpn</file>
|
||||
<file>server_scripts/prepare_host.sh</file>
|
||||
<file>server_scripts/remove_all_containers.sh</file>
|
||||
<file>server_scripts/remove_container.sh</file>
|
||||
<file>server_scripts/setup_host_firewall.sh</file>
|
||||
<file>server_scripts/sftp/configure_container.sh</file>
|
||||
<file>server_scripts/sftp/Dockerfile</file>
|
||||
<file>server_scripts/sftp/run_container.sh</file>
|
||||
<file>server_scripts/socks5_proxy/configure_container.sh</file>
|
||||
<file>server_scripts/socks5_proxy/Dockerfile</file>
|
||||
<file>server_scripts/socks5_proxy/run_container.sh</file>
|
||||
<file>server_scripts/socks5_proxy/start.sh</file>
|
||||
<file>server_scripts/website_tor/configure_container.sh</file>
|
||||
<file>server_scripts/website_tor/Dockerfile</file>
|
||||
<file>server_scripts/website_tor/run_container.sh</file>
|
||||
<file>server_scripts/wireguard/configure_container.sh</file>
|
||||
<file>server_scripts/wireguard/Dockerfile</file>
|
||||
<file>server_scripts/wireguard/run_container.sh</file>
|
||||
<file>server_scripts/wireguard/start.sh</file>
|
||||
<file>server_scripts/wireguard/template.conf</file>
|
||||
<file>server_scripts/website_tor/configure_container.sh</file>
|
||||
<file>server_scripts/website_tor/run_container.sh</file>
|
||||
<file>ui/qml/Config/GlobalConfig.qml</file>
|
||||
<file>ui/qml/Config/qmldir</file>
|
||||
<file>server_scripts/check_server_is_busy.sh</file>
|
||||
<file>server_scripts/dns/configure_container.sh</file>
|
||||
<file>server_scripts/dns/Dockerfile</file>
|
||||
<file>server_scripts/dns/run_container.sh</file>
|
||||
<file>server_scripts/sftp/configure_container.sh</file>
|
||||
<file>server_scripts/sftp/Dockerfile</file>
|
||||
<file>server_scripts/sftp/run_container.sh</file>
|
||||
<file>server_scripts/ipsec/configure_container.sh</file>
|
||||
<file>server_scripts/ipsec/Dockerfile</file>
|
||||
<file>server_scripts/ipsec/run_container.sh</file>
|
||||
<file>server_scripts/ipsec/start.sh</file>
|
||||
<file>server_scripts/ipsec/mobileconfig.plist</file>
|
||||
<file>server_scripts/ipsec/strongswan.profile</file>
|
||||
<file>server_scripts/website_tor/Dockerfile</file>
|
||||
<file>server_scripts/check_user_in_sudo.sh</file>
|
||||
<file>ui/qml/Controls2/BasicButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/TextFieldWithHeaderType.qml</file>
|
||||
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
|
||||
<file>images/controls/arrow-right.svg</file>
|
||||
<file>images/controls/chevron-right.svg</file>
|
||||
<file>ui/qml/Controls2/ImageButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/CardType.qml</file>
|
||||
<file>ui/qml/Controls2/CheckBoxType.qml</file>
|
||||
<file>images/controls/check.svg</file>
|
||||
<file>ui/qml/Controls2/DropDownType.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardStart.qml</file>
|
||||
<file>ui/qml/main2.qml</file>
|
||||
<file>images/amneziaBigLogo.png</file>
|
||||
<file>ui/qml/Controls2/FlickableType.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>
|
||||
<file>ui/qml/Controls2/HeaderType.qml</file>
|
||||
<file>images/controls/arrow-left.svg</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardProtocols.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardEasy.qml</file>
|
||||
<file>images/controls/chevron-down.svg</file>
|
||||
<file>images/controls/chevron-up.svg</file>
|
||||
<file>ui/qml/Controls2/TextTypes/ParagraphTextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/Header2TextType.qml</file>
|
||||
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
|
||||
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
|
||||
<file>ui/qml/Controls2/SwitcherType.qml</file>
|
||||
<file>ui/qml/Controls2/TabButtonType.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
|
||||
<file>images/controls/folder-open.svg</file>
|
||||
<file>images/controls/qr-code.svg</file>
|
||||
<file>images/controls/text-cursor.svg</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardTextKey.qml</file>
|
||||
<file>ui/qml/Pages2/PageStart.qml</file>
|
||||
<file>ui/qml/Controls2/TabImageButtonType.qml</file>
|
||||
<file>images/controls/home.svg</file>
|
||||
<file>images/controls/settings-2.svg</file>
|
||||
<file>images/controls/share-2.svg</file>
|
||||
<file>ui/qml/Pages2/PageHome.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServersList.qml</file>
|
||||
<file>ui/qml/Pages2/PageShare.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/Header1TextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/LabelTextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/ButtonTextType.qml</file>
|
||||
<file>ui/qml/Controls2/Header2Type.qml</file>
|
||||
<file>images/controls/plus.svg</file>
|
||||
<file>ui/qml/Components/ConnectButton.qml</file>
|
||||
<file>images/controls/download.svg</file>
|
||||
<file>ui/qml/Controls2/ProgressBarType.qml</file>
|
||||
<file>ui/qml/Components/ConnectionTypeSelectionDrawer.qml</file>
|
||||
<file>ui/qml/Components/HomeContainersListView.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/CaptionTextType.qml</file>
|
||||
<file>images/controls/settings.svg</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
|
||||
<file>ui/qml/Controls2/PageType.qml</file>
|
||||
<file>ui/qml/Controls2/PopupType.qml</file>
|
||||
<file>images/controls/edit-3.svg</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
|
||||
<file>ui/qml/Components/SettingsContainersListView.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
|
||||
<file>ui/qml/Controls2/DividerType.qml</file>
|
||||
<file>ui/qml/Controls2/StackViewType.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettings.qml</file>
|
||||
<file>images/controls/amnezia.svg</file>
|
||||
<file>images/controls/app.svg</file>
|
||||
<file>images/controls/radio.svg</file>
|
||||
<file>images/controls/save.svg</file>
|
||||
<file>images/controls/server.svg</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerServices.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
|
||||
<file>images/controls/file-cog-2.svg</file>
|
||||
<file>ui/qml/Components/QuestionDrawer.qml</file>
|
||||
<file>ui/qml/Pages2/PageDeinstalling.qml</file>
|
||||
<file>ui/qml/Controls2/BackButtonType.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerProtocol.qml</file>
|
||||
<file>ui/qml/Components/TransportProtoSelector.qml</file>
|
||||
<file>ui/qml/Controls2/ListViewWithRadioButtonType.qml</file>
|
||||
<file>images/controls/radio-button.svg</file>
|
||||
<file>images/controls/radio-button-inner-circle.png</file>
|
||||
<file>images/controls/radio-button-pressed.svg</file>
|
||||
<file>images/controls/radio-button-inner-circle-pressed.png</file>
|
||||
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApplication.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
|
||||
<file>images/controls/delete.svg</file>
|
||||
<file>ui/qml/Pages2/PageSettingsAbout.qml</file>
|
||||
<file>images/controls/github.svg</file>
|
||||
<file>images/controls/mail.svg</file>
|
||||
<file>images/controls/telegram.svg</file>
|
||||
<file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file>
|
||||
<file>ui/qml/Filters/ContainersModelFilters.qml</file>
|
||||
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
|
||||
<file>ui/qml/Controls2/BusyIndicatorType.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolOpenVpnSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
|
||||
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
|
||||
<file>images/controls/copy.svg</file>
|
||||
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
|
||||
<file>images/controls/eye.svg</file>
|
||||
<file>images/controls/eye-off.svg</file>
|
||||
<file>ui/qml/Pages2/PageSettingsSplitTunneling.qml</file>
|
||||
<file>ui/qml/Controls2/ContextMenuType.qml</file>
|
||||
<file>ui/qml/Controls2/TextAreaType.qml</file>
|
||||
<file>images/controls/trash.svg</file>
|
||||
<file>images/controls/more-vertical.svg</file>
|
||||
<file>ui/qml/Controls2/ListViewWithLabelsType.qml</file>
|
||||
<file>ui/qml/Pages2/PageServiceDnsSettings.qml</file>
|
||||
<file>ui/qml/Controls2/TopCloseButtonType.qml</file>
|
||||
<file>images/controls/x-circle.svg</file>
|
||||
<file>ui/qml/Pages2/PageProtocolAwgSettings.qml</file>
|
||||
<file>server_scripts/awg/template.conf</file>
|
||||
<file>server_scripts/awg/start.sh</file>
|
||||
<file>server_scripts/awg/configure_container.sh</file>
|
||||
<file>server_scripts/awg/run_container.sh</file>
|
||||
<file>server_scripts/awg/Dockerfile</file>
|
||||
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
|
||||
<file>images/controls/close.svg</file>
|
||||
<file>images/controls/search.svg</file>
|
||||
<file>server_scripts/xray/configure_container.sh</file>
|
||||
<file>server_scripts/xray/Dockerfile</file>
|
||||
<file>server_scripts/xray/run_container.sh</file>
|
||||
<file>server_scripts/xray/start.sh</file>
|
||||
<file>server_scripts/xray/template.json</file>
|
||||
<file>ui/qml/Pages2/PageProtocolWireGuardSettings.qml</file>
|
||||
<file>ui/qml/Components/ConnectButton.qml</file>
|
||||
<file>ui/qml/Components/ConnectionTypeSelectionDrawer.qml</file>
|
||||
<file>ui/qml/Components/HomeContainersListView.qml</file>
|
||||
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
|
||||
<file>images/controls/split-tunneling.svg</file>
|
||||
<file>ui/qml/Controls2/DrawerType2.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsAppSplitTunneling.qml</file>
|
||||
<file>ui/qml/Components/InstalledAppsDrawer.qml</file>
|
||||
<file>images/controls/alert-circle.svg</file>
|
||||
<file>images/controls/file-check-2.svg</file>
|
||||
<file>ui/qml/Components/QuestionDrawer.qml</file>
|
||||
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
|
||||
<file>ui/qml/Components/ServersListView.qml</file>
|
||||
<file>ui/qml/Components/SettingsContainersListView.qml</file>
|
||||
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
|
||||
<file>ui/qml/Components/TransportProtoSelector.qml</file>
|
||||
<file>ui/qml/Config/GlobalConfig.qml</file>
|
||||
<file>ui/qml/Config/qmldir</file>
|
||||
<file>ui/qml/Controls2/BackButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/BasicButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/BusyIndicatorType.qml</file>
|
||||
<file>ui/qml/Controls2/CardType.qml</file>
|
||||
<file>ui/qml/Controls2/CardWithIconsType.qml</file>
|
||||
<file>ui/qml/Controls2/CheckBoxType.qml</file>
|
||||
<file>ui/qml/Controls2/ContextMenuType.qml</file>
|
||||
<file>ui/qml/Controls2/DividerType.qml</file>
|
||||
<file>ui/qml/Controls2/DrawerType2.qml</file>
|
||||
<file>ui/qml/Controls2/DropDownType.qml</file>
|
||||
<file>ui/qml/Controls2/FlickableType.qml</file>
|
||||
<file>ui/qml/Controls2/Header2Type.qml</file>
|
||||
<file>ui/qml/Controls2/HeaderType.qml</file>
|
||||
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
|
||||
<file>ui/qml/Controls2/ImageButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/LabelWithImageType.qml</file>
|
||||
<file>ui/qml/Controls2/ListViewWithLabelsType.qml</file>
|
||||
<file>ui/qml/Controls2/ListViewWithRadioButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/PageType.qml</file>
|
||||
<file>ui/qml/Controls2/PopupType.qml</file>
|
||||
<file>ui/qml/Controls2/ProgressBarType.qml</file>
|
||||
<file>ui/qml/Controls2/StackViewType.qml</file>
|
||||
<file>ui/qml/Controls2/SwitcherType.qml</file>
|
||||
<file>ui/qml/Controls2/TabButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/TabImageButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/TextAreaType.qml</file>
|
||||
<file>ui/qml/Controls2/TextAreaWithFooterType.qml</file>
|
||||
<file>ui/qml/Controls2/TextFieldWithHeaderType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/ButtonTextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/CaptionTextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/Header1TextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/Header2TextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/LabelTextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/ParagraphTextType.qml</file>
|
||||
<file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file>
|
||||
<file>ui/qml/Controls2/TopCloseButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
|
||||
<file>ui/qml/Controls2/WarningType.qml</file>
|
||||
<file>fonts/pt-root-ui_vf.ttf</file>
|
||||
<file>ui/qml/Modules/Style/qmldir</file>
|
||||
<file>ui/qml/Filters/ContainersModelFilters.qml</file>
|
||||
<file>ui/qml/main2.qml</file>
|
||||
<file>ui/qml/Modules/Style/AmneziaStyle.qml</file>
|
||||
<file>ui/qml/Modules/Style/qmldir</file>
|
||||
<file>ui/qml/Pages2/PageDeinstalling.qml</file>
|
||||
<file>ui/qml/Pages2/PageDevMenu.qml</file>
|
||||
<file>ui/qml/Pages2/PageHome.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolAwgSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolOpenVpnSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolWireGuardSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageServiceDnsSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageServiceSocksProxySettings.qml</file>
|
||||
<file>server_scripts/socks5_proxy/run_container.sh</file>
|
||||
<file>server_scripts/socks5_proxy/Dockerfile</file>
|
||||
<file>server_scripts/socks5_proxy/configure_container.sh</file>
|
||||
<file>server_scripts/socks5_proxy/start.sh</file>
|
||||
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsAbout.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiServerInfo.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApplication.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsAppSplitTunneling.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerProtocol.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerServices.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServersList.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsSplitTunneling.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolAwgClientSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
|
||||
<file>ui/qml/Controls2/CardWithIconsType.qml</file>
|
||||
<file>images/controls/tag.svg</file>
|
||||
<file>images/controls/history.svg</file>
|
||||
<file>images/controls/gauge.svg</file>
|
||||
<file>images/controls/map-pin.svg</file>
|
||||
<file>ui/qml/Controls2/LabelWithImageType.qml</file>
|
||||
<file>images/controls/info.svg</file>
|
||||
<file>ui/qml/Controls2/TextAreaWithFooterType.qml</file>
|
||||
<file>images/controls/scan-line.svg</file>
|
||||
<file>images/controls/folder-search-2.svg</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiServerInfo.qml</file>
|
||||
<file>images/controls/bug.svg</file>
|
||||
<file>ui/qml/Pages2/PageDevMenu.qml</file>
|
||||
<file>images/controls/refresh-cw.svg</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
|
||||
<file>images/controls/archive-restore.svg</file>
|
||||
<file>images/controls/help-circle.svg</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardEasy.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardProtocols.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardStart.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardTextKey.qml</file>
|
||||
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
|
||||
<file>ui/qml/Pages2/PageShare.qml</file>
|
||||
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
|
||||
<file>ui/qml/Pages2/PageStart.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/countriesFlags">
|
||||
<file>images/flagKit/ZW.svg</file>
|
||||
|
|
|
|||
324
client/ui/controllers/focusController.cpp
Normal file
324
client/ui/controllers/focusController.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
#include "focusController.h"
|
||||
|
||||
#include "listViewFocusController.h"
|
||||
|
||||
#include <QQuickWindow>
|
||||
#include <QQmlApplicationEngine>
|
||||
|
||||
|
||||
bool isListView(QObject* item)
|
||||
{
|
||||
return item->inherits("QQuickListView");
|
||||
}
|
||||
|
||||
bool isOnTheScene(QObject* object)
|
||||
{
|
||||
QQuickItem* item = qobject_cast<QQuickItem*>(object);
|
||||
if (!item) {
|
||||
qWarning() << "Couldn't recognize object as item";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item->isVisible()) {
|
||||
// qDebug() << "===>> The item is not visible: " << item;
|
||||
return false;
|
||||
}
|
||||
|
||||
QRectF itemRect = item->mapRectToScene(item->childrenRect());
|
||||
|
||||
QQuickWindow* window = item->window();
|
||||
if (!window) {
|
||||
qWarning() << "Couldn't get the window on the Scene check";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto contentItem = window->contentItem();
|
||||
if (!contentItem) {
|
||||
qWarning() << "Couldn't get the content item on the Scene check";
|
||||
return false;
|
||||
}
|
||||
QRectF windowRect = contentItem->childrenRect();
|
||||
const auto res = (windowRect.contains(itemRect) || isListView(item));
|
||||
// qDebug() << (res ? "===>> item is inside the Scene" : "===>> ITEM IS OUTSIDE THE SCENE") << " itemRect: " << itemRect << "; windowRect: " << windowRect;
|
||||
return res;
|
||||
}
|
||||
|
||||
QList<QObject*> getSubChain(QObject* object)
|
||||
{
|
||||
QList<QObject*> res;
|
||||
if (!object) {
|
||||
qDebug() << "The object is NULL";
|
||||
return res;
|
||||
}
|
||||
|
||||
const auto children = object->children();
|
||||
|
||||
for(const auto child : children) {
|
||||
if (child
|
||||
&& isFocusable(child)
|
||||
&& isOnTheScene(child)
|
||||
&& isEnabled(child)
|
||||
) {
|
||||
res.append(child);
|
||||
} else {
|
||||
res.append(getSubChain(child));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
FocusController::FocusController(QQmlApplicationEngine* engine, QObject *parent)
|
||||
: QObject{parent}
|
||||
, m_engine{engine}
|
||||
, m_focusChain{}
|
||||
, m_focusedItem{nullptr}
|
||||
, m_rootObjects{}
|
||||
, m_defaultFocusItem{QSharedPointer<QQuickItem>()}
|
||||
, m_lvfc{nullptr}
|
||||
{
|
||||
QObject::connect(m_engine.get(), &QQmlApplicationEngine::objectCreated, this, [this](QObject *object, const QUrl &url){
|
||||
QQuickItem* newDefaultFocusItem = object->findChild<QQuickItem*>("defaultFocusItem");
|
||||
if(newDefaultFocusItem && m_defaultFocusItem != newDefaultFocusItem) {
|
||||
m_defaultFocusItem.reset(newDefaultFocusItem);
|
||||
qDebug() << "===>> NEW DEFAULT FOCUS ITEM: " << m_defaultFocusItem;
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(this, &FocusController::focusedItemChanged, this, [this]() {
|
||||
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void FocusController::nextKeyTabItem()
|
||||
{
|
||||
nextItem(Direction::Forward);
|
||||
}
|
||||
|
||||
void FocusController::previousKeyTabItem()
|
||||
{
|
||||
nextItem(Direction::Backward);
|
||||
}
|
||||
|
||||
void FocusController::nextKeyUpItem()
|
||||
{
|
||||
nextItem(Direction::Backward);
|
||||
}
|
||||
|
||||
void FocusController::nextKeyDownItem()
|
||||
{
|
||||
nextItem(Direction::Forward);
|
||||
}
|
||||
|
||||
void FocusController::nextKeyLeftItem()
|
||||
{
|
||||
nextItem(Direction::Backward);
|
||||
}
|
||||
|
||||
void FocusController::nextKeyRightItem()
|
||||
{
|
||||
nextItem(Direction::Forward);
|
||||
}
|
||||
|
||||
void FocusController::setFocusItem(QQuickItem* item)
|
||||
{
|
||||
if (m_focusedItem != item) {
|
||||
m_focusedItem = item;
|
||||
emit focusedItemChanged();
|
||||
qDebug() << "===>> FocusItem is changed to " << item << "!";
|
||||
} else {
|
||||
qDebug() << "===>> FocusItem is is the same: " << item << "!";
|
||||
}
|
||||
}
|
||||
|
||||
void FocusController::setFocusOnDefaultItem()
|
||||
{
|
||||
qDebug() << "===>> Setting focus on DEFAULT FOCUS ITEM...";
|
||||
setFocusItem(m_defaultFocusItem.get());
|
||||
}
|
||||
|
||||
void FocusController::pushRootObject(QObject* object)
|
||||
{
|
||||
qDebug() << "===>> Calling < pushRootObject >...";
|
||||
m_rootObjects.push(object);
|
||||
dropListView();
|
||||
// setFocusOnDefaultItem();
|
||||
qDebug() << "===>> ROOT OBJECT is changed to: " << m_rootObjects.top();
|
||||
qDebug() << "===>> ROOT OBJECTS: " << m_rootObjects;
|
||||
}
|
||||
|
||||
void FocusController::dropRootObject(QObject* object)
|
||||
{
|
||||
qDebug() << "===>> Calling < dropRootObject >...";
|
||||
if (m_rootObjects.empty()) {
|
||||
qDebug() << "ROOT OBJECT is already DEFAULT";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_rootObjects.top() == object) {
|
||||
m_rootObjects.pop();
|
||||
dropListView();
|
||||
setFocusOnDefaultItem();
|
||||
if(m_rootObjects.size()) {
|
||||
qDebug() << "===>> ROOT OBJECT is changed to: " << m_rootObjects.top();
|
||||
} else {
|
||||
qDebug() << "===>> ROOT OBJECT is changed to DEFAULT";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "===>> TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
|
||||
}
|
||||
}
|
||||
|
||||
void FocusController::resetRootObject()
|
||||
{
|
||||
qDebug() << "===>> Calling < resetRootObject >...";
|
||||
m_rootObjects.clear();
|
||||
qDebug() << "===>> ROOT OBJECT IS RESETED";
|
||||
}
|
||||
|
||||
void FocusController::reload(Direction direction)
|
||||
{
|
||||
qDebug() << "===>> Calling < reload >...";
|
||||
m_focusChain.clear();
|
||||
|
||||
QObject* rootObject = (m_rootObjects.empty()
|
||||
? m_engine->rootObjects().value(0)
|
||||
: m_rootObjects.top());
|
||||
|
||||
if(!rootObject) {
|
||||
qCritical() << "No ROOT OBJECT found!";
|
||||
resetRootObject();
|
||||
dropListView();
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "===>> ROOT OBJECTS: " << rootObject;
|
||||
|
||||
m_focusChain.append(getSubChain(rootObject));
|
||||
|
||||
std::sort(m_focusChain.begin(), m_focusChain.end(), direction == Direction::Forward ? isLess : isMore);
|
||||
|
||||
if (m_focusChain.empty()) {
|
||||
qWarning() << "Focus chain is empty!";
|
||||
resetRootObject();
|
||||
dropListView();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FocusController::nextItem(Direction direction)
|
||||
{
|
||||
qDebug() << "===>> Calling < nextItem >...";
|
||||
|
||||
reload(direction);
|
||||
|
||||
if (m_lvfc && isListView(m_focusedItem)) {
|
||||
direction == Direction::Forward ? focusNextListViewItem() : focusPreviousListViewItem();
|
||||
qDebug() << "===>> Handling the [ ListView ]...";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_focusChain.empty()) {
|
||||
qWarning() << "There are no items to navigate";
|
||||
setFocusOnDefaultItem();
|
||||
return;
|
||||
}
|
||||
|
||||
auto focusedItemIndex = m_focusChain.indexOf(m_focusedItem);
|
||||
|
||||
if (focusedItemIndex == -1) {
|
||||
qDebug() << "Current FocusItem is not in chain, switch to first in chain...";
|
||||
focusedItemIndex = 0;
|
||||
} else if (focusedItemIndex == (m_focusChain.size() - 1)) {
|
||||
qDebug() << "Last focus index. Starting from the beginning...";
|
||||
focusedItemIndex = 0;
|
||||
} else {
|
||||
qDebug() << "Incrementing focus index...";
|
||||
focusedItemIndex++;
|
||||
}
|
||||
|
||||
const auto focusedItem = qobject_cast<QQuickItem*>(m_focusChain.at(focusedItemIndex));
|
||||
|
||||
if(focusedItem == nullptr) {
|
||||
qWarning() << "Failed to get item to focus on. Setting focus on default";
|
||||
setFocusOnDefaultItem();
|
||||
return;
|
||||
}
|
||||
|
||||
if(isListView(focusedItem)) {
|
||||
qDebug() << "===>> Found [ListView]";
|
||||
m_lvfc = new ListViewFocusController(focusedItem, this);
|
||||
m_focusedItem = focusedItem;
|
||||
if(direction == Direction::Forward) {
|
||||
m_lvfc->nextDelegate();
|
||||
focusNextListViewItem();
|
||||
} else {
|
||||
m_lvfc->previousDelegate();
|
||||
focusPreviousListViewItem();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setFocusItem(focusedItem);
|
||||
|
||||
printItems(m_focusChain, focusedItem);
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
const auto w = m_defaultFocusItem->window();
|
||||
|
||||
qDebug() << "===>> CURRENT ACTIVE ITEM: " << w->activeFocusItem();
|
||||
qDebug() << "===>> CURRENT FOCUS OBJECT: " << w->focusObject();
|
||||
if(m_rootObjects.empty()) {
|
||||
qDebug() << "===>> ROOT OBJECT IS DEFAULT";
|
||||
} else {
|
||||
qDebug() << "===>> ROOT OBJECT: " << m_rootObjects.top();
|
||||
}
|
||||
}
|
||||
|
||||
void FocusController::focusNextListViewItem()
|
||||
{
|
||||
qDebug() << "===>> Calling < focusNextListViewItem >...";
|
||||
|
||||
if (m_lvfc->isLastFocusItemInListView() || m_lvfc->isReturnNeeded()) {
|
||||
qDebug() << "===>> Last item in [ ListView ] was reached. Going to the NEXT element after [ ListView ]";
|
||||
dropListView();
|
||||
nextItem(Direction::Forward);
|
||||
return;
|
||||
} else if (m_lvfc->isLastFocusItemInDelegate()) {
|
||||
qDebug() << "===>> End of delegate elements was reached. Going to the next delegate";
|
||||
m_lvfc->resetFocusChain();
|
||||
m_lvfc->nextDelegate();
|
||||
}
|
||||
|
||||
m_lvfc->focusNextItem();
|
||||
}
|
||||
|
||||
void FocusController::focusPreviousListViewItem()
|
||||
{
|
||||
qDebug() << "===>> Calling < focusPreviousListViewItem >...";
|
||||
|
||||
if (m_lvfc->isFirstFocusItemInListView() || m_lvfc->isReturnNeeded()) {
|
||||
qDebug() << "===>> First item in [ ListView ] was reached. Going to the PREVIOUS element after [ ListView ]";
|
||||
dropListView();
|
||||
nextItem(Direction::Backward);
|
||||
return;
|
||||
} else if (m_lvfc->isFirstFocusItemInDelegate()) {
|
||||
m_lvfc->resetFocusChain();
|
||||
m_lvfc->previousDelegate();
|
||||
}
|
||||
|
||||
m_lvfc->focusPreviousItem();
|
||||
}
|
||||
|
||||
void FocusController::dropListView()
|
||||
{
|
||||
qDebug() << "===>> Calling < dropListView >...";
|
||||
|
||||
if(m_lvfc) {
|
||||
delete m_lvfc;
|
||||
m_lvfc = nullptr;
|
||||
}
|
||||
}
|
||||
62
client/ui/controllers/focusController.h
Normal file
62
client/ui/controllers/focusController.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef FOCUSCONTROLLER_H
|
||||
#define FOCUSCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStack>
|
||||
#include <QSharedPointer>
|
||||
|
||||
|
||||
class QQuickItem;
|
||||
class QQmlApplicationEngine;
|
||||
class ListViewFocusController;
|
||||
|
||||
/*!
|
||||
* \brief The FocusController class makes focus control more straightforward
|
||||
* \details Focus is handled only for visible and enabled items which have
|
||||
* `isFocused` property from top left to bottom right.
|
||||
* \note There are items handled differently (e.g. ListView)
|
||||
*/
|
||||
class FocusController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FocusController(QQmlApplicationEngine* engine, QObject *parent = nullptr);
|
||||
~FocusController() override = default;
|
||||
|
||||
Q_INVOKABLE void nextKeyTabItem();
|
||||
Q_INVOKABLE void previousKeyTabItem();
|
||||
Q_INVOKABLE void nextKeyUpItem();
|
||||
Q_INVOKABLE void nextKeyDownItem();
|
||||
Q_INVOKABLE void nextKeyLeftItem();
|
||||
Q_INVOKABLE void nextKeyRightItem();
|
||||
Q_INVOKABLE void setFocusItem(QQuickItem* item);
|
||||
Q_INVOKABLE void setFocusOnDefaultItem();
|
||||
Q_INVOKABLE void pushRootObject(QObject* object);
|
||||
Q_INVOKABLE void dropRootObject(QObject* object);
|
||||
Q_INVOKABLE void resetRootObject();
|
||||
|
||||
private:
|
||||
enum class Direction {
|
||||
Forward,
|
||||
Backward,
|
||||
};
|
||||
|
||||
void reload(Direction direction);
|
||||
void nextItem(Direction direction);
|
||||
void focusNextListViewItem();
|
||||
void focusPreviousListViewItem();
|
||||
void dropListView();
|
||||
|
||||
QSharedPointer<QQmlApplicationEngine> m_engine; // Pointer to engine to get root object
|
||||
QList<QObject*> m_focusChain; // List of current objects to be focused
|
||||
QQuickItem* m_focusedItem; // Pointer to the active focus item
|
||||
QStack<QObject*> m_rootObjects;
|
||||
QSharedPointer<QQuickItem> m_defaultFocusItem;
|
||||
|
||||
ListViewFocusController* m_lvfc; // ListView focus manager
|
||||
|
||||
signals:
|
||||
void focusedItemChanged();
|
||||
};
|
||||
|
||||
#endif // FOCUSCONTROLLER_H
|
||||
393
client/ui/controllers/listViewFocusController.cpp
Normal file
393
client/ui/controllers/listViewFocusController.cpp
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
#include "listViewFocusController.h"
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QQueue>
|
||||
#include <QPointF>
|
||||
#include <QRectF>
|
||||
#include <QQuickWindow>
|
||||
|
||||
|
||||
bool isVisible(QObject* item)
|
||||
{
|
||||
const auto res = item->property("visible").toBool();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool isFocusable(QObject* item)
|
||||
{
|
||||
const auto res = item->property("isFocusable").toBool();
|
||||
return res;
|
||||
}
|
||||
|
||||
QPointF getItemCenterPointOnScene(QQuickItem* item)
|
||||
{
|
||||
const auto x0 = item->x() + (item->width() / 2);
|
||||
const auto y0 = item->y() + (item->height() / 2);
|
||||
return item->parentItem()->mapToScene(QPointF{x0, y0});
|
||||
}
|
||||
|
||||
bool isLess(QObject* item1, QObject* item2)
|
||||
{
|
||||
const auto p1 = getItemCenterPointOnScene(qobject_cast<QQuickItem*>(item1));
|
||||
const auto p2 = getItemCenterPointOnScene(qobject_cast<QQuickItem*>(item2));
|
||||
return (p1.y() == p2.y()) ? (p1.x() < p2.x()) : (p1.y() < p2.y());
|
||||
}
|
||||
|
||||
bool isMore(QObject* item1, QObject* item2)
|
||||
{
|
||||
return !isLess(item1, item2);
|
||||
}
|
||||
|
||||
bool isEnabled(QObject* obj)
|
||||
{
|
||||
const auto item = qobject_cast<QQuickItem*>(obj);
|
||||
return item && item->isEnabled();
|
||||
}
|
||||
|
||||
QList<QObject*> getItemsChain(QObject* object)
|
||||
{
|
||||
QList<QObject*> res;
|
||||
if (!object) {
|
||||
qDebug() << "The object is NULL";
|
||||
return res;
|
||||
}
|
||||
|
||||
const auto children = object->children();
|
||||
|
||||
for(const auto child : children) {
|
||||
if (child
|
||||
&& isFocusable(child)
|
||||
&& isEnabled(child)
|
||||
&& isVisible(child)
|
||||
) {
|
||||
res.append(child);
|
||||
} else {
|
||||
res.append(getItemsChain(child));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void printItems(const QList<QObject*>& items, QObject* current_item)
|
||||
{
|
||||
for(const auto& item : items) {
|
||||
QQuickItem* i = qobject_cast<QQuickItem*>(item);
|
||||
QPointF coords {getItemCenterPointOnScene(i)};
|
||||
QString prefix = current_item == i ? "==>" : " ";
|
||||
qDebug() << prefix << " Item: " << i << " with coords: " << coords;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ListViewFocusController::ListViewFocusController(QQuickItem* listView, QObject* parent)
|
||||
: QObject{parent}
|
||||
, m_listView{listView}
|
||||
, m_focusChain{}
|
||||
, m_currentSection{Section::Default}
|
||||
, m_header{nullptr}
|
||||
, m_footer{nullptr}
|
||||
, m_focusedItem{nullptr}
|
||||
, m_focusedItemIndex{-1}
|
||||
, m_delegateIndex{0}
|
||||
, m_isReturnNeeded{false}
|
||||
, m_currentSectionString {"Default", "Header", "Delegate", "Footer"}
|
||||
{
|
||||
QVariant headerItemProperty = m_listView->property("headerItem");
|
||||
m_header = headerItemProperty.canConvert<QQuickItem*>() ? headerItemProperty.value<QQuickItem*>() : nullptr;
|
||||
|
||||
QVariant footerItemProperty = m_listView->property("footerItem");
|
||||
m_footer = footerItemProperty.canConvert<QQuickItem*>() ? footerItemProperty.value<QQuickItem*>() : nullptr;
|
||||
}
|
||||
|
||||
ListViewFocusController::~ListViewFocusController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ListViewFocusController::viewAtCurrentIndex() const
|
||||
{
|
||||
switch(m_currentSection) {
|
||||
case Section::Default:
|
||||
[[fallthrough]];
|
||||
case Section::Header: {
|
||||
qDebug() << "===>> [FOCUS ON BEGINNING...]";
|
||||
QMetaObject::invokeMethod(m_listView, "positionViewAtBeginning");
|
||||
break;
|
||||
}
|
||||
case Section::Delegate: {
|
||||
qDebug() << "===>> [FOCUS ON INDEX...]";
|
||||
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex",
|
||||
Q_ARG(int, m_delegateIndex), // Index
|
||||
Q_ARG(int, 2)); // PositionMode (0 = Visible)
|
||||
break;
|
||||
}
|
||||
case Section::Footer: {
|
||||
qDebug() << "===>> [FOCUS ON END...]";
|
||||
QMetaObject::invokeMethod(m_listView, "positionViewAtEnd");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int ListViewFocusController::size() const
|
||||
{
|
||||
return m_listView->property("count").toInt();
|
||||
}
|
||||
|
||||
int ListViewFocusController::currentIndex() const
|
||||
{
|
||||
return m_delegateIndex;
|
||||
}
|
||||
|
||||
void ListViewFocusController::nextDelegate()
|
||||
{
|
||||
const auto sectionName = m_currentSectionString[static_cast<int>(m_currentSection)];
|
||||
qDebug() << "===>> [nextDelegate... current section: " << sectionName << " ]";
|
||||
switch(m_currentSection) {
|
||||
case Section::Default: {
|
||||
if(hasHeader()) {
|
||||
m_currentSection = Section::Header;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case Section::Header: {
|
||||
if (size() > 0) {
|
||||
m_currentSection = Section::Delegate;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case Section::Delegate:
|
||||
if (m_delegateIndex < (size() - 1)) {
|
||||
m_delegateIndex++;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
} else if (hasFooter()) {
|
||||
m_currentSection = Section::Footer;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case Section::Footer: {
|
||||
m_isReturnNeeded = true;
|
||||
m_currentSection = Section::Default;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
qCritical() << "Current section is invalid!";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ListViewFocusController::previousDelegate()
|
||||
{
|
||||
switch(m_currentSection) {
|
||||
case Section::Default: {
|
||||
if(hasFooter()) {
|
||||
m_currentSection = Section::Footer;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case Section::Footer: {
|
||||
if (size() > 0) {
|
||||
m_currentSection = Section::Delegate;
|
||||
m_delegateIndex = size() - 1;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case Section::Delegate: {
|
||||
if (m_delegateIndex > 0) {
|
||||
m_delegateIndex--;
|
||||
break;
|
||||
} else if (hasHeader()) {
|
||||
m_currentSection = Section::Header;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case Section::Header: {
|
||||
m_isReturnNeeded = true;
|
||||
m_currentSection = Section::Default;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
qCritical() << "Current section is invalid!";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ListViewFocusController::decrementIndex()
|
||||
{
|
||||
m_delegateIndex--;
|
||||
}
|
||||
|
||||
QQuickItem* ListViewFocusController::itemAtIndex(const int index) const
|
||||
{
|
||||
QQuickItem* item{nullptr};
|
||||
|
||||
QMetaObject::invokeMethod(m_listView, "itemAtIndex",
|
||||
Q_RETURN_ARG(QQuickItem*, item),
|
||||
Q_ARG(int, index));
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
QQuickItem* ListViewFocusController::currentDelegate() const
|
||||
{
|
||||
QQuickItem* result{nullptr};
|
||||
|
||||
switch(m_currentSection) {
|
||||
case Section::Default: {
|
||||
qWarning() << "No elements...";
|
||||
break;
|
||||
}
|
||||
case Section::Header: {
|
||||
result = m_header;
|
||||
break;
|
||||
}
|
||||
case Section::Delegate: {
|
||||
result = itemAtIndex(m_delegateIndex);
|
||||
break;
|
||||
}
|
||||
case Section::Footer: {
|
||||
result = m_footer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QQuickItem* ListViewFocusController::focusedItem() const
|
||||
{
|
||||
return m_focusedItem;
|
||||
}
|
||||
|
||||
void ListViewFocusController::focusNextItem()
|
||||
{
|
||||
if (m_isReturnNeeded) {
|
||||
qDebug() << "===>> [ RETURN IS NEEDED... ]";
|
||||
return;
|
||||
}
|
||||
|
||||
m_focusChain = getItemsChain(currentDelegate());
|
||||
|
||||
if (m_focusChain.empty()) {
|
||||
qWarning() << "No elements found in the delegate. Going to next delegate...";
|
||||
nextDelegate();
|
||||
focusNextItem();
|
||||
return;
|
||||
}
|
||||
m_focusedItemIndex++;
|
||||
m_focusedItem = qobject_cast<QQuickItem*>(m_focusChain.at(m_focusedItemIndex));
|
||||
qDebug() << "==>> [ Focused Item: " << m_focusedItem << " with Index: " << m_focusedItemIndex << " ]";
|
||||
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
|
||||
}
|
||||
|
||||
void ListViewFocusController::focusPreviousItem()
|
||||
{
|
||||
if (m_isReturnNeeded) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_focusChain.empty()) {
|
||||
qDebug() << "Empty focusChain with current delegate: " << currentDelegate() << "Scanning for elements...";
|
||||
m_focusChain = getItemsChain(currentDelegate());
|
||||
}
|
||||
if (m_focusChain.empty()) {
|
||||
qWarning() << "No elements found in the delegate. Going to next delegate...";
|
||||
previousDelegate();
|
||||
focusPreviousItem();
|
||||
return;
|
||||
}
|
||||
if (m_focusedItemIndex == -1) {
|
||||
m_focusedItemIndex = m_focusChain.size();
|
||||
}
|
||||
m_focusedItemIndex--;
|
||||
m_focusedItem = qobject_cast<QQuickItem*>(m_focusChain.at(m_focusedItemIndex));
|
||||
qDebug() << "==>> [ Focused Item: " << m_focusedItem << " with Index: " << m_focusedItemIndex << " ]";
|
||||
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
|
||||
}
|
||||
|
||||
void ListViewFocusController::resetFocusChain()
|
||||
{
|
||||
m_focusChain.clear();
|
||||
m_focusedItem = nullptr;
|
||||
m_focusedItemIndex = -1;
|
||||
}
|
||||
|
||||
bool ListViewFocusController::isFirstFocusItemInDelegate() const
|
||||
{
|
||||
return m_focusedItem && (m_focusedItem == m_focusChain.first());
|
||||
}
|
||||
|
||||
bool ListViewFocusController::isLastFocusItemInDelegate() const
|
||||
{
|
||||
return m_focusedItem && (m_focusedItem == m_focusChain.last());
|
||||
}
|
||||
|
||||
bool ListViewFocusController::hasHeader() const
|
||||
{
|
||||
return m_header && !getItemsChain(m_header).isEmpty();
|
||||
}
|
||||
|
||||
bool ListViewFocusController::hasFooter() const
|
||||
{
|
||||
return m_footer && !getItemsChain(m_footer).isEmpty();
|
||||
}
|
||||
|
||||
bool ListViewFocusController::isFirstFocusItemInListView() const
|
||||
{
|
||||
switch (m_currentSection) {
|
||||
case Section::Footer: {
|
||||
return isFirstFocusItemInDelegate() && !hasHeader() && (size() == 0);
|
||||
}
|
||||
case Section::Delegate: {
|
||||
return isFirstFocusItemInDelegate() && (m_delegateIndex == 0) && !hasHeader();
|
||||
}
|
||||
case Section::Header: {
|
||||
isFirstFocusItemInDelegate();
|
||||
}
|
||||
case Section::Default: {
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
qWarning() << "Wrong section";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ListViewFocusController::isLastFocusItemInListView() const
|
||||
{
|
||||
switch (m_currentSection) {
|
||||
case Section::Default: {
|
||||
return !hasHeader() && (size() == 0) && !hasFooter();
|
||||
}
|
||||
case Section::Header: {
|
||||
return isLastFocusItemInDelegate() && (size() == 0) && !hasFooter();
|
||||
}
|
||||
case Section::Delegate: {
|
||||
return isLastFocusItemInDelegate() && (m_delegateIndex == size() - 1) && !hasFooter();
|
||||
}
|
||||
case Section::Footer: {
|
||||
return isLastFocusItemInDelegate();
|
||||
}
|
||||
default:
|
||||
qWarning() << "Wrong section";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ListViewFocusController::isReturnNeeded() const
|
||||
{
|
||||
return m_isReturnNeeded;
|
||||
}
|
||||
76
client/ui/controllers/listViewFocusController.h
Normal file
76
client/ui/controllers/listViewFocusController.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef LISTVIEWFOCUSCONTROLLER_H
|
||||
#define LISTVIEWFOCUSCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStack>
|
||||
#include <QSharedPointer>
|
||||
#include <QQuickItem>
|
||||
|
||||
|
||||
bool isEnabled(QObject* item);
|
||||
bool isFocusable(QObject* item);
|
||||
bool isMore(QObject* item1, QObject* item2);
|
||||
bool isLess(QObject* item1, QObject* item2);
|
||||
QList<QObject*> getSubChain(QObject* object);
|
||||
|
||||
void printItems(const QList<QObject*>& items, QObject* current_item);
|
||||
|
||||
/*!
|
||||
* \brief The ListViewFocusController class manages the focus of elements in ListView
|
||||
* \details This class object moving focus to ListView's controls since ListView stores
|
||||
* it's data implicitly and it could be got one by one.
|
||||
*
|
||||
* This class was made to store as less as possible data getting it from QML
|
||||
* when it's needed.
|
||||
*/
|
||||
class ListViewFocusController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ListViewFocusController(QQuickItem* listView, QObject* parent = nullptr);
|
||||
~ListViewFocusController();
|
||||
|
||||
void nextDelegate();
|
||||
void previousDelegate();
|
||||
void decrementIndex();
|
||||
void focusNextItem();
|
||||
void focusPreviousItem();
|
||||
void resetFocusChain();
|
||||
bool isFirstFocusItemInListView() const;
|
||||
bool isFirstFocusItemInDelegate() const;
|
||||
bool isLastFocusItemInListView() const;
|
||||
bool isLastFocusItemInDelegate() const;
|
||||
bool isReturnNeeded() const;
|
||||
|
||||
private:
|
||||
enum class Section {
|
||||
Default,
|
||||
Header,
|
||||
Delegate,
|
||||
Footer,
|
||||
};
|
||||
|
||||
int size() const;
|
||||
int currentIndex() const;
|
||||
void viewAtCurrentIndex() const;
|
||||
QQuickItem* itemAtIndex(const int index) const;
|
||||
QQuickItem* currentDelegate() const;
|
||||
QQuickItem* focusedItem() const;
|
||||
|
||||
bool hasHeader() const;
|
||||
bool hasFooter() const;
|
||||
|
||||
QQuickItem* m_listView;
|
||||
QList<QObject*> m_focusChain;
|
||||
Section m_currentSection;
|
||||
QQuickItem* m_header;
|
||||
QQuickItem* m_footer;
|
||||
QQuickItem* m_focusedItem; // Pointer to focused item on Delegate
|
||||
qsizetype m_focusedItemIndex;
|
||||
qsizetype m_delegateIndex;
|
||||
bool m_isReturnNeeded;
|
||||
|
||||
QList<QString> m_currentSectionString;
|
||||
};
|
||||
|
||||
#endif // LISTVIEWFOCUSCONTROLLER_H
|
||||
|
|
@ -81,7 +81,7 @@ void PageController::keyPressEvent(Qt::Key key)
|
|||
case Qt::Key_Escape: {
|
||||
if (m_drawerDepth) {
|
||||
emit closeTopDrawer();
|
||||
setDrawerDepth(getDrawerDepth() - 1);
|
||||
decrementDrawerDepth();
|
||||
} else {
|
||||
emit escapePressed();
|
||||
}
|
||||
|
|
@ -142,11 +142,25 @@ void PageController::setDrawerDepth(const int depth)
|
|||
}
|
||||
}
|
||||
|
||||
int PageController::getDrawerDepth()
|
||||
int PageController::getDrawerDepth() const
|
||||
{
|
||||
return m_drawerDepth;
|
||||
}
|
||||
|
||||
int PageController::incrementDrawerDepth()
|
||||
{
|
||||
return ++m_drawerDepth;
|
||||
}
|
||||
|
||||
int PageController::decrementDrawerDepth()
|
||||
{
|
||||
if (m_drawerDepth == 0) {
|
||||
return m_drawerDepth;
|
||||
} else {
|
||||
return --m_drawerDepth;
|
||||
}
|
||||
}
|
||||
|
||||
void PageController::onShowErrorMessage(ErrorCode errorCode)
|
||||
{
|
||||
const auto fullErrorMessage = errorString(errorCode);
|
||||
|
|
|
|||
|
|
@ -100,7 +100,9 @@ public slots:
|
|||
void closeApplication();
|
||||
|
||||
void setDrawerDepth(const int depth);
|
||||
int getDrawerDepth();
|
||||
int getDrawerDepth() const;
|
||||
int incrementDrawerDepth();
|
||||
int decrementDrawerDepth();
|
||||
|
||||
private slots:
|
||||
void onShowErrorMessage(amnezia::ErrorCode errorCode);
|
||||
|
|
@ -135,9 +137,6 @@ signals:
|
|||
void escapePressed();
|
||||
void closeTopDrawer();
|
||||
|
||||
void forceTabBarActiveFocus();
|
||||
void forceStackActiveFocus();
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,12 @@ bool ServersModel::setData(const QModelIndex &index, const QVariant &value, int
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ServersModel::setData(const int index, const QVariant &value, int role)
|
||||
{
|
||||
QModelIndex modelIndex = this->index(index);
|
||||
return setData(modelIndex, value, role);
|
||||
}
|
||||
|
||||
QVariant ServersModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_servers.size())) {
|
||||
|
|
@ -679,6 +685,18 @@ QVariant ServersModel::getProcessedServerData(const QString roleString)
|
|||
return {};
|
||||
}
|
||||
|
||||
bool ServersModel::setProcessedServerData(const QString& roleString, const QVariant& value)
|
||||
{
|
||||
const auto roles = roleNames();
|
||||
for (auto it = roles.begin(); it != roles.end(); it++) {
|
||||
if (QString(it.value()) == roleString) {
|
||||
return setData(m_processedServerIndex, value, it.key());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
|
||||
{
|
||||
auto server = m_servers.at(m_defaultServerIndex).toObject();
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ public:
|
|||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
bool setData(const int index, const QVariant &value, int role = Qt::EditRole);
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QVariant data(const int index, int role = Qt::DisplayRole) const;
|
||||
|
||||
|
|
@ -115,6 +116,7 @@ public slots:
|
|||
QVariant getDefaultServerData(const QString roleString);
|
||||
|
||||
QVariant getProcessedServerData(const QString roleString);
|
||||
bool setProcessedServerData(const QString &roleString, const QVariant &value);
|
||||
|
||||
bool isDefaultServerDefaultContainerHasSplitTunneling();
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,32 @@ Button {
|
|||
property string connectedButtonColor: AmneziaStyle.color.goldenApricot
|
||||
property bool buttonActiveFocus: activeFocus && (Qt.platform.os !== "android" || SettingsController.isOnTv())
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitWidth: 190
|
||||
implicitHeight: 190
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ DrawerType2 {
|
|||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
|
|
@ -26,14 +26,6 @@ DrawerType2 {
|
|||
root.expandedHeight = content.implicitHeight + 32
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
|
@ -44,11 +36,6 @@ DrawerType2 {
|
|||
headerText: qsTr("Add new connection")
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: ip.rightButton
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: ip
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -59,10 +46,8 @@ DrawerType2 {
|
|||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: qrCode.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -76,10 +61,8 @@ DrawerType2 {
|
|||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
|
|||
|
|
@ -17,56 +17,87 @@ ListView {
|
|||
property var rootWidth
|
||||
property var selectedText
|
||||
|
||||
property bool a: true
|
||||
|
||||
width: rootWidth
|
||||
height: menuContent.contentItem.height
|
||||
height: contentItem.height // TODO: It should be fixed size, not content item height
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
// interactive: false
|
||||
|
||||
property FlickableType parentFlickable
|
||||
property var lastItemTabClicked
|
||||
// property FlickableType parentFlickable
|
||||
// property var lastItemTabClicked
|
||||
|
||||
property int currentFocusIndex: 0
|
||||
// property int currentFocusIndex: 0
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
this.currentFocusIndex = 0
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
}
|
||||
}
|
||||
// snapMode: ListView.SnapToItem
|
||||
|
||||
// ScrollBar.vertical: ScrollBar {}
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (currentFocusIndex < this.count - 1) {
|
||||
currentFocusIndex += 1
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
} else {
|
||||
currentFocusIndex = 0
|
||||
if (lastItemTabClicked && typeof lastItemTabClicked === "function") {
|
||||
lastItemTabClicked()
|
||||
}
|
||||
}
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
currentFocusIndex = 0
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
onCurrentFocusIndexChanged: {
|
||||
if (parentFlickable) {
|
||||
parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex))
|
||||
}
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
// activeFocusOnTab: true
|
||||
// onActiveFocusChanged: {
|
||||
// console.log("===========================")
|
||||
// positionViewAtEnd()
|
||||
// parentFlickable.ensureVisible(this.itemAtIndex(6))
|
||||
// if (activeFocus) {
|
||||
// this.currentFocusIndex = 0
|
||||
// this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
// }
|
||||
// }
|
||||
|
||||
// Keys.onTabPressed: {
|
||||
// if (currentFocusIndex < this.count - 1) {
|
||||
// currentFocusIndex += 1
|
||||
// this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
// } else {
|
||||
// currentFocusIndex = 0
|
||||
// if (lastItemTabClicked && typeof lastItemTabClicked === "function") {
|
||||
// lastItemTabClicked()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// onVisibleChanged: {
|
||||
// if (visible) {
|
||||
// currentFocusIndex = 0
|
||||
// focusItem.forceActiveFocus()
|
||||
// }
|
||||
// }
|
||||
|
||||
// Item {
|
||||
// id: focusItem
|
||||
// }
|
||||
|
||||
// onCurrentFocusIndexChanged: {
|
||||
// if (parentFlickable) {
|
||||
// parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex))
|
||||
// }
|
||||
// }
|
||||
|
||||
ButtonGroup {
|
||||
id: containersRadioButtonGroup
|
||||
}
|
||||
|
|
@ -75,12 +106,6 @@ ListView {
|
|||
implicitWidth: rootWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
containerRadioButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
|
|
@ -111,13 +136,13 @@ ListView {
|
|||
}
|
||||
|
||||
if (checked) {
|
||||
containersDropDown.close()
|
||||
containersDropDown.closeTriggered() // TODO: containersDropDown is outside this file
|
||||
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyDefaultServerContainersModel.mapToSource(index))
|
||||
} else {
|
||||
ContainersModel.setProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
|
||||
InstallController.setShouldCreateServer(false)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
||||
containersDropDown.close()
|
||||
containersDropDown.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ DrawerType2 {
|
|||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
|
|
@ -24,14 +24,6 @@ DrawerType2 {
|
|||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
|
@ -43,11 +35,6 @@ DrawerType2 {
|
|||
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: splitTunnelingSwitch.visible ? splitTunnelingSwitch : siteBasedSplitTunnelingSwitch.rightButton
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: splitTunnelingSwitch
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -59,11 +46,9 @@ DrawerType2 {
|
|||
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: siteBasedSplitTunnelingSwitch.visible ? siteBasedSplitTunnelingSwitch.rightButton : focusItem
|
||||
|
||||
clickedFunction: function() {
|
||||
// PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
// root.close()
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,13 +65,9 @@ DrawerType2 {
|
|||
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: appSplitTunnelingSwitch.visible ?
|
||||
appSplitTunnelingSwitch.rightButton :
|
||||
focusItem
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,11 +84,9 @@ DrawerType2 {
|
|||
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ DrawerType2 {
|
|||
id: installedAppsModel
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
id: container
|
||||
|
||||
implicitHeight: expandedHeight
|
||||
|
|
@ -43,7 +43,7 @@ DrawerType2 {
|
|||
BackButtonType {
|
||||
backButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
backButtonFunction: function() {
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +69,8 @@ DrawerType2 {
|
|||
clip: true
|
||||
interactive: true
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyInstalledAppsModel
|
||||
sourceModel: installedAppsModel
|
||||
|
|
@ -155,7 +157,7 @@ DrawerType2 {
|
|||
PageController.showBusyIndicator(true)
|
||||
AppSplitTunnelingController.addApps(installedAppsModel.getSelectedAppsInfo())
|
||||
PageController.showBusyIndicator(false)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ DrawerType2 {
|
|||
property var yesButtonFunction
|
||||
property var noButtonFunction
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
|
|
@ -33,14 +33,6 @@ DrawerType2 {
|
|||
root.expandedHeight = content.implicitHeight + 32
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
|
@ -59,11 +51,6 @@ DrawerType2 {
|
|||
text: descriptionText
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: yesButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: yesButton
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -78,8 +65,6 @@ DrawerType2 {
|
|||
yesButtonFunction()
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: noButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -102,8 +87,6 @@ DrawerType2 {
|
|||
noButtonFunction()
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import "../Config"
|
|||
DrawerType2 {
|
||||
id: root
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
id: container
|
||||
|
||||
implicitHeight: root.height * 0.9
|
||||
|
|
@ -20,19 +20,6 @@ DrawerType2 {
|
|||
root.expandedHeight = container.implicitHeight
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -43,167 +30,173 @@ DrawerType2 {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
backButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
backButtonFunction: function() { root.close() }
|
||||
KeyNavigation.tab: listView
|
||||
backButtonFunction: function() { root.closeTriggered() }
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Choose language")
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
clip: true
|
||||
interactive: true
|
||||
|
||||
anchors.fill: parent
|
||||
property bool isFocusable: true
|
||||
|
||||
Header2Type {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
headerText: qsTr("Choose language")
|
||||
}
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
height: listView.contentItem.height
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
model: LanguageModel
|
||||
currentIndex: LanguageModel.currentLanguageIndex
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
}
|
||||
model: LanguageModel
|
||||
currentIndex: LanguageModel.currentLanguageIndex
|
||||
|
||||
property int currentFocusIndex: 0
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
}
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
this.currentFocusIndex = 0
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
}
|
||||
}
|
||||
delegate: Item {
|
||||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (currentFocusIndex < this.count - 1) {
|
||||
currentFocusIndex += 1
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
} else {
|
||||
listViewFocusItem.forceActiveFocus()
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
RadioButton {
|
||||
id: radioButton
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: radioButtonContent.implicitHeight
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Item {
|
||||
id: listViewFocusItem
|
||||
Keys.onTabPressed: {
|
||||
root.forceActiveFocus()
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
listViewFocusItem.forceActiveFocus()
|
||||
focusItem.forceActiveFocus()
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
radioButton.forceActiveFocus()
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
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 {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
RowLayout {
|
||||
id: radioButtonContent
|
||||
anchors.fill: parent
|
||||
|
||||
RadioButton {
|
||||
id: radioButton
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: radioButtonContent.implicitHeight
|
||||
spacing: 0
|
||||
|
||||
hoverEnabled: true
|
||||
z: 1
|
||||
|
||||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
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
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 20
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
text: languageName
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: radioButtonContent
|
||||
anchors.fill: parent
|
||||
Image {
|
||||
source: "qrc:/images/controls/check.svg"
|
||||
visible: radioButton.checked
|
||||
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
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)
|
||||
root.close()
|
||||
}
|
||||
Layout.rightMargin: 8
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: radioButton.clicked()
|
||||
Keys.onReturnPressed: radioButton.clicked()
|
||||
ButtonGroup.group: buttonGroup
|
||||
checked: listView.currentIndex === index
|
||||
|
||||
onClicked: {
|
||||
listView.currentIndex = index
|
||||
LanguageModel.changeLanguage(languageIndex)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: radioButton.clicked()
|
||||
Keys.onReturnPressed: radioButton.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
133
client/ui/qml/Components/ServersListView.qml
Normal file
133
client/ui/qml/Components/ServersListView.qml
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ProtocolEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import ContainersModelFilters 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
anchors.top: serversMenuHeader.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.topMargin: 16
|
||||
|
||||
model: ServersModel
|
||||
currentIndex: ServersModel.defaultIndex
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollBar
|
||||
objectName: "scrollBar"
|
||||
policy: root.height >= root.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
|
||||
}
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Connections {
|
||||
target: ServersModel
|
||||
function onDefaultServerIndexChanged(serverIndex) {
|
||||
root.currentIndex = serverIndex
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
delegate: Item {
|
||||
id: menuContentDelegate
|
||||
objectName: "menuContentDelegate"
|
||||
|
||||
property variant delegateData: model
|
||||
property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
|
||||
|
||||
implicitWidth: root.width
|
||||
implicitHeight: serverRadioButtonContent.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: serverRadioButtonContent
|
||||
objectName: "serverRadioButtonContent"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
objectName: "serverRadioButtonRowLayout"
|
||||
|
||||
Layout.fillWidth: true
|
||||
VerticalRadioButton {
|
||||
id: serverRadioButton
|
||||
objectName: "serverRadioButton"
|
||||
|
||||
Layout.fillWidth: true
|
||||
focus: true
|
||||
text: name
|
||||
descriptionText: serverDescription
|
||||
|
||||
checked: index === root.currentIndex
|
||||
checkable: !ConnectionController.isConnected
|
||||
|
||||
ButtonGroup.group: serversRadioButtonGroup
|
||||
|
||||
onClicked: {
|
||||
if (ConnectionController.isConnected) {
|
||||
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
|
||||
return
|
||||
}
|
||||
|
||||
root.currentIndex = index
|
||||
|
||||
ServersModel.defaultIndex = index
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: serverRadioButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: serverRadioButton.clicked()
|
||||
Keys.onReturnPressed: serverRadioButton.clicked()
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: serverInfoButton
|
||||
objectName: "serverInfoButton"
|
||||
|
||||
image: "qrc:/images/controls/settings.svg"
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
z: 1
|
||||
|
||||
onClicked: function() {
|
||||
ServersModel.processedIndex = index
|
||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||
drawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 0
|
||||
Layout.rightMargin: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,28 +22,7 @@ ListView {
|
|||
clip: true
|
||||
interactive: false
|
||||
|
||||
activeFocusOnTab: true
|
||||
Keys.onTabPressed: {
|
||||
if (currentIndex < this.count - 1) {
|
||||
this.incrementCurrentIndex()
|
||||
} else {
|
||||
currentIndex = 0
|
||||
lastItemTabClickedSignal()
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (visible) {
|
||||
if (fl.contentHeight > fl.height) {
|
||||
var item = this.currentItem
|
||||
if (item.y < fl.height) {
|
||||
fl.contentY = item.y
|
||||
} else if (item.y + item.height > fl.contentY + fl.height) {
|
||||
fl.contentY = item.y + item.height - fl.height
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
property bool isFocusable: false
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
|
|
@ -55,12 +34,6 @@ ListView {
|
|||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
containerRadioButton.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
|
|
|
|||
|
|
@ -36,17 +36,9 @@ DrawerType2 {
|
|||
configFileName = "amnezia_config"
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: root.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
header.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
id: header
|
||||
anchors.top: parent.top
|
||||
|
|
@ -57,24 +49,52 @@ DrawerType2 {
|
|||
anchors.rightMargin: 16
|
||||
|
||||
headerText: root.headerText
|
||||
|
||||
KeyNavigation.tab: shareButton
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: header.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height + 32
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
property bool isFocusable: true
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
model: 1
|
||||
|
||||
clip: true
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
visible: root.contentVisible
|
||||
|
||||
|
|
@ -82,12 +102,12 @@ DrawerType2 {
|
|||
id: shareButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Share")
|
||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
KeyNavigation.tab: copyConfigTextButton
|
||||
|
||||
clickedFunc: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
|
|
@ -111,6 +131,8 @@ DrawerType2 {
|
|||
id: copyConfigTextButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
|
|
@ -124,14 +146,14 @@ DrawerType2 {
|
|||
|
||||
Keys.onReturnPressed: { copyConfigTextButton.clicked() }
|
||||
Keys.onEnterPressed: { copyConfigTextButton.clicked() }
|
||||
|
||||
KeyNavigation.tab: copyNativeConfigStringButton.visible ? copyNativeConfigStringButton : showSettingsButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: copyNativeConfigStringButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: false
|
||||
|
||||
|
|
@ -153,6 +175,8 @@ DrawerType2 {
|
|||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
|
|
@ -164,10 +188,8 @@ DrawerType2 {
|
|||
text: qsTr("Show connection settings")
|
||||
|
||||
clickedFunc: function() {
|
||||
configContentDrawer.open()
|
||||
configContentDrawer.openTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: header
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
|
|
@ -178,30 +200,11 @@ DrawerType2 {
|
|||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
header.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
id: configContentContainer
|
||||
|
||||
implicitHeight: configContentDrawer.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: configContentDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: copyNativeConfigStringButton
|
||||
function onClicked() {
|
||||
|
|
@ -231,9 +234,7 @@ DrawerType2 {
|
|||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() { configContentDrawer.close() }
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
backButtonFunction: function() { configContentDrawer.closeTriggered() }
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -302,6 +303,10 @@ DrawerType2 {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
Rectangle {
|
||||
id: qrCodeContainer
|
||||
|
|
@ -309,6 +314,8 @@ DrawerType2 {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: ExportController.qrCodesCount > 0
|
||||
|
||||
|
|
@ -320,6 +327,32 @@ DrawerType2 {
|
|||
|
||||
source: ExportController.qrCodesCount ? ExportController.qrCodes[0] : ""
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
Timer {
|
||||
property int index: 0
|
||||
interval: 1000
|
||||
|
|
@ -346,6 +379,8 @@ DrawerType2 {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: ExportController.qrCodesCount > 0
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ Rectangle {
|
|||
implicitWidth: (rootWidth - 32) / 2
|
||||
text: "UDP"
|
||||
|
||||
KeyNavigation.tab: tcpButton
|
||||
|
||||
onClicked: {
|
||||
root.currentIndex = 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Qt5Compat.GraphicalEffects
|
|||
|
||||
import Style 1.0
|
||||
|
||||
Item {
|
||||
FocusScope {
|
||||
id: root
|
||||
|
||||
property string backButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
|
|
@ -15,12 +15,6 @@ Item {
|
|||
|
||||
visible: backButtonImage !== ""
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
backButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,32 @@ Button {
|
|||
|
||||
property alias buttonTextLabel: buttonText
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitHeight: 56
|
||||
|
||||
hoverEnabled: true
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ RadioButton {
|
|||
property string pressedBorderColor: AmneziaStyle.color.softGoldenApricot
|
||||
property string selectedBorderColor: AmneziaStyle.color.goldenApricot
|
||||
property string defaultBodredColor: AmneziaStyle.color.transparent
|
||||
property string focusBorderColor: AmneziaStyle.color.paleGray
|
||||
property int borderWidth: 0
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
|
|
@ -29,6 +30,32 @@ RadioButton {
|
|||
|
||||
hoverEnabled: true
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 16
|
||||
|
|
@ -52,6 +79,8 @@ RadioButton {
|
|||
return pressedBorderColor
|
||||
} else if (root.checked) {
|
||||
return selectedBorderColor
|
||||
} else if (root.activeFocus) {
|
||||
return focusBorderColor
|
||||
}
|
||||
}
|
||||
return defaultBodredColor
|
||||
|
|
@ -59,7 +88,7 @@ RadioButton {
|
|||
|
||||
border.width: {
|
||||
if (root.enabled) {
|
||||
if(root.checked) {
|
||||
if(root.checked || root.activeFocus) {
|
||||
return 1
|
||||
}
|
||||
return root.pressed ? 1 : 0
|
||||
|
|
|
|||
|
|
@ -25,10 +25,15 @@ Button {
|
|||
|
||||
property real textOpacity: 1.0
|
||||
|
||||
property alias focusItem: rightImage
|
||||
|
||||
property FlickableType parentFlickable
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
anchors.fill: parent
|
||||
radius: 16
|
||||
|
||||
|
|
@ -39,13 +44,31 @@ Button {
|
|||
}
|
||||
}
|
||||
|
||||
function ensureVisible(item) {
|
||||
if (item.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
ensureVisible(root)
|
||||
}
|
||||
|
||||
focusItem.onFocusChanged: {
|
||||
root.ensureVisible(focusItem)
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Image {
|
||||
|
|
@ -61,6 +84,7 @@ Button {
|
|||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
ListItemTitleType {
|
||||
text: root.headerText
|
||||
visible: text !== ""
|
||||
|
|
@ -123,6 +147,7 @@ Button {
|
|||
|
||||
Rectangle {
|
||||
id: rightImageBackground
|
||||
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: "transparent"
|
||||
|
|
@ -131,10 +156,9 @@ Button {
|
|||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,17 +9,17 @@ import "TextTypes"
|
|||
Item {
|
||||
id: root
|
||||
|
||||
readonly property string drawerExpanded: "expanded"
|
||||
readonly property string drawerCollapsed: "collapsed"
|
||||
readonly property string drawerExpandedStateName: "expanded"
|
||||
readonly property string drawerCollapsedStateName: "collapsed"
|
||||
|
||||
readonly property bool isOpened: drawerContent.state === root.drawerExpanded || (drawerContent.state === root.drawerCollapsed && dragArea.drag.active === true)
|
||||
readonly property bool isClosed: drawerContent.state === root.drawerCollapsed && dragArea.drag.active === false
|
||||
// readonly property bool isExpanded: isExpandedStateActive()
|
||||
// readonly property bool isCollapsed: isCollapsedStateActive()
|
||||
|
||||
readonly property bool isExpanded: drawerContent.state === root.drawerExpanded
|
||||
readonly property bool isCollapsed: drawerContent.state === root.drawerCollapsed
|
||||
readonly property bool isOpened: isExpandedStateActive() || (isCollapsedStateActive && (dragArea.drag.active === true))
|
||||
readonly property bool isClosed: isCollapsedStateActive() && (dragArea.drag.active === false)
|
||||
|
||||
property Component collapsedContent
|
||||
property Component expandedContent
|
||||
property Component collapsedStateContent
|
||||
property Component expandedStateContent
|
||||
|
||||
property string defaultColor: AmneziaStyle.color.onyxBlack
|
||||
property string borderColor: AmneziaStyle.color.slateGray
|
||||
|
|
@ -29,29 +29,41 @@ Item {
|
|||
|
||||
property int depthIndex: 0
|
||||
|
||||
signal entered
|
||||
signal exited
|
||||
signal cursorEntered
|
||||
signal cursorExited
|
||||
signal pressed(bool pressed, bool entered)
|
||||
|
||||
signal aboutToHide
|
||||
signal aboutToShow
|
||||
signal close
|
||||
signal open
|
||||
signal closeTriggered
|
||||
signal openTriggered
|
||||
signal closed
|
||||
signal opened
|
||||
|
||||
function isExpandedStateActive() {
|
||||
return isStateActive(drawerExpandedStateName)
|
||||
}
|
||||
|
||||
function isCollapsedStateActive() {
|
||||
return isStateActive(drawerCollapsedStateName)
|
||||
}
|
||||
|
||||
function isStateActive(stateName) {
|
||||
return drawerContent.state === stateName
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PageController
|
||||
|
||||
function onCloseTopDrawer() {
|
||||
if (depthIndex === PageController.getDrawerDepth()) {
|
||||
if (isCollapsed) {
|
||||
if (isCollapsedStateActive()) {
|
||||
return
|
||||
}
|
||||
|
||||
aboutToHide()
|
||||
|
||||
drawerContent.state = root.drawerCollapsed
|
||||
drawerContent.state = root.drawerCollapsedStateName
|
||||
depthIndex = 0
|
||||
closed()
|
||||
}
|
||||
|
|
@ -61,30 +73,52 @@ Item {
|
|||
Connections {
|
||||
target: root
|
||||
|
||||
function onClose() {
|
||||
if (isCollapsed) {
|
||||
function onCloseTriggered() {
|
||||
if (isCollapsedStateActive()) {
|
||||
return
|
||||
}
|
||||
|
||||
aboutToHide()
|
||||
|
||||
drawerContent.state = root.drawerCollapsed
|
||||
depthIndex = 0
|
||||
PageController.setDrawerDepth(PageController.getDrawerDepth() - 1)
|
||||
closed()
|
||||
}
|
||||
|
||||
function onOpen() {
|
||||
if (isExpanded) {
|
||||
function onClosed() {
|
||||
drawerContent.state = root.drawerCollapsedStateName
|
||||
|
||||
if (root.isCollapsedStateActive()) {
|
||||
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
|
||||
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
|
||||
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
|
||||
}
|
||||
}
|
||||
|
||||
depthIndex = 0
|
||||
PageController.decrementDrawerDepth()
|
||||
FocusController.dropRootObject(root)
|
||||
}
|
||||
|
||||
function onOpenTriggered() {
|
||||
if (root.isExpandedStateActive()) {
|
||||
return
|
||||
}
|
||||
|
||||
aboutToShow()
|
||||
root.aboutToShow()
|
||||
|
||||
drawerContent.state = root.drawerExpanded
|
||||
depthIndex = PageController.getDrawerDepth() + 1
|
||||
PageController.setDrawerDepth(depthIndex)
|
||||
opened()
|
||||
root.opened()
|
||||
}
|
||||
|
||||
function onOpened() {
|
||||
drawerContent.state = root.drawerExpandedStateName
|
||||
|
||||
if (isExpandedStateActive()) {
|
||||
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
|
||||
PageController.updateNavigationBarColor(0xFF1C1D21)
|
||||
}
|
||||
}
|
||||
|
||||
depthIndex = PageController.incrementDrawerDepth()
|
||||
FocusController.pushRootObject(root)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,18 +136,17 @@ Item {
|
|||
MouseArea {
|
||||
id: emptyArea
|
||||
anchors.fill: parent
|
||||
enabled: root.isExpanded
|
||||
visible: enabled
|
||||
|
||||
onClicked: {
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dragArea
|
||||
objectName: "dragArea"
|
||||
|
||||
anchors.fill: drawerContentBackground
|
||||
cursorShape: root.isCollapsed ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
hoverEnabled: true
|
||||
|
||||
enabled: drawerContent.implicitHeight > 0
|
||||
|
|
@ -125,35 +158,36 @@ Item {
|
|||
|
||||
/** If drag area is released at any point other than min or max y, transition to the other state */
|
||||
onReleased: {
|
||||
if (root.isCollapsed && drawerContent.y < dragArea.drag.maximumY) {
|
||||
root.open()
|
||||
if (isCollapsedStateActive() && drawerContent.y < dragArea.drag.maximumY) {
|
||||
root.openTriggered()
|
||||
return
|
||||
}
|
||||
if (root.isExpanded && drawerContent.y > dragArea.drag.minimumY) {
|
||||
root.close()
|
||||
if (isExpandedStateActive() && drawerContent.y > dragArea.drag.minimumY) {
|
||||
root.closeTriggered()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
root.entered()
|
||||
root.cursorEntered()
|
||||
}
|
||||
onExited: {
|
||||
root.exited()
|
||||
root.cursorExited()
|
||||
}
|
||||
onPressedChanged: {
|
||||
root.pressed(pressed, entered)
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (root.isCollapsed) {
|
||||
root.open()
|
||||
if (isCollapsedStateActive()) {
|
||||
root.openTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: drawerContentBackground
|
||||
objectName: "drawerContentBackground"
|
||||
|
||||
anchors { left: drawerContent.left; right: drawerContent.right; top: drawerContent.top }
|
||||
height: root.height
|
||||
|
|
@ -174,53 +208,80 @@ Item {
|
|||
|
||||
Item {
|
||||
id: drawerContent
|
||||
objectName: "drawerContent"
|
||||
|
||||
Drag.active: dragArea.drag.active
|
||||
anchors.right: root.right
|
||||
anchors.left: root.left
|
||||
y: root.height - drawerContent.height
|
||||
state: root.drawerCollapsed
|
||||
|
||||
implicitHeight: root.isCollapsed ? collapsedHeight : expandedHeight
|
||||
|
||||
onStateChanged: {
|
||||
if (root.isCollapsed) {
|
||||
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
|
||||
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
|
||||
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (root.isExpanded) {
|
||||
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
|
||||
PageController.updateNavigationBarColor(0xFF1C1D21)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
state: root.drawerCollapsedStateName
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: root.drawerCollapsed
|
||||
name: root.drawerCollapsedStateName
|
||||
PropertyChanges {
|
||||
target: drawerContent
|
||||
implicitHeight: collapsedHeight
|
||||
y: root.height - root.collapsedHeight
|
||||
}
|
||||
PropertyChanges {
|
||||
target: background
|
||||
color: AmneziaStyle.color.transparent
|
||||
}
|
||||
PropertyChanges {
|
||||
target: dragArea
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
PropertyChanges {
|
||||
target: emptyArea
|
||||
enabled: false
|
||||
visible: false
|
||||
}
|
||||
PropertyChanges {
|
||||
target: collapsedLoader
|
||||
// visible: true
|
||||
}
|
||||
PropertyChanges {
|
||||
target: expandedLoader
|
||||
visible: false
|
||||
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: root.drawerExpanded
|
||||
name: root.drawerExpandedStateName
|
||||
PropertyChanges {
|
||||
target: drawerContent
|
||||
implicitHeight: expandedHeight
|
||||
y: dragArea.drag.minimumY
|
||||
|
||||
}
|
||||
PropertyChanges {
|
||||
target: background
|
||||
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
|
||||
}
|
||||
PropertyChanges {
|
||||
target: dragArea
|
||||
cursorShape: Qt.ArrowCursor
|
||||
}
|
||||
PropertyChanges {
|
||||
target: emptyArea
|
||||
enabled: true
|
||||
visible: true
|
||||
}
|
||||
PropertyChanges {
|
||||
target: collapsedLoader
|
||||
// visible: false
|
||||
}
|
||||
PropertyChanges {
|
||||
target: expandedLoader
|
||||
visible: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: root.drawerCollapsed
|
||||
to: root.drawerExpanded
|
||||
from: root.drawerCollapsedStateName
|
||||
to: root.drawerExpandedStateName
|
||||
PropertyAnimation {
|
||||
target: drawerContent
|
||||
properties: "y"
|
||||
|
|
@ -228,8 +289,8 @@ Item {
|
|||
}
|
||||
},
|
||||
Transition {
|
||||
from: root.drawerExpanded
|
||||
to: root.drawerCollapsed
|
||||
from: root.drawerExpandedStateName
|
||||
to: root.drawerCollapsedStateName
|
||||
PropertyAnimation {
|
||||
target: drawerContent
|
||||
properties: "y"
|
||||
|
|
@ -241,7 +302,7 @@ Item {
|
|||
Loader {
|
||||
id: collapsedLoader
|
||||
|
||||
sourceComponent: root.collapsedContent
|
||||
sourceComponent: root.collapsedStateContent
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
|
@ -250,8 +311,7 @@ Item {
|
|||
Loader {
|
||||
id: expandedLoader
|
||||
|
||||
visible: root.isExpanded
|
||||
sourceComponent: root.expandedContent
|
||||
sourceComponent: root.expandedStateContent
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
|
|
|||
|
|
@ -45,33 +45,56 @@ Item {
|
|||
property Item drawerParent
|
||||
property Component listView
|
||||
|
||||
signal open
|
||||
signal close
|
||||
signal openTriggered
|
||||
signal closeTriggered
|
||||
|
||||
function popupClosedFunc() {
|
||||
if (!GC.isMobile()) {
|
||||
this.forceActiveFocus()
|
||||
}
|
||||
readonly property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
property var parentFlickable
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitWidth: rootButtonContent.implicitWidth
|
||||
implicitHeight: rootButtonContent.implicitHeight
|
||||
|
||||
onOpen: {
|
||||
menu.open()
|
||||
onOpenTriggered: {
|
||||
menu.openTriggered()
|
||||
}
|
||||
|
||||
onClose: {
|
||||
menu.close()
|
||||
onCloseTriggered: {
|
||||
menu.closeTriggered()
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (menu.isClosed) {
|
||||
menu.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (menu.isClosed) {
|
||||
menu.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -173,7 +196,7 @@ Item {
|
|||
if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") {
|
||||
rootButtonClickedFunction()
|
||||
} else {
|
||||
menu.open()
|
||||
menu.openTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -186,27 +209,10 @@ Item {
|
|||
anchors.fill: parent
|
||||
expandedHeight: drawerParent.height * drawerHeight
|
||||
|
||||
onClosed: {
|
||||
root.popupClosedFunc()
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
id: container
|
||||
implicitHeight: menu.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: menu
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
|
|
@ -218,61 +224,40 @@ Item {
|
|||
BackButtonType {
|
||||
id: backButton
|
||||
backButtonImage: root.headerBackButtonImage
|
||||
backButtonFunction: function() { menu.close() }
|
||||
KeyNavigation.tab: listViewLoader.item
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: flickable
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: 16
|
||||
contentHeight: col.implicitHeight
|
||||
|
||||
Column {
|
||||
id: col
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 16
|
||||
|
||||
Header2Type {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
headerText: root.headerText
|
||||
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: listViewLoader
|
||||
sourceComponent: root.listView
|
||||
|
||||
onLoaded: {
|
||||
listViewLoader.item.parentFlickable = flickable
|
||||
listViewLoader.item.lastItemTabClicked = function() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
backButtonFunction: function() { menu.closeTriggered() }
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
root.listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (menu.isClosed) {
|
||||
menu.open()
|
||||
}
|
||||
}
|
||||
Column {
|
||||
id: col
|
||||
anchors.top: header.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (menu.isClosed) {
|
||||
menu.open()
|
||||
spacing: 16
|
||||
|
||||
Header2Type {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
headerText: root.headerText
|
||||
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: listViewLoader
|
||||
sourceComponent: root.listView
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ Flickable {
|
|||
|
||||
function ensureVisible(item) {
|
||||
if (item.y < fl.contentY) {
|
||||
fl.contentY = item.y
|
||||
fl.contentY = item.y - 40 // 40 is a top margin
|
||||
} else if (item.y + item.height > fl.contentY + fl.height) {
|
||||
fl.contentY = item.y + item.height - fl.height + 40 // 40 is a bottom margin
|
||||
}
|
||||
fl.returnToBounds()
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ Item {
|
|||
|
||||
property string descriptionText
|
||||
|
||||
focus: true
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,32 @@ RadioButton {
|
|||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 16
|
||||
|
|
|
|||
|
|
@ -24,22 +24,39 @@ Button {
|
|||
property int borderFocusedWidth: 1
|
||||
|
||||
hoverEnabled: true
|
||||
focus: true
|
||||
focusPolicy: Qt.TabFocus
|
||||
|
||||
icon.source: image
|
||||
icon.color: root.enabled ? imageColor : disableImageColor
|
||||
|
||||
property Flickable parentFlickable
|
||||
property bool isFocusable: true
|
||||
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(this)
|
||||
}
|
||||
}
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: root.clicked()
|
||||
Keys.onReturnPressed: root.clicked()
|
||||
|
||||
Behavior on icon.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,32 @@ Item {
|
|||
property bool descriptionOnTop: false
|
||||
property bool hideDescription: true
|
||||
|
||||
property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
||||
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
|
||||
|
||||
|
|
|
|||
|
|
@ -26,47 +26,31 @@ ListView {
|
|||
height: root.contentItem.height
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
|
||||
property FlickableType parentFlickable
|
||||
property var lastItemTabClicked
|
||||
|
||||
property int currentFocusIndex: 0
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
this.currentFocusIndex = 0
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
}
|
||||
}
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (currentFocusIndex < this.count - 1) {
|
||||
currentFocusIndex += 1
|
||||
} else {
|
||||
currentFocusIndex = 0
|
||||
}
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
Keys.onTabPressed: {
|
||||
root.forceActiveFocus()
|
||||
}
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
onCurrentFocusIndexChanged: {
|
||||
if (parentFlickable) {
|
||||
parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex))
|
||||
}
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
|
|
@ -75,94 +59,110 @@ ListView {
|
|||
|
||||
function triggerCurrentItem() {
|
||||
var item = root.itemAtIndex(currentIndex)
|
||||
var radioButton = item.children[0].children[0]
|
||||
var radioButton = item.children[0]
|
||||
radioButton.clicked()
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
delegate: ColumnLayout {
|
||||
id: content
|
||||
|
||||
implicitWidth: rootWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
// implicitHeight: content.implicitHeight
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
radioButton.forceActiveFocus()
|
||||
RadioButton {
|
||||
id: radioButton
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: radioButtonContent.implicitHeight
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
id: radioButton
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: radioButtonContent.implicitHeight
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
hoverEnabled: true
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
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
|
||||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
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 {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: radioButtonContent
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
RowLayout {
|
||||
id: radioButtonContent
|
||||
anchors.fill: parent
|
||||
|
||||
z: 1
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 20
|
||||
z: 1
|
||||
|
||||
text: name
|
||||
maximumLineCount: root.textMaximumLineCount
|
||||
elide: root.textElide
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 20
|
||||
|
||||
}
|
||||
text: name
|
||||
maximumLineCount: root.textMaximumLineCount
|
||||
elide: root.textElide
|
||||
|
||||
Image {
|
||||
source: imageSource
|
||||
visible: radioButton.checked
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
Layout.rightMargin: 8
|
||||
}
|
||||
}
|
||||
|
||||
ButtonGroup.group: buttonGroup
|
||||
checked: root.currentIndex === index
|
||||
Image {
|
||||
source: imageSource
|
||||
visible: radioButton.checked
|
||||
|
||||
onClicked: {
|
||||
root.currentIndex = index
|
||||
root.selectedText = name
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
Layout.rightMargin: 8
|
||||
}
|
||||
}
|
||||
|
||||
ButtonGroup.group: buttonGroup
|
||||
checked: root.currentIndex === index
|
||||
|
||||
onClicked: {
|
||||
root.currentIndex = index
|
||||
root.selectedText = name
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,51 +9,19 @@ Item {
|
|||
|
||||
property StackView stackView: StackView.view
|
||||
|
||||
property var defaultActiveFocusItem: null
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible && !GC.isMobile()) {
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
|
||||
function lastItemTabClicked(focusItem) {
|
||||
if (GC.isMobile()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (focusItem) {
|
||||
focusItem.forceActiveFocus()
|
||||
PageController.forceTabBarActiveFocus()
|
||||
} else {
|
||||
if (defaultActiveFocusItem) {
|
||||
defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
PageController.forceTabBarActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
// MouseArea {
|
||||
// id: globalMouseArea
|
||||
// z: 99
|
||||
// anchors.fill: parent
|
||||
|
||||
// enabled: true
|
||||
|
||||
// onPressed: function(mouse) {
|
||||
// forceActiveFocus()
|
||||
// mouse.accepted = false
|
||||
// }
|
||||
// }
|
||||
|
||||
// Set a timer to set focus after a short delay
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 100 // Milliseconds
|
||||
interval: 200 // Milliseconds
|
||||
onTriggered: {
|
||||
if (defaultActiveFocusItem) {
|
||||
defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
FocusController.resetRootObject()
|
||||
FocusController.setFocusOnDefaultItem()
|
||||
}
|
||||
repeat: false // Stop the timer after one trigger
|
||||
running: !GC.isMobile() // Start the timer
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
import "../Config"
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
|
|
@ -28,11 +29,11 @@ Popup {
|
|||
}
|
||||
|
||||
onOpened: {
|
||||
focusItem.forceActiveFocus()
|
||||
timer.start()
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
PageController.forceStackActiveFocus()
|
||||
FocusController.dropRootObject(root)
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
|
|
@ -42,6 +43,19 @@ Popup {
|
|||
radius: 4
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 400 // Milliseconds
|
||||
onTriggered: {
|
||||
if (!GC.isMobile()) {
|
||||
FocusController.setFocusItem(closeButton)
|
||||
FocusController.pushRootObject(root)
|
||||
}
|
||||
}
|
||||
repeat: false // Stop the timer after one trigger
|
||||
running: !GC.isMobile() // Start the timer
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
|
@ -72,11 +86,6 @@ Popup {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: closeButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: closeButton
|
||||
visible: closeButtonVisible
|
||||
|
|
@ -92,7 +101,6 @@ Popup {
|
|||
borderWidth: 0
|
||||
|
||||
text: qsTr("Close")
|
||||
KeyNavigation.tab: focusItem
|
||||
|
||||
clickedFunc: function() {
|
||||
root.close()
|
||||
|
|
|
|||
|
|
@ -35,10 +35,37 @@ Switch {
|
|||
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite
|
||||
property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
hoverEnabled: enabled ? true : false
|
||||
focusPolicy: Qt.TabFocus
|
||||
|
||||
property FlickableType parentFlickable: null
|
||||
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
|
|
@ -132,12 +159,26 @@ Switch {
|
|||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
root.checked = !root.checked
|
||||
root.checkedChanged()
|
||||
if (!event.isAutoRepeat) {
|
||||
root.checked = !root.checked
|
||||
root.checkedChanged()
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
root.checked = !root.checked
|
||||
root.checkedChanged()
|
||||
if (!event.isAutoRepeat) {
|
||||
root.checked = !root.checked
|
||||
root.checkedChanged()
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
Keys.onSpacePressed: {
|
||||
if (!event.isAutoRepeat) {
|
||||
root.checked = !root.checked
|
||||
root.checkedChanged()
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,35 @@ TabButton {
|
|||
|
||||
property bool isSelected: false
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitHeight: 48
|
||||
|
||||
hoverEnabled: true
|
||||
focusPolicy: Qt.TabFocus
|
||||
|
||||
background: Rectangle {
|
||||
id: background
|
||||
|
|
|
|||
|
|
@ -14,13 +14,38 @@ TabButton {
|
|||
|
||||
property bool isSelected: false
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property var clickedFunc
|
||||
|
||||
hoverEnabled: true
|
||||
focusPolicy: Qt.TabFocus
|
||||
|
||||
icon.source: image
|
||||
icon.color: isSelected ? selectedColor : defaultColor
|
||||
|
|
@ -41,7 +66,7 @@ TabButton {
|
|||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
|
|
|
|||
|
|
@ -78,9 +78,6 @@ Rectangle {
|
|||
placeholderText: root.placeholderText
|
||||
text: root.text
|
||||
|
||||
|
||||
KeyNavigation.tab: firstButton
|
||||
|
||||
onCursorVisibleChanged: {
|
||||
if (textArea.cursorVisible) {
|
||||
fl.interactive = true
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ Item {
|
|||
implicitHeight: content.implicitHeight
|
||||
|
||||
property FlickableType parentFlickable
|
||||
|
||||
Connections {
|
||||
target: textField
|
||||
function onFocusChanged() {
|
||||
|
|
@ -84,7 +85,16 @@ Item {
|
|||
|
||||
TextField {
|
||||
id: textField
|
||||
activeFocusOnTab: false
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
enabled: root.textFieldEditable
|
||||
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
|
||||
|
|
@ -209,9 +219,9 @@ Item {
|
|||
clickedFunc()
|
||||
}
|
||||
|
||||
if (KeyNavigation.tab) {
|
||||
KeyNavigation.tab.forceActiveFocus();
|
||||
}
|
||||
// if (KeyNavigation.tab) {
|
||||
// KeyNavigation.tab.forceActiveFocus();
|
||||
// }
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
|
|
@ -219,8 +229,8 @@ Item {
|
|||
clickedFunc()
|
||||
}
|
||||
|
||||
if (KeyNavigation.tab) {
|
||||
KeyNavigation.tab.forceActiveFocus();
|
||||
}
|
||||
// if (KeyNavigation.tab) {
|
||||
// KeyNavigation.tab.forceActiveFocus();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,34 @@ RadioButton {
|
|||
property string imageSource
|
||||
property bool showImage
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
hoverEnabled: true
|
||||
focusPolicy: Qt.TabFocus
|
||||
// focusPolicy: Qt.TabFocus
|
||||
|
||||
indicator: Rectangle {
|
||||
id: background
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -34,7 +27,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
// KeyNavigation.tab: removeButton
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +53,6 @@ PageType {
|
|||
headerText: "Dev menu"
|
||||
}
|
||||
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: passwordTextField
|
||||
|
||||
|
|
@ -86,8 +77,6 @@ PageType {
|
|||
SettingsController.gatewayEndpoint = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
// KeyNavigation.tab: saveButton
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Connections {
|
||||
objectName: "pageControllerConnections"
|
||||
|
||||
target: PageController
|
||||
|
||||
function onRestorePageHomeState(isContainerInstalled) {
|
||||
drawer.open()
|
||||
drawer.openTriggered()
|
||||
if (isContainerInstalled) {
|
||||
containersDropDown.rootButtonClickedFunction()
|
||||
}
|
||||
|
|
@ -33,23 +33,22 @@ PageType {
|
|||
}
|
||||
|
||||
Item {
|
||||
objectName: "homeColumnItem"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: drawer.collapsedHeight
|
||||
|
||||
ColumnLayout {
|
||||
objectName: "homeColumnLayout"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 34
|
||||
anchors.bottomMargin: 34
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: loggingButton.visible ?
|
||||
loggingButton :
|
||||
connectButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: loggingButton
|
||||
objectName: "loggingButton"
|
||||
|
||||
property bool isLoggingEnabled: SettingsController.isLoggingEnabled
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
|
@ -69,8 +68,6 @@ PageType {
|
|||
Keys.onEnterPressed: loggingButton.clicked()
|
||||
Keys.onReturnPressed: loggingButton.clicked()
|
||||
|
||||
KeyNavigation.tab: connectButton
|
||||
|
||||
onClicked: {
|
||||
PageController.goToPage(PageEnum.PageSettingsLogging)
|
||||
}
|
||||
|
|
@ -78,13 +75,15 @@ PageType {
|
|||
|
||||
ConnectButton {
|
||||
id: connectButton
|
||||
objectName: "connectButton"
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
KeyNavigation.tab: splitTunnelingButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: splitTunnelingButton
|
||||
objectName: "splitTunnelingButton"
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||
Layout.bottomMargin: 34
|
||||
|
|
@ -115,53 +114,44 @@ PageType {
|
|||
Keys.onEnterPressed: splitTunnelingButton.clicked()
|
||||
Keys.onReturnPressed: splitTunnelingButton.clicked()
|
||||
|
||||
KeyNavigation.tab: drawer
|
||||
|
||||
onClicked: {
|
||||
homeSplitTunnelingDrawer.open()
|
||||
homeSplitTunnelingDrawer.openTriggered()
|
||||
}
|
||||
|
||||
HomeSplitTunnelingDrawer {
|
||||
id: homeSplitTunnelingDrawer
|
||||
parent: root
|
||||
objectName: "homeSplitTunnelingDrawer"
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
parent: root
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DrawerType2 {
|
||||
id: drawer
|
||||
objectName: "drawerProtocol"
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
collapsedStateContent: Item {
|
||||
objectName: "ProtocolDrawerCollapsedContent"
|
||||
|
||||
collapsedContent: Item {
|
||||
implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
|
||||
Component.onCompleted: {
|
||||
drawer.expandedHeight = implicitHeight
|
||||
}
|
||||
|
||||
Connections {
|
||||
objectName: "drawerConnections"
|
||||
|
||||
target: drawer
|
||||
enabled: !GC.isMobile()
|
||||
function onActiveFocusChanged() {
|
||||
if (drawer.activeFocus && !drawer.isOpened) {
|
||||
collapsedButtonChevron.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: collapsed
|
||||
objectName: "collapsedColumnLayout"
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
|
@ -180,6 +170,8 @@ PageType {
|
|||
}
|
||||
|
||||
RowLayout {
|
||||
objectName: "rowLayout"
|
||||
|
||||
Layout.topMargin: 14
|
||||
Layout.leftMargin: 24
|
||||
Layout.rightMargin: 24
|
||||
|
|
@ -188,9 +180,11 @@ PageType {
|
|||
spacing: 0
|
||||
|
||||
Connections {
|
||||
objectName: "drawerConnections"
|
||||
|
||||
target: drawer
|
||||
function onEntered() {
|
||||
if (drawer.isCollapsed) {
|
||||
function onCursorEntered() {
|
||||
if (drawer.isCollapsedStateActive) {
|
||||
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
|
||||
collapsedButtonHeader.opacity = 0.8
|
||||
} else {
|
||||
|
|
@ -198,8 +192,8 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
function onExited() {
|
||||
if (drawer.isCollapsed) {
|
||||
function onCursorExited() {
|
||||
if (drawer.isCollapsedStateActive) {
|
||||
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
|
||||
collapsedButtonHeader.opacity = 1
|
||||
} else {
|
||||
|
|
@ -208,7 +202,7 @@ PageType {
|
|||
}
|
||||
|
||||
function onPressed(pressed, entered) {
|
||||
if (drawer.isCollapsed) {
|
||||
if (drawer.isCollapsedStateActive) {
|
||||
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
|
||||
collapsedButtonHeader.opacity = 0.7
|
||||
} else {
|
||||
|
|
@ -219,6 +213,8 @@ PageType {
|
|||
|
||||
Header1TextType {
|
||||
id: collapsedButtonHeader
|
||||
objectName: "collapsedButtonHeader"
|
||||
|
||||
Layout.maximumWidth: drawer.width - 48 - 18 - 12
|
||||
|
||||
maximumLineCount: 2
|
||||
|
|
@ -227,8 +223,6 @@ PageType {
|
|||
text: ServersModel.defaultServerName
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
|
||||
KeyNavigation.tab: tabBar
|
||||
|
||||
Behavior on opacity {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
|
@ -236,10 +230,11 @@ PageType {
|
|||
|
||||
ImageButtonType {
|
||||
id: collapsedButtonChevron
|
||||
objectName: "collapsedButtonChevron"
|
||||
|
||||
Layout.leftMargin: 8
|
||||
|
||||
visible: drawer.isCollapsed
|
||||
visible: drawer.isCollapsedStateActive()
|
||||
|
||||
hoverEnabled: false
|
||||
image: "qrc:/images/controls/chevron-down.svg"
|
||||
|
|
@ -254,18 +249,17 @@ PageType {
|
|||
|
||||
Keys.onEnterPressed: collapsedButtonChevron.clicked()
|
||||
Keys.onReturnPressed: collapsedButtonChevron.clicked()
|
||||
Keys.onTabPressed: lastItemTabClicked()
|
||||
|
||||
|
||||
onClicked: {
|
||||
if (drawer.isCollapsed) {
|
||||
drawer.open()
|
||||
if (drawer.isCollapsedStateActive()) {
|
||||
drawer.openTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
objectName: "rowLayoutLabel"
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16
|
||||
|
|
@ -316,6 +310,7 @@ PageType {
|
|||
|
||||
ColumnLayout {
|
||||
id: serversMenuHeader
|
||||
objectName: "serversMenuHeader"
|
||||
|
||||
anchors.top: collapsed.bottom
|
||||
anchors.right: parent.right
|
||||
|
|
@ -327,13 +322,9 @@ PageType {
|
|||
|
||||
visible: !ServersModel.isDefaultServerFromApi
|
||||
|
||||
Item {
|
||||
id: focusItem1
|
||||
KeyNavigation.tab: containersDropDown
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
id: containersDropDown
|
||||
objectName: "containersDropDown"
|
||||
|
||||
rootButtonImageColor: AmneziaStyle.color.midnightBlack
|
||||
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
|
||||
|
|
@ -344,28 +335,29 @@ PageType {
|
|||
rootButtonTextTopMargin: 8
|
||||
rootButtonTextBottomMargin: 8
|
||||
|
||||
enabled: drawer.isOpened
|
||||
|
||||
text: ServersModel.defaultServerDefaultContainerName
|
||||
textColor: AmneziaStyle.color.midnightBlack
|
||||
headerText: qsTr("VPN protocol")
|
||||
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
|
||||
rootButtonClickedFunction: function() {
|
||||
containersDropDown.open()
|
||||
containersDropDown.openTriggered()
|
||||
}
|
||||
|
||||
drawerParent: root
|
||||
KeyNavigation.tab: serversMenuContent
|
||||
|
||||
listView: HomeContainersListView {
|
||||
id: containersListView
|
||||
objectName: "containersListView"
|
||||
|
||||
rootWidth: root.width
|
||||
onVisibleChanged: {
|
||||
if (containersDropDown.visible && !GC.isMobile()) {
|
||||
focusItem1.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
height: 500 // TODO: make calculated
|
||||
|
||||
Connections {
|
||||
objectName: "rowLayoutConnections"
|
||||
|
||||
target: ServersModel
|
||||
|
||||
function onDefaultServerIndexChanged() {
|
||||
|
|
@ -407,167 +399,21 @@ PageType {
|
|||
|
||||
ButtonGroup {
|
||||
id: serversRadioButtonGroup
|
||||
objectName: "serversRadioButtonGroup"
|
||||
}
|
||||
|
||||
ListView {
|
||||
ServersListView {
|
||||
id: serversMenuContent
|
||||
objectName: "serversMenuContent"
|
||||
|
||||
anchors.top: serversMenuHeader.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.topMargin: 16
|
||||
|
||||
model: ServersModel
|
||||
currentIndex: ServersModel.defaultIndex
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollBar
|
||||
policy: serversMenuContent.height >= serversMenuContent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
|
||||
}
|
||||
|
||||
|
||||
activeFocusOnTab: true
|
||||
focus: true
|
||||
|
||||
property int focusItemIndex: 0
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
serversMenuContent.focusItemIndex = 0
|
||||
serversMenuContent.itemAtIndex(focusItemIndex).forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
onFocusItemIndexChanged: {
|
||||
const focusedElement = serversMenuContent.itemAtIndex(focusItemIndex)
|
||||
if (focusedElement) {
|
||||
if (focusedElement.y + focusedElement.height > serversMenuContent.height) {
|
||||
serversMenuContent.contentY = focusedElement.y + focusedElement.height - serversMenuContent.height
|
||||
} else {
|
||||
serversMenuContent.contentY = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onUpPressed: scrollBar.decrease()
|
||||
Keys.onDownPressed: scrollBar.increase()
|
||||
isFocusable: false
|
||||
|
||||
Connections {
|
||||
target: drawer
|
||||
enabled: !GC.isMobile()
|
||||
function onIsCollapsedChanged() {
|
||||
if (drawer.isCollapsed) {
|
||||
const item = serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex)
|
||||
if (item) { item.serverRadioButtonProperty.focus = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ServersModel
|
||||
function onDefaultServerIndexChanged(serverIndex) {
|
||||
serversMenuContent.currentIndex = serverIndex
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
delegate: Item {
|
||||
id: menuContentDelegate
|
||||
|
||||
property variant delegateData: model
|
||||
property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
|
||||
|
||||
implicitWidth: serversMenuContent.width
|
||||
implicitHeight: serverRadioButtonContent.implicitHeight
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
serverRadioButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: serverRadioButtonContent
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
VerticalRadioButton {
|
||||
id: serverRadioButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: name
|
||||
descriptionText: serverDescription
|
||||
|
||||
checked: index === serversMenuContent.currentIndex
|
||||
checkable: !ConnectionController.isConnected
|
||||
|
||||
ButtonGroup.group: serversRadioButtonGroup
|
||||
|
||||
onClicked: {
|
||||
if (ConnectionController.isConnected) {
|
||||
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
|
||||
return
|
||||
}
|
||||
|
||||
serversMenuContent.currentIndex = index
|
||||
|
||||
ServersModel.defaultIndex = index
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: serverRadioButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
Keys.onTabPressed: serverInfoButton.forceActiveFocus()
|
||||
Keys.onEnterPressed: serverRadioButton.clicked()
|
||||
Keys.onReturnPressed: serverRadioButton.clicked()
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: serverInfoButton
|
||||
image: "qrc:/images/controls/settings.svg"
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
z: 1
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (serversMenuContent.focusItemIndex < serversMenuContent.count - 1) {
|
||||
serversMenuContent.focusItemIndex++
|
||||
serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex).forceActiveFocus()
|
||||
} else {
|
||||
focusItem1.forceActiveFocus()
|
||||
serversMenuContent.contentY = 0
|
||||
}
|
||||
}
|
||||
Keys.onEnterPressed: serverInfoButton.clicked()
|
||||
Keys.onReturnPressed: serverInfoButton.clicked()
|
||||
|
||||
onClicked: function() {
|
||||
ServersModel.processedIndex = index
|
||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||
drawer.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 0
|
||||
Layout.rightMargin: 0
|
||||
}
|
||||
// this item shouldn't be focused when drawer is closed
|
||||
function onIsOpenedChanged() {
|
||||
serversMenuContent.isFocusable = drawer.isOpened
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,18 +16,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview.currentItem.mtuTextField.textField
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
onFocusChanged: {
|
||||
if (activeFocus) {
|
||||
fl.ensureVisible(focusItem)
|
||||
}
|
||||
}
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -39,229 +27,236 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview.currentItem.mtuTextField.textField
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
ListView {
|
||||
id: listview
|
||||
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin
|
||||
anchors.bottom: saveButton.top
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
clip: true
|
||||
|
||||
ListView {
|
||||
id: listview
|
||||
property bool isFocusable: true
|
||||
|
||||
width: parent.width
|
||||
height: listview.contentItem.height
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
model: AwgConfigModel
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
property alias mtuTextField: mtuTextField
|
||||
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
|
||||
junkPacketMaxSizeTextField.errorText === "" &&
|
||||
junkPacketMinSizeTextField.errorText === "" &&
|
||||
junkPacketCountTextField.errorText === ""
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
model: AwgConfigModel
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
|
||||
spacing: 0
|
||||
property alias mtuTextField: mtuTextField
|
||||
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
|
||||
junkPacketMaxSizeTextField.errorText === "" &&
|
||||
junkPacketMinSizeTextField.errorText === "" &&
|
||||
junkPacketCountTextField.errorText === ""
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
ColumnLayout {
|
||||
id: col
|
||||
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
}
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: mtuTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
headerText: qsTr("MTU")
|
||||
textFieldText: clientMtu
|
||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||
spacing: 0
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientMtu) {
|
||||
clientMtu = textFieldText
|
||||
}
|
||||
}
|
||||
checkEmptyText: true
|
||||
KeyNavigation.tab: junkPacketCountTextField.textField
|
||||
}
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketCountTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
}
|
||||
|
||||
headerText: "Jc - Junk packet count"
|
||||
textFieldText: clientJunkPacketCount
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
TextFieldWithHeaderType {
|
||||
id: mtuTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientJunkPacketCount) {
|
||||
clientJunkPacketCount = textFieldText
|
||||
}
|
||||
}
|
||||
headerText: qsTr("MTU")
|
||||
textFieldText: clientMtu
|
||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMinSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMinSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jmin - Junk packet minimum size"
|
||||
textFieldText: clientJunkPacketMinSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientJunkPacketMinSize) {
|
||||
clientJunkPacketMinSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMaxSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jmax - Junk packet maximum size"
|
||||
textFieldText: clientJunkPacketMaxSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientJunkPacketMaxSize) {
|
||||
clientJunkPacketMaxSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
Keys.onTabPressed: saveButton.forceActiveFocus()
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Server settings")
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textFieldText: port
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "S1 - Init packet junk size"
|
||||
textFieldText: serverInitPacketJunkSize
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "S2 - Response packet junk size"
|
||||
textFieldText: serverResponsePacketJunkSize
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H1 - Init packet magic header"
|
||||
textFieldText: serverInitPacketMagicHeader
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H2 - Response packet magic header"
|
||||
textFieldText: serverResponsePacketMagicHeader
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
parentFlickable: fl
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H3 - Underload packet magic header"
|
||||
textFieldText: serverUnderloadPacketMagicHeader
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H4 - Transport packet magic header"
|
||||
textFieldText: serverTransportPacketMagicHeader
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientMtu) {
|
||||
clientMtu = textFieldText
|
||||
}
|
||||
}
|
||||
checkEmptyText: true
|
||||
KeyNavigation.tab: junkPacketCountTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketCountTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jc - Junk packet count"
|
||||
textFieldText: clientJunkPacketCount
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientJunkPacketCount) {
|
||||
clientJunkPacketCount = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMinSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMinSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jmin - Junk packet minimum size"
|
||||
textFieldText: clientJunkPacketMinSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientJunkPacketMinSize) {
|
||||
clientJunkPacketMinSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMaxSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jmax - Junk packet maximum size"
|
||||
textFieldText: clientJunkPacketMaxSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== clientJunkPacketMaxSize) {
|
||||
clientJunkPacketMaxSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Server settings")
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textFieldText: port
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "S1 - Init packet junk size"
|
||||
textFieldText: serverInitPacketJunkSize
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "S2 - Response packet junk size"
|
||||
textFieldText: serverResponsePacketJunkSize
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H1 - Init packet magic header"
|
||||
textFieldText: serverInitPacketMagicHeader
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H2 - Response packet magic header"
|
||||
textFieldText: serverResponsePacketMagicHeader
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
parentFlickable: fl
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H3 - Underload packet magic header"
|
||||
textFieldText: serverUnderloadPacketMagicHeader
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H4 - Transport packet magic header"
|
||||
textFieldText: serverTransportPacketMagicHeader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +278,11 @@ PageType {
|
|||
|
||||
text: qsTr("Save")
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import QtCore
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
|
|
@ -17,18 +19,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview.currentItem.portTextField.textField
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
onFocusChanged: {
|
||||
if (activeFocus) {
|
||||
fl.ensureVisible(focusItem)
|
||||
}
|
||||
}
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -40,341 +30,357 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview.currentItem.portTextField.textField
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
ListView {
|
||||
id: listview
|
||||
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
property bool isFocusable: true
|
||||
|
||||
ListView {
|
||||
id: listview
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
height: listview.contentItem.height
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
model: AwgConfigModel
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
property alias portTextField: portTextField
|
||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
clip: true
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
model: AwgConfigModel
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
|
||||
spacing: 0
|
||||
property alias portTextField: portTextField
|
||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
ColumnLayout {
|
||||
id: col
|
||||
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
|
||||
enabled: delegateItem.isEnabled
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textFieldText: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== port) {
|
||||
port = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: mtuTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("MTU")
|
||||
textFieldText: mtu
|
||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText === "") {
|
||||
textFieldText = "0"
|
||||
}
|
||||
if (textFieldText !== mtu) {
|
||||
mtu = textFieldText
|
||||
}
|
||||
}
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketCountTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("Jc - Junk packet count")
|
||||
textFieldText: serverJunkPacketCount
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText === "") {
|
||||
textFieldText = "0"
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
if (textFieldText !== serverJunkPacketCount) {
|
||||
serverJunkPacketCount = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
enabled: delegateItem.isEnabled
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textFieldText: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
parentFlickable: fl
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMinSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== port) {
|
||||
port = textFieldText
|
||||
}
|
||||
headerText: qsTr("Jmin - Junk packet minimum size")
|
||||
textFieldText: serverJunkPacketMinSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverJunkPacketMinSize) {
|
||||
serverJunkPacketMinSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMaxSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("Jmax - Junk packet maximum size")
|
||||
textFieldText: serverJunkPacketMaxSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverJunkPacketMaxSize) {
|
||||
serverJunkPacketMaxSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("S1 - Init packet junk size")
|
||||
textFieldText: serverInitPacketJunkSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverInitPacketJunkSize) {
|
||||
serverInitPacketJunkSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("S2 - Response packet junk size")
|
||||
textFieldText: serverResponsePacketJunkSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverResponsePacketJunkSize) {
|
||||
serverResponsePacketJunkSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H1 - Init packet magic header")
|
||||
textFieldText: serverInitPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverInitPacketMagicHeader) {
|
||||
serverInitPacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H2 - Response packet magic header")
|
||||
textFieldText: serverResponsePacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverResponsePacketMagicHeader) {
|
||||
serverResponsePacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H4 - Transport packet magic header")
|
||||
textFieldText: serverTransportPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverTransportPacketMagicHeader) {
|
||||
serverTransportPacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H3 - Underload packet magic header")
|
||||
textFieldText: serverUnderloadPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverUnderloadPacketMagicHeader) {
|
||||
serverUnderloadPacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveRestartButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
|
||||
transportPacketMagicHeaderTextField.errorText === "" &&
|
||||
responsePacketMagicHeaderTextField.errorText === "" &&
|
||||
initPacketMagicHeaderTextField.errorText === "" &&
|
||||
responsePacketJunkSizeTextField.errorText === "" &&
|
||||
initPacketJunkSizeTextField.errorText === "" &&
|
||||
junkPacketMaxSizeTextField.errorText === "" &&
|
||||
junkPacketMinSizeTextField.errorText === "" &&
|
||||
junkPacketCountTextField.errorText === "" &&
|
||||
portTextField.errorText === ""
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
if (delegateItem.isEnabled) {
|
||||
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
|
||||
transportPacketMagicHeaderTextField.textField.text,
|
||||
responsePacketMagicHeaderTextField.textField.text,
|
||||
initPacketMagicHeaderTextField.textField.text)) {
|
||||
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
|
||||
return
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketCountTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketCountTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("Jc - Junk packet count")
|
||||
textFieldText: serverJunkPacketCount
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText === "") {
|
||||
textFieldText = "0"
|
||||
}
|
||||
|
||||
if (textFieldText !== serverJunkPacketCount) {
|
||||
serverJunkPacketCount = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMinSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMinSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("Jmin - Junk packet minimum size")
|
||||
textFieldText: serverJunkPacketMinSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverJunkPacketMinSize) {
|
||||
serverJunkPacketMinSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMaxSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("Jmax - Junk packet maximum size")
|
||||
textFieldText: serverJunkPacketMaxSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverJunkPacketMaxSize) {
|
||||
serverJunkPacketMaxSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: initPacketJunkSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("S1 - Init packet junk size")
|
||||
textFieldText: serverInitPacketJunkSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverInitPacketJunkSize) {
|
||||
serverInitPacketJunkSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: responsePacketJunkSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("S2 - Response packet junk size")
|
||||
textFieldText: serverResponsePacketJunkSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverResponsePacketJunkSize) {
|
||||
serverResponsePacketJunkSize = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: initPacketMagicHeaderTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H1 - Init packet magic header")
|
||||
textFieldText: serverInitPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverInitPacketMagicHeader) {
|
||||
serverInitPacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: responsePacketMagicHeaderTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H2 - Response packet magic header")
|
||||
textFieldText: serverResponsePacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverResponsePacketMagicHeader) {
|
||||
serverResponsePacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: transportPacketMagicHeaderTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H4 - Transport packet magic header")
|
||||
textFieldText: serverTransportPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverTransportPacketMagicHeader) {
|
||||
serverTransportPacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: underloadPacketMagicHeaderTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
parentFlickable: fl
|
||||
|
||||
headerText: qsTr("H3 - Underload packet magic header")
|
||||
textFieldText: serverUnderloadPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== serverUnderloadPacketMagicHeader) {
|
||||
serverUnderloadPacketMagicHeader = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: saveRestartButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveRestartButton
|
||||
parentFlickable: fl
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
|
||||
transportPacketMagicHeaderTextField.errorText === "" &&
|
||||
responsePacketMagicHeaderTextField.errorText === "" &&
|
||||
initPacketMagicHeaderTextField.errorText === "" &&
|
||||
responsePacketJunkSizeTextField.errorText === "" &&
|
||||
initPacketJunkSizeTextField.errorText === "" &&
|
||||
junkPacketMaxSizeTextField.errorText === "" &&
|
||||
junkPacketMinSizeTextField.errorText === "" &&
|
||||
junkPacketCountTextField.errorText === "" &&
|
||||
portTextField.errorText === ""
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
if (delegateItem.isEnabled) {
|
||||
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
|
||||
transportPacketMagicHeaderTextField.textField.text,
|
||||
responsePacketMagicHeaderTextField.textField.text,
|
||||
initPacketMagicHeaderTextField.textField.text)) {
|
||||
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
|
||||
return
|
||||
}
|
||||
|
||||
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
||||
parseInt(responsePacketJunkSizeTextField.textField.text))) {
|
||||
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var headerText = qsTr("Save settings?")
|
||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||
return
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateContainer(AwgConfigModel.getConfig())
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
saveRestartButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
||||
parseInt(responsePacketJunkSizeTextField.textField.text))) {
|
||||
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var headerText = qsTr("Save settings?")
|
||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||
return
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateContainer(AwgConfigModel.getConfig())
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
saveRestartButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -34,7 +27,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview.currentItem.trafficFromField.textField
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,8 +102,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: portTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
|
|
@ -130,8 +120,6 @@ PageType {
|
|||
port = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: cipherDropDown
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
|
|
@ -143,7 +131,6 @@ PageType {
|
|||
headerText: qsTr("Cipher")
|
||||
|
||||
drawerParent: root
|
||||
KeyNavigation.tab: saveRestartButton
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
|
|
@ -161,7 +148,7 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
cipherDropDown.close()
|
||||
cipherDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -184,7 +171,6 @@ PageType {
|
|||
Layout.bottomMargin: 24
|
||||
|
||||
text: qsTr("Save")
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
|
|
|||
|
|
@ -17,18 +17,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
fl.ensureVisible(focusItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -40,7 +28,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview.currentItem.vpnAddressSubnetTextField.textField
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +91,6 @@ PageType {
|
|||
textFieldText: subnetAddress
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: transportProtoSelector
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== subnetAddress) {
|
||||
|
|
@ -132,8 +118,6 @@ PageType {
|
|||
return transportProto === "tcp" ? 1 : 0
|
||||
}
|
||||
|
||||
KeyNavigation.tab: portTextField.enabled ? portTextField.textField : autoNegotiateEncryprionSwitcher
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (transportProto === "tcp" && currentIndex === 0) {
|
||||
transportProto = "udp"
|
||||
|
|
@ -162,8 +146,6 @@ PageType {
|
|||
port = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: autoNegotiateEncryprionSwitcher
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
|
|
@ -181,10 +163,6 @@ PageType {
|
|||
autoNegotiateEncryprion = checked
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: hashDropDown.enabled ?
|
||||
hashDropDown :
|
||||
tlsAuthCheckBox
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
|
|
@ -199,9 +177,6 @@ PageType {
|
|||
|
||||
drawerParent: root
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: cipherDropDown.enabled ?
|
||||
cipherDropDown :
|
||||
tlsAuthCheckBox
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: hashListView
|
||||
|
|
@ -224,7 +199,7 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
hashDropDown.text = selectedText
|
||||
hash = hashDropDown.text
|
||||
hashDropDown.close()
|
||||
hashDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -252,8 +227,6 @@ PageType {
|
|||
drawerParent: root
|
||||
parentFlickable: fl
|
||||
|
||||
KeyNavigation.tab: tlsAuthCheckBox
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
|
||||
|
|
@ -275,7 +248,7 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
cipherDropDown.close()
|
||||
cipherDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -320,8 +293,6 @@ PageType {
|
|||
text: qsTr("TLS auth")
|
||||
checked: tlsAuth
|
||||
|
||||
KeyNavigation.tab: blockDnsCheckBox
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== tlsAuth) {
|
||||
console.log("tlsAuth changed to: " + checked)
|
||||
|
|
@ -339,8 +310,6 @@ PageType {
|
|||
text: qsTr("Block DNS requests outside of VPN")
|
||||
checked: blockDns
|
||||
|
||||
KeyNavigation.tab: additionalClientCommandsSwitcher
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== blockDns) {
|
||||
blockDns = checked
|
||||
|
|
@ -355,9 +324,6 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: additionalClientCommandsTextArea.visible ?
|
||||
additionalClientCommandsTextArea.textArea :
|
||||
additionalServerCommandsSwitcher
|
||||
|
||||
checked: additionalClientCommands !== ""
|
||||
|
||||
|
|
@ -376,7 +342,7 @@ PageType {
|
|||
Layout.topMargin: 16
|
||||
|
||||
visible: additionalClientCommandsSwitcher.checked
|
||||
KeyNavigation.tab: additionalServerCommandsSwitcher
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
textAreaText: additionalClientCommands
|
||||
|
|
@ -394,9 +360,6 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: additionalServerCommandsTextArea.visible ?
|
||||
additionalServerCommandsTextArea.textArea :
|
||||
saveRestartButton
|
||||
|
||||
checked: additionalServerCommands !== ""
|
||||
|
||||
|
|
@ -419,7 +382,6 @@ PageType {
|
|||
textAreaText: additionalServerCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: saveRestartButton
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalServerCommands !== textAreaText) {
|
||||
additionalServerCommands = textAreaText
|
||||
|
|
@ -436,7 +398,6 @@ PageType {
|
|||
|
||||
text: qsTr("Save")
|
||||
parentFlickable: fl
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
|
|
|||
|
|
@ -19,13 +19,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
|
|
@ -37,7 +30,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listView
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -101,11 +93,9 @@ PageType {
|
|||
text: qsTr("Show connection options")
|
||||
|
||||
clickedFunction: function() {
|
||||
configContentDrawer.open()
|
||||
configContentDrawer.openTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: removeButton
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: button
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
|
@ -120,31 +110,12 @@ PageType {
|
|||
|
||||
expandedHeight: root.height * 0.9
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
parent: root
|
||||
anchors.fill: parent
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: configContentDrawer.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: configContentDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem1.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem1
|
||||
KeyNavigation.tab: backButton1
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton1
|
||||
|
||||
|
|
@ -154,10 +125,8 @@ PageType {
|
|||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() {
|
||||
configContentDrawer.close()
|
||||
configContentDrawer.closeTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: focusItem1
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -226,7 +195,6 @@ PageType {
|
|||
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||
|
|
|
|||
|
|
@ -16,15 +16,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview.currentItem.focusItemId.enabled ?
|
||||
listview.currentItem.focusItemId.textField :
|
||||
focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -36,9 +27,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview.currentItem.focusItemId.enabled ?
|
||||
listview.currentItem.focusItemId.textField :
|
||||
focusItem
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,8 +102,6 @@ PageType {
|
|||
port = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: cipherDropDown
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
|
|
@ -129,9 +115,9 @@ PageType {
|
|||
headerText: qsTr("Cipher")
|
||||
|
||||
drawerParent: root
|
||||
KeyNavigation.tab: saveRestartButton
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
|
||||
id: cipherListView
|
||||
|
||||
rootWidth: root.width
|
||||
|
|
@ -147,7 +133,7 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
cipherDropDown.close()
|
||||
cipherDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -172,7 +158,6 @@ PageType {
|
|||
enabled: isPortEditable | isCipherEditable
|
||||
|
||||
text: qsTr("Save")
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
|
|
|||
|
|
@ -150,8 +150,6 @@ PageType {
|
|||
|
||||
text: qsTr("Save")
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
var headerText = qsTr("Save settings?")
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -34,7 +27,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,12 +56,12 @@ PageType {
|
|||
|
||||
model: WireGuardConfigModel
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
// activeFocusOnTab: true
|
||||
// onActiveFocusChanged: {
|
||||
// if (activeFocus) {
|
||||
// listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
|
||||
// }
|
||||
// }
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
|
|
@ -109,8 +101,6 @@ PageType {
|
|||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
KeyNavigation.tab: saveButton
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== port) {
|
||||
port = textFieldText
|
||||
|
|
@ -120,6 +110,26 @@ PageType {
|
|||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: mtuTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("MTU")
|
||||
textFieldText: mtu
|
||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText === "") {
|
||||
textFieldText = "0"
|
||||
}
|
||||
if (textFieldText !== mtu) {
|
||||
mtu = textFieldText
|
||||
}
|
||||
}
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -130,8 +140,6 @@ PageType {
|
|||
|
||||
text: qsTr("Save")
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
onClicked: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -35,7 +28,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,12 +57,12 @@ PageType {
|
|||
|
||||
model: XrayConfigModel
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
// activeFocusOnTab: true
|
||||
// onActiveFocusChanged: {
|
||||
// if (activeFocus) {
|
||||
// listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
|
||||
// }
|
||||
// }
|
||||
|
||||
delegate: Item {
|
||||
property alias focusItemId: textFieldWithHeaderType.textField
|
||||
|
|
@ -103,8 +95,6 @@ PageType {
|
|||
headerText: qsTr("Disguised as traffic from")
|
||||
textFieldText: site
|
||||
|
||||
KeyNavigation.tab: basicButton
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textFieldText !== site) {
|
||||
var tmpText = textFieldText
|
||||
|
|
@ -128,8 +118,6 @@ PageType {
|
|||
|
||||
text: qsTr("Save")
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
onClicked: {
|
||||
forceActiveFocus()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -34,7 +27,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: removeButton
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,8 +64,6 @@ PageType {
|
|||
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: root.lastItemTabClicked()
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||
var yesButtonText = qsTr("Continue")
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Connections {
|
||||
target: InstallController
|
||||
|
||||
|
|
@ -26,11 +24,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -42,7 +35,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +99,6 @@ PageType {
|
|||
Layout.topMargin: 32
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: portLabel.rightButton
|
||||
|
||||
text: qsTr("Host")
|
||||
descriptionText: ServersModel.getProcessedServerData("hostName")
|
||||
|
|
@ -136,7 +127,6 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: usernameLabel.rightButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
|
@ -160,7 +150,6 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: passwordLabel.eyeButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
|
@ -184,14 +173,6 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
parentFlickable: fl
|
||||
eyeButton.KeyNavigation.tab: passwordLabel.rightButton
|
||||
rightButton.Keys.onTabPressed: {
|
||||
if (mountButton.visible) {
|
||||
mountButton.forceActiveFocus()
|
||||
} else {
|
||||
detailedInstructionsButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
|
@ -225,7 +206,6 @@ PageType {
|
|||
borderWidth: 1
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: detailedInstructionsButton
|
||||
|
||||
text: qsTr("Mount folder on device")
|
||||
|
||||
|
|
@ -290,7 +270,6 @@ PageType {
|
|||
text: qsTr("Detailed instructions")
|
||||
|
||||
parentFlickable: fl
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: listview
|
||||
|
||||
Connections {
|
||||
target: InstallController
|
||||
|
||||
|
|
@ -27,11 +25,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -43,7 +36,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: listview
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +91,6 @@ PageType {
|
|||
Layout.topMargin: 32
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: portLabel.rightButton
|
||||
|
||||
text: qsTr("Host")
|
||||
descriptionText: ServersModel.getProcessedServerData("hostName")
|
||||
|
|
@ -128,7 +119,6 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: usernameLabel.rightButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
|
@ -152,7 +142,6 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
parentFlickable: fl
|
||||
KeyNavigation.tab: passwordLabel.eyeButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
|
@ -176,8 +165,6 @@ PageType {
|
|||
descriptionOnTop: true
|
||||
|
||||
parentFlickable: fl
|
||||
eyeButton.KeyNavigation.tab: passwordLabel.rightButton
|
||||
rightButton.KeyNavigation.tab: changeSettingsButton
|
||||
|
||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
|
@ -200,13 +187,7 @@ PageType {
|
|||
anchors.fill: parent
|
||||
expandedHeight: root.height * 0.9
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
property string tempPort: port
|
||||
property string tempUsername: username
|
||||
property string tempPassword: password
|
||||
|
|
@ -222,9 +203,6 @@ PageType {
|
|||
Connections {
|
||||
target: changeSettingsDrawer
|
||||
function onOpened() {
|
||||
if (!GC.isMobile()) {
|
||||
drawerFocusItem.forceActiveFocus()
|
||||
}
|
||||
tempPort = port
|
||||
tempUsername = username
|
||||
tempPassword = password
|
||||
|
|
@ -239,11 +217,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: drawerFocusItem
|
||||
KeyNavigation.tab: portTextField.textField
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
|
@ -268,8 +241,6 @@ PageType {
|
|||
port = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: usernameTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
|
|
@ -290,8 +261,6 @@ PageType {
|
|||
username = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: passwordTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
|
|
@ -322,8 +291,6 @@ PageType {
|
|||
password = textFieldText
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: saveButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -334,7 +301,6 @@ PageType {
|
|||
Layout.bottomMargin: 24
|
||||
|
||||
text: qsTr("Change connection settings")
|
||||
Keys.onTabPressed: lastItemTabClicked(drawerFocusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
|
@ -356,7 +322,7 @@ PageType {
|
|||
tempPort = portTextField.textFieldText
|
||||
tempUsername = usernameTextField.textFieldText
|
||||
tempPassword = passwordTextField.textFieldText
|
||||
changeSettingsDrawer.close()
|
||||
changeSettingsDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -372,11 +338,10 @@ PageType {
|
|||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Change connection settings")
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
changeSettingsDrawer.open()
|
||||
changeSettingsDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Connections {
|
||||
target: InstallController
|
||||
|
||||
|
|
@ -27,11 +25,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
|
@ -43,7 +36,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: websiteName.rightButton
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,8 +80,6 @@ PageType {
|
|||
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(descriptionText)
|
||||
PageController.showNotificationMessage(qsTr("Copied"))
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ import "../Config"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: header
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
|
|
@ -39,8 +37,6 @@ PageType {
|
|||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Settings")
|
||||
|
||||
KeyNavigation.tab: account.rightButton
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
|
|
@ -55,8 +51,6 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsServersList)
|
||||
}
|
||||
|
||||
KeyNavigation.tab: connection.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -72,8 +66,6 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsConnection)
|
||||
}
|
||||
|
||||
KeyNavigation.tab: application.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -89,8 +81,6 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsApplication)
|
||||
}
|
||||
|
||||
KeyNavigation.tab: backup.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -106,8 +96,6 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsBackup)
|
||||
}
|
||||
|
||||
KeyNavigation.tab: about.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -123,8 +111,6 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsAbout)
|
||||
}
|
||||
KeyNavigation.tab: close
|
||||
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -138,8 +124,6 @@ PageType {
|
|||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/bug.svg"
|
||||
|
||||
// Keys.onTabPressed: lastItemTabClicked(header)
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageDevMenu)
|
||||
}
|
||||
|
|
@ -156,10 +140,8 @@ PageType {
|
|||
Layout.preferredHeight: about.height
|
||||
|
||||
text: qsTr("Close application")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/x-circle.svg"
|
||||
isLeftImageHoverEnabled: false
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(header)
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.closeApplication()
|
||||
|
|
|
|||
|
|
@ -14,19 +14,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
|
||||
onFocusChanged: {
|
||||
if (focusItem.activeFocus) {
|
||||
fl.contentY = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -35,21 +22,109 @@ PageType {
|
|||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: telegramButton
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
QtObject {
|
||||
id: telegramGroup
|
||||
|
||||
property string title: qsTr("Telegram group")
|
||||
property string description: qsTr("To discuss features")
|
||||
property string imageSource: "qrc:/images/controls/telegram.svg"
|
||||
property var handler: function() {
|
||||
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: mail
|
||||
|
||||
property string title: qsTr("support@amnezia.org")
|
||||
property string description: qsTr("For reviews and bug reports")
|
||||
property string imageSource: "qrc:/images/controls/mail.svg"
|
||||
property var handler: function() {
|
||||
GC.copyToClipBoard(title)
|
||||
PageController.showNotificationMessage(qsTr("Copied"))
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: github
|
||||
|
||||
property string title: qsTr("GitHub")
|
||||
property string description: qsTr("Discover the source code")
|
||||
property string imageSource: "qrc:/images/controls/github.svg"
|
||||
property var handler: function() {
|
||||
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: website
|
||||
|
||||
property string title: qsTr("Website")
|
||||
property string description: qsTr("Visit official website")
|
||||
property string imageSource: "qrc:/images/controls/amnezia.svg"
|
||||
property var handler: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||
}
|
||||
}
|
||||
|
||||
property list<QtObject> contacts: [
|
||||
telegramGroup,
|
||||
mail,
|
||||
github,
|
||||
website
|
||||
]
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
property bool isFocusable: true
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
model: contacts
|
||||
|
||||
clip: true
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
Image {
|
||||
id: image
|
||||
|
|
@ -96,81 +171,29 @@ PageType {
|
|||
|
||||
text: qsTr("Contacts")
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
id: telegramButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.topMargin: 6
|
||||
|
||||
text: qsTr("Telegram group")
|
||||
descriptionText: qsTr("To discuss features")
|
||||
leftImageSource: "qrc:/images/controls/telegram.svg"
|
||||
text: title
|
||||
descriptionText: description
|
||||
leftImageSource: imageSource
|
||||
|
||||
KeyNavigation.tab: mailButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
|
||||
}
|
||||
clickedFunction: handler
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: mailButton
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
text: qsTr("support@amnezia.org")
|
||||
descriptionText: qsTr("For reviews and bug reports")
|
||||
leftImageSource: "qrc:/images/controls/mail.svg"
|
||||
|
||||
KeyNavigation.tab: githubButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
GC.copyToClipBoard(text)
|
||||
PageController.showNotificationMessage(qsTr("Copied"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: githubButton
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("GitHub")
|
||||
leftImageSource: "qrc:/images/controls/github.svg"
|
||||
|
||||
KeyNavigation.tab: websiteButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: websiteButton
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Website")
|
||||
leftImageSource: "qrc:/images/controls/amnezia.svg"
|
||||
|
||||
KeyNavigation.tab: checkUpdatesButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
footer: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
CaptionTextType {
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -196,6 +219,7 @@ PageType {
|
|||
|
||||
BasicButtonType {
|
||||
id: checkUpdatesButton
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: 16
|
||||
|
|
@ -209,35 +233,30 @@ PageType {
|
|||
|
||||
text: qsTr("Check for updates")
|
||||
|
||||
KeyNavigation.tab: privacyPolicyButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: privacyPolicyButton
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.bottomMargin: 16
|
||||
Layout.topMargin: -15
|
||||
implicitHeight: 25
|
||||
id: privacyPolicyButton
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.goldenApricot
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.bottomMargin: 16
|
||||
Layout.topMargin: -15
|
||||
implicitHeight: 25
|
||||
|
||||
text: qsTr("Privacy Policy")
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked()
|
||||
parentFlickable: fl
|
||||
text: qsTr("Privacy Policy")
|
||||
|
||||
clickedFunc: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
|
||||
}
|
||||
clickedFunc: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,72 +31,68 @@ PageType {
|
|||
id: containersRadioButtonGroup
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
delegate: ColumnLayout {
|
||||
id: content
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
RowLayout {
|
||||
VerticalRadioButton {
|
||||
id: containerRadioButton
|
||||
|
||||
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/" + countryImageCode + ".svg"
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
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/" + countryImageCode + ".svg"
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
|
|
@ -32,11 +30,6 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
// KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
property bool pageEnabled
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -66,11 +64,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
|
|
@ -82,7 +75,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: switcher
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
|
@ -103,10 +95,6 @@ PageType {
|
|||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
KeyNavigation.tab: selector.enabled ?
|
||||
selector :
|
||||
searchField.textField
|
||||
|
||||
checked: AppSplitTunnelingModel.isTunnelingEnabled
|
||||
onToggled: {
|
||||
AppSplitTunnelingModel.toggleSplitTunneling(checked)
|
||||
|
|
@ -130,8 +118,6 @@ PageType {
|
|||
|
||||
enabled: Qt.platform.os === "android" && root.pageEnabled
|
||||
|
||||
KeyNavigation.tab: searchField.textField
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
rootWidth: root.width
|
||||
|
||||
|
|
@ -141,7 +127,7 @@ PageType {
|
|||
|
||||
clickedFunction: function() {
|
||||
selector.text = selectedText
|
||||
selector.close()
|
||||
selector.closeTriggered()
|
||||
if (AppSplitTunnelingModel.routeMode !== root.routeModesModel[currentIndex].type) {
|
||||
AppSplitTunnelingModel.routeMode = root.routeModesModel[currentIndex].type
|
||||
}
|
||||
|
|
@ -267,7 +253,6 @@ PageType {
|
|||
textFieldPlaceholderText: qsTr("application name")
|
||||
buttonImageSource: "qrc:/images/controls/plus.svg"
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
rightButtonClickedOnEnter: true
|
||||
|
||||
clickedFunc: function() {
|
||||
|
|
@ -281,7 +266,7 @@ PageType {
|
|||
AppSplitTunnelingController.addApp(fileName)
|
||||
}
|
||||
} else if (Qt.platform.os === "android"){
|
||||
installedAppDrawer.open()
|
||||
installedAppDrawer.openTriggered()
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
|
|
|||
|
|
@ -14,19 +14,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
|
||||
onFocusChanged: {
|
||||
if (focusItem.activeFocus) {
|
||||
fl.contentY = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -34,8 +21,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: GC.isMobile() ? switcher : switcherAutoStart
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -77,8 +62,8 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
|
||||
labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
|
||||
// KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
|
||||
// labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
|
||||
parentFlickable: fl
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +80,6 @@ PageType {
|
|||
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: labelWithButtonLanguage.rightButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
|
|
@ -117,7 +101,6 @@ PageType {
|
|||
text: qsTr("Auto start")
|
||||
descriptionText: qsTr("Launch the application every time the device is starts")
|
||||
|
||||
KeyNavigation.tab: switcherAutoConnect
|
||||
parentFlickable: fl
|
||||
|
||||
checked: SettingsController.isAutoStartEnabled()
|
||||
|
|
@ -142,7 +125,6 @@ PageType {
|
|||
text: qsTr("Auto connect")
|
||||
descriptionText: qsTr("Connect to VPN on app start")
|
||||
|
||||
KeyNavigation.tab: switcherStartMinimized
|
||||
parentFlickable: fl
|
||||
|
||||
checked: SettingsController.isAutoConnectEnabled()
|
||||
|
|
@ -167,7 +149,6 @@ PageType {
|
|||
text: qsTr("Start minimized")
|
||||
descriptionText: qsTr("Launch application minimized")
|
||||
|
||||
KeyNavigation.tab: labelWithButtonLanguage.rightButton
|
||||
parentFlickable: fl
|
||||
|
||||
checked: SettingsController.isStartMinimizedEnabled()
|
||||
|
|
@ -190,11 +171,10 @@ PageType {
|
|||
descriptionText: LanguageModel.currentLanguageName
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: labelWithButtonLogging.rightButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
selectLanguageDrawer.open()
|
||||
selectLanguageDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +188,6 @@ PageType {
|
|||
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: labelWithButtonReset.rightButton
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
|
|
@ -226,7 +205,6 @@ PageType {
|
|||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked()
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
|
|
@ -245,12 +223,12 @@ PageType {
|
|||
}
|
||||
|
||||
if (!GC.isMobile()) {
|
||||
root.defaultActiveFocusItem.forceActiveFocus()
|
||||
// root.defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
root.defaultActiveFocusItem.forceActiveFocus()
|
||||
// root.defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,11 +245,5 @@ PageType {
|
|||
|
||||
width: root.width
|
||||
height: root.height
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ import "../Controls2/TextTypes"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Connections {
|
||||
target: SettingsController
|
||||
|
||||
|
|
@ -36,11 +34,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -48,8 +41,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: makeBackupButton
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -93,6 +84,8 @@ PageType {
|
|||
|
||||
text: qsTr("Make a backup")
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
|
|
@ -111,8 +104,6 @@ PageType {
|
|||
PageController.showNotificationMessage(qsTr("Backup file saved"))
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: restoreBackupButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -129,6 +120,8 @@ PageType {
|
|||
|
||||
text: qsTr("Restore from backup")
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
var filePath = SystemController.getFileName(qsTr("Open backup file"),
|
||||
qsTr("Backup files (*.backup)"))
|
||||
|
|
@ -136,8 +129,6 @@ PageType {
|
|||
restoreBackup(filePath)
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,15 +12,8 @@ import "../Config"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -28,8 +21,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: amneziaDnsSwitch
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -67,8 +58,6 @@ PageType {
|
|||
SettingsController.toggleAmneziaDns(checked)
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: dnsServersButton.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -81,11 +70,11 @@ PageType {
|
|||
descriptionText: qsTr("When AmneziaDNS is not used or installed")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsDns)
|
||||
}
|
||||
|
||||
KeyNavigation.tab: splitTunnelingButton.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -98,19 +87,11 @@ PageType {
|
|||
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
}
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (splitTunnelingButton2.visible) {
|
||||
return splitTunnelingButton2.rightButton.forceActiveFocus()
|
||||
} else if (killSwitchSwitcher.visible) {
|
||||
return killSwitchSwitcher.forceActiveFocus()
|
||||
} else {
|
||||
lastItemTabClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
|
|
@ -127,17 +108,11 @@ PageType {
|
|||
descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||
}
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (killSwitchSwitcher.visible) {
|
||||
return killSwitchSwitcher.forceActiveFocus()
|
||||
} else {
|
||||
lastItemTabClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
|
|
@ -154,6 +129,8 @@ PageType {
|
|||
text: qsTr("KillSwitch")
|
||||
descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.")
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
checked: SettingsController.isKillSwitchEnabled()
|
||||
checkable: !ConnectionController.isConnected
|
||||
onCheckedChanged: {
|
||||
|
|
@ -166,8 +143,6 @@ PageType {
|
|||
PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection"))
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked()
|
||||
}
|
||||
|
||||
DividerType {
|
||||
|
|
|
|||
|
|
@ -14,13 +14,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: primaryDns.textField
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -28,8 +21,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: root.defaultActiveFocusItem
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -80,8 +71,6 @@ PageType {
|
|||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: secondaryDns.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
|
|
@ -94,8 +83,6 @@ PageType {
|
|||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: restoreDefaultButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -124,19 +111,17 @@ PageType {
|
|||
PageController.showNotificationMessage(qsTr("Settings have been reset"))
|
||||
|
||||
if (!GC.isMobile()) {
|
||||
defaultActiveFocusItem.forceActiveFocus()
|
||||
// defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
defaultActiveFocusItem.forceActiveFocus()
|
||||
// defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
|
||||
KeyNavigation.tab: saveButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -155,8 +140,6 @@ PageType {
|
|||
}
|
||||
PageController.showNotificationMessage(qsTr("Settings saved"))
|
||||
}
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ import "../Controls2/TextTypes"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -30,22 +23,122 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: switcher
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
QtObject {
|
||||
id: clientLogs
|
||||
|
||||
property string title: qsTr("Client logs")
|
||||
property string description: qsTr("AmneziaVPN logs")
|
||||
property bool isVisible: true
|
||||
property var openLogsHandler: function() {
|
||||
SettingsController.openLogsFolder()
|
||||
}
|
||||
property var exportLogsHandler: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = "AmneziaVPN.log"
|
||||
} else {
|
||||
fileName = SystemController.getFileName(qsTr("Save"),
|
||||
qsTr("Logs files (*.log)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN",
|
||||
true,
|
||||
".log")
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SettingsController.exportLogsFile(fileName)
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showNotificationMessage(qsTr("Logs file saved"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: serviceLogs
|
||||
|
||||
property string title: qsTr("Service logs")
|
||||
property string description: qsTr("AmneziaVPN-service logs")
|
||||
property bool isVisible: !GC.isMobile()
|
||||
property var openLogsHandler: function() {
|
||||
SettingsController.openServiceLogsFolder()
|
||||
}
|
||||
property var exportLogsHandler: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = "AmneziaVPN-service.log"
|
||||
} else {
|
||||
fileName = SystemController.getFileName(qsTr("Save"),
|
||||
qsTr("Logs files (*.log)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service",
|
||||
true,
|
||||
".log")
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SettingsController.exportServiceLogsFile(fileName)
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showNotificationMessage(qsTr("Logs file saved"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property list<QtObject> logTypes: [
|
||||
clientLogs,
|
||||
serviceLogs
|
||||
]
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
model: logTypes
|
||||
spacing: 24
|
||||
snapMode: ListView.SnapOneItem
|
||||
|
||||
reuseItems: true
|
||||
|
||||
clip: true
|
||||
|
||||
header: ColumnLayout {
|
||||
id: headerContent
|
||||
|
||||
width: listView.width
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -60,6 +153,7 @@ PageType {
|
|||
|
||||
SwitcherType {
|
||||
id: switcher
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
|
@ -68,7 +162,7 @@ PageType {
|
|||
text: qsTr("Enable logs")
|
||||
|
||||
checked: SettingsController.isLoggingEnabled
|
||||
//KeyNavigation.tab: openFolderButton
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isLoggingEnabled) {
|
||||
SettingsController.isLoggingEnabled = checked
|
||||
|
|
@ -79,7 +173,6 @@ PageType {
|
|||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
// id: labelWithButton2
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -8
|
||||
|
||||
|
|
@ -87,8 +180,6 @@ PageType {
|
|||
leftImageSource: "qrc:/images/controls/trash.svg"
|
||||
isSmallLeftImage: true
|
||||
|
||||
// KeyNavigation.tab: labelWithButton3
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Clear logs?")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
|
|
@ -99,19 +190,25 @@ PageType {
|
|||
SettingsController.clearLogs()
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showNotificationMessage(qsTr("Logs have been cleaned up"))
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
width: listView.width
|
||||
|
||||
spacing: 0
|
||||
|
||||
visible: isVisible
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -119,7 +216,7 @@ PageType {
|
|||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Client logs")
|
||||
text: title
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
|
|
@ -129,11 +226,11 @@ PageType {
|
|||
Layout.rightMargin: 16
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
text: qsTr("AmneziaVPN logs")
|
||||
|
||||
text: description
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
// id: labelWithButton2
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -8
|
||||
Layout.bottomMargin: -8
|
||||
|
|
@ -142,17 +239,12 @@ PageType {
|
|||
leftImageSource: "qrc:/images/controls/folder-open.svg"
|
||||
isSmallLeftImage: true
|
||||
|
||||
// KeyNavigation.tab: labelWithButton3
|
||||
|
||||
clickedFunction: function() {
|
||||
SettingsController.openLogsFolder()
|
||||
}
|
||||
clickedFunction: openLogsHandler
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
// id: labelWithButton2
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -8
|
||||
Layout.bottomMargin: -8
|
||||
|
|
@ -161,115 +253,10 @@ PageType {
|
|||
leftImageSource: "qrc:/images/controls/save.svg"
|
||||
isSmallLeftImage: true
|
||||
|
||||
// KeyNavigation.tab: labelWithButton3
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = "AmneziaVPN.log"
|
||||
} else {
|
||||
fileName = SystemController.getFileName(qsTr("Save"),
|
||||
qsTr("Logs files (*.log)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN",
|
||||
true,
|
||||
".log")
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SettingsController.exportLogsFile(fileName)
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showNotificationMessage(qsTr("Logs file saved"))
|
||||
}
|
||||
}
|
||||
clickedFunction: exportLogsHandler
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
ListItemTitleType {
|
||||
visible: !GC.isMobile()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Service logs")
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
visible: !GC.isMobile()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
text: qsTr("AmneziaVPN-service logs")
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
// id: labelWithButton2
|
||||
|
||||
visible: !GC.isMobile()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -8
|
||||
Layout.bottomMargin: -8
|
||||
|
||||
text: qsTr("Open logs folder")
|
||||
leftImageSource: "qrc:/images/controls/folder-open.svg"
|
||||
isSmallLeftImage: true
|
||||
|
||||
// KeyNavigation.tab: labelWithButton3
|
||||
|
||||
clickedFunction: function() {
|
||||
SettingsController.openServiceLogsFolder()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: !GC.isMobile()
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
// id: labelWithButton2
|
||||
|
||||
visible: !GC.isMobile()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -8
|
||||
Layout.bottomMargin: -8
|
||||
|
||||
text: qsTr("Export logs")
|
||||
leftImageSource: "qrc:/images/controls/save.svg"
|
||||
isSmallLeftImage: true
|
||||
|
||||
// KeyNavigation.tab: labelWithButton3
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = "AmneziaVPN-service.log"
|
||||
} else {
|
||||
fileName = SystemController.getFileName(qsTr("Save"),
|
||||
qsTr("Logs files (*.log)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service",
|
||||
true,
|
||||
".log")
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SettingsController.exportServiceLogsFile(fileName)
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showNotificationMessage(qsTr("Logs file saved"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: !GC.isMobile()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,8 +100,6 @@ PageType {
|
|||
text: qsTr("Check the server for previously installed Amnezia services")
|
||||
descriptionText: qsTr("Add them to the application if they were not displayed")
|
||||
|
||||
KeyNavigation.tab: labelWithButton2
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
InstallController.scanServerForInstalledContainers()
|
||||
|
|
@ -121,8 +119,6 @@ PageType {
|
|||
text: qsTr("Reboot server")
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
KeyNavigation.tab: labelWithButton3
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Do you want to reboot the server?")
|
||||
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
|
||||
|
|
@ -162,16 +158,6 @@ PageType {
|
|||
text: qsTr("Remove server from application")
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (content.isServerWithWriteAccess) {
|
||||
labelWithButton4.forceActiveFocus()
|
||||
} else {
|
||||
labelWithButton5.visible ?
|
||||
labelWithButton5.forceActiveFocus() :
|
||||
lastItemTabClickedSignal()
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Do you want to remove the server from application?")
|
||||
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
|
||||
|
|
@ -210,10 +196,6 @@ PageType {
|
|||
text: qsTr("Clear server from Amnezia software")
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: labelWithButton5.visible ?
|
||||
labelWithButton5.forceActiveFocus() :
|
||||
root.lastItemTabClickedSignal()
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Do you want to clear server from Amnezia software?")
|
||||
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
|
||||
|
|
@ -253,8 +235,6 @@ PageType {
|
|||
text: qsTr("Reset API config")
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Keys.onTabPressed: root.lastItemTabClickedSignal()
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Do you want to reset API config?")
|
||||
var descriptionText = ""
|
||||
|
|
|
|||
|
|
@ -19,24 +19,26 @@ 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
|
||||
readonly property int pageSettingsServerProtocols: 0
|
||||
readonly property int pageSettingsServerServices: 1
|
||||
readonly property int pageSettingsServerData: 2
|
||||
readonly property int pageSettingsApiServerInfo: 3
|
||||
readonly property int pageSettingsApiLanguageList: 4
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
property var server
|
||||
|
||||
Connections {
|
||||
target: PageController
|
||||
|
||||
function onGoToPageSettingsServerServices() {
|
||||
tabBar.currentIndex = root.pageSettingsServerServices
|
||||
tabBar.setCurrentIndex(root.pageSettingsServerServices)
|
||||
}
|
||||
}
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: proxyServersModel
|
||||
objectName: "proxyServersModel"
|
||||
|
||||
sourceModel: ServersModel
|
||||
filters: [
|
||||
ValueFilter {
|
||||
|
|
@ -44,147 +46,111 @@ PageType {
|
|||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: header
|
||||
Component.onCompleted: {
|
||||
root.server = proxyServersModel.get(0)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
objectName: "mainLayout"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 20
|
||||
|
||||
spacing: 16
|
||||
spacing: 4
|
||||
|
||||
Repeater {
|
||||
id: header
|
||||
model: proxyServersModel
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
objectName: "backButton"
|
||||
|
||||
activeFocusOnTab: true
|
||||
onFocusChanged: {
|
||||
header.itemAt(0).focusItem.forceActiveFocus()
|
||||
backButtonFunction: function() {
|
||||
if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo
|
||||
&& ServersModel.getProcessedServerData("isCountrySelectionAvailable")) {
|
||||
nestedStackView.currentIndex = root.pageSettingsApiLanguageList
|
||||
} else {
|
||||
PageController.closePage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
id: headerContent
|
||||
objectName: "headerContent"
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.bottomMargin: 10
|
||||
|
||||
actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg" : "qrc:/images/controls/edit-3.svg"
|
||||
|
||||
headerText: root.server.name
|
||||
descriptionText: {
|
||||
if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
|
||||
return ApiServicesModel.getSelectedServiceData("serviceDescription")
|
||||
} else if (ServersModel.getProcessedServerData("isServerFromTelegramApi")) {
|
||||
return root.server.serverDescription
|
||||
} else if (ServersModel.isProcessedServerHasWriteAccess()) {
|
||||
return root.server.credentialsLogin + " · " + root.server.hostName
|
||||
} else {
|
||||
return root.server.hostName
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
|
||||
property alias focusItem: backButton
|
||||
|
||||
id: content
|
||||
|
||||
Layout.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: headerContent.actionButton
|
||||
|
||||
backButtonFunction: function() {
|
||||
if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo &&
|
||||
ServersModel.getProcessedServerData("isCountrySelectionAvailable")) {
|
||||
nestedStackView.currentIndex = root.pageSettingsApiLanguageList
|
||||
} else {
|
||||
PageController.closePage()
|
||||
}
|
||||
}
|
||||
actionButtonFunction: function() {
|
||||
if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
|
||||
nestedStackView.currentIndex = root.pageSettingsApiServerInfo
|
||||
} else {
|
||||
serverNameEditDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: serverNameEditDrawer
|
||||
objectName: "serverNameEditDrawer"
|
||||
|
||||
parent: root
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: root.height * 0.35
|
||||
|
||||
expandedStateContent: ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 32
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: serverName
|
||||
|
||||
HeaderType {
|
||||
id: headerContent
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg" : "qrc:/images/controls/edit-3.svg"
|
||||
|
||||
headerText: name
|
||||
descriptionText: {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: tabBar
|
||||
|
||||
actionButtonFunction: function() {
|
||||
if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
|
||||
nestedStackView.currentIndex = root.pageSettingsApiServerInfo
|
||||
} else {
|
||||
serverNameEditDrawer.open()
|
||||
}
|
||||
}
|
||||
headerText: qsTr("Server name")
|
||||
textFieldText: root.server.name
|
||||
textField.maximumLength: 30
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: serverNameEditDrawer
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
parent: root
|
||||
Layout.fillWidth: true
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: root.height * 0.35
|
||||
text: qsTr("Save")
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
headerContent.actionButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 32
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
Connections {
|
||||
target: serverNameEditDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
serverName.textField.forceActiveFocus()
|
||||
}
|
||||
clickedFunc: function() {
|
||||
if (serverName.textFieldText === "") {
|
||||
return
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem1
|
||||
KeyNavigation.tab: serverName.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: serverName
|
||||
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("Server name")
|
||||
textFieldText: name
|
||||
textField.maximumLength: 30
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: saveButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Save")
|
||||
KeyNavigation.tab: focusItem1
|
||||
|
||||
clickedFunc: function() {
|
||||
if (serverName.textFieldText === "") {
|
||||
return
|
||||
}
|
||||
|
||||
if (serverName.textFieldText !== name) {
|
||||
name = serverName.textFieldText
|
||||
}
|
||||
serverNameEditDrawer.close()
|
||||
}
|
||||
if (serverName.textFieldText !== root.server.name) {
|
||||
ServersModel.setProcessedServerData("name", serverName.textFieldText);
|
||||
root.server = proxyServersModel.get(0);
|
||||
}
|
||||
serverNameEditDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -205,35 +171,27 @@ PageType {
|
|||
|
||||
visible: !ServersModel.getProcessedServerData("isServerFromGatewayApi")
|
||||
|
||||
activeFocusOnTab: true
|
||||
onFocusChanged: {
|
||||
if (activeFocus) {
|
||||
protocolsTab.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
TabButtonType {
|
||||
id: protocolsTab
|
||||
visible: protocolsPage.installedProtocolsCount
|
||||
width: protocolsPage.installedProtocolsCount ? undefined : 0
|
||||
isSelected: tabBar.currentIndex === root.pageSettingsServerProtocols
|
||||
isSelected: TabBar.tabBar.currentIndex === root.pageSettingsServerProtocols
|
||||
text: qsTr("Protocols")
|
||||
|
||||
KeyNavigation.tab: servicesTab
|
||||
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerProtocols
|
||||
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerProtocols
|
||||
Keys.onReturnPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerProtocols)
|
||||
Keys.onEnterPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerProtocols)
|
||||
}
|
||||
|
||||
TabButtonType {
|
||||
id: servicesTab
|
||||
visible: servicesPage.installedServicesCount
|
||||
width: servicesPage.installedServicesCount ? undefined : 0
|
||||
isSelected: tabBar.currentIndex === root.pageSettingsServerServices
|
||||
isSelected: TabBar.tabBar.currentIndex === root.pageSettingsServerServices
|
||||
text: qsTr("Services")
|
||||
|
||||
KeyNavigation.tab: dataTab
|
||||
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerServices
|
||||
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerServices
|
||||
Keys.onReturnPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerServices)
|
||||
Keys.onEnterPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerServices)
|
||||
}
|
||||
|
||||
TabButtonType {
|
||||
|
|
@ -241,24 +199,15 @@ PageType {
|
|||
isSelected: tabBar.currentIndex === root.pageSettingsServerData
|
||||
text: qsTr("Management")
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
Keys.onReturnPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerData)
|
||||
Keys.onEnterPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerData)
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: nestedStackView
|
||||
Layout.preferredWidth: root.width
|
||||
Layout.preferredHeight: root.height - tabBar.implicitHeight - header.implicitHeight
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
currentIndex: ServersModel.getProcessedServerData("isServerFromGatewayApi") ?
|
||||
(ServersModel.getProcessedServerData("isCountrySelectionAvailable") ?
|
||||
|
|
@ -267,36 +216,26 @@ PageType {
|
|||
PageSettingsServerProtocols {
|
||||
id: protocolsPage
|
||||
stackView: root.stackView
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,6 @@ PageType {
|
|||
|
||||
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
|
|
@ -39,7 +32,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: protocols
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -57,30 +49,36 @@ PageType {
|
|||
height: protocols.contentItem.height
|
||||
clip: true
|
||||
interactive: true
|
||||
model: ProtocolsModel
|
||||
|
||||
property int currentFocusIndex: 0
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
this.currentFocusIndex = 0
|
||||
protocols.itemAtIndex(currentFocusIndex).focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (currentFocusIndex < this.count - 1) {
|
||||
currentFocusIndex += 1
|
||||
protocols.itemAtIndex(currentFocusIndex).focusItem.forceActiveFocus()
|
||||
} else {
|
||||
clearCacheButton.forceActiveFocus()
|
||||
}
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
property var focusItem: clientSettings.rightButton
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
model: ProtocolsModel
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: protocols.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
|
|
@ -160,109 +158,112 @@ PageType {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: clearCacheButton
|
||||
footer: ColumnLayout {
|
||||
width: header.width
|
||||
|
||||
Layout.fillWidth: true
|
||||
LabelWithButtonType {
|
||||
id: clearCacheButton
|
||||
|
||||
visible: root.isClearCacheVisible
|
||||
KeyNavigation.tab: removeButton
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Clear profile")
|
||||
visible: root.isClearCacheVisible
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
|
||||
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
text: qsTr("Clear profile")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
|
||||
PageController.showNotificationMessage(message)
|
||||
return
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
|
||||
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
|
||||
PageController.showNotificationMessage(message)
|
||||
return
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(true)
|
||||
InstallController.clearCachedProfile()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
// if (!GC.isMobile()) {
|
||||
// focusItem.forceActiveFocus()
|
||||
// }
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(true)
|
||||
InstallController.clearCachedProfile()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
MouseArea {
|
||||
anchors.fill: clearCacheButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: clearCacheButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: root.isClearCacheVisible
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: removeButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
text: qsTr("Remove ")
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
||||
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
|
||||
} else
|
||||
{
|
||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||
InstallController.removeProcessedContainer()
|
||||
}
|
||||
visible: root.isClearCacheVisible
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
|
||||
LabelWithButtonType {
|
||||
id: removeButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
text: qsTr("Remove ")
|
||||
textColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
||||
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
|
||||
} else
|
||||
{
|
||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||
InstallController.removeProcessedContainer()
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: removeButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: removeButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,53 +21,45 @@ PageType {
|
|||
|
||||
property var installedProtocolsCount
|
||||
|
||||
onFocusChanged: settingsContainersListView.forceActiveFocus()
|
||||
signal lastItemTabClickedSignal()
|
||||
function resetView() {
|
||||
settingsContainersListView.positionViewAtBeginning()
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
SettingsContainersListView {
|
||||
id: settingsContainersListView
|
||||
|
||||
Column {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Connections {
|
||||
target: ServersModel
|
||||
|
||||
SettingsContainersListView {
|
||||
id: settingsContainersListView
|
||||
|
||||
Connections {
|
||||
target: ServersModel
|
||||
|
||||
function onProcessedServerIndexChanged() {
|
||||
settingsContainersListView.updateContainersModelFilters()
|
||||
}
|
||||
}
|
||||
|
||||
function updateContainersModelFilters() {
|
||||
if (ServersModel.isProcessedServerHasWriteAccess()) {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
|
||||
} else {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
|
||||
}
|
||||
root.installedProtocolsCount = proxyContainersModel.count
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyContainersModel
|
||||
sourceModel: ContainersModel
|
||||
sorters: [
|
||||
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder },
|
||||
RoleSorter { roleName: "installPageOrder"; sortOrder: Qt.AscendingOrder }
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: updateContainersModelFilters()
|
||||
function onProcessedServerIndexChanged() {
|
||||
settingsContainersListView.updateContainersModelFilters()
|
||||
}
|
||||
}
|
||||
|
||||
function updateContainersModelFilters() {
|
||||
if (ServersModel.isProcessedServerHasWriteAccess()) {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
|
||||
} else {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
|
||||
}
|
||||
root.installedProtocolsCount = proxyContainersModel.count
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyContainersModel
|
||||
sourceModel: ContainersModel
|
||||
sorters: [
|
||||
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder },
|
||||
RoleSorter { roleName: "installPageOrder"; sortOrder: Qt.AscendingOrder }
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
settingsContainersListView.isFocusable = true
|
||||
settingsContainersListView.interactive = true
|
||||
updateContainersModelFilters()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,52 +21,40 @@ PageType {
|
|||
|
||||
property var installedServicesCount
|
||||
|
||||
onFocusChanged: settingsContainersListView.forceActiveFocus()
|
||||
signal lastItemTabClickedSignal()
|
||||
SettingsContainersListView {
|
||||
id: settingsContainersListView
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
anchors.fill: parent
|
||||
|
||||
Column {
|
||||
id: content
|
||||
Connections {
|
||||
target: ServersModel
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
SettingsContainersListView {
|
||||
id: settingsContainersListView
|
||||
|
||||
Connections {
|
||||
target: ServersModel
|
||||
|
||||
function onProcessedServerIndexChanged() {
|
||||
settingsContainersListView.updateContainersModelFilters()
|
||||
}
|
||||
}
|
||||
|
||||
function updateContainersModelFilters() {
|
||||
if (ServersModel.isProcessedServerHasWriteAccess()) {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters()
|
||||
} else {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters()
|
||||
}
|
||||
root.installedServicesCount = proxyContainersModel.count
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyContainersModel
|
||||
sourceModel: ContainersModel
|
||||
sorters: [
|
||||
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: updateContainersModelFilters()
|
||||
function onProcessedServerIndexChanged() {
|
||||
settingsContainersListView.updateContainersModelFilters()
|
||||
}
|
||||
}
|
||||
|
||||
function updateContainersModelFilters() {
|
||||
if (ServersModel.isProcessedServerHasWriteAccess()) {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters()
|
||||
} else {
|
||||
proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters()
|
||||
}
|
||||
root.installedServicesCount = proxyContainersModel.count
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyContainersModel
|
||||
sourceModel: ContainersModel
|
||||
sorters: [
|
||||
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
settingsContainersListView.isFocusable = true
|
||||
settingsContainersListView.interactive = true
|
||||
updateContainersModelFilters()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
|
|
@ -36,7 +29,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: servers
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -48,95 +40,70 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
ListView {
|
||||
id: servers
|
||||
objectName: "servers"
|
||||
|
||||
width: parent.width
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: 16
|
||||
contentHeight: col.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Column {
|
||||
id: col
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 500 // servers.contentItem.height // TODO: calculate height
|
||||
|
||||
ListView {
|
||||
id: servers
|
||||
width: parent.width
|
||||
height: servers.contentItem.height
|
||||
property bool isFocusable: true
|
||||
|
||||
model: ServersModel
|
||||
model: ServersModel
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
clip: true
|
||||
interactive: false
|
||||
|
||||
activeFocusOnTab: true
|
||||
focus: true
|
||||
Keys.onTabPressed: {
|
||||
if (currentIndex < servers.count - 1) {
|
||||
servers.incrementCurrentIndex()
|
||||
} else {
|
||||
servers.currentIndex = 0
|
||||
focusItem.forceActiveFocus()
|
||||
root.lastItemTabClicked()
|
||||
}
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
currentIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
fl.ensureVisible(this.currentItem)
|
||||
}
|
||||
delegate: Item {
|
||||
implicitWidth: servers.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
currentIndex = 0
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: servers.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
server.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
LabelWithButtonType {
|
||||
id: server
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
text: name
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
LabelWithButtonType {
|
||||
id: server
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: name
|
||||
parentFlickable: fl
|
||||
descriptionText: {
|
||||
var servicesNameString = ""
|
||||
var servicesName = ServersModel.getAllInstalledServicesName(index)
|
||||
for (var i = 0; i < servicesName.length; i++) {
|
||||
servicesNameString += servicesName[i] + " · "
|
||||
}
|
||||
|
||||
if (ServersModel.isServerFromApi(index)) {
|
||||
return servicesNameString + serverDescription
|
||||
} else {
|
||||
return servicesNameString + hostName
|
||||
}
|
||||
}
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
ServersModel.processedIndex = index
|
||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||
}
|
||||
descriptionText: {
|
||||
var servicesNameString = ""
|
||||
var servicesName = ServersModel.getAllInstalledServicesName(index)
|
||||
for (var i = 0; i < servicesName.length; i++) {
|
||||
servicesNameString += servicesName[i] + " · "
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
if (ServersModel.isServerFromApi(index)) {
|
||||
return servicesNameString + serverDescription
|
||||
} else {
|
||||
return servicesNameString + hostName
|
||||
}
|
||||
}
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
ServersModel.processedIndex = index
|
||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,6 @@ PageType {
|
|||
|
||||
property var isServerFromTelegramApi: ServersModel.getDefaultServerData("isServerFromTelegramApi")
|
||||
|
||||
defaultActiveFocusItem: searchField.textField
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
property bool pageEnabled
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -99,7 +92,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: switcher
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
|
@ -129,8 +121,6 @@ PageType {
|
|||
onToggled: { onToggledFunc() }
|
||||
Keys.onEnterPressed: { onToggledFunc() }
|
||||
Keys.onReturnPressed: { onToggledFunc() }
|
||||
|
||||
KeyNavigation.tab: selector
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +148,7 @@ PageType {
|
|||
|
||||
clickedFunction: function() {
|
||||
selector.text = selectedText
|
||||
selector.close()
|
||||
selector.closeTriggered()
|
||||
if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) {
|
||||
SitesModel.routeMode = root.routeModesModel[currentIndex].type
|
||||
}
|
||||
|
|
@ -179,124 +169,120 @@ PageType {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: {
|
||||
return sites.count > 0 ?
|
||||
sites :
|
||||
searchField.textField
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
ListView {
|
||||
id: sites
|
||||
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: 16
|
||||
contentHeight: col.implicitHeight + addSiteButton.implicitHeight + addSiteButton.anchors.bottomMargin + addSiteButton.anchors.topMargin
|
||||
width: parent.width
|
||||
|
||||
height: 200 // TODO: Change to correct height
|
||||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
Column {
|
||||
id: col
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
property bool isFocusable: true
|
||||
|
||||
ListView {
|
||||
id: sites
|
||||
width: parent.width
|
||||
height: sites.contentItem.height
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxySitesModel
|
||||
sourceModel: SitesModel
|
||||
filters: [
|
||||
AnyOf {
|
||||
RegExpFilter {
|
||||
roleName: "url"
|
||||
pattern: ".*" + searchField.textField.text + ".*"
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
RegExpFilter {
|
||||
roleName: "ip"
|
||||
pattern: ".*" + searchField.textField.text + ".*"
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxySitesModel
|
||||
sourceModel: SitesModel
|
||||
filters: [
|
||||
AnyOf {
|
||||
RegExpFilter {
|
||||
roleName: "url"
|
||||
pattern: ".*" + searchField.textField.text + ".*"
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
RegExpFilter {
|
||||
roleName: "ip"
|
||||
pattern: ".*" + searchField.textField.text + ".*"
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: sites.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
// onActiveFocusChanged: {
|
||||
// if (activeFocus) {
|
||||
// site.rightButton.forceActiveFocus()
|
||||
// }
|
||||
// }
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
LabelWithButtonType {
|
||||
id: site
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: url
|
||||
descriptionText: ip
|
||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove ") + url + "?"
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
SitesController.removeSite(proxySitesModel.mapToSource(index))
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
|
||||
activeFocusOnTab: true
|
||||
focus: true
|
||||
Keys.onTabPressed: {
|
||||
if (currentIndex < this.count - 1) {
|
||||
this.incrementCurrentIndex()
|
||||
} else {
|
||||
currentIndex = 0
|
||||
searchField.textField.forceActiveFocus()
|
||||
}
|
||||
|
||||
fl.ensureVisible(currentItem)
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: sites.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
LabelWithButtonType {
|
||||
id: site
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: url
|
||||
descriptionText: ip
|
||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Remove ") + url + "?"
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
SitesController.removeSite(proxySitesModel.mapToSource(index))
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: addSiteButton
|
||||
anchors.bottomMargin: -24
|
||||
|
|
@ -325,7 +311,6 @@ PageType {
|
|||
|
||||
textFieldPlaceholderText: qsTr("website or IP")
|
||||
buttonImageSource: "qrc:/images/controls/plus.svg"
|
||||
KeyNavigation.tab: GC.isMobile() ? focusItem : addSiteButtonImage
|
||||
|
||||
clickedFunc: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
|
|
@ -344,13 +329,11 @@ PageType {
|
|||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
onClicked: function () {
|
||||
moreActionsDrawer.open()
|
||||
moreActionsDrawer.openTriggered()
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: addSiteButtonImage.clicked()
|
||||
Keys.onEnterPressed: addSiteButtonImage.clicked()
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -360,38 +343,13 @@ PageType {
|
|||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
onClosed: {
|
||||
if (root.defaultActiveFocusItem && !GC.isMobile()) {
|
||||
root.defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: moreActionsDrawerContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Connections {
|
||||
target: moreActionsDrawer
|
||||
|
||||
function onOpened() {
|
||||
focusItem1.forceActiveFocus()
|
||||
}
|
||||
|
||||
function onActiveFocusChanged() {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem1.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem1
|
||||
KeyNavigation.tab: importSitesButton.rightButton
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
|
@ -407,10 +365,8 @@ PageType {
|
|||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
importSitesDrawer.open()
|
||||
importSitesDrawer.openTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: exportSitesButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
@ -420,8 +376,6 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
text: qsTr("Save site list")
|
||||
|
||||
KeyNavigation.tab: focusItem1
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
|
|
@ -436,7 +390,7 @@ PageType {
|
|||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SitesController.exportSites(fileName)
|
||||
moreActionsDrawer.close()
|
||||
moreActionsDrawer.closeTriggered()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -452,28 +406,9 @@ PageType {
|
|||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
moreActionsDrawer.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: importSitesDrawer.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: importSitesDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem2.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem2
|
||||
KeyNavigation.tab: importSitesDrawerBackButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: importSitesDrawerBackButton
|
||||
|
||||
|
|
@ -482,10 +417,8 @@ PageType {
|
|||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
KeyNavigation.tab: importSitesButton2
|
||||
|
||||
backButtonFunction: function() {
|
||||
importSitesDrawer.close()
|
||||
importSitesDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +449,6 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Replace site list")
|
||||
KeyNavigation.tab: importSitesButton3
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
||||
|
|
@ -533,7 +465,6 @@ PageType {
|
|||
id: importSitesButton3
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Add imported sites to existing ones")
|
||||
KeyNavigation.tab: focusItem2
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
||||
|
|
@ -548,8 +479,8 @@ PageType {
|
|||
PageController.showBusyIndicator(true)
|
||||
SitesController.importSites(fileName, replaceExistingSites)
|
||||
PageController.showBusyIndicator(false)
|
||||
importSitesDrawer.close()
|
||||
moreActionsDrawer.close()
|
||||
importSitesDrawer.closeTriggered()
|
||||
moreActionsDrawer.closeTriggered()
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
|
|
@ -32,15 +30,9 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
Layout.topMargin: 20
|
||||
// KeyNavigation.tab: fileButton.rightButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ import "../Config"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
|
|
@ -31,15 +29,9 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
Layout.topMargin: 20
|
||||
// KeyNavigation.tab: fileButton.rightButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -59,6 +51,8 @@ PageType {
|
|||
height: containers.contentItem.height
|
||||
spacing: 16
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
currentIndex: 1
|
||||
interactive: false
|
||||
model: ApiServicesModel
|
||||
|
|
@ -93,6 +87,9 @@ PageType {
|
|||
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: clicked()
|
||||
Keys.onReturnPressed: clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,32 +25,155 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
QtObject {
|
||||
id: amneziaVpn
|
||||
|
||||
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: textKey.textField
|
||||
property string title: qsTr("VPN by Amnezia")
|
||||
property string description: qsTr("Connect to classic paid and free VPN services from Amnezia")
|
||||
property string imageSource: "qrc:/images/controls/amnezia.svg"
|
||||
property bool isVisible: true
|
||||
property var handler: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
var result = InstallController.fillAvailableServices()
|
||||
PageController.showBusyIndicator(false)
|
||||
if (result) {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardApiServicesList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: selfHostVpn
|
||||
|
||||
property string title: qsTr("Self-hosted VPN")
|
||||
property string description: qsTr("Configure Amnezia VPN on your own server")
|
||||
property string imageSource: "qrc:/images/controls/server.svg"
|
||||
property bool isVisible: true
|
||||
property var handler: function() {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: backupRestore
|
||||
|
||||
property string title: qsTr("Restore from backup")
|
||||
property string description: qsTr("")
|
||||
property string imageSource: "qrc:/images/controls/archive-restore.svg"
|
||||
property bool isVisible: true
|
||||
property var handler: function() {
|
||||
var filePath = SystemController.getFileName(qsTr("Open backup file"),
|
||||
qsTr("Backup files (*.backup)"))
|
||||
if (filePath !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SettingsController.restoreAppConfig(filePath)
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: fileOpen
|
||||
|
||||
property string title: qsTr("File with connection settings")
|
||||
property string description: qsTr("")
|
||||
property string imageSource: "qrc:/images/controls/folder-search-2.svg"
|
||||
property bool isVisible: true
|
||||
property var handler: function() {
|
||||
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)
|
||||
if (fileName !== "") {
|
||||
if (ImportController.extractConfigFromFile(fileName)) {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: qrScan
|
||||
|
||||
property string title: qsTr("QR code")
|
||||
property string description: qsTr("")
|
||||
property string imageSource: "qrc:/images/controls/scan-line.svg"
|
||||
property bool isVisible: SettingsController.isCameraPresent()
|
||||
property var handler: function() {
|
||||
ImportController.startDecodingQr()
|
||||
if (Qt.platform.os === "ios") {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardQrReader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: siteLink
|
||||
|
||||
property string title: qsTr("I have nothing")
|
||||
property string description: qsTr("")
|
||||
property string imageSource: "qrc:/images/controls/help-circle.svg"
|
||||
property bool isVisible: true
|
||||
property var handler: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||
}
|
||||
}
|
||||
|
||||
property list<QtObject> variants: [
|
||||
amneziaVpn,
|
||||
selfHostVpn,
|
||||
backupRestore,
|
||||
fileOpen,
|
||||
qrScan,
|
||||
siteLink
|
||||
]
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
model: variants
|
||||
|
||||
clip: true
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
HeaderType {
|
||||
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
|
||||
id: moreButton
|
||||
|
||||
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.rightMargin: 16
|
||||
|
|
@ -60,7 +183,7 @@ PageType {
|
|||
|
||||
actionButtonImage: isVisible ? "qrc:/images/controls/more-vertical.svg" : ""
|
||||
actionButtonFunction: function() {
|
||||
moreActionsDrawer.open()
|
||||
moreActionsDrawer.openTriggered()
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
|
|
@ -71,7 +194,7 @@ PageType {
|
|||
anchors.fill: parent
|
||||
expandedHeight: root.height * 0.5
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
|
@ -131,6 +254,8 @@ PageType {
|
|||
}
|
||||
|
||||
ParagraphTextType {
|
||||
objectName: "insertKeyLabel"
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.rightMargin: 16
|
||||
|
|
@ -154,8 +279,6 @@ PageType {
|
|||
textField.text = ""
|
||||
textField.paste()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: continueButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -169,7 +292,6 @@ PageType {
|
|||
visible: textKey.textFieldText !== ""
|
||||
|
||||
text: qsTr("Continue")
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
if (ImportController.extractConfigFromData(textKey.textFieldText)) {
|
||||
|
|
@ -188,142 +310,28 @@ PageType {
|
|||
color: AmneziaStyle.color.charcoalGray
|
||||
text: qsTr("Other connection options")
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
CardWithIconsType {
|
||||
id: apiInstalling
|
||||
id: entry
|
||||
|
||||
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")
|
||||
visible: isVisible
|
||||
|
||||
headerText: title
|
||||
bodyText: description
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/amnezia.svg"
|
||||
leftImageSource: imageSource
|
||||
|
||||
onClicked: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
var result = InstallController.fillAvailableServices()
|
||||
PageController.showBusyIndicator(false)
|
||||
if (result) {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardApiServicesList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (fileName !== "") {
|
||||
if (ImportController.extractConfigFromFile(fileName)) {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CardWithIconsType {
|
||||
id: scanQr
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: SettingsController.isCameraPresent()
|
||||
|
||||
headerText: qsTr("QR code")
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/scan-line.svg"
|
||||
|
||||
onClicked: {
|
||||
ImportController.startDecodingQr()
|
||||
if (Qt.platform.os === "ios") {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardQrReader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CardWithIconsType {
|
||||
id: siteLink
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: PageController.isStartPageVisible()
|
||||
|
||||
headerText: qsTr("I have nothing")
|
||||
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/help-circle.svg"
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||
}
|
||||
onClicked: { handler() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,6 @@ import "../Controls2/TextTypes"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: hostname.textField
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -27,8 +20,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: hostname.textField
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -61,11 +52,11 @@ PageType {
|
|||
headerText: qsTr("Server IP address [:port]")
|
||||
textFieldPlaceholderText: qsTr("255.255.255.255:22")
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onFocusChanged: {
|
||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||
}
|
||||
|
||||
KeyNavigation.tab: username.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
|
|
@ -75,11 +66,11 @@ PageType {
|
|||
headerText: qsTr("SSH Username")
|
||||
textFieldPlaceholderText: "root"
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
textField.onFocusChanged: {
|
||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||
}
|
||||
|
||||
KeyNavigation.tab: secretData.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
|
|
@ -93,6 +84,8 @@ PageType {
|
|||
buttonImageSource: textFieldText !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
|
||||
: ""
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
hidePassword = !hidePassword
|
||||
}
|
||||
|
|
@ -100,8 +93,6 @@ PageType {
|
|||
textField.onFocusChanged: {
|
||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||
}
|
||||
|
||||
KeyNavigation.tab: continueButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -112,7 +103,7 @@ PageType {
|
|||
|
||||
text: qsTr("Continue")
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
|
@ -153,6 +144,8 @@ PageType {
|
|||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
leftImageSource: "qrc:/images/controls/help-circle.svg"
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/starter-guide")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ PageType {
|
|||
id: root
|
||||
|
||||
property bool isEasySetup: true
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: proxyContainersModel
|
||||
|
|
@ -34,14 +33,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
implicitWidth: 1
|
||||
implicitHeight: 54
|
||||
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -49,8 +40,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: continueButton
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -163,7 +152,7 @@ PageType {
|
|||
implicitWidth: parent.width
|
||||
|
||||
text: qsTr("Continue")
|
||||
KeyNavigation.tab: setupLaterButton
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,32 @@ PageType {
|
|||
interactive: false
|
||||
model: proxyContainersModel
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: processedContainerListView.width
|
||||
implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height
|
||||
|
|
@ -62,19 +88,12 @@ PageType {
|
|||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
Layout.topMargin: 20
|
||||
Layout.rightMargin: -16
|
||||
Layout.leftMargin: -16
|
||||
|
||||
KeyNavigation.tab: showDetailsButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -104,42 +123,19 @@ PageType {
|
|||
KeyNavigation.tab: transportProtoSelector
|
||||
|
||||
clickedFunc: function() {
|
||||
showDetailsDrawer.open()
|
||||
showDetailsDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: showDetailsDrawer
|
||||
parent: root
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
defaultActiveFocusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
expandedContent: Item {
|
||||
Connections {
|
||||
target: showDetailsDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem2.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: showDetailsDrawer.expandedHeight
|
||||
|
||||
Item {
|
||||
id: focusItem2
|
||||
KeyNavigation.tab: showDetailsBackButton
|
||||
onFocusChanged: {
|
||||
if (focusItem2.activeFocus) {
|
||||
fl.contentY = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: showDetailsBackButton
|
||||
|
||||
|
|
@ -148,10 +144,8 @@ PageType {
|
|||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
KeyNavigation.tab: showDetailsCloseButton
|
||||
|
||||
backButtonFunction: function() {
|
||||
showDetailsDrawer.close()
|
||||
showDetailsDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -205,10 +199,9 @@ PageType {
|
|||
parentFlickable: fl
|
||||
|
||||
text: qsTr("Close")
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem2)
|
||||
|
||||
clickedFunc: function() {
|
||||
showDetailsDrawer.close()
|
||||
showDetailsDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -229,8 +222,6 @@ PageType {
|
|||
|
||||
Layout.fillWidth: true
|
||||
rootWidth: root.width
|
||||
|
||||
KeyNavigation.tab: (port.visible && port.enabled) ? port.textField : installButton
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
|
|
@ -242,8 +233,6 @@ PageType {
|
|||
headerText: qsTr("Port")
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
KeyNavigation.tab: installButton
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -259,8 +248,6 @@ PageType {
|
|||
|
||||
text: qsTr("Install")
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
if (!port.textField.acceptableInput &&
|
||||
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" &&
|
||||
|
|
@ -288,11 +275,6 @@ PageType {
|
|||
var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto)
|
||||
transportProtoSelector.visible = protocolSelectorVisible
|
||||
transportProtoHeader.visible = protocolSelectorVisible
|
||||
|
||||
if (port.visible && port.enabled)
|
||||
defaultActiveFocusItem = port.textField
|
||||
else
|
||||
defaultActiveFocusItem = focusItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,6 @@ import "../Config"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: proxyContainersModel
|
||||
sourceModel: ContainersModel
|
||||
|
|
@ -52,7 +45,6 @@ PageType {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
KeyNavigation.tab: containers
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
|
|
@ -32,11 +30,6 @@ PageType {
|
|||
Layout.preferredHeight: 287
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: startButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: startButton
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -50,8 +43,6 @@ PageType {
|
|||
clickedFunc: function() {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
|
||||
}
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,14 +13,6 @@ import "../Config"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: textKey.textField
|
||||
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: parent.top
|
||||
|
|
@ -39,7 +31,6 @@ PageType {
|
|||
BackButtonType {
|
||||
id: backButton
|
||||
Layout.topMargin: 20
|
||||
KeyNavigation.tab: textKey.textField
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
|
|
@ -67,8 +58,6 @@ PageType {
|
|||
textField.text = ""
|
||||
textField.paste()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: continueButton
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +73,6 @@ PageType {
|
|||
anchors.bottomMargin: 32
|
||||
|
||||
text: qsTr("Continue")
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
if (ImportController.extractConfigFromData(textKey.textFieldText)) {
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ PageType {
|
|||
|
||||
property bool showContent: false
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
|
|
@ -30,8 +23,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: showContentButton
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
|
@ -107,7 +98,8 @@ PageType {
|
|||
textColor: AmneziaStyle.color.goldenApricot
|
||||
|
||||
text: showContent ? qsTr("Collapse content") : qsTr("Show content")
|
||||
KeyNavigation.tab: connectButton
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
showContent = !showContent
|
||||
|
|
@ -186,8 +178,6 @@ PageType {
|
|||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
BasicButtonType {
|
||||
id: connectButton
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ import "../Config"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: clientNameTextField.textField
|
||||
|
||||
enum ConfigType {
|
||||
AmneziaConnection,
|
||||
OpenVpn,
|
||||
|
|
@ -47,7 +45,7 @@ PageType {
|
|||
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||
|
||||
shareConnectionDrawer.open()
|
||||
shareConnectionDrawer.openTriggered()
|
||||
shareConnectionDrawer.contentVisible = false
|
||||
PageController.showBusyIndicator(true)
|
||||
|
||||
|
|
@ -104,7 +102,7 @@ PageType {
|
|||
}
|
||||
|
||||
function onExportErrorOccurred(error) {
|
||||
shareConnectionDrawer.close()
|
||||
shareConnectionDrawer.closeTriggered()
|
||||
|
||||
PageController.showErrorMessage(error)
|
||||
}
|
||||
|
|
@ -172,16 +170,6 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: header.actionButton
|
||||
onFocusChanged: {
|
||||
if (focusItem.activeFocus) {
|
||||
a.contentY = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -191,10 +179,17 @@ PageType {
|
|||
|
||||
actionButtonImage: "qrc:/images/controls/more-vertical.svg"
|
||||
actionButtonFunction: function() {
|
||||
shareFullAccessDrawer.open()
|
||||
shareFullAccessDrawer.openTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: connectionRadioButton
|
||||
actionButton.onFocusChanged: {
|
||||
console.debug("MOVE THIS LOGIC TO CPP!")
|
||||
if (actionButton.activeFocus) {
|
||||
if (fl) {
|
||||
fl.ensureVisible(moreButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: shareFullAccessDrawer
|
||||
|
|
@ -203,13 +198,8 @@ PageType {
|
|||
|
||||
anchors.fill: parent
|
||||
expandedHeight: root.height
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
clientNameTextField.textField.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: shareFullAccessDrawerContent
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
|
|
@ -222,14 +212,6 @@ PageType {
|
|||
shareFullAccessDrawer.expandedHeight = shareFullAccessDrawerContent.implicitHeight + 32
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: shareFullAccessDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 16
|
||||
|
|
@ -240,24 +222,17 @@ PageType {
|
|||
descriptionText: qsTr("Use for your own devices, or share with those you trust to manage the server.")
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: shareFullAccessButton.rightButton
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: shareFullAccessButton
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Share")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
KeyNavigation.tab: focusItem
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageShareFullAccess)
|
||||
shareFullAccessDrawer.close()
|
||||
shareFullAccessDrawer.closeTriggered()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -288,8 +263,6 @@ PageType {
|
|||
implicitWidth: (root.width - 32) / 2
|
||||
text: qsTr("Connection")
|
||||
|
||||
KeyNavigation.tab: usersRadioButton
|
||||
|
||||
onClicked: {
|
||||
accessTypeSelector.currentIndex = 0
|
||||
if (!GC.isMobile()) {
|
||||
|
|
@ -305,15 +278,12 @@ PageType {
|
|||
implicitWidth: (root.width - 32) / 2
|
||||
text: qsTr("Users")
|
||||
|
||||
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? clientNameTextField.textField : serverSelector
|
||||
|
||||
onClicked: {
|
||||
accessTypeSelector.currentIndex = 1
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.updateClientManagementModel(ContainersModel.getProcessedContainerIndex(),
|
||||
ServersModel.getProcessedServerCredentials())
|
||||
PageController.showBusyIndicator(false)
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -342,9 +312,6 @@ PageType {
|
|||
textField.maximumLength: 20
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: serverSelector
|
||||
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
|
|
@ -390,7 +357,7 @@ PageType {
|
|||
serverSelector.severSelectorIndexChanged()
|
||||
}
|
||||
|
||||
serverSelector.close()
|
||||
serverSelector.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -408,8 +375,6 @@ PageType {
|
|||
ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: protocolSelector
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
|
|
@ -450,7 +415,7 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
handler()
|
||||
|
||||
protocolSelector.close()
|
||||
protocolSelector.closeTriggered()
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
|
@ -508,12 +473,6 @@ PageType {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ?
|
||||
exportTypeSelector :
|
||||
isSearchBarVisible ?
|
||||
searchTextField.textField :
|
||||
usersHeader.actionButton
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
|
|
@ -549,7 +508,7 @@ PageType {
|
|||
clickedFunction: function() {
|
||||
exportTypeSelector.text = selectedText
|
||||
exportTypeSelector.currentIndex = currentIndex
|
||||
exportTypeSelector.close()
|
||||
exportTypeSelector.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -557,9 +516,6 @@ PageType {
|
|||
exportTypeSelector.currentIndex = currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: shareButton
|
||||
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -575,7 +531,6 @@ PageType {
|
|||
text: qsTr("Share")
|
||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
parentFlickable: a
|
||||
|
||||
|
|
@ -584,7 +539,6 @@ PageType {
|
|||
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
|
|
@ -604,7 +558,6 @@ PageType {
|
|||
Keys.onTabPressed: clientsListView.model.count > 0 ?
|
||||
clientsListView.forceActiveFocus() :
|
||||
lastItemTabClicked(focusItem)
|
||||
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
|
@ -622,11 +575,11 @@ PageType {
|
|||
target: root
|
||||
function onIsSearchBarVisibleChanged() {
|
||||
if (root.isSearchBarVisible) {
|
||||
searchTextField.textField.forceActiveFocus()
|
||||
// searchTextField.textField.forceActiveFocus()
|
||||
} else {
|
||||
searchTextField.textFieldText = ""
|
||||
if (!GC.isMobile()) {
|
||||
usersHeader.actionButton.forceActiveFocus()
|
||||
// usersHeader.actionButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -638,15 +591,15 @@ PageType {
|
|||
|
||||
function navigateTo() {
|
||||
if (GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
// focusItem.forceActiveFocus()
|
||||
return;
|
||||
}
|
||||
|
||||
if (searchTextField.textFieldText === "") {
|
||||
root.isSearchBarVisible = false
|
||||
usersHeader.actionButton.forceActiveFocus()
|
||||
// usersHeader.actionButton.forceActiveFocus()
|
||||
} else {
|
||||
closeSearchButton.forceActiveFocus()
|
||||
// closeSearchButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -663,9 +616,9 @@ PageType {
|
|||
Keys.onTabPressed: {
|
||||
if (!GC.isMobile()) {
|
||||
if (clientsListView.model.count > 0) {
|
||||
clientsListView.forceActiveFocus()
|
||||
// clientsListView.forceActiveFocus()
|
||||
} else {
|
||||
lastItemTabClicked(focusItem)
|
||||
// lastItemTabClicked(focusItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -687,6 +640,32 @@ PageType {
|
|||
|
||||
visible: accessTypeSelector.currentIndex === 1
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyClientManagementModel
|
||||
sourceModel: ClientManagementModel
|
||||
|
|
@ -698,44 +677,44 @@ PageType {
|
|||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
// interactive: false
|
||||
|
||||
activeFocusOnTab: true
|
||||
focus: true
|
||||
Keys.onTabPressed: {
|
||||
if (!GC.isMobile()) {
|
||||
if (currentIndex < this.count - 1) {
|
||||
this.incrementCurrentIndex()
|
||||
currentItem.focusItem.forceActiveFocus()
|
||||
} else {
|
||||
this.currentIndex = 0
|
||||
lastItemTabClicked(focusItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
// activeFocusOnTab: true
|
||||
// focus: true
|
||||
// Keys.onTabPressed: {
|
||||
// if (!GC.isMobile()) {
|
||||
// if (currentIndex < this.count - 1) {
|
||||
// this.incrementCurrentIndex()
|
||||
// // currentItem.focusItem.forceActiveFocus()
|
||||
// } else {
|
||||
// this.currentIndex = 0
|
||||
// // lastItemTabClicked(focusItem)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (focus && !GC.isMobile()) {
|
||||
currentIndex = 0
|
||||
currentItem.focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
// onActiveFocusChanged: {
|
||||
// if (focus && !GC.isMobile()) {
|
||||
// currentIndex = 0
|
||||
// // currentItem.focusItem.forceActiveFocus()
|
||||
// }
|
||||
// }
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (currentItem) {
|
||||
if (currentItem.y < a.contentY) {
|
||||
a.contentY = currentItem.y
|
||||
} else if (currentItem.y + currentItem.height + clientsListView.y > a.contentY + a.height) {
|
||||
a.contentY = currentItem.y + clientsListView.y + currentItem.height - a.height
|
||||
}
|
||||
}
|
||||
}
|
||||
// onCurrentIndexChanged: {
|
||||
// if (currentItem) {
|
||||
// if (currentItem.y < a.contentY) {
|
||||
// a.contentY = currentItem.y
|
||||
// } else if (currentItem.y + currentItem.height + clientsListView.y > a.contentY + a.height) {
|
||||
// a.contentY = currentItem.y + clientsListView.y + currentItem.height - a.height
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: clientsListView.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
property alias focusItem: clientFocusItem.rightButton
|
||||
// property alias focusItem: clientFocusItem.rightButton
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
|
@ -755,7 +734,7 @@ PageType {
|
|||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
clientInfoDrawer.open()
|
||||
clientInfoDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -768,15 +747,15 @@ PageType {
|
|||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
// focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
width: root.width
|
||||
height: root.height
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
id: expandedContent
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: expandedStateContent
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
|
@ -785,14 +764,14 @@ PageType {
|
|||
anchors.rightMargin: 16
|
||||
|
||||
onImplicitHeightChanged: {
|
||||
clientInfoDrawer.expandedHeight = expandedContent.implicitHeight + 32
|
||||
clientInfoDrawer.expandedHeight = expandedStateContent.implicitHeight + 32
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: clientInfoDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem1.forceActiveFocus()
|
||||
// focusItem1.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -846,11 +825,6 @@ PageType {
|
|||
text: qsTr("Allowed IPs: %1").arg(allowedIps)
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem1
|
||||
KeyNavigation.tab: renameButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: renameButton
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -865,10 +839,8 @@ PageType {
|
|||
|
||||
text: qsTr("Rename")
|
||||
|
||||
KeyNavigation.tab: revokeButton
|
||||
|
||||
clickedFunc: function() {
|
||||
clientNameEditDrawer.open()
|
||||
clientNameEditDrawer.openTriggered()
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
|
|
@ -881,11 +853,11 @@ PageType {
|
|||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem1.forceActiveFocus()
|
||||
// focusItem1.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
|
@ -897,15 +869,10 @@ PageType {
|
|||
target: clientNameEditDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
clientNameEditor.textField.forceActiveFocus()
|
||||
// clientNameEditor.textField.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem2
|
||||
KeyNavigation.tab: clientNameEditor.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: clientNameEditor
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -913,8 +880,6 @@ PageType {
|
|||
textFieldText: clientName
|
||||
textField.maximumLength: 20
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: saveButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -923,7 +888,6 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Save")
|
||||
KeyNavigation.tab: focusItem2
|
||||
|
||||
clickedFunc: function() {
|
||||
if (clientNameEditor.textFieldText === "") {
|
||||
|
|
@ -937,7 +901,7 @@ PageType {
|
|||
ContainersModel.getProcessedContainerIndex(),
|
||||
ServersModel.getProcessedServerCredentials())
|
||||
PageController.showBusyIndicator(false)
|
||||
clientNameEditDrawer.close()
|
||||
clientNameEditDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -958,7 +922,6 @@ PageType {
|
|||
borderWidth: 1
|
||||
|
||||
text: qsTr("Revoke")
|
||||
KeyNavigation.tab: focusItem1
|
||||
|
||||
clickedFunc: function() {
|
||||
var headerText = qsTr("Revoke the config for a user - %1?").arg(clientName)
|
||||
|
|
@ -967,12 +930,12 @@ PageType {
|
|||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
clientInfoDrawer.close()
|
||||
clientInfoDrawer.closeTriggered()
|
||||
root.revokeConfig(index)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem1.forceActiveFocus()
|
||||
// focusItem1.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -993,7 +956,7 @@ PageType {
|
|||
anchors.fill: parent
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
clientNameTextField.textField.forceActiveFocus()
|
||||
// clientNameTextField.textField.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1001,7 +964,7 @@ PageType {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: function(mouse) {
|
||||
forceActiveFocus()
|
||||
// forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,7 @@ import "../Config"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: focusItem
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
// defaultActiveFocusItem: focusItem
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
|
@ -32,8 +27,6 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
KeyNavigation.tab: serverSelector
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
|
@ -85,8 +78,6 @@ PageType {
|
|||
descriptionText: qsTr("Server")
|
||||
headerText: qsTr("Server")
|
||||
|
||||
KeyNavigation.tab: shareButton
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: serverSelectorListView
|
||||
|
||||
|
|
@ -113,7 +104,7 @@ PageType {
|
|||
|
||||
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
|
||||
serverSelector.close()
|
||||
serverSelector.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -137,8 +128,6 @@ PageType {
|
|||
text: qsTr("Share")
|
||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||
|
||||
clickedFunc: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
|
||||
|
|
@ -153,7 +142,7 @@ PageType {
|
|||
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||
|
||||
shareConnectionDrawer.open()
|
||||
shareConnectionDrawer.openTriggered()
|
||||
shareConnectionDrawer.contentVisible = true
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
|
@ -166,10 +155,5 @@ PageType {
|
|||
id: shareConnectionDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ import "../Components"
|
|||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: homeTabButton
|
||||
|
||||
property bool isControlsDisabled: false
|
||||
property bool isTabBarDisabled: false
|
||||
|
||||
Connections {
|
||||
objectName: "pageControllerConnection"
|
||||
|
||||
target: PageController
|
||||
|
||||
function onGoToPageHome() {
|
||||
|
|
@ -90,19 +90,11 @@ PageType {
|
|||
PageController.closePage()
|
||||
}
|
||||
}
|
||||
|
||||
function onForceTabBarActiveFocus() {
|
||||
homeTabButton.focus = true
|
||||
tabBar.forceActiveFocus()
|
||||
}
|
||||
|
||||
function onForceStackActiveFocus() {
|
||||
homeTabButton.focus = true
|
||||
tabBarStackView.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
objectName: "installControllerConnections"
|
||||
|
||||
target: InstallController
|
||||
|
||||
function onInstallationErrorOccurred(error) {
|
||||
|
|
@ -165,6 +157,8 @@ PageType {
|
|||
}
|
||||
|
||||
Connections {
|
||||
objectName: "connectionControllerConnections"
|
||||
|
||||
target: ConnectionController
|
||||
|
||||
function onReconnectWithUpdatedContainer(message) {
|
||||
|
|
@ -182,6 +176,8 @@ PageType {
|
|||
}
|
||||
|
||||
Connections {
|
||||
objectName: "importControllerConnections"
|
||||
|
||||
target: ImportController
|
||||
|
||||
function onImportErrorOccurred(error, goToPageHome) {
|
||||
|
|
@ -196,6 +192,8 @@ PageType {
|
|||
}
|
||||
|
||||
Connections {
|
||||
objectName: "settingsControllerConnections"
|
||||
|
||||
target: SettingsController
|
||||
|
||||
function onLoggingDisableByWatcher() {
|
||||
|
|
@ -218,6 +216,7 @@ PageType {
|
|||
|
||||
StackViewType {
|
||||
id: tabBarStackView
|
||||
objectName: "tabBarStackView"
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
|
@ -247,13 +246,28 @@ PageType {
|
|||
}
|
||||
|
||||
Keys.onPressed: function(event) {
|
||||
PageController.keyPressEvent(event.key)
|
||||
event.accepted = true
|
||||
console.debug(">>>> ", event.key, " Event is caught by StartPage")
|
||||
switch (event.key) {
|
||||
case Qt.Key_Tab:
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Right:
|
||||
FocusController.nextKeyTabItem()
|
||||
break
|
||||
case Qt.Key_Backtab:
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Left:
|
||||
FocusController.previousKeyTabItem()
|
||||
break
|
||||
default:
|
||||
PageController.keyPressEvent(event.key)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
objectName: "tabBar"
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
|
@ -269,6 +283,8 @@ PageType {
|
|||
enabled: !root.isControlsDisabled && !root.isTabBarDisabled
|
||||
|
||||
background: Shape {
|
||||
objectName: "backgroundShape"
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
|
|
@ -289,6 +305,8 @@ PageType {
|
|||
|
||||
TabImageButtonType {
|
||||
id: homeTabButton
|
||||
objectName: "homeTabButton"
|
||||
|
||||
isSelected: tabBar.currentIndex === 0
|
||||
image: "qrc:/images/controls/home.svg"
|
||||
clickedFunc: function () {
|
||||
|
|
@ -296,14 +314,11 @@ PageType {
|
|||
ServersModel.processedIndex = ServersModel.defaultIndex
|
||||
tabBar.currentIndex = 0
|
||||
}
|
||||
|
||||
KeyNavigation.tab: shareTabButton
|
||||
Keys.onEnterPressed: this.clicked()
|
||||
Keys.onReturnPressed: this.clicked()
|
||||
}
|
||||
|
||||
TabImageButtonType {
|
||||
id: shareTabButton
|
||||
objectName: "shareTabButton"
|
||||
|
||||
Connections {
|
||||
target: ServersModel
|
||||
|
|
@ -324,32 +339,30 @@ PageType {
|
|||
tabBarStackView.goToTabBarPage(PageEnum.PageShare)
|
||||
tabBar.currentIndex = 1
|
||||
}
|
||||
|
||||
KeyNavigation.tab: settingsTabButton
|
||||
}
|
||||
|
||||
TabImageButtonType {
|
||||
id: settingsTabButton
|
||||
objectName: "settingsTabButton"
|
||||
|
||||
isSelected: tabBar.currentIndex === 2
|
||||
image: "qrc:/images/controls/settings-2.svg"
|
||||
clickedFunc: function () {
|
||||
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
|
||||
tabBar.currentIndex = 2
|
||||
}
|
||||
|
||||
KeyNavigation.tab: plusTabButton
|
||||
}
|
||||
|
||||
TabImageButtonType {
|
||||
id: plusTabButton
|
||||
objectName: "plusTabButton"
|
||||
|
||||
isSelected: tabBar.currentIndex === 3
|
||||
image: "qrc:/images/controls/plus.svg"
|
||||
clickedFunc: function () {
|
||||
tabBarStackView.goToTabBarPage(PageEnum.PageSetupWizardConfigSource)
|
||||
tabBar.currentIndex = 3
|
||||
}
|
||||
|
||||
Keys.onTabPressed: PageController.forceStackActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import "Pages2"
|
|||
Window {
|
||||
id: root
|
||||
objectName: "mainWindow"
|
||||
|
||||
visible: true
|
||||
width: GC.screenWidth
|
||||
height: GC.screenHeight
|
||||
|
|
@ -26,13 +27,39 @@ Window {
|
|||
color: AmneziaStyle.color.midnightBlack
|
||||
|
||||
onClosing: function() {
|
||||
console.debug("QML onClosing signal")
|
||||
PageController.closeWindow()
|
||||
}
|
||||
|
||||
title: "AmneziaVPN"
|
||||
|
||||
Item { // This item is needed for focus handling
|
||||
id: defaultFocusItem
|
||||
objectName: "defaultFocusItem"
|
||||
|
||||
focus: true
|
||||
|
||||
Keys.onPressed: function(event) {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Tab:
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Right:
|
||||
FocusController.nextKeyTabItem()
|
||||
break
|
||||
case Qt.Key_Backtab:
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Left:
|
||||
FocusController.previousKeyTabItem()
|
||||
break
|
||||
default:
|
||||
PageController.keyPressEvent(event.key)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
objectName: "pageControllerConnections"
|
||||
|
||||
target: PageController
|
||||
|
||||
function onRaiseMainWindow() {
|
||||
|
|
@ -58,7 +85,7 @@ Window {
|
|||
}
|
||||
|
||||
function onShowPassphraseRequestDrawer() {
|
||||
privateKeyPassphraseDrawer.open()
|
||||
privateKeyPassphraseDrawer.openTriggered()
|
||||
}
|
||||
|
||||
function onGoToPageSettingsBackup() {
|
||||
|
|
@ -72,6 +99,8 @@ Window {
|
|||
}
|
||||
|
||||
Connections {
|
||||
objectName: "settingsControllerConnections"
|
||||
|
||||
target: SettingsController
|
||||
|
||||
function onChangeSettingsFinished(finishedMessage) {
|
||||
|
|
@ -80,11 +109,15 @@ Window {
|
|||
}
|
||||
|
||||
PageStart {
|
||||
objectName: "pageStart"
|
||||
|
||||
width: root.width
|
||||
height: root.height
|
||||
}
|
||||
|
||||
Item {
|
||||
objectName: "popupNotificationItem"
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
|
|
@ -108,6 +141,8 @@ Window {
|
|||
}
|
||||
|
||||
Item {
|
||||
objectName: "popupErrorMessageItem"
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
|
|
@ -120,6 +155,8 @@ Window {
|
|||
}
|
||||
|
||||
Item {
|
||||
objectName: "privateKeyPassphraseDrawerItem"
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
DrawerType2 {
|
||||
|
|
@ -128,7 +165,7 @@ Window {
|
|||
anchors.fill: parent
|
||||
expandedHeight: root.height * 0.35
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
|
@ -167,8 +204,6 @@ Window {
|
|||
clickedFunc: function() {
|
||||
hidePassword = !hidePassword
|
||||
}
|
||||
|
||||
KeyNavigation.tab: saveButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
|
@ -186,7 +221,7 @@ Window {
|
|||
text: qsTr("Save")
|
||||
|
||||
clickedFunc: function() {
|
||||
privateKeyPassphraseDrawer.close()
|
||||
privateKeyPassphraseDrawer.closeTriggered()
|
||||
PageController.passphraseRequestDrawerClosed(passphrase.textFieldText)
|
||||
}
|
||||
}
|
||||
|
|
@ -195,6 +230,8 @@ Window {
|
|||
}
|
||||
|
||||
Item {
|
||||
objectName: "questionDrawerItem"
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
QuestionDrawer {
|
||||
|
|
@ -205,6 +242,8 @@ Window {
|
|||
}
|
||||
|
||||
Item {
|
||||
objectName: "busyIndicatorItem"
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
BusyIndicatorType {
|
||||
|
|
@ -221,26 +260,26 @@ Window {
|
|||
questionDrawer.noButtonText = noButtonText
|
||||
|
||||
questionDrawer.yesButtonFunction = function() {
|
||||
questionDrawer.close()
|
||||
questionDrawer.closeTriggered()
|
||||
if (yesButtonFunction && typeof yesButtonFunction === "function") {
|
||||
yesButtonFunction()
|
||||
}
|
||||
}
|
||||
questionDrawer.noButtonFunction = function() {
|
||||
questionDrawer.close()
|
||||
questionDrawer.closeTriggered()
|
||||
if (noButtonFunction && typeof noButtonFunction === "function") {
|
||||
noButtonFunction()
|
||||
}
|
||||
}
|
||||
questionDrawer.open()
|
||||
questionDrawer.openTriggered()
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: mainFileDialog
|
||||
objectName: "mainFileDialog"
|
||||
|
||||
property bool isSaveMode: false
|
||||
|
||||
objectName: "mainFileDialog"
|
||||
fileMode: isSaveMode ? FileDialog.SaveFile : FileDialog.OpenFile
|
||||
|
||||
onAccepted: SystemController.fileDialogClosed(true)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue