extract attachment widgets
This commit is contained in:
@@ -67,7 +67,6 @@ void main() async {
|
||||
final client = Client(
|
||||
'b67pax5b2wdq',
|
||||
logLevel: Level.INFO,
|
||||
persistenceEnabled: false,
|
||||
showLocalNotification: Platform.isAndroid ? showLocalNotification : null,
|
||||
);
|
||||
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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';
|
||||
|
||||
/// 
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user