// settings_page.dart — 设置(desktop 一级页) // // 对照 ui_kits/desktop/dapp.jsx DSettings(精简):兑换入口 + 语言段控 + // 深色外观 + 协议 + 版本。开关组(开机自启/智能分流/Kill-switch)待 l10n 补齐后加。 import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../l10n/app_text.dart'; import '../pangolin_theme.dart'; import '../state/app_providers.dart'; import '../widgets/pangolin_icons.dart'; class SettingsPage extends ConsumerStatefulWidget { const SettingsPage({super.key}); @override 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( constraints: const BoxConstraints(maxWidth: 560), child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 兑换入口 _Card(children: [ _Row(title: t.redeemEntry, sub: t.proMember, last: true, 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: 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))), ]), ]), ), ); } } class _Card extends StatelessWidget { const _Card({required this.children}); final List children; @override Widget build(BuildContext context) { final c = context.pangolin; return Container( decoration: BoxDecoration( color: c.surface, border: Border.all(color: c.border), borderRadius: BorderRadius.circular(PangolinRadius.lg), boxShadow: PangolinShadow.sm, ), clipBehavior: Clip.antiAlias, child: Column(children: children), ); } } class _Row extends StatelessWidget { const _Row({required this.title, this.sub, required this.right, this.last = false, this.onTap}); final String title; final String? sub; final Widget right; final bool last; final VoidCallback? onTap; @override Widget build(BuildContext context) { final c = context.pangolin; return InkWell( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14), decoration: BoxDecoration( border: last ? null : Border(bottom: BorderSide(color: c.border)), ), child: Row(children: [ Expanded( child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: PangolinText.body.copyWith(color: c.fg1, fontSize: 14, fontWeight: FontWeight.w500)), if (sub != null) Text(sub!, style: PangolinText.caption.copyWith(color: c.fg3)), ]), ), right, ]), ), ); } } class _LangSwitch extends StatelessWidget { const _LangSwitch({required this.lang, required this.onPick}); final AppLang lang; final ValueChanged onPick; @override Widget build(BuildContext context) { final c = context.pangolin; Widget seg(AppLang v, String label) { final on = lang == v; return GestureDetector( onTap: () => onPick(v), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), decoration: BoxDecoration( color: on ? c.accent : Colors.transparent, borderRadius: BorderRadius.circular(PangolinRadius.full), ), child: Text(label, style: PangolinText.caption.copyWith( color: on ? c.fgOnAccent : c.fg3, fontWeight: FontWeight.w700, fontSize: 12)), ), ); } return Container( padding: const EdgeInsets.all(3), decoration: BoxDecoration(color: c.bgSubtle, borderRadius: BorderRadius.circular(PangolinRadius.full)), child: Row(mainAxisSize: MainAxisSize.min, children: [seg(AppLang.zh, '中文'), seg(AppLang.en, 'EN')]), ); } }