Files
nezhacursor/gui/main_window.py

394 lines
15 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
import tkinter as tk
from tkinter import ttk, messagebox
from pathlib import Path
import logging
import os
from PIL import Image, ImageTk
import time
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:
def __init__(self):
self.config = Config()
self.switcher = AccountSwitcher()
self.root = tk.Tk()
version = get_version()
cursor_version = self.switcher.get_cursor_version()
self.root.title(f"听泉Cursor助手 v{version} (本机Cursor版本: {cursor_version})")
self.root.geometry("600x500") # 调整窗口大小
self.root.resizable(True, True) # 允许调整窗口大小
# 设置窗口最小尺寸
self.root.minsize(600, 500)
try:
# 设置图标 - 使用PIL
current_dir = os.path.dirname(os.path.abspath(__file__))
icon_path = os.path.join(os.path.dirname(current_dir), "icon", "th.jpg")
if os.path.exists(icon_path):
# 打开并调整图片大小
img = Image.open(icon_path)
img = img.resize((32, 32), Image.Resampling.LANCZOS)
# 转换为PhotoImage
self.icon = ImageTk.PhotoImage(img)
self.root.iconphoto(True, self.icon)
logging.info(f"成功加载图标: {icon_path}")
else:
logging.error(f"图标文件不存在: {icon_path}")
except Exception as e:
logging.error(f"设置图标失败: {str(e)}")
# 设置关闭窗口处理
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
# 初始化状态变量
self.status_var = tk.StringVar(value="")
# 设置样式
self.style = ttk.Style()
self.style.configure("TButton", padding=5, font=("Microsoft YaHei UI", 9))
self.style.configure("TLabelframe", padding=10, font=("Microsoft YaHei UI", 9))
self.style.configure("TLabel", padding=2, font=("Microsoft YaHei UI", 9))
self.style.configure("Custom.TButton", padding=10, font=("Microsoft YaHei UI", 9))
self.style.configure("Action.TButton", padding=8, font=("Microsoft YaHei UI", 9))
self.setup_ui()
# 启动时检查一次状态
self.check_status()
def setup_ui(self):
"""设置UI界面"""
# 主框架
main_frame = ttk.Frame(self.root, padding=10)
main_frame.pack(fill="both", expand=True)
# 功能菜单
menu_frame = ttk.Frame(main_frame)
menu_frame.pack(fill="x", pady=(0, 10))
ttk.Label(menu_frame, text="功能(F)").pack(side="left")
# 设备ID区域
device_frame = ttk.Frame(main_frame)
device_frame.pack(fill="x", pady=(0, 10))
ttk.Label(device_frame, text="设备识别码(勿动):").pack(side="left")
self.hardware_id_var = tk.StringVar(value=self.switcher.hardware_id)
device_id_entry = ttk.Entry(device_frame, textvariable=self.hardware_id_var, width=35, state="readonly")
device_id_entry.pack(side="left", padx=5)
copy_btn = ttk.Button(device_frame, text="复制ID", command=self.copy_device_id, width=8)
copy_btn.pack(side="left")
# 会员状态区域
status_frame = ttk.LabelFrame(main_frame, text="会员状态")
status_frame.pack(fill="x", pady=(0, 10))
self.status_text = tk.Text(status_frame, height=5, width=40, font=("Microsoft YaHei UI", 9))
self.status_text.pack(fill="both", padx=5, pady=5)
self.status_text.config(state="disabled")
# 激活区域
activation_frame = ttk.LabelFrame(main_frame, text="激活(叠加)会员,多个激活码可叠加整体时长")
activation_frame.pack(fill="x", pady=(0, 10))
input_frame = ttk.Frame(activation_frame)
input_frame.pack(fill="x", padx=5, pady=5)
ttk.Label(input_frame, text="激活码:").pack(side="left")
self.activation_var = tk.StringVar()
activation_entry = ttk.Entry(input_frame, textvariable=self.activation_var, width=35)
activation_entry.pack(side="left", padx=5)
activate_btn = ttk.Button(input_frame, text="激活", command=self.activate_account, width=8)
activate_btn.pack(side="left")
# 操作按钮区域
btn_frame = ttk.Frame(main_frame)
btn_frame.pack(fill="x", pady=5)
self.style.configure("Action.TButton", padding=8)
ttk.Button(btn_frame, text="刷新Cursor编辑器授权", command=self.reset_machine_id, style="Action.TButton").pack(fill="x", pady=2)
ttk.Button(btn_frame, text="突破Cursor0.45.x限制", command=self.dummy_function, style="Action.TButton").pack(fill="x", pady=2)
ttk.Button(btn_frame, text="禁用Cursor版本更新", command=self.disable_cursor_update, style="Action.TButton").pack(fill="x", pady=2)
def copy_device_id(self):
"""复制设备ID到剪贴板"""
# 先检查状态
if not self.check_status():
return
self.root.clipboard_clear()
self.root.clipboard_append(self.hardware_id_var.get())
def activate_account(self):
"""激活账号"""
code = self.activation_var.get().strip()
if not code:
messagebox.showwarning("提示", "请输入激活码")
return
self.status_var.set("正在激活...")
self.root.update()
try:
success, message, account_info = self.switcher.check_activation_code(code)
if success:
# 更新会员信息显示
self.update_status_display(account_info)
messagebox.showinfo("激活成功", "激活成功!\n" + message)
self.status_var.set("激活成功")
# 清空激活码输入框
self.activation_var.set("")
else:
messagebox.showerror("激活失败", message)
self.status_var.set("激活失败")
# 激活后检查一次状态
self.check_status()
except Exception as e:
messagebox.showerror("错误", f"激活失败: {str(e)}")
self.status_var.set("发生错误")
# 出错后也检查状态
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}")
# 启用文本框编辑
self.status_text.config(state="normal")
# 清空当前内容
self.status_text.delete(1.0, tk.END)
# 更新状态文本
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.insert(tk.END, "\n".join(status_lines))
# 禁用文本框编辑
self.status_text.config(state="disabled")
def check_status(self):
"""检查会员状态"""
try:
self.status_var.set("正在检查状态...")
self.root.update()
status = self.switcher.get_member_status()
if status:
self.update_status_display(status)
if status.get('status') == 'inactive':
self.status_var.set("未激活")
return False
self.status_var.set("状态检查完成")
return True
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)
self.status_var.set("未激活")
return False
except Exception as e:
logging.error(f"检查状态失败: {str(e)}")
self.status_var.set("状态检查失败")
messagebox.showerror("错误", f"检查状态失败: {str(e)}")
return False
def show_purchase_info(self):
"""显示购买信息"""
# 创建自定义对话框
dialog = tk.Toplevel(self.root)
dialog.title("提示")
dialog.geometry("400x280") # 增加高度
dialog.resizable(False, False)
# 设置模态
dialog.transient(self.root)
dialog.grab_set()
# 创建提示图标
icon_frame = ttk.Frame(dialog)
icon_frame.pack(pady=10)
ttk.Label(icon_frame, text="", font=("Segoe UI", 24)).pack()
# 创建消息文本
message_frame = ttk.Frame(dialog)
message_frame.pack(pady=5, padx=20)
ttk.Label(message_frame, text="您还不是会员,请先购买激活会员用讯。", font=("Microsoft YaHei UI", 10)).pack()
# 创建可复制的文本框
buy_info = "闲鱼xxxx\n微信behikcigar\n网站自助购买nezhacursor.nosqli.com"
text = tk.Text(dialog, height=4, width=40, font=("Microsoft YaHei UI", 9))
text.pack(pady=5, padx=20)
text.insert("1.0", buy_info)
text.config(state="normal") # 允许选择和复制
# 创建按钮框架
btn_frame = ttk.Frame(dialog)
btn_frame.pack(pady=10)
# 复制按钮
def copy_info():
dialog.clipboard_clear()
dialog.clipboard_append(buy_info)
messagebox.showinfo("提示", "购买信息已复制到剪贴板", parent=dialog)
ttk.Button(btn_frame, text="复制信息", command=copy_info).pack(side="left", padx=5)
ttk.Button(btn_frame, text="确定", command=dialog.destroy).pack(side="left", padx=5)
# 设置对话框位置为居中
dialog.update_idletasks()
width = dialog.winfo_width()
height = dialog.winfo_height()
x = (dialog.winfo_screenwidth() // 2) - (width // 2)
y = (dialog.winfo_screenheight() // 2) - (height // 2)
dialog.geometry(f"{width}x{height}+{x}+{y}")
# 等待对话框关闭
self.root.wait_window(dialog)
def minimize_window(self):
"""最小化窗口"""
self.root.iconify()
def maximize_window(self):
"""最大化/还原窗口"""
if self.root.state() == 'zoomed':
self.root.state('normal')
else:
self.root.state('zoomed')
def on_closing(self):
"""窗口关闭处理"""
try:
logging.info("正在关闭程序...")
# 先退出主循环
self.root.quit()
# 等待一小段时间确保资源释放
time.sleep(0.5)
except Exception as e:
logging.error(f"关闭程序时出错: {str(e)}")
finally:
try:
# 销毁窗口
self.root.destroy()
# 再等待一小段时间
time.sleep(0.5)
# 强制结束进程
if sys.platform == "win32":
import os
os._exit(0)
except:
# 如果还是无法正常关闭,直接强制退出
os._exit(0)
def run(self):
"""运行程序"""
self.root.mainloop()
def reset_machine_id(self):
"""刷新Cursor编辑器授权"""
if not self.check_status():
self.show_purchase_info()
return
try:
success, message = self.switcher.refresh_cursor_auth()
if success:
messagebox.showinfo("成功", "Cursor编辑器授权刷新成功\n" + message)
else:
messagebox.showerror("错误", message)
except Exception as e:
messagebox.showerror("错误", f"刷新失败: {str(e)}")
def disable_cursor_update(self):
"""禁用Cursor版本更新"""
if not self.check_status():
self.show_purchase_info()
return
try:
success, message = self.switcher.disable_cursor_update()
if success:
messagebox.showinfo("成功", message)
else:
messagebox.showerror("错误", message)
except Exception as e:
messagebox.showerror("错误", f"操作失败: {str(e)}")
def dummy_function(self):
"""突破版本限制"""
if not self.check_status():
self.show_purchase_info()
return
try:
success, message = self.switcher.bypass_version_limit()
if success:
messagebox.showinfo("成功", message)
else:
messagebox.showerror("错误", message)
except Exception as e:
messagebox.showerror("错误", f"操作失败: {str(e)}")