jjsos_autosos_flutter/lib/pages/me/setting_page.dart

283 lines
8.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<SettingPage> createState() => _SettingPageState();
}
class _SettingPageState extends ConsumerState<SettingPage> {
bool _push = true;
bool _sound = true;
bool _bg = true;
String _version = '';
String _cid = '';
@override
void initState() {
super.initState();
_load();
}
Future<void> _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<void> _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<void> _clearCache() async {
final ok = await showDialog<bool>(
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<void> _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<void>(
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<void> _logout() async {
final ok = await showDialog<bool>(
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,
),
),
);
}