From 4c6b128b822147c00286f81710a20c30e732eaa2 Mon Sep 17 00:00:00 2001 From: MrMirDan Date: Mon, 16 Feb 2026 13:35:58 +0200 Subject: [PATCH] demo-ui --- client/ui/controllers/qml/pageController.h | 2 + client/ui/qml/Pages2/PageHome.qml | 2 + .../PageSettingsXRayAvailableConfigs.qml | 165 ++++++++++++ .../qml/Pages2/PageSettingsXRayServerInfo.qml | 235 ++++++++++++++++++ .../Pages2/PageSetupWizardConfigSource.qml | 34 +++ 5 files changed, 438 insertions(+) create mode 100644 client/ui/qml/Pages2/PageSettingsXRayAvailableConfigs.qml create mode 100644 client/ui/qml/Pages2/PageSettingsXRayServerInfo.qml diff --git a/client/ui/controllers/qml/pageController.h b/client/ui/controllers/qml/pageController.h index df95fd7af..21ae1b935 100644 --- a/client/ui/controllers/qml/pageController.h +++ b/client/ui/controllers/qml/pageController.h @@ -44,6 +44,8 @@ namespace PageLoader PageSettingsApiNativeConfigs, PageSettingsApiDevices, PageSettingsApiSubscriptionKey, + PageSettingsXRayAvailableConfigs, + PageSettingsXRayServerInfo, PageSettingsKillSwitchExceptions, PageServiceSftpSettings, diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml index 25794211c..d970de454 100644 --- a/client/ui/qml/Pages2/PageHome.qml +++ b/client/ui/qml/Pages2/PageHome.qml @@ -359,6 +359,8 @@ PageType { PageController.goToPage(PageEnum.PageSettingsApiServerInfo) } + /*} else if (ServersModel.getProcessedServerData("isConfigSelectionAvailable")) { + PageController.goToPage(PageEnum.PageSettingsXRayAvailableConfigs)*/ } else { PageController.goToPage(PageEnum.PageSettingsServerInfo) } diff --git a/client/ui/qml/Pages2/PageSettingsXRayAvailableConfigs.qml b/client/ui/qml/Pages2/PageSettingsXRayAvailableConfigs.qml new file mode 100644 index 000000000..99f7867e9 --- /dev/null +++ b/client/ui/qml/Pages2/PageSettingsXRayAvailableConfigs.qml @@ -0,0 +1,165 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + property var processedServer + + Connections { + target: ServersModel + + function onProcessedServerChanged() { + root.processedServer = proxyServersModel.get(0) + } + } + + SortFilterProxyModel { + id: proxyServersModel + objectName: "proxyServersModel" + + sourceModel: ServersModel + filters: [ + ValueFilter { + roleName: "isCurrentlyProcessed" + value: true + } + ] + + Component.onCompleted: { + root.processedServer = proxyServersModel.get(0) + } + } + + ListViewType { + id: menuContent + + anchors.fill: parent + + model: XRayConfigsModel + + currentIndex: 0 + + ButtonGroup { + id: containersRadioButtonGroup + } + + header: ColumnLayout { + width: menuContent.width + + spacing: 4 + + BackButtonType { + id: backButton + objectName: "backButton" + + Layout.topMargin: 20 + SettingsController.safeAreaTopMargin + } + + HeaderTypeWithButton { + id: headerContent + objectName: "headerContent" + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 10 + + actionButtonImage: "qrc:/images/controls/settings.svg" + + headerText: root.processedServer.name + + actionButtonFunction: function() { + /* TODO: chnge server info to processed + PageController.showBusyIndicator(true) + let result = ApiSettingsController.getAccountInfo(false) + PageController.showBusyIndicator(false) + if (!result) { + return + }*/ + + PageController.goToPage(PageEnum.PageSettingsXRayServerInfo) + } + } + } + + delegate: ColumnLayout { + id: content + + width: menuContent.width + height: content.implicitHeight + + RowLayout { + VerticalRadioButton { + id: containerRadioButton + + Layout.fillWidth: true + Layout.leftMargin: 16 + // TODO: proper name and description + // e.g.: [DE] VMESS - WS + // VMES/WS/None + text: configName + + ButtonGroup.group: containersRadioButtonGroup + + imageSource: "qrc:/images/controls/download.svg" + + checked: index === XRayConfigsModel.currentIndex + checkable: !ConnectionController.isConnected + + onClicked: { + if (ConnectionController.isConnectionInProgress) { + PageController.showNotificationMessage(qsTr("Unable change config while trying to make an active connection")) + return + } + if (ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Unable change config while there is an active connection")) + return + } + + if (index !== XRayConfigsModel.currentIndex) { + PageController.showBusyIndicator(true) + var prevIndex = XRayConfigsModel.currentIndex + XRayConfigsModel.currentIndex = index + // TODO: properly realize switching between configs + if (!XRayConfigsController.updateServer(ServersModel.defaultIndex, configCode, configName)) { + XRayConfigsModel.currentIndex = prevIndex + } + PageController.showBusyIndicator(false) + } + } + + Keys.onEnterPressed: { + if (checkable) { + checked = true + } + containerRadioButton.clicked() + } + Keys.onReturnPressed: { + if (checkable) { + checked = true + } + containerRadioButton.clicked() + } + } + } + + DividerType { + Layout.fillWidth: true + } + } + } +} diff --git a/client/ui/qml/Pages2/PageSettingsXRayServerInfo.qml b/client/ui/qml/Pages2/PageSettingsXRayServerInfo.qml new file mode 100644 index 000000000..e296f61af --- /dev/null +++ b/client/ui/qml/Pages2/PageSettingsXRayServerInfo.qml @@ -0,0 +1,235 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + property list labelsModel: [ + lastUpdateObject, + sendObject, + downloadedObject + ] + + // TODO: contentKey functionality + QtObject { + id: lastUpdateObject + + readonly property string title: qsTr("Configuration Last Update") + readonly property string contentKey: "20 dec 2024 22:10" + readonly property string objectImageSource: "qrc:/images/controls/info.svg" // reload img + readonly property bool isRichText: true + } + + QtObject { + id: sendObject + + readonly property string title: qsTr("Send") + readonly property string contentKey: "48,9 MB" + readonly property string objectImageSource: "qrc:/images/controls/history.svg" // arrow-up img + readonly property bool isRichText: false + } + + QtObject { + id: downloadedObject + + readonly property string title: qsTr("Downloaded") + readonly property string contentKey: "2,78 GB" + readonly property string objectImageSource: "qrc:/images/controls/monitor.svg" // arrow-down img + readonly property bool isRichText: false + } + + property var processedServer + + Connections { + target: ServersModel + + function onProcessedServerChanged() { + root.processedServer = proxyServersModel.get(0) + } + } + + SortFilterProxyModel { + id: proxyServersModel + objectName: "proxyServersModel" + + sourceModel: ServersModel + filters: [ + ValueFilter { + roleName: "isCurrentlyProcessed" + value: true + } + ] + + Component.onCompleted: { + root.processedServer = proxyServersModel.get(0) + } + } + + ListViewType { + id: listView + + anchors.fill: parent + + model: labelsModel + + header: ColumnLayout { + width: listView.width + + spacing: 4 + + BackButtonType { + id: backButton + objectName: "backButton" + + Layout.topMargin: 20 + SettingsController.safeAreaTopMargin + } + + HeaderTypeWithButton { + id: headerContent + objectName: "headerContent" + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 10 + + actionButtonImage: "qrc:/images/controls/edit-3.svg" + + headerText: root.processedServer.name + + actionButtonFunction: function() { + serverNameEditDrawer.openTriggered() + } + } + } + + delegate: ColumnLayout { + width: listView.width + spacing: 0 +/* + Connections { + target: ApiAccountInfoModel + + function onModelReset() { + delegateItem.rightText = ApiAccountInfoModel.data(contentKey) + } + } +*/ + LabelWithImageType { + id: delegateItem + + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: objectImageSource + leftText: title + rightText: contentKey // ApiAccountInfoModel.data(contentKey) + rightTextFormat: isRichText ? Text.RichText : Text.PlainText + + visible: rightText !== "" + } + } + + footer: ColumnLayout { + id: footer + + width: listView.width + spacing: 0 + + BasicButtonType { + id: resetButton + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: 24 + Layout.bottomMargin: 16 + Layout.leftMargin: 8 + implicitHeight: 32 + + defaultColor: "transparent" + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + textColor: AmneziaStyle.color.vibrantRed + + text: qsTr("Reload config") + + clickedFunc: function() { + var headerText = qsTr("Reload config?") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot reload config during active connection")) + } else { + PageController.showBusyIndicator(true) + // TODO: server config reload function + PageController.showNotificationMessage(qsTr("Config reloaded")) + PageController.showBusyIndicator(false) + } + } + var noButtonFunction = function() { + } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } + + BasicButtonType { + id: removeButton + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: 16 + Layout.leftMargin: 8 + implicitHeight: 32 + + defaultColor: "transparent" + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + textColor: AmneziaStyle.color.vibrantRed + + text: qsTr("Remove from application") + + clickedFunc: function() { + var headerText = qsTr("Remove from application?") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot remove server during active connection")) + } else { + PageController.showBusyIndicator(true) + // TODO: server remove function + PageController.showNotificationMessage(qsTr("Server removed")) + PageController.showBusyIndicator(false) + } + } + var noButtonFunction = function() { + } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } + } + } + + RenameServerDrawer { + id: serverNameEditDrawer + + anchors.fill: parent + expandedHeight: parent.height * 0.35 + + serverNameText: root.processedServer.name + } +} diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 1f3318933..2d21e4efb 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -194,6 +194,40 @@ PageType { } } + TextFieldWithHeaderType { + id: texturl + + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Insert url") + buttonText: qsTr("Insert") + + clickedFunc: function() { + textField.text = "" + textField.paste() + } + } + + BasicButtonType { + id: urlcontinueButton + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + visible: texturl.textField.text !== "" + + text: qsTr("Continue") + + clickedFunc: function() { + ImportController.httpGet(texturl.textField.text) + } + } + ParagraphTextType { Layout.fillWidth: true Layout.topMargin: 32