Files
tuiche/lib/pages/mh_page/MattressControl.dart
2025-06-17 18:02:51 +08:00

387 lines
13 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutter_switch/flutter_switch.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
class MattressControlPage extends StatefulWidget {
const MattressControlPage({super.key});
@override
State<MattressControlPage> createState() => _MattressControlPageState();
}
class _MattressControlPageState extends State<MattressControlPage> {
final controller = Get.put(ControlCardController());
final data = {
"_id": "684bf0845a81f423c0000000",
"uid": "68465947a0cff49592000000",
"bind_type": 1,
"device_type": 3,
"mac": "545024122617",
"bind_mac": null,
"bind_mac_a": "48CA43B2E8C8",
"bind_mac_b": "48CA43B2E8B0",
"position": 0,
"share_uid": null,
"person": null,
"op_type": null,
"show": true,
"create_time": 1749807236514,
"shareNum": 0,
"status": {
"signal": -1,
"status": 0,
"inBed": 0,
"upgrade": 0,
"failure": 0,
"updateTime": -1
},
"code": "545024122617"
};
int selectedIndex = 1; // 当前选中的tab索引
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image:
AssetImage('assets/images/new_background.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
// 顶部返回 + 设备选择 + 蓝牙图标 + 设置按钮
appBar: AppBar(
backgroundColor: Colors.transparent,
automaticallyImplyLeading: false,
titleSpacing: 0,
elevation: 0,
title: SizedBox(
width: double.infinity,
height: 180.rpx,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(width: 20.rpx),
returnIconButtomNew,
SizedBox(width: 26.rpx),
Container(
decoration: BoxDecoration(
color: Color(0xFF003058),
borderRadius: BorderRadius.circular(30.rpx),
),
constraints: BoxConstraints(
minHeight: 60.rpx,
maxHeight: 60.rpx,
maxWidth: 260.rpx,
minWidth: 260.rpx),
padding: EdgeInsets.symmetric(
horizontal: 20.rpx), // 加左右边距
child: DropdownButton<String>(
value: 'Eason Chan',
underline: const SizedBox(),
dropdownColor: Colors.blueGrey,
iconEnabledColor: Colors.white,
style: const TextStyle(color: Colors.white),
isExpanded: true,
items: const [
DropdownMenuItem(
value: 'Eason Chan',
child: Text('Eason Chan'),
),
DropdownMenuItem(
value: 'Anna',
child: Text('Anna'),
),
],
onChanged: (_) {},
),
),
],
)),
actions: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.only(right: 69.rpx),
onTap: () {},
child: Icon(
Icons.bluetooth,
color: Colors.white,
size: 42.rpx,
),
),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.only(right: 38.rpx),
onTap: () {
Get.toNamed('/bluetoothPage', arguments: data);
},
child: Icon(Icons.tune,
color: Colors.white, size: 42.rpx))
],
centerTitle: false,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
"等待引入",
style: TextStyle(
color: Colors.white,
),
))
// _buildBedImageSection(context),
// _buildModeSelector(context),
// Expanded(child: _buildControlCards(context)),
],
),
),
))));
}
// 床体图示
Widget _buildBedImageSection(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 38.rpx, 0, 63.rpx),
child: Image.asset(
'assets/images/bed_control.png',
width: MediaQuery.of(context).size.width * 0.7, // 你需要准备这个图像资源
height: 193.rpx,
),
);
}
Widget _buildModeSelector(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width - 60.rpx; // 左右各30
final spacing = 20.0.rpx;
final thirdWidth = 215.rpx; // 三个卡片两个间距
final tabCount = 3;
final tabWidth = screenWidth / tabCount;
final sideMargin = (tabWidth - thirdWidth) / 2;
final labels = ['', '全局', ''];
return Padding(
padding: EdgeInsets.symmetric(horizontal: 30.rpx),
child: Stack(
children: [
Row(
children: List.generate(tabCount, (index) {
return Expanded(
child: GestureDetector(
onTap: () {
selectedIndex = index;
},
child: _selectorTab(
labels[index],
isSelected: selectedIndex == index,
sideMargin: sideMargin,
),
),
);
}),
),
// 白线指示器
Positioned(
bottom: 0,
left: selectedIndex * tabWidth + sideMargin,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: thirdWidth,
height: 3.rpx,
color: Colors.white,
),
),
],
),
);
}
Widget _selectorTab(String label,
{bool isSelected = false, double sideMargin = 0}) {
return Container(
margin: EdgeInsets.symmetric(horizontal: sideMargin),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
label,
style: TextStyle(
color: isSelected ? Colors.white : Colors.grey,
fontSize: 30.rpx,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
),
),
if (isSelected) SizedBox(height: 15.rpx), // 保留间距,避免文字和线重叠
],
),
);
}
Widget _buildControlCards(BuildContext context) {
final spacing = 20.0.rpx;
final List<Map<String, dynamic>> allCards = [
{'title': '一键助眠', 'time': '30:00'},
{'title': '疲劳缓解', 'time': '20:00'},
{'title': '全身放松', 'time': '20:00'},
{'title': '背部律动', 'time': '10:00'},
{'title': '腿部律动', 'time': '30:00'},
{'title': '垂直律动', 'time': ''},
{'title': '加热', 'time': '30:00'},
{'title': '柔性唤醒', 'time': 'PM 08:00'},
{'title': '记忆', 'time': ''},
];
final firstRow = allCards.sublist(0, 3);
final restCards = allCards.sublist(3);
// 后续每行两个
List<List<Map<String, dynamic>>> chunkedRows = [];
for (int i = 0; i < restCards.length; i += 2) {
int end = (i + 2 < restCards.length) ? i + 2 : restCards.length;
chunkedRows.add(restCards.sublist(i, end));
}
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 30.rpx, vertical: 30.rpx),
child: Column(
children: [
// 第一行:三个卡片
Row(
children: List.generate(firstRow.length * 2 - 1, (index) {
if (index.isOdd) {
return SizedBox(width: spacing); // 卡片间距
} else {
final item = firstRow[index ~/ 2];
return Expanded(
flex: 1,
child: _buildControlCard(
index ~/ 2,
item['title'],
item['time'],
// null, // 不再使用固定宽度
),
);
}
}),
),
SizedBox(height: spacing),
// 其余每行两个卡片
...chunkedRows.map((row) {
return Padding(
padding: EdgeInsets.only(bottom: spacing),
child: Row(
children: List.generate(row.length * 2 - 1, (index) {
if (index.isOdd) {
return SizedBox(width: spacing);
} else {
final item = row[index ~/ 2];
return Expanded(
flex: 1,
child: _buildControlCard(
index ~/ 2,
item['title'],
item['time'],
// null,
),
);
}
}),
),
);
}).toList(),
],
),
),
);
}
Widget _buildControlCard(
int index,
String title,
String time,
// double width,
) {
final controller = Get.find<ControlCardController>();
return Container(
// width: width,
height: 241.rpx,
decoration: BoxDecoration(
color: const Color(0xFF003058),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.all(15.rpx),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
SvgPicture.asset(
'assets/img/icon/group.svg',
width: 60.rpx,
height: 60.rpx,
color: Colors.white,
),
SizedBox(height: 22.rpx),
Text(
title,
style: TextStyle(color: Colors.white, fontSize: 30.rpx),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
time,
style: TextStyle(
color: const Color(0XFF929699),
fontSize: 26.rpx,
fontFamily: 'PingFang SC',
),
),
Obx(() => FlutterSwitch(
width: 71.rpx,
height: 36.rpx,
toggleSize: 30.rpx,
activeColor: const Color(0XFF6BFDAC),
inactiveColor: const Color(0XFF011D33),
value: controller.switchStates[index].value,
onToggle: (val) {
controller.switchStates[index].value = val;
},
)),
],
),
],
),
);
}
}
class ControlCardController extends GetxController {
// 共9个卡片每个卡片有自己的开关状态
final List<RxBool> switchStates = List.generate(9, (index) => false.obs);
}