// 设置页面 — 主题切换 + 关于 + 隐私政策 import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:nuanji_app/core/theme/app_colors.dart'; import 'package:nuanji_app/core/theme/app_radius.dart'; import 'package:nuanji_app/features/profile/bloc/settings_bloc.dart'; /// 设置页面 class SettingsPage extends StatelessWidget { const SettingsPage({super.key}); @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; return Scaffold( appBar: AppBar(title: const Text('设置')), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ===== 外观设置 ===== _SectionHeader(title: '外观', theme: theme), const SizedBox(height: 8), const _ThemeSelectorCard(), const SizedBox(height: 24), // ===== 关于 ===== _SectionHeader(title: '关于', theme: theme), const SizedBox(height: 8), _AboutCard(colorScheme: colorScheme), const SizedBox(height: 24), // ===== 法律信息 ===== _SectionHeader(title: '法律信息', theme: theme), const SizedBox(height: 8), _LegalCard(colorScheme: colorScheme), const SizedBox(height: 32), // ===== 底部版本号 ===== Center( child: Text( '暖记 v1.0.0 (Phase 1)', style: theme.textTheme.bodySmall?.copyWith( color: colorScheme.onSurface.withValues(alpha: 0.4), ), ), ), const SizedBox(height: 16), ], ), ), ); } } // ===== 分区标题 ===== class _SectionHeader extends StatelessWidget { const _SectionHeader({required this.title, required this.theme}); final String title; final ThemeData theme; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(left: 4), child: Text( title, style: theme.textTheme.titleSmall?.copyWith( color: theme.colorScheme.primary, fontWeight: FontWeight.w600, ), ), ); } } // ===== 主题选择器卡片 ===== class _ThemeSelectorCard extends StatelessWidget { const _ThemeSelectorCard(); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final settingsBloc = context.read(); return Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: AppRadius.lgBorder, side: BorderSide(color: colorScheme.outlineVariant), ), child: Padding( padding: const EdgeInsets.all(20), child: Column( children: [ // 标题行 Row( children: [ Icon(Icons.palette_outlined, color: colorScheme.primary), const SizedBox(width: 12), Text( '主题模式', style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w600, ), ), ], ), const SizedBox(height: 16), // 三选一 SegmentedButton(实时响应主题切换) ListenableBuilder( listenable: settingsBloc, builder: (context, _) { final current = settingsBloc.state.themeMode; return SegmentedButton( segments: const [ ButtonSegment( value: ThemeMode.system, icon: Icon(Icons.brightness_auto), label: Text('跟随系统'), ), ButtonSegment( value: ThemeMode.light, icon: Icon(Icons.light_mode), label: Text('浅色'), ), ButtonSegment( value: ThemeMode.dark, icon: Icon(Icons.dark_mode), label: Text('深色'), ), ], selected: {current}, onSelectionChanged: (modes) { settingsBloc.changeTheme(modes.first); }, ); }, ), ], ), ), ); } } // ===== 关于卡片 ===== class _AboutCard extends StatelessWidget { const _AboutCard({required this.colorScheme}); final ColorScheme colorScheme; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: AppRadius.lgBorder, side: BorderSide(color: colorScheme.outlineVariant), ), child: Column( children: [ // 应用 Logo 信息 Padding( padding: const EdgeInsets.all(20), child: Row( children: [ Container( width: 56, height: 56, decoration: BoxDecoration( color: AppColors.accent.withValues(alpha: 0.15), borderRadius: AppRadius.mdBorder, ), alignment: Alignment.center, child: const Text('📝', style: TextStyle(fontSize: 28)), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '暖记', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 2), Text( '温暖治愈的手账日记', style: theme.textTheme.bodySmall?.copyWith( color: colorScheme.onSurface.withValues(alpha: 0.6), ), ), ], ), ), ], ), ), const Divider(height: 1, indent: 20, endIndent: 20), _SettingsTile( icon: Icons.info_outline, iconColor: colorScheme.primary, title: '版本信息', subtitle: 'v1.0.0 · Phase 1', onTap: () => _showAboutDialog(context), ), _SettingsTile( icon: Icons.favorite_outline, iconColor: AppColors.accent, title: '给暖记评分', subtitle: '你的鼓励是我们前进的动力', onTap: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('应用商店评分功能即将上线')), ); }, ), _SettingsTile( icon: Icons.feedback_outlined, iconColor: AppColors.secondary, title: '意见反馈', subtitle: '告诉我们你的想法', onTap: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('反馈功能即将上线')), ); }, ), ], ), ); } void _showAboutDialog(BuildContext context) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Row( children: [ Text('📝', style: TextStyle(fontSize: 24)), SizedBox(width: 8), Text('暖记'), ], ), content: const Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('温暖治愈的手账日记 App'), SizedBox(height: 8), Text('版本: v1.0.0 (Phase 1)'), SizedBox(height: 8), Text('面向小学生首发,以手写/涂鸦为核心输入方式。'), SizedBox(height: 16), Text( '© 2026 暖记团队', style: TextStyle(fontSize: 12), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('确定'), ), ], ), ); } } // ===== 法律信息卡片 ===== class _LegalCard extends StatelessWidget { const _LegalCard({required this.colorScheme}); final ColorScheme colorScheme; @override Widget build(BuildContext context) { return Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: AppRadius.lgBorder, side: BorderSide(color: colorScheme.outlineVariant), ), child: Column( children: [ _SettingsTile( icon: Icons.shield_outlined, iconColor: colorScheme.primary, title: '隐私政策', subtitle: '了解我们如何保护你的数据', onTap: () => _showLegalDialog(context, page: _LegalPage.privacy), ), _SettingsTile( icon: Icons.description_outlined, iconColor: AppColors.tertiary, title: '用户协议', subtitle: '使用条款和服务说明', onTap: () => _showLegalDialog(context, page: _LegalPage.terms), ), _SettingsTile( icon: Icons.child_care_outlined, iconColor: AppColors.secondary, title: '儿童隐私保护', subtitle: '我们如何保护未成年人的权益', subtitleColor: AppColors.secondary, onTap: () => _showLegalDialog(context, page: _LegalPage.child), ), ], ), ); } void _showLegalDialog(BuildContext context, {required _LegalPage page}) { final (title, icon, content) = switch (page) { _LegalPage.privacy => ( '隐私政策', '🔒', ''' 暖记隐私政策(最后更新:2026年6月) 一、我们收集的信息 • 昵称和年级(不收集真实姓名和身份证号) • 日记内容(仅存储在你的设备上,云端加密存储) • 心情记录(仅用于统计分析) 二、信息使用 • 提供日记手账服务 • 班级互动功能 • 个性化体验 三、信息保护 • 所有数据传输采用 TLS 加密 • 云端数据采用 AES-256-GCM 加密 • 本地数据采用设备级加密 四、你的权利 • 查阅、更正你的个人数据 • 要求删除所有数据 • 导出你的数据 五、儿童保护 • 未满 14 岁需家长授权 • 最小必要数据原则 • 家长可管理孩子的数据 如有疑问,请联系:privacy@nuanji.app''', ), _LegalPage.terms => ( '用户协议', '📋', ''' 暖记用户协议(最后更新:2026年6月) 一、服务说明 暖记是一款面向小学生的手账日记应用,提供日记书写、心情记录、班级互动等功能。 二、用户行为规范 • 尊重他人,友善交流 • 不发布不当内容 • 遵守学校规章制度 三、内容归属 • 用户创作的日记内容归用户所有 • 暖记不会在未经授权的情况下使用用户内容 四、免责声明 • 因不可抗力导致的服务中断不承担责任 • 用户因不当使用导致的损失自行承担 五、协议修改 • 修改协议将提前通知用户 • 继续使用视为同意修改后的协议''', ), _LegalPage.child => ( '儿童隐私保护', '👶', ''' 暖记特别重视儿童个人信息保护,严格遵守《儿童个人信息网络保护规定》。 一、家长授权 • 未满 14 周岁的用户需家长同意后方可使用 • 注册时需完成家长授权验证 • 家长可随时撤回授权 二、最小必要原则 • 仅收集提供服务必需的最少数据 • 不收集真实姓名、身份证号等敏感信息 • 不进行用户画像和个性化广告推送 三、数据安全 • 采用多重加密保护儿童数据 • 严格限制数据访问权限 • 定期进行安全审计 四、家长权利 • 查阅孩子的所有数据 • 要求更正错误数据 • 要求删除孩子数据(30天内完成) • 导出孩子数据 五、账号注销 • 注销后30天内删除所有关联数据 • 包括日记、贴纸、成就等 • 删除后不可恢复 六、内容安全 • 自动过滤敏感内容 • 老师可审核班级内容 • 举报机制保护儿童安全 如需联系:child-safety@nuanji.app''', ), }; showDialog( context: context, builder: (ctx) => AlertDialog( title: Row( children: [ Text(icon, style: const TextStyle(fontSize: 24)), const SizedBox(width: 8), Expanded(child: Text(title)), ], ), content: SingleChildScrollView( child: Text( content.trim(), style: const TextStyle(fontSize: 13, height: 1.6), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('我知道了'), ), ], ), ); } } enum _LegalPage { privacy, terms, child } // ===== 通用设置列表项 ===== class _SettingsTile extends StatelessWidget { const _SettingsTile({ required this.icon, required this.iconColor, required this.title, required this.onTap, this.subtitle, this.subtitleColor, }); final IconData icon; final Color iconColor; final String title; final String? subtitle; final Color? subtitleColor; final VoidCallback onTap; @override Widget build(BuildContext context) { final theme = Theme.of(context); return ListTile( leading: Icon(icon, color: iconColor), title: Text(title, style: theme.textTheme.bodyMedium), subtitle: subtitle != null ? Text( subtitle!, style: theme.textTheme.bodySmall?.copyWith( color: subtitleColor ?? theme.colorScheme.onSurface.withValues(alpha: 0.5), ), ) : null, trailing: const Icon(Icons.chevron_right, size: 20), onTap: onTap, contentPadding: const EdgeInsets.symmetric(horizontal: 20), ); } }