diff --git a/lib/features/home/presentation/widgets/ImmersionHeader.dart b/lib/features/home/presentation/widgets/ImmersionHeader.dart index a37a46a3..87e8852b 100644 --- a/lib/features/home/presentation/widgets/ImmersionHeader.dart +++ b/lib/features/home/presentation/widgets/ImmersionHeader.dart @@ -16,11 +16,16 @@ class ImmersionHeader extends StatelessWidget { final DeviceEntity device; const ImmersionHeader({super.key, required this.device}); + String _formatName(String name, {int keepLength = 20}) { + if (name.length <= keepLength) return name; + return name.substring(name.length - keepLength); + } + @override Widget build(BuildContext context) { return Container( width: double.infinity, - height: 380, + height: 310, // 1. 修改这里:去掉 color: Colors.white,改用透明或背景色 decoration: const BoxDecoration( color: Colors.transparent, // 设为透明,直接透出 Scaffold 的 offWhite @@ -29,14 +34,14 @@ class ImmersionHeader extends StatelessWidget { children: [ // 背景文字占位 (SataBot) Positioned( - top: 140, + top: 130, left: 0, right: 0, child: Text( 'SataBot', textAlign: TextAlign.center, style: GoogleFonts.roboto( - fontSize: 100, + fontSize: 80, fontWeight: FontWeight.w900, // 2. 既然背景变深了,背景字可以稍微再淡一点点 color: Colors.black.withOpacity(0.08), @@ -46,11 +51,12 @@ class ImmersionHeader extends StatelessWidget { // 机器大图 Transform.translate( - offset: const Offset(20, 90), // 正数向右移动(例如 20 像素),负数向左 + offset: const Offset(30, 80), // 正数向右移动(例如 20 像素),负数向左 child: Center( child: Image.asset( 'assets/images/car.png', - width: 380, + width: 330, + height: 190, fit: BoxFit.contain, ), ), @@ -73,7 +79,7 @@ class ImmersionHeader extends StatelessWidget { children: [ // 设备名称和电量 Text( - device.displayName, + _formatName(device.displayName), style: GoogleFonts.roboto( fontSize: 22, fontWeight: FontWeight.w900, diff --git a/lib/features/machine_details/presentation/pages/machine_details_page.dart b/lib/features/machine_details/presentation/pages/machine_details_page.dart index 97948e01..e78e8764 100644 --- a/lib/features/machine_details/presentation/pages/machine_details_page.dart +++ b/lib/features/machine_details/presentation/pages/machine_details_page.dart @@ -2,33 +2,122 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; -class MachineDetailsPage extends StatelessWidget { - final DeviceEntity? device; // 接收传过来的设备数据 +class MachineDetailsPage extends StatefulWidget { + final DeviceEntity? device; const MachineDetailsPage({super.key, this.device}); @override - Widget build(BuildContext context) { - // 把 device 参数传递给 DeviceDetailPage - return DeviceDetailPage(device: device); - } + State createState() => _MachineDetailsPageState(); } -class DeviceDetailPage extends StatelessWidget { - final DeviceEntity? device; // 定义参数接收设备数据 +class _MachineDetailsPageState extends State { + late TextEditingController _nameController; + late String _deviceName; - // 构造函数接收 device 参数 - const DeviceDetailPage({super.key, this.device}); + @override + void initState() { + super.initState(); + + _deviceName = (widget.device?.deviceAlias?.trim().isEmpty ?? true) + ? '未知设备' + : widget.device!.deviceAlias!; + + _nameController = TextEditingController(); + } + + @override + void dispose() { + _nameController.dispose(); + super.dispose(); + } + + /// 弹出修改设备名称底部抽屉 + void _showEditNameSheet() { + _nameController.text = _deviceName; + + showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (ctx) { + return Padding( + padding: EdgeInsets.only( + left: 20, + right: 20, + top: 20, + bottom: MediaQuery.of(ctx).viewInsets.bottom + 20, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + "修改设备名称", + style: TextStyle(fontSize: 17, fontWeight: FontWeight.w600), + ), + const SizedBox(height: 16), + TextField( + controller: _nameController, + autofocus: true, + maxLength: 20, + decoration: const InputDecoration( + hintText: "请输入设备名称", + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 10), + Row( + children: [ + Expanded( + child: OutlinedButton( + onPressed: () => Navigator.pop(ctx), + child: const Text("取消"), + ), + ), + const SizedBox(width: 12), + Expanded( + child: OutlinedButton( + onPressed: () { + final text = _nameController.text.trim(); + + if (text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text("名称不能为空")), + ); + return; + } + + setState(() { + _deviceName = text; + }); + + Navigator.pop(ctx); + + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text("已修改为:$text"))); + }, + child: const Text("确认"), + ), + ), + ], + ), + ], + ), + ); + }, + ); + } @override Widget build(BuildContext context) { - // 空值校验:无设备数据时显示提示 - if (device == null) { + if (widget.device == null) { return const Scaffold(body: Center(child: Text("未获取到设备信息"))); } - // 非空断言:已经校验过 device 非空,放心使用 - final currentDevice = device!; + final currentDevice = widget.device!; return Scaffold( backgroundColor: const Color(0xFFF5F5F5), @@ -40,14 +129,14 @@ class DeviceDetailPage extends StatelessWidget { ), leading: IconButton( icon: const Icon(Icons.arrow_back_ios), - onPressed: () => Navigator.pop(context), // 正确返回上一页 + onPressed: () => Navigator.pop(context), ), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: [ - _buildDeviceStatusCard(currentDevice), // 传递设备数据 + _buildDeviceStatusCard(currentDevice), const SizedBox(height: 16), _buildBasicInfoCard(context, currentDevice), // 传递context和设备数据 const SizedBox(height: 16), @@ -60,7 +149,7 @@ class DeviceDetailPage extends StatelessWidget { ); } - // 设备状态卡片(接收设备数据参数) + /// 设备状态卡片 Widget _buildDeviceStatusCard(DeviceEntity device) { return Container( padding: const EdgeInsets.all(24), @@ -70,9 +159,8 @@ class DeviceDetailPage extends StatelessWidget { ), child: Column( children: [ - Image.asset('assets/images/car.png', width: 380, fit: BoxFit.contain), + Image.asset('assets/images/car.png', width: 300, fit: BoxFit.contain), const SizedBox(height: 12), - // 使用设备真实在线状态 Text( device.isOnline ? '在线' : '离线', style: TextStyle( @@ -95,9 +183,7 @@ class DeviceDetailPage extends StatelessWidget { : device.deviceAlias!; // 处理设备ID(空值兜底) final deviceId = device.deviceName ?? '未知ID'; - //print('激活时间:$device'); // 调试输出激活时间 - //final activeTime = device.activeTime != null ? device.activeTime : '未知时间'; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -119,14 +205,16 @@ class DeviceDetailPage extends StatelessWidget { context: context, // 关键:补上必填的context参数 icon: Icons.info_outline, label: '设备名称', - trailing: Row( - mainAxisSize: MainAxisSize.min, // 防止Row撑满宽度 - children: [ - // 显示真实设备名称 - Text(deviceName), - const SizedBox(width: 8), - const Icon(Icons.edit, size: 16, color: Color(0xFF007AFF)), - ], + trailing: GestureDetector( + onTap: _showEditNameSheet, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(_deviceName), + const SizedBox(width: 8), + const Icon(Icons.edit, size: 16, color: Color(0xFF007AFF)), + ], + ), ), ), const Divider(height: 32, color: Color(0xFFF0F0F0)), @@ -294,7 +382,7 @@ class DeviceDetailPage extends StatelessWidget { context: context, builder: (dialogContext) => AlertDialog( title: const Text('确认解绑'), - content: Text('确定要解绑【${device?.deviceAlias ?? '该设备'}】吗?'), + content: Text('确定要解绑【${_deviceName ?? '该设备'}】吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), diff --git a/lib/features/main_container/presentation/main_wrapper.dart b/lib/features/main_container/presentation/main_wrapper.dart index 9f9db71c..efbe2d83 100644 --- a/lib/features/main_container/presentation/main_wrapper.dart +++ b/lib/features/main_container/presentation/main_wrapper.dart @@ -15,7 +15,7 @@ class MainWrapper extends StatelessWidget { extendBody: true, // 必须开启,让内容流过导航栏下方 body: navigationShell, bottomNavigationBar: Container( - margin: const EdgeInsets.fromLTRB(20, 0, 20, 32), // 稍微调高底部间距 + margin: const EdgeInsets.fromLTRB(20, 0, 20, 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(32), boxShadow: [