field_control.dart 10 KB

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