rtc_prd/airhub_app/lib/pages/profile/settings_page.dart
2026-02-13 16:15:25 +08:00

374 lines
12 KiB
Dart

import 'package:flutter/foundation.dart' show defaultTargetPlatform, TargetPlatform;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:airhub_app/theme/design_tokens.dart';
import 'package:airhub_app/widgets/animated_gradient_background.dart';
import 'package:airhub_app/widgets/ios_toast.dart';
import 'package:airhub_app/pages/profile/settings_sub_pages.dart';
import 'package:airhub_app/pages/product_selection_page.dart';
import 'package:airhub_app/widgets/glass_dialog.dart';
import 'package:airhub_app/features/auth/presentation/controllers/auth_controller.dart';
import 'package:airhub_app/features/system/data/datasources/system_remote_data_source.dart';
import 'package:airhub_app/features/device/presentation/controllers/device_controller.dart';
class SettingsPage extends ConsumerStatefulWidget {
const SettingsPage({super.key});
@override
ConsumerState<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends ConsumerState<SettingsPage> {
bool _notificationEnabled = true;
@override
Widget build(BuildContext context) {
// watch 保持 provider 存活,确保硬件信息可用
ref.watch(deviceControllerProvider);
return Scaffold(
backgroundColor: Colors.transparent,
body: Stack(
children: [
const AnimatedGradientBackground(),
Column(
children: [
_buildHeader(context),
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.only(
top: 20,
left: AppSpacing.lg,
right: AppSpacing.lg,
bottom: 40 + MediaQuery.of(context).padding.bottom,
),
child: Column(
children: [
_buildSection('账号安全', [
_buildItem(
'📱',
'绑定手机',
value: '138****3069',
onTap: () => _showMessage('绑定手机', '138****3069'),
),
_buildItem(
'🔐',
'账号密码',
onTap: () => _showMessage('提示', '密码修改功能开发中...'),
),
_buildItem(
'📦',
'设备管理',
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const ProductSelectionPage(),
),
),
),
_buildItem(
'🔔',
'推送通知权限',
value: _notificationEnabled ? '已开启' : '已关闭',
onTap: _toggleNotification,
),
]),
const SizedBox(height: 24),
_buildSection('关于', [
_buildItem(
'🔄',
'检查更新',
value: '当前 1.0.0',
onTap: _checkUpdate,
),
_buildItem(
'💻',
'硬件信息',
onTap: _showHardwareInfo,
),
_buildItem(
'📄',
'用户协议',
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const AgreementPage(),
),
),
),
_buildItem(
'🔒',
'隐私政策',
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const PrivacyPage(),
),
),
),
_buildItem(
'📋',
'个人信息收集清单',
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const CollectionListPage(),
),
),
),
_buildItem(
'🔗',
'第三方信息共享清单',
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const SharingListPage(),
),
),
),
]),
const SizedBox(height: 24),
_buildSection(null, [
_buildItem(
'🚪',
'退出登录',
isDanger: true,
onTap: _showLogoutDialog,
),
_buildItem(
'⚠️',
'账号注销',
isDanger: true,
isLast: true,
onTap: _showDeleteAccountDialog,
),
]),
const SizedBox(height: 32),
const Text(
'Airhub v1.0.0\n© 2025 Airhub Team',
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.textSecondary,
fontSize: 13,
),
),
],
),
),
),
],
),
],
),
);
}
Widget _buildHeader(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top + 20,
left: AppSpacing.lg,
right: AppSpacing.lg,
bottom: AppSpacing.md,
),
child: Row(
children: [
GestureDetector(
onTap: () => Navigator.pop(context),
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.6),
borderRadius: BorderRadius.circular(12),
),
child: const Icon(
Icons.arrow_back_ios_new,
color: AppColors.textPrimary,
size: 18,
),
),
),
Expanded(
child: Center(child: Text('设置', style: AppTextStyles.title)),
),
const SizedBox(width: 40), // Balance
],
),
);
}
Widget _buildSection(String? title, List<Widget> children) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (title != null)
Padding(
padding: const EdgeInsets.only(left: 4, bottom: 8),
child: Text(
title,
style: const TextStyle(
color: AppColors.sectionTitle,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
),
Container(
decoration: BoxDecoration(
color: AppColors.cardSurface,
borderRadius: BorderRadius.circular(16),
boxShadow: const [AppShadows.card],
),
child: Column(children: children),
),
],
);
}
Widget _buildItem(
String icon,
String text, {
String? value,
bool isDanger = false,
bool isLast = false,
VoidCallback? onTap,
}) {
return InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
decoration: !isLast
? const BoxDecoration(
border: Border(bottom: BorderSide(color: AppColors.divider)),
)
: null,
child: Row(
children: [
SizedBox(
width: 24,
child: Text(icon, style: const TextStyle(fontSize: 18)),
),
const SizedBox(width: 12),
Expanded(
child: Text(
text,
style: TextStyle(
fontSize: 16,
color: isDanger ? AppColors.danger : AppColors.textPrimary,
),
),
),
if (value != null) ...[
Text(
value,
style: const TextStyle(
fontSize: 14,
color: AppColors.textSecondary,
),
),
const SizedBox(width: 8),
],
const Icon(
Icons.chevron_right,
color: AppColors.textHint,
size: 18,
),
],
),
),
);
}
void _toggleNotification() {
setState(() => _notificationEnabled = !_notificationEnabled);
}
void _showMessage(String title, String desc) {
showGlassDialog(
context: context,
title: title,
description: desc,
confirmText: '确定',
onConfirm: () => Navigator.pop(context),
);
}
void _showHardwareInfo() {
final devicesAsync = ref.read(deviceControllerProvider);
final devices = devicesAsync.value ?? [];
final firstDevice = devices.isNotEmpty ? devices.first : null;
final deviceModel = firstDevice?.device.deviceTypeInfo?.name ?? '未知';
final sn = firstDevice?.device.sn ?? '未知';
final firmwareVersion = firstDevice?.device.firmwareVersion;
final fwDisplay = (firmwareVersion != null && firmwareVersion.isNotEmpty)
? firmwareVersion
: '等待设备上报';
_showMessage(
'硬件信息',
'设备型号: $deviceModel\nSN码: $sn\n固件版本: $fwDisplay',
);
}
Future<void> _checkUpdate() async {
try {
final ds = ref.read(systemRemoteDataSourceProvider);
final platform = defaultTargetPlatform == TargetPlatform.iOS ? 'ios' : 'android';
final result = await ds.checkVersion(platform, '1.0.0');
if (!mounted) return;
final needUpdate = result['need_update'] as bool? ?? false;
if (needUpdate) {
final latestVersion = result['latest_version'] ?? '';
final description = result['description'] ?? '有新版本可用';
_showMessage('发现新版本 v$latestVersion', description as String);
} else {
_showMessage('检查更新', '当前已是最新版本 v1.0.0');
}
} catch (_) {
if (mounted) {
AppToast.show(context, '检查更新失败,请稍后重试', isError: true);
}
}
}
void _showLogoutDialog() {
showGlassDialog(
context: context,
title: '确认退出登录?',
description: '退出后需要重新登录才能使用。',
cancelText: '取消',
confirmText: '退出',
isDanger: true,
onConfirm: () async {
Navigator.pop(context); // Close dialog
await ref.read(authControllerProvider.notifier).logout();
if (mounted) context.go('/login');
},
);
}
void _showDeleteAccountDialog() {
showGlassDialog(
context: context,
title: '确认注销账号?',
description: '账号注销后所有数据将被永久删除,且无法恢复。',
cancelText: '取消',
confirmText: '确认注销',
isDanger: true,
onConfirm: () async {
Navigator.pop(context);
final success =
await ref.read(authControllerProvider.notifier).deleteAccount();
if (!mounted) return;
if (success) {
context.go('/login');
} else {
AppToast.show(context, '注销失败,请稍后重试', isError: true);
}
},
);
}
}