mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 10:10:43 +00:00
被控端 - 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%) - 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败) - 每分钟回头找局域网,自动切回快 400 倍的路径 - 画面心跳帧:静止时省流量,客户端仍知道流是活的 - 锁屏时给出可操作的提示 手表端 - 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException - 连接错误翻译成人话(证书/时间/解析/超时分别提示) - 经中转连上后用服务器报的地址刷新已配对记录 - 新增局域网连接页面、服务器延迟检测 服务器端 - 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502) - 网络调优脚本 net-tune.sh(开机自动应用) - 管理页:批量删除、网络体检、下载区 - 隧道改 HTTP/2 + 双连接 文档 - 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
298 lines
12 KiB
Python
298 lines
12 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""重做电脑端界面(保留浅色 + 简洁的设计理念,提升观感)+ 两个新入口。
|
||
|
||
改动:
|
||
* 顶栏:主色竖条 + 粗体标题 + 圆角风格的状态徽标(有底色,不是干巴巴一行字)
|
||
* 配对卡片:更大留白、更清晰的层次、副标题
|
||
* 底栏:接收目录 / 连不上? / 设置 / 退出
|
||
* 新增 open_selfcheck():一键拉起网络自检的控制台窗口
|
||
* 新增 open_settings():投图窗口标题、TTS 音色与语速、本机音乐目录
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
UI = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows"
|
||
r"\lanremote\ui.py")
|
||
|
||
OLD_BUILD_START = ''' def _build(self) -> None:
|
||
pad = {"padx": 14}
|
||
|
||
head = tk.Frame(self.root, bg=BG)
|
||
head.pack(fill="x", pady=(12, 4), **pad)
|
||
tk.Label(head, text=APP_NAME, bg=BG, fg=FG, font=FONT_TITLE).pack(side="left")
|
||
self.lbl_state = tk.Label(head, text="启动中", bg=BG, fg=DIM, font=FONT_SMALL)
|
||
self.lbl_state.pack(side="right")
|
||
|
||
card = tk.Frame(self.root, bg=CARD, highlightthickness=1,
|
||
highlightbackground=BORDER)
|
||
card.pack(fill="x", pady=6, **pad)
|
||
tk.Label(card, text="在手表上输入这串数字", bg=CARD, fg=DIM,
|
||
font=FONT_SMALL).pack(pady=(10, 0))
|
||
self.lbl_code = tk.Label(card, text="------", bg=CARD, fg=ACCENT, font=FONT_BIG)
|
||
self.lbl_code.pack(pady=(0, 2))
|
||
self.lbl_code.bind("<Double-Button-1>", lambda _e: self.copy_code())
|
||
|
||
row = tk.Frame(card, bg=CARD)
|
||
row.pack(pady=(0, 10))
|
||
self._btn(row, "换一组", self.new_code, width=8)
|
||
self._btn(row, "复制", self.copy_code, width=6)
|
||
'''
|
||
|
||
NEW_BUILD_START = ''' def _build(self) -> None:
|
||
pad = {"padx": 14}
|
||
|
||
# ---- 顶栏:主色竖条 + 标题 + 状态徽标 ----
|
||
head = tk.Frame(self.root, bg=BG)
|
||
head.pack(fill="x", pady=(12, 8), **pad)
|
||
tk.Frame(head, bg=ACCENT, width=4, height=18).pack(side="left", padx=(0, 8))
|
||
tk.Label(head, text=APP_NAME, bg=BG, fg=FG,
|
||
font=("Microsoft YaHei UI", 12, "bold")).pack(side="left")
|
||
self.state_badge = tk.Frame(head, bg="#eef1f4")
|
||
self.state_badge.pack(side="right")
|
||
self.lbl_state = tk.Label(self.state_badge, text="● 启动中", bg="#eef1f4",
|
||
fg=DIM, font=("Microsoft YaHei UI", 9, "bold"),
|
||
padx=10, pady=3)
|
||
self.lbl_state.pack()
|
||
|
||
# ---- 配对码卡片 ----
|
||
card = tk.Frame(self.root, bg=CARD, highlightthickness=1,
|
||
highlightbackground=BORDER)
|
||
card.pack(fill="x", pady=(0, 8), **pad)
|
||
tk.Label(card, text="在手表上输入这串数字", bg=CARD, fg=DIM,
|
||
font=FONT_SMALL).pack(pady=(14, 0))
|
||
self.lbl_code = tk.Label(card, text="------", bg=CARD, fg=ACCENT,
|
||
font=FONT_BIG)
|
||
self.lbl_code.pack(pady=(2, 0))
|
||
self.lbl_code.bind("<Double-Button-1>", lambda _e: self.copy_code())
|
||
tk.Label(card, text="双击数字也能复制", bg=CARD, fg="#9aa4af",
|
||
font=("Microsoft YaHei UI", 8)).pack()
|
||
|
||
row = tk.Frame(card, bg=CARD)
|
||
row.pack(pady=(12, 16))
|
||
self._btn(row, "换一组", self.new_code, width=9)
|
||
self._btn(row, "复制", self.copy_code, width=7, last=True)
|
||
'''
|
||
|
||
OLD_FOOT = ''' foot = tk.Frame(self.root, bg=BG)
|
||
foot.pack(fill="x", side="bottom", pady=(0, 6), **pad)
|
||
self._btn(foot, "打开接收目录", self.open_received, width=12)
|
||
self._btn(foot, "退出", self.quit_app, width=7, danger=True)
|
||
|
||
tk.Label(self.root,
|
||
text="关掉窗口后仍在后台运行\\n再次双击图标可找回本窗口",
|
||
bg=BG, fg=DIM, font=("Microsoft YaHei UI", 8),
|
||
anchor="w", justify="left").pack(fill="x", side="bottom",
|
||
padx=14, pady=(0, 8))
|
||
'''
|
||
|
||
NEW_FOOT = ''' foot = tk.Frame(self.root, bg=BG)
|
||
foot.pack(fill="x", side="bottom", pady=(0, 6), **pad)
|
||
self._btn(foot, "接收目录", self.open_received, width=9)
|
||
self._btn(foot, "连不上?", self.open_selfcheck, width=9)
|
||
self._btn(foot, "设置", self.open_settings, width=6)
|
||
self._btn(foot, "退出", self.quit_app, width=5, danger=True, last=True)
|
||
|
||
tk.Label(self.root,
|
||
text="关掉窗口后仍在后台运行,再次双击可找回",
|
||
bg=BG, fg=DIM, font=("Microsoft YaHei UI", 8),
|
||
anchor="w", justify="left").pack(fill="x", side="bottom",
|
||
padx=14, pady=(0, 8))
|
||
'''
|
||
|
||
OLD_BTN = ''' def _btn(self, parent, text, command, width=10, danger=False):
|
||
bg = "#ffeef0" if danger else "#eaeef2"
|
||
hover = "#ffdce0" if danger else "#dfe4ea"
|
||
btn = tk.Button(parent, text=text, command=command, width=width,
|
||
bg=bg, fg=(DANGER if danger else FG), activebackground=hover,
|
||
activeforeground=(DANGER if danger else FG), highlightthickness=1,
|
||
highlightbackground=BORDER, bd=0,
|
||
relief="flat", font=FONT_UI, cursor="hand2", padx=4, pady=4)
|
||
btn.pack(side="left", padx=(0, 8))
|
||
'''
|
||
|
||
NEW_BTN = ''' def _btn(self, parent, text, command, width=10, danger=False, last=False):
|
||
bg = "#ffeef0" if danger else "#eaeef2"
|
||
hover = "#ffdce0" if danger else "#dfe4ea"
|
||
btn = tk.Button(parent, text=text, command=command, width=width,
|
||
bg=bg, fg=(DANGER if danger else FG), activebackground=hover,
|
||
activeforeground=(DANGER if danger else FG), highlightthickness=1,
|
||
highlightbackground=BORDER, bd=0,
|
||
relief="flat", font=FONT_UI, cursor="hand2", padx=4, pady=5)
|
||
btn.pack(side="left", padx=(0, 0 if last else 8))
|
||
'''
|
||
|
||
OLD_REFRESH_STATE = ''' if sharing:
|
||
self.lbl_state.configure(text="屏幕共享中", fg=DANGER)
|
||
elif connected:
|
||
self.lbl_state.configure(text="已连接", fg=OK)
|
||
else:
|
||
self.lbl_state.configure(text="运行中", fg=OK)
|
||
'''
|
||
|
||
NEW_REFRESH_STATE = ''' if sharing:
|
||
self.set_badge("● 屏幕共享中", DANGER, "#ffeef0")
|
||
elif connected:
|
||
self.set_badge("● 已连接", OK, "#e6f4ea")
|
||
else:
|
||
self.set_badge("● 待连接", DIM, "#eef1f4")
|
||
'''
|
||
|
||
NEW_METHODS = ''' # ---- 状态徽标 ----
|
||
|
||
def set_badge(self, text: str, color: str, soft: str) -> None:
|
||
try:
|
||
self.state_badge.configure(bg=soft)
|
||
self.lbl_state.configure(text=text, bg=soft, fg=color)
|
||
except tk.TclError:
|
||
pass
|
||
|
||
# ---- 连不上?直接拉起网络自检 ----
|
||
|
||
def open_selfcheck(self) -> None:
|
||
"""连不上时一键启动网络自检(开一个控制台窗口显示实时结果)。"""
|
||
import subprocess
|
||
|
||
from .config import app_dir
|
||
bat = app_dir() / "网络自检.bat"
|
||
if not bat.is_file():
|
||
self.show_message("没找到 网络自检.bat")
|
||
return
|
||
try:
|
||
flags = getattr(subprocess, "CREATE_NEW_CONSOLE", 0)
|
||
subprocess.Popen(["cmd", "/c", str(bat)], creationflags=flags)
|
||
except Exception as exc: # noqa: BLE001
|
||
self.show_message(f"启动自检失败:{exc}")
|
||
return
|
||
self.show_message("已打开网络自检窗口")
|
||
|
||
# ---- 设置 ----
|
||
|
||
def open_settings(self) -> None:
|
||
"""设置对话框:投图窗口标题 / TTS 音色与语速 / 本机音乐目录。"""
|
||
from .actions import Actions
|
||
|
||
win = tk.Toplevel(self.root)
|
||
win.title("设置")
|
||
win.configure(bg=BG)
|
||
win.resizable(False, False)
|
||
|
||
def row_label(text, hint=""):
|
||
box = tk.Frame(win, bg=BG)
|
||
box.pack(fill="x", padx=16, pady=(10, 2))
|
||
tk.Label(box, text=text, bg=BG, fg=FG, font=FONT_UI,
|
||
anchor="w").pack(side="left")
|
||
if hint:
|
||
tk.Label(box, text=hint, bg=BG, fg=DIM,
|
||
font=("Microsoft YaHei UI", 8)).pack(side="left", padx=(6, 0))
|
||
|
||
def entry(initial, width=34):
|
||
box = tk.Frame(win, bg=BG)
|
||
box.pack(fill="x", padx=16)
|
||
ent = tk.Entry(box, width=width, bg=CARD, fg=FG, relief="flat",
|
||
font=FONT_UI, highlightthickness=1,
|
||
highlightbackground=BORDER, highlightcolor=ACCENT)
|
||
ent.pack(fill="x", ipady=5)
|
||
ent.insert(0, initial)
|
||
return ent
|
||
|
||
# 投图窗口标题
|
||
row_label("投图窗口标题", "支持 {name}")
|
||
ent_title = entry(str(self.store.get("image_window_title") or ""))
|
||
|
||
# TTS 音色
|
||
row_label("语音播报音色")
|
||
voice_box = tk.Frame(win, bg=BG)
|
||
voice_box.pack(fill="x", padx=16)
|
||
voices = []
|
||
try:
|
||
voices = Actions(self, self.store).list_voices()
|
||
except Exception: # noqa: BLE001
|
||
voices = []
|
||
current = str(self.store.get("tts_voice") or "")
|
||
options = ["系统默认"] + voices
|
||
var_voice = tk.StringVar(value=current if current in voices else "系统默认")
|
||
opt = tk.OptionMenu(voice_box, var_voice, *options)
|
||
opt.configure(bg=CARD, fg=FG, activebackground="#eaeef2",
|
||
activeforeground=FG, relief="flat", highlightthickness=1,
|
||
highlightbackground=BORDER, font=FONT_SMALL, width=26,
|
||
anchor="w", cursor="hand2", padx=4)
|
||
try:
|
||
opt["menu"].configure(bg=CARD, fg=FG, font=FONT_SMALL,
|
||
activebackground="#eaeef2", bd=0)
|
||
except tk.TclError:
|
||
pass
|
||
opt.pack(side="left")
|
||
|
||
# 语速
|
||
row_label("语速", "-10 慢 … 10 快")
|
||
ent_rate = entry(str(self.store.get("tts_rate", 0)), width=8)
|
||
|
||
# 本机音乐目录
|
||
row_label("本机音乐目录", "留空=自动找 音乐 / Music / Downloads")
|
||
ent_mp3 = entry(str(self.store.get("mp3_dir") or ""))
|
||
|
||
def save():
|
||
self.store.set("image_window_title", ent_title.get().strip())
|
||
chosen = var_voice.get()
|
||
self.store.set("tts_voice", "" if chosen == "系统默认" else chosen)
|
||
raw = ent_rate.get().strip()
|
||
try:
|
||
rate = max(-10, min(10, int(raw)))
|
||
except ValueError:
|
||
rate = 0
|
||
self.store.set("tts_rate", rate)
|
||
self.store.set("mp3_dir", ent_mp3.get().strip())
|
||
self.log(f"设置已保存(音色={chosen},语速={rate})")
|
||
win.destroy()
|
||
self.show_message("设置已保存")
|
||
|
||
buttons = tk.Frame(win, bg=BG)
|
||
buttons.pack(fill="x", padx=16, pady=(16, 16))
|
||
self._btn(buttons, "保存", save, width=8)
|
||
self._btn(buttons, "取消", win.destroy, width=6, last=True)
|
||
|
||
self.center_window(win)
|
||
|
||
def _build(self) -> None:
|
||
'''
|
||
|
||
|
||
def main() -> int:
|
||
text = UI.read_text(encoding="utf-8")
|
||
ok = True
|
||
for old, new, tag in ((OLD_BUILD_START, NEW_BUILD_START, "顶栏+卡片"),
|
||
(OLD_FOOT, NEW_FOOT, "底栏"),
|
||
(OLD_BTN, NEW_BTN, "按钮 last"),
|
||
(OLD_REFRESH_STATE, NEW_REFRESH_STATE, "状态徽标")):
|
||
if old not in text:
|
||
print(f" [失败] {tag} 锚点未匹配")
|
||
ok = False
|
||
else:
|
||
text = text.replace(old, new, 1)
|
||
print(f" {tag}: OK")
|
||
|
||
if not ok:
|
||
return 1
|
||
|
||
# 插入新方法(放在 _build 之前)
|
||
text = text.replace(" def _build(self) -> None:",
|
||
NEW_METHODS, 1)
|
||
UI.write_text(text, encoding="utf-8")
|
||
print(" 新方法: OK")
|
||
|
||
print("\n语法检查:")
|
||
import ast
|
||
try:
|
||
ast.parse(UI.read_text(encoding="utf-8"))
|
||
print(" ui.py: OK")
|
||
except SyntaxError as exc:
|
||
print(f" ui.py: 语法错误 {exc}")
|
||
return 1
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|