diff --git a/lib/app/router/app_router.dart b/lib/app/router/app_router.dart index 4d21bba..17c6bb5 100644 --- a/lib/app/router/app_router.dart +++ b/lib/app/router/app_router.dart @@ -9,12 +9,17 @@ import '../../features/home/presentation/home_page.dart'; import '../../features/home/presentation/home_tab.dart'; import '../../features/messages/presentation/messages_tab.dart'; import '../../features/profile/presentation/profile_tab.dart'; +import '../../features/album/presentation/album_page.dart'; +import '../../features/alarm/presentation/alarm_page.dart'; +import '../../features/contacts/presentation/contacts_page.dart'; +import '../../features/apps/presentation/apps_page.dart'; /// 应用路由定义(GoRouter)。 /// /// - /splash 启动页,依据登录态决定首跳 /// - /login /register 认证流程 -/// - /home Shell 路由,承载底部 Tab(首页 / 消息 / 我的) +/// - /home Shell 路由,承载底部 Tab(首页 / 管理 / 我的) +/// - /album /alarm /contacts /apps 管理页横版菜单进入的子页面(无底部 Tab) GoRouter buildAppRouter() { return GoRouter( initialLocation: '/splash', @@ -40,6 +45,22 @@ GoRouter buildAppRouter() { builder: (context, state) => LegalDocumentPage.fromExtra(state.extra), ), + GoRoute( + path: '/album', + builder: (context, state) => const AlbumPage(), + ), + GoRoute( + path: '/alarm', + builder: (context, state) => const AlarmPage(), + ), + GoRoute( + path: '/contacts', + builder: (context, state) => const ContactsPage(), + ), + GoRoute( + path: '/apps', + builder: (context, state) => const AppsPage(), + ), StatefulShellRoute.indexedStack( builder: (context, state, shell) => HomePage(child: shell), branches: [ diff --git a/lib/app/theme/app_theme.dart b/lib/app/theme/app_theme.dart index 44b2097..32e5ebf 100644 --- a/lib/app/theme/app_theme.dart +++ b/lib/app/theme/app_theme.dart @@ -6,7 +6,8 @@ import 'package:cupertino_ui/cupertino_ui.dart'; class AppTheme { const AppTheme._(); - static const Color primary = CupertinoColors.activeBlue; + /// 主色:统一采用「桐桐绿」,与移动端设计稿保持一致。 + static const Color primary = Color(0xFF07C160); static const Color background = CupertinoColors.systemBackground; static const Color groupedBackground = CupertinoColors.systemGroupedBackground; diff --git a/lib/core/network/dio_client.dart b/lib/core/network/dio_client.dart index 3853b0c..9649660 100644 --- a/lib/core/network/dio_client.dart +++ b/lib/core/network/dio_client.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; import '../../app/constants/app_constants.dart'; import '../storage/token_storage.dart'; @@ -85,27 +86,27 @@ class DioClient { try { final response = await call(); // [DEBUG] 打印接口响应状态与返回体。 - print( + debugPrint( '[DioClient] <- ${response.requestOptions.method} ' '${response.requestOptions.uri} ' 'statusCode=${response.statusCode}', ); - print('[DioClient] response body=${response.data}'); + debugPrint('[DioClient] response body=${response.data}'); return _ResponseInterceptor.parse(response); } on ApiException { rethrow; } on DioException catch (e) { - print( + debugPrint( '[DioClient] !! DioException ${e.requestOptions.method} ' '${e.requestOptions.uri} statusCode=${e.response?.statusCode} ' 'type=${e.type} message=${e.message}', ); - print('[DioClient] error response body=${e.response?.data}'); + debugPrint('[DioClient] error response body=${e.response?.data}'); throw ApiException.fromAppError( AppError.fromDioException(e), ); } catch (e) { - print('[DioClient] !! unexpected error: $e'); + debugPrint('[DioClient] !! unexpected error: $e'); throw ApiException.fromAppError(AppError.unknown(e)); } } diff --git a/lib/core/widgets/feature_ui.dart b/lib/core/widgets/feature_ui.dart new file mode 100644 index 0000000..8cc8bda --- /dev/null +++ b/lib/core/widgets/feature_ui.dart @@ -0,0 +1,154 @@ +import 'package:cupertino_ui/cupertino_ui.dart'; + +/// 设计稿统一调色板(移动端三 Tab 与子页面共用)。 +/// +/// 主色 [green] 与 [AppTheme.primary] 保持一致;其余为图标底块、进度条等装饰色。 +class AppColors { + const AppColors._(); + + static const Color green = Color(0xFF07C160); + static const Color blue = Color(0xFF5B8DEF); + static const Color orange = Color(0xFFF5A623); + static const Color purple = Color(0xFF764BA2); + static const Color red = Color(0xFFEF4444); + static const Color teal = Color(0xFF0EA5E9); + static const Color gray = Color(0xFF94A3B8); + + /// 主文本色。 + static const Color ink = Color(0xFF1F2733); + + /// 次要文本色。 + static const Color sub = Color(0xFF9AA3B2); + + /// 卡片/页面浅灰背景。 + static const Color surface = Color(0xFFF5F7FA); + + /// 轨道灰(进度条底)。 + static const Color track = Color(0xFFEEF1F6); +} + +/// 圆角图标块 + 文字标签,对应设计稿中的九宫格/横版菜单项。 +class IconTile extends StatelessWidget { + const IconTile({ + required this.emoji, + required this.color, + required this.label, + this.size = 48, + this.iconSize = 22, + this.onTap, + super.key, + }); + + final String emoji; + final Color color; + final String label; + final double size; + final double iconSize; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + final tile = Column( + children: [ + Container( + width: size, + height: size, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(size * 0.32), + ), + child: Center( + child: Text(emoji, style: TextStyle(fontSize: iconSize)), + ), + ), + const SizedBox(height: 7), + Text( + label, + style: const TextStyle(fontSize: 11.5, color: Color(0xFF4B5563)), + ), + ], + ); + if (onTap == null) return tile; + return GestureDetector(onTap: onTap, child: tile); + } +} + +/// 白色圆角卡片容器。 +class CardBox extends StatelessWidget { + const CardBox({ + required this.child, + this.padding = const EdgeInsets.all(16), + this.gradient, + super.key, + }); + + final Widget child; + final EdgeInsets padding; + final Gradient? gradient; + + @override + Widget build(BuildContext context) => Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), + padding: padding, + decoration: BoxDecoration( + gradient: gradient, + color: gradient == null ? CupertinoColors.white : null, + borderRadius: BorderRadius.circular(18), + boxShadow: const [ + BoxShadow( + color: Color(0x14141E3C), + blurRadius: 16, + offset: Offset(0, 4), + ), + ], + ), + child: child, + ); +} + +/// 浅灰分隔线(替代 Material Divider,避免引入 material 依赖)。 +class AppDivider extends StatelessWidget { + const AppDivider({super.key, this.height = 1, this.color = const Color(0xFFF1F3F7)}); + + final double height; + final Color color; + + @override + Widget build(BuildContext context) => Container(height: height, color: color); +} + +/// 分区标题(如「常用功能」「消息」),与设计稿小灰字一致。 +class SectionTitle extends StatelessWidget { + const SectionTitle(this.text, {this.action, super.key}); + + final String text; + final String? action; + + @override + Widget build(BuildContext context) => Padding( + padding: const EdgeInsets.fromLTRB(18, 16, 18, 4), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + text, + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w700, + color: AppColors.sub, + letterSpacing: 0.5, + ), + ), + if (action != null) + Text( + action!, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: AppColors.green, + ), + ), + ], + ), + ); +} diff --git a/lib/features/alarm/presentation/alarm_page.dart b/lib/features/alarm/presentation/alarm_page.dart new file mode 100644 index 0000000..23e5e54 --- /dev/null +++ b/lib/features/alarm/presentation/alarm_page.dart @@ -0,0 +1,114 @@ +import 'package:cupertino_ui/cupertino_ui.dart'; +import 'package:go_router/go_router.dart'; + +import '../../../core/widgets/feature_ui.dart'; +import '../../../l10n/app_localizations.dart'; + +/// 闹钟页(管理 → 闹钟)。 +/// +/// 对应移动端设计稿:多条闹钟卡片,大号时间 + 标签/重复说明 + 开关切换。 +class AlarmPage extends StatefulWidget { + const AlarmPage({super.key}); + + @override + State createState() => _AlarmPageState(); +} + +class _AlarmPageState extends State { + final List<_Alarm> _alarms = [ + _Alarm(time: '07:30', am: 'AM', label: '起床', repeat: '工作日 · 响铃 天籁之音', on: true), + _Alarm(time: '12:30', am: 'PM', label: '午休提醒', repeat: '每天 · 振动', on: false), + _Alarm(time: '14:00', am: 'PM', label: '会议纪要', repeat: '仅今天 · 响铃 轻快', on: true), + _Alarm(time: '21:00', am: 'PM', label: '早睡', repeat: '每天 · 渐强铃声', on: true), + _Alarm(time: '08:00', am: 'AM', label: '周末晨练', repeat: '周六、周日 · 响铃 自然', on: false), + ]; + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context); + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(l10n.alarmTitle), + leading: CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon(CupertinoIcons.back), + onPressed: () => context.go('/messages'), + ), + trailing: CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon(CupertinoIcons.add, size: 26), + onPressed: () {}, + ), + ), + child: ListView.separated( + padding: const EdgeInsets.only(bottom: 24), + itemCount: _alarms.length + 1, + separatorBuilder: (_, _) => const SizedBox(height: 12), + itemBuilder: (_, i) { + if (i == _alarms.length) { + return GestureDetector( + onTap: () {}, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 16), + height: 50, + decoration: BoxDecoration( + border: Border.all(color: const Color(0xFFCBD5E1), width: 2), + borderRadius: BorderRadius.circular(14), + ), + child: Center( + child: Text('+ ${l10n.addAlarm}', + style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: Color(0xFF6B7280))), + ), + ), + ); + } + final a = _alarms[i]; + return CardBox( + child: Row( + children: [ + RichText( + text: TextSpan( + children: [ + TextSpan( + text: a.time, + style: const TextStyle(fontSize: 30, fontWeight: FontWeight.w700, color: AppColors.ink), + ), + TextSpan( + text: ' ${a.am}', + style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.sub), + ), + ], + ), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(a.label, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: AppColors.ink)), + Text(a.repeat, style: const TextStyle(fontSize: 12, color: AppColors.sub)), + ], + ), + ), + CupertinoSwitch( + value: a.on, + activeTrackColor: AppColors.green, + onChanged: (v) => setState(() => a.on = v), + ), + ], + ), + ); + }, + ), + ); + } +} + +class _Alarm { + _Alarm({required this.time, required this.am, required this.label, required this.repeat, required this.on}); + final String time; + final String am; + final String label; + final String repeat; + bool on; +} diff --git a/lib/features/album/presentation/album_page.dart b/lib/features/album/presentation/album_page.dart new file mode 100644 index 0000000..2e1e74a --- /dev/null +++ b/lib/features/album/presentation/album_page.dart @@ -0,0 +1,151 @@ +import 'package:cupertino_ui/cupertino_ui.dart'; +import 'package:go_router/go_router.dart'; + +import '../../../core/widgets/feature_ui.dart'; +import '../../../l10n/app_localizations.dart'; + +/// 相册页(管理 → 相册)。 +/// +/// 对应移动端设计稿:分段切换(全部/收藏/视频/相簿)、照片数量统计、 +/// 三列照片墙与右下上传按钮。 +class AlbumPage extends StatefulWidget { + const AlbumPage({super.key}); + + @override + State createState() => _AlbumPageState(); +} + +class _AlbumPageState extends State { + int _segment = 0; + final _segments = ['全部', '收藏', '视频', '相簿']; + + static const _gradients = [ + [AppColors.purple, AppColors.blue], + [AppColors.red, Color(0xFFF5576C)], + [AppColors.teal, Color(0xFF00F2FE)], + [Color(0xFF43E97B), Color(0xFF38F9D7)], + [Color(0xFFFA709A), Color(0xFFFEE140)], + [Color(0xFF30CFD0), Color(0xFF330867)], + [Color(0xFFA8ED92), Color(0xFFFED6E3)], + [Color(0xFFFBC2EB), Color(0xFFFECFEF)], + [Color(0xFF5EE7DF), Color(0xFFB490CA)], + [Color(0xFFF6D365), Color(0xFFFDA085)], + [Color(0xFF84FAB0), Color(0xFF8FD3F4)], + [Color(0xFFD4FC79), Color(0xFF96E6A1)], + [Color(0xFFE0C3FC), Color(0xFF8EC5FC)], + [Color(0xFFFBC2EB), Color(0xFFA6C1EE)], + [Color(0xFF21D4FD), Color(0xFFB721FF)], + ]; + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context); + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(l10n.albumTitle), + leading: CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon(CupertinoIcons.back), + onPressed: () => context.go('/messages'), + ), + trailing: CupertinoButton( + padding: EdgeInsets.zero, + child: const Text('选择'), + onPressed: () {}, + ), + ), + child: Stack( + children: [ + ListView( + padding: const EdgeInsets.only(bottom: 90), + children: [ + // 分段切换 + Padding( + padding: const EdgeInsets.fromLTRB(16, 10, 16, 0), + child: Container( + padding: const EdgeInsets.all(3), + decoration: BoxDecoration( + color: AppColors.track, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + for (var i = 0; i < _segments.length; i++) + Expanded( + child: GestureDetector( + onTap: () => setState(() => _segment = i), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + decoration: BoxDecoration( + color: _segment == i ? CupertinoColors.white : const Color(0x00000000), + borderRadius: BorderRadius.circular(9), + boxShadow: _segment == i + ? const [BoxShadow(color: Color(0x14141E3C), blurRadius: 6, offset: Offset(0, 2))] + : null, + ), + child: Center( + child: Text(_segments[i], + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + color: _segment == i ? AppColors.ink : AppColors.sub)), + ), + ), + ), + ), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(18, 10, 18, 10), + child: Text('1280 张照片 · 42 个视频 · 已占用 6.4 GB', + style: const TextStyle(fontSize: 12, color: AppColors.sub)), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 3), + child: GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 3, + mainAxisSpacing: 3, + ), + itemCount: _gradients.length, + itemBuilder: (_, i) => Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + gradient: LinearGradient( + colors: _gradients[i], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + ), + ), + ), + ], + ), + Positioned( + right: 18, + bottom: 26, + child: GestureDetector( + onTap: () {}, + child: Container( + width: 54, + height: 54, + decoration: BoxDecoration( + color: AppColors.green, + shape: BoxShape.circle, + boxShadow: const [BoxShadow(color: Color(0x6607C160), blurRadius: 20, offset: Offset(0, 8))], + ), + child: const Center(child: Text('+', style: TextStyle(fontSize: 28, color: CupertinoColors.white))), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/features/apps/presentation/apps_page.dart b/lib/features/apps/presentation/apps_page.dart new file mode 100644 index 0000000..cea39d5 --- /dev/null +++ b/lib/features/apps/presentation/apps_page.dart @@ -0,0 +1,137 @@ +import 'package:cupertino_ui/cupertino_ui.dart'; +import 'package:go_router/go_router.dart'; + +import '../../../core/widgets/feature_ui.dart'; +import '../../../l10n/app_localizations.dart'; + +/// 应用页(管理 → 应用)。 +/// +/// 对应移动端设计稿:搜索栏 + 常用九宫格 + 系统工具/影音娱乐分类列表。 +class AppsPage extends StatelessWidget { + const AppsPage({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context); + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(l10n.appsTitle), + leading: CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon(CupertinoIcons.back), + onPressed: () => context.go('/messages'), + ), + trailing: CupertinoButton( + padding: EdgeInsets.zero, + child: const Text('管理'), + onPressed: () {}, + ), + ), + child: ListView( + padding: const EdgeInsets.only(bottom: 20), + children: [ + // 搜索栏 + Container( + margin: const EdgeInsets.fromLTRB(16, 10, 16, 4), + height: 40, + decoration: BoxDecoration( + color: CupertinoColors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: const [BoxShadow(color: Color(0x14141E3C), blurRadius: 8, offset: Offset(0, 2))], + ), + child: const Row( + children: [ + SizedBox(width: 14), + Icon(CupertinoIcons.search, size: 16, color: AppColors.sub), + SizedBox(width: 8), + Text('搜索应用', style: TextStyle(fontSize: 14, color: AppColors.sub)), + ], + ), + ), + SectionTitle(l10n.appsCommon), + CardBox( + child: Column( + children: [ + Row( + children: [ + Expanded(child: IconTile(emoji: '🖼️', color: AppColors.blue, label: l10n.menuAlbum)), + Expanded(child: IconTile(emoji: '⏰', color: AppColors.orange, label: l10n.menuAlarm)), + Expanded(child: IconTile(emoji: '👥', color: AppColors.green, label: l10n.menuContacts)), + Expanded(child: IconTile(emoji: '📁', color: AppColors.purple, label: l10n.menuFiles)), + ], + ), + const SizedBox(height: 14), + Row( + children: [ + Expanded(child: IconTile(emoji: '📷', color: AppColors.red, label: l10n.appsCamera)), + Expanded(child: IconTile(emoji: '📅', color: AppColors.teal, label: '日历')), + Expanded(child: IconTile(emoji: '📝', color: const Color(0xFF22C55E), label: '备忘录')), + Expanded(child: IconTile(emoji: '➕', color: AppColors.gray, label: l10n.appsAdd)), + ], + ), + ], + ), + ), + SectionTitle(l10n.appsSystem), + CardBox( + padding: EdgeInsets.zero, + child: Column( + children: [ + _appRow('⚙️', const Color(0xFF64748B), '设置', '系统 · 已安装'), + const AppDivider(), + _appRow('🌐', AppColors.teal, '浏览器', '系统 · 已安装'), + const AppDivider(), + _appRow('🗺️', const Color(0xFF22C55E), '地图', '系统 · 已安装'), + ], + ), + ), + SectionTitle(l10n.appsEntertain), + CardBox( + padding: EdgeInsets.zero, + child: Column( + children: [ + _appRow('🎵', AppColors.red, '音乐', 'v8.2 · 已安装'), + const AppDivider(), + _appRow('🎬', AppColors.orange, '视频', 'v5.1 · 已安装'), + const AppDivider(), + _appRow('📚', AppColors.purple, '阅读', 'v3.4 · 已安装'), + ], + ), + ), + ], + ), + ); + } + + Widget _appRow(String emoji, Color color, String name, String sub) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), + child: Row( + children: [ + Container( + width: 42, + height: 42, + decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(13)), + child: Center(child: Text(emoji, style: const TextStyle(fontSize: 19))), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(name, style: const TextStyle(fontSize: 14.5, fontWeight: FontWeight.w600, color: AppColors.ink)), + Text(sub, style: const TextStyle(fontSize: 12, color: AppColors.sub)), + ], + ), + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), + decoration: BoxDecoration( + color: const Color(0xFFE8F8EE), + borderRadius: BorderRadius.circular(14), + ), + child: const Text('打开', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: AppColors.green)), + ), + ], + ), + ); +} diff --git a/lib/features/auth/data/auth_repository_impl.dart b/lib/features/auth/data/auth_repository_impl.dart index 269dfb0..634eca0 100644 --- a/lib/features/auth/data/auth_repository_impl.dart +++ b/lib/features/auth/data/auth_repository_impl.dart @@ -1,4 +1,3 @@ -import '../../../core/network/api_exception.dart'; import '../../../core/network/dio_client.dart'; import '../../../core/storage/token_storage.dart'; import '../domain/auth_models.dart'; diff --git a/lib/features/auth/presentation/auth_controller.dart b/lib/features/auth/presentation/auth_controller.dart index 3911280..9320b61 100644 --- a/lib/features/auth/presentation/auth_controller.dart +++ b/lib/features/auth/presentation/auth_controller.dart @@ -174,9 +174,6 @@ class AuthController extends Notifier { }); } - String _messageOf(Object e) { - return userMessageOf(e); - } } /// 认证控制器 Provider(会话级 keepAlive 在 build 内通过 ref.keepAlive 实现)。 diff --git a/lib/features/contacts/presentation/contacts_page.dart b/lib/features/contacts/presentation/contacts_page.dart new file mode 100644 index 0000000..4477c97 --- /dev/null +++ b/lib/features/contacts/presentation/contacts_page.dart @@ -0,0 +1,148 @@ +import 'package:cupertino_ui/cupertino_ui.dart'; +import 'package:go_router/go_router.dart'; + +import '../../../core/widgets/feature_ui.dart'; +import '../../../l10n/app_localizations.dart'; + +/// 联系人页(管理 → 联系人)。 +/// +/// 对应移动端设计稿:搜索栏 + 分组列表(常用/同事/家人)+ 右侧字母索引。 +class ContactsPage extends StatelessWidget { + const ContactsPage({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context); + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(l10n.contactsTitle), + leading: CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon(CupertinoIcons.back), + onPressed: () => context.go('/messages'), + ), + trailing: CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon(CupertinoIcons.add, size: 26), + onPressed: () {}, + ), + ), + child: Stack( + children: [ + ListView( + padding: const EdgeInsets.only(bottom: 20), + children: [ + // 搜索栏 + Container( + margin: const EdgeInsets.fromLTRB(16, 10, 16, 4), + height: 40, + decoration: BoxDecoration( + color: CupertinoColors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: const [BoxShadow(color: Color(0x14141E3C), blurRadius: 8, offset: Offset(0, 2))], + ), + child: const Row( + children: [ + SizedBox(width: 14), + Icon(CupertinoIcons.search, size: 16, color: AppColors.sub), + SizedBox(width: 8), + Text('搜索姓名、号码', style: TextStyle(fontSize: 14, color: AppColors.sub)), + ], + ), + ), + _group(l10n.grpFavorite, [ + _Contact('妈', AppColors.blue, '妈妈', '138 **** 6621'), + _Contact('李', AppColors.green, '李工 · 运维', '159 **** 0248'), + ]), + _group(l10n.grpColleague, [ + _Contact('王', AppColors.purple, '王经理', '186 **** 7733 · 产品部'), + _Contact('张', AppColors.orange, '张总监', '135 **** 5512 · 技术部'), + _Contact('赵', AppColors.red, '赵设计', '188 **** 2019 · 设计部'), + ]), + _group(l10n.grpFamily, [ + _Contact('爸', AppColors.teal, '爸爸', '137 **** 0098'), + _Contact('妹', const Color(0xFFEC4899), '妹妹', '199 **** 3344'), + ]), + ], + ), + Positioned( + right: 5, + top: 150, + child: Column( + children: const [ + Text('★', style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: AppColors.sub)), + SizedBox(height: 3), + Text('同', style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: AppColors.sub)), + SizedBox(height: 3), + Text('家', style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: AppColors.sub)), + SizedBox(height: 3), + Text('A', style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: AppColors.sub)), + SizedBox(height: 3), + Text('B', style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: AppColors.sub)), + SizedBox(height: 3), + Text('C', style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: AppColors.sub)), + SizedBox(height: 3), + Text('D', style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: AppColors.sub)), + ], + ), + ), + ], + ), + ); + } + + Widget _group(String title, List<_Contact> items) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(18, 14, 18, 4), + child: Text(title, + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w700, color: AppColors.sub)), + ), + CardBox( + padding: EdgeInsets.zero, + child: Column( + children: [ + for (var i = 0; i < items.length; i++) ...[ + if (i > 0) const Padding(padding: EdgeInsets.symmetric(horizontal: 16), child: AppDivider()), + _row(items[i]), + ], + ], + ), + ), + ], + ); + + Widget _row(_Contact c) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), + child: Row( + children: [ + Container( + width: 42, + height: 42, + decoration: BoxDecoration(color: c.color, borderRadius: BorderRadius.circular(13)), + child: Center(child: Text(c.initial, style: const TextStyle(fontSize: 17, color: CupertinoColors.white))), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(c.name, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: AppColors.ink)), + Text(c.phone, style: const TextStyle(fontSize: 12, color: AppColors.sub)), + ], + ), + ), + const Text('›', style: TextStyle(fontSize: 16, color: Color(0xFFCBD2DC))), + ], + ), + ); +} + +class _Contact { + const _Contact(this.initial, this.color, this.name, this.phone); + final String initial; + final Color color; + final String name; + final String phone; +} diff --git a/lib/features/home/presentation/home_page.dart b/lib/features/home/presentation/home_page.dart index ea598c6..c7a3e18 100644 --- a/lib/features/home/presentation/home_page.dart +++ b/lib/features/home/presentation/home_page.dart @@ -4,7 +4,7 @@ import 'package:go_router/go_router.dart'; import '../../../l10n/app_localizations.dart'; -/// 首页 Shell(含底部 Tab:首页 / 消息 / 我的)。 +/// 首页 Shell(含底部 Tab:首页 / 管理 / 我的)。 /// /// Tab 切换通过 GoRouter 的 StatefulShellRoute 管理,本组件仅渲染当前分支与底部栏。 /// 实际 Tab 内容由对应特性模块(home / messages / profile)提供。 @@ -39,8 +39,8 @@ class HomePage extends ConsumerWidget { label: l10n.tabHome, ), BottomNavigationBarItem( - icon: const Icon(CupertinoIcons.chat_bubble_2), - label: l10n.tabMessages, + icon: const Icon(CupertinoIcons.square_grid_2x2), + label: l10n.tabManage, ), BottomNavigationBarItem( icon: const Icon(CupertinoIcons.person), diff --git a/lib/features/home/presentation/home_tab.dart b/lib/features/home/presentation/home_tab.dart index a8d758f..3c31f19 100644 --- a/lib/features/home/presentation/home_tab.dart +++ b/lib/features/home/presentation/home_tab.dart @@ -1,11 +1,13 @@ import 'package:cupertino_ui/cupertino_ui.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../../core/widgets/feature_ui.dart'; import '../../../l10n/app_localizations.dart'; /// 首页 Tab 内容(特性模块:home / presentation)。 /// -/// 当前为占位组件,后续可在此接入首页业务控制器与列表。 +/// 对应移动端设计稿的「平板信息页」:实时位置地图、最近截图、 +/// 今日使用时长、设备操作(重启/关机/截屏/刷新/定位)与常用功能网格。 class HomeTab extends ConsumerWidget { const HomeTab({super.key}); @@ -13,10 +15,321 @@ class HomeTab extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context); return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar(middle: Text(l10n.tabHome)), + navigationBar: CupertinoNavigationBar( + middle: Text(l10n.appTitle, + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.w700, color: AppColors.ink)), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(CupertinoIcons.location_fill, + size: 12, color: AppColors.green), + const SizedBox(width: 4), + Text('${l10n.homeDeviceName} · ${l10n.homeOnline}', + style: const TextStyle(fontSize: 12, color: AppColors.sub)), + const SizedBox(width: 8), + Container( + width: 30, + height: 30, + decoration: const BoxDecoration( + shape: BoxShape.circle, + gradient: LinearGradient( + colors: [Color(0xFF5B8DEF), Color(0xFF07C160)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: const Center( + child: Text('U', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w700, + color: CupertinoColors.white))), + ), + ], + ), + ), child: SafeArea( - child: Center(child: Text(l10n.homeContent)), + child: ListView( + padding: const EdgeInsets.only(bottom: 96), + children: [ + _locationCard(l10n), + _screenshotsCard(l10n), + _usageCard(l10n), + _deviceOpsCard(l10n), + SectionTitle(l10n.homeCommon), + _commonCard(l10n), + ], + ), ), ); } + + Widget _cardHeader( + String emoji, + Color color, + String title, { + String? trailing, + }) => + Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Row( + children: [ + Container( + width: 22, + height: 22, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(7), + ), + child: Center(child: Text(emoji, style: const TextStyle(fontSize: 13))), + ), + const SizedBox(width: 7), + Text(title, + style: const TextStyle( + fontSize: 15, fontWeight: FontWeight.w700, color: AppColors.ink)), + const Spacer(), + if (trailing != null) + Text(trailing, + style: const TextStyle( + fontSize: 12, fontWeight: FontWeight.w600, color: AppColors.green)), + ], + ), + ); + + Widget _locationCard(AppLocalizations l10n) => CardBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _cardHeader('📍', AppColors.green, l10n.homeLocation, trailing: l10n.homeLocating), + ClipRRect( + borderRadius: BorderRadius.circular(14), + child: Container( + height: 150, + color: const Color(0xFFF3F7FF), + child: Stack( + children: [ + // 简易路网 + Positioned(top: 38, left: 0, right: 0, height: 10, child: Container(color: CupertinoColors.white)), + Positioned(top: 96, left: 0, right: 0, height: 10, child: Container(color: CupertinoColors.white)), + Positioned(top: 0, bottom: 0, left: 120, width: 10, child: Container(color: CupertinoColors.white)), + Positioned(top: 0, bottom: 0, left: 240, width: 10, child: Container(color: CupertinoColors.white)), + // 定位标记 + Positioned( + left: 0, + right: 0, + top: 46, + child: Center( + child: Container( + width: 30, + height: 30, + decoration: const BoxDecoration( + color: AppColors.green, + shape: BoxShape.circle, + ), + child: const Center( + child: Icon(CupertinoIcons.location_fill, + color: CupertinoColors.white, size: 16), + ), + ), + ), + ), + Positioned( + left: 12, + bottom: 10, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + decoration: BoxDecoration( + color: CupertinoColors.white.withValues(alpha: 0.92), + borderRadius: BorderRadius.circular(10), + ), + child: Text('📍 ${l10n.homeAddress}', + style: const TextStyle(fontSize: 12, color: AppColors.ink)), + ), + ), + ], + ), + ), + ), + ], + ), + ); + + Widget _screenshotsCard(AppLocalizations l10n) => CardBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _cardHeader('🖼️', AppColors.blue, l10n.homeScreenshots, trailing: l10n.homeViewAll), + SizedBox( + height: 120, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: 4, + separatorBuilder: (_, _) => const SizedBox(width: 10), + itemBuilder: (_, i) => Container( + width: 88, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + gradient: const LinearGradient( + colors: [AppColors.blue, AppColors.purple], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(6), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: CupertinoColors.black.withValues(alpha: 0.45), + borderRadius: BorderRadius.circular(6), + ), + child: Text(['14:02', '13:20', '11:48', '09:15'][i], + style: const TextStyle(fontSize: 10, color: CupertinoColors.white)), + ), + ), + ), + ), + ), + ), + ], + ), + ); + + Widget _usageCard(AppLocalizations l10n) => CardBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _cardHeader('⏱️', AppColors.orange, l10n.homeUsage, trailing: l10n.homeUsageTrend), + Row( + children: [ + // 环形进度(约 60%) + SizedBox( + width: 86, + height: 86, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 86, + height: 86, + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: SweepGradient( + stops: const [0, 0.6, 0.6, 1], + colors: const [ + AppColors.green, + AppColors.green, + AppColors.track, + AppColors.track, + ], + ), + ), + ), + Container( + width: 64, + height: 64, + decoration: const BoxDecoration( + color: CupertinoColors.white, shape: BoxShape.circle), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('3.4h', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w700, color: AppColors.ink)), + Text(l10n.homeUsageToday, + style: const TextStyle(fontSize: 10, color: AppColors.sub)), + ], + ), + ), + ], + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + children: [ + _usageBar('阅读', 0.55, AppColors.green), + _usageBar('视频', 0.30, AppColors.blue), + _usageBar('办公', 0.15, AppColors.orange), + ], + ), + ), + ], + ), + ], + ), + ); + + Widget _usageBar(String name, double v, Color color) => Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + children: [ + SizedBox(width: 42, child: Text(name, style: const TextStyle(fontSize: 12, color: Color(0xFF4B5563)))), + Expanded( + child: Container( + height: 7, + decoration: BoxDecoration( + color: AppColors.track, + borderRadius: BorderRadius.circular(4), + ), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: v, + child: Container( + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(4), + ), + ), + ), + ), + ), + ], + ), + ); + + Widget _deviceOpsCard(AppLocalizations l10n) => CardBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _cardHeader('⚡', AppColors.purple, l10n.homeDeviceOps), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconTile(emoji: '🔄', color: AppColors.blue, label: l10n.opRestart, size: 50, iconSize: 20), + IconTile(emoji: '🔌', color: AppColors.red, label: l10n.opShutdown, size: 50, iconSize: 20), + IconTile(emoji: '📸', color: AppColors.green, label: l10n.opScreenshot, size: 50, iconSize: 20), + IconTile(emoji: '🔃', color: AppColors.orange, label: l10n.opRefresh, size: 50, iconSize: 20), + IconTile(emoji: '📍', color: AppColors.purple, label: l10n.opLocate, size: 50, iconSize: 20), + ], + ), + ], + ), + ); + + Widget _commonCard(AppLocalizations l10n) => CardBox( + child: Column( + children: [ + Row( + children: [ + Expanded(child: IconTile(emoji: '📁', color: AppColors.blue, label: l10n.cfFileTransfer)), + Expanded(child: IconTile(emoji: '📷', color: AppColors.green, label: l10n.cfRemoteCam)), + Expanded(child: IconTile(emoji: '💬', color: AppColors.orange, label: l10n.cfMsgSync)), + Expanded(child: IconTile(emoji: '🧹', color: AppColors.purple, label: l10n.cfClean)), + ], + ), + const SizedBox(height: 14), + Row( + children: [ + Expanded(child: IconTile(emoji: '📺', color: AppColors.red, label: l10n.cfMirror)), + Expanded(child: IconTile(emoji: '🔔', color: AppColors.teal, label: l10n.cfLost)), + Expanded(child: IconTile(emoji: '🔒', color: const Color(0xFF22C55E), label: l10n.cfAppLock)), + Expanded(child: IconTile(emoji: '➕', color: AppColors.gray, label: l10n.cfMore)), + ], + ), + ], + ), + ); } diff --git a/lib/features/messages/presentation/messages_tab.dart b/lib/features/messages/presentation/messages_tab.dart index d86e6cb..a8f54cb 100644 --- a/lib/features/messages/presentation/messages_tab.dart +++ b/lib/features/messages/presentation/messages_tab.dart @@ -1,22 +1,236 @@ import 'package:cupertino_ui/cupertino_ui.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import '../../../core/widgets/feature_ui.dart'; import '../../../l10n/app_localizations.dart'; -/// 消息 Tab 内容(特性模块:messages / presentation)。 +/// 管理 Tab 内容(特性模块:messages / presentation)。 /// -/// 当前为占位组件,后续可在此接入会话列表与未读状态控制器。 +/// 对应移动端设计稿的「管理」页:顶部横版菜单(相册/闹钟/联系人/应用 …) +/// 可点击进入对应子页面,下方为消息列表。底部 Tab 文案为「管理」。 class MessagesTab extends ConsumerWidget { const MessagesTab({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context); + + final menus = [ + _Menu(emoji: '🖼️', color: AppColors.blue, label: l10n.menuAlbum, route: '/album'), + _Menu(emoji: '⏰', color: AppColors.orange, label: l10n.menuAlarm, route: '/alarm'), + _Menu(emoji: '👥', color: AppColors.green, label: l10n.menuContacts, route: '/contacts'), + _Menu(emoji: '🧩', color: AppColors.purple, label: l10n.menuApps, route: '/apps'), + _Menu(emoji: '📁', color: AppColors.teal, label: l10n.menuFiles, route: '/apps'), + _Menu(emoji: '➕', color: AppColors.gray, label: l10n.menuMore, route: null), + ]; + + final messages = [ + _Message(emoji: '📱', color: AppColors.green, title: l10n.msgOnline, + preview: '我的平板 Pro 已连接办公室 WiFi', time: '09:30', unread: true, badge: 1), + _Message(emoji: '🖼️', color: AppColors.blue, title: l10n.msgScreenshot, + preview: '收到 3 张新截图,已存入相册', time: '昨天', unread: false), + _Message(emoji: '🛠️', color: AppColors.purple, title: l10n.msgRemote, + preview: '李工请求对平板进行远程协助', time: '昨天', unread: true), + _Message(emoji: '🔋', color: AppColors.red, title: l10n.msgBattery, + preview: '平板电量低于 20%,请尽快充电', time: '周一', unread: false), + _Message(emoji: '🔄', color: AppColors.teal, title: l10n.msgUpdate, + preview: '平板管家 v3.2.1 已更新完成', time: '周一', unread: false), + ]; + return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar(middle: Text(l10n.tabMessages)), + navigationBar: CupertinoNavigationBar( + middle: Text(l10n.manageTitle), + trailing: Container( + width: 38, + height: 38, + decoration: BoxDecoration( + color: CupertinoColors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: CupertinoColors.black.withValues(alpha: 0.06), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Stack( + children: [ + const Center( + child: + Icon(CupertinoIcons.bell, size: 18, color: AppColors.ink)), + Positioned( + top: 5, + right: 7, + child: Container( + width: 8, + height: 8, + decoration: const BoxDecoration( + color: AppColors.red, shape: BoxShape.circle), + ), + ), + ], + ), + ), + ), child: SafeArea( - child: Center(child: Text(l10n.messagesContent)), + child: ListView( + padding: const EdgeInsets.only(bottom: 96), + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(18, 10, 18, 4), + child: Text(l10n.manageSubtitle, + style: const TextStyle(fontSize: 12, color: AppColors.sub)), + ), + // 横版菜单 + SizedBox( + height: 96, + child: ListView.separated( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 16), + separatorBuilder: (_, _) => const SizedBox(width: 12), + itemCount: menus.length, + itemBuilder: (_, i) { + final m = menus[i]; + return Container( + width: 80, + decoration: BoxDecoration( + color: CupertinoColors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: const [ + BoxShadow(color: Color(0x14141E3C), blurRadius: 14, offset: Offset(0, 4)), + ], + ), + child: IconTile( + emoji: m.emoji, + color: m.color, + label: m.label, + size: 44, + iconSize: 22, + onTap: m.route == null ? null : () => context.go(m.route!), + ), + ); + }, + ), + ), + SectionTitle(l10n.tabMessages, action: l10n.msgAllRead), + CardBox( + padding: EdgeInsets.zero, + child: Column( + children: [ + for (var i = 0; i < messages.length; i++) ...[ + if (i > 0) + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: AppDivider(), + ), + _messageRow(messages[i]), + ], + ], + ), + ), + ], + ), ), ); } + + Widget _messageRow(_Message m) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + child: Row( + children: [ + Stack( + children: [ + Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: m.color, + borderRadius: BorderRadius.circular(14), + ), + child: Center(child: Text(m.emoji, style: const TextStyle(fontSize: 19))), + ), + if (m.badge != null) + Positioned( + top: -4, + right: -4, + child: Container( + constraints: const BoxConstraints(minWidth: 17), + height: 17, + padding: const EdgeInsets.symmetric(horizontal: 4), + decoration: BoxDecoration( + color: AppColors.red, + borderRadius: BorderRadius.circular(9), + ), + child: Center( + child: Text('${m.badge}', + style: const TextStyle(fontSize: 10, color: CupertinoColors.white)), + ), + ), + ), + ], + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text(m.title, + style: const TextStyle(fontSize: 14.5, fontWeight: FontWeight.w600, color: AppColors.ink)), + const Spacer(), + Text(m.time, style: const TextStyle(fontSize: 11, color: AppColors.sub)), + ], + ), + const SizedBox(height: 3), + Text(m.preview, + style: const TextStyle(fontSize: 12.5, color: AppColors.sub), + maxLines: 1, + overflow: TextOverflow.ellipsis), + ], + ), + ), + if (m.unread) + const Padding( + padding: EdgeInsets.only(left: 8), + child: SizedBox( + width: 9, + height: 9, + child: DecoratedBox( + decoration: BoxDecoration(color: AppColors.red, shape: BoxShape.circle), + ), + ), + ), + ], + ), + ); +} + +class _Menu { + const _Menu({required this.emoji, required this.color, required this.label, this.route}); + final String emoji; + final Color color; + final String label; + final String? route; +} + +class _Message { + const _Message({ + required this.emoji, + required this.color, + required this.title, + required this.preview, + required this.time, + required this.unread, + this.badge, + }); + final String emoji; + final Color color; + final String title; + final String preview; + final String time; + final bool unread; + final int? badge; } diff --git a/lib/features/profile/presentation/profile_tab.dart b/lib/features/profile/presentation/profile_tab.dart index c260fce..f0d4129 100644 --- a/lib/features/profile/presentation/profile_tab.dart +++ b/lib/features/profile/presentation/profile_tab.dart @@ -2,31 +2,230 @@ import 'package:cupertino_ui/cupertino_ui.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import '../../../core/widgets/feature_ui.dart'; import '../../../l10n/app_localizations.dart'; import '../../auth/presentation/auth_controller.dart'; /// 我的 Tab 内容(特性模块:profile / presentation)。 /// -/// 含登出入口,登出动作委托给 authController,随后路由回登录页。 +/// 对应移动端设计稿的「我的」页:个人资料头部、绑定设备、 +/// 个人资料、设置列表与退出登录。登出委托给 authController。 class ProfileTab extends ConsumerWidget { const ProfileTab({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context); + return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar(middle: Text(l10n.tabProfile)), child: SafeArea( - child: Center( - child: CupertinoButton( - child: Text(l10n.logout), - onPressed: () { - ref.read(authControllerProvider.notifier).logout(); - context.go('/login'); - }, - ), + child: ListView( + padding: const EdgeInsets.only(bottom: 96), + children: [ + // 个人资料头部 + Container( + padding: const EdgeInsets.fromLTRB(18, 18, 18, 26), + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [AppColors.green, AppColors.blue], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: Row( + children: [ + Container( + width: 62, + height: 62, + decoration: BoxDecoration( + color: CupertinoColors.white.withValues(alpha: 0.25), + shape: BoxShape.circle, + border: Border.all(color: CupertinoColors.white.withValues(alpha: 0.6), width: 2), + ), + child: const Center( + child: Text('U', style: TextStyle(fontSize: 26, fontWeight: FontWeight.w700, color: CupertinoColors.white)), + ), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('用户名', + style: TextStyle(fontSize: 19, fontWeight: FontWeight.w700, color: CupertinoColors.white)), + const SizedBox(height: 4), + Text('ID: u_8821 · 平板管家 Pro', + style: TextStyle(fontSize: 12.5, color: CupertinoColors.white.withValues(alpha: 0.92))), + ], + ), + ), + GestureDetector( + onTap: () {}, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 7), + decoration: BoxDecoration( + color: CupertinoColors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(20), + ), + child: Text(l10n.profileEdit, + style: const TextStyle(fontSize: 12.5, fontWeight: FontWeight.w600, color: CupertinoColors.white)), + ), + ), + ], + ), + ), + + SectionTitle(l10n.deviceBound), + CardBox( + padding: EdgeInsets.zero, + gradient: const LinearGradient( + colors: [Color(0xFFEEF6FF), Color(0xFFF3FBF6)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + child: Column( + children: [ + _deviceRow('📱', AppColors.green, l10n.devTablet, '在线 · 电量 82%', '管理'), + const AppDivider(), + _deviceRow('⌚', AppColors.blue, l10n.devWatch, '已连接 · 心率监测中', null), + ], + ), + ), + + SectionTitle(l10n.profileInfo), + CardBox( + padding: EdgeInsets.zero, + child: Column( + children: [ + _infoRow('🖼️', AppColors.purple, l10n.piAvatar, null), + const AppDivider(), + _infoRow('📛', AppColors.blue, l10n.piName, '用户名'), + const AppDivider(), + _infoRow('✍️', AppColors.orange, l10n.piSign, '热爱生活'), + ], + ), + ), + + SectionTitle(l10n.settingsTitle), + CardBox( + padding: EdgeInsets.zero, + child: Column( + children: [ + _settingRow('🔔', AppColors.teal, l10n.setNotify, '消息、设备状态提醒'), + const AppDivider(), + _settingRow('🔒', const Color(0xFF22C55E), l10n.setPrivacy, '定位、相册、权限管理'), + const AppDivider(), + _settingRow('🛡️', AppColors.red, l10n.setSecurity, '登录设备、密码'), + const AppDivider(), + _settingRow('❓', AppColors.gray, l10n.setHelp, null), + const AppDivider(), + _settingRow('ℹ️', const Color(0xFF64748B), l10n.setAbout, '平板管家 v3.2.1'), + ], + ), + ), + + GestureDetector( + onTap: () { + ref.read(authControllerProvider.notifier).logout(); + context.go('/login'); + }, + child: Container( + margin: const EdgeInsets.fromLTRB(16, 18, 16, 0), + height: 48, + decoration: BoxDecoration( + color: CupertinoColors.white, + borderRadius: BorderRadius.circular(14), + boxShadow: const [ + BoxShadow(color: Color(0x14141E3C), blurRadius: 16, offset: Offset(0, 4)), + ], + ), + child: Center( + child: Text(l10n.logout, + style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w700, color: AppColors.red)), + ), + ), + ), + ], ), ), ); } + + Widget _deviceRow(String emoji, Color color, String title, String sub, String? action) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + child: Row( + children: [ + Container( + width: 36, + height: 36, + decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(11)), + child: Center(child: Text(emoji, style: const TextStyle(fontSize: 17))), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: const TextStyle(fontSize: 14.5, fontWeight: FontWeight.w600, color: AppColors.ink)), + const SizedBox(height: 2), + Text(sub, style: const TextStyle(fontSize: 12, color: AppColors.sub)), + ], + ), + ), + if (action != null) + Text('$action ›', style: const TextStyle(fontSize: 13, color: AppColors.sub)) + else + const Text('›', style: TextStyle(fontSize: 16, color: Color(0xFFCBD2DC))), + ], + ), + ); + + Widget _infoRow(String emoji, Color color, String label, String? value) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + child: Row( + children: [ + Container( + width: 36, + height: 36, + decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(11)), + child: Center(child: Text(emoji, style: const TextStyle(fontSize: 17))), + ), + const SizedBox(width: 12), + Text(label, style: const TextStyle(fontSize: 14.5, fontWeight: FontWeight.w600, color: AppColors.ink)), + const Spacer(), + if (value != null) + Text(value, style: const TextStyle(fontSize: 13, color: AppColors.sub)), + const SizedBox(width: 6), + const Text('›', style: TextStyle(fontSize: 16, color: Color(0xFFCBD2DC))), + ], + ), + ); + + Widget _settingRow(String emoji, Color color, String label, String? sub) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13), + child: Row( + children: [ + Container( + width: 36, + height: 36, + decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(11)), + child: Center(child: Text(emoji, style: const TextStyle(fontSize: 17))), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: const TextStyle(fontSize: 14.5, fontWeight: FontWeight.w600, color: AppColors.ink)), + if (sub != null) ...[ + const SizedBox(height: 2), + Text(sub, style: const TextStyle(fontSize: 12, color: AppColors.sub)), + ], + ], + ), + ), + const Text('›', style: TextStyle(fontSize: 16, color: Color(0xFFCBD2DC))), + ], + ), + ); } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index d57a480..7ea1611 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -379,6 +379,408 @@ abstract class AppLocalizations { /// In zh, this message translates to: /// **'《隐私政策》\n\n我们高度重视您的隐私保护。本政策说明我们如何收集、使用、存储和保护您的个人信息。\n\n一、信息收集\n我们可能收集以下信息:\n1. 您主动提供的信息,如手机号、昵称。\n2. 设备与日志信息,用于保障服务安全与故障排查。\n\n二、信息使用\n您的信息仅用于提供和改进本应用服务、保障账户安全及必要的通知。\n\n三、信息存储\n我们采取加密等合理措施保护您的信息,并在必要的期限内保存,超出期限将予以删除或匿名化处理。\n\n四、信息共享\n除法律法规要求或为完成您所请求的服务外,我们不会向第三方披露您的个人信息。\n\n五、您的权利\n您有权查询、更正或删除您的个人信息,并可撤回已授予的授权。\n\n六、政策变更\n本政策变更后将在应用内更新,请您定期查阅。\n\n如您对隐私保护有任何疑问,请联系我们的客服。'** String get privacyPolicyContent; + + /// 闹钟页标题 + /// + /// In zh, this message translates to: + /// **'闹钟'** + String get alarmTitle; + + /// 添加闹钟按钮 + /// + /// In zh, this message translates to: + /// **'添加闹钟'** + String get addAlarm; + + /// 相册页标题 + /// + /// In zh, this message translates to: + /// **'相册'** + String get albumTitle; + + /// 应用页标题 + /// + /// In zh, this message translates to: + /// **'应用'** + String get appsTitle; + + /// 常用功能分组 + /// + /// In zh, this message translates to: + /// **'常用功能'** + String get appsCommon; + + /// 系统工具分组 + /// + /// In zh, this message translates to: + /// **'系统工具'** + String get appsSystem; + + /// 影音娱乐分组 + /// + /// In zh, this message translates to: + /// **'影音娱乐'** + String get appsEntertain; + + /// 应用页常用:相机 + /// + /// In zh, this message translates to: + /// **'相机'** + String get appsCamera; + + /// 应用页常用:添加 + /// + /// In zh, this message translates to: + /// **'添加'** + String get appsAdd; + + /// 菜单:相册 + /// + /// In zh, this message translates to: + /// **'相册'** + String get menuAlbum; + + /// 菜单:闹钟 + /// + /// In zh, this message translates to: + /// **'闹钟'** + String get menuAlarm; + + /// 菜单:联系人 + /// + /// In zh, this message translates to: + /// **'联系人'** + String get menuContacts; + + /// 菜单:文件 + /// + /// In zh, this message translates to: + /// **'文件'** + String get menuFiles; + + /// 菜单:应用 + /// + /// In zh, this message translates to: + /// **'应用'** + String get menuApps; + + /// 菜单:更多 + /// + /// In zh, this message translates to: + /// **'更多'** + String get menuMore; + + /// 常用功能:远程相机 + /// + /// In zh, this message translates to: + /// **'远程相机'** + String get cfRemoteCam; + + /// 常用功能:更多 + /// + /// In zh, this message translates to: + /// **'更多'** + String get cfMore; + + /// 联系人页标题 + /// + /// In zh, this message translates to: + /// **'联系人'** + String get contactsTitle; + + /// 联系人分组:常用 + /// + /// In zh, this message translates to: + /// **'★ 常用'** + String get grpFavorite; + + /// 联系人分组:同事 + /// + /// In zh, this message translates to: + /// **'同事'** + String get grpColleague; + + /// 联系人分组:家人 + /// + /// In zh, this message translates to: + /// **'家人'** + String get grpFamily; + + /// 底部导航:管理 + /// + /// In zh, this message translates to: + /// **'管理'** + String get tabManage; + + /// 首页导航标题 + /// + /// In zh, this message translates to: + /// **'我的平板'** + String get homeDeviceName; + + /// 设备在线状态 + /// + /// In zh, this message translates to: + /// **'在线'** + String get homeOnline; + + /// 首页常用功能 + /// + /// In zh, this message translates to: + /// **'常用功能'** + String get homeCommon; + + /// 首页实时位置卡片 + /// + /// In zh, this message translates to: + /// **'实时位置'** + String get homeLocation; + + /// 定位中提示 + /// + /// In zh, this message translates to: + /// **'定位中'** + String get homeLocating; + + /// 示例设备地址 + /// + /// In zh, this message translates to: + /// **'望京 SOHO · T3 座'** + String get homeAddress; + + /// 首页最近截图卡片 + /// + /// In zh, this message translates to: + /// **'最近截图'** + String get homeScreenshots; + + /// 查看全部入口 + /// + /// In zh, this message translates to: + /// **'查看全部'** + String get homeViewAll; + + /// 首页使用时长卡片 + /// + /// In zh, this message translates to: + /// **'今日使用时长'** + String get homeUsage; + + /// 使用趋势入口 + /// + /// In zh, this message translates to: + /// **'较昨日 ↓ 12%'** + String get homeUsageTrend; + + /// 今日使用时长 + /// + /// In zh, this message translates to: + /// **'今日'** + String get homeUsageToday; + + /// 首页设备操作卡片 + /// + /// In zh, this message translates to: + /// **'设备操作'** + String get homeDeviceOps; + + /// 设备操作:重启 + /// + /// In zh, this message translates to: + /// **'重启'** + String get opRestart; + + /// 设备操作:关机 + /// + /// In zh, this message translates to: + /// **'关机'** + String get opShutdown; + + /// 设备操作:截屏 + /// + /// In zh, this message translates to: + /// **'截屏'** + String get opScreenshot; + + /// 设备操作:刷新 + /// + /// In zh, this message translates to: + /// **'刷新'** + String get opRefresh; + + /// 设备操作:定位 + /// + /// In zh, this message translates to: + /// **'定位'** + String get opLocate; + + /// 常用功能:文件传输 + /// + /// In zh, this message translates to: + /// **'文件传输'** + String get cfFileTransfer; + + /// 常用功能:消息同步 + /// + /// In zh, this message translates to: + /// **'消息同步'** + String get cfMsgSync; + + /// 常用功能:一键清理 + /// + /// In zh, this message translates to: + /// **'清理加速'** + String get cfClean; + + /// 常用功能:屏幕镜像 + /// + /// In zh, this message translates to: + /// **'屏幕镜像'** + String get cfMirror; + + /// 常用功能:防丢失 + /// + /// In zh, this message translates to: + /// **'丢失提醒'** + String get cfLost; + + /// 常用功能:应用锁 + /// + /// In zh, this message translates to: + /// **'应用锁'** + String get cfAppLock; + + /// 消息:设备上线 + /// + /// In zh, this message translates to: + /// **'设备上线提醒'** + String get msgOnline; + + /// 消息:新截图 + /// + /// In zh, this message translates to: + /// **'截图同步'** + String get msgScreenshot; + + /// 消息:远程协助 + /// + /// In zh, this message translates to: + /// **'远程协助'** + String get msgRemote; + + /// 消息:电量提醒 + /// + /// In zh, this message translates to: + /// **'电量提醒'** + String get msgBattery; + + /// 消息:系统更新 + /// + /// In zh, this message translates to: + /// **'系统更新'** + String get msgUpdate; + + /// 管理页导航标题 + /// + /// In zh, this message translates to: + /// **'管理'** + String get manageTitle; + + /// 管理页副标题 + /// + /// In zh, this message translates to: + /// **'设备内容与消息中心'** + String get manageSubtitle; + + /// 全部已读按钮 + /// + /// In zh, this message translates to: + /// **'全部已读'** + String get msgAllRead; + + /// 个人资料编辑按钮 + /// + /// In zh, this message translates to: + /// **'编辑资料'** + String get profileEdit; + + /// 我的页已绑定设备分组 + /// + /// In zh, this message translates to: + /// **'已绑定设备'** + String get deviceBound; + + /// 绑定设备:平板 + /// + /// In zh, this message translates to: + /// **'我的平板 Pro'** + String get devTablet; + + /// 绑定设备:手表 + /// + /// In zh, this message translates to: + /// **'智能手表'** + String get devWatch; + + /// 我的页个人资料分组 + /// + /// In zh, this message translates to: + /// **'个人资料'** + String get profileInfo; + + /// 个人资料:头像 + /// + /// In zh, this message translates to: + /// **'头像'** + String get piAvatar; + + /// 个人资料:昵称 + /// + /// In zh, this message translates to: + /// **'昵称'** + String get piName; + + /// 个人资料:个性签名 + /// + /// In zh, this message translates to: + /// **'个性签名'** + String get piSign; + + /// 我的页设置分组 + /// + /// In zh, this message translates to: + /// **'设置'** + String get settingsTitle; + + /// 设置:通知 + /// + /// In zh, this message translates to: + /// **'通知设置'** + String get setNotify; + + /// 设置:隐私 + /// + /// In zh, this message translates to: + /// **'隐私设置'** + String get setPrivacy; + + /// 设置:安全 + /// + /// In zh, this message translates to: + /// **'账号与安全'** + String get setSecurity; + + /// 设置:帮助 + /// + /// In zh, this message translates to: + /// **'帮助与反馈'** + String get setHelp; + + /// 设置:关于 + /// + /// In zh, this message translates to: + /// **'关于'** + String get setAbout; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 7206fc8..1e710eb 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -151,4 +151,205 @@ class AppLocalizationsEn extends AppLocalizations { @override String get privacyPolicyContent => 'Privacy Policy\n\nWe take your privacy seriously. This policy explains how we collect, use, store, and protect your personal information.\n\n1. Information We Collect\nWe may collect information you provide (e.g., phone number, nickname) and device/log data for security and troubleshooting.\n\n2. How We Use Information\nYour information is used solely to provide and improve the service, secure your account, and send necessary notices.\n\n3. Storage\nWe apply reasonable safeguards such as encryption and retain information only as long as necessary, then delete or anonymize it.\n\n4. Sharing\nWe do not disclose personal information to third parties except as required by law or to fulfill a service you requested.\n\n5. Your Rights\nYou may access, correct, or delete your personal information and withdraw granted consents.\n\n6. Changes\nWe will update this policy within the App; please review it periodically.'; + + @override + String get alarmTitle => 'Alarms'; + + @override + String get addAlarm => 'Add Alarm'; + + @override + String get albumTitle => 'Album'; + + @override + String get appsTitle => 'Apps'; + + @override + String get appsCommon => 'Common Apps'; + + @override + String get appsSystem => 'System Tools'; + + @override + String get appsEntertain => 'Entertainment'; + + @override + String get appsCamera => 'Camera'; + + @override + String get appsAdd => 'Add'; + + @override + String get menuAlbum => 'Album'; + + @override + String get menuAlarm => 'Alarm'; + + @override + String get menuContacts => 'Contacts'; + + @override + String get menuFiles => 'Files'; + + @override + String get menuApps => 'Apps'; + + @override + String get menuMore => 'More'; + + @override + String get cfRemoteCam => 'Remote Camera'; + + @override + String get cfMore => 'More'; + + @override + String get contactsTitle => 'Contacts'; + + @override + String get grpFavorite => '★ Favorites'; + + @override + String get grpColleague => 'Colleagues'; + + @override + String get grpFamily => 'Family'; + + @override + String get tabManage => 'Manage'; + + @override + String get homeDeviceName => 'My Tablet'; + + @override + String get homeOnline => 'Online'; + + @override + String get homeCommon => 'Common Apps'; + + @override + String get homeLocation => 'Live Location'; + + @override + String get homeLocating => 'Locating…'; + + @override + String get homeAddress => 'Wangjing SOHO · T3'; + + @override + String get homeScreenshots => 'Recent Screenshots'; + + @override + String get homeViewAll => 'View All'; + + @override + String get homeUsage => 'Today\'s Usage'; + + @override + String get homeUsageTrend => '↓12% from yesterday'; + + @override + String get homeUsageToday => 'Today'; + + @override + String get homeDeviceOps => 'Device Actions'; + + @override + String get opRestart => 'Restart'; + + @override + String get opShutdown => 'Shut Down'; + + @override + String get opScreenshot => 'Screenshot'; + + @override + String get opRefresh => 'Refresh'; + + @override + String get opLocate => 'Locate'; + + @override + String get cfFileTransfer => 'File Transfer'; + + @override + String get cfMsgSync => 'Message Sync'; + + @override + String get cfClean => 'Clean & Boost'; + + @override + String get cfMirror => 'Screen Mirror'; + + @override + String get cfLost => 'Loss Alert'; + + @override + String get cfAppLock => 'App Lock'; + + @override + String get msgOnline => 'Device Online Alert'; + + @override + String get msgScreenshot => 'Screenshot Sync'; + + @override + String get msgRemote => 'Remote Help'; + + @override + String get msgBattery => 'Battery Alert'; + + @override + String get msgUpdate => 'System Update'; + + @override + String get manageTitle => 'Manage'; + + @override + String get manageSubtitle => 'Device Content & Messages'; + + @override + String get msgAllRead => 'Mark All Read'; + + @override + String get profileEdit => 'Edit Profile'; + + @override + String get deviceBound => 'Bound Devices'; + + @override + String get devTablet => 'My Tablet Pro'; + + @override + String get devWatch => 'Smart Watch'; + + @override + String get profileInfo => 'Profile Info'; + + @override + String get piAvatar => 'Avatar'; + + @override + String get piName => 'Nickname'; + + @override + String get piSign => 'Signature'; + + @override + String get settingsTitle => 'Settings'; + + @override + String get setNotify => 'Notifications'; + + @override + String get setPrivacy => 'Privacy'; + + @override + String get setSecurity => 'Account & Security'; + + @override + String get setHelp => 'Help & Feedback'; + + @override + String get setAbout => 'About'; } diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index e0bb655..027ee57 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -150,4 +150,205 @@ class AppLocalizationsZh extends AppLocalizations { @override String get privacyPolicyContent => '《隐私政策》\n\n我们高度重视您的隐私保护。本政策说明我们如何收集、使用、存储和保护您的个人信息。\n\n一、信息收集\n我们可能收集以下信息:\n1. 您主动提供的信息,如手机号、昵称。\n2. 设备与日志信息,用于保障服务安全与故障排查。\n\n二、信息使用\n您的信息仅用于提供和改进本应用服务、保障账户安全及必要的通知。\n\n三、信息存储\n我们采取加密等合理措施保护您的信息,并在必要的期限内保存,超出期限将予以删除或匿名化处理。\n\n四、信息共享\n除法律法规要求或为完成您所请求的服务外,我们不会向第三方披露您的个人信息。\n\n五、您的权利\n您有权查询、更正或删除您的个人信息,并可撤回已授予的授权。\n\n六、政策变更\n本政策变更后将在应用内更新,请您定期查阅。\n\n如您对隐私保护有任何疑问,请联系我们的客服。'; + + @override + String get alarmTitle => '闹钟'; + + @override + String get addAlarm => '添加闹钟'; + + @override + String get albumTitle => '相册'; + + @override + String get appsTitle => '应用'; + + @override + String get appsCommon => '常用功能'; + + @override + String get appsSystem => '系统工具'; + + @override + String get appsEntertain => '影音娱乐'; + + @override + String get appsCamera => '相机'; + + @override + String get appsAdd => '添加'; + + @override + String get menuAlbum => '相册'; + + @override + String get menuAlarm => '闹钟'; + + @override + String get menuContacts => '联系人'; + + @override + String get menuFiles => '文件'; + + @override + String get menuApps => '应用'; + + @override + String get menuMore => '更多'; + + @override + String get cfRemoteCam => '远程相机'; + + @override + String get cfMore => '更多'; + + @override + String get contactsTitle => '联系人'; + + @override + String get grpFavorite => '★ 常用'; + + @override + String get grpColleague => '同事'; + + @override + String get grpFamily => '家人'; + + @override + String get tabManage => '管理'; + + @override + String get homeDeviceName => '我的平板'; + + @override + String get homeOnline => '在线'; + + @override + String get homeCommon => '常用功能'; + + @override + String get homeLocation => '实时位置'; + + @override + String get homeLocating => '定位中'; + + @override + String get homeAddress => '望京 SOHO · T3 座'; + + @override + String get homeScreenshots => '最近截图'; + + @override + String get homeViewAll => '查看全部'; + + @override + String get homeUsage => '今日使用时长'; + + @override + String get homeUsageTrend => '较昨日 ↓ 12%'; + + @override + String get homeUsageToday => '今日'; + + @override + String get homeDeviceOps => '设备操作'; + + @override + String get opRestart => '重启'; + + @override + String get opShutdown => '关机'; + + @override + String get opScreenshot => '截屏'; + + @override + String get opRefresh => '刷新'; + + @override + String get opLocate => '定位'; + + @override + String get cfFileTransfer => '文件传输'; + + @override + String get cfMsgSync => '消息同步'; + + @override + String get cfClean => '清理加速'; + + @override + String get cfMirror => '屏幕镜像'; + + @override + String get cfLost => '丢失提醒'; + + @override + String get cfAppLock => '应用锁'; + + @override + String get msgOnline => '设备上线提醒'; + + @override + String get msgScreenshot => '截图同步'; + + @override + String get msgRemote => '远程协助'; + + @override + String get msgBattery => '电量提醒'; + + @override + String get msgUpdate => '系统更新'; + + @override + String get manageTitle => '管理'; + + @override + String get manageSubtitle => '设备内容与消息中心'; + + @override + String get msgAllRead => '全部已读'; + + @override + String get profileEdit => '编辑资料'; + + @override + String get deviceBound => '已绑定设备'; + + @override + String get devTablet => '我的平板 Pro'; + + @override + String get devWatch => '智能手表'; + + @override + String get profileInfo => '个人资料'; + + @override + String get piAvatar => '头像'; + + @override + String get piName => '昵称'; + + @override + String get piSign => '个性签名'; + + @override + String get settingsTitle => '设置'; + + @override + String get setNotify => '通知设置'; + + @override + String get setPrivacy => '隐私设置'; + + @override + String get setSecurity => '账号与安全'; + + @override + String get setHelp => '帮助与反馈'; + + @override + String get setAbout => '关于'; } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 78236af..f4ae97a 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -46,5 +46,72 @@ "resetPassword": "Reset Password", "resetPasswordSuccess": "Password reset successfully, please sign in with the new password", "userAgreementContent": "Terms of Service\n\nWelcome to TongTong Family Care (the \"App\"). Please read the following terms carefully before using the App. By using the App, you acknowledge that you have read, understood, and agreed to all provisions of this agreement.\n\n1. Service Description\nThe App is a family care tool providing device connection, remote assistance, and messaging. We reserve the right to adjust, suspend, or terminate parts of the service at any time.\n\n2. Account Registration and Use\nYou must register with a valid phone number and are responsible for all activities under your account. Keep your credentials secure.\n\n3. User Conduct\nYou may not use the App for any unlawful, infringing, or disruptive activity.\n\n4. Intellectual Property\nAll intellectual property related to the App belongs to the developer. No reproduction or commercial use is permitted without permission.\n\n5. Limitation of Liability\nTo the extent permitted by law, we are not liable for indirect damages arising from use or inability to use the service.\n\n6. Changes\nWe may revise this agreement; continued use constitutes acceptance of the revised terms.", - "privacyPolicyContent": "Privacy Policy\n\nWe take your privacy seriously. This policy explains how we collect, use, store, and protect your personal information.\n\n1. Information We Collect\nWe may collect information you provide (e.g., phone number, nickname) and device/log data for security and troubleshooting.\n\n2. How We Use Information\nYour information is used solely to provide and improve the service, secure your account, and send necessary notices.\n\n3. Storage\nWe apply reasonable safeguards such as encryption and retain information only as long as necessary, then delete or anonymize it.\n\n4. Sharing\nWe do not disclose personal information to third parties except as required by law or to fulfill a service you requested.\n\n5. Your Rights\nYou may access, correct, or delete your personal information and withdraw granted consents.\n\n6. Changes\nWe will update this policy within the App; please review it periodically." + "privacyPolicyContent": "Privacy Policy\n\nWe take your privacy seriously. This policy explains how we collect, use, store, and protect your personal information.\n\n1. Information We Collect\nWe may collect information you provide (e.g., phone number, nickname) and device/log data for security and troubleshooting.\n\n2. How We Use Information\nYour information is used solely to provide and improve the service, secure your account, and send necessary notices.\n\n3. Storage\nWe apply reasonable safeguards such as encryption and retain information only as long as necessary, then delete or anonymize it.\n\n4. Sharing\nWe do not disclose personal information to third parties except as required by law or to fulfill a service you requested.\n\n5. Your Rights\nYou may access, correct, or delete your personal information and withdraw granted consents.\n\n6. Changes\nWe will update this policy within the App; please review it periodically.", + "alarmTitle": "Alarms", + "addAlarm": "Add Alarm", + "albumTitle": "Album", + "appsTitle": "Apps", + "appsCommon": "Common Apps", + "appsSystem": "System Tools", + "appsEntertain": "Entertainment", + "appsCamera": "Camera", + "appsAdd": "Add", + "menuAlbum": "Album", + "menuAlarm": "Alarm", + "menuContacts": "Contacts", + "menuFiles": "Files", + "menuApps": "Apps", + "menuMore": "More", + "cfRemoteCam": "Remote Camera", + "cfMore": "More", + "contactsTitle": "Contacts", + "grpFavorite": "★ Favorites", + "grpColleague": "Colleagues", + "grpFamily": "Family", + "tabManage": "Manage", + "homeDeviceName": "My Tablet", + "homeOnline": "Online", + "homeCommon": "Common Apps", + "homeLocation": "Live Location", + "homeLocating": "Locating…", + "homeAddress": "Wangjing SOHO · T3", + "homeScreenshots": "Recent Screenshots", + "homeViewAll": "View All", + "homeUsage": "Today's Usage", + "homeUsageTrend": "↓12% from yesterday", + "homeUsageToday": "Today", + "homeDeviceOps": "Device Actions", + "opRestart": "Restart", + "opShutdown": "Shut Down", + "opScreenshot": "Screenshot", + "opRefresh": "Refresh", + "opLocate": "Locate", + "cfFileTransfer": "File Transfer", + "cfMsgSync": "Message Sync", + "cfClean": "Clean & Boost", + "cfMirror": "Screen Mirror", + "cfLost": "Loss Alert", + "cfAppLock": "App Lock", + "msgOnline": "Device Online Alert", + "msgScreenshot": "Screenshot Sync", + "msgRemote": "Remote Help", + "msgBattery": "Battery Alert", + "msgUpdate": "System Update", + "manageTitle": "Manage", + "manageSubtitle": "Device Content & Messages", + "msgAllRead": "Mark All Read", + "profileEdit": "Edit Profile", + "deviceBound": "Bound Devices", + "devTablet": "My Tablet Pro", + "devWatch": "Smart Watch", + "profileInfo": "Profile Info", + "piAvatar": "Avatar", + "piName": "Nickname", + "piSign": "Signature", + "settingsTitle": "Settings", + "setNotify": "Notifications", + "setPrivacy": "Privacy", + "setSecurity": "Account & Security", + "setHelp": "Help & Feedback", + "setAbout": "About" } diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 82d1871..dfb3913 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -187,5 +187,273 @@ "privacyPolicyContent": "《隐私政策》\n\n我们高度重视您的隐私保护。本政策说明我们如何收集、使用、存储和保护您的个人信息。\n\n一、信息收集\n我们可能收集以下信息:\n1. 您主动提供的信息,如手机号、昵称。\n2. 设备与日志信息,用于保障服务安全与故障排查。\n\n二、信息使用\n您的信息仅用于提供和改进本应用服务、保障账户安全及必要的通知。\n\n三、信息存储\n我们采取加密等合理措施保护您的信息,并在必要的期限内保存,超出期限将予以删除或匿名化处理。\n\n四、信息共享\n除法律法规要求或为完成您所请求的服务外,我们不会向第三方披露您的个人信息。\n\n五、您的权利\n您有权查询、更正或删除您的个人信息,并可撤回已授予的授权。\n\n六、政策变更\n本政策变更后将在应用内更新,请您定期查阅。\n\n如您对隐私保护有任何疑问,请联系我们的客服。", "@privacyPolicyContent": { "description": "隐私政策正文" + }, + "alarmTitle": "闹钟", + "@alarmTitle": { + "description": "闹钟页标题" + }, + "addAlarm": "添加闹钟", + "@addAlarm": { + "description": "添加闹钟按钮" + }, + "albumTitle": "相册", + "@albumTitle": { + "description": "相册页标题" + }, + "appsTitle": "应用", + "@appsTitle": { + "description": "应用页标题" + }, + "appsCommon": "常用功能", + "@appsCommon": { + "description": "常用功能分组" + }, + "appsSystem": "系统工具", + "@appsSystem": { + "description": "系统工具分组" + }, + "appsEntertain": "影音娱乐", + "@appsEntertain": { + "description": "影音娱乐分组" + }, + "appsCamera": "相机", + "@appsCamera": { + "description": "应用页常用:相机" + }, + "appsAdd": "添加", + "@appsAdd": { + "description": "应用页常用:添加" + }, + "menuAlbum": "相册", + "@menuAlbum": { + "description": "菜单:相册" + }, + "menuAlarm": "闹钟", + "@menuAlarm": { + "description": "菜单:闹钟" + }, + "menuContacts": "联系人", + "@menuContacts": { + "description": "菜单:联系人" + }, + "menuFiles": "文件", + "@menuFiles": { + "description": "菜单:文件" + }, + "menuApps": "应用", + "@menuApps": { + "description": "菜单:应用" + }, + "menuMore": "更多", + "@menuMore": { + "description": "菜单:更多" + }, + "cfRemoteCam": "远程相机", + "@cfRemoteCam": { + "description": "常用功能:远程相机" + }, + "cfMore": "更多", + "@cfMore": { + "description": "常用功能:更多" + }, + "contactsTitle": "联系人", + "@contactsTitle": { + "description": "联系人页标题" + }, + "grpFavorite": "★ 常用", + "@grpFavorite": { + "description": "联系人分组:常用" + }, + "grpColleague": "同事", + "@grpColleague": { + "description": "联系人分组:同事" + }, + "grpFamily": "家人", + "@grpFamily": { + "description": "联系人分组:家人" + }, + "tabManage": "管理", + "@tabManage": { + "description": "底部导航:管理" + }, + "homeDeviceName": "我的平板", + "@homeDeviceName": { + "description": "首页导航标题" + }, + "homeOnline": "在线", + "@homeOnline": { + "description": "设备在线状态" + }, + "homeCommon": "常用功能", + "@homeCommon": { + "description": "首页常用功能" + }, + "homeLocation": "实时位置", + "@homeLocation": { + "description": "首页实时位置卡片" + }, + "homeLocating": "定位中", + "@homeLocating": { + "description": "定位中提示" + }, + "homeAddress": "望京 SOHO · T3 座", + "@homeAddress": { + "description": "示例设备地址" + }, + "homeScreenshots": "最近截图", + "@homeScreenshots": { + "description": "首页最近截图卡片" + }, + "homeViewAll": "查看全部", + "@homeViewAll": { + "description": "查看全部入口" + }, + "homeUsage": "今日使用时长", + "@homeUsage": { + "description": "首页使用时长卡片" + }, + "homeUsageTrend": "较昨日 ↓ 12%", + "@homeUsageTrend": { + "description": "使用趋势入口" + }, + "homeUsageToday": "今日", + "@homeUsageToday": { + "description": "今日使用时长" + }, + "homeDeviceOps": "设备操作", + "@homeDeviceOps": { + "description": "首页设备操作卡片" + }, + "opRestart": "重启", + "@opRestart": { + "description": "设备操作:重启" + }, + "opShutdown": "关机", + "@opShutdown": { + "description": "设备操作:关机" + }, + "opScreenshot": "截屏", + "@opScreenshot": { + "description": "设备操作:截屏" + }, + "opRefresh": "刷新", + "@opRefresh": { + "description": "设备操作:刷新" + }, + "opLocate": "定位", + "@opLocate": { + "description": "设备操作:定位" + }, + "cfFileTransfer": "文件传输", + "@cfFileTransfer": { + "description": "常用功能:文件传输" + }, + "cfMsgSync": "消息同步", + "@cfMsgSync": { + "description": "常用功能:消息同步" + }, + "cfClean": "清理加速", + "@cfClean": { + "description": "常用功能:一键清理" + }, + "cfMirror": "屏幕镜像", + "@cfMirror": { + "description": "常用功能:屏幕镜像" + }, + "cfLost": "丢失提醒", + "@cfLost": { + "description": "常用功能:防丢失" + }, + "cfAppLock": "应用锁", + "@cfAppLock": { + "description": "常用功能:应用锁" + }, + "msgOnline": "设备上线提醒", + "@msgOnline": { + "description": "消息:设备上线" + }, + "msgScreenshot": "截图同步", + "@msgScreenshot": { + "description": "消息:新截图" + }, + "msgRemote": "远程协助", + "@msgRemote": { + "description": "消息:远程协助" + }, + "msgBattery": "电量提醒", + "@msgBattery": { + "description": "消息:电量提醒" + }, + "msgUpdate": "系统更新", + "@msgUpdate": { + "description": "消息:系统更新" + }, + "manageTitle": "管理", + "@manageTitle": { + "description": "管理页导航标题" + }, + "manageSubtitle": "设备内容与消息中心", + "@manageSubtitle": { + "description": "管理页副标题" + }, + "msgAllRead": "全部已读", + "@msgAllRead": { + "description": "全部已读按钮" + }, + "profileEdit": "编辑资料", + "@profileEdit": { + "description": "个人资料编辑按钮" + }, + "deviceBound": "已绑定设备", + "@deviceBound": { + "description": "我的页已绑定设备分组" + }, + "devTablet": "我的平板 Pro", + "@devTablet": { + "description": "绑定设备:平板" + }, + "devWatch": "智能手表", + "@devWatch": { + "description": "绑定设备:手表" + }, + "profileInfo": "个人资料", + "@profileInfo": { + "description": "我的页个人资料分组" + }, + "piAvatar": "头像", + "@piAvatar": { + "description": "个人资料:头像" + }, + "piName": "昵称", + "@piName": { + "description": "个人资料:昵称" + }, + "piSign": "个性签名", + "@piSign": { + "description": "个人资料:个性签名" + }, + "settingsTitle": "设置", + "@settingsTitle": { + "description": "我的页设置分组" + }, + "setNotify": "通知设置", + "@setNotify": { + "description": "设置:通知" + }, + "setPrivacy": "隐私设置", + "@setPrivacy": { + "description": "设置:隐私" + }, + "setSecurity": "账号与安全", + "@setSecurity": { + "description": "设置:安全" + }, + "setHelp": "帮助与反馈", + "@setHelp": { + "description": "设置:帮助" + }, + "setAbout": "关于", + "@setAbout": { + "description": "设置:关于" } } diff --git a/pubspec.lock b/pubspec.lock index 5b47bbc..ffb0c75 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -505,10 +505,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "1ca20c894b1717686a2319b8548763d812bc0aabdac580420a44c5178c57a867" + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.flutter-io.cn" source: hosted - version: "0.20.3" + version: "0.20.2" io: dependency: transitive description: @@ -609,10 +609,10 @@ packages: dependency: transitive description: name: matcher - sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.20" + version: "0.12.19" material_color_utilities: dependency: transitive description: @@ -633,10 +633,10 @@ packages: dependency: transitive description: name: meta - sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.flutter-io.cn" source: hosted - version: "1.19.0" + version: "1.18.0" mime: dependency: transitive description: @@ -1030,10 +1030,10 @@ packages: dependency: transitive description: name: test_api - sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.12" + version: "0.7.11" timing: dependency: transitive description: @@ -1062,10 +1062,10 @@ packages: dependency: transitive description: name: vector_math - sha256: f36f9f3be64c6198714492bb455c11056e33e2f85d9a0b676a48301e44fdcf47 + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.2" + version: "2.2.0" vm_service: dependency: transitive description: