import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:electronic_assistant/data/api/atmob_api.dart'; import 'package:electronic_assistant/data/api/atmob_file_api.dart'; import 'package:electronic_assistant/data/api/atmob_stream_api.dart'; import 'package:electronic_assistant/data/api/request/talk_create_request.dart'; import 'package:electronic_assistant/data/api/request/talk_delete_request.dart'; import 'package:electronic_assistant/data/api/request/talk_file_request.dart'; import 'package:electronic_assistant/data/api/request/talk_translate_request.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart'; import 'package:get/get.dart'; import 'package:get/get_connect/http/src/request/request.dart'; import 'package:path_provider/path_provider.dart'; import '../../base/base_response.dart'; import '../../dialog/talk_share_dialog.dart'; import '../../utils/foreground_util.dart'; import '../../utils/http_handler.dart'; import '../api/request/talk_export_request.dart'; import '../api/request/talk_generate_request.dart'; import '../api/request/talk_paginate_request.dart'; import '../api/request/talk_rename_request.dart'; import '../api/request/talk_request.dart'; import '../api/request/talk_summary_generate_request.dart'; import '../api/response/talk_check_electric_response.dart'; import '../api/response/talk_info_response.dart'; import '../api/response/talk_paginate_response.dart'; import '../api/response/talk_translate_response.dart'; import '../bean/talk_original.dart'; import '../bean/talks.dart'; import 'account_repository.dart'; class TalkRepository { TalkRepository._(); static const homeMaxShowCount = 15; final Set _uploadingTalkIds = {}; final Map _uploadingTalkProgress = {}; final _talkList = RxList(); RxList get talkList => _talkList; Future talkSummaryGenerate(String id, int templateId) { return atmobApi .talkSummaryGenerate(TalkSummaryGenerateRequest(id, templateId)) .then(HttpHandler.handle(false)); } Future talkTranslate(String content) { return atmobApi .talkTranslate(TalkTranslateRequest(content)) .then(HttpHandler.handle(false)); } bool isUploadingTalk(String talkId) { return _uploadingTalkIds.contains(talkId); } void renovateTalkData(TalkBean talkInfo) { for (int i = 0; i < _talkList.length; i++) { if (_talkList[i].id == talkInfo.id) { _talkList[i].updateBean(talkInfo); break; } } } Future talkExport( String talkId, String fileName, ShareTalkType type) async { ResponseBody responseBody = await atmobStreamApi.talkExportFile( TalkExportRequest(talkId, type == ShareTalkType.summary ? 1 : 2)); List? contentType = responseBody.headers['Content-Type']; if (contentType != null) { for (var value in contentType) { if (value.contains('application/json')) { BaseResponse baseResponse = BaseResponse.fromJson( jsonDecode(await responseBody.stream .map((bytes) => utf8.decoder.convert(bytes)) .toList() .then((value) => value.join())), (json) => json as String); throw ServerErrorException(baseResponse.code, baseResponse.message); } else { final directory = await getTemporaryDirectory(); final filePath = '${directory.path}/export/$fileName'; final file = File(filePath); if (!await file.exists()) { await file.create(recursive: true); } await file.writeAsBytes(await responseBody.stream.toBytes()); return file; } } } throw Exception('Invalid content type'); } void setTalkList(List list) { _talkList.assignAll(list); } void addNewTalkData(TalkBean talkInfo) { _talkList.insert(0, talkInfo); } clearTalkList() { _talkList.clear(); } Future refreshHomeTalkData({int? sortType = 1}) { int limit; if (_talkList.isEmpty || _talkList.length < homeMaxShowCount) { limit = homeMaxShowCount; } else { limit = _talkList.length; } return requestTalkPagePaginate(0, limit, sortType: sortType, isClearAll: true); } Future requestTalkPagePaginate(int offset, int limit, {String? searchKeyword, int? sortType = 1, bool? isClearAll = false}) { return talkPagePaginate(offset, limit, searchKeyword: searchKeyword, sortType: sortType) .then((response) { if (isClearAll == true) { _talkList.clear(); } if (response.list != null) { _talkList.addAll(response.list!); } return response; }); } ///sortType 1:按创建时间倒序 2:按更新时间倒序 Future talkPagePaginate(int offset, int limit, {String? searchKeyword, int? sortType = 1}) { return atmobApi .talkPagePaginate(TalkPaginateRequest(offset, limit, searchKeyword: searchKeyword, sortType: sortType)) .then(HttpHandler.handle(false)); } Future> talkOriginal(String? talkId) { return atmobApi .talkOriginal( TalkRequest(talkId, isExample: !accountRepository.isLogin.value)) .then(HttpHandler.handle(false)) .then((data) { if (data.list != null) { return data.list!; } else { return []; } }); } // duration 音频时长,单位为秒 Future checkElectric(double duration) { return atmobApi .checkElectric(TalkGenerateRequest(duration)) .then(HttpHandler.handle(false)); } Future talkInfo(String id) { return atmobApi .talkInfo(TalkRequest(id, isExample: !accountRepository.isLogin.value)) .then(HttpHandler.handle(true)); } Future talkRename(String? id, String? title) { return atmobApi .talkRename(TalkRenameRequest(id, title)) .then(HttpHandler.handle(true)); } Future talkDelete(String? id) { return atmobApi .talkDelete(TalkDeleteRequest(id)) .then(HttpHandler.handle(true)); } Future talkCreate(String requestId, int duration, {String? localAudioUrl, FileUploadType? uploadType}) { return atmobApi .talkCreate(TalkCreateRequest(duration, requestId, localAudioUrl: localAudioUrl, uploadType: uploadType?.value)) .then(HttpHandler.handle(true)) .then((bean) { //添加新的录音到最新记录 talkRepository.addNewTalkData(bean); return bean; }); } Future uploadTalkFile(String talkId, double duration, File file) { _uploadingTalkIds.add(talkId); startForegroundService( serviceId: talkId.hashCode, notificationTitle: '正在上传录音', notificationText: '请勿关闭应用', callback: setUploadCallback); RxDouble progressRx = getUploadProgress(talkId); return atmobFileApi .uploadTalkFile(TalkFileRequest(talkId, duration, file: file).toJson(), onSendProgress: (count, total) { progressRx.value = count / total; }) .then(HttpHandler.handle(true)) .then((response) { _uploadingTalkIds.remove(talkId); return response.taskId; }) .catchError((error) { _uploadingTalkIds.remove(talkId); throw error; }) .whenComplete(() { stopForegroundService(); }); } RxDouble getUploadProgress(String talkId) { if (_uploadingTalkProgress[talkId] == null) { _uploadingTalkProgress[talkId] = RxDouble(0); } return _uploadingTalkProgress[talkId]!; } } class UploadTaskHandler extends TaskHandler { @override Future onDestroy(DateTime timestamp) { // TODO: implement onDestroy return Future.value(); } @override void onRepeatEvent(DateTime timestamp) { // TODO: implement onRepeatEvent } @override Future onStart(DateTime timestamp, TaskStarter starter) { // TODO: implement onStart return Future.value(); } } @pragma('vm:entry-point') void setUploadCallback() { // The setTaskHandler function must be called to handle the task in the background. FlutterForegroundTask.setTaskHandler(UploadTaskHandler()); } enum FileUploadType { record(0), local(1); final int value; const FileUploadType(this.value); } final talkRepository = TalkRepository._();