| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import 'dart:async';
- import 'dart:convert';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter_map/flutter_map.dart';
- import 'package:get/get.dart';
- import 'package:get/get_core/src/get_main.dart';
- import 'package:injectable/injectable.dart';
- import 'package:location/base/base_controller.dart';
- import 'package:location/data/bean/user_info.dart';
- import 'package:location/data/repositories/track_repository.dart';
- import 'package:location/sdk/map/map_helper.dart';
- import 'package:location/utils/atmob_log.dart';
- import 'package:lottie/lottie.dart';
- import 'package:video_player/video_player.dart';
- import '../../data/bean/stream_chat_origin_data.dart';
- import '../../data/bean/track_daily_bean.dart';
- import '../../resource/assets.gen.dart';
- import '../../resource/string.gen.dart';
- import '../../utils/http_handler.dart';
- import '../../widget/gradually_print_text.dart';
- import 'location_analyse_util.dart';
- @injectable
- class LocationAnalyseController extends BaseController
- with GetTickerProviderStateMixin {
- late final VideoPlayerController locaController;
- final RxBool _videoReady = RxBool(false);
- UserInfo? userInfo;
- TrackDailyBean? errorInfo;
- RxList<TrackDailyBean> errorAddr = RxList();
- final RxBool _isShowAnalyseAddr = RxBool(false);
- bool get isShowAnalyseAddr => _isShowAnalyseAddr.value;
- final RxBool _showAnalyseRemainContent = RxBool(false);
- bool get showAnalyseRemainContent => _showAnalyseRemainContent.value;
- bool get videoReady => _videoReady.value;
- StreamSubscription? _streamSubscription;
- final GraduallyController graduallyController = GraduallyController();
- final RxBool _isShowAnalyseResult = RxBool(false);
- bool get isShowAnalyseResult => _isShowAnalyseResult.value;
- final RxBool _isRequestedAnalyse = RxBool(false);
- bool get isRequestedAnalyse => _isRequestedAnalyse.value;
- bool _isRequestingStream = false;
- final RxnString _summaryError = RxnString();
- String? get summaryError => _summaryError.value;
- final Rxn<LottieDelegates> _keywordDelegates = Rxn<LottieDelegates>();
- LottieDelegates? get keywordDelegates => _keywordDelegates.value;
- final TrackRepository trackRepository;
- late AnimationController keywordLottieController =
- AnimationController(vsync: this);
- Timer? _loopTimer;
- bool _triggerFinalLoop = false;
- //视频播放总长度 8175毫秒
- Duration videoTotalDuration = const Duration(milliseconds: 8175);
- Duration loopStart = const Duration(milliseconds: 5670);
- Duration loopEnd = const Duration(milliseconds: 6570);
- LocationAnalyseController(this.trackRepository);
- @override
- void onInit() {
- super.onInit();
- _initArgs();
- _getKeyword();
- _getErrorAddr();
- graduallyController.setGraduallyFinishedListener(() {
- _isRequestedAnalyse.value = true;
- _isRequestingStream = false;
- });
- locaController = VideoPlayerController.asset(
- Assets.anim.locationAnalyseRobot,
- )
- ..setVolume(0.0)
- ..initialize().then((_) {
- _videoReady.value = true;
- locaController.play();
- AtmobLog.d('zk', "duration:${locaController.value.duration}");
- _startMonitorLoop();
- }).catchError((error) {
- debugPrint('Error initializing video: $error');
- });
- }
- void _startMonitorLoop() {
- _loopTimer =
- Timer.periodic(const Duration(milliseconds: 100), (timer) async {
- final position = await locaController.position;
- if (position == null) return;
- // 第一阶段:0~6s,播放完成后进入循环
- if (!_triggerFinalLoop) {
- if (position >= loopEnd) {
- // 循环 4~6s
- locaController.seekTo(loopStart);
- }
- } else {
- // 第二阶段:触发后进入 6~8s 循环
- if (loopStart != const Duration(seconds: 6)) {
- loopStart = const Duration(seconds: 6);
- loopEnd = videoTotalDuration;
- }
- if (position >= loopEnd) {
- locaController.seekTo(loopStart);
- }
- }
- });
- }
- void _getErrorAddr() {
- trackRepository
- .trackDailyInterpret(
- startTime: errorInfo?.start,
- endTime: errorInfo?.end,
- userId: userInfo?.id)
- .then((list) {
- errorAddr.assignAll(list ?? []);
- });
- }
- void _getKeyword() {
- trackRepository
- .dailyKeyword(
- startTime: errorInfo?.start,
- endTime: errorInfo?.end,
- userId: userInfo?.id)
- .then((list) {
- //填充分析异常点到lottie占位中,有6个占位点,list如果小于则循环显示,如果超过6个,则随机6个选择,但不能重复出现
- if (list != null && list.isNotEmpty) {
- _keywordDelegates.value =
- LocationAnalyseUtil.convertKeywordDelegates(list);
- }
- });
- }
- void _initArgs() {
- final info = parameters?['userInfo'];
- if (info is UserInfo) {
- userInfo = info;
- }
- final errorInfo = parameters?['errorData'];
- if (errorInfo is TrackDailyBean) {
- this.errorInfo = errorInfo;
- }
- }
- void back() {
- Get.back();
- }
- void onTrackRefreshClick() {
- _analyseErrorAddr();
- }
- String getErrorDistance(TrackDailyBean errorAddr) {
- final lastLocation = MapHelper.getLastLocation();
- if (lastLocation == null ||
- errorAddr.lat == null ||
- errorAddr.lng == null) {
- return StringName.unopenedPositioning;
- }
- final distance = MapUtil.calculateLineDistance(lastLocation.longitude,
- lastLocation.latitude, errorAddr.lng!, errorAddr.lat!);
- return MapUtil.format(distance);
- }
- void onAnalyseTextComplete() {
- _isShowAnalyseAddr.value = true;
- Future.delayed(Duration(milliseconds: 700), () {
- _showAnalyseRemainContent.value = true;
- });
- }
- void onAnalyseFinishComplete() {
- _isShowAnalyseResult.value = true;
- _analyseErrorAddr();
- }
- void _analyseErrorAddr() {
- //准备调用分析总结
- if (_isRequestingStream) {
- return;
- }
- _isRequestedAnalyse.value = false;
- _isRequestingStream = true;
- graduallyController.clear();
- _summaryError.value = null;
- trackRepository
- .streamDailyExceptionAnalyse(
- startTime: errorInfo?.start,
- endTime: errorInfo?.end,
- userId: userInfo?.id)
- .then((stream) {
- _streamSubscription?.cancel();
- _streamSubscription = stream.listen((event) {
- try {
- Map<String, dynamic> json = jsonDecode(event.data);
- if (json.isEmpty) {
- return;
- }
- StreamChatOriginData data = StreamChatOriginData.fromJson(json);
- if (data.choices == null || data.choices!.isEmpty) {
- return;
- }
- Delta? delta = data.choices![0].delta;
- if (delta == null) {
- return;
- }
- graduallyController.append(delta.content ?? "");
- } catch (ignore) {}
- }, onDone: () {
- graduallyController.appendDone();
- _setAnalyseSuccess();
- }, onError: (error) {
- _summaryError.value = "网络错误,请检查网络连接";
- debugPrint("error: $error");
- _isRequestedAnalyse.value = false;
- _isRequestingStream = false;
- debugPrintStack();
- });
- }).catchError((error) {
- _isRequestedAnalyse.value = false;
- _isRequestingStream = false;
- if (error is ServerErrorException) {
- _summaryError.value = error.message ?? "服务出错,请稍后再试";
- } else {
- _summaryError.value = "网络错误,请检查网络连接";
- debugPrint("error: $error");
- debugPrintStack();
- }
- });
- }
- void locationKeywordLottieLoad(LottieComposition composition) async {
- keywordLottieController.duration = composition.duration;
- await keywordLottieController.animateTo(0.84);
- keywordLottieController.repeat(min: 0, max: 0.84, reverse: true);
- }
- void _setAnalyseSuccess() {
- keywordLottieController.animateTo(1);
- }
- @override
- void onClose() {
- _streamSubscription?.cancel();
- keywordLottieController.dispose();
- super.onClose();
- }
- }
|