From 18781201e37d28d09fcdce0c24bd8569a1ab53fc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Dec 2020 18:18:35 +0530 Subject: [PATCH] feat: Added video thumbnails and playback for attachments --- lib/src/file_attachment.dart | 101 +++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 16 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index cef966c5..95e628f0 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; @@ -5,11 +7,13 @@ 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 'package:video_compress/video_compress.dart'; +import 'package:video_player/video_player.dart'; import 'media_utils.dart'; enum FileAttachmentType { local, online } -class FileAttachment extends StatelessWidget { +class FileAttachment extends StatefulWidget { final Attachment attachment; final Size size; final Widget trailing; @@ -25,17 +29,44 @@ class FileAttachment extends StatelessWidget { this.file, }) : super(key: key); + @override + _FileAttachmentState createState() => _FileAttachmentState(); +} + +class _FileAttachmentState extends State { + VideoPlayerController _controller; + Future _initializeVideoPlayerFuture; + + @override + void initState() { + super.initState(); + if (MediaUtils.getMimeType(widget.attachment.title).type == 'video') { + if (widget.attachmentType == FileAttachmentType.online) { + _controller = VideoPlayerController.network( + widget.attachment.assetUrl, + ); + } else { + _controller = VideoPlayerController.file( + File.fromRawPath(widget.file.bytes), + ); + } + + _initializeVideoPlayerFuture = _controller.initialize(); + } + } + @override Widget build(BuildContext context) { return Material( child: Container( - width: size?.width ?? 100, + width: widget.size?.width ?? 100, height: 56.0, - margin: trailing != null ? EdgeInsets.only(top: 4.0) : null, + margin: widget.trailing != null ? EdgeInsets.only(top: 4.0) : null, decoration: BoxDecoration( color: Colors.white, - borderRadius: trailing != null ? BorderRadius.circular(16.0) : null, - border: trailing != null + borderRadius: + widget.trailing != null ? BorderRadius.circular(16.0) : null, + border: widget.trailing != null ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) : null, ), @@ -56,7 +87,7 @@ class FileAttachment extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - attachment?.title ?? 'File', + widget.attachment?.title ?? 'File', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14.0, @@ -68,7 +99,7 @@ class FileAttachment extends StatelessWidget { height: 3.0, ), Text( - '${attachment.extraData['file_size'] ?? 'N/A'} bytes', + '${widget.attachment.extraData['file_size'] ?? 'N/A'} bytes', style: TextStyle( color: Colors.black.withOpacity(0.5), fontSize: 14.0, @@ -79,13 +110,13 @@ class FileAttachment extends StatelessWidget { ), Column( children: [ - trailing ?? + widget.trailing ?? IconButton( icon: StreamSvgIcon.cloud_download( color: Colors.black, ), onPressed: () { - launchURL(context, attachment.assetUrl); + launchURL(context, widget.attachment.assetUrl); }, ), ], @@ -128,19 +159,19 @@ class FileAttachment extends StatelessWidget { } Widget _getFileTypeImage() { - if ((MediaUtils.getMimeType(attachment.title).type == 'image')) { - switch (attachmentType) { + if ((MediaUtils.getMimeType(widget.attachment.title).type == 'image')) { + switch (widget.attachmentType) { case FileAttachmentType.local: return Image.memory( - file.bytes, + widget.file.bytes, fit: BoxFit.cover, ); break; case FileAttachmentType.online: return CachedNetworkImage( - imageUrl: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, + imageUrl: widget.attachment.imageUrl ?? + widget.attachment.assetUrl ?? + widget.attachment.thumbUrl, fit: BoxFit.cover, progressIndicatorBuilder: (context, _, progress) { return Center( @@ -158,7 +189,45 @@ class FileAttachment extends StatelessWidget { } } - switch (attachment.extraData['mime_type']) { + if ((MediaUtils.getMimeType(widget.attachment.title).type == 'video')) { + switch (widget.attachmentType) { + case FileAttachmentType.local: + return FutureBuilder( + future: VideoCompress.getFileThumbnail(widget.file.path), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Image.asset( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ); + } + + return Image.file( + snapshot.data, + fit: BoxFit.cover, + ); + }, + ); + break; + case FileAttachmentType.online: + return FutureBuilder( + future: _initializeVideoPlayerFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return AspectRatio( + aspectRatio: _controller.value.aspectRatio, + child: VideoPlayer(_controller), + ); + } else { + return Center(child: CircularProgressIndicator()); + } + }, + ); + break; + } + } + + switch (widget.attachment.extraData['mime_type']) { case '7z': return StreamSvgIcon.filetype_7z(); break;