From f135a6510f5fe1d305953739beef60c10d322204 Mon Sep 17 00:00:00 2001 From: DLmaster Date: Sat, 4 Jan 2025 04:02:20 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E7=95=8C=E9=9D=A2=E4=B8=8E?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E7=AE=A1=E7=90=86=E7=95=8C=E9=9D=A2=E5=88=9D?= =?UTF-8?q?=E6=AD=A5=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/__init__.py | 3 +- app/config.py | 148 ++++---- app/models/MAA.py | 12 + app/ui/Widget.py | 149 ++++++++ app/ui/__init__.py | 2 +- app/ui/{gui.py => else.py} | 737 +++++++------------------------------ app/ui/main_window.py | 312 ++++++++++++++++ app/ui/member_manager.py | 527 ++++++++++++++++++++++++++ app/ui/setting.py | 623 +++++++++++++++++++++++++++++++ app/utils/Updater.py | 27 +- main.py | 12 +- resources/version.json | 4 +- 12 files changed, 1879 insertions(+), 677 deletions(-) create mode 100644 app/ui/Widget.py rename app/ui/{gui.py => else.py} (65%) create mode 100644 app/ui/main_window.py create mode 100644 app/ui/member_manager.py create mode 100644 app/ui/setting.py diff --git a/app/__init__.py b/app/__init__.py index 27ce45c..38b0e75 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -29,7 +29,7 @@ __version__ = "4.2.0" __author__ = "DLmaster361 " __license__ = "GPL-3.0 license" -from .config import AppConfig +from .config import AppConfig, MaaConfig from .models import MaaManager from .services import Notification, CryptoHandler from .ui import AUTO_MAA @@ -37,6 +37,7 @@ from .utils import Updater, version_text __all__ = [ "AppConfig", + "MaaConfig", "MaaManager", "Notification", "CryptoHandler", diff --git a/app/config.py b/app/config.py index 8323da6..35c95b3 100644 --- a/app/config.py +++ b/app/config.py @@ -31,6 +31,18 @@ import os import sys from pathlib import Path from typing import Dict, Union +from qfluentwidgets import ( + QConfig, + ConfigItem, + qconfig, + OptionsConfigItem, + RangeConfigItem, + OptionsValidator, + FolderValidator, + BoolValidator, + RangeValidator, + EnumSerializer, +) class AppConfig: @@ -42,7 +54,7 @@ class AppConfig: self.app_name = os.path.basename(self.app_path) # 获取软件自身的名称 self.database_path = self.app_path / "data/data.db" - self.config_path = self.app_path / "config/gui.json" + self.config_path = self.app_path / "config/config.json" self.key_path = self.app_path / "data/key" self.gameid_path = self.app_path / "data/gameid.txt" self.version_path = self.app_path / "resources/version.json" @@ -68,12 +80,6 @@ class AppConfig: with self.version_path.open(mode="w", encoding="utf-8") as f: json.dump(version, f, indent=4) - # 生成配置文件 - if not self.config_path.exists(): - config = {"Default": {}} - with self.config_path.open(mode="w", encoding="utf-8") as f: - json.dump(config, f, indent=4) - # 生成预设gameid替换方案文件 if not self.gameid_path.exists(): self.gameid_path.write_text( @@ -87,60 +93,11 @@ class AppConfig: def check_config(self) -> None: """检查配置文件字段完整性并补全""" - config_list = [ - ["TimeSet.set1", "False"], - ["TimeSet.run1", "00:00"], - ["TimeSet.set2", "False"], - ["TimeSet.run2", "00:00"], - ["TimeSet.set3", "False"], - ["TimeSet.run3", "00:00"], - ["TimeSet.set4", "False"], - ["TimeSet.run4", "00:00"], - ["TimeSet.set5", "False"], - ["TimeSet.run5", "00:00"], - ["TimeSet.set6", "False"], - ["TimeSet.run6", "00:00"], - ["TimeSet.set7", "False"], - ["TimeSet.run7", "00:00"], - ["TimeSet.set8", "False"], - ["TimeSet.run8", "00:00"], - ["TimeSet.set9", "False"], - ["TimeSet.run9", "00:00"], - ["TimeSet.set10", "False"], - ["TimeSet.run10", "00:00"], - ["MaaSet.path", ""], - ["TimeLimit.routine", 10], - ["TimeLimit.annihilation", 40], - ["TimesLimit.run", 3], - ["SelfSet.IfSelfStart", "False"], - ["SelfSet.IfSleep", "False"], - ["SelfSet.IfProxyDirectly", "False"], - ["SelfSet.IfSendMail", "False"], - ["SelfSet.MailAddress", ""], - ["SelfSet.IfSendMail.OnlyError", "False"], - ["SelfSet.IfSilence", "False"], - ["SelfSet.BossKey", ""], - ["SelfSet.IfToTray", "False"], - ["SelfSet.UIsize", "1200x700"], - ["SelfSet.UIlocation", "100x100"], - ["SelfSet.UImaximized", "False"], - ["SelfSet.MainIndex", 2], - ] + self.global_config = GlobalConfig() + qconfig.load(self.config_path, self.global_config) + self.global_config.save() - # 导入配置文件 - with self.config_path.open(mode="r", encoding="utf-8") as f: - config = json.load(f) - - # 检查并补充缺失的字段 - for i in range(len(config_list)): - if not config_list[i][0] in config["Default"]: - config["Default"][config_list[i][0]] = config_list[i][1] - - # 初始化配置信息 - self.content: Dict[str, Dict[str, Union[str, int]]] = config - - # 导出配置文件 - self.save_config() + self.maa_config = MaaConfig() def check_database(self) -> None: """检查用户数据库文件并处理数据库版本更新""" @@ -233,8 +190,71 @@ class AppConfig: self.cur.close() self.db.close() - def save_config(self) -> None: - """保存配置文件""" - with self.config_path.open(mode="w", encoding="utf-8") as f: - json.dump(self.content, f, indent=4) +class GlobalConfig(QConfig): + """全局配置""" + + # ["TimeSet.set1", "False"], + # ["TimeSet.run1", "00:00"], + # ["TimeSet.set2", "False"], + # ["TimeSet.run2", "00:00"], + # ["TimeSet.set3", "False"], + # ["TimeSet.run3", "00:00"], + # ["TimeSet.set4", "False"], + # ["TimeSet.run4", "00:00"], + # ["TimeSet.set5", "False"], + # ["TimeSet.run5", "00:00"], + # ["TimeSet.set6", "False"], + # ["TimeSet.run6", "00:00"], + # ["TimeSet.set7", "False"], + # ["TimeSet.run7", "00:00"], + # ["TimeSet.set8", "False"], + # ["TimeSet.run8", "00:00"], + # ["TimeSet.set9", "False"], + # ["TimeSet.run9", "00:00"], + # ["TimeSet.set10", "False"], + # ["TimeSet.run10", "00:00"], + # ["MaaSet.path", ""], + # ["TimeLimit.routine", 10], + # ["TimeLimit.annihilation", 40], + # ["TimesLimit.run", 3], + + function_IfSleep = ConfigItem("Function", "IfSleep", False, BoolValidator()) + function_IfSilence = ConfigItem("Function", "IfSilence", False, BoolValidator()) + function_BossKey = ConfigItem("Function", "BossKey", "") + + start_IfSelfStart = ConfigItem("Start", "IfSelfStart", False, BoolValidator()) + start_IfRunDirectly = ConfigItem("Start", "IfRunDirectly", False, BoolValidator()) + + ui_IfShowTray = ConfigItem("UI", "IfShowTray", False, BoolValidator()) + ui_IfToTray = ConfigItem("UI", "IfToTray", False, BoolValidator()) + ui_size = ConfigItem("UI", "size", "1200x700") + ui_location = ConfigItem("UI", "location", "100x100") + ui_maximized = ConfigItem("UI", "maximized", False, BoolValidator()) + ui_MainIndex = RangeConfigItem("UI", "MainIndex", 0, RangeValidator(0, 3)) + + notify_IfPushPlyer = ConfigItem("Notify", "IfPushPlyer", False, BoolValidator()) + notify_IfSendMail = ConfigItem("Notify", "IfSendMail", False, BoolValidator()) + notify_IfSendErrorOnly = ConfigItem( + "Notify", "IfSendErrorOnly", False, BoolValidator() + ) + notify_MailAddress = ConfigItem("Notify", "MailAddress", "") + + update_IfAutoUpdate = ConfigItem("Update", "IfAutoUpdate", False, BoolValidator()) + + +class MaaConfig(QConfig): + """MAA配置""" + + MaaSet_Name = ConfigItem("MaaSet", "Name", "") + MaaSet_Path = ConfigItem("MaaSet", "Path", ".", FolderValidator()) + + RunSet_AnnihilationTimeLimit = RangeConfigItem( + "RunSet", "AnnihilationTimeLimit", 40, RangeValidator(1, 1024) + ) + RunSet_RoutineTimeLimit = RangeConfigItem( + "RunSet", "RoutineTimeLimit", 10, RangeValidator(1, 1024) + ) + RunSet_RunTimesLimit = RangeConfigItem( + "RunSet", "RunTimesLimit", 3, RangeValidator(1, 1024) + ) diff --git a/app/models/MAA.py b/app/models/MAA.py index e268645..2e7b953 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -33,6 +33,18 @@ import subprocess import shutil import time from pathlib import Path +from qfluentwidgets import ( + QConfig, + ConfigItem, + qconfig, + OptionsConfigItem, + RangeConfigItem, + OptionsValidator, + BoolValidator, + RangeValidator, + EnumSerializer, + FolderValidator, +) from app import AppConfig diff --git a/app/ui/Widget.py b/app/ui/Widget.py new file mode 100644 index 0000000..6ed0a41 --- /dev/null +++ b/app/ui/Widget.py @@ -0,0 +1,149 @@ +# +# Copyright © <2024> + +# This file is part of AUTO_MAA. + +# AUTO_MAA is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, +# or (at your option) any later version. + +# AUTO_MAA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with AUTO_MAA. If not, see . + +# DLmaster_361@163.com + +""" +AUTO_MAA +AUTO_MAA组件 +v4.2 +作者:DLmaster_361 +""" + +from PySide6.QtCore import Qt +from PySide6.QtGui import QIcon +from qfluentwidgets import ( + LineEdit, + PasswordLineEdit, + MessageBoxBase, + SubtitleLabel, + SettingCard, + SpinBox, + FluentIconBase, + Signal, + ComboBox, + qconfig, + ConfigItem, +) + +from typing import Union + + +class InputMessageBox(MessageBoxBase): + """输入对话框""" + + def __init__(self, parent, title: str, content: str, mode: str, list: list = None): + super().__init__(parent) + self.title = SubtitleLabel(title) + + if mode == "明文": + self.input = LineEdit() + self.input.setClearButtonEnabled(True) + elif mode == "密码": + self.input = PasswordLineEdit() + elif mode == "选择": + self.input = ComboBox() + self.input.addItems(list) + self.input.setCurrentIndex(-1) + + self.input.setPlaceholderText(content) + + # 将组件添加到布局中 + self.viewLayout.addWidget(self.title) + self.viewLayout.addWidget(self.input) + + +class LineEditSettingCard(SettingCard): + """Setting card with switch button""" + + textChanged = Signal(str) + + def __init__( + self, + text, + icon: Union[str, QIcon, FluentIconBase], + title, + content=None, + configItem: ConfigItem = None, + parent=None, + ): + + super().__init__(icon, title, content, parent) + self.configItem = configItem + self.LineEdit = LineEdit(self) + self.LineEdit.setMinimumWidth(250) + self.LineEdit.setPlaceholderText(text) + + if configItem: + self.setValue(qconfig.get(configItem)) + configItem.valueChanged.connect(self.setValue) + + self.hBoxLayout.addWidget(self.LineEdit, 0, Qt.AlignRight) + self.hBoxLayout.addSpacing(16) + + self.LineEdit.textChanged.connect(self.__textChanged) + + def __textChanged(self, content: str): + self.setValue(content) + self.textChanged.emit(content) + + def setValue(self, content: str): + if self.configItem: + qconfig.set(self.configItem, content) + + self.LineEdit.setText(content) + + +class SpinBoxSettingCard(SettingCard): + + textChanged = Signal(int) + + def __init__( + self, + range: tuple[int, int], + icon: Union[str, QIcon, FluentIconBase], + title, + content=None, + configItem: ConfigItem = None, + parent=None, + ): + + super().__init__(icon, title, content, parent) + self.configItem = configItem + self.SpinBox = SpinBox(self) + self.SpinBox.setRange(range[0], range[1]) + self.SpinBox.setMinimumWidth(150) + + if configItem: + self.setValue(qconfig.get(configItem)) + configItem.valueChanged.connect(self.setValue) + + self.hBoxLayout.addWidget(self.SpinBox, 0, Qt.AlignRight) + self.hBoxLayout.addSpacing(16) + + self.SpinBox.valueChanged.connect(self.__valueChanged) + + def __valueChanged(self, value: int): + self.setValue(value) + self.textChanged.emit(value) + + def setValue(self, value: int): + if self.configItem: + qconfig.set(self.configItem, value) + + self.SpinBox.setValue(value) diff --git a/app/ui/__init__.py b/app/ui/__init__.py index 7156ee7..3764f04 100644 --- a/app/ui/__init__.py +++ b/app/ui/__init__.py @@ -29,6 +29,6 @@ __version__ = "4.2.0" __author__ = "DLmaster361 " __license__ = "GPL-3.0 license" -from .gui import AUTO_MAA +from .main_window import AUTO_MAA __all__ = ["AUTO_MAA"] diff --git a/app/ui/gui.py b/app/ui/else.py similarity index 65% rename from app/ui/gui.py rename to app/ui/else.py index d19fd28..04994bd 100644 --- a/app/ui/gui.py +++ b/app/ui/else.py @@ -1,88 +1,3 @@ -# -# Copyright © <2024> - -# This file is part of AUTO_MAA. - -# AUTO_MAA is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation, either version 3 of the License, -# or (at your option) any later version. - -# AUTO_MAA is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -# the GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with AUTO_MAA. If not, see . - -# DLmaster_361@163.com - -""" -AUTO_MAA -AUTO_MAA主界面 -v4.2 -作者:DLmaster_361 -""" - -from PySide6.QtWidgets import ( - QWidget, # - QMainWindow, # - QApplication, # - QSystemTrayIcon, # - QFileDialog, # - QTabWidget, # - QToolBox, # - QComboBox, # - QTableWidgetItem, # - QHeaderView, # -) -from qfluentwidgets import ( - Action, - PushButton, - LineEdit, - PasswordLineEdit, - TextBrowser, - TableWidget, - TimePicker, - ComboBox, - CheckBox, - SpinBox, - FluentIcon, - RoundMenu, - MessageBox, - MessageBoxBase, - HeaderCardWidget, - BodyLabel, - SubtitleLabel, -) -from PySide6.QtUiTools import QUiLoader -from PySide6.QtGui import QIcon, QCloseEvent -from PySide6 import QtCore -from functools import partial -from typing import List, Tuple -from pathlib import Path -import json -import datetime -import ctypes -import subprocess -import shutil -import win32gui -import win32process -import psutil -import pyautogui -import time -import winreg -import requests - -uiLoader = QUiLoader() - -from app import AppConfig -from app.models import MaaManager -from app.services import Notification, CryptoHandler -from app.utils import Updater, version_text - - class Main(QWidget): ES_CONTINUOUS = 0x80000000 @@ -158,168 +73,168 @@ class Main(QWidget): "-", ] - uiLoader.registerCustomWidget(PushButton) - uiLoader.registerCustomWidget(LineEdit) - uiLoader.registerCustomWidget(TextBrowser) - uiLoader.registerCustomWidget(TableWidget) - uiLoader.registerCustomWidget(TimePicker) - uiLoader.registerCustomWidget(SpinBox) - uiLoader.registerCustomWidget(CheckBox) - uiLoader.registerCustomWidget(HeaderCardWidget) - uiLoader.registerCustomWidget(BodyLabel) + # uiLoader.registerCustomWidget(PushButton) + # uiLoader.registerCustomWidget(LineEdit) + # uiLoader.registerCustomWidget(TextBrowser) + # uiLoader.registerCustomWidget(TableWidget) + # uiLoader.registerCustomWidget(TimePicker) + # uiLoader.registerCustomWidget(SpinBox) + # uiLoader.registerCustomWidget(CheckBox) + # uiLoader.registerCustomWidget(HeaderCardWidget) + # uiLoader.registerCustomWidget(BodyLabel) - # 导入ui配置 - self.ui = uiLoader.load(self.config.app_path / "resources/gui/main.ui") - self.ui.setWindowIcon( - QIcon(str(self.config.app_path / "resources/icons/AUTO_MAA.ico")) - ) + # # 导入ui配置 + # self.ui = uiLoader.load(self.config.app_path / "resources/gui/main.ui") + # self.ui.setWindowIcon( + # QIcon(str(self.config.app_path / "resources/icons/AUTO_MAA.ico")) + # ) - # 初始化控件 - self.main_tab: QTabWidget = self.ui.findChild(QTabWidget, "tabWidget_main") - self.main_tab.currentChanged.connect(self.change_config) + # # 初始化控件 + # self.main_tab: QTabWidget = self.ui.findChild(QTabWidget, "tabWidget_main") + # self.main_tab.currentChanged.connect(self.change_config) - self.user_set: QToolBox = self.ui.findChild(QToolBox, "toolBox_userset") - self.user_set.currentChanged.connect(lambda: self.update_user_info("normal")) + # self.user_set: QToolBox = self.ui.findChild(QToolBox, "toolBox_userset") + # self.user_set.currentChanged.connect(lambda: self.update_user_info("normal")) - self.user_list_simple: TableWidget = self.ui.findChild( - TableWidget, "tableWidget_userlist_simple" - ) - self.user_list_simple.itemChanged.connect( - lambda item: self.change_user_Item(item, "simple") - ) + # self.user_list_simple: TableWidget = self.ui.findChild( + # TableWidget, "tableWidget_userlist_simple" + # ) + # self.user_list_simple.itemChanged.connect( + # lambda item: self.change_user_Item(item, "simple") + # ) - self.user_list_beta: TableWidget = self.ui.findChild( - TableWidget, "tableWidget_userlist_beta" - ) - self.user_list_beta.itemChanged.connect( - lambda item: self.change_user_Item(item, "beta") - ) + # self.user_list_beta: TableWidget = self.ui.findChild( + # TableWidget, "tableWidget_userlist_beta" + # ) + # self.user_list_beta.itemChanged.connect( + # lambda item: self.change_user_Item(item, "beta") + # ) - self.user_add: PushButton = self.ui.findChild(PushButton, "pushButton_new") - self.user_add.setIcon(FluentIcon.ADD_TO) - self.user_add.clicked.connect(self.add_user) + # self.user_add: PushButton = self.ui.findChild(PushButton, "pushButton_new") + # self.user_add.setIcon(FluentIcon.ADD_TO) + # self.user_add.clicked.connect(self.add_user) - self.user_del: PushButton = self.ui.findChild(PushButton, "pushButton_del") - self.user_del.setIcon(FluentIcon.REMOVE_FROM) - self.user_del.clicked.connect(self.del_user) + # self.user_del: PushButton = self.ui.findChild(PushButton, "pushButton_del") + # self.user_del.setIcon(FluentIcon.REMOVE_FROM) + # self.user_del.clicked.connect(self.del_user) - self.user_switch: PushButton = self.ui.findChild( - PushButton, "pushButton_switch" - ) - self.user_switch.setIcon(FluentIcon.MOVE) - self.user_switch.clicked.connect(self.switch_user) + # self.user_switch: PushButton = self.ui.findChild( + # PushButton, "pushButton_switch" + # ) + # self.user_switch.setIcon(FluentIcon.MOVE) + # self.user_switch.clicked.connect(self.switch_user) - self.read_PASSWORD: PushButton = self.ui.findChild( - PushButton, "pushButton_password" - ) - self.read_PASSWORD.setIcon(FluentIcon.HIDE) - self.read_PASSWORD.clicked.connect(lambda: self.read("key")) + # self.read_PASSWORD: PushButton = self.ui.findChild( + # PushButton, "pushButton_password" + # ) + # self.read_PASSWORD.setIcon(FluentIcon.HIDE) + # self.read_PASSWORD.clicked.connect(lambda: self.read("key")) - self.refresh: PushButton = self.ui.findChild(PushButton, "pushButton_refresh") - self.refresh.setIcon(FluentIcon.SYNC) - self.refresh.clicked.connect(lambda: self.update_user_info("clear")) + # self.refresh: PushButton = self.ui.findChild(PushButton, "pushButton_refresh") + # self.refresh.setIcon(FluentIcon.SYNC) + # self.refresh.clicked.connect(lambda: self.update_user_info("clear")) - self.run_now: PushButton = self.ui.findChild(PushButton, "pushButton_runnow") - self.run_now.setIcon(FluentIcon.PLAY) - self.run_now.clicked.connect(lambda: self.maa_starter("日常代理")) + # self.run_now: PushButton = self.ui.findChild(PushButton, "pushButton_runnow") + # self.run_now.setIcon(FluentIcon.PLAY) + # self.run_now.clicked.connect(lambda: self.maa_starter("日常代理")) - self.check_start: PushButton = self.ui.findChild( - PushButton, "pushButton_checkstart" - ) - self.check_start.setIcon(FluentIcon.PLAY) - self.check_start.clicked.connect(lambda: self.maa_starter("人工排查")) + # self.check_start: PushButton = self.ui.findChild( + # PushButton, "pushButton_checkstart" + # ) + # self.check_start.setIcon(FluentIcon.PLAY) + # self.check_start.clicked.connect(lambda: self.maa_starter("人工排查")) - self.maa_path: LineEdit = self.ui.findChild(LineEdit, "lineEdit_MAApath") - self.maa_path.textChanged.connect(self.change_config) - self.maa_path.setReadOnly(True) + # self.maa_path: LineEdit = self.ui.findChild(LineEdit, "lineEdit_MAApath") + # self.maa_path.textChanged.connect(self.change_config) + # self.maa_path.setReadOnly(True) - self.get_maa_path: PushButton = self.ui.findChild( - PushButton, "pushButton_getMAApath" - ) - self.get_maa_path.setIcon(FluentIcon.FOLDER) - self.get_maa_path.clicked.connect(lambda: self.read("file_path_maa")) + # self.get_maa_path: PushButton = self.ui.findChild( + # PushButton, "pushButton_getMAApath" + # ) + # self.get_maa_path.setIcon(FluentIcon.FOLDER) + # self.get_maa_path.clicked.connect(lambda: self.read("file_path_maa")) - self.set_maa: PushButton = self.ui.findChild(PushButton, "pushButton_setMAA") - self.set_maa.setIcon(FluentIcon.SETTING) - self.set_maa.clicked.connect(lambda: self.maa_starter("设置MAA_全局")) + # self.set_maa: PushButton = self.ui.findChild(PushButton, "pushButton_setMAA") + # self.set_maa.setIcon(FluentIcon.SETTING) + # self.set_maa.clicked.connect(lambda: self.maa_starter("设置MAA_全局")) - self.routine: SpinBox = self.ui.findChild(SpinBox, "spinBox_routine") - self.routine.valueChanged.connect(self.change_config) + # self.routine: SpinBox = self.ui.findChild(SpinBox, "spinBox_routine") + # self.routine.valueChanged.connect(self.change_config) - self.annihilation: SpinBox = self.ui.findChild(SpinBox, "spinBox_annihilation") - self.annihilation.valueChanged.connect(self.change_config) + # self.annihilation: SpinBox = self.ui.findChild(SpinBox, "spinBox_annihilation") + # self.annihilation.valueChanged.connect(self.change_config) - self.num: SpinBox = self.ui.findChild(SpinBox, "spinBox_numt") - self.num.valueChanged.connect(self.change_config) + # self.num: SpinBox = self.ui.findChild(SpinBox, "spinBox_numt") + # self.num.valueChanged.connect(self.change_config) - self.if_self_start: CheckBox = self.ui.findChild( - CheckBox, "checkBox_ifselfstart" - ) - self.if_self_start.stateChanged.connect(self.change_config) + # self.if_self_start: CheckBox = self.ui.findChild( + # CheckBox, "checkBox_ifselfstart" + # ) + # self.if_self_start.stateChanged.connect(self.change_config) - self.if_sleep: CheckBox = self.ui.findChild(CheckBox, "checkBox_ifsleep") - self.if_sleep.stateChanged.connect(self.change_config) + # self.if_sleep: CheckBox = self.ui.findChild(CheckBox, "checkBox_ifsleep") + # self.if_sleep.stateChanged.connect(self.change_config) - self.if_proxy_directly: CheckBox = self.ui.findChild( - CheckBox, "checkBox_ifproxydirectly" - ) - self.if_proxy_directly.stateChanged.connect(self.change_config) + # self.if_proxy_directly: CheckBox = self.ui.findChild( + # CheckBox, "checkBox_ifproxydirectly" + # ) + # self.if_proxy_directly.stateChanged.connect(self.change_config) - self.if_send_mail: CheckBox = self.ui.findChild(CheckBox, "checkBox_ifsendmail") - self.if_send_mail.stateChanged.connect(self.change_config) + # self.if_send_mail: CheckBox = self.ui.findChild(CheckBox, "checkBox_ifsendmail") + # self.if_send_mail.stateChanged.connect(self.change_config) - self.mail_address: LineEdit = self.ui.findChild( - LineEdit, "lineEdit_mailaddress" - ) - self.mail_address.textChanged.connect(self.change_config) + # self.mail_address: LineEdit = self.ui.findChild( + # LineEdit, "lineEdit_mailaddress" + # ) + # self.mail_address.textChanged.connect(self.change_config) - self.if_send_error_only: CheckBox = self.ui.findChild( - CheckBox, "checkBox_ifonlyerror" - ) - self.if_send_error_only.stateChanged.connect(self.change_config) + # self.if_send_error_only: CheckBox = self.ui.findChild( + # CheckBox, "checkBox_ifonlyerror" + # ) + # self.if_send_error_only.stateChanged.connect(self.change_config) - self.if_silence: CheckBox = self.ui.findChild(CheckBox, "checkBox_silence") - self.if_silence.stateChanged.connect(self.change_config) + # self.if_silence: CheckBox = self.ui.findChild(CheckBox, "checkBox_silence") + # self.if_silence.stateChanged.connect(self.change_config) - self.boss_key: LineEdit = self.ui.findChild(LineEdit, "lineEdit_boss") - self.boss_key.textChanged.connect(self.change_config) + # self.boss_key: LineEdit = self.ui.findChild(LineEdit, "lineEdit_boss") + # self.boss_key.textChanged.connect(self.change_config) - self.if_to_tray: CheckBox = self.ui.findChild(CheckBox, "checkBox_iftotray") - self.if_to_tray.stateChanged.connect(self.change_config) + # self.if_to_tray: CheckBox = self.ui.findChild(CheckBox, "checkBox_iftotray") + # self.if_to_tray.stateChanged.connect(self.change_config) - self.check_update: PushButton = self.ui.findChild( - PushButton, "pushButton_check_update" - ) - self.check_update.setIcon(FluentIcon.UPDATE) - self.check_update.clicked.connect(self.check_version) + # self.check_update: PushButton = self.ui.findChild( + # PushButton, "pushButton_check_update" + # ) + # self.check_update.setIcon(FluentIcon.UPDATE) + # self.check_update.clicked.connect(self.check_version) - self.tips: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_tips") - self.tips.setOpenExternalLinks(True) + # self.tips: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_tips") + # self.tips.setOpenExternalLinks(True) - self.run_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_run") - self.wait_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_wait") - self.over_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_over") - self.error_text: TextBrowser = self.ui.findChild( - TextBrowser, "textBrowser_error" - ) - self.log_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_log") + # self.run_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_run") + # self.wait_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_wait") + # self.over_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_over") + # self.error_text: TextBrowser = self.ui.findChild( + # TextBrowser, "textBrowser_error" + # ) + # self.log_text: TextBrowser = self.ui.findChild(TextBrowser, "textBrowser_log") - self.start_time: List[Tuple[CheckBox, TimePicker]] = [] - for i in range(10): - self.start_time.append( - [ - self.ui.findChild(CheckBox, f"checkBox_t{i + 1}"), - self.ui.findChild(TimePicker, f"timeEdit_{i + 1}"), - ] - ) - self.start_time[i][0].stateChanged.connect(self.change_config) - self.start_time[i][1].timeChanged.connect(self.change_config) + # self.start_time: List[Tuple[CheckBox, TimePicker]] = [] + # for i in range(10): + # self.start_time.append( + # [ + # self.ui.findChild(CheckBox, f"checkBox_t{i + 1}"), + # self.ui.findChild(TimePicker, f"timeEdit_{i + 1}"), + # ] + # ) + # self.start_time[i][0].stateChanged.connect(self.change_config) + # self.start_time[i][1].timeChanged.connect(self.change_config) - self.change_password: PushButton = self.ui.findChild( - PushButton, "pushButton_changePASSWORD" - ) - self.change_password.setIcon(FluentIcon.VPN) - self.change_password.clicked.connect(self.change_PASSWORD) + # self.change_password: PushButton = self.ui.findChild( + # PushButton, "pushButton_changePASSWORD" + # ) + # self.change_password.setIcon(FluentIcon.VPN) + # self.change_password.clicked.connect(self.change_PASSWORD) # 初始化线程 self.MaaManager = MaaManager(self.config) @@ -332,16 +247,16 @@ class Main(QWidget): self.MaaManager.get_json.connect(self.get_maa_config) self.MaaManager.set_silence.connect(self.switch_silence) - self.last_time = "0000-00-00 00:00" - self.Timer = QtCore.QTimer() - self.Timer.timeout.connect(self.set_theme) - self.Timer.timeout.connect(self.set_system) - self.Timer.timeout.connect(self.timed_start) - self.Timer.start(1000) + # self.last_time = "0000-00-00 00:00" + # self.Timer = QtCore.QTimer() + # self.Timer.timeout.connect(self.set_theme) + # self.Timer.timeout.connect(self.set_system) + # self.Timer.timeout.connect(self.timed_start) + # self.Timer.start(1000) # 载入GUI数据 - self.update_user_info("normal") - self.update_config() + # self.update_user_info("normal") + # self.update_config() # 启动后直接开始代理 if self.config.content["Default"]["SelfSet.IfProxyDirectly"] == "True": @@ -365,86 +280,6 @@ class Main(QWidget): if choice.exec(): break - def change_PASSWORD(self) -> None: - """修改管理密钥""" - - # 获取用户信息 - self.config.cur.execute("SELECT * FROM adminx WHERE True") - data = self.config.cur.fetchall() - - if len(data) == 0: - choice = MessageBox("验证通过", "当前无用户,验证自动通过", self.ui) - choice.cancelButton.hide() - choice.buttonLayout.insertStretch(1) - # 获取新的管理密钥 - if choice.exec(): - while True: - PASSWORD_new = self.read("newkey") - if PASSWORD_new == None: - choice = MessageBox( - "确认", - "您没有输入新的管理密钥,是否取消修改管理密钥?", - self.ui, - ) - if choice.exec(): - break - else: - # 修改管理密钥 - self.PASSWORD = PASSWORD_new - self.crypto.get_PASSWORD(self.PASSWORD) - choice = MessageBox("操作成功", "管理密钥修改成功", self.ui) - choice.cancelButton.hide() - choice.buttonLayout.insertStretch(1) - if choice.exec(): - break - else: - # 验证管理密钥 - if_change = True - while if_change: - if self.read("oldkey"): - # 验证旧管理密钥 - if not self.crypto.check_PASSWORD(self.PASSWORD): - choice = MessageBox("错误", "管理密钥错误", self.ui) - choice.cancelButton.hide() - choice.buttonLayout.insertStretch(1) - if choice.exec(): - pass - else: - # 获取新的管理密钥 - while True: - PASSWORD_new = self.read("newkey") - if PASSWORD_new == None: - choice = MessageBox( - "确认", - "您没有输入新的管理密钥,是否取消修改管理密钥?", - self.ui, - ) - if choice.exec(): - if_change = False - break - # 修改管理密钥 - else: - self.crypto.change_PASSWORD( - data, self.PASSWORD, PASSWORD_new - ) - self.PASSWORD = PASSWORD_new - choice = MessageBox( - "操作成功", "管理密钥修改成功", self.ui - ) - choice.cancelButton.hide() - choice.buttonLayout.insertStretch(1) - if choice.exec(): - if_change = False - break - else: - choice = MessageBox( - "确认", - "您没有输入管理密钥,是否取消修改管理密钥?", - self.ui, - ) - if choice.exec(): - break - def update_user_info(self, operation: str) -> None: """将本地数据库中的用户配置同步至GUI的用户管理界面""" @@ -1518,111 +1353,6 @@ class Main(QWidget): self.run_now.setEnabled(True) self.check_start.setEnabled(True) - def check_version(self): - """检查版本更新,调起文件下载进程""" - - # 从本地版本信息文件获取当前版本信息 - with self.config.version_path.open(mode="r", encoding="utf-8") as f: - version_current = json.load(f) - main_version_current = list( - map(int, version_current["main_version"].split(".")) - ) - updater_version_current = list( - map(int, version_current["updater_version"].split(".")) - ) - # 检查更新器是否存在 - if not (self.config.app_path / "Updater.exe").exists(): - updater_version_current = [0, 0, 0, 0] - - # 从远程服务器获取最新版本信息 - for _ in range(3): - try: - response = requests.get( - "https://gitee.com/DLmaster_361/AUTO_MAA/raw/main/resources/version.json" - ) - version_remote = response.json() - break - except Exception as e: - err = e - time.sleep(0.1) - else: - choice = MessageBox( - "错误", - f"获取版本信息时出错:\n{err}", - self.ui, - ) - choice.cancelButton.hide() - choice.buttonLayout.insertStretch(1) - if choice.exec(): - return None - - main_version_remote = list(map(int, version_remote["main_version"].split("."))) - updater_version_remote = list( - map(int, version_remote["updater_version"].split(".")) - ) - - # 有版本更新 - if (main_version_remote > main_version_current) or ( - updater_version_remote > updater_version_current - ): - - # 生成版本更新信息 - if main_version_remote > main_version_current: - main_version_info = f" 主程序:{version_text(main_version_current)} --> {version_text(main_version_remote)}\n" - else: - main_version_info = ( - f" 主程序:{version_text(main_version_current)}\n" - ) - if updater_version_remote > updater_version_current: - updater_version_info = f" 更新器:{version_text(updater_version_current)} --> {version_text(updater_version_remote)}\n" - else: - updater_version_info = ( - f" 更新器:{version_text(updater_version_current)}\n" - ) - - # 询问是否开始版本更新 - choice = MessageBox( - "版本更新", - f"发现新版本:\n{main_version_info}{updater_version_info} 更新说明:\n{version_remote['announcement'].replace("\n# ","\n !").replace("\n## ","\n - ").replace("\n- ","\n · ")}\n\n是否开始更新?\n\n 注意:主程序更新时AUTO_MAA将自动关闭", - self.ui, - ) - if not choice.exec(): - return None - - # 更新更新器 - if updater_version_remote > updater_version_current: - # 创建更新进程 - self.updater = Updater( - self.config.app_path, - "AUTO_MAA更新器", - main_version_remote, - updater_version_remote, - ) - # 完成更新器的更新后更新主程序 - if main_version_remote > main_version_current: - self.updater.update_process.accomplish.connect(self.update_main) - # 显示更新页面 - self.updater.ui.show() - - # 更新主程序 - elif main_version_remote > main_version_current: - self.update_main() - - # 无版本更新 - else: - self.notify.push_notification("已是最新版本~", " ", " ", 3) - - def update_main(self): - """更新主程序""" - - subprocess.Popen( - str(self.config.app_path / "Updater.exe"), - shell=True, - creationflags=subprocess.CREATE_NO_WINDOW, - ) - self.close() - QApplication.quit() - def server_date(self): """获取当前的服务器日期""" @@ -1630,194 +1360,3 @@ class Main(QWidget): if dt.time() < datetime.datetime.min.time().replace(hour=4): dt = dt - datetime.timedelta(days=1) return dt.strftime("%Y-%m-%d") - - -class AUTO_MAA(QMainWindow): - - if_save = True - - def __init__(self, config: AppConfig, notify: Notification, crypto: CryptoHandler): - super(AUTO_MAA, self).__init__() - - self.config = config - self.notify = notify - - self.config.open_database() - - # 创建主窗口 - self.main = Main(config=config, notify=notify, crypto=crypto) - self.setCentralWidget(self.main.ui) - self.setWindowIcon( - QIcon(str(self.config.app_path / "resources/icons/AUTO_MAA.ico")) - ) - self.setWindowTitle("AUTO_MAA") - - # 创建系统托盘及其菜单 - self.tray = QSystemTrayIcon( - QIcon(str(self.config.app_path / "resources/icons/AUTO_MAA.ico")), - self, - ) - self.tray.setToolTip("AUTO_MAA") - self.tray_menu = RoundMenu() - - # 显示主界面菜单项 - self.tray_menu.addAction( - Action(FluentIcon.CAFE, "显示主界面", triggered=self.show_main) - ) - self.tray_menu.addSeparator() - - # 开始任务菜单项 - self.tray_menu.addActions( - [ - Action( - FluentIcon.PLAY, - "运行日常代理", - triggered=lambda: self.start_task("日常代理"), - ), - # Action( - # FluentIcon.PLAY, - # "运行人工排查", - # triggered=lambda: self.start_task("人工排查"), - # ), - Action(FluentIcon.PAUSE, "中止当前任务", triggered=self.stop_task), - ] - ) - self.tray_menu.addSeparator() - - # 退出主程序菜单项 - self.tray_menu.addAction( - Action(FluentIcon.POWER_BUTTON, "退出主程序", triggered=self.kill_main) - ) - - # 设置托盘菜单 - self.tray.setContextMenu(self.tray_menu) - self.tray.activated.connect(self.on_tray_activated) - - self.show_main() - - def show_tray(self): - """最小化到托盘""" - if self.if_save: - self.set_ui("保存") - self.hide() - self.tray.show() - - def show_main(self): - """显示主界面""" - self.set_ui("配置") - self.tray.hide() - - def on_tray_activated(self, reason): - """双击返回主界面""" - if reason == QSystemTrayIcon.DoubleClick: - self.show_main() - - def start_task(self, mode): - """调起对应任务""" - if self.main.MaaManager.isRunning(): - self.notify.push_notification( - f"无法运行{mode}!", - "当前已有任务正在运行,请在该任务结束后重试", - "当前已有任务正在运行,请在该任务结束后重试", - 3, - ) - else: - self.main.maa_starter(mode) - - def stop_task(self): - """中止当前任务""" - if self.main.MaaManager.isRunning(): - if ( - self.main.MaaManager.mode == "日常代理" - or self.main.MaaManager.mode == "人工排查" - ): - self.main.maa_ender(f"{self.main.MaaManager.mode}_结束") - elif "设置MAA" in self.main.MaaManager.mode: - self.notify.push_notification( - "正在设置MAA!", - "正在运行设置MAA任务,无法中止", - "正在运行设置MAA任务,无法中止", - 3, - ) - else: - self.notify.push_notification( - "无任务运行!", - "当前无任务正在运行,无需中止", - "当前无任务正在运行,无需中止", - 3, - ) - - def kill_main(self): - """退出主程序""" - self.close() - QApplication.quit() - - def set_ui(self, mode): - """设置窗口相关属性""" - - # 保存窗口相关属性 - if mode == "保存": - - self.config.content["Default"][ - "SelfSet.UIsize" - ] = f"{self.geometry().width()}x{self.geometry().height()}" - self.config.content["Default"][ - "SelfSet.UIlocation" - ] = f"{self.geometry().x()}x{self.geometry().y()}" - if self.isMaximized(): - self.config.content["Default"]["SelfSet.UImaximized"] = "True" - else: - self.config.content["Default"]["SelfSet.UImaximized"] = "False" - self.config.save_config() - - # 配置窗口相关属性 - elif mode == "配置": - - self.if_save = False - - size = list( - map(int, self.config.content["Default"]["SelfSet.UIsize"].split("x")) - ) - location = list( - map( - int, self.config.content["Default"]["SelfSet.UIlocation"].split("x") - ) - ) - self.setGeometry(location[0], location[1], size[0], size[1]) - if self.config.content["Default"]["SelfSet.UImaximized"] == "True": - self.showMinimized() - self.showMaximized() - else: - self.showMinimized() - self.showNormal() - - self.if_save = True - - def changeEvent(self, event: QtCore.QEvent): - """重写后的 changeEvent""" - - # 最小化到托盘功能实现 - if event.type() == QtCore.QEvent.WindowStateChange: - if self.windowState() & QtCore.Qt.WindowMinimized: - if self.config.content["Default"]["SelfSet.IfToTray"] == "True": - self.show_tray() - - # 保留其它 changeEvent 方法 - return super().changeEvent(event) - - def closeEvent(self, event: QCloseEvent): - """清理残余进程""" - - self.set_ui("保存") - - # 清理各功能线程 - self.main.Timer.stop() - self.main.Timer.deleteLater() - self.main.MaaManager.requestInterruption() - self.main.MaaManager.quit() - self.main.MaaManager.wait() - - # 关闭数据库连接 - self.config.close_database() - - event.accept() diff --git a/app/ui/main_window.py b/app/ui/main_window.py new file mode 100644 index 0000000..18e85f0 --- /dev/null +++ b/app/ui/main_window.py @@ -0,0 +1,312 @@ +# +# Copyright © <2024> + +# This file is part of AUTO_MAA. + +# AUTO_MAA is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, +# or (at your option) any later version. + +# AUTO_MAA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with AUTO_MAA. If not, see . + +# DLmaster_361@163.com + +""" +AUTO_MAA +AUTO_MAA主界面 +v4.2 +作者:DLmaster_361 +""" + +from PySide6.QtWidgets import ( + QWidget, # + QMainWindow, # + QApplication, # + QSystemTrayIcon, # + QFileDialog, # + QTabWidget, # + QToolBox, # + QComboBox, # + QTableWidgetItem, # + QHeaderView, # + QVBoxLayout, +) +from qfluentwidgets import ( + Action, + PushButton, + LineEdit, + PasswordLineEdit, + TextBrowser, + TableWidget, + TimePicker, + SystemTrayMenu, + ComboBox, + CheckBox, + SpinBox, + FluentIcon, + RoundMenu, + MessageBox, + MessageBoxBase, + HeaderCardWidget, + BodyLabel, + Dialog, + SingleDirectionScrollArea, + SubtitleLabel, + MSFluentWindow, + NavigationItemPosition, +) +from PySide6.QtUiTools import QUiLoader +from PySide6.QtGui import QIcon, QCloseEvent +from PySide6 import QtCore +from functools import partial +from typing import List, Tuple +from pathlib import Path +import json +import datetime +import ctypes +import subprocess +import shutil +import win32gui +import win32process +import psutil +import pyautogui +import time +import winreg +import requests + +uiLoader = QUiLoader() + +from app import AppConfig, MaaConfig +from app.services import Notification, CryptoHandler +from app.utils import Updater, version_text +from .Widget import InputMessageBox, LineEditSettingCard, SpinBoxSettingCard +from .setting import Setting +from .member_manager import MemberManager + + +class AUTO_MAA(MSFluentWindow): + + if_save = True + + def __init__(self, config: AppConfig, notify: Notification, crypto: CryptoHandler): + super(AUTO_MAA, self).__init__() + + self.config = config + self.notify = notify + + self.config.open_database() + + # 创建主窗口 + self.setting = Setting(config=config, notify=notify, crypto=crypto) + self.member_manager = MemberManager(config=config, notify=notify, crypto=crypto) + + self.addSubInterface( + self.setting, + FluentIcon.SETTING, + "设置", + FluentIcon.SETTING, + NavigationItemPosition.BOTTOM, + ) + self.addSubInterface( + self.member_manager, + FluentIcon.ROBOT, + "脚本管理", + FluentIcon.ROBOT, + NavigationItemPosition.TOP, + ) + + self.setWindowIcon( + QIcon(str(self.config.app_path / "resources/icons/AUTO_MAA.ico")) + ) + self.setWindowTitle("AUTO_MAA") + + # 创建系统托盘及其菜单 + self.tray = QSystemTrayIcon( + QIcon(str(self.config.app_path / "resources/icons/AUTO_MAA.ico")), + self, + ) + self.tray.setToolTip("AUTO_MAA") + self.tray_menu = SystemTrayMenu() + + # 显示主界面菜单项 + self.tray_menu.addAction( + Action(FluentIcon.CAFE, "显示主界面", triggered=self.show_main) + ) + self.tray_menu.addSeparator() + + # 开始任务菜单项 + # self.tray_menu.addActions( + # [ + # Action( + # FluentIcon.PLAY, + # "运行日常代理", + # triggered=lambda: self.start_task("日常代理"), + # ), + # Action( + # FluentIcon.PLAY, + # "运行人工排查", + # triggered=lambda: self.start_task("人工排查"), + # ), + # Action(FluentIcon.PAUSE, "中止当前任务", triggered=self.stop_task), + # ] + # ) + # self.tray_menu.addSeparator() + + # 退出主程序菜单项 + self.tray_menu.addAction( + Action(FluentIcon.POWER_BUTTON, "退出主程序", triggered=self.kill_main) + ) + + # 设置托盘菜单 + self.tray.setContextMenu(self.tray_menu) + self.tray.activated.connect(self.on_tray_activated) + + self.show_main() + + def show_tray(self): + """最小化到托盘""" + if self.if_save: + self.set_ui("保存") + self.hide() + self.tray.show() + + def show_main(self): + """显示主界面""" + self.set_ui("配置") + self.tray.hide() + + def on_tray_activated(self, reason): + """双击返回主界面""" + if reason == QSystemTrayIcon.DoubleClick: + self.show_main() + + def start_task(self, mode): + """调起对应任务""" + if self.main.MaaManager.isRunning(): + self.notify.push_notification( + f"无法运行{mode}!", + "当前已有任务正在运行,请在该任务结束后重试", + "当前已有任务正在运行,请在该任务结束后重试", + 3, + ) + else: + self.main.maa_starter(mode) + + def stop_task(self): + """中止当前任务""" + if self.main.MaaManager.isRunning(): + if ( + self.main.MaaManager.mode == "日常代理" + or self.main.MaaManager.mode == "人工排查" + ): + self.main.maa_ender(f"{self.main.MaaManager.mode}_结束") + elif "设置MAA" in self.main.MaaManager.mode: + self.notify.push_notification( + "正在设置MAA!", + "正在运行设置MAA任务,无法中止", + "正在运行设置MAA任务,无法中止", + 3, + ) + else: + self.notify.push_notification( + "无任务运行!", + "当前无任务正在运行,无需中止", + "当前无任务正在运行,无需中止", + 3, + ) + + def kill_main(self): + """退出主程序""" + self.close() + QApplication.quit() + + def set_ui(self, mode): + """设置窗口相关属性""" + + # 保存窗口相关属性 + if mode == "保存": + + self.config.global_config.set( + self.config.global_config.ui_size, + f"{self.geometry().width()}x{self.geometry().height()}", + ) + self.config.global_config.set( + self.config.global_config.ui_location, + f"{self.geometry().x()}x{self.geometry().y()}", + ) + if self.isMaximized(): + self.config.global_config.set( + self.config.global_config.ui_maximized, True + ) + else: + self.config.global_config.set( + self.config.global_config.ui_maximized, False + ) + self.config.global_config.save() + + # 配置窗口相关属性 + elif mode == "配置": + + self.if_save = False + + size = list( + map( + int, + self.config.global_config.get( + self.config.global_config.ui_size + ).split("x"), + ) + ) + location = list( + map( + int, + self.config.global_config.get( + self.config.global_config.ui_location + ).split("x"), + ) + ) + self.setGeometry(location[0], location[1], size[0], size[1]) + if self.config.global_config.get(self.config.global_config.ui_maximized): + self.showMinimized() + self.showMaximized() + else: + self.showMinimized() + self.showNormal() + + self.if_save = True + + def changeEvent(self, event: QtCore.QEvent): + """重写后的 changeEvent""" + + # 最小化到托盘功能实现 + if event.type() == QtCore.QEvent.WindowStateChange: + if self.windowState() & QtCore.Qt.WindowMinimized: + if self.config.global_config.get(self.config.global_config.ui_IfToTray): + self.show_tray() + + # 保留其它 changeEvent 方法 + return super().changeEvent(event) + + def closeEvent(self, event: QCloseEvent): + """清理残余进程""" + + self.set_ui("保存") + + # 清理各功能线程 + # self.main.Timer.stop() + # self.main.Timer.deleteLater() + # self.main.MaaManager.requestInterruption() + # self.main.MaaManager.quit() + # self.main.MaaManager.wait() + + # 关闭数据库连接 + self.config.close_database() + + event.accept() diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py new file mode 100644 index 0000000..a3e78a9 --- /dev/null +++ b/app/ui/member_manager.py @@ -0,0 +1,527 @@ +# +# Copyright © <2024> + +# This file is part of AUTO_MAA. + +# AUTO_MAA is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, +# or (at your option) any later version. + +# AUTO_MAA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with AUTO_MAA. If not, see . + +# DLmaster_361@163.com + +""" +AUTO_MAA +AUTO_MAA设置界面 +v4.2 +作者:DLmaster_361 +""" + +from PySide6.QtWidgets import ( + QWidget, # + QMainWindow, # + QApplication, # + QSystemTrayIcon, # + QFileDialog, # + QTabWidget, # + QToolBox, # + QComboBox, # + QTableWidgetItem, # + QHeaderView, # + QVBoxLayout, + QStackedWidget, + QHBoxLayout, +) +from qfluentwidgets import ( + Action, + PushButton, + LineEdit, + PasswordLineEdit, + qconfig, + TableWidget, + Pivot, + TimePicker, + ComboBox, + CheckBox, + ScrollArea, + SpinBox, + FluentIcon, + SwitchButton, + RoundMenu, + MessageBox, + MessageBoxBase, + HeaderCardWidget, + BodyLabel, + CommandBar, + SubtitleLabel, + GroupHeaderCardWidget, + SwitchSettingCard, + ExpandGroupSettingCard, + SingleDirectionScrollArea, + PushSettingCard, +) +from PySide6.QtUiTools import QUiLoader +from PySide6.QtGui import QIcon, QCloseEvent +from PySide6 import QtCore +from functools import partial +from typing import List, Tuple +from pathlib import Path +import os +import datetime +import ctypes +import subprocess +import shutil +import win32gui +import win32process +import psutil +import pyautogui +import time +import winreg +import requests + +uiLoader = QUiLoader() + +from app import AppConfig, MaaConfig +from app.services import Notification, CryptoHandler +from app.utils import Updater, version_text +from .Widget import InputMessageBox, LineEditSettingCard, SpinBoxSettingCard + + +class MemberManager(QWidget): + + def __init__(self, config: AppConfig, notify: Notification, crypto: CryptoHandler): + super(MemberManager, self).__init__() + + self.setObjectName("脚本管理") + + self.config = config + self.notify = notify + self.crypto = crypto + + layout = QVBoxLayout(self) + + self.tools = CommandBar() + + self.member_manager = MemberSettingBox(self.config) + + # 逐个添加动作 + self.tools.addActions( + [ + Action( + FluentIcon.ADD_TO, "新建脚本实例", triggered=self.add_setting_box + ), + Action( + FluentIcon.REMOVE_FROM, + "删除脚本实例", + triggered=self.del_setting_box, + ), + ] + ) + self.tools.addSeparator() + self.tools.addActions( + [ + Action( + FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_setting_box + ), + Action( + FluentIcon.RIGHT_ARROW, + "向右移动", + triggered=self.right_setting_box, + ), + ] + ) + + # 批量添加动作 + self.tools.addAction( + Action( + FluentIcon.HIDE, + "显示/隐藏密码", + checkable=True, + triggered=self.show_password, + ), + ) + + layout.addWidget(self.tools) + layout.addWidget(self.member_manager) + + def add_setting_box(self): + """添加一个脚本实例""" + + choice = InputMessageBox( + self, "选择一个脚本类型并添加相应脚本实例", "选择脚本类型", "选择", ["MAA"] + ) + if choice.exec() and choice.input.currentIndex() != -1: + + if choice.input.currentText() == "MAA": + + index = len(self.member_manager.search_member()) + 1 + + qconfig.load( + self.config.app_path / f"config/MaaConfig/脚本_{index}/config.json", + self.config.maa_config, + ) + + self.config.maa_config.set(self.config.maa_config.MaaSet_Name, "") + self.config.maa_config.set(self.config.maa_config.MaaSet_Path, ".") + self.config.maa_config.set( + self.config.maa_config.RunSet_AnnihilationTimeLimit, 40 + ) + self.config.maa_config.set( + self.config.maa_config.RunSet_RoutineTimeLimit, 10 + ) + self.config.maa_config.set( + self.config.maa_config.RunSet_RunTimesLimit, 3 + ) + self.config.maa_config.set(self.config.maa_config.MaaSet_Name, "") + self.config.maa_config.set(self.config.maa_config.MaaSet_Name, "") + self.config.maa_config.set(self.config.maa_config.MaaSet_Name, "") + self.config.maa_config.save() + + self.member_manager.add_MaaSettingBox(index) + self.member_manager.switch_SettingBox(index) + + def del_setting_box(self): + """删除一个脚本实例""" + + name = self.member_manager.pivot.currentRouteKey() + + if name == None: + return None + + choice = MessageBox( + "确认", + f"确定要删除 {name} 实例吗?", + self, + ) + if choice.exec(): + + member_list = self.member_manager.search_member() + move_list = [_ for _ in member_list if int(_[0][3:]) > int(name[3:])] + + type = [_[1] for _ in member_list if _[0] == name] + index = max(int(name[3:]) - 1, 1) + + shutil.rmtree(self.config.app_path / f"config/{type[0]}Config/{name}") + for member in move_list: + if ( + self.config.app_path / f"config/{member[1]}Config/{member[0]}" + ).exists(): + ( + self.config.app_path / f"config/{member[1]}Config/{member[0]}" + ).rename( + self.config.app_path + / f"config/{member[1]}Config/{member[0][:3]}{int(member[0][3:])-1}", + ) + + self.member_manager.clear_SettingBox() + self.member_manager.show_SettingBox() + self.member_manager.switch_SettingBox(index, if_after_clear=True) + + def left_setting_box(self): + """向左移动脚本实例""" + + name = self.member_manager.pivot.currentRouteKey() + + if name == None: + return None + + member_list = self.member_manager.search_member() + index = int(name[3:]) + + if index == 1: + return None + + type_right = [_[1] for _ in member_list if _[0] == name] + type_left = [_[1] for _ in member_list if _[0] == f"脚本_{index-1}"] + + (self.config.app_path / f"config/{type_right[0]}Config/脚本_{index}").rename( + self.config.app_path / f"config/{type_right[0]}Config/脚本_0", + ) + (self.config.app_path / f"config/{type_left[0]}Config/脚本_{index-1}").rename( + self.config.app_path / f"config/{type_left[0]}Config/脚本_{index}", + ) + (self.config.app_path / f"config/{type_right[0]}Config/脚本_0").rename( + self.config.app_path / f"config/{type_right[0]}Config/脚本_{index-1}", + ) + + self.member_manager.clear_SettingBox() + self.member_manager.show_SettingBox() + self.member_manager.switch_SettingBox(index - 1, if_after_clear=True) + + def right_setting_box(self): + """向左移动脚本实例""" + + name = self.member_manager.pivot.currentRouteKey() + + if name == None: + return None + + member_list = self.member_manager.search_member() + index = int(name[3:]) + + if index == len(member_list): + return None + + type_left = [_[1] for _ in member_list if _[0] == name] + type_right = [_[1] for _ in member_list if _[0] == f"脚本_{index+1}"] + + (self.config.app_path / f"config/{type_left[0]}Config/脚本_{index}").rename( + self.config.app_path / f"config/{type_left[0]}Config/脚本_0", + ) + (self.config.app_path / f"config/{type_right[0]}Config/脚本_{index+1}").rename( + self.config.app_path / f"config/{type_right[0]}Config/脚本_{index}", + ) + (self.config.app_path / f"config/{type_left[0]}Config/脚本_0").rename( + self.config.app_path / f"config/{type_left[0]}Config/脚本_{index+1}", + ) + + self.member_manager.clear_SettingBox() + self.member_manager.show_SettingBox() + self.member_manager.switch_SettingBox(index + 1, if_after_clear=True) + + def show_password(self): + + pass + + +class MemberSettingBox(QWidget): + + def __init__(self, config: AppConfig): + super().__init__() + + self.setObjectName("脚本管理") + self.config = config + + self.pivot = Pivot(self) + self.stackedWidget = QStackedWidget(self) + self.Layout = QVBoxLayout(self) + + self.SubInterface: List[MaaSettingBox] = [] + + self.Layout.addWidget(self.pivot, 0, QtCore.Qt.AlignHCenter) + self.Layout.addWidget(self.stackedWidget) + self.Layout.setContentsMargins(0, 0, 0, 0) + + self.pivot.currentItemChanged.connect( + lambda index: self.stackedWidget.setCurrentWidget( + self.findChild(QWidget, index) + ) + ) + self.pivot.currentItemChanged.connect( + lambda index: qconfig.load( + self.config.app_path / f"config/MaaConfig/{index}/config.json", + self.config.maa_config, + ) + ) + + self.show_SettingBox() + self.switch_SettingBox(1) + + def show_SettingBox(self) -> None: + """加载所有子界面""" + + member_list = self.search_member() + + for member in member_list: + if member[1] == "Maa": + self.add_MaaSettingBox(int(member[0][3:])) + + def switch_SettingBox(self, index: int, if_after_clear: bool = False) -> None: + """切换到指定的子界面""" + + member_list = self.search_member() + + if index > len(member_list): + return None + + type = [_[1] for _ in member_list if _[0] == f"脚本_{index}"] + + if if_after_clear: + self.pivot.currentItemChanged.disconnect() + + self.stackedWidget.setCurrentWidget(self.SubInterface[index - 1]) + self.pivot.setCurrentItem(self.SubInterface[index - 1].objectName()) + qconfig.load( + self.config.app_path + / f"config/{type[0]}Config/{self.SubInterface[index-1].objectName()}/config.json", + self.config.maa_config, + ) + + if if_after_clear: + self.pivot.currentItemChanged.connect( + lambda index: self.stackedWidget.setCurrentWidget( + self.findChild(QWidget, index) + ) + ) + self.pivot.currentItemChanged.connect( + lambda index: qconfig.load( + self.config.app_path / f"config/MaaConfig/{index}/config.json", + self.config.maa_config, + ) + ) + + def clear_SettingBox(self) -> None: + """清空所有子界面""" + + for sub_interface in self.SubInterface: + self.stackedWidget.removeWidget(sub_interface) + sub_interface.deleteLater() + self.SubInterface.clear() + self.pivot.clear() + + def add_MaaSettingBox(self, uid: int) -> None: + """添加一个MAA设置界面""" + + maa_setting_box = MaaSettingBox(self.config, uid) + + self.SubInterface.append(maa_setting_box) + + self.stackedWidget.addWidget(self.SubInterface[-1]) + + self.pivot.addItem(routeKey=f"脚本_{uid}", text=f"脚本 {uid}") + + def search_member(self) -> list: + """搜索所有脚本实例""" + + member_list = [] + + if (self.config.app_path / "config/MaaConfig").exists(): + for subdir in (self.config.app_path / "config/MaaConfig").iterdir(): + if subdir.is_dir(): + member_list.append([subdir.name, "Maa"]) + + return member_list + + +class MaaSettingBox(QWidget): + + def __init__(self, config: AppConfig, uid: int): + super().__init__() + + self.setObjectName(f"脚本_{uid}") + + self.config = config + + layout = QVBoxLayout() + + scrollArea = ScrollArea() + scrollArea.setWidgetResizable(True) + + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + + self.app_setting = self.AppSettingCard(self, self.config.maa_config) + + content_layout.addWidget(self.app_setting) + content_layout.addStretch(1) + + scrollArea.setWidget(content_widget) + + layout.addWidget(scrollArea) + + self.setLayout(layout) + + class AppSettingCard(HeaderCardWidget): + + def __init__(self, parent=None, maa_config: MaaConfig = None): + super().__init__(parent) + + self.setTitle("MAA实例") + + self.maa_config = maa_config + + Layout = QVBoxLayout() + + self.card_Name = LineEditSettingCard( + "实例名称", + FluentIcon.EDIT, + "实例名称", + "用于标识MAA实例的名称", + self.maa_config.MaaSet_Name, + ) + self.card_Path = PushSettingCard( + "选择文件夹", + FluentIcon.FOLDER, + "MAA目录", + self.maa_config.get(self.maa_config.MaaSet_Path), + ) + self.card_Set = PushSettingCard( + "设置", + FluentIcon.HOME, + "MAA全局配置", + "简洁模式下MAA将继承全局配置", + ) + self.RunSet = self.RunSetSettingCard(self, self.maa_config) + + self.card_Path.clicked.connect(self.PathClicked) + + Layout.addWidget(self.card_Name) + Layout.addWidget(self.card_Path) + Layout.addWidget(self.card_Set) + Layout.addWidget(self.RunSet) + + self.viewLayout.addLayout(Layout) + + def PathClicked(self): + + folder = QFileDialog.getExistingDirectory(self, "选择MAA目录", "./") + if not folder or self.maa_config.get(self.maa_config.MaaSet_Path) == folder: + return + self.maa_config.set(self.maa_config.MaaSet_Path, folder) + self.card_Path.setContent(folder) + + class RunSetSettingCard(ExpandGroupSettingCard): + + def __init__(self, parent=None, maa_config: MaaConfig = None): + super().__init__( + FluentIcon.SETTING, + "运行", + "MAA运行调控选项", + parent, + ) + + self.maa_config = maa_config + + widget = QWidget() + Layout = QVBoxLayout(widget) + + self.AnnihilationTimeLimit = SpinBoxSettingCard( + (1, 1024), + FluentIcon.PAGE_RIGHT, + "剿灭代理超时限制", + "MAA日志无变化时间超过该阈值视为超时", + self.maa_config.RunSet_AnnihilationTimeLimit, + ) + + self.RoutineTimeLimit = SpinBoxSettingCard( + (1, 1024), + FluentIcon.PAGE_RIGHT, + "日常代理超时限制", + "MAA日志无变化时间超过该阈值视为超时", + self.maa_config.RunSet_RoutineTimeLimit, + ) + + self.RunTimesLimit = SpinBoxSettingCard( + (1, 1024), + FluentIcon.PAGE_RIGHT, + "代理重试次数限制", + "若超过该次数限制仍未完成代理,视为代理失败", + self.maa_config.RunSet_RunTimesLimit, + ) + + Layout.addWidget(self.AnnihilationTimeLimit) + Layout.addWidget(self.RoutineTimeLimit) + Layout.addWidget(self.RunTimesLimit) + + self.viewLayout.setContentsMargins(0, 0, 0, 0) + self.viewLayout.setSpacing(0) + + self.addGroupWidget(widget) diff --git a/app/ui/setting.py b/app/ui/setting.py new file mode 100644 index 0000000..d261f2b --- /dev/null +++ b/app/ui/setting.py @@ -0,0 +1,623 @@ +# +# Copyright © <2024> + +# This file is part of AUTO_MAA. + +# AUTO_MAA is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, +# or (at your option) any later version. + +# AUTO_MAA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with AUTO_MAA. If not, see . + +# DLmaster_361@163.com + +""" +AUTO_MAA +AUTO_MAA设置界面 +v4.2 +作者:DLmaster_361 +""" + +from PySide6.QtWidgets import ( + QWidget, # + QMainWindow, # + QApplication, # + QSystemTrayIcon, # + QFileDialog, # + QTabWidget, # + QToolBox, # + QComboBox, # + QTableWidgetItem, # + QHeaderView, # + QVBoxLayout, + QHBoxLayout, +) +from qfluentwidgets import ( + Action, + PushButton, + LineEdit, + PasswordLineEdit, + TextBrowser, + TableWidget, + TimePicker, + ComboBox, + CheckBox, + ScrollArea, + SpinBox, + FluentIcon, + SwitchButton, + RoundMenu, + MessageBox, + MessageBoxBase, + HeaderCardWidget, + BodyLabel, + Dialog, + SubtitleLabel, + GroupHeaderCardWidget, + SwitchSettingCard, + ExpandGroupSettingCard, + SingleDirectionScrollArea, + PushSettingCard, +) +from PySide6.QtUiTools import QUiLoader +from PySide6.QtGui import QIcon, QCloseEvent +from PySide6 import QtCore +from functools import partial +from typing import List, Tuple +from pathlib import Path +import json +import datetime +import ctypes +import subprocess +import shutil +import win32gui +import win32process +import psutil +import pyautogui +import time +import winreg +import requests + +uiLoader = QUiLoader() + +from app import AppConfig +from app.services import Notification, CryptoHandler +from app.utils import Updater, version_text +from .Widget import InputMessageBox, LineEditSettingCard + + +class Setting(QWidget): + + def __init__(self, config: AppConfig, notify: Notification, crypto: CryptoHandler): + super(Setting, self).__init__() + + self.setObjectName("设置") + + self.config = config + self.notify = notify + self.crypto = crypto + + layout = QVBoxLayout() + + scrollArea = ScrollArea() + scrollArea.setWidgetResizable(True) + + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + + self.function = FunctionSettingCard(self, self.config) + self.start = StartSettingCard(self, self.config) + self.ui = UiSettingCard(self, self.config) + self.notification = NotifySettingCard(self, self.config) + self.security = SecuritySettingCard(self) + self.updater = UpdaterSettingCard(self, self.config) + self.other = OtherSettingCard(self, self.config) + + self.security.card_changePASSWORD.clicked.connect(self.change_PASSWORD) + self.updater.card_CheckUpdate.clicked.connect(self.check_version) + self.other.card_Tips.clicked.connect(self.show_tips) + + content_layout.addWidget(self.function) + content_layout.addWidget(self.start) + content_layout.addWidget(self.ui) + content_layout.addWidget(self.notification) + content_layout.addWidget(self.security) + content_layout.addWidget(self.updater) + content_layout.addWidget(self.other) + + scrollArea.setWidget(content_widget) + + layout.addWidget(scrollArea) + + self.setLayout(layout) + + def check_PASSWORD(self) -> None: + """检查并配置管理密钥""" + + if self.config.key_path.exists(): + return None + + while True: + + choice = InputMessageBox( + self, + "未检测到管理密钥,请设置您的管理密钥", + "管理密钥", + "密码", + ) + if choice.exec() and choice.input.text() != "": + self.crypto.get_PASSWORD(choice.input.text()) + break + else: + choice = MessageBox( + "确认", "您没有输入管理密钥,确定要暂时跳过这一步吗?", self + ) + if choice.exec(): + break + + def change_PASSWORD(self) -> None: + """修改管理密钥""" + + # 获取用户信息 + self.config.cur.execute("SELECT * FROM adminx WHERE True") + data = self.config.cur.fetchall() + + if len(data) == 0: + + choice = MessageBox("验证通过", "当前无用户,验证自动通过", self) + choice.cancelButton.hide() + choice.buttonLayout.insertStretch(1) + + # 获取新的管理密钥 + if choice.exec(): + + while True: + + a = InputMessageBox( + self, "请输入新的管理密钥", "新管理密钥", "密码" + ) + if a.exec() and a.input.text() != "": + # 修改管理密钥 + self.crypto.get_PASSWORD(a.input.text()) + choice = MessageBox("操作成功", "管理密钥修改成功", self) + choice.cancelButton.hide() + choice.buttonLayout.insertStretch(1) + if choice.exec(): + break + else: + choice = MessageBox( + "确认", + "您没有输入新的管理密钥,是否取消修改管理密钥?", + self, + ) + if choice.exec(): + break + + else: + # 验证管理密钥 + if_change = True + + while if_change: + + choice = InputMessageBox( + self, "请输入旧的管理密钥", "旧管理密钥", "密码" + ) + if choice.exec() and choice.input.text() != "": + + # 验证旧管理密钥 + if self.crypto.check_PASSWORD(choice.input.text()): + + PASSWORD_old = choice.input.text() + # 获取新的管理密钥 + while True: + + choice = InputMessageBox( + self, "请输入新的管理密钥", "新管理密钥", "密码" + ) + if choice.exec() and choice.input.text() != "": + + # 修改管理密钥 + self.crypto.change_PASSWORD( + data, PASSWORD_old, choice.input.text() + ) + choice = MessageBox( + "操作成功", "管理密钥修改成功", self + ) + choice.cancelButton.hide() + choice.buttonLayout.insertStretch(1) + if choice.exec(): + if_change = False + break + + else: + + choice = MessageBox( + "确认", + "您没有输入新的管理密钥,是否取消修改管理密钥?", + self, + ) + if choice.exec(): + if_change = False + break + + else: + choice = MessageBox("错误", "管理密钥错误", self) + choice.cancelButton.hide() + choice.buttonLayout.insertStretch(1) + if choice.exec(): + pass + else: + choice = MessageBox( + "确认", + "您没有输入管理密钥,是否取消修改管理密钥?", + self, + ) + if choice.exec(): + break + + def check_version(self): + """检查版本更新,调起文件下载进程""" + + # 从本地版本信息文件获取当前版本信息 + with self.config.version_path.open(mode="r", encoding="utf-8") as f: + version_current = json.load(f) + main_version_current = list( + map(int, version_current["main_version"].split(".")) + ) + updater_version_current = list( + map(int, version_current["updater_version"].split(".")) + ) + # 检查更新器是否存在 + if not (self.config.app_path / "Updater.exe").exists(): + updater_version_current = [0, 0, 0, 0] + + # 从远程服务器获取最新版本信息 + for _ in range(3): + try: + response = requests.get( + "https://gitee.com/DLmaster_361/AUTO_MAA/raw/main/resources/version.json" + ) + version_remote = response.json() + break + except Exception as e: + err = e + time.sleep(0.1) + else: + choice = MessageBox( + "错误", + f"获取版本信息时出错:\n{err}", + self, + ) + choice.cancelButton.hide() + choice.buttonLayout.insertStretch(1) + if choice.exec(): + return None + + main_version_remote = list(map(int, version_remote["main_version"].split("."))) + updater_version_remote = list( + map(int, version_remote["updater_version"].split(".")) + ) + + # 有版本更新 + if (main_version_remote > main_version_current) or ( + updater_version_remote > updater_version_current + ): + + # 生成版本更新信息 + if main_version_remote > main_version_current: + main_version_info = f" 主程序:{version_text(main_version_current)} --> {version_text(main_version_remote)}\n" + else: + main_version_info = ( + f" 主程序:{version_text(main_version_current)}\n" + ) + if updater_version_remote > updater_version_current: + updater_version_info = f" 更新器:{version_text(updater_version_current)} --> {version_text(updater_version_remote)}\n" + else: + updater_version_info = ( + f" 更新器:{version_text(updater_version_current)}\n" + ) + + # 询问是否开始版本更新 + choice = MessageBox( + "版本更新", + f"发现新版本:\n{main_version_info}{updater_version_info} 更新说明:\n{version_remote['announcement'].replace("\n# ","\n !").replace("\n## ","\n - ").replace("\n- ","\n · ")}\n\n是否开始更新?\n\n 注意:主程序更新时AUTO_MAA将自动关闭", + self, + ) + if not choice.exec(): + return None + + # 更新更新器 + if updater_version_remote > updater_version_current: + # 创建更新进程 + self.updater = Updater( + self.config.app_path, + "AUTO_MAA更新器", + main_version_remote, + updater_version_remote, + ) + # 完成更新器的更新后更新主程序 + if main_version_remote > main_version_current: + self.updater.update_process.accomplish.connect(self.update_main) + # 显示更新页面 + self.updater.ui.show() + + # 更新主程序 + elif main_version_remote > main_version_current: + self.update_main() + + # 无版本更新 + else: + self.notify.push_notification("已是最新版本~", " ", " ", 3) + + def update_main(self): + """更新主程序""" + + subprocess.Popen( + str(self.config.app_path / "Updater.exe"), + shell=True, + creationflags=subprocess.CREATE_NO_WINDOW, + ) + self.close() + QApplication.quit() + + def show_tips(self): + """显示小贴士""" + + choice = MessageBox("小贴士", "这里什么都没有~", self) + choice.cancelButton.hide() + choice.buttonLayout.insertStretch(1) + if choice.exec(): + pass + + +class FunctionSettingCard(HeaderCardWidget): + + def __init__(self, parent=None, config: AppConfig = None): + super().__init__(parent) + + self.setTitle("功能") + + self.config = config.global_config + + Layout = QVBoxLayout() + + self.card_IfSleep = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="启动时阻止系统休眠", + content="仅阻止电脑自动休眠,不会影响屏幕是否熄灭", + configItem=self.config.function_IfSleep, + ) + + self.card_IfSilence = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="静默模式", + content="将各代理窗口置于后台运行,减少对前台的干扰", + configItem=self.config.function_IfSilence, + ) + + # 添加各组到设置卡中 + Layout.addWidget(self.card_IfSleep) + Layout.addWidget(self.card_IfSilence) + + self.viewLayout.addLayout(Layout) + + +class StartSettingCard(HeaderCardWidget): + + def __init__(self, parent=None, config: AppConfig = None): + super().__init__(parent) + + self.setTitle("启动") + + self.config = config.global_config + + Layout = QVBoxLayout() + + self.card_IfSelfStart = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="开机时自动启动", + content="将AUTO_MAA添加到开机启动项", + configItem=self.config.start_IfSelfStart, + ) + + self.card_IfRunDirectly = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="启动后直接运行", + content="启动AUTO_MAA后自动运行任务", + configItem=self.config.start_IfRunDirectly, + ) + + # 添加各组到设置卡中 + Layout.addWidget( + self.card_IfSelfStart, + ) + Layout.addWidget(self.card_IfRunDirectly) + + self.viewLayout.addLayout(Layout) + + +class UiSettingCard(HeaderCardWidget): + + def __init__(self, parent=None, config: AppConfig = None): + super().__init__(parent) + + self.setTitle("界面") + + self.config = config.global_config + + Layout = QVBoxLayout() + + self.card_IfShowTray = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="显示托盘图标", + content="常态显示托盘图标", + configItem=self.config.ui_IfShowTray, + ) + + self.card_IfToTray = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="最小化到托盘", + content="最小化时隐藏到托盘", + configItem=self.config.ui_IfToTray, + ) + + # 添加各组到设置卡中 + Layout.addWidget(self.card_IfShowTray) + Layout.addWidget(self.card_IfToTray) + + self.viewLayout.addLayout(Layout) + + +class NotifySettingCard(HeaderCardWidget): + + def __init__(self, parent=None, config: AppConfig = None): + super().__init__(parent) + + self.setTitle("通知") + + self.config = config + + Layout = QVBoxLayout() + + self.card_IfPushPlyer = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="推送系统通知", + content="推送系统级通知,不会在通知中心停留", + configItem=self.config.global_config.notify_IfPushPlyer, + ) + + self.card_SendMail = self.SendMailSettingCard(self, self.config) + + Layout.addWidget(self.card_IfPushPlyer) + Layout.addWidget(self.card_SendMail) + + self.viewLayout.addLayout(Layout) + + class SendMailSettingCard(ExpandGroupSettingCard): + + def __init__(self, parent=None, config: AppConfig = None): + super().__init__( + FluentIcon.SETTING, + "推送邮件通知", + "通过AUTO_MAA官方通知服务邮箱推送任务结果", + parent, + ) + + self.config = config.global_config + + widget = QWidget() + Layout = QVBoxLayout(widget) + + self.card_IfSendMail = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="推送邮件通知", + content="是否启用邮件通知功能", + configItem=self.config.notify_IfSendMail, + ) + + self.MailAddress = LineEditSettingCard( + text="请输入邮箱地址", + icon=FluentIcon.PAGE_RIGHT, + title="邮箱地址", + content="接收通知的邮箱地址", + configItem=self.config.notify_MailAddress, + ) + + self.card_IfSendErrorOnly = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="仅推送异常信息", + content="仅在任务出现异常时推送通知", + configItem=self.config.notify_IfSendErrorOnly, + ) + + Layout.addWidget(self.card_IfSendMail) + Layout.addWidget(self.MailAddress) + Layout.addWidget(self.card_IfSendErrorOnly) + + # 调整内部布局 + self.viewLayout.setContentsMargins(0, 0, 0, 0) + self.viewLayout.setSpacing(0) + + self.addGroupWidget(widget) + + +class SecuritySettingCard(HeaderCardWidget): + + def __init__(self, parent=None): + super().__init__(parent) + + self.setTitle("安全") + + Layout = QVBoxLayout() + + self.card_changePASSWORD = PushSettingCard( + text="修改", + icon=FluentIcon.VPN, + title="修改管理密钥", + content="修改用于解密用户密码的管理密钥", + ) + + Layout.addWidget(self.card_changePASSWORD) + + self.viewLayout.addLayout(Layout) + + +class UpdaterSettingCard(HeaderCardWidget): + + def __init__(self, parent=None, config: AppConfig = None): + super().__init__(parent) + + self.setTitle("更新") + + self.config = config.global_config + + Layout = QVBoxLayout() + + self.card_IfAutoUpdate = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="自动检查更新", + content="将在启动时自动检查AUTO_MAA是否有新版本", + configItem=self.config.update_IfAutoUpdate, + ) + + self.card_CheckUpdate = PushSettingCard( + text="检查更新", + icon=FluentIcon.UPDATE, + title="获取最新版本", + content="检查AUTO_MAA是否有新版本", + ) + + Layout.addWidget(self.card_IfAutoUpdate) + Layout.addWidget(self.card_CheckUpdate) + + self.viewLayout.addLayout(Layout) + + +class OtherSettingCard(HeaderCardWidget): + + def __init__(self, parent=None, config: AppConfig = None): + super().__init__(parent) + + self.setTitle("其他") + + self.config = config.global_config + + Layout = QVBoxLayout() + + self.card_Tips = PushSettingCard( + text="查看", + icon=FluentIcon.PAGE_RIGHT, + title="小贴士", + content="查看AUTO_MAA的小贴士", + ) + + Layout.addWidget(self.card_Tips) + + self.viewLayout.addLayout(Layout) diff --git a/app/utils/Updater.py b/app/utils/Updater.py index 86a335f..ec59e17 100644 --- a/app/utils/Updater.py +++ b/app/utils/Updater.py @@ -39,7 +39,7 @@ from PySide6.QtWidgets import ( QDialog, QVBoxLayout, ) -from qfluentwidgets import ProgressBar, BodyLabel +from qfluentwidgets import ProgressBar, IndeterminateProgressBar, BodyLabel from PySide6.QtGui import QIcon from PySide6.QtCore import QObject, QThread, Signal @@ -262,14 +262,19 @@ class Updater(QObject): ) # 创建垂直布局 - self.Layout_v = QVBoxLayout(self.ui) + self.Layout = QVBoxLayout(self.ui) self.info = BodyLabel("正在初始化", self.ui) - self.Layout_v.addWidget(self.info) + self.progress_1 = IndeterminateProgressBar(self.ui) + self.progress_2 = ProgressBar(self.ui) - self.progress = ProgressBar(self.ui) - self.progress.setRange(0, 0) - self.Layout_v.addWidget(self.progress) + self.update_progress(0, 0, 0) + + self.Layout.addWidget(self.info) + self.Layout.addStretch(1) + self.Layout.addWidget(self.progress_1) + self.Layout.addWidget(self.progress_2) + self.Layout.addStretch(1) self.update_process = UpdateProcess( app_path, name, main_version, updater_version @@ -284,8 +289,14 @@ class Updater(QObject): self.info.setText(text) def update_progress(self, begin: int, end: int, current: int) -> None: - self.progress.setRange(begin, end) - self.progress.setValue(current) + if begin == 0 and end == 0: + self.progress_2.setVisible(False) + self.progress_1.setVisible(True) + else: + self.progress_1.setVisible(False) + self.progress_2.setVisible(True) + self.progress_2.setRange(begin, end) + self.progress_2.setValue(current) class AUTO_MAA_Updater(QApplication): diff --git a/main.py b/main.py index f185b0d..9bbb470 100644 --- a/main.py +++ b/main.py @@ -26,9 +26,13 @@ v4.2 """ from PySide6.QtWidgets import QApplication +from qfluentwidgets import FluentTranslator import sys -from app import AppConfig, Notification, CryptoHandler, AUTO_MAA +from app.config import AppConfig +from app.services.notification import Notification +from app.services.security import CryptoHandler +from app.ui.main_window import AUTO_MAA if __name__ == "__main__": @@ -37,6 +41,10 @@ if __name__ == "__main__": crypto = CryptoHandler(config) application = QApplication(sys.argv) + + translator = FluentTranslator() + application.installTranslator(translator) + window = AUTO_MAA(config=config, notify=notify, crypto=crypto) - window.main.check_PASSWORD() + window.setting.check_PASSWORD() sys.exit(application.exec()) diff --git a/resources/version.json b/resources/version.json index fbe690f..cbceef2 100644 --- a/resources/version.json +++ b/resources/version.json @@ -1,8 +1,8 @@ { "main_version": "4.2.0.1", "updater_version": "1.1.0.1", - "announcement": "\n## 新增功能\n- 初步引入`qfluentwidgets`,UI界面美化", - "proxy_list":[ + "announcement": "\n# 这是一个预览版本!\n# 这个版本仅能进行用于展示页面,未实现任何功能!!!\n- 若不慎更新到此版本,请前往官方仓库,下载4.2.0版本压缩包替换本地文件即可回退版本", + "proxy_list": [ "", "https://gitproxy.click/", "https://cdn.moran233.xyz/",