mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-24 02:00:24 +07:00
fix: Fix local proxy UI
This commit is contained in:
@@ -61,7 +61,12 @@ void CoreController::initLocalProxy()
|
||||
return;
|
||||
}
|
||||
|
||||
m_proxyServer->syncSettings();
|
||||
if (!m_proxyServer->syncSettings()) {
|
||||
qWarning() << "Local proxy: failed to start proxy core (Xray)";
|
||||
m_settings->setLocalProxyHttpEnabled(false);
|
||||
emit m_settings->localProxyStartFailed(tr("Couldn’t start the proxy due to an internal error. Try restarting the app."));
|
||||
return;
|
||||
}
|
||||
|
||||
qInfo() << "Local proxy: running on 127.0.0.1:" << kLocalProxyApiPort;
|
||||
};
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#include "core/api/apiUtils.h"
|
||||
#include "core/controllers/gatewayController.h"
|
||||
#include "core/defs.h"
|
||||
#include "portavailabilityhelper.h"
|
||||
#include "proxylogger.h"
|
||||
#include "settings.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <QSaveFile>
|
||||
#include <QSysInfo>
|
||||
#include <QStandardPaths>
|
||||
#include <QTcpServer>
|
||||
#include <QUuid>
|
||||
|
||||
ConfigManager::ConfigManager(const std::shared_ptr<Settings> &settings)
|
||||
@@ -84,18 +83,6 @@ QString ConfigManager::serializeConfig(const QJsonObject &config) const
|
||||
return QString::fromUtf8(QJsonDocument(config).toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
bool ConfigManager::isPortAvailable(int port) const
|
||||
{
|
||||
if (port < kProxyPortMin || port > kProxyPortMax) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTcpServer server;
|
||||
const bool success = server.listen(QHostAddress::LocalHost, static_cast<quint16>(port));
|
||||
server.close();
|
||||
return success;
|
||||
}
|
||||
|
||||
std::optional<ConfigManager::ConfigData> ConfigManager::buildConfig(QString &errorDescription) const
|
||||
{
|
||||
errorDescription.clear();
|
||||
@@ -223,29 +210,30 @@ std::optional<ConfigManager::ConfigData> ConfigManager::buildConfigWithFetch(QSt
|
||||
data.parsedConfig = doc.object();
|
||||
|
||||
int selectedPort = resolveProxyPort(m_settings);
|
||||
const int startPort = selectedPort;
|
||||
const bool isUserDefinedPort = m_settings->isLocalProxyPortUserDefined();
|
||||
|
||||
bool found = false;
|
||||
for (int port = selectedPort; port <= kProxyPortMax; ++port) {
|
||||
if (isPortAvailable(port)) {
|
||||
selectedPort = port;
|
||||
found = true;
|
||||
break;
|
||||
if (!PortAvailabilityHelper::isPortAvailable(selectedPort)) {
|
||||
const bool canAutoSelect = !isUserDefinedPort && selectedPort == kDefaultProxyPort;
|
||||
if (canAutoSelect) {
|
||||
const auto freePort = PortAvailabilityHelper::findFirstAvailablePort(kDefaultProxyPort + 1, kProxyPortMax);
|
||||
if (!freePort) {
|
||||
errorDescription = QStringLiteral("No available local proxy port in range %1-%2")
|
||||
.arg(kDefaultProxyPort + 1)
|
||||
.arg(kProxyPortMax);
|
||||
ProxyLogger::getInstance().error(errorDescription);
|
||||
return std::nullopt;
|
||||
}
|
||||
selectedPort = *freePort;
|
||||
} else {
|
||||
errorDescription = QStringLiteral("Local proxy port %1 is already in use")
|
||||
.arg(selectedPort);
|
||||
ProxyLogger::getInstance().error(errorDescription);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
errorDescription = QStringLiteral("No available local proxy port in range %1-%2")
|
||||
.arg(startPort)
|
||||
.arg(kProxyPortMax);
|
||||
ProxyLogger::getInstance().error(errorDescription);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (applyProxyPortToConfig(data.parsedConfig, selectedPort)) {
|
||||
data.serializedConfig = serializeConfig(data.parsedConfig);
|
||||
if (m_settings && m_settings->localProxyPort() != static_cast<quint16>(selectedPort)) {
|
||||
m_settings->setLocalProxyPort(static_cast<quint16>(selectedPort));
|
||||
}
|
||||
} else {
|
||||
ProxyLogger::getInstance().warning(QStringLiteral("Failed to override local proxy inbound port; using original config"));
|
||||
data.serializedConfig = *serializedConfig;
|
||||
|
||||
@@ -32,7 +32,6 @@ private:
|
||||
QString tempDirectory() const;
|
||||
bool applyProxyPortToConfig(QJsonObject &config, int port) const;
|
||||
QString serializeConfig(const QJsonObject &config) const;
|
||||
bool isPortAvailable(int port) const;
|
||||
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "portavailabilityhelper.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QTcpServer>
|
||||
|
||||
namespace {
|
||||
constexpr int kProxyPortMin = 1024;
|
||||
constexpr int kProxyPortMax = 65535;
|
||||
}
|
||||
|
||||
bool PortAvailabilityHelper::isPortAvailable(int port)
|
||||
{
|
||||
if (port < kProxyPortMin || port > kProxyPortMax) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTcpServer server;
|
||||
const bool success = server.listen(QHostAddress::LocalHost, static_cast<quint16>(port));
|
||||
server.close();
|
||||
return success;
|
||||
}
|
||||
|
||||
std::optional<int> PortAvailabilityHelper::findFirstAvailablePort(int startPort, int endPort)
|
||||
{
|
||||
if (startPort < kProxyPortMin) {
|
||||
startPort = kProxyPortMin;
|
||||
}
|
||||
if (endPort > kProxyPortMax) {
|
||||
endPort = kProxyPortMax;
|
||||
}
|
||||
if (startPort > endPort) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
for (int port = startPort; port <= endPort; ++port) {
|
||||
if (isPortAvailable(port)) {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
class PortAvailabilityHelper
|
||||
{
|
||||
public:
|
||||
static bool isPortAvailable(int port);
|
||||
static std::optional<int> findFirstAvailablePort(int startPort, int endPort);
|
||||
};
|
||||
|
||||
@@ -65,11 +65,11 @@ void ProxyServer::stopXrayProcess()
|
||||
m_service->stopXray();
|
||||
}
|
||||
|
||||
void ProxyServer::syncSettings()
|
||||
bool ProxyServer::syncSettings()
|
||||
{
|
||||
if (!m_isRunning) {
|
||||
qDebug() << "Local proxy: syncSettings called but server is not running";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const quint16 newProxyPort = m_settings ? m_settings->localProxyPort() : 0;
|
||||
@@ -77,14 +77,21 @@ void ProxyServer::syncSettings()
|
||||
|
||||
if (!xrayRunning) {
|
||||
qInfo() << "Local proxy: starting Xray on port" << newProxyPort;
|
||||
m_currentProxyPort = newProxyPort;
|
||||
startXrayProcess();
|
||||
return;
|
||||
const bool started = startXrayProcess();
|
||||
if (started) {
|
||||
m_currentProxyPort = newProxyPort;
|
||||
}
|
||||
return started;
|
||||
}
|
||||
|
||||
if (m_currentProxyPort != newProxyPort) {
|
||||
qInfo() << "Local proxy: proxy port changed from" << m_currentProxyPort << "to" << newProxyPort;
|
||||
m_currentProxyPort = newProxyPort;
|
||||
m_service->restartXray();
|
||||
const bool restarted = m_service->restartXray();
|
||||
if (restarted) {
|
||||
m_currentProxyPort = newProxyPort;
|
||||
}
|
||||
return restarted;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
|
||||
bool start(quint16 port = 49490);
|
||||
void stop();
|
||||
void syncSettings();
|
||||
bool syncSettings();
|
||||
|
||||
private:
|
||||
bool startXrayProcess();
|
||||
|
||||
@@ -647,6 +647,16 @@ void Settings::setLocalProxyPort(quint16 port)
|
||||
emit localProxySettingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::isLocalProxyPortUserDefined() const
|
||||
{
|
||||
return value("Conf/localProxyPortUserDefined", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setLocalProxyPortUserDefined(bool userDefined)
|
||||
{
|
||||
setValue("Conf/localProxyPortUserDefined", userDefined);
|
||||
}
|
||||
|
||||
bool Settings::isLocalProxyHttpEnabled() const
|
||||
{
|
||||
return value("Conf/localProxyHttpEnabled", false).toBool();
|
||||
|
||||
@@ -244,6 +244,8 @@ public:
|
||||
void setLocalProxyOwnerUuid(const QString &uuid);
|
||||
quint16 localProxyPort() const;
|
||||
void setLocalProxyPort(quint16 port);
|
||||
bool isLocalProxyPortUserDefined() const;
|
||||
void setLocalProxyPortUserDefined(bool userDefined);
|
||||
bool isLocalProxyHttpEnabled() const;
|
||||
void setLocalProxyHttpEnabled(bool enabled);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <QOperatingSystemVersion>
|
||||
|
||||
#include "logger.h"
|
||||
#include "core/local-proxy/portavailabilityhelper.h"
|
||||
#include "systemController.h"
|
||||
#include "ui/qautostart.h"
|
||||
#include "amnezia_application.h"
|
||||
@@ -17,6 +18,7 @@
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
constexpr int kDefaultProxyPort = 10808;
|
||||
constexpr int kLocalProxyPortMin = 1024;
|
||||
constexpr int kLocalProxyPortMax = 65535;
|
||||
}
|
||||
@@ -563,13 +565,31 @@ bool SettingsController::setLocalProxyPort(int port)
|
||||
}
|
||||
|
||||
if (m_settings->localProxyPort() == static_cast<quint16>(port)) {
|
||||
m_settings->setLocalProxyPortUserDefined(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
m_settings->setLocalProxyPort(static_cast<quint16>(port));
|
||||
m_settings->setLocalProxyPortUserDefined(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SettingsController::isLocalProxyPortBusy(int port) const
|
||||
{
|
||||
return !PortAvailabilityHelper::isPortAvailable(port);
|
||||
}
|
||||
|
||||
bool SettingsController::isLocalProxyPortUserDefined() const
|
||||
{
|
||||
return m_settings->isLocalProxyPortUserDefined();
|
||||
}
|
||||
|
||||
int SettingsController::findFirstAvailableLocalProxyPort(int startPort) const
|
||||
{
|
||||
const auto port = PortAvailabilityHelper::findFirstAvailablePort(startPort, kLocalProxyPortMax);
|
||||
return port ? *port : -1;
|
||||
}
|
||||
|
||||
bool SettingsController::enableLocalProxy(const QString &ownerUuid, int port)
|
||||
{
|
||||
if (port < kLocalProxyPortMin || port > kLocalProxyPortMax || ownerUuid.isEmpty()) {
|
||||
@@ -580,8 +600,23 @@ bool SettingsController::enableLocalProxy(const QString &ownerUuid, int port)
|
||||
return false;
|
||||
}
|
||||
|
||||
int selectedPort = port;
|
||||
|
||||
const bool isUserDefinedPort = m_settings->isLocalProxyPortUserDefined();
|
||||
if (isUserDefinedPort) {
|
||||
if (!PortAvailabilityHelper::isPortAvailable(selectedPort)) {
|
||||
return false;
|
||||
}
|
||||
} else if (selectedPort != kDefaultProxyPort && !PortAvailabilityHelper::isPortAvailable(selectedPort)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_settings->localProxyPort() != static_cast<quint16>(selectedPort)) {
|
||||
m_settings->setLocalProxyPort(static_cast<quint16>(selectedPort));
|
||||
}
|
||||
m_settings->setLocalProxyPortUserDefined(isUserDefinedPort);
|
||||
|
||||
m_settings->setLocalProxyOwnerUuid(ownerUuid);
|
||||
setLocalProxyPort(port);
|
||||
m_settings->setLocalProxyHttpEnabled(true);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -118,6 +118,9 @@ public slots:
|
||||
int localProxyPort() const;
|
||||
QString localProxyOwnerUuid() const;
|
||||
bool setLocalProxyPort(int port);
|
||||
bool isLocalProxyPortBusy(int port) const;
|
||||
bool isLocalProxyPortUserDefined() const;
|
||||
int findFirstAvailableLocalProxyPort(int startPort) const;
|
||||
bool enableLocalProxy(const QString &ownerUuid, int port);
|
||||
void disableLocalProxy();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ Item {
|
||||
property int headerTextMaximumLineCount: 2
|
||||
property int headerTextElide: Qt.ElideRight
|
||||
property string descriptionText
|
||||
property string descriptionColor: AmneziaStyle.color.mutedGray
|
||||
property alias headerRow: headerRow
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
@@ -38,7 +39,7 @@ Item {
|
||||
Layout.topMargin: 16
|
||||
Layout.fillWidth: true
|
||||
text: root.descriptionText
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
color: root.descriptionColor
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ Item {
|
||||
property string headerTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property alias errorText: errorField.text
|
||||
property bool clearErrorOnTextChanged: true
|
||||
property bool checkEmptyText: false
|
||||
property bool rightButtonClickedOnEnter: false
|
||||
|
||||
@@ -128,7 +129,9 @@ Item {
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
root.errorText = ""
|
||||
if (root.clearErrorOnTextChanged) {
|
||||
root.errorText = ""
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
|
||||
@@ -17,13 +17,25 @@ PageType {
|
||||
readonly property int localProxyPortMax: 65535
|
||||
readonly property int defaultLocalProxyPort: 10808
|
||||
|
||||
property bool portValidationEnabled: false
|
||||
property string portValidationError: ""
|
||||
property bool suppressToggleHandler: false
|
||||
property int pendingStartRequestedPort: -1
|
||||
property int pendingStartAutoSelectedPort: -1
|
||||
|
||||
Component.onCompleted: root.syncSwitchState()
|
||||
|
||||
function getPortField() {
|
||||
var item = listView.itemAtIndex(0)
|
||||
return item !== null ? item.children[0] : null
|
||||
}
|
||||
|
||||
function getHeaderBlock() {
|
||||
var headerItem = listView.headerItem
|
||||
return headerItem && headerItem.children.length > 0 ? headerItem.children[0] : null
|
||||
}
|
||||
|
||||
function computePortErrorText() {
|
||||
var portField = getPortField()
|
||||
if (portField === null) return ""
|
||||
const text = portField.textField.text.trim()
|
||||
if (text === "") {
|
||||
return qsTr("Enter a port")
|
||||
@@ -34,18 +46,11 @@ PageType {
|
||||
.arg(root.localProxyPortMin)
|
||||
.arg(root.localProxyPortMax)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function updatePortValidation(force) {
|
||||
if (force) {
|
||||
root.portValidationEnabled = true
|
||||
if (SettingsController.isLocalProxyPortBusy(value)) {
|
||||
return qsTr("Port %1 is already in use on this device. Choose another one")
|
||||
.arg(value)
|
||||
}
|
||||
root.portValidationError = root.portValidationEnabled ? root.computePortErrorText() : ""
|
||||
}
|
||||
|
||||
function isPortValid() {
|
||||
return root.computePortErrorText() === ""
|
||||
return ""
|
||||
}
|
||||
|
||||
function syncSwitchState() {
|
||||
@@ -53,11 +58,11 @@ PageType {
|
||||
}
|
||||
|
||||
function setSwitcherChecked(value) {
|
||||
if (localProxyHeader.switcher.checked === value) {
|
||||
var header = getHeaderBlock()
|
||||
if (!header || header.switcher.checked === value) {
|
||||
return
|
||||
}
|
||||
root.suppressToggleHandler = true
|
||||
localProxyHeader.switcher.checked = value
|
||||
header.switcher.checked = value
|
||||
}
|
||||
|
||||
function handleLocalProxyToggle(checked) {
|
||||
@@ -77,7 +82,7 @@ PageType {
|
||||
return
|
||||
}
|
||||
|
||||
const requestedPort = portField.portValue()
|
||||
const requestedPort = SettingsController.localProxyPort
|
||||
if (requestedPort < root.localProxyPortMin || requestedPort > root.localProxyPortMax) {
|
||||
root.setSwitcherChecked(false)
|
||||
PageController.showNotificationMessage(qsTr("Port must be between %1 and %2")
|
||||
@@ -86,6 +91,25 @@ PageType {
|
||||
return
|
||||
}
|
||||
|
||||
let autoSelectedPort = -1
|
||||
if (SettingsController.isLocalProxyPortBusy(requestedPort)) {
|
||||
if (SettingsController.isLocalProxyPortUserDefined()
|
||||
|| requestedPort !== root.defaultLocalProxyPort) {
|
||||
PageController.showNotificationMessage(qsTr("Port %1 is already in use on this device. Choose another one")
|
||||
.arg(requestedPort))
|
||||
root.setSwitcherChecked(false)
|
||||
return
|
||||
}
|
||||
|
||||
autoSelectedPort = SettingsController.findFirstAvailableLocalProxyPort(root.defaultLocalProxyPort + 1)
|
||||
if (autoSelectedPort <= 0) {
|
||||
PageController.showNotificationMessage(qsTr("Port %1 is already in use on this device. Choose another one")
|
||||
.arg(requestedPort))
|
||||
root.setSwitcherChecked(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!SettingsController.enableLocalProxy(serverUuid, requestedPort)) {
|
||||
root.setSwitcherChecked(false)
|
||||
PageController.showNotificationMessage(qsTr("Failed to enable local proxy. Check the port (%1-%2).")
|
||||
@@ -94,8 +118,14 @@ PageType {
|
||||
root.syncSwitchState()
|
||||
return
|
||||
}
|
||||
root.pendingStartRequestedPort = requestedPort
|
||||
root.pendingStartAutoSelectedPort = autoSelectedPort
|
||||
startSuccessToastTimer.restart()
|
||||
root.syncSwitchState()
|
||||
} else {
|
||||
startSuccessToastTimer.stop()
|
||||
root.pendingStartRequestedPort = -1
|
||||
root.pendingStartAutoSelectedPort = -1
|
||||
SettingsController.disableLocalProxy()
|
||||
root.syncSwitchState()
|
||||
}
|
||||
@@ -136,9 +166,10 @@ PageType {
|
||||
headerText: qsTr("Local Proxy")
|
||||
descriptionText: qsTr("Use a proxy to route selected apps (for example, the CensorTracker extension) through Amnezia Premium.")
|
||||
showSwitcher: true
|
||||
Component.onCompleted: root.syncSwitchState()
|
||||
switcherFunction: function(checked) {
|
||||
if (root.suppressToggleHandler) {
|
||||
root.suppressToggleHandler = false
|
||||
// Ignore UI sync toggles; react only to real state change intent.
|
||||
if (checked === SettingsController.isLocalProxyHttpEnabled) {
|
||||
return
|
||||
}
|
||||
root.handleLocalProxyToggle(checked)
|
||||
@@ -147,16 +178,18 @@ PageType {
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.topMargin: 12
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
color: localProxyHeader.descriptionColor
|
||||
text: qsTr("Only one can be on at a time: VPN or local proxy.")
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 8
|
||||
Layout.bottomMargin: 28
|
||||
implicitHeight: 32
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
@@ -167,7 +200,11 @@ PageType {
|
||||
|
||||
text: qsTr("Learn more")
|
||||
clickedFunc: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||
const isRussian = LanguageModel.currentLanguageName === "Русский"
|
||||
const learnMoreUrl = isRussian
|
||||
? "http://docs.amnezia.org/ru/documentation/instructions/local-proxy"
|
||||
: "http://docs.amnezia.org/documentation/instructions/local-proxy"
|
||||
Qt.openUrlExternally(learnMoreUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,26 +225,29 @@ PageType {
|
||||
headerText: qsTr("Address and port")
|
||||
buttonText: qsTr("Copy")
|
||||
errorText: root.portValidationError
|
||||
clearErrorOnTextChanged: false
|
||||
|
||||
enabled: true
|
||||
rightButtonClickedOnEnter: true
|
||||
rightButtonClickedOnEnter: false
|
||||
|
||||
clickedFunc: function() {
|
||||
const portText = portField.effectivePortText()
|
||||
GC.copyToClipBoard("127.0.0.1:" + portText)
|
||||
PageController.showNotificationMessage(qsTr("Copied: 127.0.0.1:%1").arg(portText))
|
||||
}
|
||||
|
||||
textField.validator: IntValidator {
|
||||
bottom: root.localProxyPortMin
|
||||
top: root.localProxyPortMax
|
||||
}
|
||||
textField.leftPadding: portPrefix.implicitWidth + 8
|
||||
textField.leftPadding: portPrefix.implicitWidth
|
||||
textField.placeholderText: root.defaultLocalProxyPort.toString()
|
||||
textField.inputMethodHints: Qt.ImhDigitsOnly | Qt.ImhNoPredictiveText
|
||||
|
||||
function syncPortValue() {
|
||||
const port = SettingsController.localProxyPort
|
||||
textField.text = (port >= root.localProxyPortMin && port <= root.localProxyPortMax) ? port.toString() : ""
|
||||
const isValidPort = port >= root.localProxyPortMin && port <= root.localProxyPortMax
|
||||
textField.text = (isValidPort && port !== root.defaultLocalProxyPort) ? port.toString() : ""
|
||||
}
|
||||
|
||||
function portValue() {
|
||||
@@ -229,24 +269,26 @@ PageType {
|
||||
|
||||
Component.onCompleted: syncPortValue()
|
||||
|
||||
textField.onTextChanged: root.updatePortValidation(false)
|
||||
textField.onActiveFocusChanged: {
|
||||
if (!textField.activeFocus) {
|
||||
root.updatePortValidation(true)
|
||||
textField.onTextChanged: {
|
||||
if (textField.activeFocus) {
|
||||
root.portValidationError = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LabelTextType {
|
||||
Text {
|
||||
id: portPrefix
|
||||
|
||||
parent: portField
|
||||
parent: portField.textField
|
||||
text: "127.0.0.1:"
|
||||
color: AmneziaStyle.color.paleGray
|
||||
font.pixelSize: portField.textField.font.pixelSize
|
||||
font.weight: portField.textField.font.weight
|
||||
font.family: portField.textField.font.family
|
||||
z: 1
|
||||
|
||||
anchors.left: portField.textField.left
|
||||
anchors.verticalCenter: portField.textField.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
@@ -255,18 +297,22 @@ PageType {
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Save")
|
||||
enabled: root.isPortValid()
|
||||
enabled: true
|
||||
|
||||
clickedFunc: function() {
|
||||
root.updatePortValidation(true)
|
||||
if (!root.isPortValid()) {
|
||||
const validationError = root.computePortErrorText()
|
||||
root.portValidationError = validationError
|
||||
if (validationError !== "") {
|
||||
return
|
||||
}
|
||||
|
||||
const value = portField.portValue()
|
||||
if (!SettingsController.setLocalProxyPort(value)) {
|
||||
PageController.showNotificationMessage(qsTr("Failed to save port. Valid range: %1-%2")
|
||||
.arg(root.localProxyPortMin)
|
||||
.arg(root.localProxyPortMax))
|
||||
} else {
|
||||
PageController.showNotificationMessage(qsTr("Port saved: %1").arg(value))
|
||||
}
|
||||
portField.syncPortValue()
|
||||
}
|
||||
@@ -274,17 +320,45 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: startSuccessToastTimer
|
||||
interval: 250
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: {
|
||||
if (!SettingsController.isLocalProxyHttpEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (root.pendingStartAutoSelectedPort > 0) {
|
||||
PageController.showNotificationMessage(qsTr("Port %1 is in use — selected free port %2.")
|
||||
.arg(root.defaultLocalProxyPort)
|
||||
.arg(root.pendingStartAutoSelectedPort))
|
||||
} else if (root.pendingStartRequestedPort > 0) {
|
||||
PageController.showNotificationMessage(qsTr("Local proxy is running: 127.0.0.1:%1")
|
||||
.arg(root.pendingStartRequestedPort))
|
||||
}
|
||||
|
||||
root.pendingStartRequestedPort = -1
|
||||
root.pendingStartAutoSelectedPort = -1
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsController
|
||||
|
||||
function onLocalProxySettingsUpdated() {
|
||||
root.syncSwitchState()
|
||||
if (!portField.textField.activeFocus) {
|
||||
var portField = root.getPortField()
|
||||
if (portField !== null && !portField.textField.activeFocus) {
|
||||
portField.syncPortValue()
|
||||
}
|
||||
}
|
||||
|
||||
function onLocalProxyStartFailed(message) {
|
||||
startSuccessToastTimer.stop()
|
||||
root.pendingStartRequestedPort = -1
|
||||
root.pendingStartAutoSelectedPort = -1
|
||||
PageController.showNotificationMessage(message)
|
||||
root.syncSwitchState()
|
||||
}
|
||||
@@ -295,10 +369,10 @@ PageType {
|
||||
|
||||
function onProcessedServerChanged() {
|
||||
root.syncSwitchState()
|
||||
if (!portField.textField.activeFocus) {
|
||||
var portField = root.getPortField()
|
||||
if (portField !== null && !portField.textField.activeFocus) {
|
||||
portField.syncPortValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user