diff --git a/client/lib/l10n/app_text.dart b/client/lib/l10n/app_text.dart index d7102f0..124d6e4 100644 --- a/client/lib/l10n/app_text.dart +++ b/client/lib/l10n/app_text.dart @@ -86,6 +86,13 @@ abstract class AppText { String get followLight; String get protocol; String get settingsTitle; + String get autostart; + String get autostartSub; + String get smartRoute; + String get smartRouteSub; + String get killSwitch; + String get killSwitchSub; + String get checkUpdate; // ── 套餐选择 ── String get choosePlan; diff --git a/client/lib/l10n/strings_en.dart b/client/lib/l10n/strings_en.dart index 4d10361..604b87a 100644 --- a/client/lib/l10n/strings_en.dart +++ b/client/lib/l10n/strings_en.dart @@ -125,6 +125,20 @@ class StringsEn extends AppText { String get protocol => 'Protocol'; @override String get settingsTitle => 'Settings'; + @override + String get autostart => 'Launch at startup'; + @override + String get autostartSub => 'Run automatically on system start'; + @override + String get smartRoute => 'Smart routing'; + @override + String get smartRouteSub => 'Accelerate abroad, direct at home'; + @override + String get killSwitch => 'Kill Switch'; + @override + String get killSwitchSub => 'Block traffic if the link drops'; + @override + String get checkUpdate => 'Check for updates'; @override String get choosePlan => 'Choose plan'; diff --git a/client/lib/l10n/strings_zh.dart b/client/lib/l10n/strings_zh.dart index faa8bd1..0176beb 100644 --- a/client/lib/l10n/strings_zh.dart +++ b/client/lib/l10n/strings_zh.dart @@ -124,6 +124,20 @@ class StringsZh extends AppText { String get protocol => '协议'; @override String get settingsTitle => '设置'; + @override + String get autostart => '开机自启'; + @override + String get autostartSub => '系统启动时自动运行'; + @override + String get smartRoute => '智能分流'; + @override + String get smartRouteSub => '海外应用走加速,国内直连'; + @override + String get killSwitch => 'Kill Switch'; + @override + String get killSwitchSub => '断线时阻断网络,防止泄露'; + @override + String get checkUpdate => '检查更新'; @override String get choosePlan => '选择套餐'; diff --git a/client/lib/screens/settings_page.dart b/client/lib/screens/settings_page.dart index c0da853..2320115 100644 --- a/client/lib/screens/settings_page.dart +++ b/client/lib/screens/settings_page.dart @@ -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 createState() => _SettingsPageState(); +} + +class _SettingsPageState extends ConsumerState { + // 本地演示态(暂无后端绑定),默认开,对照 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 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))), ]), ]), diff --git a/client/test/golden/desktop_pages_golden_test.dart b/client/test/golden/desktop_pages_golden_test.dart index 3af5657..b2b7595 100644 --- a/client/test/golden/desktop_pages_golden_test.dart +++ b/client/test/golden/desktop_pages_golden_test.dart @@ -59,4 +59,6 @@ void main() { testWidgets('desktop 节点页', (t) => _shoot(t, NavView.servers, 'desktop_servers')); testWidgets('desktop 统计页', (t) => _shoot(t, NavView.stats, 'desktop_stats')); testWidgets('desktop 账户页', (t) => _shoot(t, NavView.account, 'desktop_account')); + testWidgets('desktop 联系页', (t) => _shoot(t, NavView.contact, 'desktop_contact')); + testWidgets('desktop 设置页', (t) => _shoot(t, NavView.settings, 'desktop_settings')); } diff --git a/client/test/golden/goldens/desktop_contact.png b/client/test/golden/goldens/desktop_contact.png new file mode 100644 index 0000000..5267132 Binary files /dev/null and b/client/test/golden/goldens/desktop_contact.png differ diff --git a/client/test/golden/goldens/desktop_settings.png b/client/test/golden/goldens/desktop_settings.png new file mode 100644 index 0000000..9caba9b Binary files /dev/null and b/client/test/golden/goldens/desktop_settings.png differ