wangjia
9e26dd6d97
chore: bump 1.0.41+42
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-30 09:00:00 +08:00
wangjia
2fbaba7608
chore: bump 1.0.40+41
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-30 08:05:32 +08:00
wangjia
ca34d0cadb
chore: bump 1.0.39+40
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-30 07:33:43 +08:00
wangjia
af24612e04
chore: bump 1.0.38+39
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-30 07:26:31 +08:00
wangjia
48bc5c6b39
chore: bump 1.0.37+38
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-30 01:32:15 +08:00
wangjia
ba65b03fd5
chore: bump 1.0.36+37
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-30 01:23:13 +08:00
wangjia
93a31a9415
chore: bump 1.0.35+36
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-30 00:50:58 +08:00
wangjia
53eb982254
chore: bump 1.0.34+35
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 23:50:48 +08:00
wangjia
e292775c7e
chore: bump 1.0.33+34
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 23:35:40 +08:00
wangjia
7c7e8e4f6c
chore: bump 1.0.32+33
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 23:26:19 +08:00
wangjia
e9dbe9aa7d
chore: bump 1.0.31+32
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 23:21:18 +08:00
wangjia
cd143af248
chore: bump 1.0.30+31
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 21:28:08 +08:00
wangjia
701d9eb095
fix(client): 开机自启隐藏窗口在原生 runner 层跳过首帧 Show()(1.0.29)
...
1.0.28 的 Dart hide() 早于 Flutter Windows runner 首帧回调的 Show(),被覆盖,
窗口仍弹出。改在 flutter_window.cpp 检测命令行 --autostart 时不注册首帧 Show()
回调,窗口(WS_OVERLAPPEDWINDOW 无 WS_VISIBLE)保持隐藏;Dart hide() 保留以同步
window_manager 状态。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 20:20:55 +08:00
wangjia
49bef2fb27
feat(client): 开机自启拉起直接最小化到托盘(--autostart 标志)(1.0.28)
...
计划任务 /tr 命令带 --autostart;main() 检测到该参数在首帧前 windowManager.hide()
隐藏主窗口到托盘,自动连接逻辑照常跑。手动打开(无参数)仍正常显示窗口。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 20:11:36 +08:00
wangjia
ada99e6c3a
fix(client): 自动连接死锁兜底(轮询)+ 逐次门控日志(1.0.27)
...
复现:armed→设置已加载后无 ready。死锁:selLoaded 靠 selectedNode controller 的 loaded 标志,
而该标志完成时若选中值未变(==默认)不会发通知,若 nodeSub 已先于它触发则此后无人再调 tryGo。
修:_maybeAutoConnect 加 Timer.periodic(400ms,≤12s)兜底复查,decided 后停;并恢复每次 tryGo
打 check 日志(settingsLoaded/selLoaded/node uuid)以确认卡点。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 19:58:53 +08:00
wangjia
277d1c6e97
feat(client): toast 限定主显示区/自适应宽/上限80%/超长多行居中(1.0.26)
...
按真相源新规:toast 改为自定义 Overlay 实现(widgets/pangolin_toast.dart),完全控制布局——
不覆盖左侧栏(left=侧栏宽 desktop204/tablet232/mobile0)、宽度自适应内容上限主区80%、超长文本
多行、主区内水平居中贴底、淡入轻起;仍走语义 token 明暗适配。自动连接改用 showPangolinToast。
同步 design/CONTRACT.md §2 toast 规格(canonical=showPangolinToast)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 19:50:33 +08:00
wangjia
828bb4ca94
style(client): toast 跟随明暗主题(1.0.25)
...
真相源/主题里原无 toast 定义,SnackBar 用 Material 默认黑底,明亮主题下突兀。
PangolinTheme 加 snackBarTheme:surface 底 + fg1 字 + 描边圆角(与卡片同风格)、floating,
浅色得浅 toast、深色得深 toast。自动连接的 toast 随之适配。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 19:39:00 +08:00
wangjia
e89f3de748
feat(client): 记住上次选择的节点 + 自动连接 toast(1.0.24)
...
- selectedNodeCodeProvider 改为持久化 StateNotifier(select() 落盘、启动恢复,默认智能 AUTO);
自动连接复用上次选择:智能就智能、具体就具体。
- 自动连接门控加等「选中节点已恢复」(controller.loaded),避免用到未恢复的默认值。
- 自动连接触发时弹 toast「正在自动连接到 X」(全局 ScaffoldMessenger key)。
- 测试:选中节点 select 落盘 + 重启恢复(具体/智能)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 19:31:01 +08:00
wangjia
f2891ff2f9
fix(client): 自动连接门控改判生效节点就绪 + _connect 诊断日志(1.0.23)
...
自动连接已正确触发,但 _connect 撞 node.uuid.isEmpty 报「节点尚未就绪」:门控用的是
nodes.any(uuid),而 _connect 用 effectiveNode。改门控直接判 effectiveNode.uuid 非空(与
_connect 同一判据)。_connect 加一行日志记录 node/uuid/selected/nodes 便于确认。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 19:15:39 +08:00
wangjia
28f8e5ebcd
fix(client): 自动连接竞态真因 — 等设置加载完再判(1.0.22)
...
日志实证:节点就绪(~450ms)与设置加载几乎同时完成,节点回调早 1ms 读到还没加载完的
autoConnect=false → 不连。AppSettings 加 loaded 标志(_load 完成置 true,失败也置);
_maybeAutoConnect 同时监听 nodes + settings,二者都就绪(settings.loaded && 节点 uuid 非空)
才决策一次。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 19:08:49 +08:00
wangjia
ff2f2f3c07
fix(client): 自动连接回调改用强类型 ref.read + 日志落文件(1.0.21)
...
- 自动连接回调不再用 listenManual 的 next(裸订阅会退化成 dynamic → valueOrNull 扩展崩),
改 ref.read(nodesProvider) 拿强类型 AsyncValue,彻底躲开 dynamic 扩展坑。
- logLine 除 stdout 外落桌面端固定文件(%LOCALAPPDATA%\Pangolin\pangolin.log,每次启动截断),
GUI/管理员启动也能拿日志,免 Tee。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 19:01:48 +08:00
wangjia
7fdadace4e
fix(client): 自动连接回调 NoSuchMethod(valueOrNull on dynamic)— 真正根因
...
日志显示每次节点加载,_maybeAutoConnect 回调抛 NoSuchMethodError:AsyncData 没有 valueOrNull
(在判 autoConnect 之前就崩)→ 自动连接从未生效。根因:sub 声明成裸 ProviderSubscription
(=<dynamic>),逼 listenManual 推断成 dynamic,next 变 dynamic;valueOrNull 是扩展 getter,
dynamic 上不解析 → 运行期 NoSuchMethod。修:sub 标全泛型 ProviderSubscription<AsyncValue<List<Node>>>。
(1.0.18 的竞态修复是误判,真凶是这个崩溃。)诊断日志暂留,确认后清。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 18:46:57 +08:00
wangjia
f734126eb6
chore(client): 1.0.19 — 自动连接诊断日志
...
排查「自动连接没生效」:在 _RootFlow 自动连接路径(HomeShell 显示 / 节点就绪 / autoConnect/phase 判定 / 触发)
与 Settings(_load 读到的 autoConnect、setAutoConnect 落盘)加 logLine 日志,定位卡在哪一步。诊断完移除。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 18:26:47 +08:00
wangjia
6beed211b9
fix(client): 自动连接竞态 + 版本 1.0.18+19
...
_maybeAutoConnect 启动瞬间同步读 settingsProvider.autoConnect,但其 _load 异步(SharedPreferences)
还没完成 → 读到默认 false 而永久跳过自动连接。改到「节点就绪」回调里再判 autoConnect(节点走网络
拉取,远慢于本地设置读取,届时设置必已加载到位)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 18:20:13 +08:00
wangjia
9d18579c11
chore(client): 版本号 1.0.17+18(智能选择确认/搜索框配色/PangolinFieldBox/连通看门狗/自动连接+Win自启)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 17:54:33 +08:00
wangjia
0820397a14
chore(client): 版本号 1.0.16+17(single-flight 刷新 + 托盘退出崩溃修复)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 11:46:16 +08:00
wangjia
eafc7167e2
chore(client): 版本号 1.0.15+16(自适应菜单 + 节点切换防误触)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 10:11:48 +08:00
wangjia
880fa32793
fix(devices): 本机也显示 ⋯ 菜单(只「重命名」)—— 修单设备无法改名(1.0.14)
...
ci-pangolin / Lint — shellcheck (push) Successful in 8s
ci-pangolin / OpenAPI Sync Check (push) Successful in 16s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 6s
ci-pangolin / Flutter — analyze + test (push) Failing after 14s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 4s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 5s
ci-pangolin / Go — build + test (push) Successful in 9s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 15s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m10s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 14s
之前 ⋯ 菜单对本机隐藏,而用户唯一设备就是本机 → 根本点不到、改不了名。
改:本机显示 ⋯ 菜单但只含「重命名」(自我强制退出/清除无意义,仍只对他设备)。
测试:本机菜单只有重命名断言;全量 flutter 绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 09:49:09 +08:00
wangjia
315c343ed5
feat(devices): 设备默认名「平台简写·主机名」+ 支持重命名(1.0.13)
...
ci-pangolin / Lint — shellcheck (push) Successful in 7s
ci-pangolin / OpenAPI Sync Check (push) Successful in 17s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 6s
ci-pangolin / Flutter — analyze + test (push) Failing after 14s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 5s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 6s
ci-pangolin / Go — build + test (push) Successful in 11s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 14s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m3s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 14s
① 默认名:DeviceIdentity 改「平台简写(Win/Mac/Linux/iOS/Andr)·主机名」,主机名截
到 8、总长≈12(替代裸主机名,更短)。
② 重命名:新端点 POST /v1/me/devices/{uuid}/rename(Service.RenameDevice 校验归属+
截 64);store.UpdateName;客户端 account_api.renameDevice + provider.rename +
「我的设备」⋯ 菜单加「重命名」+ 输入弹窗;l10n(zh/en)。
③ 版本 1.0.13。
测试:server RenameDevice(归属/空名/404)+ 客户端 rename widget;全量 go/flutter 绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 09:12:36 +08:00
wangjia
878cef9e52
build(client): 1.0.12 — 设备下拉接已登录设备 + 版本对齐(pubspec=iss=1.0.12)
...
ci-pangolin / Lint — shellcheck (push) Successful in 5s
ci-pangolin / OpenAPI Sync Check (push) Successful in 17s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 6s
ci-pangolin / Flutter — analyze + test (push) Failing after 14s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 5s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 6s
ci-pangolin / Go — build + test (push) Successful in 9s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 14s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m6s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 15s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 08:41:37 +08:00
wangjia
8a1db07d19
fix(devices+stats): /v1/me/devices 401 修复 + 设备下拉接已登录设备 + 版本号
...
ci-pangolin / Lint — shellcheck (push) Successful in 9s
ci-pangolin / OpenAPI Sync Check (push) Successful in 19s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 6s
ci-pangolin / Flutter — analyze + test (push) Failing after 15s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 5s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 5s
ci-pangolin / Go — build + test (push) Successful in 10s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 14s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m2s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 15s
① 「我的设备打不开」根因:devices handler 读 devices.CtxKeyUserID,而鉴权中间件
把 user id 写在 auth 的 key 下(类型不同→取不到)→ /v1/me/devices 一直 401。
改 handler 用 auth.UserIDFromContext(与 accountAPI 等一致)。
② 统计页设备下拉改读 devicesProvider(已登录设备),不再只列有用量的设备 →
windows 设备现在会出现。
③ pubspec version 1.0.2+3 → 1.0.11+12,client_version 不再显示陈旧的 v1.0.2。
测试:devices_screen + stats_device_filter widget(下拉读 /v1/me/devices)+全量绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 08:37:11 +08:00
wangjia
c0c4b94e29
feat(devices): P1 设备注册打通 —— 登录/注册即写 devices 表
...
ci-pangolin / Lint — shellcheck (push) Successful in 8s
ci-pangolin / OpenAPI Sync Check (push) Successful in 16s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 7s
ci-pangolin / Flutter — analyze + test (push) Successful in 26s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 5s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 5s
ci-pangolin / Go — build + test (push) Failing after 10s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 15s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m10s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 14s
后端:auth.Service 加 DeviceMeta + DeviceRegistrar 接口(consumer-side 解耦),
Login/Register 成功签发后 best-effort 注册设备(不强制设备上限,避免免费档重装
churn 锁死用户);handler 加 device 请求体;main 用 authDeviceRegistrar 适配
devices.Service 注入;normalizePlatform 加 linux。
客户端:新 device_identity.dart(SecureKV 接缝 + 稳定 UUIDv4 device_id 持久化 +
名称/平台/版本);弃用硬编码 'mac-001';auth_api login/register + connect 携带
device 元数据。加 uuid + device_info_plus 依赖。
测试:auth 设备注册(触发/best-effort/空 meta) + device_identity(生成/持久/
读失败不重生成/UUIDv4 形态);normalizePlatform linux=true。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-29 00:28:13 +08:00
wangjia
8eb7d04fe1
feat(client): 节点地区图标改国旗(SVG 填满裁切),未知码回退码块
...
CountryCode 由 2 字母码块改为渲染真国旗:country_flags 包按 region 码出 SVG
旗(BoxFit.cover 填满裁切),全平台含 Windows 都显示(emoji 国旗在 Windows
不渲染,故走 SVG)。FlagCode 判定无效码(AUTO/占位/非地区码)时回退原码块;
选中态由 accent 底色改为 accent 边框环。
CountryCode 共享于节点列表/连接页/统计页,故三处节点图标统一变国旗,
对应 tablet_servers/connect/stats + desktop_stats golden 已 Mac 重生成
(这些页非 CI golden 闸;CI 闸的 components/auth 基线未动)。
依赖:country_flags ^3.1.0(解析 3.3.0)。analyze 干净,非 golden 测试全过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-28 16:25:48 +08:00
wangjia
62925a6886
Merge worktree-windows-icon-tray-fix: Windows 桌面/托盘/任务栏图标 + 关窗不断连接
...
- 关窗(X/Alt+F4)隐藏到托盘并保持隧道,真退出只走托盘菜单(Platform.isWindows 隔离)
- 窗口标题设「穿山甲」(无 VPN 字眼)
- Windows 托盘改用 .ico(Win32 只认 ico,PNG 空白),mac/Linux 仍 PNG
- 更新 app_icon.ico / tray_icon.ico / Runner.rc / installer
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-23 10:54:23 +08:00
wangjia
11ee3342bf
feat(client/ios): 补齐 App 图标(iPhone+iPad 全尺寸,去 alpha)
...
iOS AppIcon.appiconset 只有 Contents.json、无任何 PNG → 桌面图标空白。
以 design 单源 assets/app-icon.svg(去圆角 rx=0 全幅方形)经 qlmanage 渲染 1024,
flutter_launcher_icons 铺开 21 张全尺寸(含 iPad 76/83.5)并去 alpha(App Store 合规)。
新增 dev_dep flutter_launcher_icons + 配置块,改图标重渲源图后 dart run 即可。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-23 00:39:37 +08:00
wangjia
5ea4e1ae03
fix(client/windows): 任务栏图标 + 关闭窗口不再断连接
...
- 关闭窗口断连接:onExitRequested 原先无条件 _teardownVpn 再退出;Windows 点 X
会触发该回调拆隧道,而 window_manager 的 preventClose 又把窗口仅隐藏到托盘
→ 出现「一关就断网、进程还在」。改为 Windows 下点 X/Alt+F4 取消退出+隐藏,
保持隧道;真正退出只走托盘「退出」(onBeforeQuit 标记 _isQuitting 再拆隧道)。
macOS Cmd+Q 仍正常拆隧道退出。
- 任务栏图标没换:仅靠 WNDCLASS.hIcon(LoadIcon 单尺寸)任务栏可能拿不到正确
尺寸。窗口创建后用 LoadImage 按系统 SM_CXICON/SM_CXSMICON 各取一份,
WM_SETICON 显式设 ICON_BIG(任务栏/Alt-Tab)+ ICON_SMALL(标题栏)。
- 版本 1.0.1 → 1.0.2。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-22 17:53:34 +08:00
wangjia
94993b21b4
fix(client/windows): 修桌面/标题栏图标 + 标题文案 + 系统托盘空白
...
- app_icon.ico 重新由 assets/app-icon.svg 生成(穿山甲品牌图标,多尺寸),
替换残留的默认 Flutter logo —— 同时修好桌面图标与标题栏小图标。
- 窗口标题去掉 "VPN" 字眼:main.cpp 原生标题 pangolin_vpn → Pangolin;
main.dart 用 windowManager.setTitle('穿山甲') 显示中文品牌名;
Runner.rc 的 FileDescription/InternalName/ProductName → Pangolin。
- 系统托盘空白:Windows 走 Win32 Shell_NotifyIcon 只认 .ico(传 PNG 显示空白),
新增 BMP 编码的 assets/tray_icon.ico,system_tray.dart 按平台选 ico/png。
- 安装包版本 1.0.0 → 1.0.1(pubspec 1.0.1+2)便于区分测试构建。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-22 17:06:05 +08:00
wangjia
6fc032bac8
feat(client): 字体改本地打包(拉丁全量 + Noto Sans SC GB2312 子集)
...
生产 PangolinFonts.useBundled=true,离线可用,不再运行时拉 google_fonts;
中文经 fontFamilyFallback=[Noto Sans SC] 兜底,子集外字符再兜系统 CJK 字体。
- 拉丁:Sora/Manrope/JetBrains Mono 静态权重(复用 test/fonts)。
- 中文:Noto Sans SC 变量字体 instance 到 Regular + subset 到 GB2312 6763 字
(单权重,粗体引擎合成),client/fonts 合计约 3.4MB。
- tools/fonts/make-cjk-subset.sh 可复现生成(GB2312 字表无需联网)。
- 新增 test/unit/fonts_test.dart 锁定接线;golden 因 notdef 占位字形微调已更新。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-22 07:48:21 +08:00
wangjia
e10f214dee
feat(client): 系统托盘常驻 + 关闭窗口隐藏到托盘(桌面端)
...
ci-pangolin / Lint — shellcheck (push) Has been cancelled
ci-pangolin / OpenAPI Sync Check (push) Has been cancelled
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Has been cancelled
ci-pangolin / Flutter — analyze + test (push) Has been cancelled
- system_tray.dart:TrayService 用 tray_manager + window_manager。setPreventClose
拦截关闭 → 隐藏到托盘(常驻保持隧道);托盘图标点击/「显示主界面」重新显示,
「退出」真正退出。
- main() 改 async:桌面端 runApp 前 init 托盘;移动端/web 跳过(isDesktop 守卫)。
- 托盘图标复用 app_icon_32.png → assets/tray_icon.png。
- 新依赖:tray_manager / window_manager。
flutter analyze 0 error;114 tests passed。托盘为运行时/原生功能,需 release .app 验证。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 06:31:40 +08:00
wangjia
6ee7114ff8
feat(client): P6 设置项落地真实行为( #6 6F,本地部分)
...
ci-pangolin / Lint — shellcheck (push) Has been cancelled
ci-pangolin / OpenAPI Sync Check (push) Has been cancelled
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Has been cancelled
ci-pangolin / Flutter — analyze + test (push) Has been cancelled
- settings_provider:三开关 shared_preferences 持久化 + 副作用落地:
killSwitch→VpnBridge.setKillSwitch(on:);autostart→桌面原生登录项
(launch_at_startup);smartRoute 持久化为偏好(连接时作 split_cn,见 #5 )。
- settings_page → ConsumerWidget,开关接 settingsProvider;协议标签
WireGuard→REALITY/Hysteria2;版本号取 pubspec(package_info_plus)。
- 新依赖:shared_preferences / package_info_plus / launch_at_startup。
flutter analyze 0 error;114 tests passed;settings golden 重生成。
待办:#5 智能分流的 server 端 geoip-cn 下发 + autostart 真机验证(需 release .app)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 00:13:41 +08:00
wangjia
4dc4127252
feat(client): 三端布局架构 + macOS 桌面端 + app 图标
...
三端布局(mobile/tablet/desktop):
- core/responsive/form_factor.dart 形态判定 + shell/ 分发器(home_shell→desktop/mobile)
- desktop_shell 对照 ui_kits/desktop/dapp.jsx: 侧栏204·6项 + 套餐卡 + 顶栏(标题/状态/主题切换) + 连接页居中单列
- 新增组件 nav_sidebar / plan_badge_card / content_top_bar / bottom_tab_bar
- 新增一级页 contact_page / settings_page; navigation_provider(NavView)
- 删除旧 widgets/home_shell.dart(逻辑迁入 shell/)
macOS 桌面端:
- 窗口默认 920×600 + 最小 720×560(MainFlutterWindow.swift)
- app 图标替换为穿山甲(AppIcon.appiconset 全套, 由 app-icon.svg 渲染)
其余(本会话):
- Phase2 接线: auth_api/token_store/auth_provider/vpn_bridge_provider + 真实 connection/nodes
- lucide_icons 兼容补丁(packages/lucide_icons_patched) 修复 IconData final 报错
- 测试修复: connect_passthrough(UTF-8) / harness / golden @Skip
- l10n 新增 settingsTitle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-16 09:23:20 +08:00
wangjia
bf1717a369
merge: 控制面联调 M6 [tsk_nuoKSM4Vt-zK]
...
# Conflicts:
# .gitignore
# client/lib/widgets/home_shell.dart
# client/lib/widgets/server_tile.dart
# client/pubspec.yaml
2026-06-13 17:32:26 +08:00
wangjia
f97ae8186b
feat(client): Flutter 逐屏还原 + iPad ≥900 断点 (tsk_gpPXi-icyeOE)
...
对照 design/ui_kits mobile+tablet 原型逐屏补齐 Flutter 客户端:
- l10n 资源层(strings_zh/en,单显)+ Riverpod 状态层(连接状态机/免费额度/
节点选择/语言/主题),UI 与数据解耦,mock 数据接 API 不动 UI。
- 连接键严格三态(off 虚线轨道环 / connecting 旋转弧 / on 满环+计时+光晕),
状态来自 connectionProvider,点击只派发事件——禁止乐观显示。
- 节点页置顶「智能选择」推荐卡(clay 渐变 zap + 推荐胶囊,默认选中);
免费额度卡(剩余分钟+进度条 ≤3 分钟切 warning + 看广告解锁变绿)。
- Tab 左右滑动切换(手势竞技场仲裁,子页滚动不误触发,200ms 方向感知滑入)。
- iPad/宽屏 ≥900 LayoutBuilder 切侧栏分栏(导航行高 ≥48,连接页双栏/节点双列网格),
复用同一批原子组件,不 fork 页面。
- 语义 token 零硬编码;文案全部走 l10n;套餐数字对齐 §7;无支付表单/emoji 国旗。
- CI 红线词扫描扩展到 client/lib;新增 Flutter analyze+test CI 任务。
- 测试:连接状态机/额度/节点单测、连接键三态与卡片组件测试、
golden(连接键三态/推荐卡/额度卡 × 明暗)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-13 14:32:36 +08:00
wangjia
bd8f974a25
feat(M6): 控制面联调 — mock connect server + 客户端 ConnectApi 透传
...
tsk_nuoKSM4Vt-zK
## 服务端(server/cmd/mockserver)
- `main.go`(79 行):独立 mock HTTP server,实现 POST /v1/nodes/:id/connect
- 路径/请求体/响应体字段名与 §3.1 契约逐字一致
- Bearer token 鉴权(-token 参数,空值跳过,不入库)
- 缺少 device_id → 400;未授权 → 401;非 POST → 405
- 返回完整 sing-box config JSON(tun + REALITY/Hy2 outbound + urltest + route/dns)
- 注:mock 联调;待 #5/#6 真实 connect 接口就绪后替换
- `main_test.go`:6 项单测,覆盖 §3.1 结构校验、auth、method、path
## 客户端(client/)
- `lib/services/connect_api.dart`:ConnectApi 类
- fetchConfig(nodeId, deviceId) → 原始响应体字符串(不做任何修改)
- 错误路径:HTTP 非 200 / 超时 / 非法 JSON → ConnectApiException(含双语 message)
- `lib/services/vpn_bridge.dart`:VpnBridge stub(M6 联调,libbox 绑定待 11C)
- start(configJson) 原样存储,不修改;stop() 清空
- `lib/widgets/home_shell.dart`:_toggle/_pick 替换为真实 API 流程
- ConnectApi.fetchConfig → VpnBridge.start(透传,无中间变换)
- 错误路径:ConnectApiException → SnackBar,status 回 off,无残留半开隧道
- API URL/token/deviceId 由 --dart-define 注入(不入库)
- `lib/widgets/server_tile.dart`:ServerInfo 新增 nodeId 字段
- `pubspec.yaml`:新增 http: ^1.2.1 依赖
- `test/connect_passthrough_test.dart`:4 项透传断言单测
- 核心:fetchConfig 返回字符串 === VpnBridge.start 接收字符串(逐字节相等)
- 空格/格式原样保留(不经 jsonEncode 重序列化)
- HTTP 错误、非法 JSON 错误路径覆盖
## 运行方式(M6 联调)
```
# 启动 mock server(无 auth)
go run ./server/cmd/mockserver -addr :8081
# 启动客户端(指向 mock server)
flutter run \
--dart-define=PANGOLIN_API_URL=http://localhost:8081 \
--dart-define=PANGOLIN_API_TOKEN=dev-mock-token \
--dart-define=PANGOLIN_DEVICE_ID=demo-device-001
```
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 14:16:29 +08:00
wangjia
526e7f2f33
feat(tsk_iRa5iBC4v7Tu): Flutter 客户端工程搭建(演示态)
...
基于 design/flutter/ 起步包在 client/ 下建立 Flutter 工程:
- pubspec.yaml:flutter_svg / lucide_icons / google_fonts 依赖;
SVG 资产注册;字体由 google_fonts 运行时加载,无需本地 ttf
- lib/pangolin_theme.dart:完整设计令牌(色阶 / 间距 / 圆角 /
动效 / 文字阶),PangolinText 改用 GoogleFonts getter,
PangolinTheme.light / .dark 开箱即用
- lib/main.dart:runApp + 明暗主题 + 登录 → 引导 → 主框架 RootFlow
- lib/widgets/:全套组件雏形
pangolin_icons Lucide 图标映射
pangolin_button 胶囊按钮四态
country_code 国家码块 + 信号条
status_pill 色点胶囊
connect_button 核心连接键三态(off/connecting/on + 动画)
server_tile 服务器列表行
plan_card 套餐卡(专业版渐变高亮)
auth_screen 登录 / 注册(邮箱验证码 + 设密码)
onboarding_screen 首次引导 PageView(3 屏可滑动 + 进度点)
home_shell 底部 4 Tab(连接/节点/统计/账户 + 状态机)
account_screens 套餐选择 / 设备管理 / 兑换 / 联系我们
pangolin_logo PangolinMark / BrandLockup / AppIcon(SVG)
- assets/:logo-mark / logo-mark-white / logo-wordmark / app-icon(SVG)
- android/:Kotlin 主 Activity + Manifest + Gradle 配置
- ios/:Runner.xcodeproj + xcscheme + Podfile + AppDelegate + storyboard
运行方式(cd client/):
flutter pub get && flutter run
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 02:15:42 +08:00