diff --git a/lib/src/services/mediafiles/mediafile.service.dart b/lib/src/services/mediafiles/mediafile.service.dart index 0b11ae4..5c09e10 100644 --- a/lib/src/services/mediafiles/mediafile.service.dart +++ b/lib/src/services/mediafiles/mediafile.service.dart @@ -161,13 +161,12 @@ class MediaFileService { return; } switch (mediaFile.type) { + case MediaType.gif: case MediaType.image: // all images are already compress.. break; case MediaType.video: await createThumbnailsForVideo(storedPath, thumbnailPath); - case MediaType.gif: - Log.error('Thumbnail for .gif is not implemented yet'); } } @@ -183,8 +182,7 @@ class MediaFileService { case MediaType.video: await compressAndOverlayVideo(this); case MediaType.gif: - originalPath.renameSync(tempPath.path); - Log.error('Compression for .gif is not implemented yet.'); + originalPath.copySync(tempPath.path); } } diff --git a/lib/src/views/camera/camera_preview_components/save_to_gallery.dart b/lib/src/views/camera/camera_preview_components/save_to_gallery.dart index 5c81e0f..4a2be05 100644 --- a/lib/src/views/camera/camera_preview_components/save_to_gallery.dart +++ b/lib/src/views/camera/camera_preview_components/save_to_gallery.dart @@ -45,7 +45,8 @@ class SaveToGalleryButtonState extends State { _imageSaving = true; }); - if (widget.mediaService.mediaFile.type == MediaType.image) { + if (widget.mediaService.mediaFile.type == MediaType.image || + widget.mediaService.mediaFile.type == MediaType.gif) { await widget.storeImageAsOriginal(); } diff --git a/lib/src/views/camera/camera_preview_controller_view.dart b/lib/src/views/camera/camera_preview_controller_view.dart index 4ab20d1..176d6b3 100644 --- a/lib/src/views/camera/camera_preview_controller_view.dart +++ b/lib/src/views/camera/camera_preview_controller_view.dart @@ -285,9 +285,12 @@ class _CameraPreviewViewState extends State { Future? imageBytes, File? videoFilePath, { bool sharedFromGallery = false, + MediaType? mediaType, }) async { + final type = mediaType ?? + ((videoFilePath != null) ? MediaType.video : MediaType.image); final mediaFileService = await initializeMediaUpload( - (videoFilePath != null) ? MediaType.video : MediaType.image, + type, gUser.defaultShowTime, ); if (!mounted) return true; @@ -377,14 +380,42 @@ class _CameraPreviewViewState extends State { _sharePreviewIsShown = true; }); final picker = ImagePicker(); - final pickedFile = await picker.pickImage(source: ImageSource.gallery); + final pickedFile = await picker.pickMedia(); if (pickedFile != null) { - final imageFile = File(pickedFile.path); + final imageExtensions = [ + '.png', + '.jpg', + '.jpeg', + '.gif', + '.webp', + '.heic', + '.heif', + '.avif', + ]; + + Log.info('Picket from gallery: ${pickedFile.path}'); + + File? videoFilePath; + Future? imageBytes; + MediaType? mediaType; + + final isImage = + imageExtensions.any((ext) => pickedFile.name.contains(ext)); + if (isImage) { + if (pickedFile.name.contains('.gif')) { + mediaType = MediaType.gif; + } + imageBytes = pickedFile.readAsBytes(); + } else { + videoFilePath = File(pickedFile.path); + } + await pushMediaEditor( - imageFile.readAsBytes(), - null, + imageBytes, + videoFilePath, sharedFromGallery: true, + mediaType: mediaType, ); } setState(() { diff --git a/lib/src/views/camera/share_image_editor_view.dart b/lib/src/views/camera/share_image_editor_view.dart index 32ff434..49c2b5f 100644 --- a/lib/src/views/camera/share_image_editor_view.dart +++ b/lib/src/views/camera/share_image_editor_view.dart @@ -55,6 +55,7 @@ class _ShareImageEditorView extends State { double widthRatio = 1; double heightRatio = 1; double pixelRatio = 1; + Uint8List? imageBytes; VideoPlayerController? videoController; ImageItem currentImage = ImageItem(); ScreenshotController screenshotController = ScreenshotController(); @@ -66,13 +67,16 @@ class _ShareImageEditorView extends State { void initState() { super.initState(); - layers.add(FilterLayerData()); + if (media.type != MediaType.gif) { + layers.add(FilterLayerData()); + } if (widget.sendToGroup != null) { selectedGroupIds.add(widget.sendToGroup!.groupId); } - if (widget.mediaFileService.mediaFile.type == MediaType.image) { + if (widget.mediaFileService.mediaFile.type == MediaType.video || + widget.mediaFileService.mediaFile.type == MediaType.gif) { if (widget.imageBytesFuture != null) { loadImage(widget.imageBytesFuture!); } else { @@ -124,52 +128,55 @@ class _ShareImageEditorView extends State { return []; } return [ - ActionButton( - Icons.text_fields_rounded, - tooltipText: context.lang.addTextItem, - onPressed: () async { - layers = layers.where((x) => !x.isDeleted).toList(); - if (layers.any((x) => x.isEditing)) return; - undoLayers.clear(); - removedLayers.clear(); - layers.add( - TextLayerData( - textLayersBefore: layers.whereType().length, - ), - ); - setState(() {}); - }, - ), + if (media.type != MediaType.gif) + ActionButton( + Icons.text_fields_rounded, + tooltipText: context.lang.addTextItem, + onPressed: () async { + layers = layers.where((x) => !x.isDeleted).toList(); + if (layers.any((x) => x.isEditing)) return; + undoLayers.clear(); + removedLayers.clear(); + layers.add( + TextLayerData( + textLayersBefore: layers.whereType().length, + ), + ); + setState(() {}); + }, + ), const SizedBox(height: 8), - ActionButton( - Icons.draw_rounded, - tooltipText: context.lang.addDrawing, - onPressed: () async { - undoLayers.clear(); - removedLayers.clear(); - layers.add(DrawLayerData()); - setState(() {}); - }, - ), + if (media.type != MediaType.gif) + ActionButton( + Icons.draw_rounded, + tooltipText: context.lang.addDrawing, + onPressed: () async { + undoLayers.clear(); + removedLayers.clear(); + layers.add(DrawLayerData()); + setState(() {}); + }, + ), const SizedBox(height: 8), - ActionButton( - Icons.add_reaction_outlined, - tooltipText: context.lang.addEmoji, - onPressed: () async { - final layer = await showModalBottomSheet( - context: context, - backgroundColor: Colors.black, - builder: (BuildContext context) { - return const Emojis(); - }, - ) as Layer?; - if (layer == null) return; - undoLayers.clear(); - removedLayers.clear(); - layers.add(layer); - setState(() {}); - }, - ), + if (media.type != MediaType.gif) + ActionButton( + Icons.add_reaction_outlined, + tooltipText: context.lang.addEmoji, + onPressed: () async { + final layer = await showModalBottomSheet( + context: context, + backgroundColor: Colors.black, + builder: (BuildContext context) { + return const Emojis(); + }, + ) as Layer?; + if (layer == null) return; + undoLayers.clear(); + removedLayers.clear(); + layers.add(layer); + setState(() {}); + }, + ), const SizedBox(height: 8), NotificationBadge( count: (media.type == MediaType.video) @@ -356,12 +363,18 @@ class _ShareImageEditorView extends State { if (mediaService.tempPath.existsSync()) { mediaService.tempPath.deleteSync(); } - final imageBytes = await getEditedImageBytes(); - if (imageBytes == null) return false; - if (media.type == MediaType.image) { - mediaService.originalPath.writeAsBytesSync(imageBytes); + if (media.type == MediaType.gif) { + mediaService.originalPath.writeAsBytesSync(imageBytes!.toList()); } else { - mediaService.overlayImagePath.writeAsBytesSync(imageBytes); + final imageBytes = await getEditedImageBytes(); + if (imageBytes == null) return false; + if (media.type == MediaType.image || media.type == MediaType.gif) { + mediaService.originalPath.writeAsBytesSync(imageBytes); + } else if (media.type == MediaType.video) { + mediaService.overlayImagePath.writeAsBytesSync(imageBytes); + } else { + Log.error('MediaType not supported: ${media.type}'); + } } // In case the image was already stored, then rename the stored image. @@ -374,7 +387,8 @@ class _ShareImageEditorView extends State { } Future loadImage(Future imageBytesFuture) async { - await currentImage.load(await imageBytesFuture); + imageBytes = await imageBytesFuture; + await currentImage.load(imageBytes); if (isDisposed) return; if (!context.mounted) return; diff --git a/lib/src/views/chats/media_viewer.view.dart b/lib/src/views/chats/media_viewer.view.dart index 41dc818..5350601 100644 --- a/lib/src/views/chats/media_viewer.view.dart +++ b/lib/src/views/chats/media_viewer.view.dart @@ -298,7 +298,8 @@ class _MediaViewerViewState extends State { if (gUser.storeMediaFilesInGallery) { if (currentMedia!.mediaFile.type == MediaType.video) { await saveVideoToGallery(currentMedia!.storedPath.path); - } else if (currentMedia!.mediaFile.type == MediaType.image) { + } else if (currentMedia!.mediaFile.type == MediaType.image || + currentMedia!.mediaFile.type == MediaType.gif) { final imageBytes = await currentMedia!.storedPath.readAsBytes(); await saveImageToGallery(imageBytes); } @@ -466,7 +467,8 @@ class _MediaViewerViewState extends State { child: VideoPlayer(videoController!), ), if (currentMedia != null && - currentMedia!.mediaFile.type == MediaType.image) + currentMedia!.mediaFile.type == MediaType.image || + currentMedia!.mediaFile.type == MediaType.gif) Positioned.fill( child: Image.file( currentMedia!.tempPath, diff --git a/lib/src/views/memories/memories_item_thumbnail.dart b/lib/src/views/memories/memories_item_thumbnail.dart index a0ec884..c1486bf 100644 --- a/lib/src/views/memories/memories_item_thumbnail.dart +++ b/lib/src/views/memories/memories_item_thumbnail.dart @@ -57,7 +57,8 @@ class _MemoriesItemThumbnailState extends State { if (media.thumbnailPath.existsSync()) Image.file(media.thumbnailPath) else if (media.storedPath.existsSync() && - media.mediaFile.type == MediaType.image) + media.mediaFile.type == MediaType.image || + media.mediaFile.type == MediaType.gif) Image.file(media.storedPath) else const Text('Media file removed.'), diff --git a/lib/src/views/memories/memories_photo_slider.view.dart b/lib/src/views/memories/memories_photo_slider.view.dart index 99b1aa2..b2016d5 100644 --- a/lib/src/views/memories/memories_photo_slider.view.dart +++ b/lib/src/views/memories/memories_photo_slider.view.dart @@ -75,7 +75,8 @@ class _MemoriesPhotoSliderViewState extends State { try { if (item.mediaFile.type == MediaType.video) { await saveVideoToGallery(item.storedPath.path); - } else if (item.mediaFile.type == MediaType.image) { + } else if (item.mediaFile.type == MediaType.image || + item.mediaFile.type == MediaType.gif) { final imageBytes = await item.storedPath.readAsBytes(); await saveImageToGallery(imageBytes); }