mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 19:00:22 +08:00
update: several refactors and Import window redesign
This commit is contained in:
parent
fc71624213
commit
31f6e1389f
@ -1 +1 @@
|
|||||||
5460
|
5461
|
||||||
|
@ -66,9 +66,9 @@ namespace Qv2ray::common
|
|||||||
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, ua);
|
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, ua);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray QvHttpRequestHelper::Get(const QString &url)
|
QByteArray QvHttpRequestHelper::Get(const QUrl &url)
|
||||||
{
|
{
|
||||||
request.setUrl({ url });
|
request.setUrl(url);
|
||||||
setAccessManagerAttributes(accessManager);
|
setAccessManagerAttributes(accessManager);
|
||||||
auto _reply = accessManager.get(request);
|
auto _reply = accessManager.get(request);
|
||||||
//
|
//
|
||||||
|
@ -33,7 +33,11 @@ namespace Qv2ray::common
|
|||||||
~QvHttpRequestHelper();
|
~QvHttpRequestHelper();
|
||||||
// get
|
// get
|
||||||
void AsyncGet(const QString &url);
|
void AsyncGet(const QString &url);
|
||||||
QByteArray Get(const QString &url);
|
QByteArray Get(const QUrl &url);
|
||||||
|
QByteArray Get(const QString &url)
|
||||||
|
{
|
||||||
|
return Get(QUrl{ url });
|
||||||
|
}
|
||||||
signals:
|
signals:
|
||||||
void OnRequestFinished(QByteArray &data);
|
void OnRequestFinished(QByteArray &data);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "ConnectionIO.hpp"
|
#include "ConnectionIO.hpp"
|
||||||
|
|
||||||
|
#include "Serialization.hpp"
|
||||||
|
#include "common/HTTPRequestHelper.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core::connection
|
namespace Qv2ray::core::connection
|
||||||
@ -8,14 +10,7 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
CONFIGROOT ConvertConfigFromFile(const QString &sourceFilePath, bool importComplex)
|
CONFIGROOT ConvertConfigFromFile(const QString &sourceFilePath, bool importComplex)
|
||||||
{
|
{
|
||||||
QFile source(sourceFilePath);
|
auto root = CONFIGROOT(JsonFromString(StringFromFile(sourceFilePath)));
|
||||||
|
|
||||||
if (!source.exists())
|
|
||||||
{
|
|
||||||
LOG(MODULE_FILEIO, "Trying to import from an non-existing file.") return CONFIGROOT();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto root = CONFIGROOT(JsonFromString(StringFromFile(source)));
|
|
||||||
|
|
||||||
if (!importComplex)
|
if (!importComplex)
|
||||||
{
|
{
|
||||||
@ -29,5 +24,27 @@ namespace Qv2ray::core::connection
|
|||||||
root.remove("dns");
|
root.remove("dns");
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
QMultiHash<QString, CONFIGROOT> GetConnectionConfigFromSubscription(const QUrl &subscriptionUrl, const QString &groupName)
|
||||||
|
{
|
||||||
|
QMultiHash<QString, CONFIGROOT> subscriptionContent;
|
||||||
|
QvHttpRequestHelper helper;
|
||||||
|
const auto data = helper.Get(subscriptionUrl);
|
||||||
|
auto subscriptionLines = SplitLines(TryDecodeSubscriptionString(data));
|
||||||
|
for (const auto &line : subscriptionLines)
|
||||||
|
{
|
||||||
|
QString __alias;
|
||||||
|
QString __errMessage;
|
||||||
|
// Assign a group name, to pass the name check.
|
||||||
|
QString __groupName = groupName;
|
||||||
|
auto connectionConfigMap = ConvertConfigFromString(line.trimmed(), &__alias, &__errMessage, &__groupName);
|
||||||
|
if (!__errMessage.isEmpty())
|
||||||
|
LOG(MODULE_SUBSCRIPTION, "Error: " + __errMessage)
|
||||||
|
for (const auto &val : connectionConfigMap)
|
||||||
|
{
|
||||||
|
subscriptionContent.insert(connectionConfigMap.key(val), val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subscriptionContent;
|
||||||
|
}
|
||||||
} // namespace ConnectionIO
|
} // namespace ConnectionIO
|
||||||
} // namespace Qv2ray::core::connection
|
} // namespace Qv2ray::core::connection
|
||||||
|
@ -6,6 +6,7 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
// File Protocol
|
// File Protocol
|
||||||
CONFIGROOT ConvertConfigFromFile(const QString &sourceFilePath, bool importComplex);
|
CONFIGROOT ConvertConfigFromFile(const QString &sourceFilePath, bool importComplex);
|
||||||
|
QMultiHash<QString, CONFIGROOT> GetConnectionConfigFromSubscription(const QUrl &subscriptionUrl, const QString &groupName);
|
||||||
} // namespace ConnectionIO
|
} // namespace ConnectionIO
|
||||||
} // namespace Qv2ray::core::connection
|
} // namespace Qv2ray::core::connection
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "Serialization.hpp"
|
#include "Serialization.hpp"
|
||||||
|
|
||||||
#include "Generation.hpp"
|
#include "Generation.hpp"
|
||||||
#include "common/QvHelpers.hpp"
|
|
||||||
#include "components/plugins/QvPluginHost.hpp"
|
#include "components/plugins/QvPluginHost.hpp"
|
||||||
#include "core/CoreUtils.hpp"
|
#include "core/CoreUtils.hpp"
|
||||||
#include "core/handler/ConfigHandler.hpp"
|
#include "core/handler/ConfigHandler.hpp"
|
||||||
@ -49,7 +48,7 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
auto outbound = GenerateOutboundEntry(val.first, OUTBOUNDSETTING(val.second), {});
|
auto outbound = GenerateOutboundEntry(val.first, OUTBOUNDSETTING(val.second), {});
|
||||||
root.insert("outbounds", QJsonArray{ outbound });
|
QJsonIO::SetValue(root, outbound, "outbounds", 0);
|
||||||
connectionConf.insert(key, root);
|
connectionConf.insert(key, root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,14 +107,5 @@ namespace Qv2ray::core::connection
|
|||||||
return sharelink;
|
return sharelink;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DecodeSubscriptionString(const QByteArray &arr)
|
|
||||||
{
|
|
||||||
// String may start with: vmess:// and ss://
|
|
||||||
// We only process vmess:// here
|
|
||||||
// Some subscription providers may use plain vmess:// saperated by
|
|
||||||
// lines But others may use base64 of above.
|
|
||||||
auto result = QString::fromUtf8(arr).trimmed();
|
|
||||||
return result.contains("://") ? result : SafeBase64Decode(result);
|
|
||||||
}
|
|
||||||
} // namespace Serialization
|
} // namespace Serialization
|
||||||
} // namespace Qv2ray::core::connection
|
} // namespace Qv2ray::core::connection
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core::connection
|
namespace Qv2ray::core::connection
|
||||||
{
|
{
|
||||||
@ -15,7 +16,11 @@ namespace Qv2ray::core::connection
|
|||||||
const inline auto QV2RAY_SSD_DEFAULT_NAME_PATTERN = QObject::tr("%1 - %2 (rate %3)");
|
const inline auto QV2RAY_SSD_DEFAULT_NAME_PATTERN = QObject::tr("%1 - %2 (rate %3)");
|
||||||
//
|
//
|
||||||
// General
|
// General
|
||||||
QString DecodeSubscriptionString(const QByteArray &arr);
|
inline const QString TryDecodeSubscriptionString(const QByteArray &arr)
|
||||||
|
{
|
||||||
|
auto result = QString::fromUtf8(arr).trimmed();
|
||||||
|
return result.contains("://") ? result : SafeBase64Decode(result);
|
||||||
|
}
|
||||||
QMultiHash<QString, CONFIGROOT> ConvertConfigFromString(const QString &link, QString *aliasPrefix, QString *errMessage,
|
QMultiHash<QString, CONFIGROOT> ConvertConfigFromString(const QString &link, QString *aliasPrefix, QString *errMessage,
|
||||||
QString *newGroupName = nullptr);
|
QString *newGroupName = nullptr);
|
||||||
const QString ConvertConfigToString(const ConnectionGroupPair &id, bool isSip002 = false);
|
const QString ConvertConfigToString(const ConnectionGroupPair &id, bool isSip002 = false);
|
||||||
|
@ -66,7 +66,6 @@ namespace Qv2ray::core::connection
|
|||||||
CONFIGROOT Deserialize(const QString &vmessStr, QString *alias, QString *errMessage)
|
CONFIGROOT Deserialize(const QString &vmessStr, QString *alias, QString *errMessage)
|
||||||
{
|
{
|
||||||
#define default CONFIGROOT()
|
#define default CONFIGROOT()
|
||||||
LOG(MODULE_SETTINGS, "Trying to convert from a vmess string.")
|
|
||||||
QString vmess = vmessStr;
|
QString vmess = vmessStr;
|
||||||
|
|
||||||
if (vmess.trimmed() != vmess)
|
if (vmess.trimmed() != vmess)
|
||||||
|
@ -66,7 +66,6 @@ namespace Qv2ray::core::handlers
|
|||||||
connect(kernelHandler, &KernelInstanceHandler::OnDisconnected, this, &QvConfigHandler::OnDisconnected);
|
connect(kernelHandler, &KernelInstanceHandler::OnDisconnected, this, &QvConfigHandler::OnDisconnected);
|
||||||
//
|
//
|
||||||
tcpingHelper = new QvTCPingHelper(5, this);
|
tcpingHelper = new QvTCPingHelper(5, this);
|
||||||
httpHelper = new QvHttpRequestHelper(this);
|
|
||||||
connect(tcpingHelper, &QvTCPingHelper::OnLatencyTestCompleted, this, &QvConfigHandler::OnLatencyDataArrived_p);
|
connect(tcpingHelper, &QvTCPingHelper::OnLatencyTestCompleted, this, &QvConfigHandler::OnLatencyDataArrived_p);
|
||||||
//
|
//
|
||||||
// Save per 1 minutes.
|
// Save per 1 minutes.
|
||||||
@ -369,7 +368,6 @@ namespace Qv2ray::core::handlers
|
|||||||
{
|
{
|
||||||
LOG(MODULE_CORE_HANDLER, "Triggering save settings from destructor")
|
LOG(MODULE_CORE_HANDLER, "Triggering save settings from destructor")
|
||||||
delete kernelHandler;
|
delete kernelHandler;
|
||||||
delete httpHelper;
|
|
||||||
CHSaveConfigData();
|
CHSaveConfigData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,57 +463,33 @@ namespace Qv2ray::core::handlers
|
|||||||
bool QvConfigHandler::UpdateSubscription(const GroupId &id)
|
bool QvConfigHandler::UpdateSubscription(const GroupId &id)
|
||||||
{
|
{
|
||||||
CheckGroupExistanceEx(id, false);
|
CheckGroupExistanceEx(id, false);
|
||||||
if (isHttpRequestInProgress || !groups[id].isSubscription)
|
if (!groups[id].isSubscription)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
isHttpRequestInProgress = true;
|
return CHUpdateSubscription_p(id, groups[id].subscriptionOption.address);
|
||||||
auto data = httpHelper->Get(groups[id].subscriptionOption.address);
|
|
||||||
isHttpRequestInProgress = false;
|
|
||||||
return CHUpdateSubscription_p(id, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QvConfigHandler::CHUpdateSubscription_p(const GroupId &id, const QByteArray &subscriptionData)
|
bool QvConfigHandler::CHUpdateSubscription_p(const GroupId &id, const QString &url)
|
||||||
{
|
{
|
||||||
CheckGroupExistanceEx(id, false);
|
CheckGroupExistanceEx(id, false);
|
||||||
if (!groups.contains(id))
|
if (!groups.contains(id))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QMultiHash<QString, CONFIGROOT> allSubscriptionConnections;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
//
|
||||||
// ====================================================================================== Begin reading subscription
|
// ====================================================================================== Begin reading subscription
|
||||||
|
auto _newConnections = GetConnectionConfigFromSubscription(url, GetDisplayName(id));
|
||||||
|
if (_newConnections.count() < 5)
|
||||||
{
|
{
|
||||||
auto subscriptionLines = SplitLines(DecodeSubscriptionString(subscriptionData));
|
LOG(MODULE_SUBSCRIPTION, "Find a subscription with less than 5 connections.")
|
||||||
for (const auto &line : subscriptionLines)
|
if (QvMessageBoxAsk(
|
||||||
{
|
nullptr, tr("Update Subscription"),
|
||||||
QString __alias;
|
tr("%1 entrie(s) have been found from the subscription source, do you want to continue?").arg(_newConnections.count())) !=
|
||||||
QString __errMessage;
|
QMessageBox::Yes)
|
||||||
// Assign a group name, to pass the name check.
|
|
||||||
QString __groupName = GetDisplayName(id);
|
|
||||||
auto connectionConfigMap = ConvertConfigFromString(line.trimmed(), &__alias, &__errMessage, &__groupName);
|
|
||||||
if (!__errMessage.isEmpty())
|
|
||||||
LOG(MODULE_SUBSCRIPTION, "Error: " + __errMessage)
|
|
||||||
for (const auto &val : connectionConfigMap)
|
|
||||||
{
|
|
||||||
allSubscriptionConnections.insert(connectionConfigMap.key(val), val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allSubscriptionConnections.count() < 5)
|
|
||||||
{
|
|
||||||
LOG(MODULE_SUBSCRIPTION, "Find a subscription with less than 5 connections.")
|
|
||||||
if (QvMessageBoxAsk(nullptr, tr("Update Subscription"),
|
|
||||||
tr("%1 entrie(s) have been found from the subscription source, do you want to continue?")
|
|
||||||
.arg(allSubscriptionConnections.count())) != QMessageBox::Yes)
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ====================================================================================== End reading subscription
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
//
|
||||||
// ====================================================================================== Begin Connection Data Storage
|
// ====================================================================================== Begin Connection Data Storage
|
||||||
// Anyway, we try our best to preserve the connection id.
|
// Anyway, we try our best to preserve the connection id.
|
||||||
@ -540,9 +514,9 @@ namespace Qv2ray::core::handlers
|
|||||||
auto originalConnectionIdList = groups[id].connections;
|
auto originalConnectionIdList = groups[id].connections;
|
||||||
groups[id].connections.clear();
|
groups[id].connections.clear();
|
||||||
//
|
//
|
||||||
for (const auto &config : allSubscriptionConnections)
|
for (const auto &config : _newConnections)
|
||||||
{
|
{
|
||||||
const auto _alias = allSubscriptionConnections.key(config);
|
const auto _alias = _newConnections.key(config);
|
||||||
QString errMessage;
|
QString errMessage;
|
||||||
|
|
||||||
if (!errMessage.isEmpty())
|
if (!errMessage.isEmpty())
|
||||||
@ -562,7 +536,7 @@ namespace Qv2ray::core::handlers
|
|||||||
LOG(MODULE_CORE_HANDLER, "Reused connection id from name: " + _alias)
|
LOG(MODULE_CORE_HANDLER, "Reused connection id from name: " + _alias)
|
||||||
auto _conn = nameMap.take(_alias);
|
auto _conn = nameMap.take(_alias);
|
||||||
groups[id].connections << _conn;
|
groups[id].connections << _conn;
|
||||||
UpdateConnection(_conn, config);
|
UpdateConnection(_conn, config, true);
|
||||||
// Remove Connection Id from the list.
|
// Remove Connection Id from the list.
|
||||||
originalConnectionIdList.removeAll(_conn);
|
originalConnectionIdList.removeAll(_conn);
|
||||||
typeMap.remove(typeMap.key(_conn));
|
typeMap.remove(typeMap.key(_conn));
|
||||||
@ -573,7 +547,7 @@ namespace Qv2ray::core::handlers
|
|||||||
auto _conn = typeMap.take(outboundData);
|
auto _conn = typeMap.take(outboundData);
|
||||||
groups[id].connections << _conn;
|
groups[id].connections << _conn;
|
||||||
// Update Connection Properties
|
// Update Connection Properties
|
||||||
UpdateConnection(_conn, config);
|
UpdateConnection(_conn, config, true);
|
||||||
RenameConnection(_conn, _alias);
|
RenameConnection(_conn, _alias);
|
||||||
// Remove Connection Id from the list.
|
// Remove Connection Id from the list.
|
||||||
originalConnectionIdList.removeAll(_conn);
|
originalConnectionIdList.removeAll(_conn);
|
||||||
@ -583,7 +557,7 @@ namespace Qv2ray::core::handlers
|
|||||||
{
|
{
|
||||||
// New connection id is required since nothing matched found...
|
// New connection id is required since nothing matched found...
|
||||||
LOG(MODULE_CORE_HANDLER, "Generated new connection id for connection: " + _alias)
|
LOG(MODULE_CORE_HANDLER, "Generated new connection id for connection: " + _alias)
|
||||||
CreateConnection(config, _alias, id);
|
CreateConnection(config, _alias, id, true);
|
||||||
}
|
}
|
||||||
// ====================================================================================== End guessing new ConnectionId
|
// ====================================================================================== End guessing new ConnectionId
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "common/HTTPRequestHelper.hpp"
|
|
||||||
#include "components/latency/QvTCPing.hpp"
|
#include "components/latency/QvTCPing.hpp"
|
||||||
#include "core/CoreUtils.hpp"
|
#include "core/CoreUtils.hpp"
|
||||||
#include "core/connection/ConnectionIO.hpp"
|
#include "core/connection/ConnectionIO.hpp"
|
||||||
@ -152,7 +151,7 @@ namespace Qv2ray::core::handlers
|
|||||||
void timerEvent(QTimerEvent *event) override;
|
void timerEvent(QTimerEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CHUpdateSubscription_p(const GroupId &id, const QByteArray &subscriptionData);
|
bool CHUpdateSubscription_p(const GroupId &id, const QString &url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int saveTimerId;
|
int saveTimerId;
|
||||||
@ -163,8 +162,6 @@ namespace Qv2ray::core::handlers
|
|||||||
QHash<ConnectionId, CONFIGROOT> connectionRootCache;
|
QHash<ConnectionId, CONFIGROOT> connectionRootCache;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QvHttpRequestHelper *httpHelper;
|
|
||||||
bool isHttpRequestInProgress = false;
|
|
||||||
QvTCPingHelper *tcpingHelper;
|
QvTCPingHelper *tcpingHelper;
|
||||||
KernelInstanceHandler *kernelHandler;
|
KernelInstanceHandler *kernelHandler;
|
||||||
};
|
};
|
||||||
|
@ -257,7 +257,7 @@ GroupManager::~GroupManager()
|
|||||||
void GroupManager::on_addGroupButton_clicked()
|
void GroupManager::on_addGroupButton_clicked()
|
||||||
{
|
{
|
||||||
auto const key = tr("New Group") + " - " + GenerateRandomString(5);
|
auto const key = tr("New Group") + " - " + GenerateRandomString(5);
|
||||||
auto id = ConnectionManager->CreateGroup(key, true);
|
auto id = ConnectionManager->CreateGroup(key, false);
|
||||||
//
|
//
|
||||||
auto item = new QListWidgetItem(key);
|
auto item = new QListWidgetItem(key);
|
||||||
item->setData(Qt::UserRole, id.toString());
|
item->setData(Qt::UserRole, id.toString());
|
||||||
@ -266,7 +266,7 @@ void GroupManager::on_addGroupButton_clicked()
|
|||||||
|
|
||||||
void GroupManager::on_updateButton_clicked()
|
void GroupManager::on_updateButton_clicked()
|
||||||
{
|
{
|
||||||
if (QvMessageBoxAsk(this, tr("Reload Subscription"), tr("Would you like to reload the subscription?")) == QMessageBox::Yes)
|
if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like to update the subscription?")) == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
this->setEnabled(false);
|
this->setEnabled(false);
|
||||||
ConnectionManager->UpdateSubscription(currentGroupId);
|
ConnectionManager->UpdateSubscription(currentGroupId);
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../resources.qrc">
|
<iconset resource="../../../resources.qrc">
|
||||||
<normaloff>:/assets/icons/ui_light/add.png</normaloff>:/assets/icons/ui_light/add.png</iconset>
|
<normaloff>:/assets/icons/ui_light/add.png</normaloff>:/assets/icons/ui_light/add.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -125,7 +125,7 @@
|
|||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../resources.qrc">
|
<iconset resource="../../../resources.qrc">
|
||||||
<normaloff>:/assets/icons/ui_light/delete.png</normaloff>:/assets/icons/ui_light/delete.png</iconset>
|
<normaloff>:/assets/icons/ui_light/delete.png</normaloff>:/assets/icons/ui_light/delete.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -227,6 +227,9 @@
|
|||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<layout class="QFormLayout" name="formLayout_3">
|
<layout class="QFormLayout" name="formLayout_3">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
@ -321,26 +324,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="tab_3">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Connection Settings</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_5">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<layout class="QGridLayout" name="connectionSettingsLayout"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="tab_4">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Route Settings</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<layout class="QGridLayout" name="routeSettingsLayout"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -352,7 +335,7 @@
|
|||||||
<tabstop>updateIntervalSB</tabstop>
|
<tabstop>updateIntervalSB</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../resources.qrc"/>
|
<include location="../../../resources.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
|
@ -20,12 +20,22 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
|
constexpr auto LINK_PAGE = 0;
|
||||||
|
constexpr auto QRCODE_PAGE = 1;
|
||||||
|
constexpr auto MANUAL_PAGE = 2;
|
||||||
|
constexpr auto ADVANCED_PAGE = 3;
|
||||||
|
|
||||||
ImportConfigWindow::ImportConfigWindow(QWidget *parent) : QDialog(parent)
|
ImportConfigWindow::ImportConfigWindow(QWidget *parent) : QDialog(parent)
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
// nameTxt->setText(tr("My Connection Imported at: ") + QDateTime::currentDateTime().toString("MM-dd hh:mm"));
|
nameTxt->setText(tr("New Connection") + QDateTime::currentDateTime().toString("MM-dd hh:mm"));
|
||||||
QvMessageBusConnect(ImportConfigWindow);
|
QvMessageBusConnect(ImportConfigWindow);
|
||||||
RESTORE_RUNTIME_CONFIG(screenShotHideQv2ray, hideQv2rayCB->setChecked)
|
RESTORE_RUNTIME_CONFIG(screenShotHideQv2ray, hideQv2rayCB->setChecked)
|
||||||
|
//
|
||||||
|
for (const auto &gid : ConnectionManager->AllGroups())
|
||||||
|
{
|
||||||
|
groupCombo->addItem(GetDisplayName(gid), gid.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportConfigWindow::UpdateColorScheme()
|
void ImportConfigWindow::UpdateColorScheme()
|
||||||
@ -54,23 +64,28 @@ QMultiHash<QString, CONFIGROOT> ImportConfigWindow::SelectConnection(bool outbou
|
|||||||
// false and disable the checkbox
|
// false and disable the checkbox
|
||||||
keepImportedInboundCheckBox->setEnabled(!outboundsOnly);
|
keepImportedInboundCheckBox->setEnabled(!outboundsOnly);
|
||||||
routeEditBtn->setEnabled(!outboundsOnly);
|
routeEditBtn->setEnabled(!outboundsOnly);
|
||||||
|
groupCombo->setEnabled(false);
|
||||||
this->exec();
|
this->exec();
|
||||||
QMultiHash<QString, CONFIGROOT> conn;
|
QMultiHash<QString, CONFIGROOT> conn;
|
||||||
for (const auto &connEntry : connections.values())
|
for (const auto &connEntry : connectionsToNewGroup.values())
|
||||||
|
{
|
||||||
|
conn += connEntry;
|
||||||
|
}
|
||||||
|
for (const auto &connEntry : connectionsToExistingGroup.values())
|
||||||
{
|
{
|
||||||
conn += connEntry;
|
conn += connEntry;
|
||||||
}
|
}
|
||||||
return result() == Accepted ? conn : QMultiHash<QString, CONFIGROOT>{};
|
return result() == Accepted ? conn : QMultiHash<QString, CONFIGROOT>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImportConfigWindow::ImportConnection()
|
int ImportConfigWindow::PerformImportConnection()
|
||||||
{
|
{
|
||||||
this->exec();
|
this->exec();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (const auto &groupName : connections.keys())
|
for (const auto &groupObject : connectionsToNewGroup)
|
||||||
{
|
{
|
||||||
GroupId groupId = groupName.isEmpty() ? DefaultGroupId : ConnectionManager->CreateGroup(groupName, false);
|
const auto groupName = connectionsToNewGroup.key(groupObject);
|
||||||
const auto groupObject = connections[groupName];
|
GroupId groupId = ConnectionManager->CreateGroup(groupName, false);
|
||||||
for (const auto &connConf : groupObject)
|
for (const auto &connConf : groupObject)
|
||||||
{
|
{
|
||||||
auto connName = groupObject.key(connConf);
|
auto connName = groupObject.key(connConf);
|
||||||
@ -84,6 +99,21 @@ int ImportConfigWindow::ImportConnection()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &groupObject : connectionsToExistingGroup)
|
||||||
|
{
|
||||||
|
const auto groupId = connectionsToExistingGroup.key(groupObject);
|
||||||
|
for (const auto &connConf : groupObject)
|
||||||
|
{
|
||||||
|
auto connName = groupObject.key(connConf);
|
||||||
|
auto [protocol, host, port] = GetConnectionInfo(connConf);
|
||||||
|
if (connName.isEmpty())
|
||||||
|
{
|
||||||
|
connName = protocol + "/" + host + ":" + QSTRN(port) + "-" + GenerateRandomString(5);
|
||||||
|
}
|
||||||
|
ConnectionManager->CreateConnection(connConf, connName, groupId, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +146,7 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
|
|||||||
if (_r == QDialog::Accepted)
|
if (_r == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
auto str = DecodeQRCode(pix);
|
auto str = DecodeQRCode(pix);
|
||||||
|
qrImageLabel->setPixmap(QPixmap::fromImage(pix));
|
||||||
if (str.trimmed().isEmpty())
|
if (str.trimmed().isEmpty())
|
||||||
{
|
{
|
||||||
LOG(MODULE_UI, "Cannot decode QR Code from an image, size: h=" + QSTRN(pix.width()) + ", v=" + QSTRN(pix.height()))
|
LOG(MODULE_UI, "Cannot decode QR Code from an image, size: h=" + QSTRN(pix.width()) + ", v=" + QSTRN(pix.height()))
|
||||||
@ -124,7 +154,7 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
|
qrCodeLinkTxt->setText(str.trimmed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +165,7 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
|
|||||||
|
|
||||||
switch (tabWidget->currentIndex())
|
switch (tabWidget->currentIndex())
|
||||||
{
|
{
|
||||||
case 0:
|
case LINK_PAGE:
|
||||||
{
|
{
|
||||||
QStringList linkList = SplitLines(vmessConnectionStringTxt->toPlainText());
|
QStringList linkList = SplitLines(vmessConnectionStringTxt->toPlainText());
|
||||||
//
|
//
|
||||||
@ -165,11 +195,19 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
|
|||||||
linkErrors[link] = QSTRN(linkErrors.count() + 1) + ": " + errMessage;
|
linkErrors[link] = QSTRN(linkErrors.count() + 1) + ": " + errMessage;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else if (newGroupName.isEmpty())
|
||||||
{
|
{
|
||||||
for (const auto &conf : config)
|
for (const auto &conf : config)
|
||||||
{
|
{
|
||||||
AddToGroup(newGroupName, config.key(conf), conf);
|
connectionsToExistingGroup[GroupId{ groupCombo->currentData().toString() }].insert(config.key(conf), conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
for (const auto &conf : config)
|
||||||
|
{
|
||||||
|
connectionsToNewGroup[newGroupName].insert(config.key(conf), conf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +227,26 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case QRCODE_PAGE:
|
||||||
|
{
|
||||||
|
QString errorMsg;
|
||||||
|
const auto root = ConvertConfigFromString(qrCodeLinkTxt->text(), &aliasPrefix, &errorMsg);
|
||||||
|
if (!errorMsg.isEmpty())
|
||||||
|
{
|
||||||
|
QvMessageBoxWarn(this, tr("Failed to import connection"), errorMsg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (const auto &conf : root)
|
||||||
|
{
|
||||||
|
connectionsToExistingGroup[GroupId{ groupCombo->currentData().toString() }].insert(root.key(conf), conf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MANUAL_PAGE:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ADVANCED_PAGE:
|
||||||
{
|
{
|
||||||
// From File...
|
// From File...
|
||||||
bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
|
bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
|
||||||
@ -203,7 +260,7 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
|
|||||||
|
|
||||||
aliasPrefix += "_" + QFileInfo(path).fileName();
|
aliasPrefix += "_" + QFileInfo(path).fileName();
|
||||||
CONFIGROOT config = ConvertConfigFromFile(path, ImportAsComplex);
|
CONFIGROOT config = ConvertConfigFromFile(path, ImportAsComplex);
|
||||||
AddToGroup("", aliasPrefix, config);
|
connectionsToExistingGroup[GroupId{ groupCombo->currentData().toString() }].insert(aliasPrefix, config);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,7 +332,7 @@ void ImportConfigWindow::on_connectionEditBtn_clicked()
|
|||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
root.insert("outbounds", outboundsList);
|
root.insert("outbounds", outboundsList);
|
||||||
//
|
//
|
||||||
AddToGroup("", alias, root);
|
connectionsToExistingGroup[GroupId{ groupCombo->currentData().toString() }].insert(alias, root);
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,12 +348,13 @@ void ImportConfigWindow::on_subscriptionButton_clicked()
|
|||||||
GroupManager w(this);
|
GroupManager w(this);
|
||||||
w.exec();
|
w.exec();
|
||||||
auto importToComplex = !keepImportedInboundCheckBox->isEnabled();
|
auto importToComplex = !keepImportedInboundCheckBox->isEnabled();
|
||||||
connections.clear();
|
connectionsToNewGroup.clear();
|
||||||
|
connectionsToExistingGroup.clear();
|
||||||
|
|
||||||
if (importToComplex)
|
if (importToComplex)
|
||||||
{
|
{
|
||||||
auto [alias, conf] = w.GetSelectedConfig();
|
auto [alias, conf] = w.GetSelectedConfig();
|
||||||
AddToGroup("", alias, conf);
|
connectionsToExistingGroup[GroupId{ groupCombo->currentData().toString() }].insert(alias, conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
accept();
|
accept();
|
||||||
@ -311,7 +369,7 @@ void ImportConfigWindow::on_routeEditBtn_clicked()
|
|||||||
|
|
||||||
if (isChanged)
|
if (isChanged)
|
||||||
{
|
{
|
||||||
AddToGroup("", alias, result);
|
connectionsToExistingGroup[GroupId{ groupCombo->currentData().toString() }].insert(alias, result);
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,7 +389,7 @@ void ImportConfigWindow::on_jsonEditBtn_clicked()
|
|||||||
|
|
||||||
if (isChanged)
|
if (isChanged)
|
||||||
{
|
{
|
||||||
AddToGroup("", alias, CONFIGROOT(result));
|
connectionsToExistingGroup[GroupId{ groupCombo->currentData().toString() }].insert(alias, CONFIGROOT(result));
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ class ImportConfigWindow
|
|||||||
public:
|
public:
|
||||||
explicit ImportConfigWindow(QWidget *parent = nullptr);
|
explicit ImportConfigWindow(QWidget *parent = nullptr);
|
||||||
~ImportConfigWindow();
|
~ImportConfigWindow();
|
||||||
int ImportConnection();
|
int PerformImportConnection();
|
||||||
QMultiHash<QString, CONFIGROOT> SelectConnection(bool outboundsOnly);
|
QMultiHash<QString, CONFIGROOT> SelectConnection(bool outboundsOnly);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -43,19 +43,8 @@ class ImportConfigWindow
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateColorScheme();
|
void UpdateColorScheme();
|
||||||
QMap<QString, QMultiHash<QString, CONFIGROOT>> connections;
|
|
||||||
QMap<QString, QString> linkErrors;
|
QMap<QString, QString> linkErrors;
|
||||||
void AddToGroup(const QString &groupName, const QString &alias, const CONFIGROOT &root)
|
//
|
||||||
{
|
QHash<GroupId, QMultiHash<QString, CONFIGROOT>> connectionsToExistingGroup;
|
||||||
if (connections.contains(groupName))
|
QHash<QString, QMultiHash<QString, CONFIGROOT>> connectionsToNewGroup;
|
||||||
{
|
|
||||||
connections[groupName].insert(alias, root);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QMultiHash<QString, CONFIGROOT> temp;
|
|
||||||
temp.insert(alias, root);
|
|
||||||
connections.insert(groupName, temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>522</width>
|
<width>549</width>
|
||||||
<height>460</height>
|
<height>482</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
@ -42,15 +42,18 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import To Group</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="groupCombo"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Import Source</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
@ -58,197 +61,193 @@
|
|||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="tabWidgetPage2">
|
<widget class="QWidget" name="tabWidgetPage2">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>VMess / QRCode</string>
|
<string>Link</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_8">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Connection Share Link</string>
|
<string>Share Link</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<widget class="QLabel" name="label_7">
|
||||||
<item row="1" column="0">
|
<property name="text">
|
||||||
<widget class="QPlainTextEdit" name="vmessConnectionStringTxt">
|
<string>Error List</string>
|
||||||
<property name="horizontalScrollBarPolicy">
|
</property>
|
||||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
</widget>
|
||||||
</property>
|
|
||||||
<property name="lineWrapMode">
|
|
||||||
<enum>QPlainTextEdit::NoWrap</enum>
|
|
||||||
</property>
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Paste share link here, one line for each.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QListWidget" name="errorsList"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Error List</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_8">
|
|
||||||
<property name="text">
|
|
||||||
<string>Share Link</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="0">
|
||||||
<layout class="QFormLayout" name="formLayout_3">
|
<widget class="QPlainTextEdit" name="vmessConnectionStringTxt">
|
||||||
<item row="0" column="0">
|
<property name="horizontalScrollBarPolicy">
|
||||||
<widget class="QLabel" name="label_5">
|
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>QRCode File</string>
|
<property name="lineWrapMode">
|
||||||
</property>
|
<enum>QPlainTextEdit::NoWrap</enum>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
<property name="placeholderText">
|
||||||
<item row="0" column="1">
|
<string>Paste share link here, one line for each.</string>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
</property>
|
||||||
<item>
|
</widget>
|
||||||
<widget class="QLineEdit" name="imageFileEdit">
|
</item>
|
||||||
<property name="text">
|
<item row="1" column="1">
|
||||||
<string/>
|
<widget class="QListWidget" name="errorsList"/>
|
||||||
</property>
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="selectImageBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Select</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_11">
|
|
||||||
<property name="text">
|
|
||||||
<string>Screenshot</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> secs</string>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>5.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.500000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>0.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>Delay</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="hideQv2rayCB">
|
|
||||||
<property name="text">
|
|
||||||
<string>Hide Qv2ray</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="qrFromScreenBtn">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Go</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="tabWidgetPage4">
|
<widget class="QWidget" name="tab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Subscriptions / Manually Input</string>
|
<string>QR Code</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QFormLayout" name="formLayout_4">
|
<layout class="QFormLayout" name="formLayout_3">
|
||||||
<item row="1" column="1">
|
<item row="0" column="0">
|
||||||
<widget class="QPushButton" name="subscriptionButton">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open Subscription Manager</string>
|
<string>QRCode File</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="0" column="1">
|
||||||
<widget class="Line" name="line">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="imageFileEdit">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="selectImageBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Screenshot</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="hideQv2rayCB">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hide Qv2ray</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> secs</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>5.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.500000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Delay</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="qrFromScreenBtn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Go</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Image</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="qrImageLabel">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>10</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="label_16">
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Manually Input Connections</string>
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Detected Link</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="qrCodeLinkTxt">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Input Manually</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QFormLayout" name="formLayout_4">
|
||||||
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_12">
|
<widget class="QLabel" name="label_12">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Connection Editor</string>
|
<string>Simple Editor</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QPushButton" name="connectionEditBtn">
|
<widget class="QPushButton" name="connectionEditBtn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open Connection Editor</string>
|
<string>Open Connection Editor</string>
|
||||||
@ -258,51 +257,27 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_15">
|
<widget class="QLabel" name="label_15">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Route Editor</string>
|
<string>Complex Editor</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QPushButton" name="routeEditBtn">
|
<widget class="QPushButton" name="routeEditBtn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open Route Editor</string>
|
<string>Open Route / Complex Connection Editor</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="autoDefault">
|
<property name="autoDefault">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Json Editor</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="1">
|
|
||||||
<widget class="QPushButton" name="jsonEditBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Open JSON Editor</string>
|
|
||||||
</property>
|
|
||||||
<property name="autoDefault">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="text">
|
|
||||||
<string>Subscription Manager</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QLabel" name="label_14">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Subscription Link</string>
|
<string>You can manually input connection here.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -310,17 +285,24 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="tabWidgetPage1">
|
<widget class="QWidget" name="tabWidgetPage1">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Existing File</string>
|
<string>Advanced</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QFormLayout" name="formLayout">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_16">
|
||||||
|
<property name="text">
|
||||||
|
<string>Manually Input Connections</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="fileLabel">
|
<widget class="QLabel" name="fileLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Path</string>
|
<string>Path</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="1" column="1">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="fileLineTxt">
|
<widget class="QLineEdit" name="fileLineTxt">
|
||||||
@ -338,13 +320,30 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0" colspan="2">
|
<item row="2" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="keepImportedInboundCheckBox">
|
<widget class="QCheckBox" name="keepImportedInboundCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Import as Complex Config (Manually edit route rules and inbounds)</string>
|
<string>Import as Complex Config (Manually edit route rules and inbounds)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Json Editor</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QPushButton" name="jsonEditBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open JSON Editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
@ -384,21 +383,10 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>nameTxt</tabstop>
|
<tabstop>nameTxt</tabstop>
|
||||||
<tabstop>tabWidget</tabstop>
|
|
||||||
<tabstop>vmessConnectionStringTxt</tabstop>
|
<tabstop>vmessConnectionStringTxt</tabstop>
|
||||||
<tabstop>errorsList</tabstop>
|
<tabstop>errorsList</tabstop>
|
||||||
<tabstop>imageFileEdit</tabstop>
|
|
||||||
<tabstop>selectImageBtn</tabstop>
|
|
||||||
<tabstop>doubleSpinBox</tabstop>
|
|
||||||
<tabstop>hideQv2rayCB</tabstop>
|
|
||||||
<tabstop>qrFromScreenBtn</tabstop>
|
|
||||||
<tabstop>subscriptionButton</tabstop>
|
|
||||||
<tabstop>connectionEditBtn</tabstop>
|
|
||||||
<tabstop>routeEditBtn</tabstop>
|
|
||||||
<tabstop>jsonEditBtn</tabstop>
|
|
||||||
<tabstop>fileLineTxt</tabstop>
|
<tabstop>fileLineTxt</tabstop>
|
||||||
<tabstop>selectFileBtn</tabstop>
|
<tabstop>selectFileBtn</tabstop>
|
||||||
<tabstop>keepImportedInboundCheckBox</tabstop>
|
|
||||||
<tabstop>beginImportBtn</tabstop>
|
<tabstop>beginImportBtn</tabstop>
|
||||||
<tabstop>cancelImportBtn</tabstop>
|
<tabstop>cancelImportBtn</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
|
@ -576,7 +576,7 @@ void MainWindow::on_action_RCM_DeleteThese_triggered()
|
|||||||
void MainWindow::on_importConfigButton_clicked()
|
void MainWindow::on_importConfigButton_clicked()
|
||||||
{
|
{
|
||||||
ImportConfigWindow w(this);
|
ImportConfigWindow w(this);
|
||||||
w.ImportConnection();
|
w.PerformImportConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_action_RCM_EditAsComplex_triggered()
|
void MainWindow::on_action_RCM_EditAsComplex_triggered()
|
||||||
|
@ -86,7 +86,7 @@
|
|||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../resources.qrc">
|
<iconset resource="../../../resources.qrc">
|
||||||
<normaloff>:/assets/icons/ui_light/locate.png</normaloff>:/assets/icons/ui_light/locate.png</iconset>
|
<normaloff>:/assets/icons/ui_light/locate.png</normaloff>:/assets/icons/ui_light/locate.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../resources.qrc">
|
<iconset resource="../../../resources.qrc">
|
||||||
<normaloff>:/assets/icons/ui_light/sort.png</normaloff>:/assets/icons/ui_light/sort.png</iconset>
|
<normaloff>:/assets/icons/ui_light/sort.png</normaloff>:/assets/icons/ui_light/sort.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="popupMode">
|
<property name="popupMode">
|
||||||
@ -291,7 +291,7 @@
|
|||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../resources.qrc">
|
<iconset resource="../../../resources.qrc">
|
||||||
<normaloff>:/assets/icons/ui_light/delete.png</normaloff>:/assets/icons/ui_light/delete.png</iconset>
|
<normaloff>:/assets/icons/ui_light/delete.png</normaloff>:/assets/icons/ui_light/delete.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -354,7 +354,7 @@
|
|||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../resources.qrc">
|
<iconset resource="../../../resources.qrc">
|
||||||
<normaloff>:/assets/icons/ui_light/delete.png</normaloff>:/assets/icons/ui_light/delete.png</iconset>
|
<normaloff>:/assets/icons/ui_light/delete.png</normaloff>:/assets/icons/ui_light/delete.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -538,7 +538,7 @@
|
|||||||
<tabstop>importConfigButton</tabstop>
|
<tabstop>importConfigButton</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../resources.qrc"/>
|
<include location="../../../resources.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
Loading…
Reference in New Issue
Block a user