controller.dart 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import 'dart:async';
  2. import 'package:electronic_assistant/base/base_controller.dart';
  3. import 'package:electronic_assistant/data/consts/event_report_id.dart';
  4. import 'package:electronic_assistant/data/repositories/talk_repository.dart';
  5. import 'package:electronic_assistant/module/talk/controller.dart';
  6. import 'package:electronic_assistant/resource/string.gen.dart';
  7. import 'package:electronic_assistant/utils/error_handler.dart';
  8. import 'package:electronic_assistant/utils/toast_util.dart';
  9. import 'package:flutter/cupertino.dart';
  10. import 'package:get/get.dart';
  11. import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
  12. import '../../../data/bean/talk_original.dart';
  13. import '../../../data/bean/talks.dart';
  14. import '../../../data/repositories/account_repository.dart';
  15. import '../../../widget/high_light_search_text.dart';
  16. class OriginalController extends BaseController {
  17. final originalList = <TalkOriginal>[].obs;
  18. final String? talkId;
  19. StreamSubscription? _talkBeanListener;
  20. StreamSubscription? _talkStatusListener;
  21. StreamSubscription? _audioPlayingListener;
  22. StreamSubscription? _searchPrintListener;
  23. StreamSubscription? _searchOperationListener;
  24. final Map<int, int> searchTotalMap = {};
  25. OriginalController(this.talkId);
  26. TalkController get talkController => Get.find<TalkController>(tag: talkId);
  27. RxString get searchPrint => talkController.searchPrint;
  28. int searchNowIndex = 0;
  29. int searchTotalSize = 0;
  30. OriginalSearch? originalSearch;
  31. final ItemScrollController itemScrollController = ItemScrollController();
  32. @override
  33. void onReady() {
  34. super.onReady();
  35. _talkBeanListener = talkController.talkBean.listen((bean) {
  36. if (bean?.status.value == TalkStatus.analysisSuccess) {
  37. requestOriginal();
  38. }
  39. });
  40. _talkStatusListener =
  41. talkController.talkBean.value?.status.listen((status) {
  42. if (status == TalkStatus.analysisSuccess) {
  43. requestOriginal();
  44. }
  45. });
  46. _searchPrintListener = talkController.searchPrint.listen((txt) {
  47. if (talkController.checkTabBean.value?.type != TalkBarType.original) {
  48. return;
  49. }
  50. _dealOriginalSearch(txt);
  51. });
  52. _searchOperationListener =
  53. talkController.searchOperationCallback.listen((pair) {
  54. if (pair == null) {
  55. return;
  56. }
  57. if (pair.first != TalkBarType.original) {
  58. return;
  59. }
  60. if (searchTotalMap.isEmpty) {
  61. return;
  62. }
  63. if (pair.second == SearchOperationType.previous) {
  64. _dealSearchOperation(searchNowIndex - 1);
  65. } else if (pair.second == SearchOperationType.next) {
  66. _dealSearchOperation(searchNowIndex + 1);
  67. }
  68. });
  69. requestOriginal();
  70. setPlayAutoSelection();
  71. }
  72. void _dealSearchOperation(int updateIndex) {
  73. if (searchTotalMap.isEmpty) {
  74. originalSearch?.searchTargetBean?.checkIndex.value = null;
  75. originalSearch = null;
  76. searchNowIndex = 0;
  77. searchTotalSize = 0;
  78. talkController.updateSearchPositionDesc(searchNowIndex, searchTotalSize);
  79. return;
  80. }
  81. if (originalSearch == null) {
  82. _updateTargetBean(updateIndex, true);
  83. } else {
  84. updateSearchData(updateIndex);
  85. }
  86. scrollToIndex(originalSearch?.originalIndex);
  87. talkController.updateSearchPositionDesc(searchNowIndex, searchTotalSize);
  88. }
  89. void updateSearchData(int updateIndex) {
  90. if (updateIndex > searchNowIndex) {
  91. int nextIndex = (originalSearch?.searchTargetIndex ?? 0) + 1;
  92. if (nextIndex >= (originalSearch?.searchTargetLength ?? 0)) {
  93. //找下一个
  94. if (updateIndex > searchTotalSize) {
  95. updateIndex = 1;
  96. }
  97. _updateTargetBean(updateIndex, true);
  98. } else {
  99. originalSearch?.searchTargetIndex = nextIndex;
  100. originalSearch?.searchTargetBean?.checkIndex.value = nextIndex;
  101. }
  102. } else if (updateIndex < searchNowIndex) {
  103. //上一个
  104. int preIndex = (originalSearch?.searchTargetIndex ?? 0) - 1;
  105. if (preIndex < 0) {
  106. if (updateIndex <= 0) {
  107. updateIndex = searchTotalSize;
  108. }
  109. _updateTargetBean(updateIndex, false);
  110. } else {
  111. originalSearch?.searchTargetIndex = preIndex;
  112. originalSearch?.searchTargetBean?.checkIndex.value = preIndex;
  113. }
  114. }
  115. searchNowIndex = updateIndex;
  116. }
  117. void _updateTargetBean(int updateIndex, bool isNextTarget) {
  118. int count = 0;
  119. for (var entry in searchTotalMap.entries) {
  120. int key = entry.key;
  121. int value = entry.value;
  122. count += value;
  123. if (updateIndex <= count) {
  124. originalSearch ??= OriginalSearch();
  125. originalSearch?.searchTargetIndex = isNextTarget ? 0 : value - 1;
  126. originalSearch?.searchTargetLength = value;
  127. originalSearch?.originalIndex = key;
  128. originalSearch?.searchTargetBean?.checkIndex.value = null;
  129. originalSearch?.searchTargetBean = originalList[key];
  130. originalSearch?.searchTargetBean?.checkIndex.value =
  131. originalSearch?.searchTargetIndex;
  132. break;
  133. }
  134. }
  135. searchNowIndex = updateIndex;
  136. }
  137. _dealOriginalSearch(String txt) {
  138. searchTotalMap.clear();
  139. searchTotalSize = 0;
  140. for (int i = 0; i < originalList.length; i++) {
  141. TalkOriginal item = originalList[i];
  142. int count =
  143. HighlightSearchText.getHighlightTotal(item.sentence ?? '', txt);
  144. searchTotalSize += count;
  145. if (count > 0) {
  146. searchTotalMap.addAll({i: count});
  147. }
  148. }
  149. _dealSearchOperation(searchTotalMap.isNotEmpty ? 1 : 0);
  150. }
  151. void setPlayAutoSelection() {
  152. _audioPlayingListener = talkController.playingDuration.listen((duration) {
  153. if (duration == null) {
  154. return;
  155. }
  156. int time = duration.inMilliseconds;
  157. for (var item in originalList) {
  158. if (item.startMs == null || item.endMs == null) {
  159. continue;
  160. }
  161. if (item.startMs! <= time && item.endMs! >= time) {
  162. item.setSelected(true);
  163. } else {
  164. item.setSelected(false);
  165. }
  166. }
  167. });
  168. }
  169. void eventReport(String eventId, {Map<String, dynamic>? params}) {
  170. talkController.eventReport(eventId, params: params);
  171. }
  172. void requestOriginal() {
  173. if (talkController.talkBean.value?.status.value ==
  174. TalkStatus.analysisSuccess) {
  175. eventReport(EventId.event_101300);
  176. } else if (talkController.talkBean.value?.status.value ==
  177. TalkStatus.analysisFail) {
  178. eventReport(EventId.event_101301);
  179. }
  180. if (originalList.isNotEmpty) {
  181. return;
  182. }
  183. talkRepository
  184. .talkOriginal(talkController.talkBean.value?.id)
  185. .then((value) {
  186. originalList.value = value;
  187. });
  188. }
  189. void talkTranslateClick(TalkOriginal item) {
  190. if (!accountRepository.isLogin.value) {
  191. ToastUtil.showToast(StringName.errorCodeNoLogin.tr);
  192. return;
  193. }
  194. if (item.getTranslateStatus() == TalkTranslate.translating ||
  195. item.getTranslateStatus() == TalkTranslate.translated) {
  196. return;
  197. }
  198. if (item.sentence == null || item.sentence!.isEmpty) {
  199. ToastUtil.showToast('翻译内容为空');
  200. return;
  201. }
  202. item.setTranslateStatus(TalkTranslate.translating);
  203. talkRepository.talkTranslate(item.sentence!).then((result) {
  204. item.setTranslateStatus(TalkTranslate.translated);
  205. item.setTranslatedSentence(result.translation);
  206. }).catchError((error) {
  207. item.setTranslateStatus(TalkTranslate.normal);
  208. ErrorHandler.toastError(error);
  209. });
  210. }
  211. void scrollToIndex(int? index) {
  212. if (index == null) {
  213. return;
  214. }
  215. itemScrollController.scrollTo(
  216. index: index,
  217. duration: const Duration(milliseconds: 1),
  218. curve: Curves.easeInOut);
  219. }
  220. @override
  221. void onClose() {
  222. super.onClose();
  223. _talkBeanListener?.cancel();
  224. _talkStatusListener?.cancel();
  225. _audioPlayingListener?.cancel();
  226. _searchPrintListener?.cancel();
  227. _searchOperationListener?.cancel();
  228. }
  229. }
  230. class OriginalSearch {
  231. TalkOriginal? searchTargetBean;
  232. int? searchTargetIndex;
  233. int? searchTargetLength;
  234. int? originalIndex;
  235. }