From b6f0b6f2c1cec19733cc37c8d9e36ffc642bfd73 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 28 Feb 2020 17:01:57 +0100 Subject: [PATCH] add file upload --- example/ios/Runner/Info.plist | 4 + lib/src/message_input.dart | 161 ++++++++++++++++++++++++++++------ lib/src/message_widget.dart | 4 +- pubspec.yaml | 4 +- 4 files changed, 144 insertions(+), 29 deletions(-) diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index b4a7df41..f6d694bd 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -48,6 +48,10 @@ NSAppleMusicUsageDescription Used to send message attachments + NSCameraUsageDescription + Used to send message attachments + NSMicrophoneUsageDescription + Used to send message attachments NSPhotoLibraryUsageDescription Used to send message attachments diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index a586c704..8f3ca608 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; @@ -136,7 +137,7 @@ class _MessageInputState extends State { Container( height: 50, width: 50, - child: Image.file(attachment.file), + child: _buildAttachment(attachment), ), Positioned( height: 16, @@ -176,6 +177,25 @@ class _MessageInputState extends State { ); } + Widget _buildAttachment(_SendingAttachment attachment) { + switch (attachment.type) { + case FileType.IMAGE: + return Image.file(attachment.file); + break; + case FileType.VIDEO: + return Container( + child: Icon(Icons.videocam), + color: Colors.black26, + ); + break; + default: + return Container( + child: Icon(Icons.insert_drive_file), + color: Colors.black26, + ); + } + } + Material _buildAttachmentButton() { return Material( clipBehavior: Clip.hardEdge, @@ -184,25 +204,72 @@ class _MessageInputState extends State { ), color: Colors.transparent, child: IconButton( - onPressed: () async { - final file = await FilePicker.getFile(type: FileType.IMAGE); - print(file.path); - - final channel = StreamChannel.of(context).channel; - - final bytes = await file.readAsBytes(); - final res = await channel.sendFile(MultipartFile.fromBytes( - bytes, - filename: file.path.split('/').last, - )); - - setState(() { - _attachments.add(_SendingAttachment( - url: res.file, - extension: file.path.split('.').last, - file: file, - )); - }); + onPressed: () { + showModalBottomSheet( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), + ), + context: context, + builder: (_) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: Text( + 'Add a file', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + ListTile( + leading: Icon(Icons.image), + title: Text('Upload a photo'), + onTap: () { + _pickFile(FileType.IMAGE, false); + Navigator.pop(context); + }, + ), + ListTile( + leading: Icon(Icons.video_library), + title: Text('Upload a video'), + onTap: () { + _pickFile(FileType.VIDEO, false); + Navigator.pop(context); + }, + ), + ListTile( + leading: Icon(Icons.camera_alt), + title: Text('Photo from camera'), + onTap: () { + ImagePicker.pickImage(source: ImageSource.camera); + _pickFile(FileType.IMAGE, true); + Navigator.pop(context); + }, + ), + ListTile( + leading: Icon(Icons.videocam), + title: Text('Video from camera'), + onTap: () { + _pickFile(FileType.VIDEO, true); + Navigator.pop(context); + }, + ), + ListTile( + leading: Icon(Icons.insert_drive_file), + title: Text('Upload a file'), + onTap: () { + _pickFile(FileType.ANY, false); + Navigator.pop(context); + }, + ), + ], + ); + }); }, icon: Icon( Icons.add_circle_outline, @@ -211,6 +278,38 @@ class _MessageInputState extends State { ); } + void _pickFile(FileType type, bool camera) async { + File file; + + if (camera) { + if (type == FileType.IMAGE) { + file = await ImagePicker.pickImage(source: ImageSource.camera); + } else if (type == FileType.VIDEO) { + file = await ImagePicker.pickVideo(source: ImageSource.camera); + } + } else { + file = await FilePicker.getFile(type: type); + } + + final channel = StreamChannel.of(context).channel; + + final bytes = await file.readAsBytes(); + final res = await channel.sendFile( + MultipartFile.fromBytes( + bytes, + filename: file.path.split('/').last, + ), + ); + + setState(() { + _attachments.add(_SendingAttachment( + url: res.file, + file: file, + type: type, + )); + }); + } + Widget _buildSendButton(BuildContext context) { return IconTheme( data: @@ -239,7 +338,7 @@ class _MessageInputState extends State { return; } - final attachments = List.from(_attachments); + final attachments = List<_SendingAttachment>.from(_attachments); _textController.clear(); _attachments.clear(); @@ -257,10 +356,22 @@ class _MessageInputState extends State { parentId: widget.parentMessage?.id, text: text, attachments: attachments.map((attachment) { + String type; + switch (attachment.type) { + case FileType.IMAGE: + type = 'image'; + break; + case FileType.VIDEO: + type = 'video'; + break; + default: + type = 'file'; + } return Attachment( - imageUrl: attachment.url, + imageUrl: + attachment.type == FileType.IMAGE ? attachment.url : null, assetUrl: attachment.url, - type: 'image', + type: type, ); }).toList(), ), @@ -275,12 +386,12 @@ class _MessageInputState extends State { class _SendingAttachment { final String url; - final String extension; final File file; + final FileType type; _SendingAttachment({ this.url, - this.extension, this.file, + this.type, }); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 6fd6e4ae..d1ec0009 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -211,7 +211,7 @@ class _MessageWidgetState extends State borderRadius: boxDecoration.borderRadius, child: Container( decoration: boxDecoration, - constraints: BoxConstraints.loose(Size(300, 500)), + constraints: BoxConstraints.loose(Size.fromWidth(300)), child: Stack( children: [ Column( @@ -256,7 +256,7 @@ class _MessageWidgetState extends State ), color: Color(0xffebebeb), ) - : Container(), + : SizedBox(), ], ), attachment.type == 'image' && attachment.titleLink != null diff --git a/pubspec.yaml b/pubspec.yaml index cf0220ca..ad2f7788 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,8 +19,8 @@ dependencies: video_player: ^0.10.7 chewie: ^0.9.8+1 file_picker: ^1.4.3+2 - stream_chat: - path: ../stream_chat_dart + image_picker: ^0.6.3+4 + stream_chat: ^0.1.12 dev_dependencies: pedantic: ^1.8.0+1