Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71a67d7dca | ||
|
|
8063b6d4e8 |
@@ -7,3 +7,6 @@ lite/.claude/
|
|||||||
lite/backups/
|
lite/backups/
|
||||||
lite/build/
|
lite/build/
|
||||||
lite/dist/
|
lite/dist/
|
||||||
|
lite/RELEASE_WORKFLOW.md
|
||||||
|
*.bak
|
||||||
|
*.bak-*
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "999909171702",
|
"version": "999909181618",
|
||||||
"pac_base_url": "https://cdn.rrrosmontis.icu/RRPP/PAC/",
|
"pac_base_url": "https://cdn.rrrosmontis.icu/RRPP/PAC/",
|
||||||
"nodes_url": "https://api.rrrosmontis.icu/v1/rrpp/subscription?method=rrpp_client",
|
"nodes_url": "https://api.rrrosmontis.icu/v1/rrpp/subscription?method=rrpp_client",
|
||||||
"update_url": "https://git.rrrosmontis.icu/api/v1/repos/RoyirinRosmontis/Private-Proxy/releases/latest"
|
"update_url": "https://git.rrrosmontis.icu/api/v1/repos/RoyirinRosmontis/Private-Proxy/releases/latest"
|
||||||
|
|||||||
+736
-61
File diff suppressed because it is too large
Load Diff
+395
-5
@@ -6,7 +6,7 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal
|
from PyQt5.QtCore import Qt, pyqtSignal
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QDialog, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
QComboBox, QDialog, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
||||||
QPushButton, QVBoxLayout, QWidget,
|
QPushButton, QVBoxLayout, QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -292,6 +292,379 @@ class WhitelistDialog(QDialog):
|
|||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class FixedRouteServices:
|
||||||
|
"""域名路由编辑框所需的规则与节点服务。"""
|
||||||
|
|
||||||
|
load_icon: object
|
||||||
|
load_rules: object
|
||||||
|
available_nodes: object
|
||||||
|
validate_domain: object
|
||||||
|
save_rules: object
|
||||||
|
|
||||||
|
|
||||||
|
class FixedRouteDialog(QDialog):
|
||||||
|
"""为域名配置强制直连或指定节点代理。"""
|
||||||
|
|
||||||
|
def __init__(self, services: FixedRouteServices, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self._services = services
|
||||||
|
self.setWindowTitle("域名路由")
|
||||||
|
self.setWindowIcon(services.load_icon())
|
||||||
|
self.setFixedSize(620, 530)
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
QDialog {{ background-color: {C_BG}; }}
|
||||||
|
QLabel {{ color: {C_TEXT}; font-family: "Microsoft YaHei", "Segoe UI", sans-serif; font-size: 12px; }}
|
||||||
|
QLineEdit, QComboBox {{ background-color: {C_CARD}; border: 1px solid {C_BORDER}; border-radius: 6px;
|
||||||
|
padding: 5px 8px; color: {C_TEXT}; font-size: 12px; }}
|
||||||
|
QListWidget {{ background-color: {C_CARD}; border: 1px solid {C_BORDER}; border-radius: 6px;
|
||||||
|
padding: 4px; color: {C_TEXT}; font-size: 12px; }}
|
||||||
|
QListWidget::item {{ padding: 5px 7px; border-radius: 4px; }}
|
||||||
|
QListWidget::item:selected {{ background-color: #e3e8ee; color: {C_TEXT}; }}
|
||||||
|
QPushButton#btnOk {{ background-color: {C_GREEN}; color: #fff; border: none;
|
||||||
|
border-radius: 6px; padding: 5px 12px; font-size: 12px; font-weight: bold; }}
|
||||||
|
QPushButton#btnOk:hover {{ background-color: #5ed978; }}
|
||||||
|
QPushButton#btnSmall {{ background-color: {C_CARD}; color: {C_SUBTEXT}; border: 1px solid {C_BORDER};
|
||||||
|
border-radius: 6px; padding: 4px 10px; font-size: 11px; }}
|
||||||
|
QPushButton#btnSmall:hover {{ background-color: #e3e8ee; color: {C_TEXT}; }}
|
||||||
|
""")
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setSpacing(9)
|
||||||
|
layout.setContentsMargins(18, 14, 18, 14)
|
||||||
|
|
||||||
|
title = QLabel("域名路由")
|
||||||
|
title.setStyleSheet(f"color: {C_TITLE}; font-size: 15px; font-weight: bold;")
|
||||||
|
title.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(title)
|
||||||
|
hint = QLabel("example.com 匹配根域及子域;*.example.com 仅匹配子域")
|
||||||
|
hint.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 11px;")
|
||||||
|
hint.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(hint)
|
||||||
|
|
||||||
|
self.lb_err = QLabel("")
|
||||||
|
self.lb_err.setStyleSheet(f"color: {C_RED}; font-size: 11px;")
|
||||||
|
self.lb_err.setFixedHeight(16)
|
||||||
|
self.lb_err.hide()
|
||||||
|
layout.addWidget(self.lb_err)
|
||||||
|
|
||||||
|
self.list_widget = QListWidget()
|
||||||
|
self.list_widget.setToolTip("勾选启用规则;选中后可删除")
|
||||||
|
layout.addWidget(self.list_widget, 1)
|
||||||
|
|
||||||
|
domain_row = QHBoxLayout()
|
||||||
|
domain_row.setSpacing(7)
|
||||||
|
self.ed_domain = QLineEdit()
|
||||||
|
self.ed_domain.setPlaceholderText("域名,如 example.com 或 *.example.com")
|
||||||
|
self.ed_domain.returnPressed.connect(self._add_rule)
|
||||||
|
domain_row.addWidget(self.ed_domain, 1)
|
||||||
|
self.cb_action = QComboBox()
|
||||||
|
self.cb_action.addItem("强制不代理", "direct")
|
||||||
|
self.cb_action.addItem("强制节点代理", "node")
|
||||||
|
self.cb_action.currentIndexChanged.connect(self._on_action_changed)
|
||||||
|
domain_row.addWidget(self.cb_action)
|
||||||
|
self.cb_node = QComboBox()
|
||||||
|
self.cb_node.setMinimumWidth(190)
|
||||||
|
domain_row.addWidget(self.cb_node)
|
||||||
|
self.btn_add = QPushButton("添加")
|
||||||
|
self.btn_add.setObjectName("btnOk")
|
||||||
|
self.btn_add.clicked.connect(self._add_rule)
|
||||||
|
domain_row.addWidget(self.btn_add)
|
||||||
|
layout.addLayout(domain_row)
|
||||||
|
|
||||||
|
middle = QHBoxLayout()
|
||||||
|
self.btn_delete = QPushButton("删除选中")
|
||||||
|
self.btn_delete.setObjectName("btnSmall")
|
||||||
|
self.btn_delete.clicked.connect(self._delete_selected)
|
||||||
|
middle.addWidget(self.btn_delete)
|
||||||
|
middle.addStretch()
|
||||||
|
layout.addLayout(middle)
|
||||||
|
|
||||||
|
buttons = QHBoxLayout()
|
||||||
|
buttons.addStretch()
|
||||||
|
self.btn_cancel = QPushButton("取消")
|
||||||
|
self.btn_cancel.setObjectName("btnSmall")
|
||||||
|
self.btn_cancel.clicked.connect(self.reject)
|
||||||
|
buttons.addWidget(self.btn_cancel)
|
||||||
|
self.btn_save = QPushButton("保存")
|
||||||
|
self.btn_save.setObjectName("btnOk")
|
||||||
|
self.btn_save.clicked.connect(self._save)
|
||||||
|
buttons.addWidget(self.btn_save)
|
||||||
|
layout.addLayout(buttons)
|
||||||
|
|
||||||
|
self._reload_nodes()
|
||||||
|
for rule in services.load_rules():
|
||||||
|
self._add_item(rule)
|
||||||
|
self._on_action_changed()
|
||||||
|
|
||||||
|
def _reload_nodes(self):
|
||||||
|
self.cb_node.clear()
|
||||||
|
for node in self._services.available_nodes():
|
||||||
|
self.cb_node.addItem(node["label"], node["ref"])
|
||||||
|
if not self.cb_node.count():
|
||||||
|
self.cb_node.addItem("暂无可用节点", None)
|
||||||
|
|
||||||
|
def _on_action_changed(self, *_):
|
||||||
|
self.cb_node.setEnabled(self.cb_action.currentData() == "node")
|
||||||
|
|
||||||
|
def _add_item(self, rule):
|
||||||
|
domain = str(rule.get("domain") or rule.get("value") or "").strip()
|
||||||
|
if not domain:
|
||||||
|
return
|
||||||
|
action = str(rule.get("action") or "direct")
|
||||||
|
node_label = str(rule.get("node_label") or "节点不可用")
|
||||||
|
target = "强制不代理" if action == "direct" else f"节点代理:{node_label}"
|
||||||
|
item = QListWidgetItem(f"{domain} → {target}")
|
||||||
|
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||||
|
item.setCheckState(Qt.Checked if rule.get("enabled", True) else Qt.Unchecked)
|
||||||
|
item.setData(Qt.UserRole, {
|
||||||
|
"domain": domain,
|
||||||
|
"action": action,
|
||||||
|
"node_ref": str(rule.get("node_ref") or ""),
|
||||||
|
})
|
||||||
|
self.list_widget.addItem(item)
|
||||||
|
|
||||||
|
def _add_rule(self):
|
||||||
|
domain, error = self._services.validate_domain(self.ed_domain.text())
|
||||||
|
if error:
|
||||||
|
self.lb_err.setText(error)
|
||||||
|
self.lb_err.show()
|
||||||
|
return
|
||||||
|
action = self.cb_action.currentData()
|
||||||
|
node_ref = self.cb_node.currentData() if action == "node" else ""
|
||||||
|
if action == "node" and not node_ref:
|
||||||
|
self.lb_err.setText("请先配置至少一个可用节点")
|
||||||
|
self.lb_err.show()
|
||||||
|
return
|
||||||
|
for index in range(self.list_widget.count()):
|
||||||
|
existing = self.list_widget.item(index).data(Qt.UserRole) or {}
|
||||||
|
if str(existing.get("domain") or "").lower() == domain.lower():
|
||||||
|
self.lb_err.setText("该域名规则已存在")
|
||||||
|
self.lb_err.show()
|
||||||
|
return
|
||||||
|
self.lb_err.hide()
|
||||||
|
self._add_item({
|
||||||
|
"domain": domain,
|
||||||
|
"action": action,
|
||||||
|
"node_ref": node_ref,
|
||||||
|
"node_label": self.cb_node.currentText() if action == "node" else "",
|
||||||
|
"enabled": True,
|
||||||
|
})
|
||||||
|
self.ed_domain.clear()
|
||||||
|
|
||||||
|
def _delete_selected(self):
|
||||||
|
for item in self.list_widget.selectedItems():
|
||||||
|
self.list_widget.takeItem(self.list_widget.row(item))
|
||||||
|
|
||||||
|
def _save(self):
|
||||||
|
rules = []
|
||||||
|
for index in range(self.list_widget.count()):
|
||||||
|
item = self.list_widget.item(index)
|
||||||
|
rule = dict(item.data(Qt.UserRole) or {})
|
||||||
|
rule["enabled"] = item.checkState() == Qt.Checked
|
||||||
|
rules.append(rule)
|
||||||
|
self._services.save_rules(rules)
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class JumpServices:
|
||||||
|
"""代理跳板管理所需的节点摘要与配置回调。"""
|
||||||
|
|
||||||
|
load_icon: object
|
||||||
|
load_profiles: object
|
||||||
|
available_nodes: object
|
||||||
|
add_profile: object
|
||||||
|
remove_profile: object
|
||||||
|
|
||||||
|
|
||||||
|
class JumpDialog(QDialog):
|
||||||
|
"""配置最多三跳的节点链路;设置中只保存节点稳定标识。"""
|
||||||
|
|
||||||
|
def __init__(self, services: JumpServices, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self._services = services
|
||||||
|
self.setWindowTitle("代理跳板")
|
||||||
|
self.setWindowIcon(services.load_icon())
|
||||||
|
self.setFixedSize(560, 520)
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
QDialog {{ background-color: {C_BG}; }}
|
||||||
|
QLabel {{ color: {C_TEXT}; font-family: "Microsoft YaHei", "Segoe UI", sans-serif; font-size: 12px; }}
|
||||||
|
QListWidget {{ background-color: {C_CARD}; border: 1px solid {C_BORDER}; border-radius: 6px;
|
||||||
|
padding: 4px; color: {C_TEXT}; font-size: 12px; }}
|
||||||
|
QListWidget::item {{ padding: 5px 7px; border-radius: 4px; }}
|
||||||
|
QListWidget::item:selected {{ background-color: #e3e8ee; color: {C_TEXT}; }}
|
||||||
|
QPushButton#btnOk {{ background-color: {C_GREEN}; color: #fff; border: none;
|
||||||
|
border-radius: 6px; padding: 5px 12px; font-size: 12px; font-weight: bold; }}
|
||||||
|
QPushButton#btnOk:hover {{ background-color: #5ed978; }}
|
||||||
|
QPushButton#btnDanger {{ background-color: {C_RED}; color: #fff; border: none;
|
||||||
|
border-radius: 6px; padding: 5px 12px; font-size: 12px; font-weight: bold; }}
|
||||||
|
QPushButton#btnSmall {{ background-color: {C_CARD}; color: {C_SUBTEXT}; border: 1px solid {C_BORDER};
|
||||||
|
border-radius: 6px; padding: 4px 10px; font-size: 11px; }}
|
||||||
|
QPushButton#btnSmall:hover {{ background-color: #e3e8ee; color: {C_TEXT}; }}
|
||||||
|
""")
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setSpacing(8)
|
||||||
|
layout.setContentsMargins(18, 14, 18, 14)
|
||||||
|
|
||||||
|
title = QLabel("代理跳板")
|
||||||
|
title.setStyleSheet(f"color: {C_TITLE}; font-size: 15px; font-weight: bold;")
|
||||||
|
title.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(title)
|
||||||
|
hint = QLabel("按顺序加入节点,至少 2 个、最多 3 个;最后一个节点是出口")
|
||||||
|
hint.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 11px;")
|
||||||
|
hint.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(hint)
|
||||||
|
|
||||||
|
saved_label = QLabel("已保存跳板")
|
||||||
|
saved_label.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 11px;")
|
||||||
|
layout.addWidget(saved_label)
|
||||||
|
self.profiles = QListWidget()
|
||||||
|
self.profiles.setFixedHeight(68)
|
||||||
|
self.profiles.setToolTip("选择已保存跳板后可删除;新链路在下方配置")
|
||||||
|
layout.addWidget(self.profiles)
|
||||||
|
|
||||||
|
columns = QHBoxLayout()
|
||||||
|
columns.setSpacing(8)
|
||||||
|
left = QVBoxLayout()
|
||||||
|
left.addWidget(QLabel("当前可用节点"))
|
||||||
|
self.available = QListWidget()
|
||||||
|
self.available.setToolTip("选择节点后点击“加入链路”")
|
||||||
|
left.addWidget(self.available, 1)
|
||||||
|
columns.addLayout(left, 1)
|
||||||
|
|
||||||
|
middle = QVBoxLayout()
|
||||||
|
middle.addStretch()
|
||||||
|
self.btn_add_node = QPushButton("加入链路 →")
|
||||||
|
self.btn_add_node.setObjectName("btnSmall")
|
||||||
|
self.btn_add_node.clicked.connect(self._add_node)
|
||||||
|
middle.addWidget(self.btn_add_node)
|
||||||
|
self.btn_remove_node = QPushButton("← 移除")
|
||||||
|
self.btn_remove_node.setObjectName("btnSmall")
|
||||||
|
self.btn_remove_node.clicked.connect(self._remove_node)
|
||||||
|
middle.addWidget(self.btn_remove_node)
|
||||||
|
middle.addStretch()
|
||||||
|
columns.addLayout(middle)
|
||||||
|
|
||||||
|
right = QVBoxLayout()
|
||||||
|
right.addWidget(QLabel("新跳板链路"))
|
||||||
|
self.route = QListWidget()
|
||||||
|
self.route.setToolTip("顺序即连接顺序;可用上下按钮调整")
|
||||||
|
right.addWidget(self.route, 1)
|
||||||
|
reorder = QHBoxLayout()
|
||||||
|
self.btn_up = QPushButton("上移")
|
||||||
|
self.btn_up.setObjectName("btnSmall")
|
||||||
|
self.btn_up.clicked.connect(lambda: self._move_node(-1))
|
||||||
|
reorder.addWidget(self.btn_up)
|
||||||
|
self.btn_down = QPushButton("下移")
|
||||||
|
self.btn_down.setObjectName("btnSmall")
|
||||||
|
self.btn_down.clicked.connect(lambda: self._move_node(1))
|
||||||
|
reorder.addWidget(self.btn_down)
|
||||||
|
right.addLayout(reorder)
|
||||||
|
columns.addLayout(right, 1)
|
||||||
|
layout.addLayout(columns, 1)
|
||||||
|
|
||||||
|
self.lb_status = QLabel("")
|
||||||
|
self.lb_status.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 11px;")
|
||||||
|
self.lb_status.setFixedHeight(16)
|
||||||
|
layout.addWidget(self.lb_status)
|
||||||
|
|
||||||
|
actions = QHBoxLayout()
|
||||||
|
self.btn_add_profile = QPushButton("添加")
|
||||||
|
self.btn_add_profile.setObjectName("btnOk")
|
||||||
|
self.btn_add_profile.clicked.connect(self._add_profile)
|
||||||
|
actions.addWidget(self.btn_add_profile)
|
||||||
|
self.btn_delete_profile = QPushButton("删除选中跳板")
|
||||||
|
self.btn_delete_profile.setObjectName("btnDanger")
|
||||||
|
self.btn_delete_profile.clicked.connect(self._delete_profile)
|
||||||
|
actions.addWidget(self.btn_delete_profile)
|
||||||
|
actions.addStretch()
|
||||||
|
self.btn_close = QPushButton("关闭")
|
||||||
|
self.btn_close.setObjectName("btnSmall")
|
||||||
|
self.btn_close.clicked.connect(self.accept)
|
||||||
|
actions.addWidget(self.btn_close)
|
||||||
|
layout.addLayout(actions)
|
||||||
|
|
||||||
|
self._reload()
|
||||||
|
|
||||||
|
def _reload(self):
|
||||||
|
self.available.clear()
|
||||||
|
for node in self._services.available_nodes():
|
||||||
|
item = QListWidgetItem(node["label"])
|
||||||
|
item.setData(Qt.UserRole, node["ref"])
|
||||||
|
self.available.addItem(item)
|
||||||
|
self.profiles.clear()
|
||||||
|
for profile in self._services.load_profiles():
|
||||||
|
state = "可用" if profile.get("available") else "节点不可用"
|
||||||
|
item = QListWidgetItem(f"{profile['name']} · {profile['route']} · {state}")
|
||||||
|
item.setData(Qt.UserRole, profile["id"])
|
||||||
|
self.profiles.addItem(item)
|
||||||
|
self.route.clear()
|
||||||
|
self.lb_status.setText("")
|
||||||
|
|
||||||
|
def _add_node(self):
|
||||||
|
item = self.available.currentItem()
|
||||||
|
if item is None:
|
||||||
|
self._status("请先选择一个节点", error=True)
|
||||||
|
return
|
||||||
|
ref = item.data(Qt.UserRole)
|
||||||
|
refs = {self.route.item(i).data(Qt.UserRole) for i in range(self.route.count())}
|
||||||
|
if ref in refs:
|
||||||
|
self._status("同一条链路不能重复使用节点", error=True)
|
||||||
|
return
|
||||||
|
if self.route.count() >= 3:
|
||||||
|
self._status("最多只能配置 3 个节点", error=True)
|
||||||
|
return
|
||||||
|
copy = QListWidgetItem(item.text())
|
||||||
|
copy.setData(Qt.UserRole, ref)
|
||||||
|
self.route.addItem(copy)
|
||||||
|
self._status(f"当前链路:{self.route.count()} 个节点")
|
||||||
|
|
||||||
|
def _remove_node(self):
|
||||||
|
item = self.route.currentItem()
|
||||||
|
if item is not None:
|
||||||
|
self.route.takeItem(self.route.row(item))
|
||||||
|
|
||||||
|
def _move_node(self, offset):
|
||||||
|
row = self.route.currentRow()
|
||||||
|
new_row = row + offset
|
||||||
|
if row < 0 or not 0 <= new_row < self.route.count():
|
||||||
|
return
|
||||||
|
item = self.route.takeItem(row)
|
||||||
|
self.route.insertItem(new_row, item)
|
||||||
|
self.route.setCurrentRow(new_row)
|
||||||
|
|
||||||
|
def _add_profile(self):
|
||||||
|
if not 2 <= self.route.count() <= 3:
|
||||||
|
self._status("请先配置 2-3 个节点的链路", error=True)
|
||||||
|
return
|
||||||
|
refs = [self.route.item(i).data(Qt.UserRole) for i in range(self.route.count())]
|
||||||
|
try:
|
||||||
|
self._services.add_profile(refs)
|
||||||
|
except Exception as error:
|
||||||
|
self._status(str(error), error=True)
|
||||||
|
return
|
||||||
|
self._reload()
|
||||||
|
self._status("跳板已添加")
|
||||||
|
|
||||||
|
def _delete_profile(self):
|
||||||
|
item = self.profiles.currentItem()
|
||||||
|
if item is None:
|
||||||
|
self._status("请先选择要删除的跳板", error=True)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self._services.remove_profile(item.data(Qt.UserRole))
|
||||||
|
except Exception as error:
|
||||||
|
self._status(str(error), error=True)
|
||||||
|
return
|
||||||
|
self._reload()
|
||||||
|
self._status("跳板已删除")
|
||||||
|
|
||||||
|
def _status(self, message, error=False):
|
||||||
|
self.lb_status.setText(message)
|
||||||
|
color = C_RED if error else C_GREEN
|
||||||
|
self.lb_status.setStyleSheet(f"color: {color}; font-size: 11px;")
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ThirdPartyServices:
|
class ThirdPartyServices:
|
||||||
"""第三方订阅管理框所需的显式业务服务。"""
|
"""第三方订阅管理框所需的显式业务服务。"""
|
||||||
@@ -475,6 +848,7 @@ class SettingsServices:
|
|||||||
set_update_via_proxy: object
|
set_update_via_proxy: object
|
||||||
set_skip_update_check: object
|
set_skip_update_check: object
|
||||||
open_whitelist: object
|
open_whitelist: object
|
||||||
|
open_jump: object
|
||||||
open_third_party: object
|
open_third_party: object
|
||||||
has_login: object
|
has_login: object
|
||||||
open_login: object
|
open_login: object
|
||||||
@@ -482,14 +856,14 @@ class SettingsServices:
|
|||||||
|
|
||||||
|
|
||||||
class SettingsDialog(QDialog):
|
class SettingsDialog(QDialog):
|
||||||
"""代理端口、更新方式、白名单与登录状态设置框。"""
|
"""代理端口、更新方式、域名路由与登录状态设置框。"""
|
||||||
|
|
||||||
def __init__(self, services: SettingsServices, parent=None, port_locked=False):
|
def __init__(self, services: SettingsServices, parent=None, port_locked=False):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._services = services
|
self._services = services
|
||||||
self.setWindowTitle("设置")
|
self.setWindowTitle("设置")
|
||||||
self.setWindowIcon(services.load_icon())
|
self.setWindowIcon(services.load_icon())
|
||||||
self.setFixedSize(300, 396)
|
self.setFixedSize(300, 430)
|
||||||
self.setStyleSheet(f"""
|
self.setStyleSheet(f"""
|
||||||
QDialog {{ background-color: {C_BG}; }}
|
QDialog {{ background-color: {C_BG}; }}
|
||||||
QLabel {{ color: {C_TEXT}; font-family: "Microsoft YaHei", "Segoe UI", sans-serif; font-size: 12px; }}
|
QLabel {{ color: {C_TEXT}; font-family: "Microsoft YaHei", "Segoe UI", sans-serif; font-size: 12px; }}
|
||||||
@@ -528,9 +902,9 @@ class SettingsDialog(QDialog):
|
|||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
|
|
||||||
whitelist_row = QHBoxLayout()
|
whitelist_row = QHBoxLayout()
|
||||||
whitelist_label = QLabel("代理白名单")
|
whitelist_label = QLabel("域名路由")
|
||||||
whitelist_label.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 12px;")
|
whitelist_label.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 12px;")
|
||||||
whitelist_label.setToolTip("命中列表的域名 / IP 将强制直连(不经过代理),每条规则可单独启用")
|
whitelist_label.setToolTip("为域名配置强制不代理,或强制经过指定节点;支持 *.example.com")
|
||||||
whitelist_row.addWidget(whitelist_label)
|
whitelist_row.addWidget(whitelist_label)
|
||||||
whitelist_row.addStretch()
|
whitelist_row.addStretch()
|
||||||
self.btn_whitelist = QPushButton("配置")
|
self.btn_whitelist = QPushButton("配置")
|
||||||
@@ -544,6 +918,19 @@ class SettingsDialog(QDialog):
|
|||||||
whitelist_row.addWidget(self.btn_whitelist)
|
whitelist_row.addWidget(self.btn_whitelist)
|
||||||
layout.addLayout(whitelist_row)
|
layout.addLayout(whitelist_row)
|
||||||
|
|
||||||
|
jump_row = QHBoxLayout()
|
||||||
|
jump_label = QLabel("代理跳板")
|
||||||
|
jump_label.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 12px;")
|
||||||
|
jump_label.setToolTip("把当前可用节点串成 2-3 跳链路;最后一个节点作为对外出口")
|
||||||
|
jump_row.addWidget(jump_label)
|
||||||
|
jump_row.addStretch()
|
||||||
|
self.btn_jump = QPushButton("添加")
|
||||||
|
self.btn_jump.setCursor(Qt.PointingHandCursor)
|
||||||
|
self.btn_jump.setStyleSheet(self.btn_whitelist.styleSheet())
|
||||||
|
self.btn_jump.clicked.connect(self._open_jump)
|
||||||
|
jump_row.addWidget(self.btn_jump)
|
||||||
|
layout.addLayout(jump_row)
|
||||||
|
|
||||||
third_party_row = QHBoxLayout()
|
third_party_row = QHBoxLayout()
|
||||||
third_party_label = QLabel("第三方")
|
third_party_label = QLabel("第三方")
|
||||||
third_party_label.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 12px;")
|
third_party_label.setStyleSheet(f"color: {C_SUBTEXT}; font-size: 12px;")
|
||||||
@@ -636,6 +1023,9 @@ class SettingsDialog(QDialog):
|
|||||||
def _open_whitelist(self):
|
def _open_whitelist(self):
|
||||||
self._services.open_whitelist(self)
|
self._services.open_whitelist(self)
|
||||||
|
|
||||||
|
def _open_jump(self):
|
||||||
|
self._services.open_jump(self)
|
||||||
|
|
||||||
def _open_third_party(self):
|
def _open_third_party(self):
|
||||||
self._services.open_third_party(self)
|
self._services.open_third_party(self)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user