From bd36e3039e653dc35f84a7922ea1c257ff333121 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Fri, 17 Jan 2020 11:08:12 +0100 Subject: [PATCH] Implement mediaplayer and content viewer --- lib/components/avatar.dart | 37 +++++++----- lib/components/content_banner.dart | 52 +++++++++------- lib/components/list_items/message.dart | 21 +++++-- lib/components/message_content.dart | 83 ++++++++++++++++++++++++-- lib/views/content_web_view.dart | 35 +++++++++++ 5 files changed, 183 insertions(+), 45 deletions(-) create mode 100644 lib/views/content_web_view.dart diff --git a/lib/components/avatar.dart b/lib/components/avatar.dart index 3ae49cdf..6da65799 100644 --- a/lib/components/avatar.dart +++ b/lib/components/avatar.dart @@ -8,8 +8,10 @@ import 'matrix.dart'; class Avatar extends StatelessWidget { final MxContent mxContent; final double size; + final Function onTap; - const Avatar(this.mxContent, {this.size = 40, Key key}) : super(key: key); + const Avatar(this.mxContent, {this.size = 40, this.onTap, Key key}) + : super(key: key); @override Widget build(BuildContext context) { @@ -19,21 +21,24 @@ class Avatar extends StatelessWidget { height: size * MediaQuery.of(context).devicePixelRatio, method: ThumbnailMethod.scale, ); - return CircleAvatar( - radius: size / 2, - backgroundImage: mxContent.mxc?.isNotEmpty ?? false - ? kIsWeb - ? NetworkImage( - src, - ) - : CachedNetworkImageProvider( - src, - ) - : null, - backgroundColor: Theme.of(context).secondaryHeaderColor, - child: mxContent.mxc.isEmpty - ? Text("@", style: TextStyle(color: Colors.blueGrey)) - : null, + return InkWell( + onTap: onTap, + child: CircleAvatar( + radius: size / 2, + backgroundImage: mxContent.mxc?.isNotEmpty ?? false + ? kIsWeb + ? NetworkImage( + src, + ) + : CachedNetworkImageProvider( + src, + ) + : null, + backgroundColor: Theme.of(context).secondaryHeaderColor, + child: mxContent.mxc.isEmpty + ? Text("@", style: TextStyle(color: Colors.blueGrey)) + : null, + ), ); } } diff --git a/lib/components/content_banner.dart b/lib/components/content_banner.dart index 2ee86eb4..596736e5 100644 --- a/lib/components/content_banner.dart +++ b/lib/components/content_banner.dart @@ -1,5 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/utils/app_route.dart'; +import 'package:fluffychat/views/content_web_view.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -29,27 +31,35 @@ class ContentBanner extends StatelessWidget { height: bannerSize, method: ThumbnailMethod.scale, ); - return Container( - height: 200, - color: Theme.of(context).secondaryHeaderColor, - child: !loading - ? mxContent.mxc?.isNotEmpty ?? false - ? kIsWeb - ? Image.network( - src, - height: 200, - fit: BoxFit.cover, - ) - : CachedNetworkImage( - imageUrl: src, - height: 200, - fit: BoxFit.cover, - placeholder: (c, s) => - Center(child: CircularProgressIndicator()), - errorWidget: (c, s, o) => Icon(Icons.error, size: 200), - ) - : Icon(defaultIcon, size: 200) - : Icon(defaultIcon, size: 200), + return InkWell( + onTap: () => Navigator.of(context).push( + AppRoute.defaultRoute( + context, + ContentWebView(mxContent), + ), + ), + child: Container( + height: 200, + color: Theme.of(context).secondaryHeaderColor, + child: !loading + ? mxContent.mxc?.isNotEmpty ?? false + ? kIsWeb + ? Image.network( + src, + height: 200, + fit: BoxFit.cover, + ) + : CachedNetworkImage( + imageUrl: src, + height: 200, + fit: BoxFit.cover, + placeholder: (c, s) => + Center(child: CircularProgressIndicator()), + errorWidget: (c, s, o) => Icon(Icons.error, size: 200), + ) + : Icon(defaultIcon, size: 200) + : Icon(defaultIcon, size: 200), + ), ); } } diff --git a/lib/components/list_items/message.dart b/lib/components/list_items/message.dart index a07cb398..9ff10bdf 100644 --- a/lib/components/list_items/message.dart +++ b/lib/components/list_items/message.dart @@ -2,7 +2,9 @@ import 'package:bubble/bubble.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/dialogs/redact_message_dialog.dart'; import 'package:fluffychat/components/message_content.dart'; +import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/utils/date_time_extension.dart'; +import 'package:fluffychat/views/content_web_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -26,8 +28,10 @@ class Message extends StatelessWidget { final bool ownMessage = event.senderId == client.userID; Alignment alignment = ownMessage ? Alignment.topRight : Alignment.topLeft; Color color = Theme.of(context).secondaryHeaderColor; - final bool sameSender = - nextEvent != null ? nextEvent.sender.id == event.sender.id : false; + final bool sameSender = nextEvent != null && + [EventTypes.Message, EventTypes.Sticker].contains(nextEvent.type) + ? nextEvent.sender.id == event.sender.id + : false; BubbleNip nip = sameSender ? BubbleNip.no : ownMessage ? BubbleNip.rightBottom : BubbleNip.leftBottom; @@ -151,8 +155,17 @@ class Message extends StatelessWidget { ), ), ]; - final Widget avatarOrSizedBox = - sameSender ? SizedBox(width: 40) : Avatar(event.sender.avatarUrl); + final Widget avatarOrSizedBox = sameSender + ? SizedBox(width: 40) + : Avatar( + event.sender.avatarUrl, + onTap: () => Navigator.of(context).push( + AppRoute.defaultRoute( + context, + ContentWebView(event.sender.avatarUrl), + ), + ), + ); if (ownMessage) { rowChildren.add(avatarOrSizedBox); } else { diff --git a/lib/components/message_content.dart b/lib/components/message_content.dart index 5facb509..7831584c 100644 --- a/lib/components/message_content.dart +++ b/lib/components/message_content.dart @@ -1,6 +1,8 @@ import 'package:bubble/bubble.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/utils/app_route.dart'; +import 'package:fluffychat/views/content_web_view.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:link_text/link_text.dart'; @@ -58,9 +60,11 @@ class MessageContent extends StatelessWidget { radius: Radius.circular(10), elevation: 0, child: InkWell( - onTap: () => launch( - MxContent(event.content["url"]) - .getDownloadLink(Matrix.of(context).client), + onTap: () => Navigator.of(context).push( + AppRoute.defaultRoute( + context, + ContentWebView(MxContent(event.content["url"])), + ), ), child: kIsWeb ? Image.network( @@ -74,8 +78,78 @@ class MessageContent extends StatelessWidget { ), ); case MessageTypes.Audio: - case MessageTypes.File: + if (textOnly) { + return Text( + "${event.sender.calcDisplayname()} sent an audio message", + maxLines: maxLines, + style: TextStyle( + color: textColor, + decoration: + event.redacted ? TextDecoration.lineThrough : null, + ), + ); + } + return Container( + width: 200, + child: RaisedButton( + color: Colors.blueGrey, + child: Row( + children: [ + Icon(Icons.play_arrow, color: Colors.white), + Text( + "Play ${event.body}", + overflow: TextOverflow.fade, + softWrap: false, + maxLines: 1, + style: TextStyle(color: Colors.white), + ), + ], + ), + onPressed: () => Navigator.of(context).push( + AppRoute.defaultRoute( + context, + ContentWebView(MxContent(event.content["url"])), + ), + ), + ), + ); case MessageTypes.Video: + if (textOnly) { + return Text( + "${event.sender.calcDisplayname()} sent a video message", + maxLines: maxLines, + style: TextStyle( + color: textColor, + decoration: + event.redacted ? TextDecoration.lineThrough : null, + ), + ); + } + return Container( + width: 200, + child: RaisedButton( + color: Colors.blueGrey, + child: Row( + children: [ + Icon(Icons.play_arrow, color: Colors.white), + Text( + "Play ${event.body}", + overflow: TextOverflow.fade, + softWrap: false, + maxLines: 1, + style: TextStyle(color: Colors.white), + ), + ], + ), + onPressed: () => Navigator.of(context).push( + AppRoute.defaultRoute( + context, + ContentWebView(MxContent(event.content["url"])), + ), + ), + ), + ); + case MessageTypes.File: if (textOnly) { return Text( "${event.sender.calcDisplayname()} sent a file", @@ -96,6 +170,7 @@ class MessageContent extends StatelessWidget { overflow: TextOverflow.fade, softWrap: false, maxLines: 1, + style: TextStyle(color: Colors.white), ), onPressed: () => launch( MxContent(event.content["url"]) diff --git a/lib/views/content_web_view.dart b/lib/views/content_web_view.dart new file mode 100644 index 00000000..d5f423cd --- /dev/null +++ b/lib/views/content_web_view.dart @@ -0,0 +1,35 @@ +import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/components/matrix.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class ContentWebView extends StatelessWidget { + final MxContent content; + + const ContentWebView(this.content); + + @override + Widget build(BuildContext context) { + final String url = content.getDownloadLink(Matrix.of(context).client); + print(url); + return Scaffold( + appBar: AppBar( + title: Text( + "Content viewer", + ), + actions: [ + IconButton( + icon: Icon( + Icons.file_download, + ), + onPressed: () => launch(url), + ), + ], + ), + body: WebView( + initialUrl: url, + ), + ); + } +}