Browse Source
- 底部:原「AI」tab 改名「首页」;中间新增圆形「AI」按钮(不是常驻页,点了才打开对话页, 避免百炼连接和麦克风常驻);右边「我的」。设备、拾忆不再是 tab - 首页顶栏:左上角产品小图标(DeviceStatusChip,已连接绿圈+绿点+电量,未连接置灰), 点进设备页 /device;右上角「编辑」紧挨「日历」,日历点进拾忆页 /recall。 两个独立页复用原 DeviceTab / TodoTab(standalone 模式带返回箭头,TabScaffold 新增 onBack) - AI 按钮:openAiAssistant() 按「当前连着、没连就最近连过的设备」→ 品类默认编排里第一个对话助手: EaiCar 香薰 → EaiCar 车载助手,其余 → navigateToAIAssistant(EMAI / 移动精灵) - 首页网格不再显示对话助手(AgentModuleService.assistantIds:EMAI、EaiCar),只是不显示, 编排与设备按键唤醒找 agent 不受影响;拖拽排序改走 moveOnHome 换算下标 - 三个扫描页连上后改为回到首页再打开设备页(showDeviceAfterConnect) 验证:dart analyze 无 error;flutter test 221 全过;release 包装到 ALN-AL80 真机点过首页、 日历、设备、AI 按钮(打开 EMAI)。连着 EaiCar 时打开 EaiCar 助手这条未实测。 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>main
15 changed files with 405 additions and 77 deletions
@ -0,0 +1,145 @@ |
|||
import 'package:device_plugin_interface/device_plugin_interface.dart'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
import '../../../../core/theme/app_palette.dart'; |
|||
import '../../../../core/utils/device_connection.dart'; |
|||
import '../../../../devices/device_hub.dart'; |
|||
import 'battery_indicator.dart'; |
|||
|
|||
/// AI 页左上角的设备入口:产品小图标 + 电量,点击进设备页。 |
|||
/// |
|||
/// - 已连接:图标外圈绿色,右下角一个绿点,旁边显示电量; |
|||
/// - 未连接:图标置灰,不显示电量。 |
|||
/// |
|||
/// 图标取「当前连着的、没连就最近连过的」那台设备([DeviceConnection.currentIconImage]), |
|||
/// 从没连过时是通用图。**不认厂商**:电量按 [DeviceBattery.summary] 有什么显示什么, |
|||
/// TWS 耳机给的是左右较低的一侧,支架这类拿不到电量的设备就只显示图标。 |
|||
class DeviceStatusChip extends StatelessWidget { |
|||
const DeviceStatusChip({ |
|||
Key? key, |
|||
required this.isDarkMode, |
|||
required this.onTap, |
|||
}) : super(key: key); |
|||
|
|||
final bool isDarkMode; |
|||
final VoidCallback onTap; |
|||
|
|||
/// 置灰矩阵(ITU-R BT.601 亮度系数),给未连接时的产品图标用 |
|||
static const ColorFilter _grayscale = ColorFilter.matrix(<double>[ |
|||
0.299, 0.587, 0.114, 0, 0, // |
|||
0.299, 0.587, 0.114, 0, 0, // |
|||
0.299, 0.587, 0.114, 0, 0, // |
|||
0, 0, 0, 1, 0, |
|||
]); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
final hub = DeviceHub.to; |
|||
return Obx(() { |
|||
// revision 随任一会话的 info(含电量)变化 +1,读一下让 Obx 收集到它 |
|||
hub.revision.value; |
|||
final bool connected = hub.anyConnected.value; |
|||
final DeviceInfo? info = hub.primaryInfo.value; |
|||
final DeviceBattery? battery = connected ? info?.battery : null; |
|||
final int? level = battery?.summary; |
|||
final bool charging = battery != null && |
|||
(battery.chargingSingle || |
|||
battery.chargingLeft || |
|||
battery.chargingRight); |
|||
|
|||
final Color ring = connected |
|||
? AppPalette.success |
|||
: (isDarkMode ? Colors.white24 : Colors.black12); |
|||
|
|||
Widget icon = Image.asset( |
|||
DeviceConnection.currentIconImage(), |
|||
width: 26.w, |
|||
height: 26.w, |
|||
fit: BoxFit.contain, |
|||
errorBuilder: (_, __, ___) => Icon( |
|||
Icons.devices_other, |
|||
size: 20.sp, |
|||
color: isDarkMode ? Colors.white54 : AppPalette.brand400, |
|||
), |
|||
); |
|||
if (!connected) { |
|||
icon = Opacity( |
|||
opacity: 0.55, |
|||
child: ColorFiltered(colorFilter: _grayscale, child: icon), |
|||
); |
|||
} |
|||
|
|||
return GestureDetector( |
|||
behavior: HitTestBehavior.opaque, |
|||
onTap: onTap, |
|||
child: Row( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: [ |
|||
SizedBox( |
|||
width: 36.w, |
|||
height: 36.w, |
|||
child: Stack( |
|||
clipBehavior: Clip.none, |
|||
children: [ |
|||
Container( |
|||
width: 36.w, |
|||
height: 36.w, |
|||
alignment: Alignment.center, |
|||
decoration: BoxDecoration( |
|||
color: isDarkMode |
|||
? Colors.white.withOpacity(0.06) |
|||
: Colors.white, |
|||
shape: BoxShape.circle, |
|||
border: Border.all( |
|||
color: ring, |
|||
width: connected ? 1.6 : 1, |
|||
), |
|||
boxShadow: [ |
|||
BoxShadow( |
|||
color: Colors.black |
|||
.withOpacity(isDarkMode ? 0.2 : 0.06), |
|||
blurRadius: 6, |
|||
offset: const Offset(0, 2), |
|||
), |
|||
], |
|||
), |
|||
child: icon, |
|||
), |
|||
if (connected) |
|||
Positioned( |
|||
right: 0, |
|||
bottom: 0, |
|||
child: Container( |
|||
width: 9.w, |
|||
height: 9.w, |
|||
decoration: BoxDecoration( |
|||
color: AppPalette.success, |
|||
shape: BoxShape.circle, |
|||
border: Border.all( |
|||
color: isDarkMode |
|||
? const Color(0xFF0A0F1A) |
|||
: Colors.white, |
|||
width: 1.5, |
|||
), |
|||
), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
if (level != null) ...[ |
|||
SizedBox(width: 6.w), |
|||
BatteryIndicator( |
|||
level: level, |
|||
isDarkMode: isDarkMode, |
|||
charging: charging, |
|||
), |
|||
], |
|||
], |
|||
), |
|||
); |
|||
}); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue