feat(client): 节点列表防误触 — 已连接时切换节点先弹确认
未连接(off)点节点直接选→跳连接页(无破坏性,不弹框);已连接/连接中点其他 节点会断开重连,先弹确认框(标题含目标节点名),取消则维持当前连接。新增 nodeSwitchTitle/Body/Confirm 三条文案 + node_connect_confirm_test 覆盖 off/on 两路。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,43 @@ class _NodesPageState extends ConsumerState<NodesPage> {
|
||||
widget.onPicked();
|
||||
}
|
||||
|
||||
// 点节点:未连接(off)直接选→跳连接页,无破坏性;已连接/连接中切换会断开重连,
|
||||
// 弹确认防误触(误碰节点把当前连接切走)。
|
||||
void _onTapNode(Node n) {
|
||||
final phase = ref.read(connectionProvider).phase;
|
||||
if (phase == VpnPhase.off) {
|
||||
_pick(n.code);
|
||||
return;
|
||||
}
|
||||
_confirmSwitch(n);
|
||||
}
|
||||
|
||||
Future<void> _confirmSwitch(Node n) async {
|
||||
final c = context.pangolin;
|
||||
final t = ref.read(appTextProvider);
|
||||
final ok = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
backgroundColor: c.surface,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(PangolinRadius.xl)),
|
||||
title: Text(t.nodeSwitchTitle(n.localizedName(t.lang)),
|
||||
style: PangolinText.body.copyWith(color: c.fg1, fontWeight: FontWeight.w700)),
|
||||
content: Text(t.nodeSwitchBody, style: PangolinText.sm.copyWith(color: c.fg2, height: 1.5)),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, false),
|
||||
child: Text(t.devCancel, style: PangolinText.sm.copyWith(color: c.fg2, fontWeight: FontWeight.w600)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: Text(t.nodeSwitchConfirm, style: PangolinText.sm.copyWith(color: c.accent, fontWeight: FontWeight.w700)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (ok == true) _pick(n.code);
|
||||
}
|
||||
|
||||
List<Node> _filtered(List<Node> nodes) {
|
||||
if (_q.trim().isEmpty) return nodes;
|
||||
final q = _q.toLowerCase();
|
||||
@@ -95,7 +132,7 @@ class _NodesPageState extends ConsumerState<NodesPage> {
|
||||
childAspectRatio: 4.4,
|
||||
children: [
|
||||
for (final n in nodes)
|
||||
_NodeGridTile(node: n, lang: t.lang, active: !smart && n.code == selected, onTap: () => _pick(n.code)),
|
||||
_NodeGridTile(node: n, lang: t.lang, active: !smart && n.code == selected, onTap: () => _onTapNode(n)),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -133,7 +170,7 @@ class _NodesPageState extends ConsumerState<NodesPage> {
|
||||
node: nodes[i],
|
||||
lang: t.lang,
|
||||
active: !smart && nodes[i].code == selected,
|
||||
onTap: () => _pick(nodes[i].code),
|
||||
onTap: () => _onTapNode(nodes[i]),
|
||||
),
|
||||
if (i < nodes.length - 1) Divider(height: 1, thickness: 1, color: c.border),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user