Line data Source code
1 : import 'package:cross_file/cross_file.dart';
2 : import 'package:media_source/src/media_type.dart';
3 : import 'package:media_source/src/sources/media_source.dart';
4 : import 'package:media_source/src/sources/memory_media_source.dart';
5 : import 'package:media_source/src/extensions/file_extensions.dart';
6 : import 'package:media_source/src/utils/platform_utils.dart';
7 : import 'package:path/path.dart' as p;
8 : import 'package:file_sized/file_sized.dart';
9 : import 'package:file_type_plus/file_type_plus.dart';
10 :
11 : /// Abstract base class for file-based media sources.
12 : ///
13 : /// This class manages media content stored on the file system. It provides:
14 : /// - File I/O operations (save, move, delete)
15 : /// - Type-specific file media implementations
16 : /// - Conversion to in-memory representation
17 : /// - Factory methods for creating instances from file paths or XFile objects
18 : ///
19 : /// Subclasses include:
20 : /// - [VideoFileMedia] for video files
21 : /// - [AudioFileMedia] for audio files
22 : /// - [ImageFileMedia] for image files
23 : /// - [DocumentFileMedia] for document files
24 : /// - [OtherTypeFileMedia] for unclassified files
25 : abstract class FileMediaSource<M extends FileType> extends MediaSource<M> implements ToMemoryConvertableMedia<M> {
26 : /// The underlying cross-platform file object.
27 : final XFile file;
28 :
29 : /// Internal constructor for creating file media sources.
30 : ///
31 : /// Parameters:
32 : /// - [file]: The XFile representing the media file
33 : /// - [metadata]: Type-specific metadata (VideoType, AudioType, etc.)
34 : /// - [name]: Optional custom name, defaults to file name
35 : /// - [size]: Optional file size, auto-detected if not provided
36 : /// - [mimeType]: Optional MIME type, auto-detected if not provided
37 1 : FileMediaSource._({
38 : required this.file,
39 : required super.metadata,
40 : required String? name,
41 : required super.size,
42 : required String? mimeType,
43 1 : }) : super(
44 0 : mimeType: mimeType ?? file.mimeType ?? FileUtil.getMimeTypeFromPath(file.path),
45 0 : name: name ?? file.name,
46 : );
47 :
48 : /// Saves this media to the specified file path.
49 : ///
50 : /// Returns a new [FileMediaSource] instance pointing to the saved file.
51 : /// Subclasses implement specific type handling.
52 : Future<FileMediaSource<M>> saveTo(String path);
53 :
54 : /// Saves this media to a folder, preserving the original filename.
55 : ///
56 : /// Parameters:
57 : /// - [folderPath]: The directory where the file should be saved
58 : ///
59 : /// Returns a new [FileMediaSource] instance with the file in the folder.
60 0 : Future<FileMediaSource<M>> saveToFolder(String folderPath) => saveTo(p.join(folderPath, name));
61 :
62 : /// Moves this media to a new file path.
63 : ///
64 : /// If the destination already exists, it will be deleted before moving.
65 : /// Returns early if the source path matches the destination.
66 : ///
67 : /// Parameters:
68 : /// - [path]: The destination file path
69 : ///
70 : /// Returns a new [FileMediaSource] instance at the new location.
71 0 : Future<FileMediaSource<M>> moveTo(String path) async {
72 0 : if (file.path == path) return this;
73 0 : final newPathFile = XFile(path);
74 0 : if (await newPathFile.exists()) {
75 0 : await newPathFile.delete();
76 : }
77 0 : final saved = await saveTo(path);
78 0 : await delete();
79 : return saved;
80 : }
81 :
82 : /// Moves this media to a folder, preserving the original filename.
83 : ///
84 : /// Parameters:
85 : /// - [folderPath]: The directory where the file should be moved
86 : ///
87 : /// Returns a new [FileMediaSource] instance with the file in the folder.
88 0 : Future<FileMediaSource<M>> moveToFolder(String folderPath) => moveTo(p.join(folderPath, name));
89 :
90 : /// Deletes the file from the file system.
91 : ///
92 : /// Returns true if deletion was successful, false otherwise.
93 0 : Future<bool> delete() => file.delete();
94 :
95 : /// Creates a [FileMediaSource] from a file path.
96 : ///
97 : /// Automatically detects the media type and returns the appropriate subclass.
98 : /// If media type is not provided, it will be determined from the file.
99 : ///
100 : /// Parameters:
101 : /// - [path]: The file system path to the media file
102 : /// - [name]: Optional custom display name
103 : /// - [size]: Optional pre-computed file size
104 : /// - [mimeType]: Optional MIME type
105 : /// - [duration]: Optional duration for audio/video files
106 : /// - [mediaType]: Optional explicit media type (for type narrowing)
107 : ///
108 : /// Returns the appropriate [FileMediaSource] subclass based on media type.
109 0 : static Future<FileMediaSource> fromPath(
110 : String path, {
111 : String? name,
112 : FileSize? size,
113 : String? mimeType,
114 : Duration? duration,
115 : FileType? mediaType,
116 : }) =>
117 0 : fromFile(
118 0 : XFile(
119 : path,
120 : mimeType: mimeType,
121 0 : length: size?.inBytes,
122 : name: name,
123 : ),
124 : name: name,
125 : mimeType: mimeType,
126 : duration: duration,
127 : mediaType: mediaType,
128 : size: size,
129 : );
130 :
131 : /// Creates a [FileMediaSource] from an XFile object.
132 : ///
133 : /// Automatically detects the media type and returns the appropriate subclass.
134 : /// Supports:
135 : /// - [AudioFileMedia] for audio files
136 : /// - [VideoFileMedia] for video files
137 : /// - [ImageFileMedia] for image files
138 : /// - [DocumentFileMedia] for document files
139 : /// - [OtherTypeFileMedia] for unclassified files
140 : ///
141 : /// Parameters:
142 : /// - [file]: The XFile object representing the media
143 : /// - [name]: Optional custom display name
144 : /// - [mimeType]: Optional MIME type override
145 : /// - [duration]: Optional duration for audio/video files
146 : /// - [mediaType]: Optional explicit media type
147 : /// - [size]: Optional pre-computed file size
148 : ///
149 : /// Returns the appropriate [FileMediaSource] subclass.
150 0 : static Future<FileMediaSource> fromFile(
151 : XFile file, {
152 : String? name,
153 : String? mimeType,
154 : Duration? duration,
155 : FileType? mediaType,
156 : FileSize? size,
157 : }) async {
158 0 : mediaType ??= await file.getMediaType(mimeType);
159 0 : if (mediaType.isAny([FileType.audio])) {
160 0 : return AudioFileMedia.fromFile(
161 : file,
162 : name: name,
163 : duration: duration,
164 : mimeType: mimeType,
165 : size: size,
166 : );
167 : }
168 0 : if (mediaType.isAny([FileType.video])) {
169 0 : return VideoFileMedia.fromFile(
170 : file,
171 : name: name,
172 : duration: duration,
173 : mimeType: mimeType,
174 : size: size,
175 : );
176 : }
177 0 : if (mediaType.isAny([FileType.image])) {
178 0 : return ImageFileMedia.fromFile(
179 : file,
180 : name: name,
181 : mimeType: mimeType,
182 : size: size,
183 : );
184 : }
185 0 : if (mediaType.isAny([FileType.document])) {
186 0 : return DocumentFileMedia.fromFile(
187 : file,
188 : name: name,
189 : mimeType: mimeType,
190 : size: size,
191 : );
192 : }
193 0 : return OtherTypeFileMedia.fromFile(
194 : file,
195 : name: name,
196 : mimeType: mimeType,
197 : size: size,
198 : );
199 : }
200 :
201 : /// Includes the file object in equality comparisons.
202 0 : @override
203 0 : List<Object?> get props => [file, ...super.props];
204 : }
205 :
206 : /// Represents video files stored on the file system.
207 : ///
208 : /// Stores video metadata including optional duration information.
209 : /// Supports saving, moving, deleting, and conversion to in-memory representation.
210 : class VideoFileMedia extends FileMediaSource<VideoType> {
211 : /// Internal constructor for creating video file media.
212 : ///
213 : /// Parameters:
214 : /// - [file]: The video file
215 : /// - [name]: Display name
216 : /// - [duration]: Optional video duration
217 : /// - [size]: File size
218 : /// - [mimeType]: MIME type of the video
219 1 : VideoFileMedia._({
220 : required super.file,
221 : required super.name,
222 : required Duration? duration,
223 : required super.size,
224 : required super.mimeType,
225 2 : }) : super._(metadata: VideoType(duration));
226 :
227 : /// Creates a [VideoFileMedia] from a file path.
228 : ///
229 : /// Parameters:
230 : /// - [path]: The file system path to the video
231 : /// - [name]: Optional custom display name
232 : /// - [duration]: Optional video duration
233 : /// - [mimeType]: Optional MIME type override
234 : /// - [size]: Optional pre-computed file size
235 0 : static Future<VideoFileMedia> fromPath(
236 : String path, {
237 : String? name,
238 : Duration? duration,
239 : String? mimeType,
240 : FileSize? size,
241 : }) async {
242 0 : final file = XFile(
243 : path,
244 : name: name,
245 : mimeType: mimeType,
246 0 : length: size?.inBytes,
247 : );
248 0 : return fromFile(
249 : file,
250 : name: name,
251 : duration: duration,
252 : mimeType: mimeType,
253 : size: size,
254 : );
255 : }
256 :
257 : /// Creates a [VideoFileMedia] from an XFile object.
258 : ///
259 : /// Parameters:
260 : /// - [file]: The XFile representing the video
261 : /// - [name]: Optional custom display name
262 : /// - [duration]: Optional video duration
263 : /// - [mimeType]: Optional MIME type override
264 : /// - [size]: Optional pre-computed file size, auto-detected if not provided
265 1 : static Future<VideoFileMedia> fromFile(
266 : XFile file, {
267 : String? name,
268 : Duration? duration,
269 : String? mimeType,
270 : FileSize? size,
271 : }) async {
272 1 : return VideoFileMedia._(
273 : file: file,
274 0 : size: size ?? await file.size(),
275 : name: name,
276 : duration: duration,
277 : mimeType: mimeType,
278 : );
279 : }
280 :
281 : /// Saves this video to the specified file path.
282 : ///
283 : /// Creates the directory if it doesn't exist, then saves the file
284 : /// and returns a new instance pointing to the saved location.
285 1 : @override
286 : Future<VideoFileMedia> saveTo(String path) async {
287 2 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
288 2 : await file.saveTo(path);
289 1 : return VideoFileMedia._(
290 1 : file: XFile(
291 : path,
292 1 : name: name,
293 1 : mimeType: mimeType,
294 2 : length: size?.inBytes,
295 : ),
296 1 : size: size ?? await file.size(),
297 1 : name: name,
298 2 : duration: metadata.duration,
299 1 : mimeType: mimeType,
300 : );
301 : }
302 :
303 : /// Converts this video to an in-memory representation.
304 : ///
305 : /// Loads the entire file content into memory as a byte array.
306 : /// Useful for uploading or processing without file system access.
307 0 : @override
308 : Future<MemoryMediaSource<VideoType>> convertToMemory() async {
309 0 : return VideoMemoryMedia(
310 0 : await file.readAsBytes(),
311 0 : name: name,
312 0 : duration: metadata.duration,
313 0 : mimeType: mimeType,
314 : );
315 : }
316 : }
317 :
318 : /// Represents audio files stored on the file system.
319 : ///
320 : /// Stores audio metadata including optional duration information.
321 : /// Supports saving, moving, deleting, and conversion to in-memory representation.
322 : class AudioFileMedia extends FileMediaSource<AudioType> {
323 : /// Internal constructor for creating audio file media.
324 : ///
325 : /// Parameters:
326 : /// - [file]: The audio file
327 : /// - [name]: Display name
328 : /// - [duration]: Optional audio duration
329 : /// - [size]: File size
330 : /// - [mimeType]: MIME type of the audio
331 1 : AudioFileMedia._({
332 : required super.file,
333 : required super.name,
334 : required Duration? duration,
335 : required super.size,
336 : required super.mimeType,
337 2 : }) : super._(metadata: AudioType(duration));
338 :
339 : /// Creates an [AudioFileMedia] from a file path.
340 : ///
341 : /// Parameters:
342 : /// - [path]: The file system path to the audio file
343 : /// - [name]: Optional custom display name
344 : /// - [duration]: Optional audio duration
345 : /// - [mimeType]: Optional MIME type override
346 : /// - [size]: Optional pre-computed file size
347 0 : static Future<AudioFileMedia> fromPath(
348 : String path, {
349 : String? name,
350 : Duration? duration,
351 : String? mimeType,
352 : FileSize? size,
353 : }) async {
354 0 : final file = XFile(
355 : path,
356 : mimeType: mimeType,
357 : name: name,
358 0 : length: size?.inBytes,
359 : );
360 0 : return fromFile(
361 : file,
362 : name: name,
363 : duration: duration,
364 : mimeType: mimeType,
365 : size: size,
366 : );
367 : }
368 :
369 : /// Creates an [AudioFileMedia] from an XFile object.
370 : ///
371 : /// Parameters:
372 : /// - [file]: The XFile representing the audio
373 : /// - [name]: Optional custom display name
374 : /// - [duration]: Optional audio duration
375 : /// - [mimeType]: Optional MIME type override
376 : /// - [size]: Optional pre-computed file size, auto-detected if not provided
377 1 : static Future<AudioFileMedia> fromFile(
378 : XFile file, {
379 : String? name,
380 : Duration? duration,
381 : String? mimeType,
382 : FileSize? size,
383 : }) async {
384 1 : return AudioFileMedia._(
385 : file: file,
386 0 : size: size ?? await file.size(),
387 : name: name,
388 : duration: duration,
389 : mimeType: mimeType,
390 : );
391 : }
392 :
393 : /// Saves this audio to the specified file path.
394 : ///
395 : /// Creates the directory if it doesn't exist, then saves the file
396 : /// and returns a new instance pointing to the saved location.
397 1 : @override
398 : Future<AudioFileMedia> saveTo(String path) async {
399 2 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
400 2 : await file.saveTo(path);
401 1 : return AudioFileMedia._(
402 1 : file: XFile(
403 : path,
404 1 : name: super.name,
405 1 : mimeType: super.mimeType,
406 2 : length: size?.inBytes,
407 : ),
408 1 : size: size ?? await file.size(),
409 1 : name: name,
410 2 : duration: metadata.duration,
411 1 : mimeType: mimeType,
412 : );
413 : }
414 :
415 : /// Converts this audio to an in-memory representation.
416 : ///
417 : /// Loads the entire file content into memory as a byte array.
418 : /// Useful for uploading or processing without file system access.
419 0 : @override
420 : Future<MemoryMediaSource<AudioType>> convertToMemory() async {
421 0 : return AudioMemoryMedia(
422 0 : await file.readAsBytes(),
423 0 : name: name,
424 0 : duration: metadata.duration,
425 0 : mimeType: mimeType,
426 : );
427 : }
428 : }
429 :
430 : /// Represents image files stored on the file system.
431 : ///
432 : /// Stores image metadata and supports saving, moving, deleting,
433 : /// and conversion to in-memory representation.
434 : class ImageFileMedia extends FileMediaSource<ImageType> {
435 : /// Internal constructor for creating image file media.
436 : ///
437 : /// Parameters:
438 : /// - [file]: The image file
439 : /// - [name]: Display name
440 : /// - [size]: File size
441 : /// - [mimeType]: MIME type of the image
442 1 : ImageFileMedia._({
443 : required super.file,
444 : required super.name,
445 : required super.size,
446 : required super.mimeType,
447 2 : }) : super._(metadata: ImageType());
448 :
449 : /// Creates an [ImageFileMedia] from a file path.
450 : ///
451 : /// Parameters:
452 : /// - [path]: The file system path to the image
453 : /// - [name]: Optional custom display name
454 : /// - [mimeType]: Optional MIME type override
455 : /// - [size]: Optional pre-computed file size
456 0 : static Future<ImageFileMedia> fromPath(
457 : String path, {
458 : String? name,
459 : String? mimeType,
460 : FileSize? size,
461 : }) async {
462 0 : final file = XFile(
463 : path,
464 : name: name,
465 : mimeType: mimeType,
466 0 : length: size?.inBytes,
467 : );
468 0 : return fromFile(
469 : file,
470 : name: name,
471 : mimeType: mimeType,
472 : size: size,
473 : );
474 : }
475 :
476 : /// Creates an [ImageFileMedia] from an XFile object.
477 : ///
478 : /// Parameters:
479 : /// - [file]: The XFile representing the image
480 : /// - [name]: Optional custom display name
481 : /// - [mimeType]: Optional MIME type override
482 : /// - [size]: Optional pre-computed file size, auto-detected if not provided
483 1 : static Future<ImageFileMedia> fromFile(
484 : XFile file, {
485 : String? name,
486 : String? mimeType,
487 : FileSize? size,
488 : }) async {
489 1 : return ImageFileMedia._(
490 : file: file,
491 0 : size: size ?? await file.size(),
492 : name: name,
493 : mimeType: mimeType,
494 : );
495 : }
496 :
497 : /// Saves this image to the specified file path.
498 : ///
499 : /// Creates the directory if it doesn't exist, then saves the file
500 : /// and returns a new instance pointing to the saved location.
501 1 : @override
502 : Future<ImageFileMedia> saveTo(String path) async {
503 2 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
504 2 : await file.saveTo(path);
505 1 : return ImageFileMedia._(
506 1 : file: XFile(
507 : path,
508 1 : name: super.name,
509 1 : mimeType: super.mimeType,
510 2 : length: size?.inBytes,
511 : ),
512 1 : size: size ?? await file.size(),
513 1 : name: name,
514 1 : mimeType: mimeType,
515 : );
516 : }
517 :
518 : /// Converts this image to an in-memory representation.
519 : ///
520 : /// Loads the entire file content into memory as a byte array.
521 : /// Useful for uploading or processing without file system access.
522 1 : @override
523 : Future<MemoryMediaSource<ImageType>> convertToMemory() async {
524 1 : return ImageMemoryMedia(
525 2 : await file.readAsBytes(),
526 1 : name: name,
527 1 : mimeType: mimeType,
528 : );
529 : }
530 : }
531 :
532 : /// Represents document files stored on the file system.
533 : ///
534 : /// Supports documents like PDF, DOC, XLSX, etc. Provides saving, moving,
535 : /// deleting, and conversion to in-memory representation.
536 : class DocumentFileMedia extends FileMediaSource<DocumentType> {
537 : /// Internal constructor for creating document file media.
538 : ///
539 : /// Parameters:
540 : /// - [file]: The document file
541 : /// - [name]: Display name
542 : /// - [size]: File size
543 : /// - [mimeType]: MIME type of the document
544 1 : DocumentFileMedia._({
545 : required super.file,
546 : required super.name,
547 : required super.size,
548 : required super.mimeType,
549 2 : }) : super._(metadata: DocumentType());
550 :
551 : /// Creates a [DocumentFileMedia] from a file path.
552 : ///
553 : /// Parameters:
554 : /// - [path]: The file system path to the document
555 : /// - [name]: Optional custom display name
556 : /// - [mimeType]: Optional MIME type override
557 : /// - [size]: Optional pre-computed file size
558 0 : static Future<DocumentFileMedia> fromPath(
559 : String path, {
560 : String? name,
561 : String? mimeType,
562 : FileSize? size,
563 : }) async {
564 0 : final file = XFile(
565 : path,
566 : name: name,
567 : mimeType: mimeType,
568 0 : length: size?.inBytes,
569 : );
570 0 : return fromFile(
571 : file,
572 : name: name,
573 : mimeType: mimeType,
574 : size: size,
575 : );
576 : }
577 :
578 : /// Creates a [DocumentFileMedia] from an XFile object.
579 : ///
580 : /// Parameters:
581 : /// - [file]: The XFile representing the document
582 : /// - [name]: Optional custom display name
583 : /// - [mimeType]: Optional MIME type override
584 : /// - [size]: Optional pre-computed file size, auto-detected if not provided
585 1 : static Future<DocumentFileMedia> fromFile(
586 : XFile file, {
587 : String? name,
588 : String? mimeType,
589 : FileSize? size,
590 : }) async {
591 1 : return DocumentFileMedia._(
592 : file: file,
593 0 : size: size ?? await file.size(),
594 : name: name,
595 : mimeType: mimeType,
596 : );
597 : }
598 :
599 : /// Saves this document to the specified file path.
600 : ///
601 : /// Creates the directory if it doesn't exist, then saves the file
602 : /// and returns a new instance pointing to the saved location.
603 1 : @override
604 : Future<DocumentFileMedia> saveTo(String path) async {
605 2 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
606 2 : await file.saveTo(path);
607 1 : return DocumentFileMedia._(
608 1 : file: XFile(
609 : path,
610 1 : name: super.name,
611 1 : mimeType: super.mimeType,
612 2 : length: size?.inBytes,
613 : ),
614 1 : size: size ?? await file.size(),
615 1 : name: name,
616 1 : mimeType: mimeType,
617 : );
618 : }
619 :
620 : /// Converts this document to an in-memory representation.
621 : ///
622 : /// Loads the entire file content into memory as a byte array.
623 : /// Useful for uploading or processing without file system access.
624 0 : @override
625 : Future<MemoryMediaSource<DocumentType>> convertToMemory() async {
626 0 : return DocumentMemoryMedia(
627 0 : await file.readAsBytes(),
628 0 : name: name,
629 0 : mimeType: mimeType,
630 : );
631 : }
632 : }
633 :
634 : /// Represents files of unclassified or unknown types.
635 : ///
636 : /// Used for media files that don't fit into the standard categories
637 : /// (video, audio, image, document). Provides the same operations as
638 : /// other file media types.
639 : class OtherTypeFileMedia extends FileMediaSource<OtherType> {
640 : /// Internal constructor for creating other type file media.
641 : ///
642 : /// Parameters:
643 : /// - [file]: The file
644 : /// - [name]: Display name
645 : /// - [size]: File size
646 : /// - [mimeType]: MIME type of the file
647 1 : @override
648 : OtherTypeFileMedia._({
649 : required super.file,
650 : required super.name,
651 : required super.size,
652 : required super.mimeType,
653 2 : }) : super._(metadata: OtherType());
654 :
655 : /// Creates an [OtherTypeFileMedia] from a file path.
656 : ///
657 : /// Parameters:
658 : /// - [path]: The file system path to the file
659 : /// - [name]: Optional custom display name
660 : /// - [mimeType]: Optional MIME type override
661 : /// - [size]: Optional pre-computed file size
662 0 : static Future<OtherTypeFileMedia> fromPath(
663 : String path, {
664 : String? name,
665 : String? mimeType,
666 : FileSize? size,
667 : }) {
668 0 : final file = XFile(
669 : path,
670 : name: name,
671 : mimeType: mimeType,
672 0 : length: size?.inBytes,
673 : );
674 0 : return fromFile(
675 : file,
676 : name: name,
677 : mimeType: mimeType,
678 : size: size,
679 : );
680 : }
681 :
682 : /// Creates an [OtherTypeFileMedia] from an XFile object.
683 : ///
684 : /// Parameters:
685 : /// - [file]: The XFile representing the file
686 : /// - [name]: Optional custom display name
687 : /// - [mimeType]: Optional MIME type override
688 : /// - [size]: Optional pre-computed file size, auto-detected if not provided
689 1 : static Future<OtherTypeFileMedia> fromFile(
690 : XFile file, {
691 : String? name,
692 : String? mimeType,
693 : FileSize? size,
694 : }) async {
695 1 : return OtherTypeFileMedia._(
696 : file: file,
697 0 : size: size ?? await file.size(),
698 : name: name,
699 : mimeType: mimeType,
700 : );
701 : }
702 :
703 : /// Saves this file to the specified file path.
704 : ///
705 : /// Creates the directory if it doesn't exist, then saves the file
706 : /// and returns a new instance pointing to the saved location.
707 1 : @override
708 : Future<OtherTypeFileMedia> saveTo(String path) async {
709 2 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
710 2 : await file.saveTo(path);
711 1 : return OtherTypeFileMedia._(
712 3 : file: XFile(path, name: super.name, mimeType: super.mimeType),
713 2 : size: await file.size(),
714 1 : name: name,
715 1 : mimeType: mimeType,
716 : );
717 : }
718 :
719 : /// Converts this file to an in-memory representation.
720 : ///
721 : /// Loads the entire file content into memory as a byte array.
722 : /// Useful for uploading or processing without file system access.
723 0 : @override
724 : Future<MemoryMediaSource<OtherType>> convertToMemory() async {
725 0 : return OtherTypeMemoryMedia(
726 0 : await file.readAsBytes(),
727 0 : name: name,
728 0 : mimeType: mimeType,
729 : );
730 : }
731 : }
|