diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_media.dart similarity index 98% rename from lib/src/full_screen_image.dart rename to lib/src/full_screen_media.dart index ba2b56bf..88f8d2b9 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_media.dart @@ -79,7 +79,8 @@ class _FullScreenMediaState extends State }, itemBuilder: (context, position) { print(widget.mediaAttachments[position].type); - if (widget.mediaAttachments[position].type == 'image' || widget.mediaAttachments[position].type == 'giphy') { + if (widget.mediaAttachments[position].type == 'image' || + widget.mediaAttachments[position].type == 'giphy') { return PhotoView( imageProvider: CachedNetworkImageProvider( widget.mediaAttachments[position].imageUrl ?? diff --git a/lib/src/full_screen_video.dart b/lib/src/full_screen_video.dart deleted file mode 100644 index 98729243..00000000 --- a/lib/src/full_screen_video.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:chewie/chewie.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:video_player/video_player.dart'; - -import 'utils.dart'; - -class FullScreenVideo extends StatefulWidget { - final Attachment attachment; - - FullScreenVideo({ - Key key, - @required this.attachment, - }) : super(key: key); - - @override - _FullScreenVideoState createState() => _FullScreenVideoState(); -} - -class _FullScreenVideoState extends State { - ChewieController _chewieController; - VideoPlayerController _videoPlayerController; - bool initialized = false; - final GlobalKey _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.black, - iconTheme: IconThemeData( - color: Colors.white, - ), - ), - body: Builder( - key: _scaffoldKey, - builder: (context) { - if (!initialized) { - return Center( - child: CircularProgressIndicator(), - ); - } - return Chewie( - controller: _chewieController, - ); - }, - ), - ); - } - - @override - void initState() { - super.initState(); - _videoPlayerController = - VideoPlayerController.network(widget.attachment.assetUrl); - _videoPlayerController.initialize().whenComplete(() { - setState(() { - initialized = true; - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController, - autoInitialize: false, - aspectRatio: _videoPlayerController.value.aspectRatio, - ); - }); - }); - - VoidCallback errorListener; - errorListener = () { - if (_videoPlayerController.value.hasError) { - Navigator.pop(context); - launchURL(_scaffoldKey.currentContext, widget.attachment.titleLink); - } - _videoPlayerController.removeListener(errorListener); - }; - _videoPlayerController.addListener(errorListener); - } - - @override - void dispose() { - _videoPlayerController?.dispose(); - _chewieController?.dispose(); - super.dispose(); - } -} diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 323a3ae1..8f02b8a8 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import '../stream_chat_flutter.dart'; import 'attachment_error.dart'; -import 'full_screen_image.dart'; +import 'full_screen_media.dart'; class GiphyAttachment extends StatelessWidget { final Attachment attachment; diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 415fc22d..c3f699a5 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -1,10 +1,10 @@ -import 'dart:io'; +import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:gallery_saver/gallery_saver.dart'; - +import 'package:dio/dio.dart'; +import 'package:image_gallery_saver/image_gallery_saver.dart'; import '../stream_chat_flutter.dart'; import 'stream_icons.dart'; @@ -122,14 +122,21 @@ class ImageActionsModal extends StatelessWidget { Navigator.pop(context); Navigator.pop(context); }), - _buildButton(context, 'Save Image', StreamIcons.save_1, - () async { + _buildButton( + context, + 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', + StreamIcons.save_1, () async { var url = urls[currentIndex].imageUrl ?? urls[currentIndex].assetUrl ?? urls[currentIndex].thumbUrl; - var file = await _downloadFile(url); - Navigator.pop(context); + if (urls[currentIndex].type == 'video') { + await _saveVideo(url); + Navigator.pop(context); + } else { + await _saveImage(url); + Navigator.pop(context); + } }), if (StreamChat.of(context).user.id == message.user.id) _buildButton(context, 'Delete', StreamIcons.delete, @@ -181,13 +188,22 @@ class ImageActionsModal extends StatelessWidget { ); } - static Future _downloadFile(String url) async { - var _client = http.Client(); - var req = await _client.get(Uri.parse(url)); - var bytes = req.bodyBytes; - var dir = (await getTemporaryDirectory()).path; - var file = File('$dir/${basename(url)}'); - await file.writeAsBytes(bytes); - return file; + Future _saveImage(String url) async { + var response = await Dio() + .get(url, options: Options(responseType: ResponseType.bytes)); + final result = await ImageGallerySaver.saveImage( + Uint8List.fromList(response.data), + quality: 60, + name: "${DateTime.now().millisecondsSinceEpoch}"); + return result; + } + + Future _saveVideo(String url) async { + var appDocDir = await getTemporaryDirectory(); + var savePath = + appDocDir.path + "/${DateTime.now().millisecondsSinceEpoch}.mp4"; + await Dio().download(url, savePath); + final result = await ImageGallerySaver.saveFile(savePath); + print(result); } } diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index a7dde6ef..2345b2b8 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import '../stream_chat_flutter.dart'; import 'attachment_error.dart'; import 'attachment_title.dart'; -import 'full_screen_image.dart'; +import 'full_screen_media.dart'; import 'utils.dart'; class ImageAttachment extends StatelessWidget { diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 459e7b26..ed82e09a 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -6,7 +6,10 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:gallery_saver/gallery_saver.dart'; +import 'package:dio/dio.dart'; +import 'dart:typed_data'; +import 'package:image_gallery_saver/image_gallery_saver.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; @@ -380,15 +383,20 @@ class _ImageFooterState extends State { child: Material( child: InkWell( onTap: () async { - await GallerySaver.saveImage((widget - .urls[widget.currentPage] - .imageUrl ?? - widget.urls[widget.currentPage] - .assetUrl ?? - widget.urls[widget.currentPage] - .thumbUrl) - .split('?')[0]); - Navigator.pop(context); + var url = widget + .urls[widget.currentPage].imageUrl ?? + widget + .urls[widget.currentPage].assetUrl ?? + widget.urls[widget.currentPage].thumbUrl; + + if (widget.urls[widget.currentPage].type == + 'video') { + await _saveVideo(url); + Navigator.pop(context); + } else { + await _saveImage(url); + Navigator.pop(context); + } }, child: SizedBox.expand( child: Center( @@ -697,6 +705,25 @@ class _ImageFooterState extends State { _selectedUsers.clear(); Navigator.pop(context); } + + Future _saveImage(String url) async { + var response = await Dio() + .get(url, options: Options(responseType: ResponseType.bytes)); + final result = await ImageGallerySaver.saveImage( + Uint8List.fromList(response.data), + quality: 60, + name: "${DateTime.now().millisecondsSinceEpoch}"); + return result; + } + + Future _saveVideo(String url) async { + var appDocDir = await getTemporaryDirectory(); + var savePath = + appDocDir.path + "/${DateTime.now().millisecondsSinceEpoch}.mp4"; + await Dio().download(url, savePath); + final result = await ImageGallerySaver.saveFile(savePath); + print(result); + } } /// Used for clipping textfield prefix icon diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 6702e839..44c15623 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -3,7 +3,7 @@ import 'package:carousel_slider/carousel_options.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/full_screen_image.dart'; +import 'package:stream_chat_flutter/src/full_screen_media.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ImageGroup extends StatelessWidget { diff --git a/lib/src/video_attachment.dart b/lib/src/video_attachment.dart index b6caed53..782b81cb 100644 --- a/lib/src/video_attachment.dart +++ b/lib/src/video_attachment.dart @@ -1,8 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/full_screen_image.dart'; -import 'package:stream_chat_flutter/src/full_screen_video.dart'; +import 'package:stream_chat_flutter/src/full_screen_media.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:video_player/video_player.dart'; @@ -84,14 +83,19 @@ class _VideoAttachmentState extends State { return GestureDetector( onTap: () { + final channel = StreamChannel.of(context).channel; + Navigator.push( context, MaterialPageRoute( - builder: (_) => FullScreenMedia( - mediaAttachments: [widget.attachment], - userName: widget.message.user.name, - sentAt: widget.message.createdAt, - message: widget.message, + builder: (_) => StreamChannel( + channel: channel, + child: FullScreenMedia( + mediaAttachments: [widget.attachment], + userName: widget.message.user.name, + sentAt: widget.message.createdAt, + message: widget.message, + ), ), ), ); diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 91ac68c8..fcb34121 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -10,7 +10,9 @@ export 'src/channels_bloc.dart'; export 'src/date_divider.dart'; export 'src/deleted_message.dart'; export 'src/file_attachment.dart'; -export 'src/full_screen_video.dart'; +export 'src/full_screen_media.dart'; +export 'src/image_header.dart'; +export 'src/image_footer.dart'; export 'src/giphy_attachment.dart'; export 'src/image_attachment.dart'; export 'src/message_input.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 012a0293..b7e11a5b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 - gallery_saver: ^2.0.1 + image_gallery_saver: ^1.6.6 esys_flutter_share: ^1.0.2 media_gallery: git: https://github.com/imtoori/media_gallery.git