import 'package:common_pub/model/distance.dart'; import 'package:common_pub/model/pace.dart'; import 'package:common_pub/model/position.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 '../logger.dart'; import '../service/api.dart' as pb; import 'package:fixnum/fixnum.dart'; typedef MapId = Int64; 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 ActiveInfo{ var id = 0; var name = ''; var cpAllCount = 0; var userList = []; final isHide = false.obs; UserInfo? getUserById(int id){ for (final one in userList){ if(one.gameInfo.userId==id){ return one; } } return null; } Future newUserInfo(pb.ToOrienteerInGameInfo info)async{ final r =await pb.ApiService.to.stub.toUserInActionBasicQuery(pb.ToUserInActionBasicQueryRequest( actId: id, userId: info.userId )); return UserInfo() ..routeInfo = r.courseBaseInfo ..userInfo = r.baseInfo ..gameInfo = info ; } Future update(pb.ToActionInfo info) async { final newUserList = []; for (final nUser in info.userList) { late UserInfo user; final oUser = getUserById(nUser.userId); if (oUser != null) { user = oUser; await user.update(nUser); }else{ user = await newUserInfo(nUser); } newUserList.add(user); } userList = newUserList; } } extension ActiveInfoExt on pb.ToActionInfo{ Future into() async { final info = await pb.ApiService.to.stub.toActionBasicQuery( pb.IdRequest(id: Int64(actId))); final out = ActiveInfo() ..id = actId ..name = info.actName ..cpAllCount = info.totalControlNum; for(final one in userList){ out.userList.add(await out.newUserInfo(one)); } return out; } } class UserInfo{ final isHide = false.obs; String get name => userInfo.name; String get routeName => routeInfo.courseName; Pace get pace => Pace.perKm( gameInfo.gpsInfo.pace.seconds); Duration get duration => DateTime.now().difference(gameInfo.gameSaveInfo.startAt.toModel()); Distance get distance => Distance(m: gameInfo.gpsInfo.distance.toDouble()); var gameInfo = pb.ToOrienteerInGameInfo(); var routeInfo = pb.CourseBaseInfo(); var userInfo = pb.OrienteerBaseInfo(); var trace = [].obs; var flag = Flag.red.obs; DateTime? get startAt => gameInfo.gameSaveInfo.hasStartAt()?gameInfo.gameSaveInfo.startAt.toModel(): null; Distance get nextDistance { final one = nextWant; if(one!= null){ final p1 = Position(longitude: one.ciPosition.longitude, latitude: one.ciPosition.latitude); final p22 = gameInfo.gpsInfo.gameGpsInfos.lastOrNull; if(p22 != null){ final p2 = Position(longitude: p22.longitude, latitude: p22.latitude); return p1.distance(p2); } } return const Distance(m: 1000); } pb.ToControlPoint? get nextWant{ final no = gameInfo.gameSaveInfo.nextControlPoint.orderNo; if(no < routeInfo.controlPointSortedList.length){ final out = routeInfo.controlPointSortedList[no]; out.orderNo=no; return out; } return null; } String get nextCPSN{ var str = '开始'; final next = nextWant; final wantList = routeInfo.controlPointSortedList; if(next != null){ if(next.orderNo == wantList.length-1){ str = '结束'; }else if(next.orderNo > 0){ str = '${next.orderNo}号'; } } return str; } Future update(pb.ToOrienteerInGameInfo info)async{ final map = MapWatchService.instance; gameInfo = info; final indexMap = {}; for (final one in trace){ indexMap[one.ts.inMilliseconds]=one; } for(final one in info.gpsInfo.gameGpsInfos){ final t = one.gpsTime.toModel(); final startAt = gameInfo.gameSaveInfo.startAt.toModel(); final ts = t.difference(startAt); if(ts.inMilliseconds>0 && !indexMap.containsKey(ts.inMilliseconds)){ final pos = one.toModel(); trace.add(TracePoint() ..ts = ts ..position=pos ); } } if(map!.plugMap.isInitFinish){ for (final one in trace){ if(one.onMap==Offset.zero){ one.onMap = await map.plugMap.gameMap.worldToPixel(one.position); } } } } } class MapWatchService extends PlugController{ static final Rx _instance = Rx(null); static MapWatchService? get instance => _instance.value; static Future setMapById(MapId id)async{ final info = await pb.ApiService.to.stub.toMapDetailV2(pb.IdRequest() ..id = id); final thisInstance = MapWatchService( id: id) ..name = info.mapName ..plugMap.gameMap = info.zipImage.toGameMap() ; thisInstance.addPlugs([thisInstance.plugMap]); _instance.value = thisInstance; thisInstance.init(); thisInstance.workFlushData(); } Future workFlushData()async{ while(isActive){ try{ await flushData(); }catch(e){ error(e); } await 1.seconds.delay(); } } ActiveInfo? getActiveById(int id){ for (final one in activeList){ if(one.id==id){ return one; } } return null; } Future flushData()async{ final r = await pb.ApiService.to.stub.toUserDetailQueryV2(pb.ToUserDetailQueryRequestV2( mapId: id.toInt())); final newList = []; for(final one in r.list){ late ActiveInfo info; final old = getActiveById(one.actId); if(old != null){ info = old; await info.update(one); }else{ info = await one.into(); } newList.add(info); } activeList.value = newList; } MapWatchService({required this.id}); final MapId id; String name= ''; final plugMap = PlugMap(); final activeList = [].obs; }