attachment_download_helper.dart 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import 'dart:typed_data';
  2. import 'package:flutter/material.dart';
  3. import 'package:tdesign_flutter/tdesign_flutter.dart';
  4. import '../../core/i18n/app_localizations.dart';
  5. import '../../core/navigation/host_app_channel.dart';
  6. import '../models/bill_attachment.dart';
  7. import '../widgets/loading_dialog.dart';
  8. /// 附件下载辅助类,供详情页复用下载逻辑。
  9. class AttachmentDownloadHelper {
  10. /// 根据扩展名返回 MIME 类型
  11. static String mimeType(String ext) {
  12. switch (ext.toLowerCase()) {
  13. case 'pdf':
  14. return 'application/pdf';
  15. case 'doc':
  16. return 'application/msword';
  17. case 'docx':
  18. return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
  19. case 'xls':
  20. return 'application/vnd.ms-excel';
  21. case 'xlsx':
  22. return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  23. case 'jpg':
  24. case 'jpeg':
  25. return 'image/jpeg';
  26. case 'png':
  27. return 'image/png';
  28. case 'gif':
  29. return 'image/gif';
  30. case 'bmp':
  31. return 'image/bmp';
  32. case 'webp':
  33. return 'image/webp';
  34. default:
  35. return 'application/octet-stream';
  36. }
  37. }
  38. /// 下载附件并保存到公共目录,成功显示路径弹窗。
  39. static Future<void> downloadAndSave(
  40. BuildContext context,
  41. BillAttachment attachment,
  42. Future<Uint8List?> Function(String id) downloader,
  43. ) async {
  44. final l10n = AppLocalizations.of(context);
  45. try {
  46. LoadingDialog.show(context, text: l10n.get('downloading'));
  47. final bytes = await downloader(attachment.id);
  48. if (!context.mounted) return;
  49. LoadingDialog.hide(context);
  50. if (bytes == null) {
  51. TDToast.showText(l10n.get('downloadFailed'), context: context);
  52. return;
  53. }
  54. final path = await HostAppChannel.saveFileToDownloads(
  55. bytes,
  56. attachment.fileName,
  57. mimeType(attachment.ext),
  58. );
  59. if (!context.mounted) return;
  60. if (path != null) {
  61. _showSuccessDialog(context, l10n, path);
  62. } else {
  63. TDToast.showText(l10n.get('downloadFailed'), context: context);
  64. }
  65. } catch (_) {
  66. if (context.mounted) LoadingDialog.hide(context);
  67. if (context.mounted) {
  68. TDToast.showText(l10n.get('downloadFailed'), context: context);
  69. }
  70. }
  71. }
  72. static void _showSuccessDialog(
  73. BuildContext context,
  74. AppLocalizations l10n,
  75. String path,
  76. ) {
  77. showGeneralDialog(
  78. context: context,
  79. pageBuilder: (buildContext, animation, secondaryAnimation) {
  80. return TDConfirmDialog(
  81. title: l10n.get('downloadSuccess'),
  82. content: path,
  83. buttonStyle: TDDialogButtonStyle.text,
  84. buttonText: l10n.get('confirm'),
  85. );
  86. },
  87. );
  88. }
  89. }