feat(client): settings 完整版(开关组) + 联系/设置整页 golden

- settings_page 补全对照 dapp.jsx DSettings: 功能开关组(开机自启/智能分流/
  Kill Switch, 本地演示态) + 配置组补检查更新行; 改 ConsumerStatefulWidget 持开关态
- l10n 新增 autostart/smartRoute/killSwitch(+Sub) + checkUpdate(中英)
- desktop 整页 golden 补 联系页 + 设置页(凑齐可截 5 页: 节点/统计/账户/联系/设置)

测试: flutter test 81 通过(+2 golden), analyze 0 error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-16 12:22:28 +08:00
parent 22e4eb1ead
commit 4886416e8b
7 changed files with 61 additions and 7 deletions
+24 -7
View File
@@ -10,17 +10,30 @@ import '../pangolin_theme.dart';
import '../state/app_providers.dart';
import '../widgets/pangolin_icons.dart';
class SettingsPage extends ConsumerWidget {
class SettingsPage extends ConsumerStatefulWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
ConsumerState<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends ConsumerState<SettingsPage> {
// 本地演示态(暂无后端绑定),默认开,对照 dapp.jsx DSettings。
bool _autostart = true;
bool _smartRoute = true;
bool _killSwitch = true;
@override
Widget build(BuildContext context) {
final c = context.pangolin;
final t = ref.watch(appTextProvider);
final lang = ref.watch(localeProvider);
final mode = ref.watch(themeModeProvider);
final isDark = mode == ThemeMode.dark;
Widget sw(bool v, ValueChanged<bool> on) =>
Switch(value: v, activeThumbColor: c.accent, onChanged: on);
return SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(32, 16, 32, 24),
child: ConstrainedBox(
@@ -32,19 +45,23 @@ class SettingsPage extends ConsumerWidget {
right: Icon(PangolinIcons.chevronRight, size: 18, color: c.fg3), onTap: () {}),
]),
const SizedBox(height: 16),
// 功能开关组
_Card(children: [
_Row(title: t.autostart, sub: t.autostartSub, right: sw(_autostart, (v) => setState(() => _autostart = v))),
_Row(title: t.smartRoute, sub: t.smartRouteSub, right: sw(_smartRoute, (v) => setState(() => _smartRoute = v))),
_Row(title: t.killSwitch, sub: t.killSwitchSub, last: true, right: sw(_killSwitch, (v) => setState(() => _killSwitch = v))),
]),
const SizedBox(height: 16),
// 配置组
_Card(children: [
_Row(title: t.language, right: _LangSwitch(lang: lang, onPick: (l) => ref.read(localeProvider.notifier).state = l)),
_Row(
title: t.darkAppearance,
sub: isDark ? t.stateOn : t.followLight,
right: Switch(
value: isDark,
activeThumbColor: c.accent,
onChanged: (v) => ref.read(themeModeProvider.notifier).state = v ? ThemeMode.dark : ThemeMode.light,
),
right: sw(isDark, (v) => ref.read(themeModeProvider.notifier).state = v ? ThemeMode.dark : ThemeMode.light),
),
_Row(title: t.protocol, right: Text('WireGuard', style: PangolinText.mono.copyWith(fontSize: 13, color: c.fg3))),
_Row(title: t.checkUpdate, right: Icon(PangolinIcons.chevronRight, size: 18, color: c.fg3), onTap: () {}),
_Row(title: 'Version', last: true, right: Text('v1.0.0', style: PangolinText.mono.copyWith(fontSize: 13, color: c.fg3))),
]),
]),