rename file & update name class & update list xray

This commit is contained in:
dranik
2026-03-26 13:55:15 +03:00
parent 5734b3a55d
commit 520b3095d4
14 changed files with 223 additions and 176 deletions

View File

@@ -87,8 +87,8 @@ void CoreController::initModels()
m_xrayConfigModel = new XrayConfigModel(this);
setQmlContextProperty("XrayConfigModel", m_xrayConfigModel);
m_xrayConfigsModel = new XrayConfigsModel(m_appSettingsRepository, this);
setQmlContextProperty("XrayConfigsModel", m_xrayConfigsModel);
m_xrayConfigSnapshotsModel = new XrayConfigSnapshotsModel(m_appSettingsRepository, m_xrayConfigModel, this);
setQmlContextProperty("XrayConfigSnapshotsModel", m_xrayConfigSnapshotsModel);
m_torConfigModel = new TorConfigModel(this);
setQmlContextProperty("TorConfigModel", m_torConfigModel);

View File

@@ -64,7 +64,7 @@
#include "ui/models/protocols/openvpnConfigModel.h"
#include "ui/models/protocols/wireguardConfigModel.h"
#include "ui/models/protocols/xrayConfigModel.h"
#include "ui/models/protocols/xrayConfigsModel.h"
#include "ui/models/protocols/xrayConfigSnapshotsModel.h"
#include "ui/models/protocolsModel.h"
#include "ui/models/services/torConfigModel.h"
#include "ui/models/serversModel.h"
@@ -203,7 +203,7 @@ private:
OpenVpnConfigModel* m_openVpnConfigModel;
XrayConfigModel* m_xrayConfigModel;
XrayConfigsModel* m_xrayConfigsModel;
XrayConfigSnapshotsModel* m_xrayConfigSnapshotsModel;
TorConfigModel* m_torConfigModel;
WireGuardConfigModel* m_wireGuardConfigModel;
AwgConfigModel* m_awgConfigModel;

View File

@@ -82,7 +82,7 @@ namespace PageLoader
PageDevMenu,
PageProtocolXrayConfigsSettings,
PageProtocolXraySnapshots,
PageProtocolXrayTransportSettings,
PageProtocolXrayXmuxSettings,
PageProtocolXrayXPaddingSettings,

View File

