extract attachment widgets

This commit is contained in:
Salvatore Giordano
2020-04-22 15:39:06 +02:00
parent 17c171f984
commit 493ebe33f4
8 changed files with 384 additions and 193 deletions
-1
View File
@@ -67,7 +67,6 @@ void main() async {
final client = Client(
'b67pax5b2wdq',
logLevel: Level.INFO,
persistenceEnabled: false,
showLocalNotification: Platform.isAndroid ? showLocalNotification : null,
);
+58
View File
@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
class AttachmentActions extends StatelessWidget {
final Attachment attachment;
final Message message;
const AttachmentActions({
Key key,
this.attachment,
this.message,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final streamChannel = StreamChannel.of(context);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: attachment.actions?.map((action) {
if (action.style == 'primary') {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Text('${action.text}'),
color: action.style == 'primary'
? StreamChatTheme.of(context).accentColor
: null,
textColor: Colors.white,
onPressed: () {
streamChannel.channel.sendAction(message, {
action.name: action.value,
});
},
),
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: OutlineButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Text('${action.text}'),
color: StreamChatTheme.of(context).accentColor,
onPressed: () {
streamChannel.channel.sendAction(message, {
action.name: action.value,
});
},
),
);
})?.toList(),
);
}
}
+66
View File
@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:stream_chat/stream_chat.dart';
import 'stream_chat_theme.dart';
import 'utils.dart';
class AttachmentTitle extends StatelessWidget {
const AttachmentTitle({
Key key,
@required this.attachment,
@required this.messageTheme,
}) : super(key: key);
final MessageTheme messageTheme;
final Attachment attachment;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (attachment.titleLink != null) {
launchURL(context, attachment.titleLink);
}
},
child: Container(
constraints: BoxConstraints.loose(
Size(
MediaQuery.of(context).size.width * 0.7,
500,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
attachment.title,
overflow: TextOverflow.ellipsis,
style: messageTheme.messageText.copyWith(
color: StreamChatTheme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
if (attachment.titleLink != null ||
attachment.ogScrapeUrl != null)
Text(
Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl)
.authority
.split('.')
.reversed
.take(2)
.toList()
.reversed
.join('.'),
overflow: TextOverflow.ellipsis,
style: messageTheme.createdAt,
),
],
),
),
),
);
}
}
+30
View File
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/utils.dart';
class FileAttachment extends StatelessWidget {
final Attachment attachment;
const FileAttachment({
Key key,
@required this.attachment,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
child: InkWell(
onTap: () {
launchURL(context, attachment.assetUrl);
},
child: Container(
width: 100,
height: 100,
child: Center(
child: Icon(Icons.attach_file),
),
),
),
);
}
}
+100
View File
@@ -0,0 +1,100 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/attachment_actions.dart';
import '../stream_chat_flutter.dart';
import 'attachment_error.dart';
import 'attachment_title.dart';
import 'full_screen_image.dart';
import 'utils.dart';
class GiphyAttachment extends StatelessWidget {
final Attachment attachment;
final MessageTheme messageTheme;
final Message message;
const GiphyAttachment({
Key key,
this.attachment,
this.messageTheme,
this.message,
}) : super(key: key);
@override
Widget build(BuildContext context) {
if (attachment.thumbUrl == null &&
attachment.imageUrl == null &&
attachment.assetUrl == null) {
return AttachmentError(
attachment: attachment,
);
}
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Stack(
children: <Widget>[
Hero(
tag: attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl,
child: CachedNetworkImage(
imageBuilder: (context, provider) {
return GestureDetector(
child: Image(image: provider),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return FullScreenImage(
url: attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl,
);
}));
},
);
},
placeholder: (_, __) {
return Container(
width: 200,
height: 140,
);
},
imageUrl: attachment.thumbUrl ??
attachment.imageUrl ??
attachment.assetUrl,
errorWidget: (context, url, error) => AttachmentError(
attachment: attachment,
),
fit: BoxFit.cover,
),
),
if (attachment.titleLink != null || attachment.ogScrapeUrl != null)
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => launchURL(
context,
attachment.titleLink ?? attachment.ogScrapeUrl,
),
),
),
),
],
),
if (attachment.title != null)
AttachmentTitle(
messageTheme: messageTheme,
attachment: attachment,
),
if (attachment.actions != null)
AttachmentActions(
attachment: attachment,
message: message,
),
],
);
}
}
+92
View File
@@ -0,0 +1,92 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import '../stream_chat_flutter.dart';
import 'attachment_error.dart';
import 'attachment_title.dart';
import 'full_screen_image.dart';
import 'utils.dart';
class ImageAttachment extends StatelessWidget {
final Attachment attachment;
final MessageTheme messageTheme;
const ImageAttachment({
Key key,
this.attachment,
this.messageTheme,
}) : super(key: key);
@override
Widget build(BuildContext context) {
if (attachment.thumbUrl == null &&
attachment.imageUrl == null &&
attachment.assetUrl == null) {
return AttachmentError(
attachment: attachment,
);
}
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Stack(
children: <Widget>[
Hero(
tag: attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl,
child: CachedNetworkImage(
imageBuilder: (context, provider) {
return GestureDetector(
child: Image(image: provider),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return FullScreenImage(
url: attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl,
);
}));
},
);
},
placeholder: (_, __) {
return Container(
width: 200,
height: 140,
);
},
imageUrl: attachment.thumbUrl ??
attachment.imageUrl ??
attachment.assetUrl,
errorWidget: (context, url, error) => AttachmentError(
attachment: attachment,
),
fit: BoxFit.cover,
),
),
if (attachment.titleLink != null || attachment.ogScrapeUrl != null)
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => launchURL(
context,
attachment.titleLink ?? attachment.ogScrapeUrl,
),
),
),
),
],
),
if (attachment.title != null)
AttachmentTitle(
messageTheme: messageTheme,
attachment: attachment,
),
],
);
}
}
+18 -184
View File
@@ -1,12 +1,11 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:jiffy/jiffy.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/attachment_error.dart';
import 'package:stream_chat_flutter/src/full_screen_image.dart';
import 'package:stream_chat_flutter/src/giphy_attachment.dart';
import 'package:stream_chat_flutter/src/image_attachment.dart';
import 'package:stream_chat_flutter/src/message_input.dart';
import 'package:stream_chat_flutter/src/message_list_view.dart';
import 'package:stream_chat_flutter/src/reaction_picker.dart';
@@ -20,6 +19,7 @@ import 'package:stream_chat_flutter/src/video_attachment.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'deleted_message.dart';
import 'file_attachment.dart';
import 'stream_chat.dart';
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_widget.png)
@@ -216,25 +216,23 @@ class _MessageWidgetState extends State<MessageWidget>
if (attachment.type == 'video') {
attachmentWidget = VideoAttachment(
attachment: attachment,
messageTheme: _messageTheme,
enableFullScreen: widget.showVideoFullScreen,
);
} else if (attachment.type == 'image' ||
attachment.type == 'giphy') {
attachmentWidget = _buildImage(attachment);
} else if (attachment.type == 'giphy') {
attachmentWidget = GiphyAttachment(
attachment: attachment,
message: widget.message,
messageTheme: _messageTheme,
);
} else if (attachment.type == 'image') {
attachmentWidget = ImageAttachment(
attachment: attachment,
messageTheme: _messageTheme,
);
} else if (attachment.type == 'file') {
attachmentWidget = Material(
child: InkWell(
onTap: () {
launchURL(context, attachment.assetUrl);
},
child: Container(
width: 100,
height: 100,
child: Center(
child: Icon(Icons.attach_file),
),
),
),
attachmentWidget = FileAttachment(
attachment: attachment,
);
}
@@ -375,29 +373,12 @@ class _MessageWidgetState extends State<MessageWidget>
constraints: BoxConstraints.loose(
Size.fromWidth(MediaQuery.of(context).size.width * 0.7),
),
child: Stack(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
attachmentWidget,
if (attachment.title != null)
_buildAttachmentTitle(attachment),
],
),
if (attachment.type == 'image' &&
attachment.titleLink != null)
_buildPreviewInkwell(attachment),
],
),
child: attachmentWidget,
margin: EdgeInsets.only(
top: nOfAttachmentWidgets > 1 ? 5 : 0,
),
),
),
if (attachment.actions != null)
_buildAttachmentActions(attachment, context),
],
),
);
@@ -508,109 +489,6 @@ class _MessageWidgetState extends State<MessageWidget>
return text;
}
Row _buildAttachmentActions(Attachment attachment, BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: attachment.actions?.map((action) {
if (action.style == 'primary') {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Text('${action.text}'),
color: action.style == 'primary'
? StreamChatTheme.of(context).accentColor
: null,
textColor: Colors.white,
onPressed: () {
_streamChannel.channel.sendAction(widget.message, {
action.name: action.value,
});
},
),
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: OutlineButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Text('${action.text}'),
color: StreamChatTheme.of(context).accentColor,
onPressed: () {
_streamChannel.channel.sendAction(widget.message, {
action.name: action.value,
});
},
),
);
})?.toList(),
);
}
Positioned _buildPreviewInkwell(Attachment attachment) {
return Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => launchURL(context, attachment.titleLink),
),
),
);
}
GestureDetector _buildAttachmentTitle(Attachment attachment) {
return GestureDetector(
onTap: () {
if (attachment.titleLink != null) {
launchURL(context, attachment.titleLink);
}
},
child: Container(
constraints: BoxConstraints.loose(
Size(
MediaQuery.of(context).size.width * 0.7,
500,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
attachment.title,
overflow: TextOverflow.ellipsis,
style: _messageTheme.messageText.copyWith(
color: StreamChatTheme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
if (attachment.titleLink != null ||
attachment.ogScrapeUrl != null)
Text(
Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl)
.authority
.split('.')
.reversed
.take(2)
.toList()
.reversed
.join('.'),
overflow: TextOverflow.ellipsis,
style: _messageTheme.createdAt,
),
],
),
),
),
);
}
Widget _buildReactionPaint() {
return widget.message.reactionCounts?.isNotEmpty == true
? Positioned(
@@ -888,50 +766,6 @@ class _MessageWidgetState extends State<MessageWidget>
'wow': '😲',
};
Widget _buildImage(
Attachment attachment,
) {
if (attachment.thumbUrl == null &&
attachment.imageUrl == null &&
attachment.assetUrl == null) {
return AttachmentError(
attachment: attachment,
);
}
return Hero(
tag: attachment.imageUrl ?? attachment.assetUrl ?? attachment.thumbUrl,
child: CachedNetworkImage(
imageBuilder: (context, provider) {
return GestureDetector(
child: Image(image: provider),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return FullScreenImage(
url: attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl,
);
}));
},
);
},
placeholder: (_, __) {
return Container(
width: 200,
height: 140,
);
},
imageUrl:
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl,
errorWidget: (context, url, error) => AttachmentError(
attachment: attachment,
),
fit: BoxFit.cover,
),
);
}
@override
void dispose() {
super.dispose();
+20 -8
View File
@@ -6,14 +6,17 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:video_player/video_player.dart';
import 'attachment_error.dart';
import 'attachment_title.dart';
class VideoAttachment extends StatefulWidget {
final Attachment attachment;
final bool enableFullScreen;
final MessageTheme messageTheme;
VideoAttachment({
Key key,
@required this.attachment,
@required this.messageTheme,
this.enableFullScreen = true,
}) : super(key: key);
@@ -72,8 +75,19 @@ class _VideoAttachmentState extends State<VideoAttachment> {
);
});
return Chewie(
controller: _chewieController,
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Chewie(
controller: _chewieController,
),
if (widget.attachment.title != null)
AttachmentTitle(
messageTheme: widget.messageTheme,
attachment: widget.attachment,
),
],
);
}
@@ -82,12 +96,10 @@ class _VideoAttachmentState extends State<VideoAttachment> {
super.initState();
_videoPlayerController = VideoPlayerController.network(
widget.attachment.localUri ?? widget.attachment.assetUrl);
_videoPlayerController.initialize().then((_) {
if (_videoPlayerController.value.initialized) {
setState(() {
initialized = true;
});
}
_videoPlayerController.initialize().whenComplete(() {
setState(() {
initialized = true;
});
});
}