file_upload_check_helper.dart 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import 'dart:io';
  2. import 'package:electronic_assistant/utils/pair.dart';
  3. import 'package:electronic_assistant/utils/toast_util.dart';
  4. import 'package:get/get.dart';
  5. import 'package:just_audio/just_audio.dart';
  6. import 'package:uuid/uuid.dart';
  7. import '../data/bean/talks.dart';
  8. import '../data/repositories/talk_repository.dart';
  9. import '../dialog/loading_dialog.dart';
  10. import '../module/talk/view.dart';
  11. import '../resource/string.gen.dart';
  12. import 'audio_picker_utils.dart';
  13. import 'package:path_provider/path_provider.dart';
  14. import 'common_utils.dart';
  15. import 'error_handler.dart';
  16. class FileUploadCheckHelper {
  17. FileUploadCheckHelper._();
  18. static bool isAllowAudioFile(String path) {
  19. try {
  20. String ext = path.split('.').last;
  21. return AudioPickerUtils.allowFileType.contains(ext);
  22. } catch (e) {
  23. return false;
  24. }
  25. }
  26. static Future<void> choicePlatformLocalFileAndCreateOrder() async {
  27. TalkBean? bean;
  28. try {
  29. Pair<File, Duration>? pair =
  30. await FileUploadCheckHelper.pickerPlatformFile();
  31. if (pair == null) {
  32. //未选择文件
  33. return;
  34. }
  35. LoadingDialog.show(StringName.fileImporting.tr);
  36. bean = await FileUploadCheckHelper.createTalkFromLocalFile(
  37. pair.first, pair.second);
  38. TalkPage.start(bean);
  39. } catch (e) {
  40. if (e is PickerException) {
  41. ToastUtil.showToast(e.message);
  42. } else {
  43. ErrorHandler.toastError(e, message: StringName.fileImportFail.tr);
  44. }
  45. } finally {
  46. LoadingDialog.hide();
  47. }
  48. if (bean != null) {
  49. TalkPage.start(bean);
  50. }
  51. }
  52. static Future<Duration> checkCanUpload(File file) async {
  53. //文件不能超过500M
  54. if (file.lengthSync() > 500 * 1024 * 1024) {
  55. throw PickerException(StringName.fileChoiceSizeLimit.tr);
  56. }
  57. AudioPlayer? player;
  58. try {
  59. player = AudioPlayer();
  60. player.setAudioSource(AudioSource.uri(file.uri));
  61. Duration? duration = await player.durationStream
  62. .firstWhere((duration) => duration != null);
  63. if (duration == null) {
  64. throw PickerException(StringName.fileAudioDurationCannotObtained.tr);
  65. }
  66. if (duration.inSeconds < 3) {
  67. throw PickerException(StringName.recordingDurationCannotLessThan3s.tr);
  68. }
  69. //录音时长不能超过5小时
  70. if (duration.inHours > 5) {
  71. throw PickerException(StringName.fileAudioDurationLimit.tr);
  72. }
  73. return duration;
  74. } finally {
  75. player?.dispose();
  76. }
  77. }
  78. static Future<Pair<File, Duration>?> pickerPlatformFile() async {
  79. File? file = await AudioPickerUtils.pickSingleFileByPlatform();
  80. if (file == null) {
  81. return null;
  82. }
  83. Duration duration = await checkCanUpload(file);
  84. return Pair(file, duration);
  85. }
  86. static Future<TalkBean> createTalkFromLocalFile(
  87. File file, Duration duration) async {
  88. TalkBean bean = await talkRepository.talkCreate(
  89. const Uuid().v4(), duration.inSeconds,
  90. uploadType: FileUploadType.local);
  91. String childDirName = bean.id;
  92. Directory dir = await getChoiceUploadDir(childDirName);
  93. await moveFileToDirectory(file, dir);
  94. return bean;
  95. }
  96. static Future<Directory> getChoiceUploadDir(String talkId) async {
  97. Directory documentDir = await getApplicationDocumentsDirectory();
  98. return Directory("${documentDir.path}/.atmob/choice/$talkId");
  99. }
  100. static Future<File?> getChoiceUploadFile(String talkId) async {
  101. Directory dir = await getChoiceUploadDir(talkId);
  102. if (!dir.existsSync()) {
  103. return null;
  104. }
  105. List<FileSystemEntity> list = dir.listSync();
  106. if (list.isEmpty) {
  107. return null;
  108. }
  109. return list.first as File;
  110. }
  111. static Future<void> moveFileToDirectory(File file, Directory dir) async {
  112. if (!dir.existsSync()) {
  113. dir.createSync(recursive: true);
  114. }
  115. String newFilePath = '${dir.path}/${file.uri.pathSegments.last}';
  116. file.renameSync(newFilePath);
  117. }
  118. static const String _uploadServerAudioTag = '_&&@@##_';
  119. //拼接设备ID用于标识
  120. static String joinUploadServerAudioTag(String id) {
  121. return '${getDeviceId()}$_uploadServerAudioTag$id';
  122. }
  123. static String? getLocalAudioId(String? tag) {
  124. if (tag == null || tag.isEmpty) {
  125. return null;
  126. }
  127. if (!tag.contains(_uploadServerAudioTag)) {
  128. return null;
  129. }
  130. List<String> audioTag = tag.split(_uploadServerAudioTag);
  131. if (audioTag.first != getDeviceId()) {
  132. return null;
  133. }
  134. return tag.split(_uploadServerAudioTag).last;
  135. }
  136. }
  137. class PickerException implements Exception {
  138. final String message;
  139. PickerException(this.message);
  140. @override
  141. String toString() {
  142. return 'PickerException: $message';
  143. }
  144. }