| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- 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<HeartRateMeasurement>? _heartRateMeasurementSubscription;
- final _exercise = Exercise();
- final _app = App.to;
- final hrUploadHistory = <pb.HeartRate>[];
- final ApiService _api = Get.find();
- var _initStepCount = -1;
- /// 上次保存的步数
- var _stepOffset = 0;
- List<pb.HeartRate> _lastHr = [];
- PlugSportWear({required List<pb.HeartRate> lastHr}){
- _lastHr = lastHr;
- }
- @override
- Future<void> 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<void> loopUploadHr() async {
- while (isActive) {
- await Future.delayed(1.seconds);
- try {
- await loopUploadHrOnce();
- } catch (e) {
- warn('上传运动状态失败: $e');
- }
- }
- }
- Future<void> 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<void> uploadHr() async {
- if(hrUploadHistory.isNotEmpty){
- final gameId = _model.gameSrcState.value.pbGameData.gameId;
- await _api.gameHrUpload(gameId, hrUploadHistory);
- hrUploadHistory.clear();
- }
- }
- Future<void> _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<void> close() async{
- await _makeSureUploadAll();
- super.close();
- _heartRateMeasurementSubscription?.cancel();
- _exercise.close();
- debug('[运动数据插件]已关闭');
- }
- }
|