Merge pull request #171 from GetStream/qa-fix-attachments
Qa fix attachments
This commit is contained in:
+135
-12
@@ -1,38 +1,79 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat/stream_chat.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/stream_svg_icon.dart';
|
||||||
import 'package:stream_chat_flutter/src/utils.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';
|
||||||
|
|
||||||
class FileAttachment extends StatelessWidget {
|
enum FileAttachmentType { local, online }
|
||||||
|
|
||||||
|
class FileAttachment extends StatefulWidget {
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
final Size size;
|
final Size size;
|
||||||
final Widget trailing;
|
final Widget trailing;
|
||||||
|
final FileAttachmentType attachmentType;
|
||||||
|
final PlatformFile file;
|
||||||
|
|
||||||
const FileAttachment({
|
const FileAttachment({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.attachment,
|
@required this.attachment,
|
||||||
this.size,
|
this.size,
|
||||||
this.trailing,
|
this.trailing,
|
||||||
|
this.attachmentType = FileAttachmentType.online,
|
||||||
|
this.file,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_FileAttachmentState createState() => _FileAttachmentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FileAttachmentState extends State<FileAttachment> {
|
||||||
|
VideoPlayerController _controller;
|
||||||
|
Future<void> _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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Material(
|
return Material(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: size?.width ?? 100,
|
width: widget.size?.width ?? 100,
|
||||||
height: 56.0,
|
height: 56.0,
|
||||||
margin: trailing != null ? EdgeInsets.only(top: 4.0) : null,
|
margin: widget.trailing != null ? EdgeInsets.only(top: 4.0) : null,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: trailing != null ? BorderRadius.circular(16.0) : null,
|
borderRadius:
|
||||||
border: trailing != null
|
widget.trailing != null ? BorderRadius.circular(16.0) : null,
|
||||||
|
border: widget.trailing != null
|
||||||
? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6)))
|
? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6)))
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
child: _getFileTypeImage(attachment.extraData['mime_type']),
|
child: _getFileTypeImage(),
|
||||||
height: 40.0,
|
height: 40.0,
|
||||||
width: 33.33,
|
width: 33.33,
|
||||||
margin: EdgeInsets.all(8.0),
|
margin: EdgeInsets.all(8.0),
|
||||||
@@ -46,7 +87,7 @@ class FileAttachment extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
attachment?.title ?? 'File',
|
widget.attachment?.title ?? 'File',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14.0,
|
fontSize: 14.0,
|
||||||
@@ -58,7 +99,7 @@ class FileAttachment extends StatelessWidget {
|
|||||||
height: 3.0,
|
height: 3.0,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'${attachment.extraData['file_size'] ?? 'N/A'} bytes',
|
'${_getSizeText(widget.attachment.extraData['file_size'])}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: Colors.black.withOpacity(0.5),
|
||||||
fontSize: 14.0,
|
fontSize: 14.0,
|
||||||
@@ -69,13 +110,13 @@ class FileAttachment extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
trailing ??
|
widget.trailing ??
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.cloud_download(
|
icon: StreamSvgIcon.cloud_download(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
launchURL(context, attachment.assetUrl);
|
launchURL(context, widget.attachment.assetUrl);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -117,8 +158,76 @@ class FileAttachment extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSvgIcon _getFileTypeImage(String type) {
|
Widget _getFileTypeImage() {
|
||||||
switch (type) {
|
if ((MediaUtils.getMimeType(widget.attachment.title).type == 'image')) {
|
||||||
|
switch (widget.attachmentType) {
|
||||||
|
case FileAttachmentType.local:
|
||||||
|
return Image.memory(
|
||||||
|
widget.file.bytes,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case FileAttachmentType.online:
|
||||||
|
return CachedNetworkImage(
|
||||||
|
imageUrl: widget.attachment.imageUrl ??
|
||||||
|
widget.attachment.assetUrl ??
|
||||||
|
widget.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((MediaUtils.getMimeType(widget.attachment.title).type == 'video')) {
|
||||||
|
switch (widget.attachmentType) {
|
||||||
|
case FileAttachmentType.local:
|
||||||
|
return FutureBuilder<File>(
|
||||||
|
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':
|
case '7z':
|
||||||
return StreamSvgIcon.filetype_7z();
|
return StreamSvgIcon.filetype_7z();
|
||||||
break;
|
break;
|
||||||
@@ -175,4 +284,18 @@ class FileAttachment extends StatelessWidget {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _getSizeText(int bytes) {
|
||||||
|
if (bytes == null) {
|
||||||
|
return 'Size N/A';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes <= 1000) {
|
||||||
|
return '${bytes} bytes';
|
||||||
|
} else if (bytes <= 100000) {
|
||||||
|
return '${(bytes / 1000).toStringAsFixed(2)} KB';
|
||||||
|
} else {
|
||||||
|
return '${(bytes / 1000000).toStringAsFixed(2)} MB';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
|
|||||||
MediaThumbnailProvider key, DecoderCallback decode) async {
|
MediaThumbnailProvider key, DecoderCallback decode) async {
|
||||||
assert(key == this);
|
assert(key == this);
|
||||||
final bytes = await media.thumbData;
|
final bytes = await media.thumbData;
|
||||||
if (bytes.isEmpty) return null;
|
if (bytes?.isNotEmpty != true) return null;
|
||||||
|
|
||||||
return await decode(bytes);
|
return await decode(bytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+117
-49
@@ -326,14 +326,17 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
return AnimatedCrossFade(
|
return AnimatedCrossFade(
|
||||||
crossFadeState:
|
crossFadeState:
|
||||||
_actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond,
|
_actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond,
|
||||||
firstChild: IconButton(
|
firstChild: InkWell(
|
||||||
onPressed: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_actionsShrunk = false;
|
_actionsShrunk = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: StreamSvgIcon.emptyCircleLeft(
|
child: Padding(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0),
|
||||||
|
child: StreamSvgIcon.emptyCircleLeft(
|
||||||
|
color: StreamChatTheme.of(context).accentColor,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
secondChild: Row(
|
secondChild: Row(
|
||||||
@@ -354,11 +357,12 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(20.0),
|
borderRadius: BorderRadius.circular(24.0),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -404,26 +408,45 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: Chip(
|
child: Chip(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
StreamChatTheme.of(context).accentColor,
|
StreamChatTheme.of(context).accentColor,
|
||||||
label: Text(
|
padding: EdgeInsets.zero,
|
||||||
_chosenCommand?.name ?? "",
|
labelPadding:
|
||||||
style: TextStyle(color: Colors.white),
|
EdgeInsets.symmetric(horizontal: 9.0),
|
||||||
),
|
label: Row(
|
||||||
avatar: StreamSvgIcon.lightning(
|
mainAxisSize: MainAxisSize.min,
|
||||||
color: Colors.white,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
StreamSvgIcon.lightning(
|
||||||
|
color: Colors.white,
|
||||||
|
size: 16.0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
_chosenCommand?.name?.toUpperCase() ?? "",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white, fontSize: 12.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
suffixIcon: _commandEnabled
|
suffixIcon: _commandEnabled
|
||||||
? IconButton(
|
? InkWell(
|
||||||
icon: Icon(Icons.cancel_outlined),
|
child: Padding(
|
||||||
onPressed: () {
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
child: StreamSvgIcon.close_small(),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_commandEnabled = false;
|
_commandEnabled = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
suffixIconConstraints: BoxConstraints(
|
||||||
|
maxHeight: 24.0,
|
||||||
|
maxWidth: 40.0,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
textCapitalization: TextCapitalization.sentences,
|
textCapitalization: TextCapitalization.sentences,
|
||||||
),
|
),
|
||||||
@@ -664,14 +687,18 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
Color _getIconColor(int index) {
|
Color _getIconColor(int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return _attachmentContainsFile && _attachments.isNotEmpty
|
return _attachments.isEmpty
|
||||||
? Colors.black.withOpacity(0.2)
|
? StreamChatTheme.of(context).accentColor
|
||||||
: Colors.black.withOpacity(0.5);
|
: (!_attachmentContainsFile
|
||||||
|
? StreamChatTheme.of(context).accentColor
|
||||||
|
: Colors.black.withOpacity(0.2));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
return !_attachmentContainsFile && _attachments.isNotEmpty
|
return _attachmentContainsFile
|
||||||
? Colors.black.withOpacity(0.2)
|
? StreamChatTheme.of(context).accentColor
|
||||||
: Colors.black.withOpacity(0.5);
|
: (_attachments.isEmpty
|
||||||
|
? Colors.black.withOpacity(0.5)
|
||||||
|
: Colors.black.withOpacity(0.2));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return _attachmentContainsFile && _attachments.isNotEmpty
|
return _attachmentContainsFile && _attachments.isNotEmpty
|
||||||
@@ -799,7 +826,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
Widget _buildPickerSection() {
|
Widget _buildPickerSection() {
|
||||||
var _attachmentContainsFile =
|
var _attachmentContainsFile =
|
||||||
_attachments.any((element) => element.attachment.type == 'file');
|
_attachments.any((element) => element.attachment?.type == 'file');
|
||||||
|
|
||||||
switch (_filePickerIndex) {
|
switch (_filePickerIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -813,22 +840,38 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (snapshot.data) {
|
if (snapshot.data) {
|
||||||
return IgnorePointer(
|
if (_attachmentContainsFile) {
|
||||||
ignoring: _attachmentContainsFile,
|
return GestureDetector(
|
||||||
child: MediaListView(
|
onTap: () {
|
||||||
selectedIds: _attachments.map((e) => e.id).toList(),
|
pickFile(DefaultAttachmentTypes.file);
|
||||||
onSelect: (media) async {
|
|
||||||
if (!_attachments
|
|
||||||
.any((element) => element.id == media.id)) {
|
|
||||||
_addAttachment(media);
|
|
||||||
} else {
|
|
||||||
setState(() {
|
|
||||||
_attachments
|
|
||||||
.removeWhere((element) => element.id == media.id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
child: Container(
|
||||||
|
constraints: BoxConstraints.expand(),
|
||||||
|
color: Color(0xfff2f2f2),
|
||||||
|
child: Text(
|
||||||
|
'Add more files',
|
||||||
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context).accentColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return MediaListView(
|
||||||
|
selectedIds: _attachments.map((e) => e.id).toList(),
|
||||||
|
onSelect: (media) async {
|
||||||
|
if (!_attachments
|
||||||
|
.any((element) => element.id == media.id)) {
|
||||||
|
_addAttachment(media);
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_attachments
|
||||||
|
.removeWhere((element) => element.id == media.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1253,6 +1296,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: FileAttachment(
|
child: FileAttachment(
|
||||||
attachment: e.attachment,
|
attachment: e.attachment,
|
||||||
|
attachmentType: FileAttachmentType.local,
|
||||||
|
file: e.file,
|
||||||
size: Size(
|
size: Size(
|
||||||
MediaQuery.of(context).size.width * 0.55,
|
MediaQuery.of(context).size.width * 0.55,
|
||||||
MediaQuery.of(context).size.height * 0.3,
|
MediaQuery.of(context).size.height * 0.3,
|
||||||
@@ -1442,16 +1487,31 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0),
|
const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0),
|
||||||
child: StreamSvgIcon.lightning(
|
child: StreamSvgIcon.lightning(
|
||||||
color: Color(0xFF000000).withAlpha(128),
|
color: _commandsOverlay != null
|
||||||
|
? StreamChatTheme.of(context).accentColor
|
||||||
|
: Color(0xFF000000).withAlpha(128),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
|
if (_openFilePickerSection) {
|
||||||
|
setState(() {
|
||||||
|
_animateContainer = false;
|
||||||
|
_openFilePickerSection = false;
|
||||||
|
_filePickerSize = _kMinMediaPickerSize;
|
||||||
|
});
|
||||||
|
await Future.delayed(Duration(milliseconds: 300));
|
||||||
|
}
|
||||||
|
|
||||||
if (_commandsOverlay == null) {
|
if (_commandsOverlay == null) {
|
||||||
_commandsOverlay = _buildCommandsOverlayEntry();
|
setState(() {
|
||||||
Overlay.of(context).insert(_commandsOverlay);
|
_commandsOverlay = _buildCommandsOverlayEntry();
|
||||||
|
Overlay.of(context).insert(_commandsOverlay);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
_commandsOverlay?.remove();
|
setState(() {
|
||||||
_commandsOverlay = null;
|
_commandsOverlay?.remove();
|
||||||
|
_commandsOverlay = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -1646,12 +1706,16 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
final mimeType = _getMimeType(file.path.split('/').last);
|
final mimeType = _getMimeType(file.path.split('/').last);
|
||||||
|
|
||||||
if (mimeType.type == 'video' || mimeType.type == 'image') {
|
|
||||||
attachmentType = mimeType.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> extraDataMap = {};
|
Map<String, dynamic> extraDataMap = {};
|
||||||
|
|
||||||
|
if (camera) {
|
||||||
|
if (mimeType.type == 'video' || mimeType.type == 'image') {
|
||||||
|
attachmentType = mimeType.type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
attachmentType = 'file';
|
||||||
|
}
|
||||||
|
|
||||||
if (mimeType?.subtype != null) {
|
if (mimeType?.subtype != null) {
|
||||||
extraDataMap['mime_type'] = mimeType.subtype.toLowerCase();
|
extraDataMap['mime_type'] = mimeType.subtype.toLowerCase();
|
||||||
}
|
}
|
||||||
@@ -1667,7 +1731,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
localUri: file.path != null ? Uri.parse(file.path) : null,
|
localUri: file.path != null ? Uri.parse(file.path) : null,
|
||||||
type: attachmentType,
|
type: attachmentType,
|
||||||
extraData: extraDataMap.isNotEmpty ? extraDataMap : null,
|
extraData: extraDataMap.isNotEmpty ? extraDataMap : null,
|
||||||
title: file.name ?? 'File',
|
title: file.name,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1784,7 +1848,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
Widget _buildIdleSendButton(BuildContext context) {
|
Widget _buildIdleSendButton(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -1793,6 +1857,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: StreamSvgIcon(
|
child: StreamSvgIcon(
|
||||||
assetName: _getIdleSendIcon(),
|
assetName: _getIdleSendIcon(),
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
|
height: 24.0,
|
||||||
|
width: 24.0,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@@ -1801,7 +1867,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
Widget _buildSendButton(BuildContext context) {
|
Widget _buildSendButton(BuildContext context) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
sendMessage();
|
sendMessage();
|
||||||
@@ -1809,6 +1875,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: StreamSvgIcon(
|
child: StreamSvgIcon(
|
||||||
assetName: _getSendIcon(),
|
assetName: _getSendIcon(),
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context).accentColor,
|
||||||
|
height: 24.0,
|
||||||
|
width: 24.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -78,8 +78,9 @@ class UrlAttachment extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
if (urlAttachment.title != null)
|
if (urlAttachment.title != null)
|
||||||
Text(
|
Text(
|
||||||
urlAttachment.title,
|
urlAttachment.title.trim(),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
fontSize: 12.0,
|
fontSize: 12.0,
|
||||||
|
|||||||
Reference in New Issue
Block a user