field_control.dart 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import 'package:application/service/api.dart' as pb;
  2. import 'package:application/widget.dart';
  3. import 'package:common_pub/ui/map_view/map_view.dart';
  4. import 'package:common_pub/ui/map_view/view_map_cp.dart';
  5. import 'package:common_pub/ui/map_view/view_map_image.dart';
  6. import 'package:common_pub/ui/map_view/view_map_trace_tail.dart';
  7. import 'package:common_pub/ui/map_view/view_map_touch.dart';
  8. import 'package:common_pub/ui/map_view/view_map_user_point.dart';
  9. import 'package:common_pub/ui/map_view/view_plug_loading.dart';
  10. import 'package:common_pub/utils.dart';
  11. import 'field_control_controller.dart';
  12. class FieldControlPage extends StatelessWidget {
  13. const FieldControlPage({super.key});
  14. @override
  15. Widget build(BuildContext context) {
  16. return GetBuilder(
  17. init: FieldControlController(),
  18. builder: (c) {
  19. return Container(
  20. height: double.infinity,
  21. width: double.infinity,
  22. color: const Color(0xffc9c0c0),
  23. alignment: Alignment.center,
  24. child: Obx(() {
  25. final mapWatch = c.mapWatch;
  26. return mapWatch != null
  27. ? content(context, mapWatch, c)
  28. : noData();
  29. }));
  30. });
  31. }
  32. Widget noData() {
  33. return Center(
  34. child: Column(
  35. mainAxisSize: MainAxisSize.min,
  36. children: [
  37. Image.asset(Assets.imagesIcNoData, height: 64),
  38. const SizedBox(height: 25),
  39. const Text('没有数据, 请选择地图',
  40. style: TextStyle(color: Color(0xff707070), fontSize: 18.5)),
  41. ],
  42. ),
  43. );
  44. }
  45. Widget content(
  46. BuildContext context, MapWatchService map, FieldControlController c) {
  47. final children = <Widget>[
  48. ViewPlugLoading(map.plugMap),
  49. ViewMapImage(map.plugMap),
  50. ];
  51. final focusUser = c.focusUser.value;
  52. if (focusUser != null) {
  53. children.add(ViewMapCP(
  54. map.plugMap,
  55. cpWantAndHistoryList: focusUser.cpList,
  56. isHideRouteBeforeStart: false,
  57. ));
  58. }
  59. children.addAll([
  60. _ViewTrace(map: map, traceDuration: 30.seconds),
  61. ViewMapTouch(map.plugMap)
  62. ]);
  63. return Row(
  64. children: [
  65. Expanded(
  66. child: Column(
  67. children: [
  68. Expanded(
  69. child: ViewMapStack(plug: map.plugMap, children: children)),
  70. _MsgView(),
  71. ],
  72. )),
  73. _ActiveInfoView()
  74. ],
  75. );
  76. }
  77. }
  78. class _ViewTrace extends GetView<FieldControlController> {
  79. const _ViewTrace({required this.map, required this.traceDuration});
  80. final MapWatchService map;
  81. final Duration traceDuration;
  82. @override
  83. Widget build(BuildContext context) {
  84. return Obx(() {
  85. final children = <Widget>[];
  86. for (final act in map.activeList) {
  87. for (final user in act.userList) {
  88. if (user.isHide.value) {
  89. continue;
  90. }
  91. final trace = user.trace.lastOrNull;
  92. final traceTailOnMap = <Offset>[];
  93. final st = user.gameInfo.gameSaveInfo.startAt.toModel();
  94. for (final one in user.trace) {
  95. if (DateTime.now().difference(st.add(one.ts)) < traceDuration) {
  96. traceTailOnMap.add(one.onMap);
  97. }
  98. }
  99. if (trace != null) {
  100. children.add(ViewMapTraceTail(
  101. plug: map.plugMap,
  102. onMapTrace: traceTailOnMap,
  103. color: user.flag.value.color,
  104. ));
  105. children.add(ViewMapUserPoint(map.plugMap, trace,
  106. info: user.name, color: user.flag.value.color));
  107. }
  108. }
  109. }
  110. return Stack(alignment: Alignment.topLeft, children: children);
  111. });
  112. }
  113. }
  114. class _ActiveInfoView extends GetView<FieldControlController> {
  115. @override
  116. Widget build(BuildContext context) {
  117. return Obx(() => Container(
  118. width: 370,
  119. height: double.infinity,
  120. color: Colors.white,
  121. child: ListView(
  122. children: controller.activeList
  123. .map((element) => activeView(element))
  124. .toList(),
  125. ),
  126. ));
  127. }
  128. Widget activeView(ActiveInfo info) {
  129. final children = <Widget>[
  130. Row(children: [
  131. Text('${info.name} (${info.userList.length}人)'),
  132. const Spacer(),
  133. IconButton(
  134. onPressed: () {
  135. info.isHide.value = !info.isHide.value;
  136. },
  137. icon: info.isHide.value
  138. ? const Icon(Icons.arrow_drop_down)
  139. : const Icon(Icons.arrow_drop_up))
  140. ]),
  141. ];
  142. if (!info.isHide.value) {
  143. children.addAll([
  144. Container(
  145. decoration: BoxDecoration(
  146. color: Colors.white, borderRadius: BorderRadius.circular(5)),
  147. padding: const EdgeInsets.fromLTRB(26, 11, 26, 11),
  148. child: Row(
  149. children: [
  150. Text('广播'),
  151. const Spacer(),
  152. Image.asset(Assets.imagesIcCp, height: 20, width: 20),
  153. Text(' ${info.cpAllCount}'),
  154. const Spacer(),
  155. Text('全部隐藏'),
  156. ],
  157. ),
  158. )
  159. ]);
  160. children
  161. .addAll(info.userList.map((e) => _UserInfoView(data: e)).toList());
  162. }
  163. return Container(
  164. decoration: BoxDecoration(
  165. color: const Color(0xffe0e0e0),
  166. borderRadius: BorderRadius.circular(5)),
  167. margin: const EdgeInsets.fromLTRB(9, 12, 9, 12),
  168. padding: const EdgeInsets.all(9),
  169. child: Column(
  170. children: children,
  171. ),
  172. );
  173. }
  174. }
  175. class _UserInfoView extends GetView<FieldControlController> {
  176. const _UserInfoView({required this.data});
  177. final UserInfo data;
  178. @override
  179. Widget build(BuildContext context) {
  180. return Container(
  181. decoration: BoxDecoration(
  182. color: Colors.white, borderRadius: BorderRadius.circular(5)),
  183. padding: const EdgeInsets.fromLTRB(7, 11, 7, 11),
  184. margin: const EdgeInsets.only(top: 5),
  185. child: Row(
  186. crossAxisAlignment: CrossAxisAlignment.start,
  187. children: [
  188. Obx(() => Container(
  189. margin: const EdgeInsets.only(top: 2),
  190. decoration: BoxDecoration(
  191. color: data.flag.value.color,
  192. borderRadius: BorderRadius.circular(4)),
  193. width: 7,
  194. height: 16)),
  195. const SizedBox(
  196. width: 8,
  197. ),
  198. Expanded(
  199. child: Column(
  200. crossAxisAlignment: CrossAxisAlignment.start,
  201. children: [
  202. Text.rich(TextSpan(
  203. text: data.name,
  204. children: [TextSpan(text: ' [${data.routeName}]')])),
  205. const SizedBox(height: 5),
  206. Row(
  207. children: [
  208. container(null, cpInfo, Colors.blue),
  209. container(
  210. const Icon(
  211. Icons.favorite,
  212. size: 13,
  213. color: Colors.white,
  214. ),
  215. ' ${hr == 0 ? '--' : hr}',
  216. (data.gameInfo.otherInfo.hasHeartRatePercent()
  217. ? data.gameInfo.otherInfo.heartRatePercent
  218. : 0)
  219. .toHRPColor()),
  220. container(null, paceInfo, data.pace.color)
  221. ],
  222. ),
  223. const SizedBox(height: 5),
  224. Row(
  225. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  226. children: [
  227. Text('距离 ${data.nextDistance.toString()}'),
  228. Text('时间 ${data.duration.toAppString()}'),
  229. Text('里程 ${data.distance.toString()}'),
  230. ],
  231. )
  232. ],
  233. )),
  234. GestureDetector(
  235. onTap: () {
  236. controller.focusUser.value = data;
  237. },
  238. child: Obx(() => Icon(
  239. Icons.route,
  240. color: data.gameInfo.userId !=
  241. controller.focusUser.value?.gameInfo.userId
  242. ? Colors.grey
  243. : const Color(0xffffbb77),
  244. )),
  245. ),
  246. const SizedBox(width: 8),
  247. GestureDetector(
  248. onTap: () {
  249. data.isHide.value = !data.isHide.value;
  250. },
  251. child: Obx(() => Icon(
  252. data.isHide.value ? Icons.visibility_off : Icons.visibility,
  253. color:
  254. data.isHide.value ? Colors.grey : const Color(0xffffbb77),
  255. )),
  256. )
  257. ],
  258. ),
  259. );
  260. }
  261. int get hr {
  262. return data.gameInfo.hrInfo.hrInfo.lastOrNull?.hr ?? 0;
  263. }
  264. String get cpInfo {
  265. final next = data.nextWant;
  266. return next != null ? '${data.nextCPSN}点(${next.areaId})' : '--';
  267. }
  268. String get paceInfo {
  269. Duration;
  270. return data.pace.toString();
  271. }
  272. Widget container(Widget? icon, String text, Color color) {
  273. final children = <Widget>[];
  274. if (icon != null) {
  275. children.add(icon);
  276. }
  277. children.add(
  278. Text(text, style: const TextStyle(color: Colors.white, fontSize: 14)));
  279. return Container(
  280. height: 18,
  281. padding: const EdgeInsets.fromLTRB(10, 0, 12, 0),
  282. margin: const EdgeInsets.only(right: 6),
  283. alignment: Alignment.center,
  284. decoration:
  285. BoxDecoration(color: color, borderRadius: BorderRadius.circular(9)),
  286. child: Row(
  287. children: children,
  288. ),
  289. );
  290. }
  291. }
  292. class _MsgView extends GetView<FieldControlController> {
  293. @override
  294. Widget build(BuildContext context) {
  295. return Container();
  296. }
  297. }