import 'dart:async'; import 'package:fixnum/fixnum.dart'; import 'package:grpc/grpc.dart'; import 'package:trackoffical_app/appcore/exercise.dart'; import 'package:trackoffical_app/service/app.dart'; import 'package:trackoffical_app/service/game/game_model.dart'; import 'package:trackoffical_app/service/game/plug.dart'; import 'package:trackoffical_app/service/sport_wear.dart'; import 'package:get/get.dart'; import 'package:pedometer/pedometer.dart'; import 'package:sensor/sensor.dart'; import 'package:trackoffical_app/pb.dart' as pb; import 'package:sensors_plus/sensors_plus.dart'; import '../../logger.dart'; import '../api.dart'; class PlugSportWear extends Plug{ final SportWearService _sportWearService = Get.find(); final GameModel _model = Get.find(); StreamSubscription? _heartRateMeasurementSubscription; final _exercise = Exercise(); final _app = App.to; final hrUploadHistory = []; final ApiService _api = Get.find(); var _initStepCount = -1; /// 上次保存的步数 var _stepOffset = 0; List _lastHr = []; PlugSportWear({required List lastHr}){ _lastHr = lastHr; } @override Future init() async { await _exercise.init(); final userProfile = _app.userProfile; await _exercise.set( age: userProfile.age.val, sex: userProfile.sex, weightKg: userProfile.weightKg.val, heightCm: userProfile.heightCm.val, rhr: userProfile.rhr.val.toDouble()); if(_lastHr.isNotEmpty){ for(var one in _lastHr){ final ts = DateTime.fromMillisecondsSinceEpoch(one.timeStampMs.toInt()).toLocal(); await _exercise.hrPush(one.hr, ts); } } _stepOffset = _model.gameSrcState.value.pbGameSave.stepNum; _model.stepCount.value = _stepOffset; _heartRateMeasurementSubscription =_sportWearService.heartRateMeasurement .listen((p0) { _model.heartRate.value = p0.heartRate; _exercise.hrPercent(p0.heartRate).then((value) => _model.heartRatePercent.value = value); final hr = pb.HeartRate() ..timeStampMs= Int64(p0.timestamp.millisecondsSinceEpoch) ..hr= p0.heartRate ; if(_model.isStarted && (!_model.isFinish)){ _exercise.hrPush(p0.heartRate, p0.timestamp).then((value){ _exercise.ei().then((v) => _model.ei.value = v); _exercise.ck().then((v) => _model.ck.value = v); _exercise.kCal().then((v) => _model.kCal.value = v); _exercise.exerciseKcal().then((v) => _model.exerciseKcal.value = v); _exercise.hrMax().then((v) => _model.hrMax.value = v); _exercise.hrMean().then((v) => _model.hrMean.value = v); }); _model.gameSrcState.value.pbGameSave.gameHrInfos.add(hr); } hrUploadHistory.add(hr); }); loopUploadHr(); final stream = Pedometer.stepCountStream; _model.stepCount.bindStream(stream.map((event){ if(!_model.isStarted){ return 0; } if(_initStepCount == -1){ _initStepCount = event.steps; return 0; } final stepCount = event.steps - _initStepCount + _stepOffset; _model.gameSrcState.value.pbGameSave.stepNum = stepCount; return stepCount; })); _model.isWalking.value = false; _model.isWalking.bindStream(Pedometer.pedestrianStatusStream.map((event){ return event.status=='walking'; })); } Future loopUploadHr() async { while (isActive) { await Future.delayed(1.seconds); try { await loopUploadHrOnce(); } catch (e) { warn('上传运动状态失败: $e'); } } } Future loopUploadHrOnce() async { if(!_model.isStarted){ return; } await uploadHr(); final gameId = _model.gameSrcState.value.pbGameData.gameId; await _api.gameExerciseStateUpload( gameId, _model.hrMean.value, _model.hrMax.value, (_model.kCal.value * 1000).round(), _model.ck.value, _model.ei.value, _model.stepCount.value, _model.heartRatePercent.value.toInt() ); } Future uploadHr() async { if(hrUploadHistory.isNotEmpty){ final gameId = _model.gameSrcState.value.pbGameData.gameId; await _api.gameHrUpload(gameId, hrUploadHistory); hrUploadHistory.clear(); } } Future _makeSureUploadAll() async { while (true) { try { final gameId = _model.gameSrcState.value.pbGameData.gameId; await uploadHr(); await _api.gameExerciseStateUpload( gameId, _model.hrMean.value, _model.hrMax.value, (_model.kCal.value * 1000).round(), _model.ck.value, _model.ei.value, _model.stepCount.value, _model.heartRatePercent.value.toInt() ); return; } on GrpcError catch (e) { if (e.code != StatusCode.unavailable) { return; } error(e); } catch (e) { error(e); return; } await Future.delayed(100.milliseconds); } } @override Future close() async{ await _makeSureUploadAll(); super.close(); _heartRateMeasurementSubscription?.cancel(); _exercise.close(); debug('[运动数据插件]已关闭'); } }