feat: 全面优化用户界面和操作流程 1.统一所有弹窗界面风格 2.优化禁用更新/突破限制/刷新授权的操作流程 3.增加复制命令按钮功能 4.改进错误提示和操作指引 5.提升整体操作流畅度

This commit is contained in:
huangzhenpc
2025-02-14 20:44:16 +08:00
parent 26e159d71c
commit ae698796e7
9 changed files with 945 additions and 509 deletions

View File

@@ -6,9 +6,9 @@ from PIL import Image
from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QFrame, QTextEdit,
QMessageBox, QApplication, QSystemTrayIcon, QMenu,
QDialog, QProgressBar, QStyle)
QDialog, QProgressBar, QStyle, QDialogButtonBox, QToolTip)
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtGui import QIcon, QPixmap, QCursor
import time
import requests
from urllib.parse import quote
@@ -608,6 +608,30 @@ class MainWindow(QMainWindow):
disable_update_btn.setMinimumWidth(500)
btn_layout.addWidget(disable_update_btn, 0, Qt.AlignCenter)
# 重启Cursor按钮
self.restart_cursor_btn = QPushButton("重启Cursor")
self.restart_cursor_btn.setFixedHeight(30)
self.restart_cursor_btn.setStyleSheet("""
QPushButton {
background-color: #2d8cf0;
border: none;
color: white;
padding: 5px 15px;
border-radius: 4px;
font-size: 13px;
}
QPushButton:hover {
background-color: #2b85e4;
}
QPushButton:pressed {
background-color: #2979d9;
}
QPushButton:disabled {
background-color: #bbbec4;
}
""")
self.restart_cursor_btn.clicked.connect(self.restart_cursor)
main_layout.addWidget(btn_frame)
# 检查更新按钮
@@ -1336,91 +1360,11 @@ class MainWindow(QMainWindow):
try:
# 显示加载对话框
self.show_loading_dialog("正在禁用更新,请稍候...")
self.show_loading_dialog("正在禁用更新...")
# 创建工作线程
from utils.cursor_registry import CursorRegistry
registry = CursorRegistry()
def disable_func():
try:
# 1. 先关闭所有Cursor进程
if sys.platform == "win32":
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 关闭Cursor
subprocess.run(
"taskkill /f /im Cursor.exe >nul 2>&1",
startupinfo=startupinfo,
shell=True
)
time.sleep(2)
# 2. 处理updater文件
updater_path = Path(os.getenv('LOCALAPPDATA')) / "cursor-updater"
try:
# 如果是目录,则删除
if updater_path.is_dir():
import shutil
shutil.rmtree(str(updater_path))
logging.info("删除updater目录成功")
# 如果是文件,则删除
if updater_path.is_file():
updater_path.unlink()
logging.info("删除updater文件成功")
# 创建阻止文件
updater_path.touch()
logging.info("创建updater空文件成功")
# 设置文件权限
import subprocess
import stat
# 设置只读属性
os.chmod(str(updater_path), stat.S_IREAD)
logging.info("设置只读属性成功")
# 使用icacls设置权限只读
username = os.getenv('USERNAME')
cmd = f'icacls "{str(updater_path)}" /inheritance:r /grant:r "{username}:(R)"'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
logging.error(f"设置文件权限失败: {result.stderr}")
return False, "设置文件权限失败"
logging.info("设置文件权限成功")
# 验证设置
if not os.path.exists(updater_path):
return False, "文件创建失败"
if os.access(str(updater_path), os.W_OK):
return False, "文件权限设置失败"
except Exception as e:
logging.error(f"处理updater文件失败: {str(e)}")
return False, "处理updater文件失败"
# 3. 修改package.json配置
if not registry.fix_cursor_startup():
return False, "修改配置失败"
# 4. 重启Cursor
cursor_exe = registry.cursor_path / "Cursor.exe"
if cursor_exe.exists():
os.startfile(str(cursor_exe))
logging.info("Cursor重启成功")
return True, "Cursor更新已禁用程序已重启"
else:
return False, "未找到Cursor程序"
except Exception as e:
logging.error(f"禁用更新时发生错误: {str(e)}")
return False, str(e)
self.worker = ApiWorker(disable_func)
self.worker.finished.connect(lambda result: self.on_disable_update_complete(result))
self.worker = ApiWorker(self.switcher.disable_cursor_update)
self.worker.finished.connect(self.on_disable_update_complete)
self.worker.start()
except Exception as e:
@@ -1429,167 +1373,243 @@ class MainWindow(QMainWindow):
self.show_custom_error("禁用更新失败", str(e))
def on_disable_update_complete(self, result):
"""禁用更新完成回调"""
success, data = result
self.hide_loading_dialog()
self._request_complete()
if success:
self.show_custom_message(
"成功",
"禁用更新成功",
data,
QStyle.SP_DialogApplyButton,
"#198754"
)
else:
self.show_custom_error("禁用更新失败", str(data))
"""禁用更新完成回调"""
try:
success, data = result
logging.info(f"禁用更新操作结果: success={success}, data={data}")
self.hide_loading_dialog()
self._request_complete()
if isinstance(data, tuple):
inner_success, inner_message = data
if inner_success:
self.show_custom_message(
"成功",
"禁用更新成功",
inner_message,
QMessageBox.Information,
"#198754"
)
QTimer.singleShot(1000, self.check_status)
else:
# 创建自定义对话框
dialog = QDialog(self)
dialog.setWindowTitle("禁用更新失败")
dialog.setFixedWidth(400)
layout = QVBoxLayout()
# 警告图标和标题
header_layout = QHBoxLayout()
warning_icon = QLabel()
warning_icon.setPixmap(self.style().standardIcon(QStyle.SP_MessageBoxWarning).pixmap(32, 32))
header_layout.addWidget(warning_icon)
header_label = QLabel("需要手动操作")
header_label.setStyleSheet("color: red; font-size: 16px; font-weight: bold;")
header_layout.addWidget(header_label)
header_layout.addStretch()
layout.addLayout(header_layout)
# 分隔线
line = QFrame()
line.setFrameShape(QFrame.HLine)
line.setFrameShadow(QFrame.Sunken)
layout.addWidget(line)
# 手动步骤说明
steps_label = QLabel(
"请按以下步骤手动操作:\n\n"
"1. 按下 Win + R 组合键\n"
"2. 在运行框中输入 powershell 或 pwsh\n"
"3. 按 Ctrl + Shift + Enter 以管理员身份运行\n"
"4. 在管理员终端中输入以下命令:"
)
steps_label.setWordWrap(True)
steps_label.setStyleSheet("margin: 10px 0;")
layout.addWidget(steps_label)
# 命令文本框和复制按钮
command_layout = QHBoxLayout()
command_text = QLineEdit()
command_text.setText("irm https://github.com/maticarmy/cursor-nosqli-tools/blob/main/scripts/run/cursor_win_id_modifier.ps1 | iex")
command_text.setReadOnly(True)
command_layout.addWidget(command_text)
copy_button = QPushButton("复制")
copy_button.setStyleSheet("""
QPushButton {
background-color: #007bff;
color: white;
border: none;
padding: 5px 15px;
border-radius: 3px;
}
QPushButton:hover {
background-color: #0056b3;
}
""")
copy_button.clicked.connect(lambda: self.copy_and_show_tip(command_text, command_text.text(), "命令已复制到剪贴板"))
command_layout.addWidget(copy_button)
layout.addLayout(command_layout)
# 按钮
button_box = QDialogButtonBox(QDialogButtonBox.Ok)
button_box.accepted.connect(dialog.accept)
layout.addWidget(button_box)
dialog.setLayout(layout)
dialog.exec_()
else:
self.show_custom_error("禁用更新失败", str(data))
except Exception as e:
logging.error(f"处理禁用更新回调时发生错误: {str(e)}")
self.show_custom_error("错误", "处理结果时发生错误,请重试")
def bypass_cursor_limit(self):
"""突破Cursor版本限制"""
if not self.check_activation_status():
return
if not self._check_request_throttle():
return
# 显示加载对话框
self.show_loading_dialog("正在突破限制...")
# 创建工作线程
self.worker = ApiWorker(self.switcher.bypass_cursor_limit)
self.worker.finished.connect(self.on_bypass_limit_complete)
self.worker.start()
def on_bypass_limit_complete(self, result):
"""突破限制完成回调"""
try:
# 显示加载对话框
self.show_loading_dialog("正在突破版本限制,请稍候...")
success, data = result
logging.info(f"突破限制操作结果: success={success}, data={data}")
# 创建工作线程
from utils.cursor_registry import CursorRegistry
registry = CursorRegistry()
# 确保在主线程中执行 UI 操作
self.hide_loading_dialog()
self._request_complete()
def reset_func():
try:
# 1. 先关闭所有Cursor进程
if sys.platform == "win32":
os.system("taskkill /f /im Cursor.exe >nul 2>&1")
time.sleep(2)
if isinstance(data, tuple):
inner_success, inner_message = data
if inner_success:
try:
logging.info("准备显示成功消息对话框")
self.show_custom_message(
"成功",
"突破限制成功",
inner_message,
QStyle.SP_DialogApplyButton,
"#198754"
)
logging.info("成功消息对话框显示完成")
# 更新状态显示
QTimer.singleShot(1000, self.check_status)
logging.info("已安排状态更新")
except Exception as e:
logging.error(f"显示成功消息时发生错误: {str(e)}")
# 使用更简单的消息框作为后备方案
QMessageBox.information(self, "成功", "突破限制成功")
else:
try:
logging.info("准备显示错误消息对话框")
self.show_custom_error("突破限制失败", str(inner_message))
logging.info("错误消息对话框显示完成")
except Exception as e:
logging.error(f"显示错误消息时发生错误: {str(e)}")
# 使用更简单的消息框作为后备方案
QMessageBox.critical(self, "错误", f"突破限制失败: {str(inner_message)}")
else:
self.show_custom_error("突破限制失败", str(data))
# 2. 清理注册表
if not registry.clean_registry():
return False, "清理注册表失败"
# 3. 清理文件
if not registry.clean_cursor_files():
return False, "清理文件失败"
# 4. 重启Cursor
cursor_exe = self.cursor_path / "Cursor.exe"
if cursor_exe.exists():
os.startfile(str(cursor_exe))
logging.info("Cursor重启成功")
return True, "突破限制成功"
else:
return False, "未找到Cursor程序"
except Exception as e:
logging.error(f"突破限制时发生错误: {str(e)}")
return False, str(e)
except Exception as e:
logging.error(f"处理突破限制回调时发生错误: {str(e)}")
try:
self.hide_loading_dialog()
self._request_complete()
QMessageBox.critical(self, "错误", "处理结果时发生错误,请重试")
except:
pass
def show_custom_message(self, title, header, message, icon_type, color, show_copy_button=False, copy_text=None):
"""显示自定义消息对话框
Args:
show_copy_button: 是否显示复制按钮
copy_text: 要复制的文本内容
"""
try:
logging.info(f"准备显示自定义消息框: {header}")
self.worker = ApiWorker(reset_func)
self.worker.finished.connect(self.on_bypass_complete)
self.worker.start()
dialog = QDialog(self)
dialog.setWindowTitle(title)
dialog.setFixedWidth(500)
layout = QVBoxLayout()
# 标题标签
header_label = QLabel(header)
header_label.setStyleSheet(f"color: {color}; font-size: 16px; font-weight: bold;")
layout.addWidget(header_label)
# 消息文本
message_label = QLabel(message)
message_label.setWordWrap(True)
message_label.setStyleSheet("margin: 10px 0;")
layout.addWidget(message_label)
# 添加复制按钮
if show_copy_button and copy_text:
copy_button = QPushButton("复制命令")
copy_button.setStyleSheet("""
QPushButton {
background-color: #007bff;
color: white;
border: none;
padding: 5px 15px;
border-radius: 3px;
}
QPushButton:hover {
background-color: #0056b3;
}
""")
copy_button.clicked.connect(lambda: self.copy_to_clipboard(copy_text))
layout.addWidget(copy_button, alignment=Qt.AlignCenter)
# 确定按钮
button_box = QDialogButtonBox(QDialogButtonBox.Ok)
button_box.accepted.connect(dialog.accept)
layout.addWidget(button_box)
dialog.setLayout(layout)
dialog.exec_()
logging.info("自定义消息框已关闭")
except Exception as e:
self._request_complete()
self.hide_loading_dialog()
self.show_custom_error("突破限制失败", str(e))
def on_bypass_complete(self, result):
"""突破限制完成回调"""
success, data = result
self.hide_loading_dialog()
self._request_complete()
if success:
self.show_custom_message(
"成功",
"突破限制成功",
"Cursor版本限制已突破编辑器已重启。",
QStyle.SP_DialogApplyButton,
"#198754"
)
else:
self.show_custom_error("突破限制失败", str(data))
logging.error(f"显示自定义消息框时发生错误: {str(e)}")
QMessageBox.critical(self, title, message)
def copy_to_clipboard(self, text):
"""复制文本到剪贴板"""
clipboard = QApplication.clipboard()
clipboard.setText(text)
QToolTip.showText(QCursor.pos(), "已复制到剪贴板", None, 2000)
def show_custom_message(self, title, header, message, icon_type, color):
"""显示自定义消息框"""
msg = QDialog(self)
msg.setWindowTitle(title)
msg.setFixedWidth(400)
msg.setWindowFlags(msg.windowFlags() & ~Qt.WindowContextHelpButtonHint)
layout = QVBoxLayout()
# 添加图标
icon_label = QLabel()
icon_label.setPixmap(self.style().standardIcon(icon_type).pixmap(32, 32))
icon_label.setAlignment(Qt.AlignCenter)
layout.addWidget(icon_label)
# 添加标题
text_label = QLabel(header)
text_label.setAlignment(Qt.AlignCenter)
text_label.setStyleSheet(f"""
font-size: 14px;
font-weight: bold;
color: {color};
padding: 10px;
""")
layout.addWidget(text_label)
# 添加详细信息
info_label = QLabel(message)
info_label.setAlignment(Qt.AlignLeft)
info_label.setWordWrap(True)
info_label.setStyleSheet("""
QLabel {
color: #333333;
font-size: 14px;
padding: 15px;
background-color: #f8f9fa;
border-radius: 4px;
border: 1px solid #dee2e6;
margin: 10px;
}
""")
layout.addWidget(info_label)
# 确定按钮
btn_layout = QHBoxLayout()
ok_btn = QPushButton("确定")
ok_btn.clicked.connect(msg.accept)
ok_btn.setStyleSheet(f"""
QPushButton {{
background-color: {color};
color: white;
border: none;
padding: 8px 25px;
border-radius: 4px;
font-size: 13px;
min-width: 100px;
}}
QPushButton:hover {{
background-color: {color.replace('fd', 'd7') if 'fd' in color else color.replace('54', '47')};
}}
""")
btn_layout.addWidget(ok_btn)
layout.addLayout(btn_layout)
msg.setLayout(layout)
msg.exec_()
def show_custom_error(self, header, message):
"""显示自定义错误消息框"""
self.show_custom_message(
"错误",
header,
message,
QStyle.SP_MessageBoxCritical,
"#dc3545"
)
try:
logging.info(f"准备显示错误消息框: {header}")
self.show_custom_message(
"错误",
header,
message,
QStyle.SP_MessageBoxCritical,
"#dc3545"
)
logging.info("错误消息框显示完成")
except Exception as e:
logging.error(f"显示自定义错误消息框失败: {str(e)}")
QMessageBox.critical(self, "错误", f"{header}\n\n{message}")
def _check_request_throttle(self) -> bool:
"""检查是否可以发送请求(防重复提交)
@@ -2028,4 +2048,55 @@ class MainWindow(QMainWindow):
# 更新状态显示
self.check_status()
else:
logging.error(f"心跳发送失败: {message}")
logging.error(f"心跳发送失败: {message}")
def restart_cursor(self):
"""重启Cursor进程"""
try:
self.restart_cursor_btn.setEnabled(False)
self.show_loading_dialog("正在重启Cursor...")
def restart_func():
try:
# 先关闭进程
if not self.switcher.close_cursor_process():
return False, "无法关闭Cursor进程请手动关闭后重试"
# 等待资源释放
time.sleep(2)
# 重启Cursor
if not self.switcher.restart_cursor():
return False, "重启Cursor失败请手动启动Cursor"
return True, "Cursor重启成功"
except Exception as e:
logging.error(f"重启Cursor失败: {str(e)}")
return False, f"重启失败: {str(e)}"
# 创建工作线程
worker = ApiWorker(restart_func)
worker.finished.connect(self.on_restart_complete)
worker.start()
except Exception as e:
self.restart_cursor_btn.setEnabled(True)
self.hide_loading_dialog()
self.show_custom_error("重启失败", str(e))
def on_restart_complete(self, result):
"""重启完成的回调函数"""
success, message = result
self.restart_cursor_btn.setEnabled(True)
self.hide_loading_dialog()
if success:
self.show_custom_message(
"重启成功",
"Cursor已重启",
message,
QMessageBox.Information,
"#2d8cf0"
)
else:
self.show_custom_error("重启失败", message)