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>
This commit is contained in:
wangjia
2026-06-29 19:31:01 +08:00
parent f2891ff2f9
commit e89f3de748
10 changed files with 113 additions and 7 deletions
+1 -1
View File
@@ -262,7 +262,7 @@ class ConnectionController extends StateNotifier<ConnectionState> {
final smart = _ref.read(selectedNodeCodeProvider) == kSmartNodeCode;
final altCode = smart ? _pickAlternativeCode(_ref.read(effectiveNodeProvider).code) : null;
if (smart && altCode != null) {
_ref.read(selectedNodeCodeProvider.notifier).state = altCode;
_ref.read(selectedNodeCodeProvider.notifier).select(altCode);
await _disconnect();
await _connect();
// 重连进行中给出「已自动切换」提示(connecting 态显示,连上后随 copyWith 清除)。
+36 -1
View File
@@ -7,6 +7,7 @@ import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import '../models/node.dart';
import '../services/api_config.dart';
@@ -96,8 +97,42 @@ final nodesProvider =
AsyncNotifierProvider<NodesNotifier, List<Node>>(NodesNotifier.new);
// ── 当前选中的节点 code'AUTO' 表示智能选择(默认)─────────────────
//
// 持久化:用户的选择(智能 / 具体节点)跨重启保存,启动时恢复,供自动连接复用上次选择。
const _kSelectedNode = 'selected_node_code';
final selectedNodeCodeProvider = StateProvider<String>((ref) => kSmartNodeCode);
class SelectedNodeController extends StateNotifier<String> {
SelectedNodeController() : super(kSmartNodeCode) {
_load();
}
/// 是否已从持久化恢复完(自动连接要等它 true 再读,避免用到未恢复的默认值)。
bool loaded = false;
Future<void> _load() async {
try {
final p = await SharedPreferences.getInstance();
if (!mounted) return;
final v = p.getString(_kSelectedNode);
if (v != null && v.isNotEmpty) state = v;
} catch (_) {
// 测试/无平台:保留默认(智能)。
}
loaded = true;
}
/// 选择节点(智能传 kSmartNodeCode)并持久化。
Future<void> select(String code) async {
state = code;
try {
final p = await SharedPreferences.getInstance();
await p.setString(_kSelectedNode, code);
} catch (_) {}
}
}
final selectedNodeCodeProvider =
StateNotifierProvider<SelectedNodeController, String>((ref) => SelectedNodeController());
/// 是否处于智能选择。
final isSmartSelectProvider = Provider<bool>(