Squashed commit of the following:

commit 8724c545a8af8f34565aa71620e66cbd71547f37
Author: DLmaster <DLmaster_361@163.com>
Date:   Fri Apr 11 18:08:28 2025 +0800

    feat(core): 预接入mirrorc

commit d57ebaa281ff7c418aa8f11fe8e8ba260d8dbeca
Author: DLmaster <DLmaster_361@163.com>
Date:   Thu Apr 10 12:37:26 2025 +0800

    chore(core): 基础配置相关内容重构

    - 添加理智药设置选项 #34
    - 输入对话框添加回车键确认能力 #35
    - 用户列表UI改版升级
    - 配置类取消单例限制
    - 配置读取方式与界面渲染方法优化

commit 710542287d04719c8443b91acb227de1dccc20d0
Author: DLmaster <DLmaster_361@163.com>
Date:   Fri Mar 28 23:32:17 2025 +0800

    chore(core): search相关结构重整

commit 8009c69236655e29119ce62ff53a0360abaed2af
Merge: 648f42b 9f88f92
Author: DLmaster <DLmaster_361@163.com>
Date:   Mon Mar 24 15:31:40 2025 +0800

    Merge branch 'dev' into user_list_dev
This commit is contained in:
DLmaster
2025-04-11 18:57:10 +08:00
parent bded794647
commit 38a04fc4b2
21 changed files with 3759 additions and 3018 deletions

View File

