nibp.dart 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:vnote_device_plugin/devices/nibp.dart';
  4. import 'package:vnote_device_plugin/models/exams/nibp.dart';
  5. class NibpCard extends StatefulWidget {
  6. final String mac;
  7. final String model;
  8. const NibpCard({super.key, required this.mac, required this.model});
  9. @override
  10. State<StatefulWidget> createState() => _NibpCardState();
  11. }
  12. class _NibpCardState extends State<NibpCard> {
  13. late final NibpDeviceWorker worker = NibpDeviceWorker(
  14. mac: widget.mac,
  15. model: widget.model,
  16. );
  17. NibpExamValue? value;
  18. int? liveValue;
  19. bool _working = false;
  20. @override
  21. void initState() {
  22. worker.liveUpdateEvent.addListener(_onLiveUpdate);
  23. worker.resultUpdateEvent.addListener(_onSuccess);
  24. worker.errorEvent.addListener(_onError);
  25. super.initState();
  26. }
  27. @override
  28. void dispose() {
  29. worker.liveUpdateEvent.removeListener(_onLiveUpdate);
  30. worker.resultUpdateEvent.removeListener(_onSuccess);
  31. worker.errorEvent.removeListener(_onError);
  32. worker.disconnect();
  33. super.dispose();
  34. }
  35. void _onSuccess(_, NibpExamValue e) {
  36. setState(() {
  37. value = e;
  38. });
  39. }
  40. void _onLiveUpdate(_, int e) {
  41. setState(() {
  42. liveValue = e;
  43. });
  44. }
  45. void _onError(_, String e) {
  46. Get.snackbar(
  47. "提示",
  48. "测量错误: $e",
  49. snackPosition: SnackPosition.TOP,
  50. );
  51. }
  52. Widget _buildValue() {
  53. if (value != null) {
  54. return _buildResultWidget();
  55. }
  56. if (liveValue != null) {
  57. return _buildLiveWidget();
  58. }
  59. return const Center(
  60. child: Text(
  61. "00",
  62. style: TextStyle(fontSize: 80),
  63. ),
  64. );
  65. }
  66. Widget _buildLiveWidget() {
  67. final textStyle = TextStyle(fontSize: 80, color: Colors.orange.shade700);
  68. return Center(
  69. child: Text(
  70. liveValue!.toString(),
  71. style: textStyle,
  72. ),
  73. );
  74. }
  75. Widget _buildResultWidget() {
  76. const textStyle = TextStyle(fontSize: 48, color: Colors.green);
  77. return Stack(
  78. children: [
  79. Column(
  80. mainAxisAlignment: MainAxisAlignment.center,
  81. mainAxisSize: MainAxisSize.min,
  82. crossAxisAlignment: CrossAxisAlignment.center,
  83. children: [
  84. Align(
  85. alignment: Alignment.centerLeft,
  86. child: Text(
  87. value!.systolicPressure.toString(),
  88. style: textStyle,
  89. ),
  90. ),
  91. Align(
  92. alignment: Alignment.centerRight,
  93. child: Text(
  94. value!.diastolicPressure.toString(),
  95. style: textStyle,
  96. ),
  97. ),
  98. ],
  99. ),
  100. const Positioned.fill(
  101. child: Center(
  102. child: Text(
  103. " /",
  104. style: TextStyle(fontSize: 24),
  105. ),
  106. ),
  107. ),
  108. ],
  109. );
  110. }
  111. @override
  112. Widget build(BuildContext context) {
  113. return Card(
  114. elevation: 4,
  115. shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
  116. child: Container(
  117. alignment: Alignment.center,
  118. width: 360,
  119. height: 160,
  120. child: SizedBox(
  121. // height: 160,
  122. child: Row(
  123. mainAxisAlignment: MainAxisAlignment.center,
  124. crossAxisAlignment: CrossAxisAlignment.end,
  125. children: [
  126. SizedBox(width: 160, child: _buildValue()),
  127. const SizedBox(width: 8),
  128. Container(
  129. height: 100,
  130. alignment: Alignment.bottomCenter,
  131. child: const Text(
  132. "mmHg",
  133. style: TextStyle(fontSize: 18),
  134. ),
  135. ),
  136. const SizedBox(width: 8),
  137. SizedBox(
  138. width: 60,
  139. height: 60,
  140. child: _working
  141. ? OutlinedButton(
  142. style: ButtonStyle(
  143. backgroundColor: MaterialStatePropertyAll(
  144. Colors.red.withOpacity(.08),
  145. ),
  146. shape: MaterialStatePropertyAll(
  147. RoundedRectangleBorder(
  148. borderRadius: BorderRadius.circular(30),
  149. ),
  150. ),
  151. ),
  152. onPressed: () async {
  153. await worker.disconnect();
  154. setState(() {
  155. _working = false;
  156. value = null;
  157. liveValue = null;
  158. });
  159. },
  160. child: const Text(
  161. "停止",
  162. style: TextStyle(color: Colors.red),
  163. ),
  164. )
  165. : OutlinedButton(
  166. style: ButtonStyle(
  167. backgroundColor: MaterialStatePropertyAll(
  168. Theme.of(context).primaryColor.withOpacity(.08),
  169. ),
  170. shape: MaterialStatePropertyAll(
  171. RoundedRectangleBorder(
  172. borderRadius: BorderRadius.circular(30),
  173. ),
  174. ),
  175. ),
  176. onPressed: () async {
  177. await worker.connect();
  178. setState(() {
  179. _working = true;
  180. });
  181. },
  182. child: const Text("开始"),
  183. ),
  184. ),
  185. ],
  186. ),
  187. ),
  188. ),
  189. );
  190. }
  191. }