map_watch.dart 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import 'package:common_pub/model/control_point.dart';
  2. import 'package:common_pub/model/distance.dart';
  3. import 'package:common_pub/model/pace.dart';
  4. import 'package:common_pub/model/position.dart';
  5. import 'package:common_pub/service/controller.dart';
  6. import 'package:common_pub/ui/map_view/map_view.dart';
  7. import 'package:common_pub/ui/map_view/view_map_trace.dart';
  8. import '../logger.dart';
  9. import '../service/api.dart' as pb;
  10. import 'package:fixnum/fixnum.dart';
  11. typedef MapId = Int64;
  12. class Flag {
  13. Flag(this.value);
  14. int value;
  15. Color get color => Color(value);
  16. @override
  17. bool operator ==(Object other) {
  18. if (other is Flag) {
  19. return value == other.value;
  20. }
  21. return false;
  22. }
  23. @override
  24. int get hashCode => value.hashCode;
  25. static final red = Flag(0xffff0000);
  26. static final yellow = Flag(0xffffcb00);
  27. static final blue = Flag(0xff00a0ff);
  28. static List<Flag> get values => [red, yellow, blue];
  29. }
  30. class ActiveInfo {
  31. var id = 0;
  32. var name = '';
  33. var cpAllCount = 0;
  34. var userList = <UserInfo>[];
  35. final isHide = false.obs;
  36. UserInfo? getUserById(int id) {
  37. for (final one in userList) {
  38. if (one.gameInfo.userId == id) {
  39. return one;
  40. }
  41. }
  42. return null;
  43. }
  44. Future<UserInfo> newUserInfo(pb.ToOrienteerInGameInfo info) async {
  45. final r = await pb.ApiService.to.stub.toUserInActionBasicQuery(
  46. pb.ToUserInActionBasicQueryRequest(actId: id, userId: info.userId));
  47. final user = UserInfo()
  48. ..routeInfo = r.courseBaseInfo
  49. ..userInfo = r.baseInfo;
  50. await user.setGameInfo(info);
  51. return user;
  52. }
  53. Future<void> update(pb.ToActionInfo info) async {
  54. final newUserList = <UserInfo>[];
  55. for (final nUser in info.userList) {
  56. late UserInfo user;
  57. final oUser = getUserById(nUser.userId);
  58. if (oUser != null) {
  59. user = oUser;
  60. await user.update(nUser);
  61. } else {
  62. user = await newUserInfo(nUser);
  63. }
  64. newUserList.add(user);
  65. }
  66. userList = newUserList;
  67. }
  68. }
  69. extension ActiveInfoExt on pb.ToActionInfo {
  70. Future<ActiveInfo> into() async {
  71. final info = await pb.ApiService.to.stub
  72. .toActionBasicQuery(pb.IdRequest(id: Int64(actId)));
  73. final out = ActiveInfo()
  74. ..id = actId
  75. ..name = info.actName
  76. ..cpAllCount = info.totalControlNum;
  77. for (final one in userList) {
  78. out.userList.add(await out.newUserInfo(one));
  79. }
  80. return out;
  81. }
  82. }
  83. class UserInfo {
  84. final isHide = false.obs;
  85. String get name => userInfo.name;
  86. String get routeName => routeInfo.courseName;
  87. Pace get pace => Pace.perKm(gameInfo.gpsInfo.pace.seconds);
  88. Duration get duration =>
  89. DateTime.now().difference(gameInfo.gameSaveInfo.startAt.toModel());
  90. Distance get distance => Distance(m: gameInfo.gpsInfo.distance.toDouble());
  91. var gameInfo = pb.ToOrienteerInGameInfo();
  92. var routeInfo = pb.CourseBaseInfo();
  93. var userInfo = pb.OrienteerBaseInfo();
  94. var trace = <TracePoint>[].obs;
  95. var flag = Flag.red.obs;
  96. DateTime? get startAt => gameInfo.gameSaveInfo.hasStartAt()
  97. ? gameInfo.gameSaveInfo.startAt.toModel()
  98. : null;
  99. var cpList = <ControlPoint>[];
  100. ControlPoint? nextWant;
  101. Distance get nextDistance {
  102. final one = nextWant;
  103. if (one != null) {
  104. final p1 = one.position;
  105. final p22 = gameInfo.gpsInfo.gameGpsInfos.lastOrNull;
  106. if (p22 != null) {
  107. final p2 = Position(longitude: p22.longitude, latitude: p22.latitude);
  108. return p1.distance(p2);
  109. }
  110. }
  111. return const Distance(m: 1000);
  112. }
  113. String get nextCPSN {
  114. return nextWant?.snString ?? '';
  115. }
  116. Future<void> update(pb.ToOrienteerInGameInfo info) async {
  117. final map = MapWatchService.instance;
  118. await setGameInfo(info);
  119. final indexMap = <int, TracePoint>{};
  120. for (final one in trace) {
  121. indexMap[one.ts.inMilliseconds] = one;
  122. }
  123. for (final one in info.gpsInfo.gameGpsInfos) {
  124. final t = one.gpsTime.toModel();
  125. final startAt = gameInfo.gameSaveInfo.startAt.toModel();
  126. final ts = t.difference(startAt);
  127. if (ts.inMilliseconds > 0 && !indexMap.containsKey(ts.inMilliseconds)) {
  128. final pos = one.toModel();
  129. trace.add(TracePoint()
  130. ..ts = ts
  131. ..position = pos);
  132. }
  133. }
  134. if (map!.plugMap.isInitFinish) {
  135. for (final one in trace) {
  136. if (one.onMap == Offset.zero) {
  137. one.onMap = await map.plugMap.gameMap.worldToPixel(one.position);
  138. }
  139. }
  140. }
  141. }
  142. Future<void> setGameInfo(pb.ToOrienteerInGameInfo info) async {
  143. final map = MapWatchService.instance;
  144. gameInfo = info;
  145. cpList.clear();
  146. final cpMap = <int, ControlPoint>{};
  147. for (var (i, src) in routeInfo.controlPointSortedList.indexed) {
  148. final one = src.toModel()..sn = i.toString();
  149. if (map != null) {
  150. one.onMap = await map.plugMap.gameMap.worldToPixel(one.position);
  151. }
  152. cpList.add(one);
  153. cpMap[one.intId.toInt()] = one;
  154. }
  155. if (cpList.isNotEmpty) {
  156. cpList.first.isStart = true;
  157. cpList.last.isFinish = true;
  158. }
  159. for (var cp in gameInfo.gameSaveInfo.checkedSortedList) {
  160. cpMap[cp.controlPointId.toInt()]!.isSuccess = cp.isCheckSuccess;
  161. }
  162. for (var cp in cpList) {
  163. if (!cp.isSuccess) {
  164. cp.isNext = true;
  165. nextWant = cp;
  166. break;
  167. }
  168. }
  169. }
  170. }
  171. class MapWatchService extends PlugController {
  172. static final Rx<MapWatchService?> _instance = Rx(null);
  173. static MapWatchService? get instance => _instance.value;
  174. static Future<void> setMapById(MapId id) async {
  175. final info =
  176. await pb.ApiService.to.stub.toMapDetailV2(pb.IdRequest()..id = id);
  177. final thisInstance = MapWatchService(id: id)
  178. ..name = info.mapName
  179. ..plugMap.gameMap = info.zipImage.toGameMap();
  180. thisInstance.addPlugs([thisInstance.plugMap]);
  181. _instance.value = thisInstance;
  182. thisInstance.init();
  183. thisInstance.workFlushData();
  184. }
  185. Future<void> workFlushData() async {
  186. while (isActive) {
  187. try {
  188. await flushData();
  189. } catch (e) {
  190. error(e);
  191. }
  192. await 1.seconds.delay();
  193. }
  194. }
  195. ActiveInfo? getActiveById(int id) {
  196. for (final one in activeList) {
  197. if (one.id == id) {
  198. return one;
  199. }
  200. }
  201. return null;
  202. }
  203. Future<void> flushData() async {
  204. final r = await pb.ApiService.to.stub
  205. .toUserDetailQueryV2(pb.ToUserDetailQueryRequestV2(mapId: id.toInt()));
  206. final newList = <ActiveInfo>[];
  207. for (final one in r.list) {
  208. late ActiveInfo info;
  209. final old = getActiveById(one.actId);
  210. if (old != null) {
  211. info = old;
  212. await info.update(one);
  213. } else {
  214. info = await one.into();
  215. }
  216. newList.add(info);
  217. }
  218. activeList.value = newList;
  219. }
  220. MapWatchService({required this.id});
  221. final MapId id;
  222. String name = '';
  223. final plugMap = PlugMap();
  224. final activeList = <ActiveInfo>[].obs;
  225. }