location_analyse_controller.dart 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter_map/flutter_map.dart';
  5. import 'package:get/get.dart';
  6. import 'package:get/get_core/src/get_main.dart';
  7. import 'package:injectable/injectable.dart';
  8. import 'package:location/base/base_controller.dart';
  9. import 'package:location/data/bean/user_info.dart';
  10. import 'package:location/data/repositories/track_repository.dart';
  11. import 'package:location/sdk/map/map_helper.dart';
  12. import 'package:lottie/lottie.dart';
  13. import 'package:video_player/video_player.dart';
  14. import '../../data/bean/stream_chat_origin_data.dart';
  15. import '../../data/bean/track_daily_bean.dart';
  16. import '../../resource/assets.gen.dart';
  17. import '../../resource/string.gen.dart';
  18. import '../../utils/http_handler.dart';
  19. import '../../widget/gradually_print_text.dart';
  20. import 'location_analyse_util.dart';
  21. @injectable
  22. class LocationAnalyseController extends BaseController
  23. with GetTickerProviderStateMixin {
  24. late final VideoPlayerController locaController;
  25. final RxBool _videoReady = RxBool(false);
  26. UserInfo? userInfo;
  27. TrackDailyBean? errorInfo;
  28. RxList<TrackDailyBean> errorAddr = RxList();
  29. final RxBool _isShowAnalyseAddr = RxBool(false);
  30. bool get isShowAnalyseAddr => _isShowAnalyseAddr.value;
  31. final RxBool _showAnalyseRemainContent = RxBool(false);
  32. bool get showAnalyseRemainContent => _showAnalyseRemainContent.value;
  33. bool get videoReady => _videoReady.value;
  34. StreamSubscription? _streamSubscription;
  35. final GraduallyController graduallyController = GraduallyController();
  36. final RxBool _isShowAnalyseResult = RxBool(false);
  37. bool get isShowAnalyseResult => _isShowAnalyseResult.value;
  38. final RxBool _isRequestedAnalyse = RxBool(false);
  39. bool get isRequestedAnalyse => _isRequestedAnalyse.value;
  40. bool _isRequestingStream = false;
  41. final RxnString _summaryError = RxnString();
  42. String? get summaryError => _summaryError.value;
  43. final Rxn<LottieDelegates> _keywordDelegates = Rxn<LottieDelegates>();
  44. LottieDelegates? get keywordDelegates => _keywordDelegates.value;
  45. final TrackRepository trackRepository;
  46. late AnimationController keywordLottieController =
  47. AnimationController(vsync: this);
  48. Timer? _loopTimer;
  49. Duration loopStart = const Duration(milliseconds: 0);
  50. Duration loopEnd = const Duration(milliseconds: 5032);
  51. LocationAnalyseController(this.trackRepository);
  52. @override
  53. void onInit() {
  54. super.onInit();
  55. _initArgs();
  56. _getKeyword();
  57. _getErrorAddr();
  58. graduallyController.setGraduallyFinishedListener(() {
  59. _isRequestingStream = false;
  60. });
  61. locaController = VideoPlayerController.asset(
  62. Assets.anim.locationAnalyseRobot,
  63. )
  64. ..setVolume(0.0)
  65. ..initialize().then((_) {
  66. _videoReady.value = true;
  67. _startMonitorLoop();
  68. }).catchError((error) {
  69. debugPrint('Error initializing video: $error');
  70. });
  71. }
  72. void _startMonitorLoop() {
  73. locaController.play();
  74. _loopTimer =
  75. Timer.periodic(const Duration(milliseconds: 100), (timer) async {
  76. final position = await locaController.position;
  77. if (position == null) return;
  78. if (position >= loopEnd) {
  79. locaController.seekTo(loopStart);
  80. }
  81. });
  82. }
  83. void _getErrorAddr() {
  84. trackRepository
  85. .trackDailyInterpret(
  86. startTime: errorInfo?.start,
  87. endTime: errorInfo?.end,
  88. userId: userInfo?.id)
  89. .then((list) {
  90. errorAddr.assignAll(list ?? []);
  91. });
  92. }
  93. void _getKeyword() {
  94. trackRepository
  95. .dailyKeyword(
  96. startTime: errorInfo?.start,
  97. endTime: errorInfo?.end,
  98. userId: userInfo?.id)
  99. .then((list) {
  100. //填充分析异常点到lottie占位中,有6个占位点,list如果小于则循环显示,如果超过6个,则随机6个选择,但不能重复出现
  101. if (list != null && list.isNotEmpty) {
  102. _keywordDelegates.value =
  103. LocationAnalyseUtil.convertKeywordDelegates(list);
  104. }
  105. });
  106. }
  107. void _initArgs() {
  108. final info = parameters?['userInfo'];
  109. if (info is UserInfo) {
  110. userInfo = info;
  111. }
  112. final errorInfo = parameters?['errorData'];
  113. if (errorInfo is TrackDailyBean) {
  114. this.errorInfo = errorInfo;
  115. }
  116. }
  117. void back() {
  118. Get.back();
  119. }
  120. void onTrackRefreshClick() {
  121. if (_isRequestingStream) {
  122. return;
  123. }
  124. _startMonitorLoop();
  125. _startKeywordLottieAnimation();
  126. _analyseErrorAddr();
  127. }
  128. String getErrorDistance(TrackDailyBean errorAddr) {
  129. final lastLocation = MapHelper.getLastLocation();
  130. if (lastLocation == null ||
  131. errorAddr.lat == null ||
  132. errorAddr.lng == null) {
  133. return StringName.unopenedPositioning;
  134. }
  135. final distance = MapUtil.calculateLineDistance(lastLocation.longitude,
  136. lastLocation.latitude, errorAddr.lng!, errorAddr.lat!);
  137. return MapUtil.format(distance);
  138. }
  139. void onAnalyseTextComplete() {
  140. _isShowAnalyseAddr.value = true;
  141. Future.delayed(Duration(milliseconds: 700), () {
  142. _showAnalyseRemainContent.value = true;
  143. });
  144. }
  145. void onAnalyseFinishComplete() {
  146. _isShowAnalyseResult.value = true;
  147. _analyseErrorAddr();
  148. }
  149. void _analyseErrorAddr() {
  150. //准备调用分析总结
  151. if (_isRequestingStream) {
  152. return;
  153. }
  154. _isRequestedAnalyse.value = false;
  155. _isRequestingStream = true;
  156. graduallyController.clear();
  157. _summaryError.value = null;
  158. trackRepository
  159. .streamDailyExceptionAnalyse(
  160. startTime: errorInfo?.start,
  161. endTime: errorInfo?.end,
  162. userId: userInfo?.id)
  163. .then((stream) {
  164. _streamSubscription?.cancel();
  165. _streamSubscription = stream.listen((event) {
  166. try {
  167. Map<String, dynamic> json = jsonDecode(event.data);
  168. if (json.isEmpty) {
  169. return;
  170. }
  171. StreamChatOriginData data = StreamChatOriginData.fromJson(json);
  172. if (data.choices == null || data.choices!.isEmpty) {
  173. return;
  174. }
  175. Delta? delta = data.choices![0].delta;
  176. if (delta == null) {
  177. return;
  178. }
  179. graduallyController.append(delta.content ?? "");
  180. } catch (ignore) {}
  181. }, onDone: () {
  182. graduallyController.appendDone();
  183. _setAnalyseSuccess();
  184. }, onError: (error) {
  185. _summaryError.value = "网络错误,请检查网络连接";
  186. debugPrint("error: $error");
  187. _isRequestedAnalyse.value = false;
  188. _isRequestingStream = false;
  189. debugPrintStack();
  190. });
  191. }).catchError((error) {
  192. _isRequestedAnalyse.value = false;
  193. _isRequestingStream = false;
  194. if (error is ServerErrorException) {
  195. _summaryError.value = error.message ?? "服务出错,请稍后再试";
  196. } else {
  197. _summaryError.value = "网络错误,请检查网络连接";
  198. debugPrint("error: $error");
  199. debugPrintStack();
  200. }
  201. });
  202. }
  203. void locationKeywordLottieLoad(LottieComposition composition) {
  204. keywordLottieController.duration = composition.duration;
  205. _startKeywordLottieAnimation();
  206. }
  207. void _startKeywordLottieAnimation() async {
  208. await keywordLottieController.animateTo(0.84);
  209. keywordLottieController.repeat(min: 0, max: 0.84, reverse: true);
  210. }
  211. void _setAnalyseSuccess() async {
  212. _loopTimer?.cancel();
  213. await keywordLottieController.animateTo(1);
  214. _isRequestedAnalyse.value = true;
  215. }
  216. @override
  217. void onClose() {
  218. _loopTimer?.cancel();
  219. _streamSubscription?.cancel();
  220. keywordLottieController.dispose();
  221. super.onClose();
  222. }
  223. }