picker_service.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import 'dart:io';
  2. import 'package:image_picker/image_picker.dart';
  3. import 'package:sino_med_cloud/core/utils/logger.dart';
  4. import 'media_exception.dart';
  5. /// 相册和快速拍照服务
  6. ///
  7. /// 适合普通拍照、表单上传、医疗资料拍照(非实时)
  8. ///
  9. /// 使用示例:
  10. /// ```dart
  11. /// // 从相册选择
  12. /// final file = await PickerService.pickFromGallery();
  13. ///
  14. /// // 使用系统相机拍照
  15. /// final photo = await PickerService.pickFromCamera();
  16. /// ```
  17. class PickerService {
  18. static final ImagePicker _picker = ImagePicker();
  19. /// 默认图片质量(1-100)
  20. static const int defaultImageQuality = 90;
  21. /// 从相册选择图片
  22. ///
  23. /// - [imageQuality] 图片质量(1-100),默认 90
  24. /// - [maxWidth] 最大宽度,null 表示不限制
  25. /// - [maxHeight] 最大高度,null 表示不限制
  26. ///
  27. /// 返回选择的图片文件,如果用户取消选择返回 null
  28. ///
  29. /// 抛出 [MediaException] 如果选择失败
  30. static Future<File?> pickFromGallery({
  31. int imageQuality = defaultImageQuality,
  32. double? maxWidth,
  33. double? maxHeight,
  34. }) async {
  35. try {
  36. AppLogger.d('开始从相册选择图片...');
  37. final XFile? file = await _picker.pickImage(
  38. source: ImageSource.gallery,
  39. imageQuality: imageQuality,
  40. maxWidth: maxWidth,
  41. maxHeight: maxHeight,
  42. );
  43. if (file == null) {
  44. AppLogger.d('用户取消了相册选择');
  45. return null;
  46. }
  47. final imageFile = File(file.path);
  48. if (!await imageFile.exists()) {
  49. throw MediaFileException('选择的图片文件不存在: ${file.path}');
  50. }
  51. AppLogger.d('相册选择成功: ${file.path}');
  52. return imageFile;
  53. } on MediaException {
  54. rethrow;
  55. } catch (e) {
  56. AppLogger.e('相册选择失败', e);
  57. if (e.toString().contains('permission') || e.toString().contains('权限')) {
  58. throw MediaPermissionException(
  59. '相册访问权限被拒绝,请在设置中开启相册权限',
  60. originalError: e,
  61. );
  62. }
  63. throw MediaException(
  64. '相册选择失败: ${e.toString()}',
  65. originalError: e,
  66. );
  67. }
  68. }
  69. /// 使用系统相机拍照(轻量级)
  70. ///
  71. /// - [imageQuality] 图片质量(1-100),默认 90
  72. /// - [maxWidth] 最大宽度,null 表示不限制
  73. /// - [maxHeight] 最大高度,null 表示不限制
  74. ///
  75. /// 返回拍摄的照片文件,如果用户取消拍照返回 null
  76. ///
  77. /// 抛出 [MediaException] 如果拍照失败
  78. static Future<File?> pickFromCamera({
  79. int imageQuality = defaultImageQuality,
  80. double? maxWidth,
  81. double? maxHeight,
  82. }) async {
  83. try {
  84. AppLogger.d('开始使用系统相机拍照...');
  85. final XFile? file = await _picker.pickImage(
  86. source: ImageSource.camera,
  87. imageQuality: imageQuality,
  88. maxWidth: maxWidth,
  89. maxHeight: maxHeight,
  90. );
  91. if (file == null) {
  92. AppLogger.d('用户取消了拍照');
  93. return null;
  94. }
  95. final photoFile = File(file.path);
  96. if (!await photoFile.exists()) {
  97. throw MediaFileException('拍摄的照片文件不存在: ${file.path}');
  98. }
  99. AppLogger.d('拍照成功: ${file.path}');
  100. return photoFile;
  101. } on MediaException {
  102. rethrow;
  103. } catch (e) {
  104. AppLogger.e('相机拍照失败', e);
  105. if (e.toString().contains('permission') || e.toString().contains('权限')) {
  106. throw MediaPermissionException(
  107. '相机权限被拒绝,请在设置中开启相机权限',
  108. originalError: e,
  109. );
  110. }
  111. throw MediaException(
  112. '相机拍照失败: ${e.toString()}',
  113. originalError: e,
  114. );
  115. }
  116. }
  117. /// 从相册选择视频
  118. ///
  119. /// 返回选择的视频文件,如果用户取消选择返回 null
  120. ///
  121. /// 抛出 [MediaException] 如果选择失败
  122. static Future<File?> pickVideoFromGallery() async {
  123. try {
  124. AppLogger.d('开始从相册选择视频...');
  125. final XFile? file = await _picker.pickVideo(
  126. source: ImageSource.gallery,
  127. );
  128. if (file == null) {
  129. AppLogger.d('用户取消了视频选择');
  130. return null;
  131. }
  132. final videoFile = File(file.path);
  133. if (!await videoFile.exists()) {
  134. throw MediaFileException('选择的视频文件不存在: ${file.path}');
  135. }
  136. AppLogger.d('视频选择成功: ${file.path}');
  137. return videoFile;
  138. } on MediaException {
  139. rethrow;
  140. } catch (e) {
  141. AppLogger.e('视频选择失败', e);
  142. if (e.toString().contains('permission') || e.toString().contains('权限')) {
  143. throw MediaPermissionException(
  144. '相册访问权限被拒绝,请在设置中开启相册权限',
  145. originalError: e,
  146. );
  147. }
  148. throw MediaException(
  149. '视频选择失败: ${e.toString()}',
  150. originalError: e,
  151. );
  152. }
  153. }
  154. }