import 'dart:async'; import 'package:electronic_assistant/base/base_controller.dart'; import 'package:electronic_assistant/data/consts/event_report_id.dart'; import 'package:electronic_assistant/data/repositories/talk_repository.dart'; import 'package:electronic_assistant/module/talk/controller.dart'; import 'package:electronic_assistant/resource/string.gen.dart'; import 'package:electronic_assistant/utils/error_handler.dart'; import 'package:electronic_assistant/utils/toast_util.dart'; import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import '../../../data/bean/talk_original.dart'; import '../../../data/bean/talks.dart'; import '../../../data/repositories/account_repository.dart'; import '../../../widget/high_light_search_text.dart'; class OriginalController extends BaseController { final originalList = [].obs; final String? talkId; StreamSubscription? _talkBeanListener; StreamSubscription? _talkStatusListener; StreamSubscription? _audioPlayingListener; StreamSubscription? _searchPrintListener; StreamSubscription? _searchOperationListener; final Map searchTotalMap = {}; OriginalController(this.talkId); TalkController get talkController => Get.find(tag: talkId); RxString get searchPrint => talkController.searchPrint; int searchNowIndex = 0; int searchTotalSize = 0; OriginalSearch? originalSearch; final ItemScrollController itemScrollController = ItemScrollController(); @override void onReady() { super.onReady(); _talkBeanListener = talkController.talkBean.listen((bean) { if (bean?.status.value == TalkStatus.analysisSuccess) { requestOriginal(); } }); _talkStatusListener = talkController.talkBean.value?.status.listen((status) { if (status == TalkStatus.analysisSuccess) { requestOriginal(); } }); _searchPrintListener = talkController.searchPrint.listen((txt) { if (talkController.checkTabBean.value?.type != TalkBarType.original) { return; } _dealOriginalSearch(txt); }); _searchOperationListener = talkController.searchOperationCallback.listen((pair) { if (pair == null) { return; } if (pair.first != TalkBarType.original) { return; } if (searchTotalMap.isEmpty) { return; } if (pair.second == SearchOperationType.previous) { _dealSearchOperation(searchNowIndex - 1); } else if (pair.second == SearchOperationType.next) { _dealSearchOperation(searchNowIndex + 1); } }); requestOriginal(); setPlayAutoSelection(); } void _dealSearchOperation(int updateIndex) { if (searchTotalMap.isEmpty) { originalSearch?.searchTargetBean?.checkIndex.value = null; originalSearch = null; searchNowIndex = 0; searchTotalSize = 0; talkController.updateSearchPositionDesc(searchNowIndex, searchTotalSize); return; } if (originalSearch == null) { _updateTargetBean(updateIndex, true); } else { updateSearchData(updateIndex); } scrollToIndex(originalSearch?.originalIndex); talkController.updateSearchPositionDesc(searchNowIndex, searchTotalSize); } void updateSearchData(int updateIndex) { if (updateIndex > searchNowIndex) { int nextIndex = (originalSearch?.searchTargetIndex ?? 0) + 1; if (nextIndex >= (originalSearch?.searchTargetLength ?? 0)) { //找下一个 if (updateIndex > searchTotalSize) { updateIndex = 1; } _updateTargetBean(updateIndex, true); } else { originalSearch?.searchTargetIndex = nextIndex; originalSearch?.searchTargetBean?.checkIndex.value = nextIndex; } } else if (updateIndex < searchNowIndex) { //上一个 int preIndex = (originalSearch?.searchTargetIndex ?? 0) - 1; if (preIndex < 0) { if (updateIndex <= 0) { updateIndex = searchTotalSize; } _updateTargetBean(updateIndex, false); } else { originalSearch?.searchTargetIndex = preIndex; originalSearch?.searchTargetBean?.checkIndex.value = preIndex; } } searchNowIndex = updateIndex; } void _updateTargetBean(int updateIndex, bool isNextTarget) { int count = 0; for (var entry in searchTotalMap.entries) { int key = entry.key; int value = entry.value; count += value; if (updateIndex <= count) { originalSearch ??= OriginalSearch(); originalSearch?.searchTargetIndex = isNextTarget ? 0 : value - 1; originalSearch?.searchTargetLength = value; originalSearch?.originalIndex = key; originalSearch?.searchTargetBean?.checkIndex.value = null; originalSearch?.searchTargetBean = originalList[key]; originalSearch?.searchTargetBean?.checkIndex.value = originalSearch?.searchTargetIndex; break; } } searchNowIndex = updateIndex; } _dealOriginalSearch(String txt) { searchTotalMap.clear(); searchTotalSize = 0; for (int i = 0; i < originalList.length; i++) { TalkOriginal item = originalList[i]; int count = HighlightSearchText.getHighlightTotal(item.sentence ?? '', txt); searchTotalSize += count; if (count > 0) { searchTotalMap.addAll({i: count}); } } _dealSearchOperation(searchTotalMap.isNotEmpty ? 1 : 0); } void setPlayAutoSelection() { _audioPlayingListener = talkController.playingDuration.listen((duration) { if (duration == null) { return; } int time = duration.inMilliseconds; for (var item in originalList) { if (item.startMs == null || item.endMs == null) { continue; } if (item.startMs! <= time && item.endMs! >= time) { item.setSelected(true); } else { item.setSelected(false); } } }); } void eventReport(String eventId, {Map? params}) { talkController.eventReport(eventId, params: params); } void requestOriginal() { if (talkController.talkBean.value?.status.value == TalkStatus.analysisSuccess) { eventReport(EventId.event_101300); } else if (talkController.talkBean.value?.status.value == TalkStatus.analysisFail) { eventReport(EventId.event_101301); } if (originalList.isNotEmpty) { return; } talkRepository .talkOriginal(talkController.talkBean.value?.id) .then((value) { originalList.value = value; }); } void talkTranslateClick(TalkOriginal item) { if (!accountRepository.isLogin.value) { ToastUtil.showToast(StringName.errorCodeNoLogin.tr); return; } if (item.getTranslateStatus() == TalkTranslate.translating || item.getTranslateStatus() == TalkTranslate.translated) { return; } if (item.sentence == null || item.sentence!.isEmpty) { ToastUtil.showToast('翻译内容为空'); return; } item.setTranslateStatus(TalkTranslate.translating); talkRepository.talkTranslate(item.sentence!).then((result) { item.setTranslateStatus(TalkTranslate.translated); item.setTranslatedSentence(result.translation); }).catchError((error) { item.setTranslateStatus(TalkTranslate.normal); ErrorHandler.toastError(error); }); } void scrollToIndex(int? index) { if (index == null) { return; } itemScrollController.scrollTo( index: index, duration: const Duration(milliseconds: 1), curve: Curves.easeInOut); } @override void onClose() { super.onClose(); _talkBeanListener?.cancel(); _talkStatusListener?.cancel(); _audioPlayingListener?.cancel(); _searchPrintListener?.cancel(); _searchOperationListener?.cancel(); } } class OriginalSearch { TalkOriginal? searchTargetBean; int? searchTargetIndex; int? searchTargetLength; int? originalIndex; }