import 'dart:async'; import 'dart:io'; import 'package:electronic_assistant/base/base_controller.dart'; import 'package:electronic_assistant/data/repositories/task_repository.dart'; import 'package:electronic_assistant/module/chat/view.dart'; import 'package:electronic_assistant/module/home/controller.dart'; import 'package:electronic_assistant/module/talk/summary/view.dart'; import 'package:electronic_assistant/module/talk/todo/view.dart'; import 'package:electronic_assistant/resource/assets.gen.dart'; import 'package:electronic_assistant/resource/colors.gen.dart'; import 'package:electronic_assistant/resource/string.gen.dart'; import 'package:electronic_assistant/utils/error_handler.dart'; import 'package:electronic_assistant/utils/expand.dart'; import 'package:electronic_assistant/utils/mmkv_util.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import '../../data/bean/agenda_list_all_bean.dart'; import '../../data/bean/talks.dart'; import '../../data/repositories/agenda_repository.dart'; import '../../data/repositories/talk_repository.dart'; import '../../dialog/alert_dialog.dart'; import '../../router/app_pages.dart'; import '../../utils/toast_util.dart'; import '../record/controller.dart'; import 'original/view.dart'; import 'package:just_audio/just_audio.dart'; class TalkController extends BaseController { final String uploadNoPrompts = "UPLOAD_NO_PROMPTS"; final Rxn talkBean = Rxn(); final isShowElectricLow = false.obs; bool isAudioLoading = false; final double sliderMax = 1; bool? audioFileIsExist; bool? isUploadedFile; Rxn isUploading = Rxn(); final isAudioPlaying = false.obs; final audioProgressValue = 0.0.obs; final audioDuration = Duration.zero.obs; final agendaAllList = [].obs; final List tabBeans = [ StringName.talkTabSummary.tr, StringName.talkTabMyTask.tr, StringName.talkTabOriginal.tr ]; final _audioPlayer = AudioPlayer(); StreamSubscription? _talkBeanListener; final pages = [const SummaryView(), const TodoView(), const OriginalView()]; @override void onReady() { super.onReady(); _initAudioPlayer(); _initListener(); _getArguments(); } void _initAudioPlayer() { _audioPlayer.playerStateStream.listen((playerState) { if (playerState.processingState == ProcessingState.loading || playerState.processingState == ProcessingState.buffering) { isAudioLoading = true; debugPrint('音频load = true'); } else { debugPrint('音频load = false'); isAudioLoading = false; if (playerState.processingState == ProcessingState.completed) { _audioPlayer.stop(); _audioPlayer.seek(Duration.zero); isAudioPlaying.value = false; debugPrint('音频 播放结束了'); } } isAudioPlaying.value = playerState.playing; }, onError: (Object e, StackTrace stackTrace) { debugPrint('音频加载异常 == $e'); }); _audioPlayer.durationStream.listen((duration) { if (duration != null) { debugPrint('音频总播放时长 == ${duration.inMilliseconds}'); audioDuration.value = duration; } }); _audioPlayer.positionStream.listen((position) { if (audioDuration.value.inMilliseconds > 0) { audioProgressValue.value = (position.inMilliseconds / audioDuration.value.inMilliseconds) .clamp(0.0, sliderMax); } }); } void _initListener() { _talkBeanListener = talkBean.listen((bean) { _dealTalkUpdate(bean); }); } void _dealTalkUpdate(TalkBean? bean) async { String? id = talkBean.value?.id; if (id == null) { return; } if (talkRepository.isUploadingTalk(id) && talkBean.value?.status.value == TalkStatus.notAnalysis) { isUploading.value = true; } else { isUploading.value = false; } try { Uri? uri; if (bean?.isExample == true && bean?.audioUrl != null) { uri = Uri.parse(bean!.audioUrl!); } else { File? file = await getFileByTalk(id, bean?.uploadType); if (file?.existsSync() == true) { uri = file?.uri; } } if (uri == null) { throw '音频文件不存在'; } await _audioPlayer.setAudioSource(AudioSource.uri(uri)); audioFileIsExist = true; } catch (e) { audioFileIsExist = false; debugPrint('音频设置异常 == $e'); } } void _getArguments() { if (Get.arguments is TalkBean) { talkBean.value = Get.arguments as TalkBean; } } void updateProgress(double value) { final newPosition = Duration( milliseconds: (value * audioDuration.value.inMilliseconds).toInt()); _audioPlayer.seek(newPosition); } void clickPlayAudio() { if (audioFileIsExist != true) { ToastUtil.showToast(StringName.talkFileNotFind.tr); return; } if (isAudioLoading) { ToastUtil.showToast(StringName.talkAudioLoading.tr); return; } if (_audioPlayer.playing) { _audioPlayer.pause(); isAudioPlaying.value = false; } else { _audioPlayer.play(); isAudioPlaying.value = true; } } void _checkFileSizeAndNet() async { String? id = talkBean.value?.id; if (id == null) { return; } File? file = await getFileByTalk(talkBean.value?.id, talkBean.value?.uploadType); if (file == null || !file.existsSync()) { ToastUtil.showToast(StringName.talkUploadFileNotExist.tr); return; } bool isCheckRemind = KVUtil.getBool(uploadNoPrompts, false); if (isCheckRemind) { _requestAnalyze(file); return; } //如果文件大小低于250MB 不弹窗提醒 if (file.lengthSync() < 250 * 1024 * 1024) { _requestAnalyze(file); return; } final List connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult.contains(ConnectivityResult.wifi)) { _requestAnalyze(file); } else { _showTrafficRemindDialog(file.lengthSync().toReadableSize(), confirmOnTap: (isCheckRemind) { if (isCheckRemind) { KVUtil.putBool(uploadNoPrompts, true); } _requestAnalyze(file); }); } } void _showTrafficRemindDialog(String holderTxt, {void Function(bool isCheckRemind)? confirmOnTap}) { final remindTrafficConsume = false.obs; Widget getSelectIcon() { return Obx(() { return remindTrafficConsume.value ? Assets.images.iconSelectTrue.image() : Assets.images.iconSelectFalse.image(); }); } Assets.images.iconSelectTrue.image(); EAAlertDialog.show( contentWidget: Column( children: [ Text( StringName.talkTrafficRemindTitle.tr .replacePlaceholders([holderTxt]), style: TextStyle(fontSize: 15.sp, color: ColorName.primaryTextColor), ), SizedBox(height: 8.h), GestureDetector( onTap: () { remindTrafficConsume.value = !remindTrafficConsume.value; }, child: IntrinsicWidth( child: Row( children: [ SizedBox(width: 20.w, height: 20.w, child: getSelectIcon()), SizedBox(width: 5.w), Text( StringName.talkTrafficRemindTips.tr, style: TextStyle( fontSize: 15.sp, color: ColorName.tertiaryTextColor), ) ], ), ), ) ], ), cancelText: StringName.cancel.tr, confirmText: StringName.sure.tr, confirmOnTap: () { confirmOnTap?.call(remindTrafficConsume.value); }); } void checkCanAnalyze() { String? id = talkBean.value?.id; double? duration = talkBean.value?.duration; if (id == null || duration == null) { return; } talkRepository.checkElectric(duration).then((data) { if (data.enough) { //检查网络以及文件大小 _checkFileSizeAndNet(); } else { ToastUtil.showToast(StringName.talkAnalyseLowToast.tr); isShowElectricLow.value = true; } }).catchError((error) { ToastUtil.showToast(error); }); } void _requestAnalyze(File file) { String? talkId = talkBean.value?.id; double? duration = talkBean.value?.duration; if (talkId == null || duration == null || isUploadedFile == true) { return; } isUploading.value = true; talkRepository.uploadTalkFile(talkId, duration, file).then((taskId) { isUploadedFile = true; taskRepository.addTask(taskId); }).catchError((error) { isUploading.value = false; ErrorHandler.toastError(error); }); } void refreshAgendaAllData() { String? id = talkBean.value?.id; if (id == null || agendaAllList.isNotEmpty) { return; } agendaRepository.agendaListAll(id).then((agenda) { if (agenda.list != null) { agendaAllList.value = agenda.list!; } }); } void clickAIAnalysis() { if (talkBean.value != null) { ChatPage.startByTalk(talkBean.value!); } } @override void onClose() { super.onClose(); _talkBeanListener?.cancel(); _audioPlayer.dispose(); } void onGoElectricStore() { Get.toNamed(RoutePath.store); Future.delayed(const Duration(milliseconds: 250), () { isShowElectricLow.value = false; }); } } Future getFileByTalk(String? talkId, int? uploadType) async { if (talkId == null) { return null; } if (uploadType == TalkUploadType.localUpload) { return await getChoiceUploadFile(talkId); } else { return await RecordController.getRecordFile(talkId); } }