controller.dart 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:electronic_assistant/base/base_controller.dart';
  4. import 'package:electronic_assistant/data/repositories/task_repository.dart';
  5. import 'package:electronic_assistant/module/talk/summary/view.dart';
  6. import 'package:electronic_assistant/module/talk/todo/view.dart';
  7. import 'package:electronic_assistant/resource/assets.gen.dart';
  8. import 'package:electronic_assistant/resource/colors.gen.dart';
  9. import 'package:electronic_assistant/resource/string.gen.dart';
  10. import 'package:electronic_assistant/utils/error_handler.dart';
  11. import 'package:electronic_assistant/utils/expand.dart';
  12. import 'package:electronic_assistant/utils/mmkv_util.dart';
  13. import 'package:flutter/cupertino.dart';
  14. import 'package:flutter_screenutil/flutter_screenutil.dart';
  15. import 'package:get/get.dart';
  16. import 'package:connectivity_plus/connectivity_plus.dart';
  17. import '../../data/bean/agenda_list_all_bean.dart';
  18. import '../../data/bean/talks.dart';
  19. import '../../data/repositories/agenda_repository.dart';
  20. import '../../data/repositories/talk_repository.dart';
  21. import '../../dialog/alert_dialog.dart';
  22. import '../../utils/toast_util.dart';
  23. import '../record/controller.dart';
  24. import 'original/view.dart';
  25. import 'package:just_audio/just_audio.dart';
  26. class TalkController extends BaseController {
  27. final String uploadNoPrompts = "UPLOAD_NO_PROMPTS";
  28. final Rxn<TalkBean> talkBean = Rxn();
  29. final isShowElectricLow = false.obs;
  30. bool isAudioLoading = false;
  31. final double sliderMax = 1;
  32. bool? audioFileIsExist;
  33. bool? isUploadedFile;
  34. final isAudioPlaying = false.obs;
  35. final audioProgressValue = 0.0.obs;
  36. final audioDuration = Duration.zero.obs;
  37. final agendaAllList = <AgendaListAllBean>[].obs;
  38. final List<String> tabBeans = [
  39. StringName.talkTabSummary.tr,
  40. StringName.talkTabMyTask.tr,
  41. StringName.talkTabOriginal.tr
  42. ];
  43. final _audioPlayer = AudioPlayer();
  44. StreamSubscription? _talkBeanListener;
  45. final pages = [const SummaryView(), const TodoView(), const OriginalView()];
  46. @override
  47. void onReady() {
  48. super.onReady();
  49. _initAudioPlayer();
  50. _initListener();
  51. _getArguments();
  52. }
  53. void _initAudioPlayer() {
  54. _audioPlayer.playerStateStream.listen((playerState) {
  55. if (playerState.processingState == ProcessingState.loading ||
  56. playerState.processingState == ProcessingState.buffering) {
  57. isAudioLoading = true;
  58. debugPrint('音频load = true');
  59. } else {
  60. debugPrint('音频load = false');
  61. isAudioLoading = false;
  62. if (playerState.processingState == ProcessingState.completed) {
  63. _audioPlayer.stop();
  64. _audioPlayer.seek(Duration.zero);
  65. isAudioPlaying.value = false;
  66. debugPrint('音频 播放结束了');
  67. }
  68. }
  69. isAudioPlaying.value = playerState.playing;
  70. }, onError: (Object e, StackTrace stackTrace) {
  71. debugPrint('音频加载异常 == $e');
  72. });
  73. _audioPlayer.durationStream.listen((duration) {
  74. if (duration != null) {
  75. debugPrint('音频总播放时长 == ${duration.inMilliseconds}');
  76. audioDuration.value = duration;
  77. }
  78. });
  79. _audioPlayer.positionStream.listen((position) {
  80. if (audioDuration.value.inMilliseconds > 0) {
  81. audioProgressValue.value =
  82. (position.inMilliseconds / audioDuration.value.inMilliseconds)
  83. .clamp(0.0, sliderMax);
  84. }
  85. });
  86. }
  87. void _initListener() {
  88. _talkBeanListener = talkBean.listen((bean) {
  89. _dealTalkUpdate(bean);
  90. });
  91. }
  92. void _dealTalkUpdate(TalkBean? bean) async {
  93. String? id = talkBean.value?.id;
  94. if (id == null) {
  95. return;
  96. }
  97. try {
  98. File file = await RecordController.getRecordFile(id);
  99. await _audioPlayer.setAudioSource(AudioSource.uri(file.uri));
  100. audioFileIsExist = true;
  101. } catch (e) {
  102. audioFileIsExist = false;
  103. debugPrint('音频设置异常 == $e');
  104. }
  105. }
  106. void _getArguments() {
  107. if (Get.arguments is TalkBean) {
  108. talkBean.value = Get.arguments as TalkBean;
  109. }
  110. }
  111. void updateProgress(double value) {
  112. final newPosition = Duration(
  113. milliseconds: (value * audioDuration.value.inMilliseconds).toInt());
  114. _audioPlayer.seek(newPosition);
  115. }
  116. void clickPlayAudio() {
  117. if (audioFileIsExist != true) {
  118. ToastUtil.showToast(StringName.talkFileNotFind.tr);
  119. return;
  120. }
  121. if (isAudioLoading) {
  122. ToastUtil.showToast(StringName.talkAudioLoading.tr);
  123. return;
  124. }
  125. if (_audioPlayer.playing) {
  126. _audioPlayer.pause();
  127. isAudioPlaying.value = false;
  128. } else {
  129. _audioPlayer.play();
  130. isAudioPlaying.value = true;
  131. }
  132. }
  133. void _checkFileSizeAndNet() async {
  134. String? id = talkBean.value?.id;
  135. if (id == null) {
  136. return;
  137. }
  138. File file = await RecordController.getRecordFile(id);
  139. if (!file.existsSync()) {
  140. ToastUtil.showToast(StringName.talkUploadFileNotExist.tr);
  141. return;
  142. }
  143. bool isCheckRemind = KVUtil.getBool(uploadNoPrompts, false);
  144. if (isCheckRemind) {
  145. _requestAnalyze(file);
  146. return;
  147. }
  148. //如果文件大小低于250MB 不弹窗提醒
  149. if (file.lengthSync() < 250 * 1024 * 1024) {
  150. _requestAnalyze(file);
  151. return;
  152. }
  153. final List<ConnectivityResult> connectivityResult =
  154. await (Connectivity().checkConnectivity());
  155. if (connectivityResult.contains(ConnectivityResult.wifi)) {
  156. _requestAnalyze(file);
  157. } else {
  158. _showTrafficRemindDialog(file.lengthSync().toReadableSize(),
  159. confirmOnTap: (isCheckRemind) {
  160. if (isCheckRemind) {
  161. KVUtil.putBool(uploadNoPrompts, true);
  162. }
  163. _requestAnalyze(file);
  164. });
  165. }
  166. }
  167. void _showTrafficRemindDialog(String holderTxt,
  168. {void Function(bool isCheckRemind)? confirmOnTap}) {
  169. final remindTrafficConsume = false.obs;
  170. Widget getSelectIcon() {
  171. return Obx(() {
  172. return remindTrafficConsume.value
  173. ? Assets.images.iconSelectTrue.image()
  174. : Assets.images.iconSelectFalse.image();
  175. });
  176. }
  177. Assets.images.iconSelectTrue.image();
  178. EAAlertDialog.show(
  179. contentWidget: Column(
  180. children: [
  181. Text(
  182. StringName.talkTrafficRemindTitle.tr
  183. .replacePlaceholders([holderTxt]),
  184. style:
  185. TextStyle(fontSize: 15.sp, color: ColorName.primaryTextColor),
  186. ),
  187. SizedBox(height: 8.h),
  188. GestureDetector(
  189. onTap: () {
  190. remindTrafficConsume.value = !remindTrafficConsume.value;
  191. },
  192. child: IntrinsicWidth(
  193. child: Row(
  194. children: [
  195. SizedBox(width: 20.w, height: 20.w, child: getSelectIcon()),
  196. SizedBox(width: 5.w),
  197. Text(
  198. StringName.talkTrafficRemindTips.tr,
  199. style: TextStyle(
  200. fontSize: 15.sp, color: ColorName.tertiaryTextColor),
  201. )
  202. ],
  203. ),
  204. ),
  205. )
  206. ],
  207. ),
  208. cancelText: StringName.cancel.tr,
  209. confirmText: StringName.sure.tr,
  210. confirmOnTap: () {
  211. confirmOnTap?.call(remindTrafficConsume.value);
  212. });
  213. }
  214. void checkCanAnalyze() async {
  215. String? id = talkBean.value?.id;
  216. double? duration = talkBean.value?.duration;
  217. if (id == null || duration == null) {
  218. return;
  219. }
  220. talkRepository.checkElectric(duration).then((data) {
  221. if (data.enough) {
  222. //检查网络以及文件大小
  223. _checkFileSizeAndNet();
  224. } else {
  225. ToastUtil.showToast(StringName.talkAnalyseLowToast.tr);
  226. isShowElectricLow.value = true;
  227. }
  228. }).catchError((error) {
  229. ToastUtil.showToast(error);
  230. });
  231. }
  232. void _requestAnalyze(File file) {
  233. String? talkId = talkBean.value?.id;
  234. double? duration = talkBean.value?.duration;
  235. if (talkId == null || duration == null || isUploadedFile == true) {
  236. return;
  237. }
  238. talkRepository.uploadTalkFile(talkId, duration, file).then((taskId) {
  239. ToastUtil.showToast('提交成功,小听正在分析谈话,请稍后');
  240. isUploadedFile = true;
  241. talkBean.value?.taskId = taskId;
  242. talkBean.value?.status = TalkStatus.analysing;
  243. taskRepository.addTask(taskId);
  244. }).catchError((error) {
  245. ErrorHandler.toastError(error);
  246. });
  247. }
  248. void goElectricStore() {
  249. //TODO 跳转至商店页
  250. }
  251. void refreshAgendaAllData() {
  252. String? id = talkBean.value?.id;
  253. if (id == null || agendaAllList.isNotEmpty) {
  254. return;
  255. }
  256. agendaRepository.agendaListAll(id).then((agenda) {
  257. if (agenda.list != null) {
  258. agendaAllList.value = agenda.list!;
  259. }
  260. });
  261. }
  262. @override
  263. void onClose() {
  264. super.onClose();
  265. _talkBeanListener?.cancel();
  266. _audioPlayer.dispose();
  267. }
  268. }