- 新增首页平板信息卡片(定位、截图、使用时长、设备操作) - 将消息 Tab 改为管理 Tab,增加横版菜单与消息列表 - 新增相册、闹钟、联系人、应用子页面路由 - 统一主色为桐桐绿并优化调试日志输出
336 lines
13 KiB
Dart
336 lines
13 KiB
Dart
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});
|
||
|
||
@override
|
||
Widget build(BuildContext context, WidgetRef ref) {
|
||
final l10n = AppLocalizations.of(context);
|
||
return CupertinoPageScaffold(
|
||
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: 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)),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|