feat: 全面优化用户界面和操作流程 1.统一所有弹窗界面风格 2.优化禁用更新/突破限制/刷新授权的操作流程 3.增加复制命令按钮功能 4.改进错误提示和操作指引 5.提升整体操作流畅度
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user