@@ -1,4 +1,4 @@
#include "xrayConfigsModel.h"
#include "xrayConfigSnapshotsModel.h"
#include <QJsonDocument>
#include <QUuid>
@@ -26,13 +26,14 @@ XrayConfigSnapshot XrayConfigSnapshot::fromJson(const QJsonObject &json)
return s;
}
XrayConfigsModel::XrayConfigsModel(SecureAppSettingsRepository *appSettings, QObject *parent)
: QAbstractListModel(parent), m_appSettings(appSettings)
XrayConfigSnapshotsModel::XrayConfigSnapshotsModel(SecureAppSettingsRepository *appSettings,
XrayConfigModel *xrayConfigModel, QObject *parent)
: QAbstractListModel(parent), m_appSettings(appSettings), m_xrayConfigModel(xrayConfigModel)
{
loadAll();
}
void XrayConfigsModel::loadAll()
void XrayConfigSnapshotsModel::loadAll()
{
m_configs.clear();
QByteArray raw = m_appSettings->xraySavedConfigs();
@@ -46,7 +47,7 @@ void XrayConfigsModel::loadAll()
}
}
void XrayConfigsModel::persistAll()
void XrayConfigSnapshotsModel::persistAll()
{
QJsonArray arr;
for (const XrayConfigSnapshot &s : m_configs) {
@@ -55,13 +56,13 @@ void XrayConfigsModel::persistAll()
m_appSettings->setXraySavedConfigs(QJsonDocument(arr).toJson(QJsonDocument::Compact));
}
int XrayConfigsModel::rowCount(const QModelIndex &parent) const
int XrayConfigSnapshotsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_configs.size();
}
QVariant XrayConfigsModel::data(const QModelIndex &index, int role) const
QVariant XrayConfigSnapshotsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_configs.size()) {
return QVariant();
@@ -83,7 +84,7 @@ QVariant XrayConfigsModel::data(const QModelIndex &index, int role) const
return QVariant();
}
QHash<int, QByteArray> XrayConfigsModel::roleNames() const
QHash<int, QByteArray> XrayConfigSnapshotsModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[IdRole] = "configId";
@@ -92,14 +93,14 @@ QHash<int, QByteArray> XrayConfigsModel::roleNames() const
return roles;
}
void XrayConfigsModel::reload()
void XrayConfigSnapshotsModel::reload()
{
beginResetModel();
loadAll();
endResetModel();
}
void XrayConfigsModel::createFromCurrent(const amnezia::XrayServerConfig &serverConfig)
void XrayConfigSnapshotsModel::createFromCurrent(const amnezia::XrayServerConfig &serverConfig)
{
XrayConfigSnapshot snapshot;
snapshot.id = QUuid::createUuid().toString(QUuid::WithoutBraces);
@@ -114,7 +115,7 @@ void XrayConfigsModel::createFromCurrent(const amnezia::XrayServerConfig &server
persistAll();
}
amnezia::XrayServerConfig XrayConfigsModel::applyConfig(int index) const
amnezia::XrayServerConfig XrayConfigSnapshotsModel::applyConfig(int index) const
{
if (index < 0 || index >= m_configs.size()) {
return amnezia::XrayServerConfig {};
@@ -123,7 +124,7 @@ amnezia::XrayServerConfig XrayConfigsModel::applyConfig(int index) const
return m_configs.at(index).serverConfig;
}
void XrayConfigsModel::removeConfig(int index)
void XrayConfigSnapshotsModel::removeConfig(int index)
{
if (index < 0 || index >= m_configs.size()) {
return;
@@ -137,7 +138,7 @@ void XrayConfigsModel::removeConfig(int index)
emit configRemoved(index);
}
QString XrayConfigsModel::exportToJson(int index) const
QString XrayConfigSnapshotsModel::exportToJson(int index) const
{
if (index < 0 || index >= m_configs.size()) {
return {};
@@ -145,7 +146,7 @@ QString XrayConfigsModel::exportToJson(int index) const
return QString::fromUtf8(QJsonDocument(m_configs.at(index).toJson()).toJson(QJsonDocument::Indented));
}
bool XrayConfigsModel::importFromJson(const QString &jsonString)
bool XrayConfigSnapshotsModel::importFromJson(const QString &jsonString)
{
QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8());
if (!doc.isObject()) {
@@ -170,7 +171,7 @@ bool XrayConfigsModel::importFromJson(const QString &jsonString)
return true;
}
QString XrayConfigsModel::buildDisplayName(const amnezia::XrayServerConfig &cfg)
QString XrayConfigSnapshotsModel::buildDisplayName(const amnezia::XrayServerConfig &cfg)
{
// Build a human-readable name: "XHTTP TLS Reality", "RAW Reality", etc.
QString transport;
@@ -194,22 +195,22 @@ QString XrayConfigsModel::buildDisplayName(const amnezia::XrayServerConfig &cfg)
return QString("%1 %2").arg(transport, security).trimmed();
}
void XrayConfigsModel::createFromXrayModel(XrayConfigModel *model)
void XrayConfigSnapshotsModel::createFromCurrentModel()
{
if (!model) {
if (!m_xrayConfigModel) {
return;
}
createFromCurrent(model->getProtocolConfig().serverConfig);
createFromCurrent(m_xrayConfigModel->getProtocolConfig().serverConfig);
}
void XrayConfigsModel::applyConfigToXrayModel(int index, XrayConfigModel *model)
void XrayConfigSnapshotsModel::applyConfigToCurrentModel(int index)
{
if (!model) {
if (!m_xrayConfigModel) {
return;
}
amnezia::XrayServerConfig cfg = applyConfig(index);
if (cfg.port.isEmpty()) {
return; // guard against invalid index
}
model->applyServerConfig(cfg);
m_xrayConfigModel->applyServerConfig(cfg);
}

View File

@@ -24,7 +24,7 @@ struct XrayConfigSnapshot
static XrayConfigSnapshot fromJson(const QJsonObject &json);
};
class XrayConfigsModel : public QAbstractListModel
class XrayConfigSnapshotsModel : public QAbstractListModel
{
Q_OBJECT
@@ -35,7 +35,8 @@ public:
CreatedAtRole, // "dd.MM.yyyy HH:mm"
};
explicit XrayConfigsModel(SecureAppSettingsRepository *appSettings, QObject *parent = nullptr);
explicit XrayConfigSnapshotsModel(SecureAppSettingsRepository *appSettings, XrayConfigModel *xrayConfigModel,
QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
@@ -51,8 +52,8 @@ public slots:
Q_INVOKABLE bool importFromJson(const QString &jsonString);
// Convenience: create snapshot from live model, apply snapshot back to model
Q_INVOKABLE void createFromXrayModel(XrayConfigModel *model);
Q_INVOKABLE void applyConfigToXrayModel(int index, XrayConfigModel *model);
Q_INVOKABLE void createFromCurrentModel();
Q_INVOKABLE void applyConfigToCurrentModel(int index);
signals:
void configApplied(int index);
@@ -64,6 +65,7 @@ protected:
private:
SecureAppSettingsRepository *m_appSettings;
XrayConfigModel *m_xrayConfigModel;
QVector<XrayConfigSnapshot> m_configs;
void persistAll();

View File

@@ -25,7 +25,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: saveButton.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -86,20 +86,20 @@ PageType {
}
}
BasicButtonType {
id: saveButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
anchors.leftMargin: 16
anchors.rightMargin: 16
text: qsTr("Save")
onClicked: {
forceActiveFocus()
PageController.closePage()
}
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
}
// BasicButtonType {
// id: saveButton
// anchors.bottom: parent.bottom
// anchors.left: parent.left
// anchors.right: parent.right
// anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
// anchors.leftMargin: 16
// anchors.rightMargin: 16
// text: qsTr("Save")
// onClicked: {
// forceActiveFocus()
// PageController.closePage()
// }
// Keys.onEnterPressed: clicked()
// Keys.onReturnPressed: clicked()
// }
}

View File

@@ -25,7 +25,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: saveButton.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -304,20 +304,21 @@ PageType {
}
}
BasicButtonType {
id: saveButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
anchors.leftMargin: 16
anchors.rightMargin: 16
text: qsTr("Save")
onClicked: {
forceActiveFocus()
PageController.closePage()
}
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
}
// BasicButtonType {
// id: saveButton
// anchors.bottom: parent.bottom
// anchors.left: parent.left
// anchors.right: parent.right
// anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
// anchors.leftMargin: 16
// anchors.rightMargin: 16
// text: qsTr("Save")
// onClicked: {
// forceActiveFocus()
// PageController.closePage()
// }
// Keys.onEnterPressed: clicked()
// Keys.onReturnPressed: clicked()
// }
}

View File

@@ -68,7 +68,7 @@ PageType {
implicitHeight: 40
image: "qrc:/images/controls/more-vertical.svg"
imageColor: AmneziaStyle.color.mutedGray
onClicked: PageController.goToPage(PageEnum.PageProtocolXrayConfigsSettings)
onClicked: PageController.goToPage(PageEnum.PageProtocolXraySnapshots)
}
}

View File

@@ -10,6 +10,7 @@ import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
import Qt.labs.platform 1.1
PageType {
id: root
@@ -18,7 +19,29 @@ PageType {
property int selectedConfigIndex: -1
// Reload the list every time we open this page
Component.onCompleted: XrayConfigsModel.reload()
Component.onCompleted: XrayConfigSnapshotsModel.reload()
// Save xray config snapshot to file
function saveConfigToFile(json) {
var fileName = ""
if (GC.isMobile()) {
fileName = "amnezia_xray_config.json"
} else {
fileName = SystemController.getFileName(
qsTr("Save XRay configuration"),
qsTr("JSON files (*.json)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_xray_config",
true,
".json")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
ExportController.setConfigFromString(json, fileName)
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Configuration saved"))
}
}
BackButtonType {
id: backButton
@@ -35,7 +58,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
model: XrayConfigsModel
model: XrayConfigSnapshotsModel
header: ColumnLayout {
width: listView.width
@@ -57,31 +80,30 @@ PageType {
text: qsTr("Create configuration based on current settings")
textMaximumLineCount: 2
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
XrayConfigsModel.createFromXrayModel(XrayConfigModel)
clickedFunction: function () {
XrayConfigSnapshotsModel.createFromCurrentModel()
}
}
DividerType {}
DividerType {
}
// Export
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Export settings")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
if (root.selectedConfigIndex >= 0) {
var json = XrayConfigsModel.exportToJson(root.selectedConfigIndex)
ExportController.setConfigFromString(json, "xray_config.json")
} else if (XrayConfigsModel.rowCount() > 0) {
// Export the first one if none selected
var json = XrayConfigsModel.exportToJson(0)
ExportController.setConfigFromString(json, "xray_config.json")
clickedFunction: function () {
var idx = root.selectedConfigIndex >= 0 ? root.selectedConfigIndex : 0
if (listView.count > 0) {
var json = XrayConfigSnapshotsModel.exportToJson(idx)
saveConfigToFile(json)
}
}
}
DividerType {}
DividerType {
}
// Import
LabelWithButtonType {
@@ -89,18 +111,25 @@ PageType {
text: qsTr("Import settings")
descriptionText: qsTr("In JSON format")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
var filePath = SystemController.getFileName(qsTr("Open XRay config"), qsTr("JSON files (*.json)"))
clickedFunction: function () {
var filePath = SystemController.getFileName(
qsTr("Open XRay configuration"),
qsTr("JSON files (*.json)"))
if (filePath !== "") {
var jsonContent = ImportController.readTextFile(filePath)
if (jsonContent !== "") {
XrayConfigsModel.importFromJson(jsonContent)
if (!XrayConfigSnapshotsModel.importFromJson(jsonContent)) {
PageController.showNotificationMessage(qsTr("Failed to import configuration"))
} else {
PageController.showNotificationMessage(qsTr("Configuration imported successfully"))
}
}
}
}
}
DividerType {}
DividerType {
}
// Section label
CaptionTextType {
@@ -111,17 +140,19 @@ PageType {
Layout.bottomMargin: 8
text: qsTr("Configurations")
color: AmneziaStyle.color.mutedGray
visible: XrayConfigsModel.rowCount() > 0
visible: listView.count > 0
}
}
// Empty state
footer: ColumnLayout {
width: listView.width
visible: XrayConfigsModel.rowCount() === 0
visible: listView.count === 0
spacing: 0
Item { Layout.preferredHeight: 32 }
Item {
Layout.preferredHeight: 32
}
ParagraphTextType {
Layout.fillWidth: true
@@ -144,20 +175,22 @@ PageType {
text: configName
descriptionText: configDate
rightImageSource: "qrc:/images/controls/more-vertical.svg"
clickedFunction: function() {
clickedFunction: function () {
root.selectedConfigName = configName
root.selectedConfigIndex = index
configActionsDrawer.openTriggered()
}
}
DividerType {}
DividerType {
}
}
}
// Import result handler
Connections {
target: XrayConfigsModel
target: XrayConfigSnapshotsModel
function onImportFailed(errorMessage) {
PageController.showNotificationMessage(errorMessage)
}
@@ -184,7 +217,7 @@ PageType {
BackButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
backButtonFunction: function() {
backButtonFunction: function () {
configActionsDrawer.closeTriggered()
}
}
@@ -204,38 +237,40 @@ PageType {
Layout.fillWidth: true
text: qsTr("Apply configuration")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
clickedFunction: function () {
configActionsDrawer.closeTriggered()
XrayConfigsModel.applyConfigToXrayModel(root.selectedConfigIndex, XrayConfigModel)
XrayConfigSnapshotsModel.applyConfigToCurrentModel(root.selectedConfigIndex)
PageController.closePage()
}
}
DividerType {}
DividerType {
}
// Export this config
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Export configuration")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
clickedFunction: function () {
configActionsDrawer.closeTriggered()
var json = XrayConfigsModel.exportToJson(root.selectedConfigIndex)
ExportController.setConfigFromString(json, "xray_config.json")
var json = XrayConfigSnapshotsModel.exportToJson(root.selectedConfigIndex)
saveConfigToFile(json)
}
}
DividerType {}
DividerType {
}
// Delete
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Delete configuration")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
clickedFunction: function () {
configActionsDrawer.closeTriggered()
var yesButtonFunction = function() {
XrayConfigsModel.removeConfig(root.selectedConfigIndex)
var yesButtonFunction = function () {
XrayConfigSnapshotsModel.removeConfig(root.selectedConfigIndex)
root.selectedConfigIndex = -1
root.selectedConfigName = ""
}
@@ -243,12 +278,16 @@ PageType {
qsTr("Delete configuration?"),
qsTr("This action cannot be undone."),
qsTr("Delete"), qsTr("Cancel"),
yesButtonFunction, function() {})
yesButtonFunction, function () {
})
}
}
DividerType {}
Item { Layout.preferredHeight: 16 }
DividerType {
}
Item {
Layout.preferredHeight: 16
}
}
}
}

View File

@@ -25,7 +25,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: saveButton.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -735,20 +735,21 @@ PageType {
}
}
BasicButtonType {
id: saveButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
anchors.leftMargin: 16
anchors.rightMargin: 16
text: qsTr("Save")
onClicked: {
forceActiveFocus()
PageController.closePage()
}
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
}
// BasicButtonType {
// id: saveButton
// anchors.bottom: parent.bottom
// anchors.left: parent.left
// anchors.right: parent.right
// anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
// anchors.leftMargin: 16
// anchors.rightMargin: 16
// text: qsTr("Save")
// onClicked: {
// forceActiveFocus()
// PageController.closePage()
// }
// Keys.onEnterPressed: clicked()
// Keys.onReturnPressed: clicked()
// }
}

View File

@@ -25,7 +25,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: saveButton.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -63,24 +63,26 @@ PageType {
onMaxChanged: xPaddingBytesMax = val
}
Item { Layout.preferredHeight: 16 }
Item {
Layout.preferredHeight: 16
}
}
}
BasicButtonType {
id: saveButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
anchors.leftMargin: 16
anchors.rightMargin: 16
text: qsTr("Save")
onClicked: {
forceActiveFocus()
PageController.closePage()
}
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
}
// BasicButtonType {
// id: saveButton
// anchors.bottom: parent.bottom
// anchors.left: parent.left
// anchors.right: parent.right
// anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
// anchors.leftMargin: 16
// anchors.rightMargin: 16
// text: qsTr("Save")
// onClicked: {
// forceActiveFocus()
// PageController.closePage()
// }
// Keys.onEnterPressed: clicked()
// Keys.onReturnPressed: clicked()
// }
}

