controller.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:connectivity_plus/connectivity_plus.dart';
  4. import 'package:electronic_assistant/base/base_controller.dart';
  5. import 'package:electronic_assistant/data/consts/event_report_id.dart';
  6. import 'package:electronic_assistant/data/repositories/account_repository.dart';
  7. import 'package:electronic_assistant/data/repositories/task_repository.dart';
  8. import 'package:electronic_assistant/handler/event_handler.dart';
  9. import 'package:electronic_assistant/module/chat/view.dart';
  10. import 'package:electronic_assistant/module/login/view.dart';
  11. import 'package:electronic_assistant/module/record/record_handler.dart';
  12. import 'package:electronic_assistant/module/store/view.dart';
  13. import 'package:electronic_assistant/module/talk/todo/controller.dart';
  14. import 'package:electronic_assistant/resource/assets.gen.dart';
  15. import 'package:electronic_assistant/resource/colors.gen.dart';
  16. import 'package:electronic_assistant/resource/string.gen.dart';
  17. import 'package:electronic_assistant/router/app_pages.dart';
  18. import 'package:electronic_assistant/utils/audio_picker_utils.dart';
  19. import 'package:electronic_assistant/utils/error_handler.dart';
  20. import 'package:electronic_assistant/utils/expand.dart';
  21. import 'package:electronic_assistant/utils/file_upload_check_helper.dart';
  22. import 'package:electronic_assistant/utils/mmkv_util.dart';
  23. import 'package:flutter/cupertino.dart';
  24. import 'package:flutter/material.dart';
  25. import 'package:flutter/scheduler.dart';
  26. import 'package:flutter_screenutil/flutter_screenutil.dart';
  27. import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
  28. import 'package:get/get.dart';
  29. import 'package:just_audio/just_audio.dart';
  30. import 'package:share_plus/share_plus.dart';
  31. import 'package:wakelock_plus/wakelock_plus.dart';
  32. import '../../data/api/request/agenda_update_bean.dart';
  33. import '../../data/bean/agenda.dart';
  34. import '../../data/bean/agenda_list_all_bean.dart';
  35. import '../../data/bean/talks.dart';
  36. import '../../data/bean/template_bean.dart';
  37. import '../../data/repositories/agenda_repository.dart';
  38. import '../../data/repositories/talk_repository.dart';
  39. import '../../dialog/add_agenda_dialog.dart';
  40. import '../../dialog/alert_dialog.dart';
  41. import '../../dialog/rename_dialog.dart';
  42. import '../../dialog/talk_share_dialog.dart';
  43. import '../../utils/common_utils.dart';
  44. import '../../utils/event_bus.dart';
  45. import '../../utils/system_share_util.dart';
  46. import '../../utils/toast_util.dart';
  47. class TalkController extends BaseController {
  48. static const String argumentItem = 'argument_item';
  49. static const String argumentTalkId = 'argument_talk_id';
  50. static const String argumentEventTag = 'argument_event_tag';
  51. final String uploadNoPrompts = "UPLOAD_NO_PROMPTS";
  52. final Rxn<TalkBean> talkBean = Rxn();
  53. StreamSubscription? _talkUploadListener;
  54. final RxDouble uploadProgress = RxDouble(0);
  55. final isShowElectricLow = false.obs;
  56. bool isAudioLoading = false;
  57. final double sliderMax = 1;
  58. bool? audioFileIsExist;
  59. bool? isUploadedFile;
  60. Rxn<bool> isUploading = Rxn();
  61. final isAudioPlaying = false.obs;
  62. final audioProgressValue = 0.0.obs;
  63. final audioDuration = Duration.zero.obs;
  64. final agendaOriginalAllList = <AgendaListAllBean>[];
  65. final agendaAllList = <AgendaListAllBean>[].obs;
  66. final _isEditModel = false.obs;
  67. final defaultIndex = 0;
  68. final Rxn<TalkBarBean> checkTabBean = Rxn();
  69. final List<TalkBarBean> tabBeans = [
  70. TalkBarBean(TalkBarType.summary, StringName.talkTabSummary.tr, true),
  71. TalkBarBean(TalkBarType.mindMap, StringName.talkMindMap.tr, false,
  72. isDisallowScroll: true),
  73. TalkBarBean(TalkBarType.myTask, StringName.talkTabMyTask.tr, true),
  74. TalkBarBean(TalkBarType.original, StringName.talkTabOriginal.tr, false)
  75. ];
  76. bool get isEditModel => _isEditModel.value;
  77. RxBool get isEditModelRx => _isEditModel;
  78. final _audioPlayer = AudioPlayer();
  79. StreamSubscription? _talkBeanListener;
  80. TextEditingController? _agendaContentController;
  81. TextEditingController? _agendaNameController;
  82. TextEditingController get agendaContentController {
  83. _agendaContentController ??= TextEditingController();
  84. return _agendaContentController!;
  85. }
  86. TextEditingController get agendaNameController {
  87. _agendaNameController ??= TextEditingController();
  88. return _agendaNameController!;
  89. }
  90. String? paramId;
  91. String? eventTag;
  92. bool isLocalFileHas = false;
  93. final Rxn<Duration> playingDuration = Rxn();
  94. bool isFirstRequestTask = true;
  95. //模板
  96. Rxn<List<TemplateBean>?> templateList = Rxn();
  97. Rxn<int> templateSelectId = Rxn();
  98. final RxBool isShowMindFullScreen = false.obs;
  99. final mindFullDuration = const Duration(milliseconds: 250);
  100. GlobalKey headGlobalKey = GlobalKey();
  101. GlobalKey bottomGlobalKey = GlobalKey();
  102. double? _bottomViewHeight;
  103. final RxnDouble _headViewHeight = RxnDouble();
  104. double? get headViewHeight => _headViewHeight.value;
  105. @override
  106. void onInit() {
  107. super.onInit();
  108. checkTabBean.value = tabBeans[defaultIndex];
  109. }
  110. @override
  111. void onReady() {
  112. super.onReady();
  113. _initAudioPlayer();
  114. _getArguments();
  115. eventReport(EventId.event_101001, params: {EventId.id: eventTag});
  116. WidgetsBinding.instance.addPostFrameCallback((_) {
  117. _bottomViewHeight = bottomGlobalKey.currentContext?.size?.height;
  118. _headViewHeight.value = headGlobalKey.currentContext?.size?.height;
  119. });
  120. }
  121. double getBottomViewHeight() {
  122. if (_bottomViewHeight == null) {
  123. return -250.h;
  124. }
  125. return -_bottomViewHeight!;
  126. }
  127. void eventReport(String eventId, {Map<String, dynamic>? params}) {
  128. if (talkBean.value == null || talkBean.value?.isExample == true) {
  129. return;
  130. }
  131. EventHandler.report(eventId, params: params);
  132. }
  133. void _initAudioPlayer() {
  134. _audioPlayer.playerStateStream.listen((playerState) {
  135. if (playerState.processingState == ProcessingState.loading ||
  136. playerState.processingState == ProcessingState.buffering) {
  137. isAudioLoading = true;
  138. debugPrint('音频load = true');
  139. } else {
  140. debugPrint('音频load = false');
  141. isAudioLoading = false;
  142. if (playerState.processingState == ProcessingState.completed) {
  143. _audioPlayer.stop();
  144. _audioPlayer.seek(Duration.zero);
  145. isAudioPlaying.value = false;
  146. debugPrint('音频 播放结束了');
  147. }
  148. }
  149. isAudioPlaying.value = playerState.playing;
  150. }, onError: (Object e, StackTrace stackTrace) {
  151. debugPrint('音频加载异常 == $e');
  152. });
  153. _audioPlayer.durationStream.listen((duration) {
  154. if (duration != null) {
  155. debugPrint('音频总播放时长 == ${duration.inMilliseconds}');
  156. audioDuration.value = duration;
  157. }
  158. });
  159. _audioPlayer.positionStream.listen((duration) {
  160. debugPrint('音频播放时长 == ${duration.inMilliseconds}');
  161. playingDuration.value = duration;
  162. if (audioDuration.value.inMilliseconds > 0) {
  163. audioProgressValue.value =
  164. (duration.inMilliseconds / audioDuration.value.inMilliseconds)
  165. .clamp(0.0, sliderMax);
  166. }
  167. });
  168. }
  169. void _dealTalk(TalkBean? bean) async {
  170. debugPrint('talkBean == $bean');
  171. String? id = bean?.id;
  172. if (id == null) {
  173. return;
  174. }
  175. _loadAudioFile(bean);
  176. if (bean?.status.value == TalkStatus.notAnalysis) {
  177. setUploadingProgress(id);
  178. }
  179. if (bean?.status.value == TalkStatus.notAnalysis &&
  180. talkRepository.isUploadingTalk(id)) {
  181. isUploading.value = true;
  182. } else {
  183. isUploading.value = false;
  184. }
  185. }
  186. void setUploadingProgress(String id) {
  187. talkRepository.getUploadProgress(id).listen((progress) {
  188. uploadProgress.value = (progress * 20).toFormattedDouble(1);
  189. });
  190. }
  191. Future<void> _loadAudioFile(TalkBean? bean, {bool? loadPlay}) async {
  192. try {
  193. Uri? uri;
  194. if (bean?.isExample == true && bean?.audioUrl != null) {
  195. uri = Uri.parse(bean!.audioUrl!);
  196. } else {
  197. File? file = await getFileByTalk(talkBean.value);
  198. if (file?.existsSync() == true) {
  199. uri = file?.uri;
  200. }
  201. }
  202. if (uri == null) {
  203. throw '音频文件不存在';
  204. }
  205. await _audioPlayer.setAudioSource(AudioSource.uri(uri));
  206. if (loadPlay == true) {
  207. clickPlayAudio();
  208. }
  209. audioFileIsExist = true;
  210. } catch (e) {
  211. audioFileIsExist = false;
  212. debugPrint('音频设置异常 == $e');
  213. }
  214. }
  215. void _getArguments() {
  216. TalkBean? bean = parameters?[argumentItem];
  217. if (bean != null) {
  218. talkBean.value = bean;
  219. debugPrint('talkBean == ${bean.summary}');
  220. _dealTalk(bean);
  221. } else {
  222. paramId = parameters?[argumentTalkId];
  223. if (paramId != null) {
  224. talkRepository.talkInfo(paramId!).then((data) {
  225. talkBean.value = data.talkInfo;
  226. _dealTalk(data.talkInfo);
  227. }).catchError((error) {
  228. ErrorHandler.toastError(error);
  229. });
  230. }
  231. }
  232. eventTag = parameters?[argumentEventTag];
  233. }
  234. void updateProgress(double value) {
  235. final newPosition = Duration(
  236. milliseconds: (value * audioDuration.value.inMilliseconds).toInt());
  237. _audioPlayer.seek(newPosition);
  238. }
  239. void clickPlayAudio() async {
  240. if (audioFileIsExist != true && isLocalFileHas == false) {
  241. ToastUtil.showToast(StringName.talkFileNotFind.tr);
  242. return;
  243. }
  244. if (isLocalFileHas == true &&
  245. audioFileIsExist == false &&
  246. !await AudioPickerUtils.hasPermission()) {
  247. bool has = await AudioPickerUtils.requestPermissionExtend();
  248. if (has == false) {
  249. ToastUtil.showToast(StringName.authorizationFailed.tr);
  250. return;
  251. }
  252. //重新加载
  253. _loadAudioFile(talkBean.value, loadPlay: true);
  254. return;
  255. }
  256. if (isAudioLoading) {
  257. ToastUtil.showToast(StringName.talkAudioLoading.tr);
  258. return;
  259. }
  260. if (_audioPlayer.playing) {
  261. _audioPlayer.pause();
  262. isAudioPlaying.value = false;
  263. } else {
  264. _audioPlayer.play();
  265. isAudioPlaying.value = true;
  266. }
  267. }
  268. void _checkFileSizeAndNet() async {
  269. String? id = talkBean.value?.id;
  270. if (id == null) {
  271. return;
  272. }
  273. File? file = await getFileByTalk(talkBean.value);
  274. if (isLocalFileHas == true &&
  275. audioFileIsExist == false &&
  276. !await AudioPickerUtils.hasPermission()) {
  277. bool has = await AudioPickerUtils.requestPermissionExtend();
  278. if (has == false) {
  279. ToastUtil.showToast(StringName.authorizationFailed.tr);
  280. return;
  281. }
  282. //重新上传
  283. _checkFileSizeAndNet();
  284. return;
  285. }
  286. if (file == null || !file.existsSync()) {
  287. ToastUtil.showToast(StringName.talkUploadFileNotExist.tr);
  288. return;
  289. }
  290. bool isCheckRemind = KVUtil.getBool(uploadNoPrompts, false);
  291. if (isCheckRemind) {
  292. _requestAnalyze(file);
  293. return;
  294. }
  295. //如果文件大小低于250MB 不弹窗提醒
  296. if (file.lengthSync() < 250 * 1024 * 1024) {
  297. _requestAnalyze(file);
  298. return;
  299. }
  300. final List<ConnectivityResult> connectivityResult =
  301. await (Connectivity().checkConnectivity());
  302. if (connectivityResult.contains(ConnectivityResult.wifi)) {
  303. _requestAnalyze(file);
  304. } else {
  305. _showTrafficRemindDialog(file.lengthSync().toReadableSize(),
  306. confirmOnTap: (isCheckRemind) {
  307. if (isCheckRemind) {
  308. KVUtil.putBool(uploadNoPrompts, true);
  309. }
  310. _requestAnalyze(file);
  311. });
  312. }
  313. }
  314. void _showTrafficRemindDialog(String holderTxt,
  315. {void Function(bool isCheckRemind)? confirmOnTap}) {
  316. final remindTrafficConsume = false.obs;
  317. Widget getSelectIcon() {
  318. return Obx(() {
  319. return remindTrafficConsume.value
  320. ? Assets.images.iconSelectTrue.image()
  321. : Assets.images.iconSelectFalse.image();
  322. });
  323. }
  324. Assets.images.iconSelectTrue.image();
  325. EAAlertDialog.show(
  326. contentWidget: Column(
  327. children: [
  328. Text(
  329. StringName.talkTrafficRemindTitle.tr
  330. .replacePlaceholders([holderTxt]),
  331. style:
  332. TextStyle(fontSize: 15.sp, color: ColorName.primaryTextColor),
  333. ),
  334. SizedBox(height: 8.h),
  335. GestureDetector(
  336. onTap: () {
  337. remindTrafficConsume.value = !remindTrafficConsume.value;
  338. },
  339. child: IntrinsicWidth(
  340. child: Row(
  341. children: [
  342. SizedBox(width: 20.w, height: 20.w, child: getSelectIcon()),
  343. SizedBox(width: 5.w),
  344. Text(
  345. StringName.talkTrafficRemindTips.tr,
  346. style: TextStyle(
  347. fontSize: 15.sp, color: ColorName.tertiaryTextColor),
  348. )
  349. ],
  350. ),
  351. ),
  352. )
  353. ],
  354. ),
  355. cancelText: StringName.cancel.tr,
  356. confirmText: StringName.sure.tr,
  357. confirmOnTap: () {
  358. confirmOnTap?.call(remindTrafficConsume.value);
  359. });
  360. }
  361. void checkCanAnalyze() {
  362. String? id = talkBean.value?.id;
  363. double? duration = talkBean.value?.duration;
  364. if (id == null || duration == null) {
  365. return;
  366. }
  367. eventReport(EventId.event_101002);
  368. talkRepository.checkElectric(duration).then((data) {
  369. if (data.enough) {
  370. //检查网络以及文件大小
  371. _checkFileSizeAndNet();
  372. } else {
  373. ToastUtil.showToast(StringName.talkAnalyseLowToast.tr);
  374. isShowElectricLow.value = true;
  375. }
  376. }).catchError((error) {
  377. ErrorHandler.toastError(error);
  378. });
  379. }
  380. void _requestAnalyze(File file) {
  381. String? talkId = talkBean.value?.id;
  382. double? duration = talkBean.value?.duration;
  383. if (talkId == null || duration == null || isUploadedFile == true) {
  384. return;
  385. }
  386. isUploading.value = true;
  387. WakelockPlus.enable();
  388. talkRepository.uploadTalkFile(talkId, duration, file).then((taskId) {
  389. isUploadedFile = true;
  390. isUploading.value = false;
  391. talkBean.value?.progressContent.value =
  392. StringName.talkUploadingFileTip.tr;
  393. talkBean.value?.progress.value = 20;
  394. talkBean.value?.status.value = TalkStatus.analysing;
  395. taskRepository.addTask(taskId);
  396. }).catchError((error) {
  397. isUploading.value = false;
  398. ErrorHandler.toastError(error);
  399. }).whenComplete(() => WakelockPlus.disable());
  400. }
  401. void refreshAgendaAllData({bool isForceRefresh = false}) {
  402. String? id = talkBean.value?.id;
  403. if (id == null || (!isForceRefresh && agendaAllList.isNotEmpty)) {
  404. return;
  405. }
  406. agendaRepository.agendaListAll(id).then((agenda) {
  407. isFirstRequestTask = false;
  408. agendaAllList.clear();
  409. agendaOriginalAllList.clear();
  410. if (agenda.list != null) {
  411. agendaOriginalAllList.addAll(
  412. agenda.list!.map((item) => AgendaListAllBean.from(item)).toList());
  413. agendaAllList.addAll(agenda.list!);
  414. }
  415. });
  416. }
  417. void clickAIAnalysis() async {
  418. if (!await checkLogin()) {
  419. return;
  420. }
  421. if (talkBean.value != null) {
  422. eventReport(EventId.event_101003);
  423. ChatPage.startByTalk(
  424. talkBean.value!.isExample == true
  425. ? ChatFromType.fromTalkExample
  426. : ChatFromType.fromTalkDetail,
  427. talkBean.value!);
  428. }
  429. }
  430. void onGoElectricStore() {
  431. StorePage.start(fromType: StoreFromType.analyse);
  432. Future.delayed(const Duration(milliseconds: 250), () {
  433. isShowElectricLow.value = false;
  434. });
  435. }
  436. void onEditModelClick() async {
  437. if (!await checkLogin()) {
  438. return;
  439. }
  440. _isEditModel.value = true;
  441. if (_audioPlayer.playing) {
  442. _audioPlayer.pause();
  443. isAudioPlaying.value = false;
  444. }
  445. }
  446. void updateTabIndex(int index) {
  447. checkTabBean.value = tabBeans[index];
  448. }
  449. void onEditCancel() {
  450. _isEditModel.value = false;
  451. agendaAllList.assignAll(agendaOriginalAllList
  452. .map((item) => AgendaListAllBean.from(item))
  453. .toList());
  454. }
  455. void onEditDoneClick() {
  456. if (talkBean.value == null) {
  457. return;
  458. }
  459. List<AgendaUpdateBean> list = [];
  460. for (AgendaListAllBean item in agendaAllList) {
  461. if (item.list != null) {
  462. for (Agenda agenda in item.list!) {
  463. list.add(AgendaUpdateBean(agenda.id, agenda.name, agenda.content));
  464. }
  465. }
  466. }
  467. agendaRepository.agendaUpdate(talkBean.value!.id, list).then((data) {
  468. refreshAgendaAllData(isForceRefresh: true);
  469. eventBus.emit(TodoController.refreshTalkMineTask);
  470. isEditModelRx.value = false;
  471. }).catchError((error) {
  472. ErrorHandler.toastError(error);
  473. });
  474. }
  475. void removeTalkAgenda(List<Agenda>? list, Agenda agenda) {
  476. list?.remove(agenda);
  477. agendaAllList.refresh();
  478. }
  479. void showSingleAddAgendaDialog(BuildContext context) {
  480. showAddAgendaDialog(context, agendaContentController, agendaNameController,
  481. list: agendaAllList.map((e) => e.name ?? "").toList(), callback: () {
  482. if (agendaContentController.text.isEmpty) {
  483. ToastUtil.showToast(StringName.talkAddAgendaContentHint.tr);
  484. return;
  485. }
  486. if (agendaNameController.text.isEmpty) {
  487. ToastUtil.showToast(StringName.talkAddAgendaNameHint.tr);
  488. return;
  489. }
  490. Get.back();
  491. _dealAddProcedureList();
  492. });
  493. }
  494. void _dealAddProcedureList() {
  495. String name = agendaNameController.text;
  496. final addItem = Agenda(
  497. id: "",
  498. talkId: "",
  499. name: name,
  500. );
  501. addItem.content = agendaContentController.text;
  502. for (AgendaListAllBean item in agendaAllList) {
  503. if (item.name == name) {
  504. List<Agenda> list = item.list ?? [];
  505. list.add(addItem);
  506. item.list = list;
  507. agendaAllList.refresh();
  508. agendaContentController.clear();
  509. agendaNameController.clear();
  510. return;
  511. }
  512. }
  513. agendaAllList.add(AgendaListAllBean(name: name, list: [addItem]));
  514. agendaContentController.clear();
  515. agendaNameController.clear();
  516. }
  517. Future<File?> getFileByTalk(TalkBean? bean) async {
  518. isLocalFileHas = false;
  519. if (bean == null) {
  520. return null;
  521. }
  522. if (bean.uploadType == TalkUploadType.localUpload) {
  523. String? audioId =
  524. FileUploadCheckHelper.getLocalAudioId(bean.localAudioUrl);
  525. if (audioId != null && audioId.isNotEmpty) {
  526. isLocalFileHas = true;
  527. return await AudioPickerUtils.getAssetFile(audioId);
  528. } else {
  529. return await FileUploadCheckHelper.getChoiceUploadFile(bean.id);
  530. }
  531. } else {
  532. return await RecordHandler.getRecordFile(bean.id);
  533. }
  534. }
  535. Future<bool> checkLogin() async {
  536. if (!accountRepository.isLogin.value) {
  537. bool isLogin = await LoginPage.start(fromType: LoginFromType.talkDetail);
  538. if (isLogin) {
  539. backToSpecificPage(RoutePath.mainTab);
  540. }
  541. return false;
  542. }
  543. return true;
  544. }
  545. void onShareClick() async {
  546. if (!await checkLogin()) {
  547. return;
  548. }
  549. if (talkBean.value?.status.value != TalkStatus.analysisSuccess) {
  550. return;
  551. }
  552. eventReport(EventId.event_101004);
  553. showTalkShareDialog(talkBean.value?.title.value,
  554. (type, shareTo, fileName, tag) {
  555. if (type == ShareTalkType.summary || type == ShareTalkType.original) {
  556. _shareSummaryOrOriginal(
  557. talkBean.value!.id, fileName, type, shareTo, tag);
  558. } else if (type == ShareTalkType.mindMap) {
  559. //TODO 生成思维导图
  560. _shareMindMap();
  561. }
  562. });
  563. }
  564. void _shareMindMap() {}
  565. void _shareSummaryOrOriginal(String id, String fileName, ShareTalkType type,
  566. ShareTo shareTo, String tag) async {
  567. talkRepository.talkExport(id, fileName, type).then((file) async {
  568. if (shareTo == ShareTo.ios) {
  569. await Share.shareXFiles([XFile(file.path)], subject: fileName);
  570. } else if (shareTo == ShareTo.wechat) {
  571. await SystemShareUtil.shareWechatFile(file.path);
  572. } else if (shareTo == ShareTo.qq) {
  573. await SystemShareUtil.shareQQFile(file.path);
  574. }
  575. SmartDialog.dismiss(tag: tag);
  576. }).catchError((error) {
  577. if (error is SystemShareException) {
  578. ToastUtil.showToast(error.message);
  579. } else {
  580. ErrorHandler.toastError(error);
  581. }
  582. });
  583. }
  584. void seekTo(int? startMs) {
  585. if (startMs == null) {
  586. return;
  587. }
  588. _audioPlayer.seek(Duration(milliseconds: startMs));
  589. }
  590. Future<TalkBean?> refreshTalkDetail() async {
  591. String? id = talkBean.value?.id;
  592. if (id == null) {
  593. return null;
  594. }
  595. return talkRepository.talkInfo(id).then((data) {
  596. var bean = data.talkInfo;
  597. if (bean != null) {
  598. if (talkBean.value == null) {
  599. talkBean.value = data.talkInfo;
  600. } else {
  601. talkBean.value?.updateBean(bean);
  602. }
  603. templateSelectId.value = bean.templateId;
  604. }
  605. templateList.value = data.templateList;
  606. return bean;
  607. });
  608. }
  609. void onEditTitleClick() {
  610. reNameDialog(StringName.talkRenameTitle.tr, talkBean.value?.title.value,
  611. hintTxt: StringName.talkRenameTitleHint.tr,
  612. maxLength: 15, returnBuilder: (newName) {
  613. talkRepository.talkRename(talkBean.value!.id, newName).then((data) {
  614. talkBean.value?.title.value = newName;
  615. }).catchError((error) {
  616. ErrorHandler.toastError(error);
  617. });
  618. });
  619. }
  620. void onExitMindFullScreen() {
  621. isShowMindFullScreen.value = false;
  622. }
  623. @override
  624. void onClose() {
  625. super.onClose();
  626. _talkUploadListener?.cancel();
  627. _talkBeanListener?.cancel();
  628. _audioPlayer.dispose();
  629. _agendaContentController?.dispose();
  630. _agendaNameController?.dispose();
  631. }
  632. }
  633. enum TalkBarType { summary, mindMap, myTask, original }
  634. class TalkBarBean {
  635. final TalkBarType type;
  636. final String title;
  637. final bool isShowEdit;
  638. final bool? isDisallowScroll;
  639. TalkBarBean(this.type, this.title, this.isShowEdit, {this.isDisallowScroll});
  640. }