Files
nezhacursor/gui/main_window.py
huangzhenpc e3058b9e39 feat: 完成PyQt5 GUI实现,支持系统托盘和图标显示
1. 实现了基于PyQt5的GUI界面 2. 添加系统托盘功能,支持最小化到托盘 3. 修复了图标显示问题,包括窗口图标和任务栏图标 4. 优化了打包配置,支持PyInstaller打包 5. 版本更新到v3.3.1
2025-02-12 14:18:08 +08:00

277 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sys
from pathlib import Path
import logging
import os
from PIL import Image
from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QFrame, QTextEdit,
QMessageBox, QApplication, QSystemTrayIcon, QMenu)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QIcon, QPixmap
sys.path.append(str(Path(__file__).parent.parent))
from utils.config import Config
from account_switcher import AccountSwitcher
def get_version():
try:
version_file = Path(__file__).parent.parent / 'version.txt'
with open(version_file, 'r', encoding='utf-8') as f:
return f.read().strip()
except Exception as e:
logging.error(f"读取版本号失败: {str(e)}")
return "未知版本"
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.config = Config()
self.switcher = AccountSwitcher()
version = get_version()
cursor_version = self.switcher.get_cursor_version()
self.setWindowTitle(f"听泉Cursor助手 v{version} (本机Cursor版本: {cursor_version})")
self.setMinimumSize(600, 500)
# 设置窗口图标
icon_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "icon", "two.ico")
if os.path.exists(icon_path):
window_icon = QIcon(icon_path)
if not window_icon.isNull():
self.setWindowIcon(window_icon)
logging.info(f"成功设置窗口图标: {icon_path}")
# 创建系统托盘图标
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(self.windowIcon())
self.tray_icon.setToolTip("听泉Cursor助手")
# 创建托盘菜单
tray_menu = QMenu()
show_action = tray_menu.addAction("显示主窗口")
show_action.triggered.connect(self.show)
quit_action = tray_menu.addAction("退出")
quit_action.triggered.connect(QApplication.instance().quit)
# 设置托盘菜单
self.tray_icon.setContextMenu(tray_menu)
# 连接托盘图标的信号
self.tray_icon.activated.connect(self.on_tray_icon_activated)
# 显示托盘图标
self.tray_icon.show()
# 创建主窗口部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QVBoxLayout(central_widget)
# 设备ID区域
device_frame = QFrame()
device_layout = QHBoxLayout(device_frame)
device_layout.addWidget(QLabel("设备识别码(勿动):"))
self.hardware_id_edit = QLineEdit(self.switcher.hardware_id)
self.hardware_id_edit.setReadOnly(True)
device_layout.addWidget(self.hardware_id_edit)
copy_btn = QPushButton("复制ID")
copy_btn.clicked.connect(self.copy_device_id)
device_layout.addWidget(copy_btn)
main_layout.addWidget(device_frame)
# 会员状态区域
status_frame = QFrame()
status_layout = QVBoxLayout(status_frame)
status_layout.addWidget(QLabel("会员状态"))
self.status_text = QTextEdit()
self.status_text.setReadOnly(True)
self.status_text.setMinimumHeight(100)
status_layout.addWidget(self.status_text)
main_layout.addWidget(status_frame)
# 激活区域
activation_frame = QFrame()
activation_layout = QVBoxLayout(activation_frame)
activation_layout.addWidget(QLabel("激活(叠加)会员,多个激活码可叠加整体时长"))
input_frame = QFrame()
input_layout = QHBoxLayout(input_frame)
input_layout.addWidget(QLabel("激活码:"))
self.activation_edit = QLineEdit()
input_layout.addWidget(self.activation_edit)
activate_btn = QPushButton("激活")
activate_btn.clicked.connect(self.activate_account)
input_layout.addWidget(activate_btn)
activation_layout.addWidget(input_frame)
main_layout.addWidget(activation_frame)
# 操作按钮区域
btn_frame = QFrame()
btn_layout = QVBoxLayout(btn_frame)
refresh_btn = QPushButton("刷新Cursor编辑器授权")
refresh_btn.clicked.connect(self.refresh_cursor_auth)
btn_layout.addWidget(refresh_btn)
bypass_btn = QPushButton("突破Cursor0.45.x限制")
bypass_btn.clicked.connect(self.dummy_function)
btn_layout.addWidget(bypass_btn)
disable_update_btn = QPushButton("禁用Cursor版本更新")
disable_update_btn.clicked.connect(self.disable_cursor_update)
btn_layout.addWidget(disable_update_btn)
main_layout.addWidget(btn_frame)
# 启动时检查一次状态
QTimer.singleShot(0, self.check_status)
def on_tray_icon_activated(self, reason):
"""处理托盘图标的点击事件"""
if reason == QSystemTrayIcon.DoubleClick:
self.show()
self.activateWindow()
def closeEvent(self, event):
"""重写关闭事件,最小化到托盘而不是退出"""
if hasattr(self, 'tray_icon') and self.tray_icon.isVisible():
event.ignore()
self.hide()
self.tray_icon.showMessage(
"听泉Cursor助手",
"程序已最小化到系统托盘",
QSystemTrayIcon.Information,
2000
)
else:
event.accept()
def copy_device_id(self):
"""复制设备ID到剪贴板"""
if not self.check_status():
return
QApplication.clipboard().setText(self.hardware_id_edit.text())
QMessageBox.information(self, "提示", "设备ID已复制到剪贴板")
def activate_account(self):
"""激活账号"""
code = self.activation_edit.text().strip()
if not code:
QMessageBox.warning(self, "提示", "请输入激活码")
return
try:
success, message, account_info = self.switcher.check_activation_code(code)
if success:
# 更新会员信息显示
self.update_status_display(account_info)
QMessageBox.information(self, "激活成功", "激活成功!\n" + message)
# 清空激活码输入框
self.activation_edit.clear()
else:
QMessageBox.critical(self, "激活失败", message)
# 激活后检查一次状态
self.check_status()
except Exception as e:
QMessageBox.critical(self, "错误", f"激活失败: {str(e)}")
# 出错后也检查状态
self.check_status()
def update_status_display(self, status_info: dict):
"""更新状态显示"""
# 打印API返回的原始数据
logging.info("=== API返回数据 ===")
logging.info(f"状态信息: {status_info}")
if 'activation_records' in status_info:
logging.info("激活记录:")
for record in status_info['activation_records']:
logging.info(f"- 记录: {record}")
# 更新状态文本
status_map = {
"active": "正常",
"inactive": "未激活",
"expired": "已过期"
}
status_text = status_map.get(status_info.get('status', 'inactive'), "未知")
# 构建状态文本
status_lines = [
f"会员状态:{status_text}",
f"到期时间:{status_info.get('expire_time', '')}",
f"总天数:{status_info.get('total_days', 0)}",
f"剩余天数:{status_info.get('days_left', 0)}"
]
# 如果有激活记录,显示最近一次激活信息
activation_records = status_info.get('activation_records', [])
if activation_records:
latest_record = activation_records[-1] # 获取最新的激活记录
device_info = latest_record.get('device_info', {})
status_lines.extend([
"",
"最近激活信息:",
f"激活码:{latest_record.get('code', '')}",
f"激活时间:{latest_record.get('activation_time', '')}",
f"增加天数:{latest_record.get('days', 0)}",
"",
"设备信息:",
f"系统:{device_info.get('os', '')}",
f"设备名:{device_info.get('device_name', '')}",
f"IP地址{device_info.get('ip', '')}",
f"地区:{device_info.get('location', '--')}"
])
# 更新状态文本
self.status_text.setPlainText("\n".join(status_lines))
def check_status(self):
"""检查会员状态"""
try:
status = self.switcher.get_member_status()
if status:
self.update_status_display(status)
return status.get('status') != 'inactive'
else:
# 更新为未激活状态
inactive_status = {
"hardware_id": self.switcher.hardware_id,
"expire_time": "",
"days_left": 0,
"total_days": 0,
"status": "inactive",
"activation_records": []
}
self.update_status_display(inactive_status)
return False
except Exception as e:
QMessageBox.critical(self, "错误", f"检查状态失败: {str(e)}")
return False
def refresh_cursor_auth(self):
"""刷新Cursor授权"""
try:
success, message = self.switcher.refresh_cursor_auth()
if success:
QMessageBox.information(self, "成功", message)
else:
QMessageBox.critical(self, "失败", message)
except Exception as e:
QMessageBox.critical(self, "错误", f"刷新授权失败: {str(e)}")
def disable_cursor_update(self):
"""禁用Cursor更新"""
try:
success, message = self.switcher.disable_cursor_update()
if success:
QMessageBox.information(self, "成功", message)
else:
QMessageBox.critical(self, "失败", message)
except Exception as e:
QMessageBox.critical(self, "错误", f"禁用更新失败: {str(e)}")
def dummy_function(self):
"""占位函数"""
QMessageBox.information(self, "提示", "此功能暂未实现")