controller.dart 21 KB

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