You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
10 KiB
320 lines
10 KiB
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:audio_waveforms/audio_waveforms.dart';
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart' show rootBundle;
|
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import '../../../core/utils/synchrodata.dart';
|
|
import '../../../data/services/db/sqflite_api.dart';
|
|
import '../../../data/services/meeting/meeting_task_service.dart';
|
|
import '../../../data/services/meeting/meeting_task_service2.dart';
|
|
import '../../../data/services/meeting/meeting_upload_service.dart';
|
|
import '../../../data/services/meeting/summary_task_service.dart';
|
|
import '../model/meeting_details_model.dart';
|
|
import '../model/meeting_model.dart';
|
|
|
|
/// 会议详情控制器
|
|
class MeetingDetailsController extends GetxController
|
|
with GetTickerProviderStateMixin {
|
|
late TabController tabController;
|
|
final RxInt currentIndex = 0.obs;
|
|
|
|
late AnimationController lottieController;
|
|
|
|
late final Worker _tasktypeListener;
|
|
late final Worker _tasktypeListenerV2;
|
|
|
|
final _meetingUploadService = Get.find<MeetingUploadService>();
|
|
final _meetingTaskService = Get.find<MeetingTaskService>();
|
|
final _meetingTaskService2 = Get.find<MeetingTaskService2>();
|
|
final _summaryTaskService = Get.find<SummaryTaskService>();
|
|
|
|
final PlayerController playerController = PlayerController();
|
|
|
|
StreamSubscription? _currentDurationSubscription;
|
|
StreamSubscription? _playerStateSubscription;
|
|
|
|
RxBool isTop = false.obs;
|
|
RxInt durationMax = 0.obs;
|
|
RxDouble dragOffset = 210.w.obs;
|
|
|
|
RxBool isPlay = false.obs;
|
|
RxInt currentDuration = 0.obs;
|
|
|
|
RxInt speakerAllStarttime = (-1).obs;
|
|
RxInt speakerAllEndtime = (-1).obs;
|
|
|
|
int id = 0;
|
|
|
|
RxBool isLoading = true.obs;
|
|
Rx<MeetingModel> meetingData = MeetingModel().obs;
|
|
Rx<MeetingDetailsModel> meetingDetails = MeetingDetailsModel().obs;
|
|
RxList textList = [].obs;
|
|
RxBool isSpeakerText = false.obs;
|
|
List editSpeakerTextList = [];
|
|
RxInt editSpeakerTextId = 0.obs;
|
|
String editSpeakerTextChange = '';
|
|
|
|
int _everType = 99;
|
|
RxInt summaryNumberModifications = 0.obs;
|
|
RxInt personnelNumberModifications = 0.obs;
|
|
|
|
String markmapLibJs = '';
|
|
String d3Js = '';
|
|
String markmapViewJs = '';
|
|
String markmapToolbarJs = '';
|
|
String saveSvgAsPngJs = '';
|
|
|
|
RxBool isDownload = false.obs;
|
|
RxDouble downloadProgress = 0.0.obs;
|
|
|
|
List categoryTemplateList = [];
|
|
Map editTemplate = {};
|
|
int deleteTemplateId = 0;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
tabController = TabController(length: 4, vsync: this);
|
|
tabController.addListener(() {
|
|
if (currentIndex.value == 2 && tabController.index != 2) {
|
|
FocusScope.of(Get.context!).unfocus();
|
|
}
|
|
currentIndex.value = tabController.index;
|
|
});
|
|
lottieController = AnimationController(vsync: this)
|
|
..duration = const Duration(seconds: 2);
|
|
final Map<String, dynamic> args = Get.arguments ?? {};
|
|
id = args['id'];
|
|
_meetingTaskService.meetingId = id;
|
|
_getDataDetails();
|
|
_loadJS();
|
|
_tasktypeListener = ever(_meetingTaskService.tasktype, (value) {
|
|
meetingDetails.value.tasktype = value;
|
|
if (_everType <= value) {
|
|
if (value == 2) {
|
|
textList.value = _meetingTaskService.textList;
|
|
} else if (value == 3) {
|
|
meetingDetails.value.summary = _summaryTaskService.summary;
|
|
meetingDetails.value.overview = _summaryTaskService.overview;
|
|
summaryNumberModifications.value++;
|
|
}
|
|
}
|
|
meetingDetails.refresh();
|
|
});
|
|
_tasktypeListenerV2 = ever(_meetingTaskService2.tasktype, (value) {
|
|
meetingDetails.value.tasktype = value;
|
|
if (_everType <= value) {
|
|
if (value == 2) {
|
|
textList.value = _meetingTaskService2.textList;
|
|
} else if (value == 3) {
|
|
meetingDetails.value.summary = _meetingTaskService2.summary;
|
|
meetingDetails.value.overview = _meetingTaskService2.overview;
|
|
summaryNumberModifications.value++;
|
|
}
|
|
}
|
|
meetingDetails.refresh();
|
|
});
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_tasktypeListener.dispose();
|
|
_tasktypeListenerV2.dispose();
|
|
_currentDurationSubscription?.cancel();
|
|
_playerStateSubscription?.cancel();
|
|
tabController.dispose();
|
|
playerController.dispose();
|
|
lottieController.dispose();
|
|
super.onClose();
|
|
}
|
|
|
|
void popInvokedWithResult(didPop, result) async {
|
|
_meetingUploadService.removeUpload(id);
|
|
_meetingTaskService.removeTask(id);
|
|
_meetingTaskService2.removeTask(id);
|
|
_meetingTaskService.meetingId = 0;
|
|
}
|
|
|
|
void _getDataDetails() async {
|
|
final data = await SqfliteApi.getMeetingDetails(id);
|
|
meetingData.value = MeetingModel.fromJson(data);
|
|
meetingDetails.value = MeetingDetailsModel.fromJson(data['details']);
|
|
_everType = meetingDetails.value.tasktype + 1;
|
|
_meetingTaskService.tasktype.value = meetingDetails.value.tasktype;
|
|
if (meetingDetails.value.tasktype >= 3) {
|
|
dragOffset.value = 0;
|
|
isTop.value = true;
|
|
}
|
|
if (meetingData.value.filepath.isNotEmpty) {
|
|
await _loadPlayerController();
|
|
}
|
|
if (meetingDetails.value.tasktype >= 2) {
|
|
List speakerList = await SqfliteApi.getMeetingSpeaker(id);
|
|
textList.value = List.from(speakerList);
|
|
}
|
|
isLoading.value = false;
|
|
}
|
|
|
|
Future<void> _loadPlayerController() async {
|
|
await playerController.preparePlayer(
|
|
path: meetingData.value.filepath,
|
|
shouldExtractWaveform: false,
|
|
noOfSamples: 88,
|
|
);
|
|
durationMax.value = await playerController.getDuration(DurationType.max);
|
|
playerController.setFinishMode(finishMode: FinishMode.pause);
|
|
_currentDurationSubscription =
|
|
playerController.onCurrentDurationChanged.listen((int position) {
|
|
currentDuration.value = position;
|
|
if (speakerAllEndtime.value > 0) {
|
|
if (position >= speakerAllEndtime.value) {
|
|
playerController.pausePlayer();
|
|
speakerAllStarttime.value = -1;
|
|
speakerAllEndtime.value = -1;
|
|
}
|
|
}
|
|
});
|
|
_playerStateSubscription =
|
|
playerController.onPlayerStateChanged.listen((PlayerState playerState) {
|
|
isPlay.value = playerState.isPlaying;
|
|
if (playerState.isPlaying) {
|
|
lottieController.repeat();
|
|
} else {
|
|
lottieController.stop();
|
|
}
|
|
});
|
|
}
|
|
|
|
void _loadJS() async {
|
|
markmapLibJs = await rootBundle.loadString('assets/js/markmap-lib.js');
|
|
d3Js = await rootBundle.loadString('assets/js/d3@7.js');
|
|
markmapViewJs = await rootBundle.loadString('assets/js/markmap-view.js');
|
|
markmapToolbarJs =
|
|
await rootBundle.loadString('assets/js/markmap-toolbar.js');
|
|
saveSvgAsPngJs =
|
|
await rootBundle.loadString('assets/js/saveSvgAsPng.min.js');
|
|
}
|
|
|
|
void downloadAudio() async {
|
|
if (isDownload.value) return;
|
|
isDownload.value = true;
|
|
final directory = await getApplicationDocumentsDirectory();
|
|
final directoryDir = Directory('${directory.path}/DownloadAudio');
|
|
if (!await directoryDir.exists()) {
|
|
await directoryDir.create(recursive: true);
|
|
}
|
|
final fileName = meetingData.value.audiourl.split('/').last;
|
|
final String filePath = '${directory.path}/DownloadAudio/$fileName';
|
|
await Dio().download(
|
|
meetingData.value.audiourl,
|
|
filePath,
|
|
onReceiveProgress: (int received, int total) {
|
|
downloadProgress.value = total > 0 ? received / total : 0.0;
|
|
},
|
|
);
|
|
meetingData.value.filepath = filePath;
|
|
meetingData.refresh();
|
|
_loadPlayerController();
|
|
SqfliteApi.editMeetingTitle(id, {'filePath': filePath});
|
|
isDownload.value = false;
|
|
}
|
|
|
|
void editSpeakerText() async {
|
|
if (editSpeakerTextId.value != 0 && editSpeakerTextChange.isNotEmpty) {
|
|
Map? foundElement = editSpeakerTextList.firstWhere(
|
|
(element) => element['id'] == editSpeakerTextId.value,
|
|
orElse: () => null,
|
|
);
|
|
if (foundElement != null) {
|
|
foundElement['content'] = editSpeakerTextChange;
|
|
} else {
|
|
editSpeakerTextList.add({
|
|
'id': editSpeakerTextId.value,
|
|
'content': editSpeakerTextChange,
|
|
});
|
|
}
|
|
}
|
|
if (editSpeakerTextList.isNotEmpty) {
|
|
EasyLoading.show();
|
|
var result = await SqfliteApi.editMeetingSpeaker(editSpeakerTextList);
|
|
if (result != null) {
|
|
for (var element in editSpeakerTextList) {
|
|
int index =
|
|
textList.indexWhere((item) => item['id'] == element['id']);
|
|
if (index != -1) {
|
|
final dataMap = Map<String, dynamic>.from(textList[index]);
|
|
dataMap['content'] = element['content'];
|
|
textList[index] = dataMap;
|
|
}
|
|
}
|
|
Synchrodata.saveOperationRecord('update', {
|
|
'original': jsonEncode(textList),
|
|
'id': id,
|
|
});
|
|
isSpeakerText.value = false;
|
|
editSpeakerTextId.value = 0;
|
|
editSpeakerTextList = [];
|
|
}
|
|
EasyLoading.dismiss();
|
|
} else {
|
|
isSpeakerText.value = false;
|
|
editSpeakerTextId.value = 0;
|
|
editSpeakerTextList = [];
|
|
}
|
|
}
|
|
|
|
void summaryCreate(
|
|
bool isSpeaker, String language, String prompt, String outline) async {
|
|
EasyLoading.show();
|
|
_everType = 2;
|
|
final String audiourl = meetingData.value.audiourl;
|
|
final int seconds = meetingData.value.seconds;
|
|
if (seconds > 0 && seconds <= 7200) {
|
|
await _meetingTaskService2.addTask(
|
|
id,
|
|
audiourl,
|
|
isSpeaker: isSpeaker,
|
|
language: language,
|
|
targetLanguage: '',
|
|
prompt: prompt,
|
|
outline: outline,
|
|
);
|
|
} else {
|
|
final String taskId = meetingDetails.value.taskid;
|
|
await _meetingTaskService.addTask(
|
|
id,
|
|
audiourl,
|
|
taskId,
|
|
isSpeaker,
|
|
language,
|
|
prompt,
|
|
outline,
|
|
);
|
|
}
|
|
meetingDetails.value.tasktype = 1;
|
|
meetingDetails.refresh();
|
|
EasyLoading.dismiss();
|
|
}
|
|
|
|
void refreshSummary(String prompt, String outline) async {
|
|
String text = '';
|
|
for (var element in textList) {
|
|
if (element['speaker'].isNotEmpty) {
|
|
text += '[${element['speaker']}]: ';
|
|
}
|
|
text += '${element['content']}\n';
|
|
}
|
|
_everType = 3;
|
|
await SqfliteApi.editMeeting(id, {'tasktype': 2});
|
|
_meetingTaskService.tasktype.value = 2;
|
|
_summaryTaskService.addTaskList(id, text, prompt, outline);
|
|
}
|
|
}
|
|
|