diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 4e25097d..aeed439b 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -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()); diff --git a/client/amnezia_application.h b/client/amnezia_application.h index 64566216..cfeac0d1 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -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 m_connectionController; + QScopedPointer m_focusController; QScopedPointer m_pageController; QScopedPointer m_installController; QScopedPointer m_importController; diff --git a/client/resources.qrc b/client/resources.qrc index a10a784d..5edd1e8a 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -1,225 +1,226 @@ + fonts/pt-root-ui_vf.ttf + images/amneziaBigLogo.png + images/AmneziaVPN.png + images/controls/alert-circle.svg + images/controls/amnezia.svg + images/controls/app.svg + images/controls/archive-restore.svg + images/controls/arrow-left.svg + images/controls/arrow-right.svg + images/controls/bug.svg + images/controls/check.svg + images/controls/chevron-down.svg + images/controls/chevron-right.svg + images/controls/chevron-up.svg + images/controls/close.svg + images/controls/copy.svg + images/controls/delete.svg + images/controls/download.svg + images/controls/edit-3.svg + images/controls/eye-off.svg + images/controls/eye.svg + images/controls/file-check-2.svg + images/controls/file-cog-2.svg + images/controls/folder-open.svg + images/controls/folder-search-2.svg + images/controls/gauge.svg + images/controls/github.svg + images/controls/help-circle.svg + images/controls/history.svg + images/controls/home.svg + images/controls/info.svg + images/controls/mail.svg + images/controls/map-pin.svg + images/controls/more-vertical.svg + images/controls/plus.svg + images/controls/qr-code.svg + images/controls/radio-button-inner-circle-pressed.png + images/controls/radio-button-inner-circle.png + images/controls/radio-button-pressed.svg + images/controls/radio-button.svg + images/controls/radio.svg + images/controls/refresh-cw.svg + images/controls/save.svg + images/controls/scan-line.svg + images/controls/search.svg + images/controls/server.svg + images/controls/settings-2.svg + images/controls/settings.svg + images/controls/share-2.svg + images/controls/split-tunneling.svg + images/controls/tag.svg + images/controls/telegram.svg + images/controls/text-cursor.svg + images/controls/trash.svg + images/controls/x-circle.svg images/tray/active.png images/tray/default.png images/tray/error.png - images/AmneziaVPN.png - server_scripts/remove_container.sh - server_scripts/setup_host_firewall.sh - server_scripts/openvpn_cloak/Dockerfile + server_scripts/awg/configure_container.sh + server_scripts/awg/Dockerfile + server_scripts/awg/run_container.sh + server_scripts/awg/start.sh + server_scripts/awg/template.conf + server_scripts/build_container.sh + server_scripts/check_connection.sh + server_scripts/check_server_is_busy.sh + server_scripts/check_user_in_sudo.sh + server_scripts/dns/configure_container.sh + server_scripts/dns/Dockerfile + server_scripts/dns/run_container.sh + server_scripts/install_docker.sh + server_scripts/ipsec/configure_container.sh + server_scripts/ipsec/Dockerfile + server_scripts/ipsec/mobileconfig.plist + server_scripts/ipsec/run_container.sh + server_scripts/ipsec/start.sh + server_scripts/ipsec/strongswan.profile server_scripts/openvpn_cloak/configure_container.sh + server_scripts/openvpn_cloak/Dockerfile + server_scripts/openvpn_cloak/run_container.sh server_scripts/openvpn_cloak/start.sh server_scripts/openvpn_cloak/template.ovpn - server_scripts/install_docker.sh - server_scripts/build_container.sh - server_scripts/prepare_host.sh - server_scripts/check_connection.sh - server_scripts/remove_all_containers.sh - server_scripts/openvpn_cloak/run_container.sh - server_scripts/openvpn/configure_container.sh - server_scripts/openvpn/run_container.sh - server_scripts/openvpn/template.ovpn - server_scripts/openvpn/Dockerfile - server_scripts/openvpn/start.sh server_scripts/openvpn_shadowsocks/configure_container.sh server_scripts/openvpn_shadowsocks/Dockerfile server_scripts/openvpn_shadowsocks/run_container.sh server_scripts/openvpn_shadowsocks/start.sh server_scripts/openvpn_shadowsocks/template.ovpn + server_scripts/openvpn/configure_container.sh + server_scripts/openvpn/Dockerfile + server_scripts/openvpn/run_container.sh + server_scripts/openvpn/start.sh + server_scripts/openvpn/template.ovpn + server_scripts/prepare_host.sh + server_scripts/remove_all_containers.sh + server_scripts/remove_container.sh + server_scripts/setup_host_firewall.sh + server_scripts/sftp/configure_container.sh + server_scripts/sftp/Dockerfile + server_scripts/sftp/run_container.sh + server_scripts/socks5_proxy/configure_container.sh + server_scripts/socks5_proxy/Dockerfile + server_scripts/socks5_proxy/run_container.sh + server_scripts/socks5_proxy/start.sh + server_scripts/website_tor/configure_container.sh + server_scripts/website_tor/Dockerfile + server_scripts/website_tor/run_container.sh server_scripts/wireguard/configure_container.sh server_scripts/wireguard/Dockerfile server_scripts/wireguard/run_container.sh server_scripts/wireguard/start.sh server_scripts/wireguard/template.conf - server_scripts/website_tor/configure_container.sh - server_scripts/website_tor/run_container.sh - ui/qml/Config/GlobalConfig.qml - ui/qml/Config/qmldir - server_scripts/check_server_is_busy.sh - server_scripts/dns/configure_container.sh - server_scripts/dns/Dockerfile - server_scripts/dns/run_container.sh - server_scripts/sftp/configure_container.sh - server_scripts/sftp/Dockerfile - server_scripts/sftp/run_container.sh - server_scripts/ipsec/configure_container.sh - server_scripts/ipsec/Dockerfile - server_scripts/ipsec/run_container.sh - server_scripts/ipsec/start.sh - server_scripts/ipsec/mobileconfig.plist - server_scripts/ipsec/strongswan.profile - server_scripts/website_tor/Dockerfile - server_scripts/check_user_in_sudo.sh - ui/qml/Controls2/BasicButtonType.qml - ui/qml/Controls2/TextFieldWithHeaderType.qml - ui/qml/Controls2/LabelWithButtonType.qml - images/controls/arrow-right.svg - images/controls/chevron-right.svg - ui/qml/Controls2/ImageButtonType.qml - ui/qml/Controls2/CardType.qml - ui/qml/Controls2/CheckBoxType.qml - images/controls/check.svg - ui/qml/Controls2/DropDownType.qml - ui/qml/Pages2/PageSetupWizardStart.qml - ui/qml/main2.qml - images/amneziaBigLogo.png - ui/qml/Controls2/FlickableType.qml - ui/qml/Pages2/PageSetupWizardCredentials.qml - ui/qml/Controls2/HeaderType.qml - images/controls/arrow-left.svg - ui/qml/Pages2/PageSetupWizardProtocols.qml - ui/qml/Pages2/PageSetupWizardEasy.qml - images/controls/chevron-down.svg - images/controls/chevron-up.svg - ui/qml/Controls2/TextTypes/ParagraphTextType.qml - ui/qml/Controls2/TextTypes/Header2TextType.qml - ui/qml/Controls2/HorizontalRadioButton.qml - ui/qml/Controls2/VerticalRadioButton.qml - ui/qml/Controls2/SwitcherType.qml - ui/qml/Controls2/TabButtonType.qml - ui/qml/Pages2/PageSetupWizardProtocolSettings.qml - ui/qml/Pages2/PageSetupWizardInstalling.qml - ui/qml/Pages2/PageSetupWizardConfigSource.qml - images/controls/folder-open.svg - images/controls/qr-code.svg - images/controls/text-cursor.svg - ui/qml/Pages2/PageSetupWizardTextKey.qml - ui/qml/Pages2/PageStart.qml - ui/qml/Controls2/TabImageButtonType.qml - images/controls/home.svg - images/controls/settings-2.svg - images/controls/share-2.svg - ui/qml/Pages2/PageHome.qml - ui/qml/Pages2/PageSettingsServersList.qml - ui/qml/Pages2/PageShare.qml - ui/qml/Controls2/TextTypes/Header1TextType.qml - ui/qml/Controls2/TextTypes/LabelTextType.qml - ui/qml/Controls2/TextTypes/ButtonTextType.qml - ui/qml/Controls2/Header2Type.qml - images/controls/plus.svg - ui/qml/Components/ConnectButton.qml - images/controls/download.svg - ui/qml/Controls2/ProgressBarType.qml - ui/qml/Components/ConnectionTypeSelectionDrawer.qml - ui/qml/Components/HomeContainersListView.qml - ui/qml/Controls2/TextTypes/CaptionTextType.qml - images/controls/settings.svg - ui/qml/Pages2/PageSettingsServerInfo.qml - ui/qml/Controls2/PageType.qml - ui/qml/Controls2/PopupType.qml - images/controls/edit-3.svg - ui/qml/Pages2/PageSettingsServerData.qml - ui/qml/Components/SettingsContainersListView.qml - ui/qml/Controls2/TextTypes/ListItemTitleType.qml - ui/qml/Controls2/DividerType.qml - ui/qml/Controls2/StackViewType.qml - ui/qml/Pages2/PageSettings.qml - images/controls/amnezia.svg - images/controls/app.svg - images/controls/radio.svg - images/controls/save.svg - images/controls/server.svg - ui/qml/Pages2/PageSettingsServerProtocols.qml - ui/qml/Pages2/PageSettingsServerServices.qml - ui/qml/Pages2/PageSetupWizardViewConfig.qml - images/controls/file-cog-2.svg - ui/qml/Components/QuestionDrawer.qml - ui/qml/Pages2/PageDeinstalling.qml - ui/qml/Controls2/BackButtonType.qml - ui/qml/Pages2/PageSettingsServerProtocol.qml - ui/qml/Components/TransportProtoSelector.qml - ui/qml/Controls2/ListViewWithRadioButtonType.qml - images/controls/radio-button.svg - images/controls/radio-button-inner-circle.png - images/controls/radio-button-pressed.svg - images/controls/radio-button-inner-circle-pressed.png - ui/qml/Components/ShareConnectionDrawer.qml - ui/qml/Pages2/PageSettingsConnection.qml - ui/qml/Pages2/PageSettingsDns.qml - ui/qml/Pages2/PageSettingsApplication.qml - ui/qml/Pages2/PageSettingsBackup.qml - images/controls/delete.svg - ui/qml/Pages2/PageSettingsAbout.qml - images/controls/github.svg - images/controls/mail.svg - images/controls/telegram.svg - ui/qml/Controls2/TextTypes/SmallTextType.qml - ui/qml/Filters/ContainersModelFilters.qml - ui/qml/Components/SelectLanguageDrawer.qml - ui/qml/Controls2/BusyIndicatorType.qml - ui/qml/Pages2/PageProtocolOpenVpnSettings.qml - ui/qml/Pages2/PageProtocolShadowSocksSettings.qml - ui/qml/Pages2/PageProtocolCloakSettings.qml - ui/qml/Pages2/PageProtocolXraySettings.qml - ui/qml/Pages2/PageProtocolRaw.qml - ui/qml/Pages2/PageSettingsLogging.qml - ui/qml/Pages2/PageServiceSftpSettings.qml - images/controls/copy.svg - ui/qml/Pages2/PageServiceTorWebsiteSettings.qml - ui/qml/Pages2/PageSetupWizardQrReader.qml - images/controls/eye.svg - images/controls/eye-off.svg - ui/qml/Pages2/PageSettingsSplitTunneling.qml - ui/qml/Controls2/ContextMenuType.qml - ui/qml/Controls2/TextAreaType.qml - images/controls/trash.svg - images/controls/more-vertical.svg - ui/qml/Controls2/ListViewWithLabelsType.qml - ui/qml/Pages2/PageServiceDnsSettings.qml - ui/qml/Controls2/TopCloseButtonType.qml - images/controls/x-circle.svg - ui/qml/Pages2/PageProtocolAwgSettings.qml - server_scripts/awg/template.conf - server_scripts/awg/start.sh - server_scripts/awg/configure_container.sh - server_scripts/awg/run_container.sh - server_scripts/awg/Dockerfile - ui/qml/Pages2/PageShareFullAccess.qml - images/controls/close.svg - images/controls/search.svg server_scripts/xray/configure_container.sh server_scripts/xray/Dockerfile server_scripts/xray/run_container.sh server_scripts/xray/start.sh server_scripts/xray/template.json - ui/qml/Pages2/PageProtocolWireGuardSettings.qml + ui/qml/Components/ConnectButton.qml + ui/qml/Components/ConnectionTypeSelectionDrawer.qml + ui/qml/Components/HomeContainersListView.qml ui/qml/Components/HomeSplitTunnelingDrawer.qml - images/controls/split-tunneling.svg - ui/qml/Controls2/DrawerType2.qml - ui/qml/Pages2/PageSettingsAppSplitTunneling.qml ui/qml/Components/InstalledAppsDrawer.qml - images/controls/alert-circle.svg - images/controls/file-check-2.svg + ui/qml/Components/QuestionDrawer.qml + ui/qml/Components/SelectLanguageDrawer.qml + ui/qml/Components/ServersListView.qml + ui/qml/Components/SettingsContainersListView.qml + ui/qml/Components/ShareConnectionDrawer.qml + ui/qml/Components/TransportProtoSelector.qml + ui/qml/Config/GlobalConfig.qml + ui/qml/Config/qmldir + ui/qml/Controls2/BackButtonType.qml + ui/qml/Controls2/BasicButtonType.qml + ui/qml/Controls2/BusyIndicatorType.qml + ui/qml/Controls2/CardType.qml + ui/qml/Controls2/CardWithIconsType.qml + ui/qml/Controls2/CheckBoxType.qml + ui/qml/Controls2/ContextMenuType.qml + ui/qml/Controls2/DividerType.qml + ui/qml/Controls2/DrawerType2.qml + ui/qml/Controls2/DropDownType.qml + ui/qml/Controls2/FlickableType.qml + ui/qml/Controls2/Header2Type.qml + ui/qml/Controls2/HeaderType.qml + ui/qml/Controls2/HorizontalRadioButton.qml + ui/qml/Controls2/ImageButtonType.qml + ui/qml/Controls2/LabelWithButtonType.qml + ui/qml/Controls2/LabelWithImageType.qml + ui/qml/Controls2/ListViewWithLabelsType.qml + ui/qml/Controls2/ListViewWithRadioButtonType.qml + ui/qml/Controls2/PageType.qml + ui/qml/Controls2/PopupType.qml + ui/qml/Controls2/ProgressBarType.qml + ui/qml/Controls2/StackViewType.qml + ui/qml/Controls2/SwitcherType.qml + ui/qml/Controls2/TabButtonType.qml + ui/qml/Controls2/TabImageButtonType.qml + ui/qml/Controls2/TextAreaType.qml + ui/qml/Controls2/TextAreaWithFooterType.qml + ui/qml/Controls2/TextFieldWithHeaderType.qml + ui/qml/Controls2/TextTypes/ButtonTextType.qml + ui/qml/Controls2/TextTypes/CaptionTextType.qml + ui/qml/Controls2/TextTypes/Header1TextType.qml + ui/qml/Controls2/TextTypes/Header2TextType.qml + ui/qml/Controls2/TextTypes/LabelTextType.qml + ui/qml/Controls2/TextTypes/ListItemTitleType.qml + ui/qml/Controls2/TextTypes/ParagraphTextType.qml + ui/qml/Controls2/TextTypes/SmallTextType.qml + ui/qml/Controls2/TopCloseButtonType.qml + ui/qml/Controls2/VerticalRadioButton.qml ui/qml/Controls2/WarningType.qml - fonts/pt-root-ui_vf.ttf - ui/qml/Modules/Style/qmldir + ui/qml/Filters/ContainersModelFilters.qml + ui/qml/main2.qml ui/qml/Modules/Style/AmneziaStyle.qml + ui/qml/Modules/Style/qmldir + ui/qml/Pages2/PageDeinstalling.qml + ui/qml/Pages2/PageDevMenu.qml + ui/qml/Pages2/PageHome.qml + ui/qml/Pages2/PageProtocolAwgSettings.qml + ui/qml/Pages2/PageProtocolCloakSettings.qml + ui/qml/Pages2/PageProtocolOpenVpnSettings.qml + ui/qml/Pages2/PageProtocolRaw.qml + ui/qml/Pages2/PageProtocolShadowSocksSettings.qml + ui/qml/Pages2/PageProtocolWireGuardSettings.qml + ui/qml/Pages2/PageProtocolXraySettings.qml + ui/qml/Pages2/PageServiceDnsSettings.qml + ui/qml/Pages2/PageServiceSftpSettings.qml ui/qml/Pages2/PageServiceSocksProxySettings.qml - server_scripts/socks5_proxy/run_container.sh - server_scripts/socks5_proxy/Dockerfile - server_scripts/socks5_proxy/configure_container.sh - server_scripts/socks5_proxy/start.sh + ui/qml/Pages2/PageServiceTorWebsiteSettings.qml + ui/qml/Pages2/PageSettings.qml + ui/qml/Pages2/PageSettingsAbout.qml + ui/qml/Pages2/PageSettingsApiLanguageList.qml + ui/qml/Pages2/PageSettingsApiServerInfo.qml + ui/qml/Pages2/PageSettingsApplication.qml + ui/qml/Pages2/PageSettingsAppSplitTunneling.qml + ui/qml/Pages2/PageSettingsBackup.qml + ui/qml/Pages2/PageSettingsConnection.qml + ui/qml/Pages2/PageSettingsDns.qml + ui/qml/Pages2/PageSettingsLogging.qml + ui/qml/Pages2/PageSettingsServerData.qml + ui/qml/Pages2/PageSettingsServerInfo.qml + ui/qml/Pages2/PageSettingsServerProtocol.qml + ui/qml/Pages2/PageSettingsServerProtocols.qml + ui/qml/Pages2/PageSettingsServerServices.qml + ui/qml/Pages2/PageSettingsServersList.qml + ui/qml/Pages2/PageSettingsSplitTunneling.qml ui/qml/Pages2/PageProtocolAwgClientSettings.qml ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml - ui/qml/Pages2/PageSetupWizardApiServicesList.qml ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml - ui/qml/Controls2/CardWithIconsType.qml - images/controls/tag.svg - images/controls/history.svg - images/controls/gauge.svg - images/controls/map-pin.svg - ui/qml/Controls2/LabelWithImageType.qml - images/controls/info.svg - ui/qml/Controls2/TextAreaWithFooterType.qml - images/controls/scan-line.svg - images/controls/folder-search-2.svg - ui/qml/Pages2/PageSettingsApiServerInfo.qml - images/controls/bug.svg - ui/qml/Pages2/PageDevMenu.qml - images/controls/refresh-cw.svg - ui/qml/Pages2/PageSettingsApiLanguageList.qml - images/controls/archive-restore.svg - images/controls/help-circle.svg + ui/qml/Pages2/PageSetupWizardApiServicesList.qml + ui/qml/Pages2/PageSetupWizardConfigSource.qml + ui/qml/Pages2/PageSetupWizardCredentials.qml + ui/qml/Pages2/PageSetupWizardEasy.qml + ui/qml/Pages2/PageSetupWizardInstalling.qml + ui/qml/Pages2/PageSetupWizardProtocols.qml + ui/qml/Pages2/PageSetupWizardProtocolSettings.qml + ui/qml/Pages2/PageSetupWizardQrReader.qml + ui/qml/Pages2/PageSetupWizardStart.qml + ui/qml/Pages2/PageSetupWizardTextKey.qml + ui/qml/Pages2/PageSetupWizardViewConfig.qml + ui/qml/Pages2/PageShare.qml + ui/qml/Pages2/PageShareFullAccess.qml + ui/qml/Pages2/PageStart.qml images/flagKit/ZW.svg diff --git a/client/ui/controllers/focusController.cpp b/client/ui/controllers/focusController.cpp new file mode 100644 index 00000000..58e33c7e --- /dev/null +++ b/client/ui/controllers/focusController.cpp @@ -0,0 +1,476 @@ +#include "focusController.h" + +#include +#include +#include +#include +#include +#include + + +bool isVisible(QObject* item) +{ + const auto res = item->property("visible").toBool(); + // qDebug() << "==>> " << (res ? "VISIBLE" : "NOT visible") << item; + return res; +} + +bool isFocusable(QObject* item) +{ + const auto res = item->property("isFocusable").toBool(); + // qDebug() << "==>> " << (res ? "FOCUSABLE" : "NOT focusable") << item; + return res; +} + +QRectF getItemCoordsOnScene(QQuickItem* item) // TODO: remove? +{ + if (!item) return {}; + return item->mapRectToScene(item->childrenRect()); +} + +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(item1)); + const auto p2 = getItemCenterPointOnScene(qobject_cast(item2)); + return (p1.y() == p2.y()) ? (p1.x() < p2.x()) : (p1.y() < p2.y()); +} + +bool isListView(QObject* item) +{ + return item->inherits("QQuickListView"); +} + +bool isOnTheScene(QObject* object) +{ + QQuickItem* item = qobject_cast(object); + if (!item) { + qWarning() << "Couldn't recognize object as item"; + return false; + } + + if (!item->isVisible()) { + qInfo() << "The item is not visible: " << item; + return false; + } + + QRectF itemRect{}; // TODO: ListView couln't get into list because it's children's rect is too large + // if (isListView(item)) { + // itemRect = QRectF(item->x(), item->y(), item->width(), item->height()); + // } else { + 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; + return true; +} + +bool isEnabled(QObject* obj) +{ + const auto item = qobject_cast(obj); + return item && item->isEnabled(); +} + +QQuickItem* getPageOfItem(QQuickItem* item) // TODO: remove? +{ + if(!item) { + qWarning() << "item is null"; + return {}; + } + const auto pagePattern = QString::fromLatin1("Page"); + QString className{item->metaObject()->className()}; + qDebug() << "=====================>> Item: " << item << " with name: " << item->metaObject()->className(); + const auto isPage = className.contains(pagePattern, Qt::CaseSensitive); + if(isPage) { + return item; + } else { + return getPageOfItem(item->parentItem()); + } +} + +QList getSubChain(QObject* item) +{ + QList res; + if (!item) { + qDebug() << "null top item"; + return res; + } + const auto children = item->children(); + for(const auto child : children) { + if (child + && isFocusable(child) + && (isOnTheScene(child)) + && isEnabled(child) + ) { + res.append(child); + // qDebug() << "==>> [*** added ***] " << qobject_cast(child); + } else { + // qDebug() << "==>> [** skipped **] " << qobject_cast(child); + res.append(getSubChain(child)); + } + } + return res; +} + +template +void printItems(const T& items, QObject* current_item) +{ + qDebug() << "**********************************************"; + for(const auto& item : items) { + QQuickItem* i = qobject_cast(item); + QPointF coords {getItemCenterPointOnScene(i)}; + QString prefix = current_item == i ? "==>" : " "; + qDebug() << prefix << " Item: " << i << " with coords: " << coords; + } + qDebug() << "**********************************************"; +} + +/*! + * \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 +{ +public: + explicit ListViewFocusController(QQuickItem* listView, QObject* parent = nullptr); + ~ListViewFocusController(); + + void incrementIndex(); + void decrementCurrentIndex(); + void positionViewAtIndex(); + void focusNextItem(); + void focusPreviousItem(); + void resetFocusChain(); + bool isListViewLastFocusItem(); + bool isDelegateLastFocusItem(); + +private: + int size() const; + int currentIndex() const; + QQuickItem* itemAtIndex(const int index); + QQuickItem* currentDelegate(); + QQuickItem* focusedItem(); + + QQuickItem* m_listView; + QList m_focusChain; + QQuickItem* m_focusedItem; + qsizetype m_focusedItemIndex; + qsizetype m_delegateIndex; +}; + +ListViewFocusController::ListViewFocusController(QQuickItem* listView, QObject* parent) + : QObject{parent} + , m_listView{listView} + , m_focusChain{} + , m_focusedItem{nullptr} + , m_focusedItemIndex{-1} + , m_delegateIndex{0} +{ +} + +ListViewFocusController::~ListViewFocusController() +{ + +} + +void ListViewFocusController::positionViewAtIndex() +{ + QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", + Q_ARG(int, m_delegateIndex), // Index + Q_ARG(int, 2)); // PositionMode (0 = Visible) +} + +int ListViewFocusController::size() const +{ + return m_listView->property("count").toInt(); +} + +int ListViewFocusController::currentIndex() const +{ + return m_delegateIndex; +} + +void ListViewFocusController::incrementIndex() +{ + m_delegateIndex++; +} + +void ListViewFocusController::decrementCurrentIndex() +{ + m_delegateIndex--; +} + +QQuickItem* ListViewFocusController::itemAtIndex(const int index) +{ + QQuickItem* item{nullptr}; + + QMetaObject::invokeMethod(m_listView, "itemAtIndex", + Q_RETURN_ARG(QQuickItem*, item), + Q_ARG(int, index)); + + return item; +} + +QQuickItem* ListViewFocusController::currentDelegate() +{ + return itemAtIndex(m_delegateIndex); +} + +QQuickItem* ListViewFocusController::focusedItem() +{ + return m_focusedItem; +} + +void ListViewFocusController::focusNextItem() +{ + if (m_focusChain.empty()) { + qWarning() << "Empty focusChain with current delegate: " << currentDelegate(); + m_focusChain = getSubChain(currentDelegate()); + } + m_focusedItemIndex++; + m_focusedItem = qobject_cast(m_focusChain.at(m_focusedItemIndex)); + m_focusedItem->forceActiveFocus(); +} + +void ListViewFocusController::focusPreviousItem() +{ + // TODO: implement +} + +void ListViewFocusController::resetFocusChain() +{ + m_focusChain.clear(); + m_focusedItem = nullptr; + m_focusedItemIndex = -1; +} + +bool ListViewFocusController::isDelegateLastFocusItem() +{ + return m_focusedItem && (m_focusedItem == m_focusChain.last()); +} + +bool ListViewFocusController::isListViewLastFocusItem() +{ + return (m_delegateIndex == size() - 1) && isDelegateLastFocusItem(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +FocusController::FocusController(QQmlApplicationEngine* engine, QObject *parent) + : QObject{parent} + , m_engine{engine} + , m_focusChain{} + , m_focusedItem{nullptr} + , m_focusedItemIndex{-1} + , m_rootItem{nullptr} + , m_lvfc{nullptr} +{ + connect(this, &FocusController::rootItemChanged, this, &FocusController::reload); +} + +void FocusController::resetFocus() +{ + reload(); + if (m_focusChain.empty()) { + qWarning() << "There is no focusable elements"; + return; + } + if(m_focusedItemIndex == -1) { + m_focusedItemIndex = 0; + m_focusedItem = qobject_cast(m_focusChain.at(m_focusedItemIndex)); + m_focusedItem->forceActiveFocus(); + } +} + +void FocusController::nextKeyTabItem() +{ + if (m_lvfc) { + focusNextListViewItem(); // Need to go on first element by default? + return; + } + + reload(); + + if(m_focusChain.empty()) { + qWarning() << "There are no items to navigate"; + return; + } + + if (m_focusedItemIndex == (m_focusChain.size() - 1)) { + qDebug() << "Last focus index. Making it zero"; + m_focusedItemIndex = 0; + } else { + qDebug() << "Incrementing focus index"; + m_focusedItemIndex++; + } + + m_focusedItem = qobject_cast(m_focusChain.at(m_focusedItemIndex)); + + if(m_focusedItem == nullptr) { + qWarning() << "Failed to get item to focus on"; + return; + } + + if(isListView(m_focusedItem)) { + qDebug() << "===>> Found ListView Item: " << m_focusedItem; // TODO: remove? + m_lvfc = new ListViewFocusController(m_focusedItem, this); + focusNextListViewItem(); + return; + } + + m_focusedItem->forceActiveFocus(Qt::TabFocusReason); + + printItems(m_focusChain, m_focusedItem); +} + +void FocusController::focusNextListViewItem() +{ + m_lvfc->focusNextItem(); + + if (m_lvfc->isListViewLastFocusItem()) { + delete m_lvfc; + m_lvfc = nullptr; + } else if (m_lvfc->isDelegateLastFocusItem()) { + m_lvfc->resetFocusChain(); + m_lvfc->incrementIndex(); + m_lvfc->positionViewAtIndex(); + } +} + +void FocusController::focusPreviousListViewItem() +{ + // TODO: implement +} + +void FocusController::previousKeyTabItem() +{ + reload(); + + if(m_focusChain.empty()) { + return; + } + + if (m_focusedItemIndex <= 0) { + m_focusedItemIndex = m_focusChain.size() - 1; + } else { + m_focusedItemIndex--; + } + + m_focusedItem = qobject_cast(m_focusChain.at(m_focusedItemIndex)); + m_focusedItem->forceActiveFocus(Qt::TabFocusReason); + + qDebug() << "--> Current focus was changed to " << m_focusedItem; +} + +void FocusController::nextKeyUpItem() +{ + qDebug() << "nextKeyUpItem" << "triggered"; +} + +void FocusController::nextKeyDownItem() +{ + qDebug() << "nextKeyDownItem" << "triggered"; +} + +void FocusController::nextKeyLeftItem() +{ + qDebug() << "nextKeyLeftItem" << "triggered"; +} + +void FocusController::nextKeyRightItem() +{ + qDebug() << "nextKeyRightItem" << "triggered"; +} + +void FocusController::reload() +{ + m_focusChain.clear(); + + QObjectList rootObjects; + + const auto rootItem = m_rootItem; + + if (rootItem != nullptr) { + qDebug() << "*** root item: " << rootItem; + rootObjects << qobject_cast(rootItem); + } else { + qDebug() << "*** root item is null"; + rootObjects = m_engine->rootObjects(); + } + + if(rootObjects.empty()) { + qWarning() << "Empty focus chain detected!"; + emit focusChainChanged(); + return; + } + + for(const auto object : rootObjects) { + m_focusChain.append(getSubChain(object)); + } + + std::sort(m_focusChain.begin(), m_focusChain.end(), isLess); + + printItems(m_focusChain, m_focusedItem); + + emit focusChainChanged(); + + if (m_focusChain.empty()) { + m_focusedItemIndex = -1; + qWarning() << "reloaded to empty focus chain"; + return; + } + + QQuickWindow* window = qobject_cast(rootObjects[0]); + if (!window) { + window = qobject_cast(rootObjects[0])->window(); + } + + if (!window) { + qCritical() << "Couldn't get the current window"; + return; + } + + // qDebug() << "==> Active Focused Item: " << window->activeFocusItem(); + // qDebug() << "--> Active Focused Object: " << window->focusObject(); + // qDebug() << ">>> Current Focused Item: " << m_focused_item; + + m_focusedItemIndex = m_focusChain.indexOf(window->activeFocusItem()); + + if(m_focusedItemIndex == -1) { + qDebug() << "===>> No focus item in chain. Moving focus to begin..."; + // m_focused_item_index = 0; // if not in focus chain current + return; + } + + m_focusedItem = qobject_cast(m_focusChain.at(m_focusedItemIndex)); + + m_focusedItem->forceActiveFocus(); +} + +void FocusController::setRootItem(QQuickItem* item) +{ + m_rootItem = item; +} diff --git a/client/ui/controllers/focusController.h b/client/ui/controllers/focusController.h new file mode 100644 index 00000000..f593fc8d --- /dev/null +++ b/client/ui/controllers/focusController.h @@ -0,0 +1,52 @@ +#ifndef FOCUSCONTROLLER_H +#define FOCUSCONTROLLER_H + +#include + +class QQuickItem; +class QQmlApplicationEngine; +class ListViewFocusController; + +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(); + +signals: + void nextTabItemChanged(QObject* item); + void previousTabItemChanged(QObject* item); + void nextKeyUpItemChanged(QObject* item); + void nextKeyDownItemChanged(QObject* item); + void nextKeyLeftItemChanged(QObject* item); + void nextKeyRightItemChanged(QObject* item); + void focusChainChanged(); + void rootItemChanged(); + +public slots: + void resetFocus(); + void reload(); + void setRootItem(QQuickItem* item); + +private: + void focusNextListViewItem(); + void focusPreviousListViewItem(); + + QQmlApplicationEngine* m_engine; // Pointer to engine to get root object + QList m_focusChain; // List of current objects to be focused + QQuickItem* m_focusedItem; // Pointer to the active focus item + qsizetype m_focusedItemIndex; // Active focus item's index in focus chain + QQuickItem* m_rootItem; + + ListViewFocusController* m_lvfc; // ListView focus manager +}; + +#endif // FOCUSCONTROLLER_H diff --git a/client/ui/controllers/pageController.cpp b/client/ui/controllers/pageController.cpp index bbcc55a1..d515df49 100644 --- a/client/ui/controllers/pageController.cpp +++ b/client/ui/controllers/pageController.cpp @@ -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); diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h index f89d39a1..ffbdd3a1 100644 --- a/client/ui/controllers/pageController.h +++ b/client/ui/controllers/pageController.h @@ -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 m_serversModel; diff --git a/client/ui/qml/Components/ConnectButton.qml b/client/ui/qml/Components/ConnectButton.qml index fa18703b..c3032eab 100644 --- a/client/ui/qml/Components/ConnectButton.qml +++ b/client/ui/qml/Components/ConnectButton.qml @@ -16,6 +16,16 @@ 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() + } + implicitWidth: 190 implicitHeight: 190 diff --git a/client/ui/qml/Components/ConnectionTypeSelectionDrawer.qml b/client/ui/qml/Components/ConnectionTypeSelectionDrawer.qml index 23fe0d2a..1b43a628 100644 --- a/client/ui/qml/Components/ConnectionTypeSelectionDrawer.qml +++ b/client/ui/qml/Components/ConnectionTypeSelectionDrawer.qml @@ -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 @@ -61,8 +48,6 @@ DrawerType2 { PageController.goToPage(PageEnum.PageSetupWizardCredentials) root.close() } - - KeyNavigation.tab: qrCode.rightButton } DividerType {} @@ -78,8 +63,6 @@ DrawerType2 { PageController.goToPage(PageEnum.PageSetupWizardConfigSource) root.close() } - - KeyNavigation.tab: focusItem } DividerType {} diff --git a/client/ui/qml/Components/HomeContainersListView.qml b/client/ui/qml/Components/HomeContainersListView.qml index b0e074d0..9c3d3857 100644 --- a/client/ui/qml/Components/HomeContainersListView.qml +++ b/client/ui/qml/Components/HomeContainersListView.qml @@ -20,52 +20,71 @@ ListView { 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() - } - } + console.debug("--> Tab is pressed on HomeContainersListView: ", objectName) + FocusController.nextKeyTabItem() } - onVisibleChanged: { - if (visible) { - currentFocusIndex = 0 - focusItem.forceActiveFocus() - } - } - - Item { - id: focusItem + Keys.onBacktabPressed: { + console.debug("--> Shift+Tab is pressed on HomeContainersListView: ", objectName) + FocusController.previousKeyTabItem() } - onCurrentFocusIndexChanged: { - if (parentFlickable) { - parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex)) - } - } + // 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 +94,6 @@ ListView { implicitWidth: rootWidth implicitHeight: content.implicitHeight - onActiveFocusChanged: { - if (activeFocus) { - containerRadioButton.forceActiveFocus() - } - } - ColumnLayout { id: content @@ -111,13 +124,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() } } diff --git a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml index 405d4eda..b37b0b81 100644 --- a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml +++ b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml @@ -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,7 +46,7 @@ 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 + // KeyNavigation.tab: siteBasedSplitTunnelingSwitch.visible ? siteBasedSplitTunnelingSwitch.rightButton : focusItem clickedFunction: function() { // PageController.goToPage(PageEnum.PageSettingsSplitTunneling) @@ -80,13 +67,13 @@ DrawerType2 { descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") rightImageSource: "qrc:/images/controls/chevron-right.svg" - KeyNavigation.tab: appSplitTunnelingSwitch.visible ? - appSplitTunnelingSwitch.rightButton : - focusItem + // KeyNavigation.tab: appSplitTunnelingSwitch.visible ? + // appSplitTunnelingSwitch.rightButton : + // focusItem clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsSplitTunneling) - root.close() + root.closeTriggered() } } @@ -103,11 +90,11 @@ DrawerType2 { descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") rightImageSource: "qrc:/images/controls/chevron-right.svg" - KeyNavigation.tab: focusItem + // KeyNavigation.tab: focusItem clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) - root.close() + root.closeTriggered() } } diff --git a/client/ui/qml/Components/InstalledAppsDrawer.qml b/client/ui/qml/Components/InstalledAppsDrawer.qml index e5d10055..0ee48100 100644 --- a/client/ui/qml/Components/InstalledAppsDrawer.qml +++ b/client/ui/qml/Components/InstalledAppsDrawer.qml @@ -26,7 +26,7 @@ DrawerType2 { id: installedAppsModel } - expandedContent: Item { + expandedStateContent: Item { id: container implicitHeight: expandedHeight diff --git a/client/ui/qml/Components/QuestionDrawer.qml b/client/ui/qml/Components/QuestionDrawer.qml index a0e86dbc..09e8638a 100644 --- a/client/ui/qml/Components/QuestionDrawer.qml +++ b/client/ui/qml/Components/QuestionDrawer.qml @@ -20,7 +20,7 @@ DrawerType2 { property var yesButtonFunction property var noButtonFunction - expandedContent: ColumnLayout { + expandedStateContent: ColumnLayout { id: content anchors.top: parent.top @@ -37,7 +37,11 @@ DrawerType2 { target: root enabled: !GC.isMobile() function onOpened() { - focusItem.forceActiveFocus() + FocusController.setRoot(root) + } + + function onClosed() { + FocusController.setRoot(null) } } @@ -59,11 +63,6 @@ DrawerType2 { text: descriptionText } - Item { - id: focusItem - KeyNavigation.tab: yesButton - } - BasicButtonType { id: yesButton Layout.fillWidth: true @@ -78,8 +77,6 @@ DrawerType2 { yesButtonFunction() } } - - KeyNavigation.tab: noButton } BasicButtonType { @@ -102,8 +99,6 @@ DrawerType2 { noButtonFunction() } } - - KeyNavigation.tab: focusItem } } } diff --git a/client/ui/qml/Components/SelectLanguageDrawer.qml b/client/ui/qml/Components/SelectLanguageDrawer.qml index 4d9d7f0e..3124445e 100644 --- a/client/ui/qml/Components/SelectLanguageDrawer.qml +++ b/client/ui/qml/Components/SelectLanguageDrawer.qml @@ -11,7 +11,7 @@ import "../Config" DrawerType2 { id: root - expandedContent: Item { + expandedStateContent: Item { id: container implicitHeight: root.height * 0.9 @@ -24,13 +24,12 @@ DrawerType2 { target: root enabled: !GC.isMobile() function onOpened() { - focusItem.forceActiveFocus() + FocusController.setRoot(root) } - } - Item { - id: focusItem - KeyNavigation.tab: backButton + function onClosed() { + FocusController.setRoot(null) + } } ColumnLayout { @@ -44,8 +43,7 @@ DrawerType2 { BackButtonType { id: backButton backButtonImage: "qrc:/images/controls/arrow-left.svg" - backButtonFunction: function() { root.close() } - KeyNavigation.tab: listView + backButtonFunction: function() { root.closeTriggered() } } } @@ -97,15 +95,15 @@ DrawerType2 { } } - Keys.onTabPressed: { - if (currentFocusIndex < this.count - 1) { - currentFocusIndex += 1 - this.itemAtIndex(currentFocusIndex).forceActiveFocus() - } else { - listViewFocusItem.forceActiveFocus() - focusItem.forceActiveFocus() - } - } + // Keys.onTabPressed: { + // if (currentFocusIndex < this.count - 1) { + // currentFocusIndex += 1 + // this.itemAtIndex(currentFocusIndex).forceActiveFocus() + // } else { + // listViewFocusItem.forceActiveFocus() + // focusItem.forceActiveFocus() + // } + // } Item { id: listViewFocusItem @@ -195,7 +193,7 @@ DrawerType2 { onClicked: { listView.currentIndex = index LanguageModel.changeLanguage(languageIndex) - root.close() + root.closeTriggered() } } } diff --git a/client/ui/qml/Components/ServersListView.qml b/client/ui/qml/Components/ServersListView.qml new file mode 100644 index 00000000..76f3f267 --- /dev/null +++ b/client/ui/qml/Components/ServersListView.qml @@ -0,0 +1,208 @@ +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 + } + + readonly property bool isFocusable: true + + // Keys.onTabPressed: { + // FocusController.nextKeyTabItem() + // } + + // activeFocusOnTab: true + // focus: true + + property int focusItemIndex: 0 + + // onFocusItemIndexChanged: { + // console.debug("===>> root onFocusItemIndexChanged") + + // // const focusedElement = root.itemAtIndex(focusItemIndex) + // // if (focusedElement) { + // // if (focusedElement.y + focusedElement.height > root.height) { + // // root.contentY = focusedElement.y + focusedElement.height - root.height + // // } else { + // // root.contentY = 0 + // // } + // // } + // } + + Keys.onUpPressed: scrollBar.decrease() + Keys.onDownPressed: scrollBar.increase() + + // Connections { + // target: drawer + // enabled: !GC.isMobile() + // function onIsCollapsedChanged() { + // if (drawer.isCollapsedStateActive) { + // const item = root.itemAtIndex(root.focusItemIndex) + // if (item) { item.serverRadioButtonProperty.focus = false } + // } + // } + // } + + 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.onTabPressed: serverInfoButton.forceActiveFocus() + Keys.onEnterPressed: serverRadioButton.clicked() + Keys.onReturnPressed: serverRadioButton.clicked() + } + + ImageButtonType { + id: serverInfoButton + objectName: "serverInfoButton" + + // signal keyTabOnLastElement + + // isFocusable: false + + image: "qrc:/images/controls/settings.svg" + imageColor: AmneziaStyle.color.paleGray + + implicitWidth: 56 + implicitHeight: 56 + + z: 1 + + // onActiveFocusChanged: { + // console.debug("===>> serverInfoButton::activeFocusChanged") + + // if (activeFocus) { + // if (currentIndex === root.count - 1) { + // console.log("---> Latest element") + // keyTabOnLastElement() + // } + + // console.log("--->>", currentIndex) + // // serverRadioButton.forceActiveFocus() + // } + // } + + // onKeyTabOnLastElement: { + // console.log("*** Signal emmited! ***") + // FocusController.nextKeyTabItem() + // } + + // Keys.onTabPressed: { + // console.log("===>> serverInfoButton::Keys.onTabPressed") + // if (root.focusItemIndex < root.count - 1) { + // root.focusItemIndex++ + // root.itemAtIndex(root.focusItemIndex).forceActiveFocus() + // } else { + // FocusController.nextKeyTabItem() + // root.contentY = 0 + // } + // } + Keys.onEnterPressed: serverInfoButton.clicked() + Keys.onReturnPressed: serverInfoButton.clicked() + + onClicked: function() { + console.debug("===>> onClicked serverInfoButton") + + ServersModel.processedIndex = index + PageController.goToPage(PageEnum.PageSettingsServerInfo) + drawer.closeTriggered() + } + } + } + + DividerType { + Layout.fillWidth: true + Layout.leftMargin: 0 + Layout.rightMargin: 0 + } + } + } +} diff --git a/client/ui/qml/Components/ShareConnectionDrawer.qml b/client/ui/qml/Components/ShareConnectionDrawer.qml index d2bf28ab..261cd742 100644 --- a/client/ui/qml/Components/ShareConnectionDrawer.qml +++ b/client/ui/qml/Components/ShareConnectionDrawer.qml @@ -36,7 +36,7 @@ DrawerType2 { configFileName = "amnezia_config" } - expandedContent: Item { + expandedStateContent: Item { implicitHeight: root.expandedHeight Connections { @@ -57,8 +57,6 @@ DrawerType2 { anchors.rightMargin: 16 headerText: root.headerText - - KeyNavigation.tab: shareButton } FlickableType { @@ -86,8 +84,6 @@ DrawerType2 { text: qsTr("Share") leftImageSource: "qrc:/images/controls/share-2.svg" - KeyNavigation.tab: copyConfigTextButton - clickedFunc: function() { var fileName = "" if (GC.isMobile()) { @@ -124,8 +120,6 @@ DrawerType2 { Keys.onReturnPressed: { copyConfigTextButton.clicked() } Keys.onEnterPressed: { copyConfigTextButton.clicked() } - - KeyNavigation.tab: copyNativeConfigStringButton.visible ? copyNativeConfigStringButton : showSettingsButton } BasicButtonType { @@ -166,8 +160,6 @@ DrawerType2 { clickedFunc: function() { configContentDrawer.open() } - - KeyNavigation.tab: header } DrawerType2 { @@ -184,24 +176,11 @@ DrawerType2 { } } - 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() { @@ -232,8 +211,6 @@ DrawerType2 { anchors.topMargin: 16 backButtonFunction: function() { configContentDrawer.close() } - - KeyNavigation.tab: focusItem } FlickableType { diff --git a/client/ui/qml/Components/TransportProtoSelector.qml b/client/ui/qml/Components/TransportProtoSelector.qml index e40dd4bb..323892fa 100644 --- a/client/ui/qml/Components/TransportProtoSelector.qml +++ b/client/ui/qml/Components/TransportProtoSelector.qml @@ -39,8 +39,6 @@ Rectangle { implicitWidth: (rootWidth - 32) / 2 text: "UDP" - KeyNavigation.tab: tcpButton - onClicked: { root.currentIndex = 0 } diff --git a/client/ui/qml/Controls2/BackButtonType.qml b/client/ui/qml/Controls2/BackButtonType.qml index 86fc86a2..41aac9e7 100644 --- a/client/ui/qml/Controls2/BackButtonType.qml +++ b/client/ui/qml/Controls2/BackButtonType.qml @@ -4,23 +4,27 @@ import Qt5Compat.GraphicalEffects import Style 1.0 -Item { +FocusScope { id: root property string backButtonImage: "qrc:/images/controls/arrow-left.svg" property var backButtonFunction + // property bool isFocusable: true + + // Keys.onTabPressed: { + // FocusController.nextKeyTabItem() + // } + + // Keys.onBacktabPressed: { + // FocusController.previousKeyTabItem() + // } + implicitWidth: content.implicitWidth implicitHeight: content.implicitHeight visible: backButtonImage !== "" - onActiveFocusChanged: { - if (activeFocus) { - backButton.forceActiveFocus() - } - } - RowLayout { id: content @@ -35,6 +39,8 @@ Item { implicitWidth: 40 implicitHeight: 40 + // focus: true + onClicked: { if (backButtonFunction && typeof backButtonFunction === "function") { backButtonFunction() diff --git a/client/ui/qml/Controls2/BasicButtonType.qml b/client/ui/qml/Controls2/BasicButtonType.qml index 828c32bc..e925035b 100644 --- a/client/ui/qml/Controls2/BasicButtonType.qml +++ b/client/ui/qml/Controls2/BasicButtonType.qml @@ -35,12 +35,25 @@ Button { property alias buttonTextLabel: buttonText + property bool isFocusable: true + + Keys.onTabPressed: { + console.debug("--> Tab is pressed on BasicButtonType: ", objectName) + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + console.debug("--> Shift+Tab is pressed on ", objectName) + FocusController.previousKeyTabItem() + } + implicitHeight: 56 hoverEnabled: true focusPolicy: Qt.TabFocus onFocusChanged: { + console.debug("===>> BUTTON: active.focus: ", root.activeFocus, " parentFlickable: ", root.parentFlickable ) if (root.activeFocus) { if (root.parentFlickable) { root.parentFlickable.ensureVisible(this) diff --git a/client/ui/qml/Controls2/CardWithIconsType.qml b/client/ui/qml/Controls2/CardWithIconsType.qml index fea65116..f5d2bea2 100644 --- a/client/ui/qml/Controls2/CardWithIconsType.qml +++ b/client/ui/qml/Controls2/CardWithIconsType.qml @@ -25,10 +25,13 @@ Button { property real textOpacity: 1.0 + property alias focusItem: rightImage + hoverEnabled: true background: Rectangle { id: backgroundRect + anchors.fill: parent radius: 16 @@ -44,8 +47,10 @@ Button { anchors.right: parent.right implicitHeight: content.implicitHeight + RowLayout { id: content + anchors.fill: parent Image { @@ -61,6 +66,7 @@ Button { } ColumnLayout { + ListItemTitleType { text: root.headerText visible: text !== "" @@ -123,6 +129,7 @@ Button { Rectangle { id: rightImageBackground + anchors.fill: parent radius: 12 color: "transparent" @@ -131,10 +138,9 @@ Button { PropertyAnimation { duration: 200 } } } + onClicked: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } + root.clicked() } } } diff --git a/client/ui/qml/Controls2/DrawerType2.qml b/client/ui/qml/Controls2/DrawerType2.qml index c4b584c1..df07c52f 100644 --- a/client/ui/qml/Controls2/DrawerType2.qml +++ b/client/ui/qml/Controls2/DrawerType2.qml @@ -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,43 @@ 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() { + console.debug("===>> onCloseTopDrawer function") + if (depthIndex === PageController.getDrawerDepth()) { - if (isCollapsed) { + if (isCollapsedStateActive()) { return } aboutToHide() - drawerContent.state = root.drawerCollapsed + drawerContent.state = root.drawerCollapsedStateName depthIndex = 0 closed() } @@ -61,30 +75,62 @@ Item { Connections { target: root - function onClose() { - if (isCollapsed) { + function onCloseTriggered() { + console.debug("***>> onClose root connection") + + if (isCollapsedStateActive()) { return } aboutToHide() - drawerContent.state = root.drawerCollapsed - depthIndex = 0 - PageController.setDrawerDepth(PageController.getDrawerDepth() - 1) closed() } - function onOpen() { - if (isExpanded) { + function onClosed() { + console.debug("***>> onClosed root connection") + + drawerContent.state = root.drawerCollapsedStateName + + if (root.isCollapsedStateActive()) { + var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor() + if (initialPageNavigationBarColor !== 0xFF1C1D21) { + PageController.updateNavigationBarColor(initialPageNavigationBarColor) + } + } + + depthIndex = 0 + PageController.decrementDrawerDepth() + FocusController.setRootItem(null) + } + + function onOpenTriggered() { + console.debug("===>> onOpen root connection") + + 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 + + console.debug("===>> onOpened root connection") + + if (isExpandedStateActive()) { + console.error("new state - extended") + if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) { + PageController.updateNavigationBarColor(0xFF1C1D21) + } + } + + depthIndex = PageController.incrementDrawerDepth() + FocusController.setRootItem(root) + console.debug("===>> Root item has changed to ", root) } } @@ -102,18 +148,18 @@ Item { MouseArea { id: emptyArea anchors.fill: parent - enabled: root.isExpanded - visible: enabled + onClicked: { - root.close() + console.debug("===>> onClicked emptyArea") + 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 +171,46 @@ 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() + console.debug("===>> onReleased dragArea") + + 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() + console.debug("===>> onEntered dragArea") + + root.cursorEntered() } onExited: { - root.exited() + console.debug("===>> onExited dragArea") + + root.cursorExited() } onPressedChanged: { + console.debug("===>> onPressedChanged dragArea") + root.pressed(pressed, entered) } onClicked: { - if (root.isCollapsed) { - root.open() + console.debug("===>> onClicked dragArea") + + if (isCollapsedStateActive()) { + root.openTriggered() } } } Rectangle { id: drawerContentBackground + objectName: "drawerContentBackground" anchors { left: drawerContent.left; right: drawerContent.right; top: drawerContent.top } height: root.height @@ -174,53 +231,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 +312,8 @@ Item { } }, Transition { - from: root.drawerExpanded - to: root.drawerCollapsed + from: root.drawerExpandedStateName + to: root.drawerCollapsedStateName PropertyAnimation { target: drawerContent properties: "y" @@ -241,7 +325,7 @@ Item { Loader { id: collapsedLoader - sourceComponent: root.collapsedContent + sourceComponent: root.collapsedStateContent anchors.right: parent.right anchors.left: parent.left @@ -250,8 +334,7 @@ Item { Loader { id: expandedLoader - visible: root.isExpanded - sourceComponent: root.expandedContent + sourceComponent: root.expandedStateContent anchors.right: parent.right anchors.left: parent.left diff --git a/client/ui/qml/Controls2/DropDownType.qml b/client/ui/qml/Controls2/DropDownType.qml index 906cfffe..8b683d94 100644 --- a/client/ui/qml/Controls2/DropDownType.qml +++ b/client/ui/qml/Controls2/DropDownType.qml @@ -45,33 +45,51 @@ 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) - } - } - } + // function popupClosedFunc() { + // if (!GC.isMobile()) { + // this.forceActiveFocus() + // } + // } + + // property var parentFlickable + // onFocusChanged: { + // if (root.activeFocus) { + // if (root.parentFlickable) { + // root.parentFlickable.ensureVisible(root) + // } + // } + // } 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 { @@ -153,6 +171,8 @@ Item { } ImageButtonType { + // isFocusable: false + Layout.rightMargin: 16 implicitWidth: 40 @@ -173,7 +193,7 @@ Item { if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") { rootButtonClickedFunction() } else { - menu.open() + menu.openTriggered() } } } @@ -186,27 +206,14 @@ Item { anchors.fill: parent expandedHeight: drawerParent.height * drawerHeight - onClosed: { - root.popupClosedFunc() - } + // 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 +225,43 @@ Item { BackButtonType { id: backButton backButtonImage: root.headerBackButtonImage - backButtonFunction: function() { menu.close() } - KeyNavigation.tab: listViewLoader.item + backButtonFunction: function() { menu.closeTriggered() } + // 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 - Column { - id: col - anchors.top: parent.top + spacing: 16 + + Header2Type { anchors.left: parent.left anchors.right: parent.right + anchors.leftMargin: 16 + anchors.rightMargin: 16 - spacing: 16 + headerText: root.headerText - Header2Type { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 + width: parent.width + } - headerText: root.headerText + Loader { + id: listViewLoader + sourceComponent: root.listView - width: parent.width - } - - Loader { - id: listViewLoader - sourceComponent: root.listView - - onLoaded: { - listViewLoader.item.parentFlickable = flickable - listViewLoader.item.lastItemTabClicked = function() { - focusItem.forceActiveFocus() - } - } + onLoaded: { + // listViewLoader.item.parentFlickable = flickable + // FocusController.reload() + // listViewLoader.item.lastItemTabClicked = function() { + // focusItem.forceActiveFocus() + // } } } } } } - - Keys.onEnterPressed: { - if (menu.isClosed) { - menu.open() - } - } - - Keys.onReturnPressed: { - if (menu.isClosed) { - menu.open() - } - } } diff --git a/client/ui/qml/Controls2/FlickableType.qml b/client/ui/qml/Controls2/FlickableType.qml index bcd14487..db857ea9 100644 --- a/client/ui/qml/Controls2/FlickableType.qml +++ b/client/ui/qml/Controls2/FlickableType.qml @@ -7,7 +7,7 @@ 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 } diff --git a/client/ui/qml/Controls2/HorizontalRadioButton.qml b/client/ui/qml/Controls2/HorizontalRadioButton.qml index 1ac1cd30..b87d9b84 100644 --- a/client/ui/qml/Controls2/HorizontalRadioButton.qml +++ b/client/ui/qml/Controls2/HorizontalRadioButton.qml @@ -27,6 +27,18 @@ RadioButton { implicitWidth: content.implicitWidth implicitHeight: content.implicitHeight + property bool isFocusable: true + + Keys.onTabPressed: { + console.debug("--> Tab is pressed on BasicButtonType: ", objectName) + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + console.debug("--> Shift+Tab is pressed on ", objectName) + FocusController.previousKeyTabItem() + } + indicator: Rectangle { anchors.fill: parent radius: 16 diff --git a/client/ui/qml/Controls2/ImageButtonType.qml b/client/ui/qml/Controls2/ImageButtonType.qml index fffb6d84..8770f454 100644 --- a/client/ui/qml/Controls2/ImageButtonType.qml +++ b/client/ui/qml/Controls2/ImageButtonType.qml @@ -24,22 +24,23 @@ 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.onEnterPressed: root.clicked() + Keys.onReturnPressed: root.clicked() + Behavior on icon.color { PropertyAnimation { duration: 200 } } diff --git a/client/ui/qml/Controls2/LabelWithButtonType.qml b/client/ui/qml/Controls2/LabelWithButtonType.qml index 41faf108..5e05c30e 100644 --- a/client/ui/qml/Controls2/LabelWithButtonType.qml +++ b/client/ui/qml/Controls2/LabelWithButtonType.qml @@ -41,27 +41,37 @@ 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() + } + implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } + // onFocusChanged: { + // if (root.activeFocus) { + // if (root.parentFlickable) { + // root.parentFlickable.ensureVisible(root) + // } + // } + // } - Connections { - target: rightImage - function onFocusChanged() { - if (rightImage.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - } + // Connections { + // target: rightImage + // function onFocusChanged() { + // if (rightImage.activeFocus) { + // if (root.parentFlickable) { + // root.parentFlickable.ensureVisible(root) + // } + // } + // } + // } MouseArea { anchors.fill: parent diff --git a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml index f7b777a7..ed5fa6d9 100644 --- a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml +++ b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml @@ -33,40 +33,14 @@ ListView { 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() - } - } - - onVisibleChanged: { - if (visible) { - focusItem.forceActiveFocus() - } - } - - onCurrentFocusIndexChanged: { - if (parentFlickable) { - parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex)) - } + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() } ButtonGroup { @@ -83,12 +57,6 @@ ListView { implicitWidth: rootWidth implicitHeight: content.implicitHeight - onActiveFocusChanged: { - if (activeFocus) { - radioButton.forceActiveFocus() - } - } - ColumnLayout { id: content diff --git a/client/ui/qml/Controls2/PageType.qml b/client/ui/qml/Controls2/PageType.qml index 0a2a2998..abe7c8d6 100644 --- a/client/ui/qml/Controls2/PageType.qml +++ b/client/ui/qml/Controls2/PageType.qml @@ -9,30 +9,12 @@ 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 @@ -49,11 +31,10 @@ Item { // Set a timer to set focus after a short delay Timer { id: timer - interval: 100 // Milliseconds + interval: 1000 // Milliseconds // TODO: return to 500 onTriggered: { - if (defaultActiveFocusItem) { - defaultActiveFocusItem.forceActiveFocus() - } + console.debug("===>> Page creation completed") + FocusController.resetFocus() } repeat: false // Stop the timer after one trigger running: !GC.isMobile() // Start the timer diff --git a/client/ui/qml/Controls2/PopupType.qml b/client/ui/qml/Controls2/PopupType.qml index 7a6a770e..e5019fe5 100644 --- a/client/ui/qml/Controls2/PopupType.qml +++ b/client/ui/qml/Controls2/PopupType.qml @@ -28,11 +28,11 @@ Popup { } onOpened: { - focusItem.forceActiveFocus() + FocusController.setRoot(root) } onClosed: { - PageController.forceStackActiveFocus() + FocusController.setRoot(null) } background: Rectangle { @@ -72,11 +72,6 @@ Popup { } } - Item { - id: focusItem - KeyNavigation.tab: closeButton - } - BasicButtonType { id: closeButton visible: closeButtonVisible @@ -92,7 +87,6 @@ Popup { borderWidth: 0 text: qsTr("Close") - KeyNavigation.tab: focusItem clickedFunc: function() { root.close() diff --git a/client/ui/qml/Controls2/SwitcherType.qml b/client/ui/qml/Controls2/SwitcherType.qml index 43c35778..b96f40e4 100644 --- a/client/ui/qml/Controls2/SwitcherType.qml +++ b/client/ui/qml/Controls2/SwitcherType.qml @@ -35,6 +35,16 @@ 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() + } + hoverEnabled: enabled ? true : false focusPolicy: Qt.TabFocus diff --git a/client/ui/qml/Controls2/TabButtonType.qml b/client/ui/qml/Controls2/TabButtonType.qml index d57ff3a0..d3dc0d1b 100644 --- a/client/ui/qml/Controls2/TabButtonType.qml +++ b/client/ui/qml/Controls2/TabButtonType.qml @@ -17,10 +17,19 @@ TabButton { property bool isSelected: false + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + implicitHeight: 48 hoverEnabled: true - focusPolicy: Qt.TabFocus background: Rectangle { id: background diff --git a/client/ui/qml/Controls2/TabImageButtonType.qml b/client/ui/qml/Controls2/TabImageButtonType.qml index abe544aa..3e0b5aed 100644 --- a/client/ui/qml/Controls2/TabImageButtonType.qml +++ b/client/ui/qml/Controls2/TabImageButtonType.qml @@ -14,13 +14,23 @@ TabButton { property bool isSelected: false + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 property var clickedFunc hoverEnabled: true - focusPolicy: Qt.TabFocus + // focusPolicy: Qt.TabFocus icon.source: image icon.color: isSelected ? selectedColor : defaultColor @@ -41,8 +51,9 @@ TabButton { cursorShape: Qt.PointingHandCursor enabled: false } - + Keys.onEnterPressed: { + console.log("$$$$$$$$$ ENTER PRESSED INSIDE TABIMAGEBUTTONTYPE") if (root.clickedFunc && typeof root.clickedFunc === "function") { root.clickedFunc() } diff --git a/client/ui/qml/Controls2/TextAreaWithFooterType.qml b/client/ui/qml/Controls2/TextAreaWithFooterType.qml index 102929e2..cf7b9146 100644 --- a/client/ui/qml/Controls2/TextAreaWithFooterType.qml +++ b/client/ui/qml/Controls2/TextAreaWithFooterType.qml @@ -78,9 +78,6 @@ Rectangle { placeholderText: root.placeholderText text: root.text - - KeyNavigation.tab: firstButton - onCursorVisibleChanged: { if (textArea.cursorVisible) { fl.interactive = true diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml index 365faa94..875eed9f 100644 --- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml +++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml @@ -84,7 +84,16 @@ Item { TextField { id: textField - activeFocusOnTab: false + // 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 +218,9 @@ Item { clickedFunc() } - if (KeyNavigation.tab) { - KeyNavigation.tab.forceActiveFocus(); - } + // if (KeyNavigation.tab) { + // KeyNavigation.tab.forceActiveFocus(); + // } } Keys.onReturnPressed: { @@ -219,8 +228,8 @@ Item { clickedFunc() } - if (KeyNavigation.tab) { - KeyNavigation.tab.forceActiveFocus(); - } + // if (KeyNavigation.tab) { + // KeyNavigation.tab.forceActiveFocus(); + // } } } diff --git a/client/ui/qml/Controls2/VerticalRadioButton.qml b/client/ui/qml/Controls2/VerticalRadioButton.qml index 1a781f20..4320103b 100644 --- a/client/ui/qml/Controls2/VerticalRadioButton.qml +++ b/client/ui/qml/Controls2/VerticalRadioButton.qml @@ -28,8 +28,14 @@ RadioButton { property string imageSource property bool showImage + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + hoverEnabled: true - focusPolicy: Qt.TabFocus + // focusPolicy: Qt.TabFocus indicator: Rectangle { id: background diff --git a/client/ui/qml/Pages2/PageDevMenu.qml b/client/ui/qml/Pages2/PageDevMenu.qml index 5da40eff..7f3ff1f0 100644 --- a/client/ui/qml/Pages2/PageDevMenu.qml +++ b/client/ui/qml/Pages2/PageDevMenu.qml @@ -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 { diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml index 8422a10f..aa2f0501 100644 --- a/client/ui/qml/Pages2/PageHome.qml +++ b/client/ui/qml/Pages2/PageHome.qml @@ -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,47 @@ PageType { Keys.onEnterPressed: splitTunnelingButton.clicked() Keys.onReturnPressed: splitTunnelingButton.clicked() - KeyNavigation.tab: drawer - onClicked: { - homeSplitTunnelingDrawer.open() + homeSplitTunnelingDrawer.openTriggered() } HomeSplitTunnelingDrawer { id: homeSplitTunnelingDrawer + objectName: "homeSplitTunnelingDrawer" + parent: root onClosed: { - if (!GC.isMobile()) { - focusItem.forceActiveFocus() - } + console.log(objectName, " was closed...") + FocusController.setRootItem(null) } } } } } - 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 +173,8 @@ PageType { } RowLayout { + objectName: "rowLayout" + Layout.topMargin: 14 Layout.leftMargin: 24 Layout.rightMargin: 24 @@ -188,9 +183,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 +195,8 @@ PageType { } } - function onExited() { - if (drawer.isCollapsed) { + function onCursorExited() { + if (drawer.isCollapsedStateActive) { collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor collapsedButtonHeader.opacity = 1 } else { @@ -208,7 +205,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 +216,8 @@ PageType { Header1TextType { id: collapsedButtonHeader + objectName: "collapsedButtonHeader" + Layout.maximumWidth: drawer.width - 48 - 18 - 12 maximumLineCount: 2 @@ -227,8 +226,6 @@ PageType { text: ServersModel.defaultServerName horizontalAlignment: Qt.AlignHCenter - KeyNavigation.tab: tabBar - Behavior on opacity { PropertyAnimation { duration: 200 } } @@ -236,10 +233,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 +252,19 @@ PageType { Keys.onEnterPressed: collapsedButtonChevron.clicked() Keys.onReturnPressed: collapsedButtonChevron.clicked() - Keys.onTabPressed: lastItemTabClicked() - onClicked: { - if (drawer.isCollapsed) { - drawer.open() + console.debug("onClicked collapsedButtonChevron") + if (drawer.isCollapsedStateActive()) { + drawer.openTriggered() + FocusController.setRootItem(drawer) } } } } RowLayout { + objectName: "rowLayoutLabel" Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.topMargin: 8 Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16 @@ -316,6 +315,7 @@ PageType { ColumnLayout { id: serversMenuHeader + objectName: "serversMenuHeader" anchors.top: collapsed.bottom anchors.right: parent.right @@ -327,13 +327,9 @@ PageType { visible: !ServersModel.isDefaultServerFromApi - Item { - id: focusItem1 - KeyNavigation.tab: containersDropDown - } - DropDownType { id: containersDropDown + objectName: "containersDropDown" rootButtonImageColor: AmneziaStyle.color.midnightBlack rootButtonBackgroundColor: AmneziaStyle.color.paleGray @@ -350,22 +346,23 @@ PageType { 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 + + // isFocusable: false // TODO: this is a workaround. Need to remove it Connections { + objectName: "rowLayoutConnections" + target: ServersModel function onDefaultServerIndexChanged() { @@ -407,169 +404,12 @@ PageType { ButtonGroup { id: serversRadioButtonGroup + objectName: "serversRadioButtonGroup" } - ListView { + ServersListView { id: 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() - - 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 - } - } - } + objectName: "serversMenuContent" } } } diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index 27ea66f9..d03b3580 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -17,18 +17,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,7 +28,6 @@ PageType { BackButtonType { id: backButton - KeyNavigation.tab: listview.currentItem.portTextField.textField } } @@ -114,8 +101,26 @@ PageType { } checkEmptyText: true + } - KeyNavigation.tab: junkPacketCountTextField.textField + 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 { @@ -139,8 +144,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: junkPacketMinSizeTextField.textField } TextFieldWithHeaderType { @@ -160,8 +163,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: junkPacketMaxSizeTextField.textField } TextFieldWithHeaderType { @@ -181,8 +182,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: initPacketJunkSizeTextField.textField } TextFieldWithHeaderType { @@ -202,8 +201,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: responsePacketJunkSizeTextField.textField } TextFieldWithHeaderType { @@ -223,8 +220,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: initPacketMagicHeaderTextField.textField } TextFieldWithHeaderType { @@ -244,8 +239,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: responsePacketMagicHeaderTextField.textField } TextFieldWithHeaderType { @@ -265,8 +258,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: transportPacketMagicHeaderTextField.textField } TextFieldWithHeaderType { @@ -286,8 +277,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: underloadPacketMagicHeaderTextField.textField } TextFieldWithHeaderType { @@ -307,8 +296,6 @@ PageType { } checkEmptyText: true - - KeyNavigation.tab: saveRestartButton } BasicButtonType { @@ -332,8 +319,6 @@ PageType { text: qsTr("Save") - Keys.onTabPressed: lastItemTabClicked(focusItem) - clickedFunc: function() { forceActiveFocus() diff --git a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml index 5089a764..29df03ef 100644 --- a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml @@ -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 diff --git a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml index 30540a93..75fdd18d 100644 --- a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml @@ -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 @@ -252,8 +227,6 @@ PageType { drawerParent: root parentFlickable: fl - KeyNavigation.tab: tlsAuthCheckBox - listView: ListViewWithRadioButtonType { id: cipherListView @@ -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 diff --git a/client/ui/qml/Pages2/PageProtocolRaw.qml b/client/ui/qml/Pages2/PageProtocolRaw.qml index 24853afd..3cb02435 100644 --- a/client/ui/qml/Pages2/PageProtocolRaw.qml +++ b/client/ui/qml/Pages2/PageProtocolRaw.qml @@ -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 { @@ -104,8 +96,6 @@ PageType { configContentDrawer.open() } - KeyNavigation.tab: removeButton - MouseArea { anchors.fill: button cursorShape: Qt.PointingHandCursor @@ -129,7 +119,7 @@ PageType { parent: root anchors.fill: parent - expandedContent: Item { + expandedStateContent: Item { implicitHeight: configContentDrawer.expandedHeight Connections { @@ -140,11 +130,6 @@ PageType { } } - Item { - id: focusItem1 - KeyNavigation.tab: backButton1 - } - BackButtonType { id: backButton1 @@ -156,8 +141,6 @@ PageType { backButtonFunction: function() { configContentDrawer.close() } - - KeyNavigation.tab: focusItem1 } FlickableType { diff --git a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml index 4d3b2c4e..dae96b5a 100644 --- a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml @@ -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 diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index b5d08132..ab50f444 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -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 diff --git a/client/ui/qml/Pages2/PageProtocolXraySettings.qml b/client/ui/qml/Pages2/PageProtocolXraySettings.qml index 20ee1da6..d74aabad 100644 --- a/client/ui/qml/Pages2/PageProtocolXraySettings.qml +++ b/client/ui/qml/Pages2/PageProtocolXraySettings.qml @@ -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 diff --git a/client/ui/qml/Pages2/PageServiceDnsSettings.qml b/client/ui/qml/Pages2/PageServiceDnsSettings.qml index bb3cbf96..c50f9a9b 100644 --- a/client/ui/qml/Pages2/PageServiceDnsSettings.qml +++ b/client/ui/qml/Pages2/PageServiceDnsSettings.qml @@ -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 } } diff --git a/client/ui/qml/Pages2/PageServiceSftpSettings.qml b/client/ui/qml/Pages2/PageServiceSftpSettings.qml index 9bdbf2db..8513f111 100644 --- a/client/ui/qml/Pages2/PageServiceSftpSettings.qml +++ b/client/ui/qml/Pages2/PageServiceSftpSettings.qml @@ -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,7 +173,7 @@ PageType { descriptionOnTop: true parentFlickable: fl - eyeButton.KeyNavigation.tab: passwordLabel.rightButton + rightButton.Keys.onTabPressed: { if (mountButton.visible) { mountButton.forceActiveFocus() @@ -225,7 +214,6 @@ PageType { borderWidth: 1 parentFlickable: fl - KeyNavigation.tab: detailedInstructionsButton text: qsTr("Mount folder on device") diff --git a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml index 9d21963d..cadfee09 100644 --- a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml +++ b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml @@ -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 @@ -206,7 +193,7 @@ PageType { } } - expandedContent: ColumnLayout { + expandedStateContent: ColumnLayout { property string tempPort: port property string tempUsername: username property string tempPassword: password @@ -239,11 +226,6 @@ PageType { } } - Item { - id: drawerFocusItem - KeyNavigation.tab: portTextField.textField - } - HeaderType { Layout.fillWidth: true @@ -268,8 +250,6 @@ PageType { port = textFieldText } } - - KeyNavigation.tab: usernameTextField.textField } TextFieldWithHeaderType { @@ -290,8 +270,6 @@ PageType { username = textFieldText } } - - KeyNavigation.tab: passwordTextField.textField } TextFieldWithHeaderType { @@ -322,8 +300,6 @@ PageType { password = textFieldText } } - - KeyNavigation.tab: saveButton } BasicButtonType { diff --git a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml index 946a77bb..a1e41f29 100644 --- a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml +++ b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml @@ -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 } } diff --git a/client/ui/qml/Pages2/PageSettings.qml b/client/ui/qml/Pages2/PageSettings.qml index bb5ca766..6e291ff0 100644 --- a/client/ui/qml/Pages2/PageSettings.qml +++ b/client/ui/qml/Pages2/PageSettings.qml @@ -14,9 +14,7 @@ import "../Config" PageType { id: root - defaultActiveFocusItem: header - - FlickableType { + FlickableType { // TODO: refactor either replace with ListView or Repeater id: fl anchors.top: parent.top anchors.bottom: parent.bottom @@ -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,9 @@ 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) + // isLeftImageHoverEnabled: false clickedFunction: function() { PageController.closeApplication() diff --git a/client/ui/qml/Pages2/PageSettingsAbout.qml b/client/ui/qml/Pages2/PageSettingsAbout.qml index cde9ee20..5407e75e 100644 --- a/client/ui/qml/Pages2/PageSettingsAbout.qml +++ b/client/ui/qml/Pages2/PageSettingsAbout.qml @@ -14,18 +14,16 @@ import "../Components" PageType { id: root - defaultActiveFocusItem: focusItem + // Item { + // id: focusItem + // KeyNavigation.tab: backButton - Item { - id: focusItem - KeyNavigation.tab: backButton - - onFocusChanged: { - if (focusItem.activeFocus) { - fl.contentY = 0 - } - } - } + // onFocusChanged: { + // if (focusItem.activeFocus) { + // fl.contentY = 0 + // } + // } + // } BackButtonType { id: backButton @@ -34,8 +32,6 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 - - KeyNavigation.tab: telegramButton } FlickableType { @@ -106,7 +102,6 @@ PageType { descriptionText: qsTr("To discuss features") leftImageSource: "qrc:/images/controls/telegram.svg" - KeyNavigation.tab: mailButton parentFlickable: fl clickedFunction: function() { @@ -124,7 +119,6 @@ PageType { descriptionText: qsTr("For reviews and bug reports") leftImageSource: "qrc:/images/controls/mail.svg" - KeyNavigation.tab: githubButton parentFlickable: fl clickedFunction: function() { @@ -143,7 +137,6 @@ PageType { text: qsTr("GitHub") leftImageSource: "qrc:/images/controls/github.svg" - KeyNavigation.tab: websiteButton parentFlickable: fl clickedFunction: function() { @@ -161,7 +154,6 @@ PageType { text: qsTr("Website") leftImageSource: "qrc:/images/controls/amnezia.svg" - KeyNavigation.tab: checkUpdatesButton parentFlickable: fl clickedFunction: function() { @@ -209,7 +201,6 @@ PageType { text: qsTr("Check for updates") - KeyNavigation.tab: privacyPolicyButton parentFlickable: fl clickedFunc: function() { diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index 2d6c1d9b..73fdc551 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -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 diff --git a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml index 2e8bda2f..4751aa71 100644 --- a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml @@ -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 diff --git a/client/ui/qml/Pages2/PageSettingsApplication.qml b/client/ui/qml/Pages2/PageSettingsApplication.qml index 0f85ac30..dfccabcf 100644 --- a/client/ui/qml/Pages2/PageSettingsApplication.qml +++ b/client/ui/qml/Pages2/PageSettingsApplication.qml @@ -14,18 +14,15 @@ import "../Components" PageType { id: root - defaultActiveFocusItem: focusItem + // Item { + // id: focusItem - Item { - id: focusItem - KeyNavigation.tab: backButton - - onFocusChanged: { - if (focusItem.activeFocus) { - fl.contentY = 0 - } - } - } + // onFocusChanged: { + // if (focusItem.activeFocus) { + // fl.contentY = 0 + // } + // } + // } BackButtonType { id: backButton @@ -35,7 +32,7 @@ PageType { anchors.right: parent.right anchors.topMargin: 20 - KeyNavigation.tab: GC.isMobile() ? switcher : switcherAutoStart + // KeyNavigation.tab: GC.isMobile() ? switcher : switcherAutoStart } FlickableType { @@ -77,8 +74,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 +92,7 @@ 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 + // KeyNavigation.tab: labelWithButtonLanguage.rightButton parentFlickable: fl clickedFunction: function() { @@ -117,7 +114,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 +138,6 @@ PageType { text: qsTr("Auto connect") descriptionText: qsTr("Connect to VPN on app start") - KeyNavigation.tab: switcherStartMinimized parentFlickable: fl checked: SettingsController.isAutoConnectEnabled() @@ -167,7 +162,6 @@ PageType { text: qsTr("Start minimized") descriptionText: qsTr("Launch application minimized") - KeyNavigation.tab: labelWithButtonLanguage.rightButton parentFlickable: fl checked: SettingsController.isStartMinimizedEnabled() @@ -190,11 +184,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 +201,6 @@ PageType { descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled") rightImageSource: "qrc:/images/controls/chevron-right.svg" - KeyNavigation.tab: labelWithButtonReset.rightButton parentFlickable: fl clickedFunction: function() { @@ -245,12 +237,12 @@ PageType { } if (!GC.isMobile()) { - root.defaultActiveFocusItem.forceActiveFocus() + // root.defaultActiveFocusItem.forceActiveFocus() } } var noButtonFunction = function() { if (!GC.isMobile()) { - root.defaultActiveFocusItem.forceActiveFocus() + // root.defaultActiveFocusItem.forceActiveFocus() } } @@ -268,10 +260,10 @@ PageType { width: root.width height: root.height - onClosed: { - if (!GC.isMobile()) { - focusItem.forceActiveFocus() - } - } + // onClosed: { + // if (!GC.isMobile()) { + // focusItem.forceActiveFocus() + // } + // } } } diff --git a/client/ui/qml/Pages2/PageSettingsBackup.qml b/client/ui/qml/Pages2/PageSettingsBackup.qml index abede9b3..35d45589 100644 --- a/client/ui/qml/Pages2/PageSettingsBackup.qml +++ b/client/ui/qml/Pages2/PageSettingsBackup.qml @@ -17,7 +17,7 @@ import "../Controls2/TextTypes" PageType { id: root - defaultActiveFocusItem: focusItem + // defaultActiveFocusItem: focusItem Connections { target: SettingsController @@ -36,11 +36,6 @@ PageType { } } - Item { - id: focusItem - KeyNavigation.tab: backButton - } - BackButtonType { id: backButton @@ -48,8 +43,6 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 - - KeyNavigation.tab: makeBackupButton } FlickableType { @@ -111,8 +104,6 @@ PageType { PageController.showNotificationMessage(qsTr("Backup file saved")) } } - - KeyNavigation.tab: restoreBackupButton } BasicButtonType { diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index 31b1c764..5991b713 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -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 {} @@ -84,8 +73,6 @@ PageType { clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsDns) } - - KeyNavigation.tab: splitTunnelingButton.rightButton } DividerType {} diff --git a/client/ui/qml/Pages2/PageSettingsDns.qml b/client/ui/qml/Pages2/PageSettingsDns.qml index 1d7517d9..cede6c74 100644 --- a/client/ui/qml/Pages2/PageSettingsDns.qml +++ b/client/ui/qml/Pages2/PageSettingsDns.qml @@ -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 { diff --git a/client/ui/qml/Pages2/PageSettingsLogging.qml b/client/ui/qml/Pages2/PageSettingsLogging.qml index 9abfc453..bea366a6 100644 --- a/client/ui/qml/Pages2/PageSettingsLogging.qml +++ b/client/ui/qml/Pages2/PageSettingsLogging.qml @@ -16,13 +16,6 @@ import "../Controls2/TextTypes" PageType { id: root - 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: switcher } FlickableType { @@ -68,12 +59,21 @@ PageType { text: qsTr("Enable logs") checked: SettingsController.isLoggingEnabled - //KeyNavigation.tab: openFolderButton + onCheckedChanged: { if (checked !== SettingsController.isLoggingEnabled) { SettingsController.isLoggingEnabled = checked } } + + onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (activeFocus) { + if (fl) { + fl.ensureVisible(this) + } + } + } } DividerType {} @@ -87,8 +87,6 @@ PageType { leftImageSource: "qrc:/images/controls/trash.svg" isSmallLeftImage: true - // KeyNavigation.tab: labelWithButton3 - clickedFunction: function() { var headerText = qsTr("Clear logs?") var yesButtonText = qsTr("Continue") @@ -104,9 +102,9 @@ PageType { } } var noButtonFunction = function() { - if (!GC.isMobile()) { - focusItem.forceActiveFocus() - } + // if (!GC.isMobile()) { + // focusItem.forceActiveFocus() + // } } showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) @@ -142,8 +140,6 @@ PageType { leftImageSource: "qrc:/images/controls/folder-open.svg" isSmallLeftImage: true - // KeyNavigation.tab: labelWithButton3 - clickedFunction: function() { SettingsController.openLogsFolder() } @@ -161,7 +157,14 @@ PageType { leftImageSource: "qrc:/images/controls/save.svg" isSmallLeftImage: true - // KeyNavigation.tab: labelWithButton3 + onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (activeFocus) { + if (fl) { + fl.ensureVisible(this) + } + } + } clickedFunction: function() { var fileName = "" @@ -221,7 +224,14 @@ PageType { leftImageSource: "qrc:/images/controls/folder-open.svg" isSmallLeftImage: true - // KeyNavigation.tab: labelWithButton3 + onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (activeFocus) { + if (fl) { + fl.ensureVisible(this) + } + } + } clickedFunction: function() { SettingsController.openServiceLogsFolder() @@ -245,7 +255,14 @@ PageType { leftImageSource: "qrc:/images/controls/save.svg" isSmallLeftImage: true - // KeyNavigation.tab: labelWithButton3 + onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (activeFocus) { + if (fl) { + fl.ensureVisible(this) + } + } + } clickedFunction: function() { var fileName = "" diff --git a/client/ui/qml/Pages2/PageSettingsServerData.qml b/client/ui/qml/Pages2/PageSettingsServerData.qml index e170a351..0568c5f4 100644 --- a/client/ui/qml/Pages2/PageSettingsServerData.qml +++ b/client/ui/qml/Pages2/PageSettingsServerData.qml @@ -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?") diff --git a/client/ui/qml/Pages2/PageSettingsServerInfo.qml b/client/ui/qml/Pages2/PageSettingsServerInfo.qml index 95ae5c8a..4f6ab934 100644 --- a/client/ui/qml/Pages2/PageSettingsServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsServerInfo.qml @@ -25,7 +25,7 @@ PageType { property int pageSettingsApiServerInfo: 3 property int pageSettingsApiLanguageList: 4 - defaultActiveFocusItem: focusItem + // defaultActiveFocusItem: focusItem Connections { target: PageController @@ -46,11 +46,6 @@ PageType { ] } - Item { - id: focusItem - KeyNavigation.tab: header - } - ColumnLayout { anchors.fill: parent @@ -75,7 +70,6 @@ PageType { BackButtonType { id: backButton - KeyNavigation.tab: headerContent.actionButton backButtonFunction: function() { if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo && @@ -108,13 +102,11 @@ PageType { } } - KeyNavigation.tab: tabBar - actionButtonFunction: function() { if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) { nestedStackView.currentIndex = root.pageSettingsApiServerInfo } else { - serverNameEditDrawer.open() + serverNameEditDrawer.openTriggered() } } } @@ -133,7 +125,7 @@ PageType { } } - expandedContent: ColumnLayout { + expandedStateContent: ColumnLayout { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right @@ -149,11 +141,6 @@ PageType { } } - Item { - id: focusItem1 - KeyNavigation.tab: serverName.textField - } - TextFieldWithHeaderType { id: serverName @@ -162,8 +149,6 @@ PageType { textFieldText: name textField.maximumLength: 30 checkEmptyText: true - - KeyNavigation.tab: saveButton } BasicButtonType { @@ -172,7 +157,6 @@ PageType { Layout.fillWidth: true text: qsTr("Save") - KeyNavigation.tab: focusItem1 clickedFunc: function() { if (serverName.textFieldText === "") { @@ -182,7 +166,7 @@ PageType { if (serverName.textFieldText !== name) { name = serverName.textFieldText } - serverNameEditDrawer.close() + serverNameEditDrawer.closeTriggered() } } } @@ -219,7 +203,6 @@ PageType { isSelected: tabBar.currentIndex === root.pageSettingsServerProtocols text: qsTr("Protocols") - KeyNavigation.tab: servicesTab Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerProtocols Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerProtocols } @@ -231,7 +214,6 @@ PageType { isSelected: tabBar.currentIndex === root.pageSettingsServerServices text: qsTr("Services") - KeyNavigation.tab: dataTab Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerServices Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerServices } diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml index dcdf01af..73e1e2c6 100644 --- a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml +++ b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml @@ -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 { @@ -168,7 +160,6 @@ PageType { Layout.fillWidth: true visible: root.isClearCacheVisible - KeyNavigation.tab: removeButton text: qsTr("Clear profile") diff --git a/client/ui/qml/Pages2/PageSettingsServersList.qml b/client/ui/qml/Pages2/PageSettingsServersList.qml index 102dd46f..6f43c3fe 100644 --- a/client/ui/qml/Pages2/PageSettingsServersList.qml +++ b/client/ui/qml/Pages2/PageSettingsServersList.qml @@ -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,88 @@ 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 + 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() + // } - activeFocusOnTab: true - focus: true - Keys.onTabPressed: { - if (currentIndex < servers.count - 1) { - servers.incrementCurrentIndex() - } else { - servers.currentIndex = 0 - focusItem.forceActiveFocus() - root.lastItemTabClicked() - } + // fl.ensureVisible(this.currentItem) + // } - fl.ensureVisible(this.currentItem) - } + onVisibleChanged: { + if (visible) { + currentIndex = 0 + } + } - onVisibleChanged: { - if (visible) { - currentIndex = 0 - } - } + delegate: Item { + implicitWidth: servers.width + implicitHeight: delegateContent.implicitHeight - delegate: Item { - implicitWidth: servers.width - implicitHeight: delegateContent.implicitHeight + // onFocusChanged: { + // if (focus) { + // server.rightButton.forceActiveFocus() + // } + // } - onFocusChanged: { - if (focus) { - server.rightButton.forceActiveFocus() - } - } + ColumnLayout { + id: delegateContent - ColumnLayout { - id: delegateContent + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + LabelWithButtonType { + id: server + Layout.fillWidth: true - 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) - } + text: name + // parentFlickable: fl + 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 {} } } } diff --git a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml index f5fe285a..4bd4d0a4 100644 --- a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml @@ -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 } } @@ -180,11 +170,11 @@ PageType { } } - KeyNavigation.tab: { - return sites.count > 0 ? - sites : - searchField.textField - } + // KeyNavigation.tab: { + // return sites.count > 0 ? + // sites : + // searchField.textField + // } } } @@ -325,7 +315,7 @@ PageType { textFieldPlaceholderText: qsTr("website or IP") buttonImageSource: "qrc:/images/controls/plus.svg" - KeyNavigation.tab: GC.isMobile() ? focusItem : addSiteButtonImage + // KeyNavigation.tab: GC.isMobile() ? focusItem : addSiteButtonImage clickedFunc: function() { PageController.showBusyIndicator(true) @@ -344,7 +334,7 @@ PageType { imageColor: AmneziaStyle.color.paleGray onClicked: function () { - moreActionsDrawer.open() + moreActionsDrawer.openTriggered() } Keys.onReturnPressed: addSiteButtonImage.clicked() @@ -361,12 +351,12 @@ PageType { expandedHeight: parent.height * 0.4375 onClosed: { - if (root.defaultActiveFocusItem && !GC.isMobile()) { - root.defaultActiveFocusItem.forceActiveFocus() - } + // if (root.defaultActiveFocusItem && !GC.isMobile()) { + // root.defaultActiveFocusItem.forceActiveFocus() + // } } - expandedContent: ColumnLayout { + expandedStateContent: ColumnLayout { id: moreActionsDrawerContent anchors.top: parent.top @@ -387,11 +377,6 @@ PageType { } } - Item { - id: focusItem1 - KeyNavigation.tab: importSitesButton.rightButton - } - Header2Type { Layout.fillWidth: true Layout.margins: 16 @@ -407,10 +392,8 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" clickedFunction: function() { - importSitesDrawer.open() + importSitesDrawer.openTriggered() } - - KeyNavigation.tab: exportSitesButton } DividerType {} @@ -420,8 +403,6 @@ PageType { Layout.fillWidth: true text: qsTr("Save site list") - KeyNavigation.tab: focusItem1 - clickedFunction: function() { var fileName = "" if (GC.isMobile()) { @@ -436,7 +417,7 @@ PageType { if (fileName !== "") { PageController.showBusyIndicator(true) SitesController.exportSites(fileName) - moreActionsDrawer.close() + moreActionsDrawer.closeTriggered() PageController.showBusyIndicator(false) } } @@ -458,7 +439,7 @@ PageType { } } - expandedContent: Item { + expandedStateContent: Item { implicitHeight: importSitesDrawer.expandedHeight Connections { @@ -469,11 +450,6 @@ PageType { } } - Item { - id: focusItem2 - KeyNavigation.tab: importSitesDrawerBackButton - } - BackButtonType { id: importSitesDrawerBackButton @@ -482,10 +458,8 @@ PageType { anchors.right: parent.right anchors.topMargin: 16 - KeyNavigation.tab: importSitesButton2 - backButtonFunction: function() { - importSitesDrawer.close() + importSitesDrawer.closeTriggered() } } @@ -516,7 +490,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 +506,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 +520,8 @@ PageType { PageController.showBusyIndicator(true) SitesController.importSites(fileName, replaceExistingSites) PageController.showBusyIndicator(false) - importSitesDrawer.close() - moreActionsDrawer.close() + importSitesDrawer.closeTriggered() + moreActionsDrawer.closeTriggered() } DividerType {} diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml index 75fd3d47..9e541ded 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml @@ -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 { diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml index 85a50393..82e2e7e1 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml @@ -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 { diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 7c031997..e5030336 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -25,7 +25,7 @@ PageType { } } - defaultActiveFocusItem: focusItem + // defaultActiveFocusItem: focusItem FlickableType { id: fl @@ -42,15 +42,11 @@ PageType { spacing: 0 - Item { - id: focusItem - KeyNavigation.tab: textKey.textField - } - - 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 +56,16 @@ PageType { actionButtonImage: isVisible ? "qrc:/images/controls/more-vertical.svg" : "" actionButtonFunction: function() { - moreActionsDrawer.open() + moreActionsDrawer.openTriggered() + } + + actionButton.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (actionButton.activeFocus) { + if (fl) { + fl.ensureVisible(moreButton) + } + } } DrawerType2 { @@ -71,7 +76,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 @@ -154,8 +159,6 @@ PageType { textField.text = "" textField.paste() } - - KeyNavigation.tab: continueButton } BasicButtonType { @@ -166,10 +169,18 @@ PageType { Layout.rightMargin: 16 Layout.leftMargin: 16 + onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (activeFocus) { + if (fl) { + fl.ensureVisible(this) + } + } + } + visible: textKey.textFieldText !== "" text: qsTr("Continue") - Keys.onTabPressed: lastItemTabClicked(focusItem) clickedFunc: function() { if (ImportController.extractConfigFromData(textKey.textFieldText)) { @@ -203,6 +214,15 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" leftImageSource: "qrc:/images/controls/amnezia.svg" + focusItem.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (focusItem.activeFocus) { + if (fl) { + fl.ensureVisible(apiInstalling) + } + } + } + onClicked: function() { PageController.showBusyIndicator(true) var result = InstallController.fillAvailableServices() @@ -227,6 +247,15 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" leftImageSource: "qrc:/images/controls/server.svg" + focusItem.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (focusItem.activeFocus) { + if (fl) { + fl.ensureVisible(manualInstalling) + } + } + } + onClicked: { PageController.goToPage(PageEnum.PageSetupWizardCredentials) } @@ -247,6 +276,15 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" leftImageSource: "qrc:/images/controls/archive-restore.svg" + focusItem.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (focusItem.activeFocus) { + if (fl) { + fl.ensureVisible(backupRestore) + } + } + } + onClicked: { var filePath = SystemController.getFileName(qsTr("Open backup file"), qsTr("Backup files (*.backup)")) @@ -271,6 +309,13 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" leftImageSource: "qrc:/images/controls/folder-search-2.svg" + focusItem.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (fl) { + fl.ensureVisible(openFile) + } + } + onClicked: { var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" : "Config files (*.vpn *.ovpn *.conf *.json)" @@ -298,6 +343,15 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" leftImageSource: "qrc:/images/controls/scan-line.svg" + focusItem.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (focusItem.activeFocus) { + if (fl) { + fl.ensureVisible(scanQr) + } + } + } + onClicked: { ImportController.startDecodingQr() if (Qt.platform.os === "ios") { @@ -321,6 +375,15 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" leftImageSource: "qrc:/images/controls/help-circle.svg" + focusItem.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (focusItem.activeFocus) { + if (fl) { + fl.ensureVisible(siteLink) + } + } + } + onClicked: { Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl()) } diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index aced12b1..5139ad5a 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -13,12 +13,7 @@ import "../Controls2/TextTypes" PageType { id: root - defaultActiveFocusItem: hostname.textField - - Item { - id: focusItem - KeyNavigation.tab: backButton - } + // defaultActiveFocusItem: hostname.textField BackButtonType { id: backButton @@ -27,8 +22,6 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 - - KeyNavigation.tab: hostname.textField } FlickableType { @@ -64,8 +57,6 @@ PageType { textField.onFocusChanged: { textField.text = textField.text.replace(/^\s+|\s+$/g, '') } - - KeyNavigation.tab: username.textField } TextFieldWithHeaderType { @@ -78,8 +69,6 @@ PageType { textField.onFocusChanged: { textField.text = textField.text.replace(/^\s+|\s+$/g, '') } - - KeyNavigation.tab: secretData.textField } TextFieldWithHeaderType { @@ -100,8 +89,6 @@ PageType { textField.onFocusChanged: { textField.text = textField.text.replace(/^\s+|\s+$/g, '') } - - KeyNavigation.tab: continueButton } BasicButtonType { @@ -112,8 +99,6 @@ PageType { text: qsTr("Continue") - Keys.onTabPressed: lastItemTabClicked(focusItem) - clickedFunc: function() { forceActiveFocus() if (!isCredentialsFilled()) { diff --git a/client/ui/qml/Pages2/PageSetupWizardEasy.qml b/client/ui/qml/Pages2/PageSetupWizardEasy.qml index 02a7c928..27df72b0 100644 --- a/client/ui/qml/Pages2/PageSetupWizardEasy.qml +++ b/client/ui/qml/Pages2/PageSetupWizardEasy.qml @@ -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() { diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml index 6b4c0a1c..de8275f1 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml @@ -62,19 +62,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 { @@ -113,13 +106,13 @@ PageType { parent: root onClosed: { if (!GC.isMobile()) { - defaultActiveFocusItem.forceActiveFocus() + // defaultActiveFocusItem.forceActiveFocus() } } anchors.fill: parent expandedHeight: parent.height * 0.9 - expandedContent: Item { + expandedStateContent: Item { Connections { target: showDetailsDrawer enabled: !GC.isMobile() @@ -130,15 +123,15 @@ PageType { implicitHeight: showDetailsDrawer.expandedHeight - Item { - id: focusItem2 - KeyNavigation.tab: showDetailsBackButton - onFocusChanged: { - if (focusItem2.activeFocus) { - fl.contentY = 0 - } - } - } + // Item { + // id: focusItem2 + // KeyNavigation.tab: showDetailsBackButton + // onFocusChanged: { + // if (focusItem2.activeFocus) { + // fl.contentY = 0 + // } + // } + // } BackButtonType { id: showDetailsBackButton @@ -148,8 +141,6 @@ PageType { anchors.right: parent.right anchors.topMargin: 16 - KeyNavigation.tab: showDetailsCloseButton - backButtonFunction: function() { showDetailsDrawer.close() } @@ -230,7 +221,7 @@ PageType { Layout.fillWidth: true rootWidth: root.width - KeyNavigation.tab: (port.visible && port.enabled) ? port.textField : installButton + // 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 { @@ -289,10 +278,10 @@ PageType { transportProtoSelector.visible = protocolSelectorVisible transportProtoHeader.visible = protocolSelectorVisible - if (port.visible && port.enabled) - defaultActiveFocusItem = port.textField - else - defaultActiveFocusItem = focusItem + // if (port.visible && port.enabled) + // defaultActiveFocusItem = port.textField + // else + // defaultActiveFocusItem = focusItem } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml index 48265f66..15c1170f 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml @@ -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 } } diff --git a/client/ui/qml/Pages2/PageSetupWizardStart.qml b/client/ui/qml/Pages2/PageSetupWizardStart.qml index b12c7830..2d6790ba 100644 --- a/client/ui/qml/Pages2/PageSetupWizardStart.qml +++ b/client/ui/qml/Pages2/PageSetupWizardStart.qml @@ -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) } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml index c4227df1..86880713 100644 --- a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml +++ b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml @@ -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 } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml index 92048f36..dffaa8c6 100644 --- a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml +++ b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml @@ -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,6 @@ PageType { textColor: AmneziaStyle.color.goldenApricot text: showContent ? qsTr("Collapse content") : qsTr("Show content") - KeyNavigation.tab: connectButton clickedFunc: function() { showContent = !showContent diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 995fa3e7..cef516df 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -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. 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,18 @@ PageType { actionButtonImage: "qrc:/images/controls/more-vertical.svg" actionButtonFunction: function() { - shareFullAccessDrawer.open() + shareFullAccessDrawer.openTriggered() } - KeyNavigation.tab: connectionRadioButton + // KeyNavigation.tab: connectionRadioButton + actionButton.onFocusChanged: { + console.debug("MOVE THIS LOGIC TO CPP!") + if (actionButton.activeFocus) { + if (fl) { + fl.ensureVisible(moreButton) + } + } + } DrawerType2 { id: shareFullAccessDrawer @@ -205,11 +201,11 @@ PageType { expandedHeight: root.height onClosed: { if (!GC.isMobile()) { - clientNameTextField.textField.forceActiveFocus() + // clientNameTextField.textField.forceActiveFocus() } } - expandedContent: ColumnLayout { + expandedStateContent: ColumnLayout { id: shareFullAccessDrawerContent anchors.top: parent.top anchors.left: parent.left @@ -226,7 +222,7 @@ PageType { target: shareFullAccessDrawer enabled: !GC.isMobile() function onOpened() { - focusItem.forceActiveFocus() + // focusItem.forceActiveFocus() } } @@ -240,10 +236,10 @@ 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 - } + // Item { + // id: focusItem + // // KeyNavigation.tab: shareFullAccessButton.rightButton + // } LabelWithButtonType { id: shareFullAccessButton @@ -251,11 +247,11 @@ PageType { text: qsTr("Share") rightImageSource: "qrc:/images/controls/chevron-right.svg" - KeyNavigation.tab: focusItem + // KeyNavigation.tab: focusItem clickedFunction: function() { PageController.goToPage(PageEnum.PageShareFullAccess) - shareFullAccessDrawer.close() + shareFullAccessDrawer.closeTriggered() } } @@ -288,12 +284,12 @@ PageType { implicitWidth: (root.width - 32) / 2 text: qsTr("Connection") - KeyNavigation.tab: usersRadioButton + // KeyNavigation.tab: usersRadioButton onClicked: { accessTypeSelector.currentIndex = 0 if (!GC.isMobile()) { - clientNameTextField.textField.forceActiveFocus() + // clientNameTextField.textField.forceActiveFocus() } } } @@ -305,7 +301,7 @@ PageType { implicitWidth: (root.width - 32) / 2 text: qsTr("Users") - KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? clientNameTextField.textField : serverSelector + // KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? clientNameTextField.textField : serverSelector onClicked: { accessTypeSelector.currentIndex = 1 @@ -313,7 +309,7 @@ PageType { ExportController.updateClientManagementModel(ContainersModel.getProcessedContainerIndex(), ServersModel.getProcessedServerCredentials()) PageController.showBusyIndicator(false) - focusItem.forceActiveFocus() + // focusItem.forceActiveFocus() } } } @@ -343,7 +339,7 @@ PageType { checkEmptyText: true - KeyNavigation.tab: serverSelector + // KeyNavigation.tab: serverSelector } @@ -390,7 +386,7 @@ PageType { serverSelector.severSelectorIndexChanged() } - serverSelector.close() + serverSelector.closeTriggered() } Component.onCompleted: { @@ -409,7 +405,7 @@ PageType { } } - KeyNavigation.tab: protocolSelector + // KeyNavigation.tab: protocolSelector } DropDownType { @@ -450,7 +446,7 @@ PageType { clickedFunction: function() { handler() - protocolSelector.close() + protocolSelector.closeTriggered() } Connections { @@ -509,11 +505,11 @@ PageType { } } - KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? - exportTypeSelector : - isSearchBarVisible ? - searchTextField.textField : - usersHeader.actionButton + // KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? + // exportTypeSelector : searchTextField.textField + // isSearchBarVisible ? + // searchTextField.textField : + // usersHeader.actionButton } DropDownType { @@ -549,7 +545,7 @@ PageType { clickedFunction: function() { exportTypeSelector.text = selectedText exportTypeSelector.currentIndex = currentIndex - exportTypeSelector.close() + exportTypeSelector.closeTriggered() } Component.onCompleted: { @@ -558,7 +554,7 @@ PageType { } } - KeyNavigation.tab: shareButton + // KeyNavigation.tab: shareButton } @@ -622,11 +618,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 +634,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 +659,9 @@ PageType { Keys.onTabPressed: { if (!GC.isMobile()) { if (clientsListView.model.count > 0) { - clientsListView.forceActiveFocus() + // clientsListView.forceActiveFocus() } else { - lastItemTabClicked(focusItem) + // lastItemTabClicked(focusItem) } } } @@ -706,10 +702,10 @@ PageType { if (!GC.isMobile()) { if (currentIndex < this.count - 1) { this.incrementCurrentIndex() - currentItem.focusItem.forceActiveFocus() + // currentItem.focusItem.forceActiveFocus() } else { this.currentIndex = 0 - lastItemTabClicked(focusItem) + // lastItemTabClicked(focusItem) } } } @@ -717,7 +713,7 @@ PageType { onActiveFocusChanged: { if (focus && !GC.isMobile()) { currentIndex = 0 - currentItem.focusItem.forceActiveFocus() + // currentItem.focusItem.forceActiveFocus() } } @@ -735,7 +731,7 @@ PageType { implicitWidth: clientsListView.width implicitHeight: delegateContent.implicitHeight - property alias focusItem: clientFocusItem.rightButton + // property alias focusItem: clientFocusItem.rightButton ColumnLayout { id: delegateContent @@ -755,7 +751,7 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" clickedFunction: function() { - clientInfoDrawer.open() + clientInfoDrawer.openTriggered() } } @@ -768,15 +764,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 +781,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 +842,6 @@ PageType { text: qsTr("Allowed IPs: %1").arg(allowedIps) } - Item { - id: focusItem1 - KeyNavigation.tab: renameButton - } - BasicButtonType { id: renameButton Layout.fillWidth: true @@ -865,10 +856,10 @@ PageType { text: qsTr("Rename") - KeyNavigation.tab: revokeButton + // KeyNavigation.tab: revokeButton clickedFunc: function() { - clientNameEditDrawer.open() + clientNameEditDrawer.openTriggered() } DrawerType2 { @@ -881,11 +872,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 +888,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 @@ -914,7 +900,7 @@ PageType { textField.maximumLength: 20 checkEmptyText: true - KeyNavigation.tab: saveButton + // KeyNavigation.tab: saveButton } BasicButtonType { @@ -923,7 +909,7 @@ PageType { Layout.fillWidth: true text: qsTr("Save") - KeyNavigation.tab: focusItem2 + // KeyNavigation.tab: focusItem2 clickedFunc: function() { if (clientNameEditor.textFieldText === "") { @@ -937,7 +923,7 @@ PageType { ContainersModel.getProcessedContainerIndex(), ServersModel.getProcessedServerCredentials()) PageController.showBusyIndicator(false) - clientNameEditDrawer.close() + clientNameEditDrawer.closeTriggered() } } } @@ -958,7 +944,7 @@ PageType { borderWidth: 1 text: qsTr("Revoke") - KeyNavigation.tab: focusItem1 + // KeyNavigation.tab: focusItem1 clickedFunc: function() { var headerText = qsTr("Revoke the config for a user - %1?").arg(clientName) @@ -967,12 +953,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 +979,7 @@ PageType { anchors.fill: parent onClosed: { if (!GC.isMobile()) { - clientNameTextField.textField.forceActiveFocus() + // clientNameTextField.textField.forceActiveFocus() } } } @@ -1001,7 +987,7 @@ PageType { MouseArea { anchors.fill: parent onPressed: function(mouse) { - forceActiveFocus() + // forceActiveFocus() mouse.accepted = false } } diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 404ba563..70451b83 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -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 @@ -137,8 +128,6 @@ PageType { text: qsTr("Share") leftImageSource: "qrc:/images/controls/share-2.svg" - Keys.onTabPressed: lastItemTabClicked(focusItem) - clickedFunc: function() { PageController.showBusyIndicator(true) @@ -166,10 +155,5 @@ PageType { id: shareConnectionDrawer anchors.fill: parent - onClosed: { - if (!GC.isMobile()) { - focusItem.forceActiveFocus() - } - } } } diff --git a/client/ui/qml/Pages2/PageStart.qml b/client/ui/qml/Pages2/PageStart.qml index 640c61ef..9f37458c 100644 --- a/client/ui/qml/Pages2/PageStart.qml +++ b/client/ui/qml/Pages2/PageStart.qml @@ -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() { @@ -91,18 +91,20 @@ PageType { } } - function onForceTabBarActiveFocus() { - homeTabButton.focus = true - tabBar.forceActiveFocus() - } + // function onForceTabBarActiveFocus() { + // homeTabButton.focus = true + // tabBar.forceActiveFocus() + // } - function onForceStackActiveFocus() { - homeTabButton.focus = true - tabBarStackView.forceActiveFocus() - } + // function onForceStackActiveFocus() { + // homeTabButton.focus = true + // tabBarStackView.forceActiveFocus() + // } } Connections { + objectName: "installControllerConnections" + target: InstallController function onInstallationErrorOccurred(error) { @@ -165,6 +167,8 @@ PageType { } Connections { + objectName: "connectionControllerConnections" + target: ConnectionController function onReconnectWithUpdatedContainer(message) { @@ -182,6 +186,8 @@ PageType { } Connections { + objectName: "importControllerConnections" + target: ImportController function onImportErrorOccurred(error, goToPageHome) { @@ -196,6 +202,8 @@ PageType { } Connections { + objectName: "settingsControllerConnections" + target: SettingsController function onLoggingDisableByWatcher() { @@ -218,6 +226,7 @@ PageType { StackViewType { id: tabBarStackView + objectName: "tabBarStackView" anchors.top: parent.top anchors.right: parent.right @@ -254,6 +263,7 @@ PageType { TabBar { id: tabBar + objectName: "tabBar" anchors.right: parent.right anchors.left: parent.left @@ -269,6 +279,8 @@ PageType { enabled: !root.isControlsDisabled && !root.isTabBarDisabled background: Shape { + objectName: "backgroundShape" + width: parent.width height: parent.height @@ -289,21 +301,25 @@ PageType { TabImageButtonType { id: homeTabButton + objectName: "homeTabButton" + isSelected: tabBar.currentIndex === 0 image: "qrc:/images/controls/home.svg" clickedFunc: function () { tabBarStackView.goToTabBarPage(PageEnum.PageHome) ServersModel.processedIndex = ServersModel.defaultIndex tabBar.currentIndex = 0 + FocusController.setRootItem(null) // TODO: move to do it automaticaly } - KeyNavigation.tab: shareTabButton - Keys.onEnterPressed: this.clicked() - Keys.onReturnPressed: this.clicked() + // KeyNavigation.tab: shareTabButton + // Keys.onEnterPressed: this.clicked() + // Keys.onReturnPressed: this.clicked() } TabImageButtonType { id: shareTabButton + objectName: "shareTabButton" Connections { target: ServersModel @@ -325,11 +341,13 @@ PageType { tabBar.currentIndex = 1 } - KeyNavigation.tab: settingsTabButton + // KeyNavigation.tab: settingsTabButton } TabImageButtonType { id: settingsTabButton + objectName: "settingsTabButton" + isSelected: tabBar.currentIndex === 2 image: "qrc:/images/controls/settings-2.svg" clickedFunc: function () { @@ -337,11 +355,13 @@ PageType { tabBar.currentIndex = 2 } - KeyNavigation.tab: plusTabButton + // KeyNavigation.tab: plusTabButton } TabImageButtonType { id: plusTabButton + objectName: "plusTabButton" + isSelected: tabBar.currentIndex === 3 image: "qrc:/images/controls/plus.svg" clickedFunc: function () { @@ -349,7 +369,7 @@ PageType { tabBar.currentIndex = 3 } - Keys.onTabPressed: PageController.forceStackActiveFocus() + // Keys.onTabPressed: PageController.forceStackActiveFocus() } } } diff --git a/client/ui/qml/main2.qml b/client/ui/qml/main2.qml index fb99559f..18b69795 100644 --- a/client/ui/qml/main2.qml +++ b/client/ui/qml/main2.qml @@ -33,6 +33,8 @@ Window { title: "AmneziaVPN" Connections { + objectName: "pageControllerConnections" + target: PageController function onRaiseMainWindow() { @@ -72,6 +74,8 @@ Window { } Connections { + objectName: "settingsControllerConnections" + target: SettingsController function onChangeSettingsFinished(finishedMessage) { @@ -80,11 +84,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 +116,8 @@ Window { } Item { + objectName: "popupErrorMessageItem" + anchors.right: parent.right anchors.left: parent.left anchors.bottom: parent.bottom @@ -120,6 +130,8 @@ Window { } Item { + objectName: "privateKeyPassphraseDrawerItem" + anchors.fill: parent DrawerType2 { @@ -128,7 +140,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 @@ -168,7 +180,7 @@ Window { hidePassword = !hidePassword } - KeyNavigation.tab: saveButton + // KeyNavigation.tab: saveButton } BasicButtonType { @@ -195,6 +207,8 @@ Window { } Item { + objectName: "questionDrawerItem" + anchors.fill: parent QuestionDrawer { @@ -205,6 +219,8 @@ Window { } Item { + objectName: "busyIndicatorItem" + anchors.fill: parent BusyIndicatorType { @@ -221,26 +237,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)