From 54cb49eac198142eec3d239f480e768f4264c47b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 10 Dec 2020 19:52:32 +0530 Subject: [PATCH] feat: Added file previews --- lib/src/file_attachment.dart | 46 +++++++++++++++++++++++++++++++++--- lib/src/media_utils.dart | 17 +++++++++++++ lib/src/message_input.dart | 26 +++++++++++++++----- 3 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 lib/src/media_utils.dart diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index fff13bbe..cef966c5 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -1,18 +1,28 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'media_utils.dart'; + +enum FileAttachmentType { local, online } class FileAttachment extends StatelessWidget { final Attachment attachment; final Size size; final Widget trailing; + final FileAttachmentType attachmentType; + final PlatformFile file; const FileAttachment({ Key key, @required this.attachment, this.size, this.trailing, + this.attachmentType = FileAttachmentType.online, + this.file, }) : super(key: key); @override @@ -32,7 +42,7 @@ class FileAttachment extends StatelessWidget { child: Row( children: [ Container( - child: _getFileTypeImage(attachment.extraData['mime_type']), + child: _getFileTypeImage(), height: 40.0, width: 33.33, margin: EdgeInsets.all(8.0), @@ -117,8 +127,38 @@ class FileAttachment extends StatelessWidget { ); } - StreamSvgIcon _getFileTypeImage(String type) { - switch (type) { + Widget _getFileTypeImage() { + if ((MediaUtils.getMimeType(attachment.title).type == 'image')) { + switch (attachmentType) { + case FileAttachmentType.local: + return Image.memory( + file.bytes, + fit: BoxFit.cover, + ); + break; + case FileAttachmentType.online: + return CachedNetworkImage( + imageUrl: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + fit: BoxFit.cover, + progressIndicatorBuilder: (context, _, progress) { + return Center( + child: Container( + width: 20.0, + height: 20.0, + child: CircularProgressIndicator( + backgroundColor: StreamChatTheme.of(context).accentColor, + ), + ), + ); + }, + ); + break; + } + } + + switch (attachment.extraData['mime_type']) { case '7z': return StreamSvgIcon.filetype_7z(); break; diff --git a/lib/src/media_utils.dart b/lib/src/media_utils.dart new file mode 100644 index 00000000..e91a47d6 --- /dev/null +++ b/lib/src/media_utils.dart @@ -0,0 +1,17 @@ +import 'package:http_parser/http_parser.dart' as httpParser; +import 'package:mime/mime.dart'; + +class MediaUtils { + static httpParser.MediaType getMimeType(String filename) { + httpParser.MediaType mimeType; + if (filename != null) { + if (filename.toLowerCase().endsWith('heic')) { + mimeType = httpParser.MediaType.parse('image/heic'); + } else { + mimeType = httpParser.MediaType.parse(lookupMimeType(filename)); + } + } + + return mimeType; + } +} diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e21ab4b1..870c1ed9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -683,10 +683,18 @@ class MessageInputState extends State { Color _getIconColor(int index) { switch (index) { case 0: - return _attachments.isEmpty ? StreamChatTheme.of(context).accentColor : (!_attachmentContainsFile ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.2)); + return _attachments.isEmpty + ? StreamChatTheme.of(context).accentColor + : (!_attachmentContainsFile + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.2)); break; case 1: - return _attachmentContainsFile ? StreamChatTheme.of(context).accentColor : (_attachments.isEmpty ? Colors.black.withOpacity(0.5) : Colors.black.withOpacity(0.2)); + return _attachmentContainsFile + ? StreamChatTheme.of(context).accentColor + : (_attachments.isEmpty + ? Colors.black.withOpacity(0.5) + : Colors.black.withOpacity(0.2)); break; case 2: return _attachmentContainsFile && _attachments.isNotEmpty @@ -1268,6 +1276,8 @@ class MessageInputState extends State { clipBehavior: Clip.antiAlias, child: FileAttachment( attachment: e.attachment, + attachmentType: FileAttachmentType.local, + file: e.file, size: Size( MediaQuery.of(context).size.width * 0.55, MediaQuery.of(context).size.height * 0.3, @@ -1676,12 +1686,16 @@ class MessageInputState extends State { final mimeType = _getMimeType(file.path.split('/').last); - if (mimeType.type == 'video' || mimeType.type == 'image') { - attachmentType = mimeType.type; - } - Map extraDataMap = {}; + if (camera) { + if (mimeType.type == 'video' || mimeType.type == 'image') { + attachmentType = mimeType.type; + } + } else { + attachmentType = 'file'; + } + if (mimeType?.subtype != null) { extraDataMap['mime_type'] = mimeType.subtype.toLowerCase(); }