field_control.dart 11 KB

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