fix video attachment fullscreen
This commit is contained in:
@@ -94,7 +94,7 @@ class MyApp extends StatelessWidget {
|
||||
return MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
darkTheme: ThemeData.dark(),
|
||||
themeMode: ThemeMode.system,
|
||||
themeMode: ThemeMode.dark,
|
||||
home: Container(
|
||||
child: StreamChat(
|
||||
client: client,
|
||||
|
||||
@@ -32,7 +32,6 @@ class _FullScreenVideoState extends State<FullScreenVideo> {
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
return Chewie(
|
||||
controller: _chewieController,
|
||||
);
|
||||
@@ -49,28 +48,28 @@ class _FullScreenVideoState extends State<FullScreenVideo> {
|
||||
_videoPlayerController.initialize().whenComplete(() {
|
||||
setState(() {
|
||||
initialized = true;
|
||||
_chewieController = ChewieController(
|
||||
videoPlayerController: _videoPlayerController,
|
||||
autoInitialize: false,
|
||||
aspectRatio: _videoPlayerController.value.aspectRatio,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
_chewieController = ChewieController(
|
||||
videoPlayerController: _videoPlayerController,
|
||||
autoInitialize: false,
|
||||
aspectRatio: _videoPlayerController.value.aspectRatio,
|
||||
);
|
||||
_videoPlayerController.addListener(() {
|
||||
VoidCallback errorListener;
|
||||
errorListener = () {
|
||||
if (_videoPlayerController.value.hasError) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
Navigator.pop(context);
|
||||
launchURL(context, widget.attachment.titleLink);
|
||||
});
|
||||
Navigator.pop(context);
|
||||
launchURL(context, widget.attachment.titleLink);
|
||||
}
|
||||
});
|
||||
_videoPlayerController.removeListener(errorListener);
|
||||
};
|
||||
_videoPlayerController.addListener(errorListener);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_videoPlayerController.dispose();
|
||||
_chewieController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,55 +32,61 @@ class ImageAttachment extends StatelessWidget {
|
||||
size: size,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Hero(
|
||||
tag: attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
attachment.thumbUrl,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (_) {
|
||||
return FullScreenImage(
|
||||
url: attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
attachment.thumbUrl,
|
||||
);
|
||||
}));
|
||||
},
|
||||
child: CachedNetworkImage(
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
placeholder: (_, __) {
|
||||
return Container(
|
||||
width: size?.width,
|
||||
height: size?.height,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Hero(
|
||||
tag: attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
attachment.thumbUrl,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (_) {
|
||||
return FullScreenImage(
|
||||
url: attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
attachment.thumbUrl,
|
||||
);
|
||||
}));
|
||||
},
|
||||
child: CachedNetworkImage(
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
placeholder: (_, __) {
|
||||
return Container(
|
||||
width: size?.width,
|
||||
height: size?.height,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
},
|
||||
imageUrl: attachment.thumbUrl ??
|
||||
attachment.imageUrl ??
|
||||
attachment.assetUrl,
|
||||
errorWidget: (context, url, error) => AttachmentError(
|
||||
attachment: attachment,
|
||||
size: size,
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
},
|
||||
imageUrl: attachment.thumbUrl ??
|
||||
attachment.imageUrl ??
|
||||
attachment.assetUrl,
|
||||
errorWidget: (context, url, error) => AttachmentError(
|
||||
attachment: attachment,
|
||||
size: size,
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (attachment.title != null)
|
||||
Positioned.fill(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Material(
|
||||
child: AttachmentTitle(
|
||||
messageTheme: messageTheme,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (attachment.title != null)
|
||||
Positioned.fill(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Material(
|
||||
child: AttachmentTitle(
|
||||
messageTheme: messageTheme,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (attachment.titleLink != null || attachment.ogScrapeUrl != null)
|
||||
Positioned.fill(
|
||||
child: Material(
|
||||
|
||||
@@ -13,41 +13,98 @@ import 'message_text.dart';
|
||||
|
||||
typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment);
|
||||
|
||||
/// The display behaviour of a widget
|
||||
enum DisplayWidget {
|
||||
/// Hides the widget replacing its space with a spacer
|
||||
hide,
|
||||
|
||||
/// Hides the widget not replacing its space
|
||||
gone,
|
||||
|
||||
/// Shows the widget normally
|
||||
show,
|
||||
}
|
||||
|
||||
/// 
|
||||
/// 
|
||||
///
|
||||
/// It shows a message with reactions, replies and user avatar.
|
||||
///
|
||||
/// Usually you don't use this widget as it's the default message widget used by [MessageListView].
|
||||
///
|
||||
/// The widget components render the ui based on the first ancestor of type [StreamChatTheme].
|
||||
/// Modify it to change the widget appearance.
|
||||
class MessageWidget extends StatelessWidget {
|
||||
/// Function called on mention tap
|
||||
final void Function(User) onMentionTap;
|
||||
|
||||
/// The function called when tapping on replies
|
||||
final void Function(Message) onThreadTap;
|
||||
final Widget Function(BuildContext, Message) editMessageInputBuilder;
|
||||
final Widget Function(BuildContext, Message) textBuilder;
|
||||
|
||||
/// Function called on long press
|
||||
final void Function(BuildContext, Message) onMessageActions;
|
||||
|
||||
/// The message
|
||||
final Message message;
|
||||
|
||||
/// The message theme
|
||||
final MessageTheme messageTheme;
|
||||
|
||||
/// If true the widget will be mirrored
|
||||
final bool reverse;
|
||||
|
||||
/// The shape of the message text
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// The shape of an attachment
|
||||
final ShapeBorder attachmentShape;
|
||||
|
||||
/// The borderside of the message text
|
||||
final BorderSide borderSide;
|
||||
|
||||
/// The borderside of an attachment
|
||||
final BorderSide attachmentBorderSide;
|
||||
|
||||
/// The border radius of the message text
|
||||
final BorderRadiusGeometry borderRadiusGeometry;
|
||||
|
||||
/// The border radius of an attachment
|
||||
final BorderRadiusGeometry attachmentBorderRadiusGeometry;
|
||||
|
||||
/// The padding of the widget
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
/// The internal padding of the message text
|
||||
final EdgeInsetsGeometry textPadding;
|
||||
|
||||
/// The internal padding of an attachment
|
||||
final EdgeInsetsGeometry attachmentPadding;
|
||||
|
||||
/// It controls the display behaviour of the user avatar
|
||||
final DisplayWidget showUserAvatar;
|
||||
|
||||
/// It controls the display behaviour of the sending indicator
|
||||
final DisplayWidget showSendingIndicator;
|
||||
|
||||
/// If true the widget will show the reactions
|
||||
final bool showReactions;
|
||||
|
||||
/// If true the widget will show the reply indicator
|
||||
final bool showReplyIndicator;
|
||||
final bool isParent;
|
||||
|
||||
/// The function called when tapping on UserAvatar
|
||||
final void Function(User) onUserAvatarTap;
|
||||
|
||||
/// If true show the users username next to the timestamp of the message
|
||||
final bool showUsername;
|
||||
final bool showTimestamp;
|
||||
final bool showDeleteMessage;
|
||||
final bool showEditMessage;
|
||||
final Map<String, AttachmentBuilder> attachmentBuilders;
|
||||
final Map<String, String> reactionToEmoji = {
|
||||
|
||||
final Map<String, String> _reactionToEmoji = {
|
||||
'love': '❤️️',
|
||||
'haha': '😂',
|
||||
'like': '👍',
|
||||
@@ -71,13 +128,13 @@ class MessageWidget extends StatelessWidget {
|
||||
this.showUserAvatar = DisplayWidget.show,
|
||||
this.showSendingIndicator = DisplayWidget.show,
|
||||
this.showReplyIndicator = true,
|
||||
this.isParent = false,
|
||||
this.onThreadTap,
|
||||
this.showUsername = true,
|
||||
this.showTimestamp = true,
|
||||
this.showReactions = true,
|
||||
this.showDeleteMessage = true,
|
||||
this.showEditMessage = true,
|
||||
this.onUserAvatarTap,
|
||||
this.onMessageActions,
|
||||
this.editMessageInputBuilder,
|
||||
this.textBuilder,
|
||||
@@ -338,7 +395,7 @@ class MessageWidget extends StatelessWidget {
|
||||
Text _buildReactionsText(BuildContext context) {
|
||||
return Text(
|
||||
message.reactionCounts.keys.map((reactionType) {
|
||||
return reactionToEmoji[reactionType] ?? '?';
|
||||
return _reactionToEmoji[reactionType] ?? '?';
|
||||
}).join(' ') +
|
||||
' ${message.reactionCounts.values.fold(0, (t, v) => v + t).toString()}',
|
||||
style: TextStyle(
|
||||
@@ -499,6 +556,7 @@ class MessageWidget extends StatelessWidget {
|
||||
Offset(0, messageTheme.avatarTheme.constraints.maxHeight / 2),
|
||||
child: UserAvatar(
|
||||
user: message.user,
|
||||
onTap: onUserAvatarTap,
|
||||
constraints: messageTheme.avatarTheme.constraints,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -24,7 +24,16 @@ class StreamChatTheme extends InheritedWidget {
|
||||
|
||||
/// Use this method to get the current [StreamChatThemeData] instance
|
||||
static StreamChatThemeData of(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<StreamChatTheme>().data;
|
||||
final streamChatTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<StreamChatTheme>();
|
||||
|
||||
if (streamChatTheme == null) {
|
||||
throw Exception(
|
||||
'You must have a StreamChatTheme widget at the top of your widget tree',
|
||||
);
|
||||
}
|
||||
|
||||
return streamChatTheme.data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class _VideoAttachmentState extends State<VideoAttachment> {
|
||||
}
|
||||
_chewieController = ChewieController(
|
||||
videoPlayerController: _videoPlayerController,
|
||||
autoInitialize: false,
|
||||
autoInitialize: true,
|
||||
showControls: false,
|
||||
aspectRatio: _videoPlayerController.value.aspectRatio,
|
||||
errorBuilder: (_, e) {
|
||||
@@ -137,8 +137,8 @@ class _VideoAttachmentState extends State<VideoAttachment> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_videoPlayerController = VideoPlayerController.network(
|
||||
widget.attachment.localUri ?? widget.attachment.assetUrl);
|
||||
_videoPlayerController =
|
||||
VideoPlayerController.network(widget.attachment.assetUrl);
|
||||
_videoPlayerController.initialize().whenComplete(() {
|
||||
setState(() {
|
||||
initialized = true;
|
||||
|
||||
@@ -9,6 +9,7 @@ export 'src/channels_bloc.dart';
|
||||
export 'src/date_divider.dart';
|
||||
export 'src/deleted_message.dart';
|
||||
export 'src/file_attachment.dart';
|
||||
export 'src/full_screen_video.dart';
|
||||
export 'src/giphy_attachment.dart';
|
||||
export 'src/image_attachment.dart';
|
||||
export 'src/message_input.dart';
|
||||
|
||||
+2
-2
@@ -15,10 +15,10 @@ dependencies:
|
||||
flutter_portal: ^0.1.0
|
||||
cached_network_image: ^2.2.0+1
|
||||
flutter_markdown: ^0.3.5
|
||||
url_launcher: ^5.4.5
|
||||
url_launcher: ^5.4.7
|
||||
video_player: ^0.10.10
|
||||
chewie: ^0.9.10
|
||||
file_picker: ^1.8.0+2
|
||||
file_picker: ^1.9.0+1
|
||||
image_picker: ^0.6.6+1
|
||||
flutter_keyboard_visibility: ^2.0.0
|
||||
stream_chat:
|
||||
|
||||
Reference in New Issue
Block a user