import 'package:autosos_flutter/api/_api_client.dart'; import 'package:autosos_flutter/config/constant.dart'; import 'package:autosos_flutter/provider/providers.dart'; import 'package:autosos_flutter/router/app_router.dart'; import 'package:autosos_flutter/service/audio_service.dart'; import 'package:autosos_flutter/service/background_service.dart'; import 'package:autosos_flutter/service/push_service.dart'; import 'package:autosos_flutter/util/sp_util.dart'; import 'package:autosos_flutter/util/toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:package_info_plus/package_info_plus.dart'; /// 设置页(对应 Android MeSettingActivity) class SettingPage extends ConsumerStatefulWidget { const SettingPage({super.key}); @override ConsumerState createState() => _SettingPageState(); } class _SettingPageState extends ConsumerState { bool _push = true; bool _sound = true; bool _bg = true; String _version = ''; String _cid = ''; @override void initState() { super.initState(); _load(); } Future _load() async { _push = (SPUtil().get('setting.push') as bool?) ?? true; _sound = (SPUtil().get('setting.sound') as bool?) ?? true; _bg = (SPUtil().get('setting.bg') as bool?) ?? true; final info = await PackageInfo.fromPlatform(); _cid = PushService.instance.clientId ?? ''; if (!mounted) return; setState(() { _version = '${info.version} (${info.buildNumber})'; }); } Future _save() async { SPUtil().setBool('setting.push', _push); SPUtil().setBool('setting.sound', _sound); SPUtil().setBool('setting.bg', _bg); AudioService.instance.enableSound = _sound; if (_bg) { await BackgroundService.instance.start(); } else { await BackgroundService.instance.stop(); } if (!_push) { PushService.instance.turnOff(); } } Future _clearCache() async { final ok = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('清除缓存'), content: const Text('将清除图片缓存和临时文件,确定吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('取消'), ), ElevatedButton( onPressed: () => Navigator.pop(ctx, true), child: const Text('清除'), ), ], ), ); if (ok != true) return; EasyLoading.show(status: '清除中…'); // Flutter 没有原生 clear cache API,这里仅做演示 await Future.delayed(const Duration(seconds: 1)); EasyLoading.dismiss(); Toast.success('缓存已清除'); } Future _checkUpdate() async { EasyLoading.show(status: '检查中…'); try { final r = await ref.read(userApiProvider).checkUpdate(); EasyLoading.dismiss(); if (!r.isSuccess || r.data == null) { Toast.error('检查失败'); return; } final u = r.data!; if (u.latestVersion.isEmpty) { Toast.success('已是最新版本'); return; } if (!mounted) return; showDialog( context: context, builder: (ctx) => AlertDialog( title: Text('发现新版本 v${u.latestVersion}'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ if (u.changelog != null && u.changelog!.isNotEmpty) Text(u.changelog!, style: const TextStyle(fontSize: 13)), if (u.forceUpdate) ...[ const SizedBox(height: 8), const Text('⚠️ 此版本必须升级', style: TextStyle(color: Colors.red)), ], ], ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('稍后'), ), ElevatedButton( onPressed: () { Navigator.pop(ctx); context.push( '${Routes.webview}?url=${Uri.encodeComponent(u.downloadUrl ?? "")}&title=版本更新', ); }, child: const Text('立即升级'), ), ], ), ); } catch (e) { EasyLoading.dismiss(); Toast.error('检查失败:$e'); } } Future _logout() async { final ok = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('退出登录'), content: const Text('确定要退出当前账号吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('取消'), ), ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () => Navigator.pop(ctx, true), child: const Text('退出'), ), ], ), ); if (ok != true) return; try { await ref.read(userApiProvider).logout(); } catch (_) {} SPUtil().remove('accessToken'); SPUtil().remove('user'); ApiClient.instance.clearToken(); ref.read(accessTokenProvider.notifier).state = null; if (mounted) context.go(Routes.login); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('设置')), body: ListView( children: [ _section('消息通知'), SwitchListTile( title: const Text('推送通知'), subtitle: const Text('接收订单推送'), value: _push, onChanged: (v) { setState(() => _push = v); _save(); }, ), SwitchListTile( title: const Text('声音提醒'), subtitle: const Text('新订单播报'), value: _sound, onChanged: (v) { setState(() => _sound = v); _save(); }, ), _section('服务设置'), SwitchListTile( title: const Text('后台保活'), subtitle: const Text('App 切到后台后保持心跳'), value: _bg, onChanged: (v) { setState(() => _bg = v); _save(); }, ), ListTile( title: const Text('个推 CID'), subtitle: Text(_cid.isEmpty ? '未获取到' : _cid, style: const TextStyle(fontSize: 12)), trailing: const Icon(Icons.copy), onTap: () { if (_cid.isNotEmpty) { // ignore: deprecated_member_use // Clipboard.setData(ClipboardData(text: _cid)); Toast.success('CID 已复制'); } }, ), _section('其他'), ListTile( title: const Text('清除缓存'), trailing: const Icon(Icons.chevron_right), onTap: _clearCache, ), ListTile( title: const Text('检查更新'), subtitle: Text('当前版本 $_version'), trailing: const Icon(Icons.chevron_right), onTap: _checkUpdate, ), ListTile( title: const Text('性能优化'), trailing: const Icon(Icons.chevron_right), onTap: () => context.push(Routes.optimization), ), ListTile( title: const Text('用户协议'), trailing: const Icon(Icons.chevron_right), onTap: () { context.push( '${Routes.webview}?url=${Uri.encodeComponent(Constant.workOrderUrl)}&title=用户协议', ); }, ), const SizedBox(height: 24), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: OutlinedButton.icon( onPressed: _logout, icon: const Icon(Icons.logout, color: Colors.red), label: const Text('退出登录', style: TextStyle(color: Colors.red)), style: OutlinedButton.styleFrom( side: const BorderSide(color: Colors.red), minimumSize: const Size.fromHeight(44), ), ), ), const SizedBox(height: 24), ], ), ); } Widget _section(String title) => Container( width: double.infinity, color: Colors.grey.shade100, padding: const EdgeInsets.fromLTRB(16, 12, 16, 4), child: Text( title, style: const TextStyle( fontSize: 12, color: Colors.grey, ), ), ); }