diff --git a/packages/stream_chat_flutter/lib/src/info_tile.dart b/packages/stream_chat_flutter/lib/src/info_tile.dart index 53a9755f..81a701c0 100644 --- a/packages/stream_chat_flutter/lib/src/info_tile.dart +++ b/packages/stream_chat_flutter/lib/src/info_tile.dart @@ -2,16 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +/// Tile to display a message, used in stream chat to display connection status class InfoTile extends StatelessWidget { - final String message; - final Widget child; - final bool showMessage; - final Alignment? tileAnchor; - final Alignment? childAnchor; - final TextStyle? textStyle; - final Color? backgroundColor; - + /// Constructor for creating an [InfoTile] widget const InfoTile({ + Key? key, required this.message, required this.child, required this.showMessage, @@ -19,31 +14,50 @@ class InfoTile extends StatelessWidget { this.childAnchor, this.textStyle, this.backgroundColor, - }); + }) : super(key: key); + + /// String to display + final String message; + + /// Widget to display over + final Widget child; + + /// Flag to show message + final bool showMessage; + + /// Anchor for tile - [portalAnchor] for [PortalEntry] + final Alignment? tileAnchor; + + /// Alignment for child - [childAnchor] for [PortalEntry] + final Alignment? childAnchor; + + /// [TextStyle] for message + final TextStyle? textStyle; + + /// Background color for tile + final Color? backgroundColor; @override - Widget build(BuildContext context) { - return PortalEntry( - visible: showMessage, - portalAnchor: tileAnchor ?? Alignment.topCenter, - childAnchor: childAnchor ?? Alignment.bottomCenter, - portal: Container( - height: 25, - color: backgroundColor ?? - StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), - child: Center( - child: Text( - message, - style: textStyle ?? - StreamChatTheme.of(context).textTheme.body.copyWith( - color: Colors.white, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, + Widget build(BuildContext context) => PortalEntry( + visible: showMessage, + portalAnchor: tileAnchor ?? Alignment.topCenter, + childAnchor: childAnchor ?? Alignment.bottomCenter, + portal: Container( + height: 25, + color: backgroundColor ?? + StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), + child: Center( + child: Text( + message, + style: textStyle ?? + StreamChatTheme.of(context).textTheme.body.copyWith( + color: Colors.white, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), ), ), - ), - child: child, - ); - } + child: child, + ); } diff --git a/packages/stream_chat_flutter/lib/src/media_list_view.dart b/packages/stream_chat_flutter/lib/src/media_list_view.dart index a34dc8dd..e0d0c27e 100644 --- a/packages/stream_chat_flutter/lib/src/media_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/media_list_view.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; - -import '../stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; extension on Duration { String format() { @@ -19,16 +18,21 @@ extension on Duration { } } +/// Constructs a list of media class MediaListView extends StatefulWidget { - final List selectedIds; - final void Function(AssetEntity media)? onSelect; - + /// Constructor for creating a [MediaListView] widget const MediaListView({ Key? key, this.selectedIds = const [], this.onSelect, }) : super(key: key); + /// Stores the media selected + final List selectedIds; + + /// Callback for on media selected + final void Function(AssetEntity media)? onSelect; + @override _MediaListViewState createState() => _MediaListViewState(); } @@ -39,103 +43,103 @@ class _MediaListViewState extends State { int _currentPage = 0; @override - Widget build(BuildContext context) { - return LazyLoadScrollView( - onEndOfPage: () async => _getMedia(), - child: GridView.builder( - itemCount: _media.length, - controller: _scrollController, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - ), - itemBuilder: ( - context, - position, - ) { - final media = _media.elementAt(position); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1), - child: InkWell( - onTap: () { - if (widget.onSelect != null) { - widget.onSelect!(media); - } - }, - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1, - child: FadeInImage( - fadeInDuration: Duration(milliseconds: 300), - placeholder: AssetImage( - 'images/placeholder.png', - package: 'stream_chat_flutter', + Widget build(BuildContext context) => LazyLoadScrollView( + onEndOfPage: () async => _getMedia(), + child: GridView.builder( + itemCount: _media.length, + controller: _scrollController, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + ), + itemBuilder: ( + context, + position, + ) { + final media = _media.elementAt(position); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1), + child: InkWell( + onTap: () { + if (widget.onSelect != null) { + widget.onSelect!(media); + } + }, + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1, + child: FadeInImage( + fadeInDuration: const Duration(milliseconds: 300), + placeholder: const AssetImage( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ), + image: MediaThumbnailProvider( + media: media, + ), + fit: BoxFit.cover, ), - image: MediaThumbnailProvider( - media: media, - ), - fit: BoxFit.cover, ), - ), - Positioned.fill( - child: IgnorePointer( - child: AnimatedOpacity( - duration: Duration(milliseconds: 300), - opacity: widget.selectedIds.any((id) => id == media.id) - ? 1.0 - : 0.0, - child: Container( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - alignment: Alignment.topRight, - padding: const EdgeInsets.only( - top: 8, - right: 8, - ), - child: CircleAvatar( - radius: 12, - backgroundColor: - StreamChatTheme.of(context).colorTheme.white, - child: StreamSvgIcon.check( - size: 24, - color: - StreamChatTheme.of(context).colorTheme.black, + Positioned.fill( + child: IgnorePointer( + child: AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: + widget.selectedIds.any((id) => id == media.id) + ? 1.0 + : 0.0, + child: Container( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + alignment: Alignment.topRight, + padding: const EdgeInsets.only( + top: 8, + right: 8, + ), + child: CircleAvatar( + radius: 12, + backgroundColor: + StreamChatTheme.of(context).colorTheme.white, + child: StreamSvgIcon.check( + size: 24, + color: StreamChatTheme.of(context) + .colorTheme + .black, + ), ), ), ), ), ), - ), - if (media.type == AssetType.video) ...[ - Positioned( - left: 8, - bottom: 10, - child: SvgPicture.asset( - 'svgs/video_call_icon.svg', - package: 'stream_chat_flutter', - ), - ), - Positioned( - right: 4, - bottom: 10, - child: Text( - media.videoDuration.format(), - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.white, + if (media.type == AssetType.video) ...[ + Positioned( + left: 8, + bottom: 10, + child: SvgPicture.asset( + 'svgs/video_call_icon.svg', + package: 'stream_chat_flutter', ), ), - ), - ] - ], + Positioned( + right: 4, + bottom: 10, + child: Text( + media.videoDuration.format(), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.white, + ), + ), + ), + ] + ], + ), ), - ), - ); - }, - ), - ); - } + ); + }, + ), + ); @override void initState() { @@ -165,36 +169,38 @@ class _MediaListViewState extends State { } } +/// ImageProvider implementation class MediaThumbnailProvider extends ImageProvider { + /// Constructor for creating a [MediaThumbnailProvider] const MediaThumbnailProvider({ required this.media, }); + /// Media to load final AssetEntity media; @override - ImageStreamCompleter load(key, decode) { - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decode), - scale: 1, - informationCollector: () sync* { - yield ErrorDescription('Id: ${media.id}'); - }, - ); - } + ImageStreamCompleter load( + MediaThumbnailProvider key, DecoderCallback decode) => + MultiFrameImageStreamCompleter( + codec: _loadAsync(key, decode), + scale: 1, + informationCollector: () sync* { + yield ErrorDescription('Id: ${media.id}'); + }, + ); Future _loadAsync( MediaThumbnailProvider key, DecoderCallback decode) async { - assert(key == this); + assert(key == this, 'Checks MediaThumbnailProvider'); final bytes = await media.thumbData; - return await decode(bytes!); + return decode(bytes!); } @override - Future obtainKey(ImageConfiguration configuration) { - return SynchronousFuture(this); - } + Future obtainKey(ImageConfiguration configuration) => + SynchronousFuture(this); @override bool operator ==(dynamic other) { diff --git a/packages/stream_chat_flutter/lib/src/mention_tile.dart b/packages/stream_chat_flutter/lib/src/mention_tile.dart index 186e1f16..e8859946 100644 --- a/packages/stream_chat_flutter/lib/src/mention_tile.dart +++ b/packages/stream_chat_flutter/lib/src/mention_tile.dart @@ -3,8 +3,19 @@ import 'package:flutter/material.dart'; import '../stream_chat_flutter.dart'; /// This widget is used for showing user tiles for mentions -/// Use [title], [subtitle], [leading], [trailing] for substituting widgets in respective positions +/// Use [title], [subtitle], [leading], [trailing] for +/// substituting widgets in respective positions class MentionTile extends StatelessWidget { + /// Constructor for creating a [MentionTile] widget + const MentionTile( + this.member, { + Key? key, + this.title, + this.subtitle, + this.leading, + this.trailing, + }) : super(key: key); + /// Member to display in the tile final Member member; @@ -20,82 +31,72 @@ class MentionTile extends StatelessWidget { /// Widget at the end of tile final Widget? trailing; - const MentionTile( - this.member, { - this.title, - this.subtitle, - this.leading, - this.trailing, - }); - @override - Widget build(BuildContext context) { - return Container( - height: 56, - child: Row( - children: [ - SizedBox( - width: 16, - ), - leading ?? - UserAvatar( - constraints: BoxConstraints.tight( - Size( - 40, - 40, + Widget build(BuildContext context) => SizedBox( + height: 56, + child: Row( + children: [ + const SizedBox( + width: 16, + ), + leading ?? + UserAvatar( + constraints: BoxConstraints.tight( + const Size( + 40, + 40, + ), ), + user: member.user!, + ), + const SizedBox( + width: 8, + ), + Expanded( + child: Align( + alignment: Alignment.centerLeft, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title ?? + Text( + member.user!.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: StreamChatTheme.of(context).textTheme.bodyBold, + ), + const SizedBox( + height: 2, + ), + subtitle ?? + Text( + '@${member.userId}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: StreamChatTheme.of(context) + .textTheme + .footnoteBold + .copyWith( + color: + StreamChatTheme.of(context).colorTheme.grey, + ), + ), + ], ), - user: member.user!, - ), - SizedBox( - width: 8, - ), - Expanded( - child: Align( - alignment: Alignment.centerLeft, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - title ?? - Text( - member.user!.name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context).textTheme.bodyBold, - ), - SizedBox( - height: 2, - ), - subtitle ?? - Text( - '@${member.userId}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context) - .textTheme - .footnoteBold - .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ], ), ), - ), - trailing ?? - Padding( - padding: const EdgeInsets.only( - right: 18, - left: 8, + trailing ?? + Padding( + padding: const EdgeInsets.only( + right: 18, + left: 8, + ), + child: StreamSvgIcon.mentions( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ), ), - child: StreamSvgIcon.mentions( - color: StreamChatTheme.of(context).colorTheme.accentBlue, - ), - ), - ], - ), - ); - } + ], + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/message_action.dart b/packages/stream_chat_flutter/lib/src/message_action.dart index 6d4bd93c..49a57b1e 100644 --- a/packages/stream_chat_flutter/lib/src/message_action.dart +++ b/packages/stream_chat_flutter/lib/src/message_action.dart @@ -3,6 +3,13 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Class describing a message action class MessageAction { + /// returns a new instance of a [MessageAction] + MessageAction({ + this.leading, + this.title, + this.onTap, + }); + /// leading widget final Widget? leading; @@ -11,11 +18,4 @@ class MessageAction { /// callback called on tap final OnMessageTap? onTap; - - /// returns a new instance of a [MessageAction] - MessageAction({ - this.leading, - this.title, - this.onTap, - }); }