@@ -46,12 +46,13 @@ from qfluentwidgets import (
FluentIconBase,
Signal,
ComboBox,
EditableComboBox,
CheckBox,
IconWidget,
FluentIcon,
CardWidget,
BodyLabel,
qconfig,
QConfig,
ConfigItem,
TimeEdit,
OptionsConfigItem,
@@ -65,22 +66,27 @@ from qfluentwidgets import (
ProgressRing,
TextBrowser,
HeaderCardWidget,
SwitchButton,
IndicatorPosition,
Slider,
)
from qfluentwidgets.common.overload import singledispatchmethod
import os
import re
import markdown
from datetime import datetime
from urllib.parse import urlparse
from functools import partial
from typing import Optional, Union, List, Dict
from app.core import Config
from app.services import Crypto
class LineEditMessageBox(MessageBoxBase):
"""输入对话框"""
def __init__(self, parent, title: str, content: str, mode: str):
def __init__(self, parent, title: str, content: Union[str, None], mode: str):
super().__init__(parent)
self.title = SubtitleLabel(title)
@@ -90,6 +96,7 @@ class LineEditMessageBox(MessageBoxBase):
elif mode == "密码":
self.input = PasswordLineEdit()
self.input.returnPressed.connect(self.yesButton.click)
self.input.setPlaceholderText(content)
# 将组件添加到布局中
@@ -248,6 +255,143 @@ class NoticeMessageBox(MessageBoxBase):
self.Layout.addStretch(1)
class SwitchSettingCard(SettingCard):
"""Setting card with switch button"""
checkedChanged = Signal(bool)
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title: str,
content: Union[str, None],
qconfig: QConfig,
configItem: ConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.switchButton = SwitchButton(self.tr("Off"), self, IndicatorPosition.RIGHT)
if configItem:
self.setValue(self.qconfig.get(configItem))
configItem.valueChanged.connect(self.setValue)
# add switch button to layout
self.hBoxLayout.addWidget(self.switchButton, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.switchButton.checkedChanged.connect(self.__onCheckedChanged)
def __onCheckedChanged(self, isChecked: bool):
"""switch button checked state changed slot"""
self.setValue(isChecked)
self.checkedChanged.emit(isChecked)
def setValue(self, isChecked: bool):
if self.configItem:
self.qconfig.set(self.configItem, isChecked)
self.switchButton.setChecked(isChecked)
self.switchButton.setText(self.tr("On") if isChecked else self.tr("Off"))
def setChecked(self, isChecked: bool):
self.setValue(isChecked)
def isChecked(self):
return self.switchButton.isChecked()
class RangeSettingCard(SettingCard):
"""Setting card with a slider"""
valueChanged = Signal(int)
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title: str,
content: Union[str, None],
qconfig: QConfig,
configItem: ConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.slider = Slider(Qt.Horizontal, self)
self.valueLabel = QLabel(self)
self.slider.setMinimumWidth(268)
self.slider.setSingleStep(1)
self.slider.setRange(*configItem.range)
self.slider.setValue(configItem.value)
self.valueLabel.setNum(configItem.value)
self.hBoxLayout.addStretch(1)
self.hBoxLayout.addWidget(self.valueLabel, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(6)
self.hBoxLayout.addWidget(self.slider, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.valueLabel.setObjectName("valueLabel")
configItem.valueChanged.connect(self.setValue)
self.slider.valueChanged.connect(self.__onValueChanged)
def __onValueChanged(self, value: int):
"""slider value changed slot"""
self.setValue(value)
self.valueChanged.emit(value)
def setValue(self, value):
self.qconfig.set(self.configItem, value)
self.valueLabel.setNum(value)
self.valueLabel.adjustSize()
self.slider.setValue(value)
class ComboBoxSettingCard(SettingCard):
"""Setting card with a combo box"""
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title: str,
content: Union[str, None],
texts: List[str],
qconfig: QConfig,
configItem: OptionsConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.comboBox = ComboBox(self)
self.hBoxLayout.addWidget(self.comboBox, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.optionToText = {o: t for o, t in zip(configItem.options, texts)}
for text, option in zip(texts, configItem.options):
self.comboBox.addItem(text, userData=option)
self.comboBox.setCurrentText(self.optionToText[self.qconfig.get(configItem)])
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
configItem.valueChanged.connect(self.setValue)
def _onCurrentIndexChanged(self, index: int):
self.qconfig.set(self.configItem, self.comboBox.itemData(index))
def setValue(self, value):
if value not in self.optionToText:
return
self.comboBox.setCurrentText(self.optionToText[value])
self.qconfig.set(self.configItem, value)
class LineEditSettingCard(SettingCard):
"""Setting card with LineEdit"""
@@ -255,22 +399,24 @@ class LineEditSettingCard(SettingCard):
def __init__(
self,
text,
icon: Union[str, QIcon, FluentIconBase],
title,
content=None,
configItem: ConfigItem = None,
title: str,
content: Union[str, None],
text: str,
qconfig: QConfig,
configItem: ConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.LineEdit = LineEdit(self)
self.LineEdit.setMinimumWidth(250)
self.LineEdit.setPlaceholderText(text)
if configItem:
self.setValue(qconfig.get(configItem))
self.setValue(self.qconfig.get(configItem))
configItem.valueChanged.connect(self.setValue)
self.hBoxLayout.addWidget(self.LineEdit, 0, Qt.AlignRight)
@@ -279,39 +425,46 @@ class LineEditSettingCard(SettingCard):
self.LineEdit.textChanged.connect(self.__textChanged)
def __textChanged(self, content: str):
self.setValue(content)
self.textChanged.emit(content)
self.setValue(content.strip())
self.textChanged.emit(content.strip())
def setValue(self, content: str):
if self.configItem:
qconfig.set(self.configItem, content)
self.qconfig.set(self.configItem, content.strip())
self.LineEdit.setText(content)
self.LineEdit.setText(content.strip())
class PasswordLineEditSettingCard(SettingCard):
"""Setting card with PasswordLineEdit"""
textChanged = Signal(str)
textChanged = Signal()
def __init__(
self,
text,
icon: Union[str, QIcon, FluentIconBase],
title,
content=None,
configItem: ConfigItem = None,
title: str,
content: Union[str, None],
text: str,
algorithm: str,
qconfig: QConfig,
configItem: ConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.algorithm = algorithm
self.qconfig = qconfig
self.configItem = configItem
self.LineEdit = PasswordLineEdit(self)
self.LineEdit.setMinimumWidth(250)
self.LineEdit.setMinimumWidth(200)
self.LineEdit.setPlaceholderText(text)
if algorithm == "AUTO":
self.LineEdit.setViewPasswordButtonVisible(False)
self.if_setValue = False
if configItem:
self.setValue(qconfig.get(configItem))
self.setValue(self.qconfig.get(configItem))
configItem.valueChanged.connect(self.setValue)
self.hBoxLayout.addWidget(self.LineEdit, 0, Qt.AlignRight)
@@ -320,14 +473,141 @@ class PasswordLineEditSettingCard(SettingCard):
self.LineEdit.textChanged.connect(self.__textChanged)
def __textChanged(self, content: str):
self.setValue(Crypto.win_encryptor(content))
self.textChanged.emit(content)
if self.if_setValue:
return None
if self.algorithm == "DPAPI":
self.setValue(Crypto.win_encryptor(content))
elif self.algorithm == "AUTO":
self.setValue(Crypto.AUTO_encryptor(content))
self.textChanged.emit()
def setValue(self, content: str):
if self.configItem:
qconfig.set(self.configItem, content)
self.LineEdit.setText(Crypto.win_decryptor(content))
self.if_setValue = True
if self.configItem:
self.qconfig.set(self.configItem, content)
if self.algorithm == "DPAPI":
self.LineEdit.setText(Crypto.win_decryptor(content))
elif self.algorithm == "AUTO":
if Crypto.check_PASSWORD(Config.PASSWORD):
self.LineEdit.setText(Crypto.AUTO_decryptor(content, Config.PASSWORD))
self.LineEdit.setPasswordVisible(True)
self.LineEdit.setReadOnly(False)
elif Config.PASSWORD:
self.LineEdit.setText("管理密钥错误")
self.LineEdit.setPasswordVisible(True)
self.LineEdit.setReadOnly(True)
else:
self.LineEdit.setText("************")
self.LineEdit.setPasswordVisible(False)
self.LineEdit.setReadOnly(True)
self.if_setValue = False
class UserLableSettingCard(SettingCard):
"""Setting card with User's Lable"""
textChanged = Signal(str)
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title: str,
content: Union[str, None],
qconfig: QConfig,
configItems: Dict[str, ConfigItem],
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItems = configItems
self.Lable = SubtitleLabel(self)
if configItems:
for configItem in configItems.values():
configItem.valueChanged.connect(self.setValue)
self.setValue()
self.hBoxLayout.addWidget(self.Lable, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
def setValue(self):
if self.configItems:
text_list = []
if not self.qconfig.get(self.configItems["IfPassCheck"]):
text_list.append("未通过人工排查")
text_list.append(
f"今日已代理{self.qconfig.get(self.configItems["ProxyTimes"])}"
if Config.server_date()
== self.qconfig.get(self.configItems["LastProxyDate"])
else "今日未进行代理"
)
text_list.append(
"本周剿灭已完成"
if datetime.strptime(
self.qconfig.get(self.configItems["LastAnnihilationDate"]),
"%Y-%m-%d",
).isocalendar()[:2]
== datetime.strptime(Config.server_date(), "%Y-%m-%d").isocalendar()[:2]
else "本周剿灭未完成"
)
self.Lable.setText(" | ".join(text_list))
class PushAndSwitchButtonSettingCard(SettingCard):
"""Setting card with push & switch button"""
checkedChanged = Signal(bool)
clicked = Signal()
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title: str,
content: Union[str, None],
text: str,
qconfig: QConfig,
configItem: ConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.switchButton = SwitchButton("", self, IndicatorPosition.RIGHT)
self.button = PushButton(text, self)
self.hBoxLayout.addWidget(self.button, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.button.clicked.connect(self.clicked)
if configItem:
self.setValue(self.qconfig.get(configItem))
configItem.valueChanged.connect(self.setValue)
# add switch button to layout
self.hBoxLayout.addWidget(self.switchButton, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.switchButton.checkedChanged.connect(self.__onCheckedChanged)
def __onCheckedChanged(self, isChecked: bool):
"""switch button checked state changed slot"""
self.setValue(isChecked)
self.checkedChanged.emit(isChecked)
def setValue(self, isChecked: bool):
if self.configItem:
self.qconfig.set(self.configItem, isChecked)
self.switchButton.setChecked(isChecked)
self.switchButton.setText("" if isChecked else "")
class SpinBoxSettingCard(SettingCard):
@@ -337,15 +617,17 @@ class SpinBoxSettingCard(SettingCard):
def __init__(
self,
range: tuple[int, int],
icon: Union[str, QIcon, FluentIconBase],
title,
content=None,
configItem: ConfigItem = None,
title: str,
content: Union[str, None],
range: tuple[int, int],
qconfig: QConfig,
configItem: ConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.SpinBox = SpinBox(self)
self.SpinBox.setRange(range[0], range[1])
@@ -366,7 +648,7 @@ class SpinBoxSettingCard(SettingCard):
def setValue(self, value: int):
if self.configItem:
qconfig.set(self.configItem, value)
self.qconfig.set(self.configItem, value)
self.SpinBox.setValue(value)
@@ -375,16 +657,18 @@ class NoOptionComboBoxSettingCard(SettingCard):
def __init__(
self,
configItem: OptionsConfigItem,
icon: Union[str, QIcon, FluentIconBase],
title,
content=None,
value=None,
texts=None,
title: str,
content: Union[str, None],
value: List[str],
texts: List[str],
qconfig: QConfig,
configItem: OptionsConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.comboBox = ComboBox(self)
self.comboBox.setMinimumWidth(250)
@@ -395,20 +679,131 @@ class NoOptionComboBoxSettingCard(SettingCard):
for text, option in zip(texts, value):
self.comboBox.addItem(text, userData=option)
self.comboBox.setCurrentText(self.optionToText[qconfig.get(configItem)])
self.comboBox.setCurrentText(self.optionToText[self.qconfig.get(configItem)])
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
configItem.valueChanged.connect(self.setValue)
def _onCurrentIndexChanged(self, index: int):
qconfig.set(self.configItem, self.comboBox.itemData(index))
self.qconfig.set(self.configItem, self.comboBox.itemData(index))
def setValue(self, value):
if value not in self.optionToText:
return
self.comboBox.setCurrentText(self.optionToText[value])
qconfig.set(self.configItem, value)
self.qconfig.set(self.configItem, value)
def reLoadOptions(self, value: List[str], texts: List[str]):
self.comboBox.currentIndexChanged.disconnect()
self.comboBox.clear()
self.optionToText = {o: t for o, t in zip(value, texts)}
for text, option in zip(texts, value):
self.comboBox.addItem(text, userData=option)
self.comboBox.setCurrentText(
self.optionToText[self.qconfig.get(self.configItem)]
)
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
class EditableComboBoxSettingCard(SettingCard):
"""Setting card with EditableComboBox"""
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title: str,
content: Union[str, None],
value: List[str],
texts: List[str],
qconfig: QConfig,
configItem: OptionsConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.comboBox = self._EditableComboBox(self)
self.comboBox.setMinimumWidth(100)
self.hBoxLayout.addWidget(self.comboBox, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.optionToText = {o: t for o, t in zip(value, texts)}
for text, option in zip(texts, value):
self.comboBox.addItem(text, userData=option)
if qconfig.get(configItem) not in self.optionToText:
self.optionToText[qconfig.get(configItem)] = qconfig.get(configItem)
self.comboBox.addItem(
qconfig.get(configItem), userData=qconfig.get(configItem)
)
self.comboBox.setCurrentText(self.optionToText[qconfig.get(configItem)])
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
configItem.valueChanged.connect(self.setValue)
def _onCurrentIndexChanged(self, index: int):
self.qconfig.set(
self.configItem,
(
self.comboBox.itemData(index)
if self.comboBox.itemData(index)
else self.comboBox.itemText(index)
),
)
def setValue(self, value):
if value not in self.optionToText:
self.optionToText[value] = value
if self.comboBox.findText(value) == -1:
self.comboBox.addItem(value, userData=value)
else:
self.comboBox.setItemData(self.comboBox.findText(value), value)
self.comboBox.setCurrentText(self.optionToText[value])
self.qconfig.set(self.configItem, value)
def reLoadOptions(self, value: List[str], texts: List[str]):
self.comboBox.currentIndexChanged.disconnect()
self.comboBox.clear()
self.optionToText = {o: t for o, t in zip(value, texts)}
for text, option in zip(texts, value):
self.comboBox.addItem(text, userData=option)
if self.qconfig.get(self.configItem) not in self.optionToText:
self.optionToText[self.qconfig.get(self.configItem)] = self.qconfig.get(
self.configItem
)
self.comboBox.addItem(
self.qconfig.get(self.configItem),
userData=self.qconfig.get(self.configItem),
)
self.comboBox.setCurrentText(
self.optionToText[self.qconfig.get(self.configItem)]
)
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
class _EditableComboBox(EditableComboBox):
"""EditableComboBox"""
def __init__(self, parent=None):
super().__init__(parent)
def _onReturnPressed(self):
if not self.text():
return
index = self.findText(self.text())
if index >= 0 and index != self.currentIndex():
self._currentIndex = index
self.currentIndexChanged.emit(index)
elif index == -1:
self.addItem(self.text())
self.setCurrentIndex(self.count() - 1)
self.currentIndexChanged.emit(self.count() - 1)
class TimeEditSettingCard(SettingCard):
@@ -419,14 +814,16 @@ class TimeEditSettingCard(SettingCard):
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
title,
content=None,
configItem_bool: ConfigItem = None,
configItem_time: ConfigItem = None,
title: str,
content: Union[str, None],
qconfig: QConfig,
configItem_bool: ConfigItem,
configItem_time: ConfigItem,
parent=None,
):
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem_bool = configItem_bool
self.configItem_time = configItem_time
self.CheckBox = CheckBox(self)
@@ -464,13 +861,13 @@ class TimeEditSettingCard(SettingCard):
def setValue_bool(self, value: bool):
if self.configItem_bool:
qconfig.set(self.configItem_bool, value)
self.qconfig.set(self.configItem_bool, value)
self.CheckBox.setChecked(value)
def setValue_time(self, value: str):
if self.configItem_time:
qconfig.set(self.configItem_time, value)
self.qconfig.set(self.configItem_time, value)
self.TimeEdit.setTime(QTime.fromString(value, "HH:mm"))
@@ -510,31 +907,18 @@ class UrlListSettingCard(ExpandSettingCard):
def __init__(
self,
icon: Union[str, QIcon, FluentIconBase],
configItem: ConfigItem,
title: str,
content: str = None,
content: Union[str, None],
qconfig: QConfig,
configItem: ConfigItem,
parent=None,
):
"""
Parameters
----------
configItem: RangeConfigItem
configuration item operated by the card
title: str
the title of card
content: str
the content of card
parent: QWidget
parent widget
"""
super().__init__(icon, title, content, parent)
self.qconfig = qconfig
self.configItem = configItem
self.addUrlButton = PushButton("添加代理网址", self)
self.urls: List[str] = qconfig.get(configItem).copy()
self.urls: List[str] = self.qconfig.get(configItem).copy()
self.__initWidget()
def __initWidget(self):
@@ -567,7 +951,7 @@ class UrlListSettingCard(ExpandSettingCard):
self.__addUrlItem(url)
self.urls.append(url)
qconfig.set(self.configItem, self.urls)
self.qconfig.set(self.configItem, self.urls)
self.urlChanged.emit(self.urls)
def __addUrlItem(self, url: str):
@@ -600,7 +984,7 @@ class UrlListSettingCard(ExpandSettingCard):
self._adjustViewSize()
self.urlChanged.emit(self.urls)
qconfig.set(self.configItem, self.urls)
self.qconfig.set(self.configItem, self.urls)
def __validate(self, value):
@@ -681,7 +1065,7 @@ class IconButton(TransparentToolButton):
icon: Union[str, QIcon, FluentIconBase],
isTooltip: bool,
tip_title: str,
tip_content: str,
tip_content: Union[str, None],
parent: QWidget = None,
):
self.__init__(parent)