View File

@@ -25,7 +25,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: saveButton.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -194,20 +194,20 @@ PageType {
}
}
BasicButtonType {
id: saveButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
anchors.leftMargin: 16
anchors.rightMargin: 16
text: qsTr("Save")
onClicked: {
forceActiveFocus()
PageController.closePage()
}
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
}
// BasicButtonType {
// id: saveButton
// anchors.bottom: parent.bottom
// anchors.left: parent.left
// anchors.right: parent.right
// anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
// anchors.leftMargin: 16
// anchors.rightMargin: 16
// text: qsTr("Save")
// onClicked: {
// forceActiveFocus()
// PageController.closePage()
// }
// Keys.onEnterPressed: clicked()
// Keys.onReturnPressed: clicked()
// }
}

View File

@@ -25,7 +25,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: saveButton.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -182,20 +182,21 @@ PageType {
}
}
BasicButtonType {
id: saveButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
anchors.leftMargin: 16
anchors.rightMargin: 16
text: qsTr("Save")
onClicked: {
forceActiveFocus()
PageController.closePage()
}
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
}
// BasicButtonType {
// id: saveButton
// anchors.bottom: parent.bottom
// anchors.left: parent.left
// anchors.right: parent.right
// anchors.bottomMargin: 16 + PageController.safeAreaBottomMargin
// anchors.leftMargin: 16
// anchors.rightMargin: 16
// text: qsTr("Save")
// onClicked: {
// forceActiveFocus()
// PageController.closePage()
// }
// Keys.onEnterPressed: clicked()
// Keys.onReturnPressed: clicked()
// }
}

View File

@@ -78,7 +78,7 @@
<file>Pages2/PageProtocolWireGuardSettings.qml</file>
<file>Pages2/PageProtocolXraySettings.qml</file>
<file>Pages2/PageProtocolXrayConfigsSettings.qml</file>
<file>Pages2/PageProtocolXraySnapshots.qml</file>
<file>Pages2/PageProtocolXrayFlowSettings.qml</file>
<file>Pages2/PageProtocolXraySecuritySettings.qml</file>
<file>Pages2/PageProtocolXrayTransportSettings.qml</file>