device_card.dart 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // ignore_for_file: non_constant_identifier_names, constant_identifier_names
  2. import 'package:flutter/material.dart';
  3. import 'package:vitalapp/managers/interfaces/models/device.dart';
  4. import 'package:vitalapp/pages/settings/devices/widgets/consts.dart';
  5. /// 设备卡片
  6. class DeviceCard extends StatelessWidget {
  7. static const Color _BOUND_COLOR = Colors.green;
  8. static final Color _UNBOUND_COLOR = Colors.orange.shade800;
  9. /// 设备类型
  10. final String type;
  11. /// 设备数据
  12. final DeviceModel? data;
  13. /// 点击绑定/解绑事件
  14. final ValueChanged<bool>? onTapChangeBind;
  15. const DeviceCard({
  16. super.key,
  17. required this.type,
  18. this.data,
  19. this.onTapChangeBind,
  20. });
  21. bool get hasData => data != null;
  22. @override
  23. Widget build(BuildContext context) {
  24. EdgeInsets padding =
  25. const EdgeInsets.symmetric(vertical: 12, horizontal: 16);
  26. final children = <Widget>[];
  27. children.add(_buildHeader());
  28. if (data != null) {
  29. children.add(const SizedBox(height: 8));
  30. final divider = Divider(
  31. height: 1,
  32. // indent: 8,
  33. // endIndent: 8,
  34. color: Colors.grey.shade300,
  35. );
  36. final cells = _buildInfoCells();
  37. for (final cell in cells) {
  38. children.add(divider);
  39. children.add(cell);
  40. }
  41. // 缩小下内距
  42. padding = padding.copyWith(bottom: 8);
  43. }
  44. return Container(
  45. padding: padding,
  46. decoration: BoxDecoration(
  47. color: Colors.white,
  48. borderRadius: BorderRadius.circular(8),
  49. border: Border.all(width: 1, color: Colors.grey.shade300),
  50. ),
  51. child: Column(
  52. children: children,
  53. ),
  54. );
  55. }
  56. List<Widget> _buildInfoCells() {
  57. return [
  58. _InfoCell("名称", data!.productName),
  59. _InfoCell("型号", data!.model),
  60. _InfoCell("Mac", data!.mac),
  61. ];
  62. }
  63. Widget _buildHeader() {
  64. return Row(
  65. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  66. children: [
  67. _ProductImage(type),
  68. Expanded(
  69. child: _buildTypeSummary(),
  70. ),
  71. _buildOperateButton(),
  72. ],
  73. );
  74. }
  75. Widget _buildTypeSummary() {
  76. final typeName = DevicesSettingConsts.getDeviceNameByType(type);
  77. return Container(
  78. alignment: Alignment.centerLeft,
  79. padding: const EdgeInsets.only(left: 12),
  80. child: Column(
  81. crossAxisAlignment: CrossAxisAlignment.start,
  82. children: [
  83. Text(
  84. typeName,
  85. style: const TextStyle(
  86. color: Colors.black,
  87. fontSize: 16,
  88. ),
  89. ),
  90. const SizedBox(height: 4),
  91. Row(
  92. crossAxisAlignment: CrossAxisAlignment.center,
  93. children: [
  94. SizedBox(
  95. width: 8,
  96. height: 8,
  97. child: CircleAvatar(
  98. backgroundColor: hasData ? _BOUND_COLOR : _UNBOUND_COLOR,
  99. ),
  100. ),
  101. const SizedBox(width: 4),
  102. Text(
  103. hasData ? "已绑定" : "未绑定",
  104. style: TextStyle(
  105. color: Colors.grey.shade600,
  106. fontSize: 14,
  107. ),
  108. ),
  109. ],
  110. ),
  111. ],
  112. ),
  113. );
  114. }
  115. Widget _buildOperateButton() {
  116. final color = hasData ? _UNBOUND_COLOR : _BOUND_COLOR;
  117. return TextButton(
  118. style: ButtonStyle(
  119. overlayColor: MaterialStatePropertyAll(color.withOpacity(.2)),
  120. ),
  121. onPressed: () {
  122. onTapChangeBind?.call(!hasData);
  123. },
  124. child: Row(
  125. children: [
  126. Text(
  127. hasData ? "解除绑定" : "去绑定",
  128. style: TextStyle(
  129. color: color,
  130. fontSize: 14,
  131. ),
  132. ),
  133. Icon(
  134. Icons.arrow_forward_ios,
  135. color: color,
  136. size: 12,
  137. ),
  138. ],
  139. ),
  140. );
  141. }
  142. }
  143. class _ProductImage extends StatelessWidget {
  144. final String type;
  145. const _ProductImage(this.type);
  146. @override
  147. Widget build(BuildContext context) {
  148. final path = "assets/images/device/icon/$type.png";
  149. return Container(
  150. width: 76,
  151. height: 76,
  152. decoration: BoxDecoration(
  153. color: Colors.grey.withOpacity(.08),
  154. borderRadius: BorderRadius.circular(8),
  155. ),
  156. child: Image.asset(
  157. path,
  158. fit: BoxFit.contain,
  159. ),
  160. );
  161. }
  162. }
  163. class _InfoCell extends StatelessWidget {
  164. static const double _CELL_HEIGHT = 46.0;
  165. static const double _FONT_SIZE = 16.0;
  166. static const _LABEL_STYLE =
  167. TextStyle(color: Colors.black, fontSize: _FONT_SIZE);
  168. static final _CONTENT_STYLE =
  169. TextStyle(color: Colors.grey.shade700, fontSize: _FONT_SIZE);
  170. final String label;
  171. final String content;
  172. const _InfoCell(
  173. this.label,
  174. this.content,
  175. );
  176. @override
  177. Widget build(BuildContext context) {
  178. return SizedBox(
  179. height: _CELL_HEIGHT,
  180. child: Row(
  181. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  182. children: [
  183. Text(label, style: _LABEL_STYLE),
  184. Text(content, style: _CONTENT_STYLE),
  185. ],
  186. ),
  187. );
  188. }
  189. }