extract videoattachment
This commit is contained in:
@@ -67,6 +67,7 @@ void main() async {
|
|||||||
final client = Client(
|
final client = Client(
|
||||||
'b67pax5b2wdq',
|
'b67pax5b2wdq',
|
||||||
logLevel: Level.INFO,
|
logLevel: Level.INFO,
|
||||||
|
persistenceEnabled: false,
|
||||||
showLocalNotification: Platform.isAndroid ? showLocalNotification : null,
|
showLocalNotification: Platform.isAndroid ? showLocalNotification : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
|
class AttachmentError extends StatelessWidget {
|
||||||
|
final Attachment attachment;
|
||||||
|
|
||||||
|
const AttachmentError({
|
||||||
|
Key key,
|
||||||
|
@required this.attachment,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (attachment.localUri != null) {
|
||||||
|
return Image.file(
|
||||||
|
File(attachment.localUri.path),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
width: 200,
|
||||||
|
height: 140,
|
||||||
|
color: Color(0xffd0021B).withOpacity(.1),
|
||||||
|
child: Center(
|
||||||
|
child: Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-123
@@ -1,13 +1,11 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:chewie/chewie.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
import 'package:stream_chat/stream_chat.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/full_screen_image.dart';
|
||||||
import 'package:stream_chat_flutter/src/message_input.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/message_list_view.dart';
|
||||||
@@ -17,9 +15,9 @@ import 'package:stream_chat_flutter/src/sending_indicator.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_channel.dart';
|
import 'package:stream_chat_flutter/src/stream_channel.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/utils.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/video_attachment.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
import 'package:video_player/video_player.dart';
|
|
||||||
|
|
||||||
import 'deleted_message.dart';
|
import 'deleted_message.dart';
|
||||||
import 'stream_chat.dart';
|
import 'stream_chat.dart';
|
||||||
@@ -81,9 +79,6 @@ class MessageWidget extends StatefulWidget {
|
|||||||
|
|
||||||
class _MessageWidgetState extends State<MessageWidget>
|
class _MessageWidgetState extends State<MessageWidget>
|
||||||
with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
|
with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
|
||||||
final Map<String, ChangeNotifier> _videoControllers = {};
|
|
||||||
final Map<String, ChangeNotifier> _chuwieControllers = {};
|
|
||||||
|
|
||||||
MessageTheme _messageTheme;
|
MessageTheme _messageTheme;
|
||||||
StreamChatState _streamChat;
|
StreamChatState _streamChat;
|
||||||
StreamChannelState _streamChannel;
|
StreamChannelState _streamChannel;
|
||||||
@@ -219,7 +214,10 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
|
|
||||||
Widget attachmentWidget;
|
Widget attachmentWidget;
|
||||||
if (attachment.type == 'video') {
|
if (attachment.type == 'video') {
|
||||||
attachmentWidget = _buildVideo(attachment);
|
attachmentWidget = VideoAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
enableFullScreen: widget.showVideoFullScreen,
|
||||||
|
);
|
||||||
} else if (attachment.type == 'image' ||
|
} else if (attachment.type == 'image' ||
|
||||||
attachment.type == 'giphy') {
|
attachment.type == 'giphy') {
|
||||||
attachmentWidget = _buildImage(attachment);
|
attachmentWidget = _buildImage(attachment);
|
||||||
@@ -227,7 +225,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
attachmentWidget = Material(
|
attachmentWidget = Material(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_launchURL(attachment.assetUrl);
|
launchURL(context, attachment.assetUrl);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 100,
|
width: 100,
|
||||||
@@ -478,7 +476,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
print('tap on ${mentionedUser.name}');
|
print('tap on ${mentionedUser.name}');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_launchURL(link);
|
launchURL(context, link);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
styleSheet: MarkdownStyleSheet.fromTheme(
|
styleSheet: MarkdownStyleSheet.fromTheme(
|
||||||
@@ -558,7 +556,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => _launchURL(attachment.titleLink),
|
onTap: () => launchURL(context, attachment.titleLink),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -568,7 +566,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (attachment.titleLink != null) {
|
if (attachment.titleLink != null) {
|
||||||
_launchURL(attachment.titleLink);
|
launchURL(context, attachment.titleLink);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
@@ -896,7 +894,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
if (attachment.thumbUrl == null &&
|
if (attachment.thumbUrl == null &&
|
||||||
attachment.imageUrl == null &&
|
attachment.imageUrl == null &&
|
||||||
attachment.assetUrl == null) {
|
attachment.assetUrl == null) {
|
||||||
return _buildErrorImage(attachment);
|
return AttachmentError(
|
||||||
|
attachment: attachment,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Hero(
|
return Hero(
|
||||||
@@ -924,122 +924,16 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
},
|
},
|
||||||
imageUrl:
|
imageUrl:
|
||||||
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl,
|
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl,
|
||||||
errorWidget: (context, url, error) => _buildErrorImage(attachment),
|
errorWidget: (context, url, error) => AttachmentError(
|
||||||
|
attachment: attachment,
|
||||||
|
),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildErrorImage(Attachment attachment) {
|
|
||||||
if (attachment.localUri != null) {
|
|
||||||
return Image.file(
|
|
||||||
File(attachment.localUri.path),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Center(
|
|
||||||
child: Container(
|
|
||||||
width: 200,
|
|
||||||
height: 140,
|
|
||||||
color: Color(0xffd0021B).withOpacity(.1),
|
|
||||||
child: Center(
|
|
||||||
child: Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildVideo(
|
|
||||||
Attachment attachment,
|
|
||||||
) {
|
|
||||||
VideoPlayerController videoController;
|
|
||||||
if (_videoControllers.containsKey(attachment.assetUrl)) {
|
|
||||||
videoController = _videoControllers[attachment.assetUrl];
|
|
||||||
} else {
|
|
||||||
videoController = VideoPlayerController.network(attachment.assetUrl);
|
|
||||||
_videoControllers[attachment.assetUrl] = videoController;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FutureBuilder<void>(
|
|
||||||
future: videoController.value.initialized
|
|
||||||
? Future.value(true)
|
|
||||||
: videoController.initialize(),
|
|
||||||
builder: (_, snapshot) {
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) {
|
|
||||||
return Container(
|
|
||||||
height: 100,
|
|
||||||
width: 100,
|
|
||||||
child: Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ChewieController chewieController;
|
|
||||||
if (_chuwieControllers.containsKey(attachment.assetUrl)) {
|
|
||||||
chewieController = _chuwieControllers[attachment.assetUrl];
|
|
||||||
} else {
|
|
||||||
chewieController = ChewieController(
|
|
||||||
allowFullScreen: widget.showVideoFullScreen,
|
|
||||||
videoPlayerController: videoController,
|
|
||||||
autoInitialize: false,
|
|
||||||
aspectRatio: videoController.value.aspectRatio,
|
|
||||||
errorBuilder: (_, e) {
|
|
||||||
if (attachment.thumbUrl != null) {
|
|
||||||
return Stack(
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
image: DecorationImage(
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
image: CachedNetworkImageProvider(
|
|
||||||
attachment.thumbUrl,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (attachment.titleLink != null)
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () => _launchURL(attachment.titleLink),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buildErrorImage(attachment);
|
|
||||||
});
|
|
||||||
_chuwieControllers[attachment.assetUrl] = chewieController;
|
|
||||||
}
|
|
||||||
return Chewie(
|
|
||||||
key: ValueKey<String>(
|
|
||||||
'ATTACHMENT-${attachment.title}-${widget.message.id}'),
|
|
||||||
controller: chewieController,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _launchURL(String url) async {
|
|
||||||
if (await canLaunch(url)) {
|
|
||||||
await launch(url);
|
|
||||||
} else {
|
|
||||||
Scaffold.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Cannot launch the url'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_videoControllers.values.forEach((element) {
|
|
||||||
element.dispose();
|
|
||||||
});
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
Future<void> launchURL(BuildContext context, String url) async {
|
||||||
|
if (await canLaunch(url)) {
|
||||||
|
await launch(url);
|
||||||
|
} else {
|
||||||
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Cannot launch the url'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:chewie/chewie.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/utils.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
import 'attachment_error.dart';
|
||||||
|
|
||||||
|
class VideoAttachment extends StatefulWidget {
|
||||||
|
final Attachment attachment;
|
||||||
|
final bool enableFullScreen;
|
||||||
|
|
||||||
|
VideoAttachment({
|
||||||
|
Key key,
|
||||||
|
@required this.attachment,
|
||||||
|
this.enableFullScreen = true,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_VideoAttachmentState createState() => _VideoAttachmentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoAttachmentState extends State<VideoAttachment> {
|
||||||
|
ChewieController _chewieController;
|
||||||
|
VideoPlayerController _videoPlayerController;
|
||||||
|
bool initialized = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (!initialized) {
|
||||||
|
return Container(
|
||||||
|
height: 100,
|
||||||
|
width: 100,
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_chewieController = ChewieController(
|
||||||
|
allowFullScreen: widget.enableFullScreen,
|
||||||
|
videoPlayerController: _videoPlayerController,
|
||||||
|
autoInitialize: false,
|
||||||
|
aspectRatio: _videoPlayerController.value.aspectRatio,
|
||||||
|
errorBuilder: (_, e) {
|
||||||
|
if (widget.attachment.thumbUrl != null) {
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
image: CachedNetworkImageProvider(
|
||||||
|
widget.attachment.thumbUrl,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (widget.attachment.titleLink != null)
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () =>
|
||||||
|
launchURL(context, widget.attachment.titleLink),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return AttachmentError(
|
||||||
|
attachment: widget.attachment,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Chewie(
|
||||||
|
controller: _chewieController,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_videoPlayerController = VideoPlayerController.network(
|
||||||
|
widget.attachment.localUri ?? widget.attachment.assetUrl);
|
||||||
|
_videoPlayerController.initialize().then((_) {
|
||||||
|
if (_videoPlayerController.value.initialized) {
|
||||||
|
setState(() {
|
||||||
|
initialized = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_videoPlayerController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user