127 lines
4.0 KiB
Dart
127 lines
4.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../services/ble_service.dart';
|
|
|
|
class DataPacketCard extends StatelessWidget {
|
|
final DataPacket packet;
|
|
|
|
const DataPacketCard({super.key, required this.packet});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final timeStr = '${packet.timestamp.hour.toString().padLeft(2, '0')}:'
|
|
'${packet.timestamp.minute.toString().padLeft(2, '0')}:'
|
|
'${packet.timestamp.second.toString().padLeft(2, '0')}';
|
|
|
|
return Card(
|
|
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
child: ExpansionTile(
|
|
leading: CircleAvatar(
|
|
backgroundColor: Theme.of(context).primaryColor,
|
|
child: Text(
|
|
'#${packet.packetNumber}',
|
|
style: const TextStyle(color: Colors.white, fontSize: 12),
|
|
),
|
|
),
|
|
title: Text(
|
|
packet.hexString,
|
|
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
|
|
),
|
|
subtitle: Text('$timeStr • ${packet.data.length} bytes'),
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
_buildSection('Hex', packet.hexString),
|
|
const SizedBox(height: 8),
|
|
// 'timbang' style: bytes shown in decimal (matching Python output)
|
|
_buildSection('timbang', packet.bytesString),
|
|
const SizedBox(height: 16),
|
|
if (packet.value32BitUnsigned != null) ...[
|
|
_buildValueRow(
|
|
'32-bit Unsigned (BE)',
|
|
packet.value32BitUnsigned.toString(),
|
|
),
|
|
_buildValueRow(
|
|
'32-bit Signed (BE)',
|
|
packet.value32BitSigned.toString(),
|
|
),
|
|
if (packet.value32BitUnsigned! > 0) ...[
|
|
_buildValueRow(
|
|
'As Float (÷100)',
|
|
(packet.value32BitUnsigned! / 100.0).toStringAsFixed(2),
|
|
),
|
|
_buildValueRow(
|
|
'As Float (÷1000)',
|
|
(packet.value32BitUnsigned! / 1000.0).toStringAsFixed(3),
|
|
),
|
|
],
|
|
],
|
|
if (packet.value16BitUnsigned != null) ...[
|
|
const SizedBox(height: 8),
|
|
_buildValueRow(
|
|
'16-bit Unsigned (BE)',
|
|
packet.value16BitUnsigned.toString(),
|
|
),
|
|
_buildValueRow(
|
|
'16-bit Signed (BE)',
|
|
packet.value16BitSigned.toString(),
|
|
),
|
|
],
|
|
if (packet.asciiString != null) ...[
|
|
const SizedBox(height: 8),
|
|
_buildSection('ASCII', packet.asciiString!),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildSection(String label, String value) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: const TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 12,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
SelectableText(
|
|
value,
|
|
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildValueRow(String label, String value) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
|
),
|
|
Text(
|
|
value,
|
|
style: const TextStyle(
|
|
fontFamily: 'monospace',
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|