import 'package:common_pub/logger.dart'; import 'package:common_pub/service/controller.dart'; import 'package:common_pub/ui/map_view/map_view.dart'; import 'package:common_pub/ui/map_view/view_map_trace.dart'; import 'package:track_common/model.dart'; import 'package:track_common/model/event_state.dart'; class Flag { Flag(this.value); int value; Color get color => Color(value); @override bool operator ==(Object other) { if (other is Flag) { return value == other.value; } return false; } @override int get hashCode => value.hashCode; static final red = Flag(0xffff0000); static final yellow = Flag(0xffffcb00); static final blue = Flag(0xff00a0ff); static List get values => [red, yellow, blue]; } class PlayerInfo extends AppGameState { var id = 0; int heartRatePercent = 0; } class PlayerInfoExt { var name = ''; var routeName = ''; var cpListWant = []; } class EventInfo { var id = 0; var players = []; } class EventInfoExt { var name = ''; var cpAllCount = 0; String startAt = ''; String endAt = ''; EventState state = EventState.idle; } class PlayerOnMap { var info = PlayerInfo(); var _ext = PlayerInfoExt(); set ext(PlayerInfoExt v) { _ext = v; info.cpListWant = v.cpListWant; } int get id => info.id; String get name => _ext.name; List get cpList => info.cpListWant; final isHide = false.obs; var trace = [].obs; var flag = Flag.red.obs; String get routeName => _ext.routeName; Distance get distance => info.distance; List get hrInfo => info.hrHistory; List get positionList => info.positionHistory; DateTime watchAt = DateTime.now(); int get heartRatePercent => info.heartRatePercent; Pace get pace => info.pace; Duration get duration => info.duration; ControlPoint? get cpNextWant => info.cpNextWant; Distance get nextDistance { final one = info.cpNextWant; if (one != null) { final p1 = one.position; final p22 = positionList.lastOrNull; if (p22 != null) { return p1.distance(p22); } } return const Distance(m: 1000); } String get nextCPSN { return info.cpNextWant?.snString ?? ''; } } class EventOnMap { var info = EventInfo(); var ext = EventInfoExt(); var userList = []; int get id => info.id; String get name => ext.name; int get cpAllCount => ext.cpAllCount; final isHide = false.obs; PlayerOnMap? getUserById(int id) { for (final one in userList) { if (one.id == id) { return one; } } return null; } } abstract class MapWatchService extends GetxService { final Rx _instance = Rx(null); MapWatch? get instance => _instance.value; @protected Future newInstanceByMap(MapInfo info); Future setMap(MapInfo? mapInfo) async { _instance.value?.close(); if (mapInfo != null) { final thisInstance = await newInstanceByMap(mapInfo); thisInstance.addPlugs([thisInstance.plugMap]); _instance.value = thisInstance; thisInstance.init(); thisInstance.workFlushData(); } else { _instance.value = null; } } } abstract class MapWatch extends PlugController { Future workFlushData() async { while (isActive) { try { await flushData(); } catch (e) { error(e); } await 1.seconds.delay(); } } EventOnMap? getEventById(int id) { for (final one in eventList) { if (one.id == id) { return one; } } return null; } MapWatch({required this.id}); final int id; String name = ''; final plugMap = PlugMap(); final eventList = [].obs; Future flushData() async { final list = await getEventList(id); final newList = []; for (final one in list) { late EventOnMap event; final old = getEventById(one.id); if (old != null) { event = old; await updateEvent(event, one); } else { event = await initEvent(one); } newList.add(event); } eventList.value = newList; } Future initEvent(EventInfo info) async { final ext = await getEventInfoExt(info.id); final one = EventOnMap() ..info = info ..ext = ext; for (var p in info.players) { one.userList.add(await initPlayer(info, p)); } return one; } Future initPlayer(EventInfo event, PlayerInfo playerInfo) async { final userId = playerInfo.id; final ext = await getPlayerInfoExt(event.id, userId); final player = PlayerOnMap()..info = playerInfo; player.ext = ext; return player; } Future updateEvent(EventOnMap old, EventInfo newOne) async { final newUserList = []; for (final nUser in newOne.players) { late PlayerOnMap user; final oUser = old.getUserById(nUser.id); if (oUser != null) { user = await updatePlayer(oUser, nUser); } else { user = await initPlayer(old.info, nUser); } await playerUpdateMap(user); newUserList.add(user); } old.userList = newUserList; } Future playerUpdateMap(PlayerOnMap info) async { for (var one in info.cpList) { one.onMap = await plugMap.gameMap.worldToPixel(one.position); } } Future updatePlayer(PlayerOnMap old, PlayerInfo newUser) async { final indexMap = {}; old.info = newUser; old.ext = old._ext; for (final one in old.trace) { indexMap[one.ts.inMilliseconds] = one; } for (final one in newUser.positionHistory) { final t = one.timestamp; final startAt = old.watchAt; final ts = t.difference(startAt); if (ts.inMilliseconds > 0 && !indexMap.containsKey(ts.inMilliseconds)) { final pos = one; final oneTrace = TracePoint() ..ts = ts ..position = pos; if (plugMap.isInitFinish) { oneTrace.onMap = await plugMap.gameMap.worldToPixel(oneTrace.position); } old.trace.add(oneTrace); } else if (old.trace.isEmpty) { final oneTrace = TracePoint() ..ts = Duration.zero ..position = one; if (plugMap.isInitFinish) { oneTrace.onMap = await plugMap.gameMap.worldToPixel(oneTrace.position); old.trace.add(oneTrace); } } } return old; } @protected Future> getEventList(int mapId); @protected Future getEventInfoExt(int id); @protected Future getPlayerInfoExt(int eventId, int userId); }