优化: 统一成功提示弹窗样式,优化会员状态检查

This commit is contained in:
ruisu
2025-02-19 19:16:29 +08:00
parent 8bff4ebdf7
commit 21f85ca6c1
3 changed files with 393 additions and 40 deletions

View File

@@ -399,7 +399,7 @@ def reset_auth_with_password(password: str = None) -> tuple[bool, str]:
auth_manager = CursorAuthManager()
if auth_manager.update_auth(email, access_token, refresh_token):
logging.info("认证信息更新成功")
# 重置机器码
logging.info("正在重置机器码...")

View File

@@ -1,5 +1,6 @@
import sys
import os
import json
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QLabel, QLineEdit, QPushButton, QTextEdit, QMessageBox,
QHBoxLayout, QDialog)
@@ -22,12 +23,64 @@ except Exception as e:
log_error(f"导入模块错误: {str(e)}\n{traceback.format_exc()}")
raise
# 添加密码管理类
class PasswordManager:
def __init__(self):
# 获取应用程序的实际运行路径
if getattr(sys, 'frozen', False):
# 如果是打包后的应用
if sys.platform == 'darwin':
# macOS下使用应用程序包内的Resources目录
bundle_dir = os.path.dirname(sys.executable)
app_root = os.path.abspath(os.path.join(bundle_dir, '..', 'Resources'))
self.app_support_dir = os.path.join(app_root, 'config')
else:
# 其他系统使用可执行文件所在目录
app_root = os.path.dirname(sys.executable)
self.app_support_dir = os.path.join(app_root, 'config')
else:
# 开发环境下使用用户目录
if sys.platform == 'darwin':
self.app_support_dir = os.path.expanduser('~/Library/Application Support/听泉Cursor助手')
else:
self.app_support_dir = os.path.expanduser('~/.听泉Cursor助手')
self.config_file = os.path.join(self.app_support_dir, 'config.json')
os.makedirs(self.app_support_dir, exist_ok=True)
logging.debug(f"密码管理器初始化,配置文件路径: {self.config_file}")
def save_password(self, password):
"""保存密码(这里可以添加简单加密)"""
try:
config = {'password': password}
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config, f)
logging.debug(f"密码保存{'成功' if password else '已清除'}")
return True
except Exception as e:
logging.error(f"保存密码失败: {str(e)}")
return False
def get_password(self):
"""获取保存的密码"""
try:
if os.path.exists(self.config_file):
with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
password = config.get('password')
logging.debug(f"读取到保存的密码: {'' if password else ''}")
return password
except Exception as e:
logging.error(f"读取密码失败: {str(e)}")
return None
class SuccessDialog(QDialog):
def __init__(self, message, parent=None):
super().__init__(parent)
self.setWindowTitle("激活成功")
self.setFixedSize(400, 300) # 增加窗口大小
self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.FramelessWindowHint)
self.setFixedSize(400, 300)
# 移除可能导致问题的窗口标志
self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
# 设置样式
self.setStyleSheet("""
@@ -136,34 +189,150 @@ class PasswordDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("输入系统密码")
self.setFixedSize(400, 150)
self.setFixedSize(450, 250) # 增加高度以容纳新控件
# 设置样式
self.setStyleSheet("""
QDialog {
background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 10px;
}
QLabel {
color: #333333;
font-size: 14px;
padding: 5px;
}
QLabel#tipLabel {
color: #666666;
font-size: 13px;
padding: 12px 15px;
background-color: #f8f8f8;
border-radius: 6px;
line-height: 20px;
min-height: 45px;
}
QLineEdit {
padding: 8px 12px;
border: 2px solid #cccccc;
border-radius: 6px;
background-color: white;
font-size: 14px;
min-height: 20px;
}
QLineEdit:focus {
border-color: #0078d4;
}
QPushButton {
background-color: #0078d4;
color: white;
border: none;
padding: 8px 20px;
border-radius: 6px;
font-size: 14px;
min-width: 80px;
}
QPushButton:hover {
background-color: #006cbd;
}
QPushButton:pressed {
background-color: #005ba1;
}
QPushButton#cancelButton {
background-color: #f0f0f0;
color: #333333;
}
QPushButton#cancelButton:hover {
background-color: #e0e0e0;
}
QPushButton#cancelButton:pressed {
background-color: #d0d0d0;
}
QCheckBox {
color: #333333;
font-size: 13px;
}
QCheckBox::indicator {
width: 18px;
height: 18px;
}
QCheckBox::indicator:unchecked {
border: 2px solid #cccccc;
background: white;
border-radius: 4px;
}
QCheckBox::indicator:checked {
border: 2px solid #0078d4;
background: #0078d4;
border-radius: 4px;
}
""")
layout = QVBoxLayout()
layout.setSpacing(15)
layout.setSpacing(8)
layout.setContentsMargins(20, 20, 20, 20)
# 提示文字
tip_label = QLabel("提示这里需要输入您的Mac电脑开机密码系统管理员密码\n用于执行需要管理员权限的操作。")
tip_label.setObjectName("tipLabel")
tip_label.setWordWrap(True)
layout.addWidget(tip_label)
# 密码输入框
self.password_input = QLineEdit()
self.password_input.setEchoMode(QLineEdit.EchoMode.Password)
self.password_input.setPlaceholderText("请输入系统密码")
self.password_input.setPlaceholderText("请输入Mac系统管理员密码")
layout.addWidget(self.password_input)
# 记住密码选项
from PyQt6.QtWidgets import QCheckBox
self.remember_checkbox = QCheckBox("记住密码")
self.remember_checkbox.setChecked(True) # 默认勾选
layout.addWidget(self.remember_checkbox)
# 按钮区域
button_layout = QHBoxLayout()
ok_button = QPushButton("确定")
button_layout.setSpacing(8)
cancel_button = QPushButton("取消")
ok_button.clicked.connect(self.accept)
cancel_button.setObjectName("cancelButton")
cancel_button.setCursor(Qt.CursorShape.PointingHandCursor)
cancel_button.clicked.connect(self.reject)
cancel_button.setFixedWidth(80)
button_layout.addWidget(ok_button)
ok_button = QPushButton("确定")
ok_button.setCursor(Qt.CursorShape.PointingHandCursor)
ok_button.clicked.connect(self.accept)
ok_button.setFixedWidth(80)
button_layout.addStretch()
button_layout.addWidget(cancel_button)
button_layout.addWidget(ok_button)
layout.addSpacing(5)
layout.addLayout(button_layout)
self.setLayout(layout)
# 设置窗口位置为父窗口中心
if parent:
self.move(
parent.x() + (parent.width() - self.width()) // 2,
parent.y() + (parent.height() - self.height()) // 2
)
# 尝试加载保存的密码
self.password_manager = PasswordManager()
saved_password = self.password_manager.get_password()
if saved_password:
self.password_input.setText(saved_password)
def get_password(self):
return self.password_input.text()
password = self.password_input.text()
# 如果选择记住密码,则保存
if self.remember_checkbox.isChecked():
self.password_manager.save_password(password)
return password
class CursorGUI(QMainWindow):
def __init__(self):
@@ -171,6 +340,14 @@ class CursorGUI(QMainWindow):
self.setWindowTitle("听泉Cursor助手 v3.0.2")
self.setFixedSize(600, 600)
# 添加全局会员状态
self.is_member_active = False
# 设置定时器每3分钟检查一次会员状态
self.status_timer = QTimer(self)
self.status_timer.timeout.connect(self.check_member_status)
self.status_timer.start(180000) # 180000毫秒 = 3分钟
# 设置整体样式
self.setStyleSheet("""
QMainWindow {
@@ -266,7 +443,7 @@ class CursorGUI(QMainWindow):
layout.addWidget(self.status_text)
# 激活区域
activate_label = QLabel("激活(盈加)会员,多个激活的可盈加整体时长")
activate_label = QLabel("激活会员,多个激活码叠加整体时长")
activate_layout = QHBoxLayout()
activate_layout.setSpacing(10) # 设置水平间距
self.activate_input = QLineEdit()
@@ -348,13 +525,15 @@ class CursorGUI(QMainWindow):
# 获取设备信息
device_info = status_data.get("device_info", {}) if success else {}
# 设置状态文本
# 设置状态文本和更新全局状态
if success and status_data.get("is_active"):
status_emoji = ""
status_text = "正常"
self.is_member_active = True
else:
status_emoji = ""
status_text = "未激活"
self.is_member_active = False
# 格式化显示文本
display_text = f"会员状态:{status_text} {status_emoji}\n"
@@ -389,10 +568,36 @@ class CursorGUI(QMainWindow):
clipboard.setText(self.id_text.text())
QMessageBox.information(self, "提示", "设备ID已复制到剪贴板")
def show_success_message(self, message):
"""显示统一的成功提示弹窗"""
msg = QMessageBox(self)
msg.setIcon(QMessageBox.Icon.Information)
msg.setWindowTitle("提示")
msg.setText(message)
msg.setStyleSheet("""
QMessageBox {
background-color: white;
}
QPushButton {
background-color: #0078d4;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
min-width: 80px;
}
QPushButton:hover {
background-color: #006cbd;
}
""")
msg.exec()
def activate_account(self):
"""激活账号"""
code = self.activate_input.text().strip()
if not code:
logging.debug("激活码为空,显示警告")
QMessageBox.warning(self, "警告", "请输入激活码")
return
@@ -402,12 +607,16 @@ class CursorGUI(QMainWindow):
QApplication.processEvents()
try:
logging.debug(f"开始检查激活码: {code}")
account_manager = backend.CursorAccountManager()
success, message, account_info = account_manager.check_activation_code(code)
logging.debug(f"激活码检查结果: success={success}, message={message}, account_info={account_info}")
if success:
# 更新状态显示
logging.debug("激活成功,开始更新状态")
# 更新状态显示和全局状态
self.update_status()
self.is_member_active = True
# 构建成功消息
success_message = (
@@ -417,28 +626,133 @@ class CursorGUI(QMainWindow):
f"总天数:{account_info.get('total_days', 0)}\n"
f"剩余天数:{account_info.get('days_left', 0)}"
)
logging.debug(f"准备显示成功弹窗,消息内容: {success_message}")
# 显示成功弹窗
dialog = SuccessDialog(success_message, self)
dialog.exec()
# 使用统一的成功提示弹窗
self.show_success_message(success_message)
logging.debug("成功弹窗显示完成")
# 清空输入框
self.activate_input.clear()
logging.debug("激活流程完成")
else:
logging.debug(f"激活失败,显示错误消息: {message}")
QMessageBox.warning(self, "错误", message)
except Exception as e:
error_msg = f"激活过程出错: {str(e)}\n{traceback.format_exc()}"
logging.error(error_msg)
QMessageBox.warning(self, "错误", f"激活过程出错: {str(e)}")
finally:
# 恢复激活按钮状态
logging.debug("恢复激活按钮状态")
self.activate_btn.setEnabled(True)
self.activate_btn.setText("激活")
def show_activation_dialog(self):
"""显示统一的激活提示弹窗"""
msg = QMessageBox(self)
msg.setIcon(QMessageBox.Icon.Warning)
msg.setWindowTitle("提示")
msg.setText("请输入激活码")
# 设置详细信息
msg.setInformativeText("获取会员激活码,请通过以下方式:\n\n" +
"• 官方自助网站cursor.nosqli.com\n" +
"• 微信客服号behikcigxr\n" +
"• 闲鱼店铺xxx\n\n" +
"诚招代理商,欢迎加盟合作!")
# 添加按钮
visit_btn = msg.addButton("复制网站", QMessageBox.ButtonRole.ActionRole)
copy_wx_btn = msg.addButton("复制微信", QMessageBox.ButtonRole.ActionRole)
ok_btn = msg.addButton("确定", QMessageBox.ButtonRole.AcceptRole)
msg.setDefaultButton(ok_btn)
# 设置样式
msg.setStyleSheet("""
QMessageBox {
background-color: white;
}
QPushButton {
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
min-width: 80px;
}
QPushButton[text="确定"] {
background-color: #0078d4;
color: white;
border: none;
}
QPushButton[text="确定"]:hover {
background-color: #006cbd;
}
QPushButton[text="复制网站"], QPushButton[text="复制微信"] {
background-color: white;
border: 1px solid #0078d4;
color: #0078d4;
}
QPushButton[text="复制网站"]:hover, QPushButton[text="复制微信"]:hover {
background-color: #f0f9ff;
}
""")
# 显示对话框
clicked = msg.exec()
# 处理按钮点击
if msg.clickedButton() == visit_btn:
clipboard = QApplication.clipboard()
clipboard.setText("cursor.nosqli.com")
QMessageBox.information(self, "提示", "网址已复制到剪贴板")
elif msg.clickedButton() == copy_wx_btn:
clipboard = QApplication.clipboard()
clipboard.setText("behikcigxr")
QMessageBox.information(self, "提示", "微信号已复制到剪贴板")
return False
def check_member_status(self):
"""检查会员状态"""
try:
account_manager = backend.CursorAccountManager()
success, status_data = account_manager.check_member_status()
if success and status_data.get("is_active"):
self.is_member_active = True
return True
self.is_member_active = False
return False
except Exception as e:
logging.error(f"检查会员状态失败: {str(e)}")
self.is_member_active = False
return False
def refresh_auth(self):
"""刷新授权"""
# 显示密码输入对话框
dialog = PasswordDialog(self)
if dialog.exec() == QDialog.DialogCode.Accepted:
password = dialog.get_password()
# 检查会员状态,未激活则显示激活提示
if not self.is_member_active:
self.show_activation_dialog()
return
# 会员已激活,继续执行原有逻辑
while True:
# 先尝试获取保存的密码
password_manager = PasswordManager()
saved_password = password_manager.get_password()
if saved_password:
# 如果有保存的密码,直接使用
password = saved_password
else:
# 如果没有保存的密码,显示密码输入对话框
dialog = PasswordDialog(self)
if dialog.exec() == QDialog.DialogCode.Accepted:
password = dialog.get_password()
else:
QMessageBox.warning(self, "取消", "重置操作已取消")
return
# 显示加载状态
self.refresh_btn.setEnabled(False)
@@ -448,57 +762,95 @@ class CursorGUI(QMainWindow):
try:
success, message = backend.reset_auth_with_password(password)
if success:
QMessageBox.information(self, "成功", "重置成功")
self.show_success_message("重置成功")
self.update_status()
break # 成功后退出循环
else:
# 密码错误,清除保存的密码
password_manager.save_password("")
QMessageBox.warning(self, "错误", message)
# 继续循环,重新输入密码
except Exception as e:
QMessageBox.warning(self, "错误", f"重置失败: {str(e)}")
break # 遇到其他错误时退出循环
finally:
# 恢复按钮状态
self.refresh_btn.setEnabled(True)
self.refresh_btn.setText("刷新Cursor授权 (对话次数用完了提示limit时点一次)")
else:
QMessageBox.warning(self, "取消", "重置操作已取消")
def install_patch(self):
"""安装补丁"""
# 检查会员状态,未激活则显示激活提示
if not self.is_member_active:
self.show_activation_dialog()
return
# 会员已激活,继续执行原有逻辑
try:
# 检查版本
greater_than_0_45 = backend.check_cursor_version()
logging.debug(f"Cursor版本检查结果: {'> 0.45' if greater_than_0_45 else '<= 0.45'}")
# 显示密码输入对话框
dialog = PasswordDialog(self)
if dialog.exec() == QDialog.DialogCode.Accepted:
password = dialog.get_password()
while True: # 添加循环以支持重试
# 先尝试获取保存的密码
password_manager = PasswordManager()
saved_password = password_manager.get_password()
if saved_password:
logging.debug("使用保存的密码进行验证")
password = saved_password
else:
logging.debug("没有保存的密码,显示密码输入对话框")
dialog = PasswordDialog(self)
if dialog.exec() == QDialog.DialogCode.Accepted:
password = dialog.get_password()
logging.debug("用户输入了新密码")
else:
logging.debug("用户取消了密码输入")
QMessageBox.warning(self, "取消", "操作已取消")
return
# 显示加载状态
self.patch_btn.setEnabled(False)
self.patch_btn.setText("安装中...")
self.patch_btn.setText("突破中...")
QApplication.processEvents()
try:
# 设置环境变量
os.environ['SUDO_PASSWORD'] = password
logging.debug("开始执行补丁安装...")
# 执行重置
backend.reset_machine_id(greater_than_0_45)
QMessageBox.information(self, "成功", "补丁安装成功")
# 直接显示成功消息
logging.debug("补丁安装完成")
self.show_success_message("补丁安装成功")
self.update_status()
break # 成功后退出循环
except Exception as e:
QMessageBox.warning(self, "错误", f"安装失败: {str(e)}")
logging.error(f"补丁安装过程发生错误: {str(e)}")
# 密码错误,清除保存的密码
password_manager.save_password("")
QMessageBox.warning(self, "错误", "密码验证失败,请重新输入")
continue # 继续循环,重新输入密码
finally:
# 恢复按钮状态
self.patch_btn.setEnabled(True)
self.patch_btn.setText("突破0.45.x限制 (Too many free trials问题点这里)")
else:
QMessageBox.warning(self, "取消", "安装操作已取消")
except Exception as e:
logging.error(f"安装补丁失败: {str(e)}")
QMessageBox.warning(self, "错误", f"安装补丁失败: {str(e)}")
def update_cursor(self):
"""更新Cursor版本"""
# TODO: 实现版本更新逻辑
# 检查会员状态,未激活则显示激活提示
if not self.is_member_active:
self.show_activation_dialog()
return
# 会员已激活,继续执行原有逻辑
QMessageBox.information(self, "提示", "更新功能开发中")
if __name__ == "__main__":

View File

@@ -7,8 +7,8 @@ class PrefixFormatter(logging.Formatter):
"""自定义格式化器,为 DEBUG 级别日志添加开源项目前缀"""
def format(self, record):
if record.levelno == logging.DEBUG: # 只给 DEBUG 级别添加前缀
record.msg = f"[开源项目https://github.com/chengazhen/cursor-auto-free] {record.msg}"
if record.levelno == 10: # DEBUG 级别的数值是 10
record.msg = f"[听泉助手https://cursorapi.nosqli.com] {record.msg}"
return super().format(record)
def setup_logger():
@@ -31,17 +31,17 @@ def setup_logger():
# 创建日志记录器
logger = logging.getLogger('CursorHelper')
logger.setLevel(logging.DEBUG)
logger.setLevel(logging.DEBUG) # 设置为DEBUG级别以记录所有日志
# 创建文件处理器
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler.setLevel(logging.DEBUG)
file_handler.setLevel(logging.DEBUG) # 文件处理器也设置为DEBUG级别
file_handler.setFormatter(PrefixFormatter('%(asctime)s - %(levelname)s - %(message)s'))
# 创建控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(PrefixFormatter('%(message)s'))
console_handler.setLevel(logging.DEBUG) # 控制台也输出DEBUG级别的日志
console_handler.setFormatter(PrefixFormatter('%(levelname)s: %(message)s'))
# 添加处理器到日志记录器
logger.addHandler(file_handler)
@@ -50,6 +50,7 @@ def setup_logger():
# 记录初始化信息
logger.info('日志系统初始化成功')
logger.info(f'日志文件路径: {log_file}')
logger.debug('调试日志已启用')
return logger