lint changes mlv

This commit is contained in:
Deven Joshi
2021-05-05 15:53:08 +05:30
parent bda64e8764
commit 160baa5d95
@@ -12,34 +12,60 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/system_message.dart'; import 'package:stream_chat_flutter/src/system_message.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:visibility_detector/visibility_detector.dart'; import 'package:visibility_detector/visibility_detector.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/swipeable.dart';
import '../stream_chat_flutter.dart'; /// Widget builder for message
import 'connection_status_builder.dart';
import 'date_divider.dart';
import 'extension.dart';
import 'swipeable.dart';
typedef MessageBuilder = Widget Function( typedef MessageBuilder = Widget Function(
BuildContext, BuildContext,
MessageDetails, MessageDetails,
List<Message>, List<Message>,
); );
/// Widget builder for parent message
typedef ParentMessageBuilder = Widget Function( typedef ParentMessageBuilder = Widget Function(
BuildContext, BuildContext,
Message?, Message?,
); );
/// Widget builder for system message
typedef SystemMessageBuilder = Widget Function( typedef SystemMessageBuilder = Widget Function(
BuildContext, BuildContext,
Message, Message,
); );
/// Widget builder for thread
typedef ThreadBuilder = Widget Function(BuildContext context, Message? parent); typedef ThreadBuilder = Widget Function(BuildContext context, Message? parent);
/// Callback for thread taps
typedef ThreadTapCallback = void Function(Message, Widget?); typedef ThreadTapCallback = void Function(Message, Widget?);
/// Callback on message swiped
typedef OnMessageSwiped = void Function(Message); typedef OnMessageSwiped = void Function(Message);
/// Callback on message tapped
typedef OnMessageTap = void Function(Message); typedef OnMessageTap = void Function(Message);
/// Callback on reply tapped
typedef ReplyTapCallback = void Function(Message); typedef ReplyTapCallback = void Function(Message);
/// Class for message details
class MessageDetails { class MessageDetails {
/// Constructor for creating [MessageDetails]
MessageDetails(
BuildContext context,
this.message,
List<Message> messages,
this.index,
) {
isMyMessage = message.user?.id == StreamChat.of(context).user?.id;
isLastUser = index + 1 < messages.length &&
message.user?.id == messages[index + 1].user?.id;
isNextUser =
index - 1 >= 0 && message.user!.id == messages[index - 1].user?.id;
}
/// True if the message belongs to the current user /// True if the message belongs to the current user
bool? isMyMessage; bool? isMyMessage;
@@ -54,19 +80,6 @@ class MessageDetails {
/// The index of the message /// The index of the message
int index; int index;
MessageDetails(
BuildContext context,
this.message,
List<Message> messages,
this.index,
) {
isMyMessage = message.user?.id == StreamChat.of(context).user?.id;
isLastUser = index + 1 < messages.length &&
message.user?.id == messages[index + 1].user?.id;
isNextUser =
index - 1 >= 0 && message.user!.id == messages[index - 1].user?.id;
}
} }
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png)
@@ -104,10 +117,12 @@ class MessageDetails {
/// ``` /// ```
/// ///
/// ///
/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channels. /// Make sure to have a [StreamChannel] ancestor in order to
/// provide the information about the channels.
/// The widget uses a [ListView.custom] to render the list of channels. /// The widget uses a [ListView.custom] to render the list of channels.
/// ///
/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// The widget components render the ui based on the first
/// ancestor of type [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class MessageListView extends StatefulWidget { class MessageListView extends StatefulWidget {
/// Instantiate a new MessageListView /// Instantiate a new MessageListView
@@ -158,10 +173,12 @@ class MessageListView extends StatefulWidget {
final ThreadBuilder? threadBuilder; final ThreadBuilder? threadBuilder;
/// Function called when tapping on a thread /// Function called when tapping on a thread
/// By default it calls [Navigator.push] using the widget built using [threadBuilder] /// By default it calls [Navigator.push] using the widget
/// built using [threadBuilder]
final ThreadTapCallback? onThreadTap; final ThreadTapCallback? onThreadTap;
/// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero /// If true will show a scroll to bottom message when there are new
/// messages and the scroll offset is not zero
final bool showScrollToBottom; final bool showScrollToBottom;
/// Parent message in case of a thread /// Parent message in case of a thread
@@ -201,8 +218,10 @@ class MessageListView extends StatefulWidget {
/// Color used while highlighting initial message /// Color used while highlighting initial message
final Color? messageHighlightColor; final Color? messageHighlightColor;
/// Callback when show message is tapped
final ShowMessageCallback? onShowMessage; final ShowMessageCallback? onShowMessage;
/// Flag for showing tile on header
final bool showConnectionStateTile; final bool showConnectionStateTile;
/// Function called when messages are fetched /// Function called when messages are fetched
@@ -214,8 +233,10 @@ class MessageListView extends StatefulWidget {
/// Function used to build an empty widget /// Function used to build an empty widget
final WidgetBuilder? emptyBuilder; final WidgetBuilder? emptyBuilder;
/// Callback triggered when an error occurs while performing the given request. /// Callback triggered when an error occurs while performing the
/// This parameter can be used to display an error message to users in the event /// given request.
/// This parameter can be used to display an error message to
/// users in the event
/// of a connection failure. /// of a connection failure.
final ErrorBuilder? errorWidgetBuilder; final ErrorBuilder? errorWidgetBuilder;
@@ -223,10 +244,12 @@ class MessageListView extends StatefulWidget {
final bool Function(Message)? messageFilter; final bool Function(Message)? messageFilter;
/// Attachment builders for the default message widget /// Attachment builders for the default message widget
/// Please change this in the [MessageWidget] if you are using a custom implementation /// Please change this in the [MessageWidget] if you are using a
/// custom implementation
final Map<String, AttachmentBuilder>? customAttachmentBuilders; final Map<String, AttachmentBuilder>? customAttachmentBuilders;
/// Called when any message is tapped except a system message (use [onSystemMessageTap] instead) /// Called when any message is tapped except a system message
/// (use [onSystemMessageTap] instead)
final OnMessageTap? onMessageTap; final OnMessageTap? onMessageTap;
/// Called when system message is tapped /// Called when system message is tapped
@@ -238,6 +261,7 @@ class MessageListView extends StatefulWidget {
/// Customize the MessageWidget textBuilder /// Customize the MessageWidget textBuilder
final void Function(BuildContext context, Message message)? textBuilder; final void Function(BuildContext context, Message message)? textBuilder;
/// Callback for when link is tapped
final void Function(String link)? onLinkTap; final void Function(String link)? onLinkTap;
@override @override
@@ -257,9 +281,8 @@ class _MessageListViewState extends State<MessageListView> {
if (streamChannel!.initialMessageId != null) { if (streamChannel!.initialMessageId != null) {
final messages = streamChannel!.channel.state!.messages; final messages = streamChannel!.channel.state!.messages;
final totalMessages = messages.length; final totalMessages = messages.length;
final messageIndex = messages.indexWhere((e) { final messageIndex =
return e.id == streamChannel!.initialMessageId; messages.indexWhere((e) => e.id == streamChannel!.initialMessageId);
});
final index = totalMessages - messageIndex; final index = totalMessages - messageIndex;
if (index != 0) return index - 1; if (index != 0) return index - 1;
return index; return index;
@@ -272,9 +295,7 @@ class _MessageListViewState extends State<MessageListView> {
return 0; return 0;
} }
bool _isInitialMessage(String id) { bool _isInitialMessage(String id) => streamChannel!.initialMessageId == id;
return streamChannel!.initialMessageId == id;
}
bool get _upToDate => streamChannel!.channel.state!.isUpToDate; bool get _upToDate => streamChannel!.channel.state!.isUpToDate;
@@ -295,50 +316,46 @@ class _MessageListViewState extends State<MessageListView> {
final MessageListController _messageListController = MessageListController(); final MessageListController _messageListController = MessageListController();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => MessageListCore(
return MessageListCore(
messageFilter: widget.messageFilter, messageFilter: widget.messageFilter,
loadingBuilder: widget.loadingBuilder ?? loadingBuilder: widget.loadingBuilder ??
(context) { (context) => const Center(
return Center( child: CircularProgressIndicator(),
child: const CircularProgressIndicator(), ),
);
},
emptyBuilder: widget.emptyBuilder ?? emptyBuilder: widget.emptyBuilder ??
(context) { (context) => Center(
return Center(
child: Text( child: Text(
'No chats here yet...', 'No chats here yet...',
style: StreamChatTheme.of(context).textTheme.footnote.copyWith( style: StreamChatTheme.of(context)
.textTheme
.footnote
.copyWith(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
.black .black
.withOpacity(.5)), .withOpacity(.5)),
), ),
); ),
},
messageListBuilder: widget.messageListBuilder ?? messageListBuilder: widget.messageListBuilder ??
(context, list) { (context, list) => _buildListView(list),
return _buildListView(list);
},
messageListController: _messageListController, messageListController: _messageListController,
parentMessage: widget.parentMessage, parentMessage: widget.parentMessage,
showScrollToBottom: widget.showScrollToBottom, showScrollToBottom: widget.showScrollToBottom,
errorWidgetBuilder: widget.errorWidgetBuilder ?? errorWidgetBuilder: widget.errorWidgetBuilder ??
(BuildContext context, Object error) { (BuildContext context, Object error) => Center(
return Center(
child: Text( child: Text(
'Something went wrong', 'Something went wrong',
style: StreamChatTheme.of(context).textTheme.footnote.copyWith( style: StreamChatTheme.of(context)
.textTheme
.footnote
.copyWith(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
.black .black
.withOpacity(.5)), .withOpacity(.5)),
), ),
),
); );
},
);
}
Widget _buildListView(List<Message> data) { Widget _buildListView(List<Message> data) {
messages = data; messages = data;
@@ -384,6 +401,7 @@ class _MessageListViewState extends State<MessageListView> {
} }
return InfoTile( return InfoTile(
// ignore: avoid_bool_literals_in_conditional_expressions
showMessage: widget.showConnectionStateTile ? showStatus : false, showMessage: widget.showConnectionStateTile ? showStatus : false,
tileAnchor: Alignment.topCenter, tileAnchor: Alignment.topCenter,
childAnchor: Alignment.topCenter, childAnchor: Alignment.topCenter,
@@ -426,8 +444,8 @@ class _MessageListViewState extends State<MessageListView> {
itemCount: itemCount:
messages.length + 2 + (_isThreadConversation ? 1 : 0), messages.length + 2 + (_isThreadConversation ? 1 : 0),
separatorBuilder: (context, i) { separatorBuilder: (context, i) {
if (i == messages.length) return Offstage(); if (i == messages.length) return const Offstage();
if (i == 0) return SizedBox(height: 30); if (i == 0) return const SizedBox(height: 30);
if (i == messages.length + 1) { if (i == messages.length + 1) {
final replyCount = widget.parentMessage!.replyCount; final replyCount = widget.parentMessage!.replyCount;
return Container( return Container(
@@ -438,6 +456,7 @@ class _MessageListViewState extends State<MessageListView> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Text( child: Text(
// ignore: lines_longer_than_80_chars
'$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: StreamChatTheme.of(context) style: StreamChatTheme.of(context)
@@ -481,9 +500,9 @@ class _MessageListViewState extends State<MessageListView> {
!isNextUserSame || !isNextUserSame ||
isThread || isThread ||
isDeleted) { isDeleted) {
return SizedBox(height: 8); return const SizedBox(height: 8);
} }
return SizedBox(height: 2); return const SizedBox(height: 2);
}, },
itemBuilder: (context, i) { itemBuilder: (context, i) {
if (i == messages.length + 2) { if (i == messages.length + 2) {
@@ -559,13 +578,13 @@ class _MessageListViewState extends State<MessageListView> {
builder: (context, values, _) { builder: (context, values, _) {
final items = _itemPositionListener.itemPositions.value; final items = _itemPositionListener.itemPositions.value;
if (items.isEmpty || messages.isEmpty) { if (items.isEmpty || messages.isEmpty) {
return SizedBox(); return const SizedBox();
} }
var index = _getTopElement(values).index; var index = _getTopElement(values).index;
if (index > messages.length) { if (index > messages.length) {
return SizedBox(); return const SizedBox();
} }
if (index == messages.length) { if (index == messages.length) {
@@ -587,19 +606,15 @@ class _MessageListViewState extends State<MessageListView> {
} }
Future<void> _paginateData( Future<void> _paginateData(
StreamChannelState? channel, QueryDirection direction) { StreamChannelState? channel, QueryDirection direction) =>
return _messageListController.paginateData!(direction: direction); _messageListController.paginateData!(direction: direction);
}
ItemPosition _getTopElement(Iterable<ItemPosition> values) { ItemPosition _getTopElement(Iterable<ItemPosition> values) => values
return values
.where((ItemPosition position) => position.itemLeadingEdge < 0.9) .where((ItemPosition position) => position.itemLeadingEdge < 0.9)
.reduce((ItemPosition max, ItemPosition position) => .reduce((ItemPosition max, ItemPosition position) =>
position.itemLeadingEdge > max.itemLeadingEdge ? position : max); position.itemLeadingEdge > max.itemLeadingEdge ? position : max);
}
Widget _buildScrollToBottom() { Widget _buildScrollToBottom() => StreamBuilder<Tuple2<bool, int>>(
return StreamBuilder<Tuple2<bool, int>>(
stream: Rx.combineLatest2( stream: Rx.combineLatest2(
streamChannel!.channel.state!.isUpToDateStream, streamChannel!.channel.state!.isUpToDateStream,
streamChannel!.channel.state!.unreadCountStream, streamChannel!.channel.state!.unreadCountStream,
@@ -607,14 +622,14 @@ class _MessageListViewState extends State<MessageListView> {
), ),
builder: (_, snapshot) { builder: (_, snapshot) {
if (snapshot.hasError) { if (snapshot.hasError) {
return Offstage(); return const Offstage();
} else if (!snapshot.hasData) { } else if (!snapshot.hasData) {
return Offstage(); return const Offstage();
} }
final isUpToDate = snapshot.data!.item1; final isUpToDate = snapshot.data!.item1;
final showScrollToBottom = !isUpToDate || _showScrollToBottom; final showScrollToBottom = !isUpToDate || _showScrollToBottom;
if (!showScrollToBottom) { if (!showScrollToBottom) {
return Offstage(); return const Offstage();
} }
final unreadCount = snapshot.data!.item2; final unreadCount = snapshot.data!.item2;
final showUnreadCount = unreadCount > 0 && final showUnreadCount = unreadCount > 0 &&
@@ -642,7 +657,7 @@ class _MessageListViewState extends State<MessageListView> {
setState(() => _showScrollToBottom = false); setState(() => _showScrollToBottom = false);
_scrollController!.scrollTo( _scrollController!.scrollTo(
index: 0, index: 0,
duration: Duration(seconds: 1), duration: const Duration(seconds: 1),
curve: Curves.easeInOut, curve: Curves.easeInOut,
); );
} }
@@ -662,7 +677,7 @@ class _MessageListViewState extends State<MessageListView> {
padding: const EdgeInsets.all(3), padding: const EdgeInsets.all(3),
child: Text( child: Text(
'$unreadCount', '$unreadCount',
style: TextStyle( style: const TextStyle(
fontSize: 11, fontSize: 11,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -675,7 +690,6 @@ class _MessageListViewState extends State<MessageListView> {
); );
}, },
); );
}
Widget _buildLoadingIndicator( Widget _buildLoadingIndicator(
StreamChannelState? streamChannel, StreamChannelState? streamChannel,
@@ -685,7 +699,7 @@ class _MessageListViewState extends State<MessageListView> {
? streamChannel!.queryTopMessages ? streamChannel!.queryTopMessages
: streamChannel!.queryBottomMessages; : streamChannel!.queryBottomMessages;
return StreamBuilder<bool>( return StreamBuilder<bool>(
key: Key('LOADING-INDICATOR'), key: const Key('LOADING-INDICATOR'),
stream: stream, stream: stream,
initialData: false, initialData: false,
builder: (context, snapshot) { builder: (context, snapshot) {
@@ -695,24 +709,24 @@ class _MessageListViewState extends State<MessageListView> {
.colorTheme .colorTheme
.accentRed .accentRed
.withOpacity(.2), .withOpacity(.2),
child: Center( child: const Center(
child: Text('Error loading messages'), child: Text('Error loading messages'),
), ),
); );
} }
if (!snapshot.data!) { if (!snapshot.data!) {
if (!_isThreadConversation && direction == QueryDirection.top) { if (!_isThreadConversation && direction == QueryDirection.top) {
return Container( return const SizedBox(
height: 52, height: 52,
width: double.infinity, width: double.infinity,
); );
} }
return Offstage(); return const Offstage();
} }
return Center( return const Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: EdgeInsets.all(8),
child: const CircularProgressIndicator(), child: CircularProgressIndicator(),
), ),
); );
}, },
@@ -728,7 +742,7 @@ class _MessageListViewState extends State<MessageListView> {
Widget messageWidget; Widget messageWidget;
if (widget.messageBuilder != null) { if (widget.messageBuilder != null) {
messageWidget = Builder( messageWidget = Builder(
key: ValueKey<String>('TOP-MESSAGE'), key: const ValueKey<String>('TOP-MESSAGE'),
builder: (_) => widget.messageBuilder!( builder: (_) => widget.messageBuilder!(
context, context,
MessageDetails( MessageDetails(
@@ -810,7 +824,7 @@ class _MessageListViewState extends State<MessageListView> {
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
showSendingIndicator: false, showSendingIndicator: false,
onThreadTap: _onThreadTap as void Function(Message)?, onThreadTap: _onThreadTap as void Function(Message)?,
borderRadiusGeometry: BorderRadius.only( borderRadiusGeometry: const BorderRadius.only(
topLeft: Radius.circular(16), topLeft: Radius.circular(16),
bottomLeft: Radius.circular(2), bottomLeft: Radius.circular(2),
topRight: Radius.circular(16), topRight: Radius.circular(16),
@@ -886,8 +900,8 @@ class _MessageListViewState extends State<MessageListView> {
final channel = streamChannel!.channel; final channel = streamChannel!.channel;
final readList = channel.state?.read?.where((read) { final readList = channel.state?.read?.where((read) {
if (read.user.id == userId) return false; if (read.user.id == userId) return false;
return (read.lastRead.isAfter(message.createdAt) || return read.lastRead.isAfter(message.createdAt) ||
read.lastRead.isAtSameMomentAs(message.createdAt)); read.lastRead.isAtSameMomentAs(message.createdAt);
}).toList() ?? }).toList() ??
[]; [];
@@ -945,6 +959,7 @@ class _MessageListViewState extends State<MessageListView> {
showSendingIndicator: showSendingIndicator, showSendingIndicator: showSendingIndicator,
showUserAvatar: showUserAvatar, showUserAvatar: showUserAvatar,
onQuotedMessageTap: (quotedMessageId) async { onQuotedMessageTap: (quotedMessageId) async {
// ignore: prefer_function_declarations_over_variables
final scrollToIndex = () { final scrollToIndex = () {
final index = messages.indexWhere((m) => m.id == quotedMessageId); final index = messages.indexWhere((m) => m.id == quotedMessageId);
_scrollController?.scrollTo( _scrollController?.scrollTo(
@@ -984,14 +999,14 @@ class _MessageListViewState extends State<MessageListView> {
), ),
attachmentPadding: EdgeInsets.all(hasFileAttachment ? 4 : 2), attachmentPadding: EdgeInsets.all(hasFileAttachment ? 4 : 2),
borderRadiusGeometry: BorderRadius.only( borderRadiusGeometry: BorderRadius.only(
topLeft: Radius.circular(16), topLeft: const Radius.circular(16),
bottomLeft: Radius.circular( bottomLeft: Radius.circular(
(timeDiff >= 1 || !isNextUserSame) && !(hasReplies || isThreadMessage) (timeDiff >= 1 || !isNextUserSame) && !(hasReplies || isThreadMessage)
? 0 ? 0
: 16, : 16,
), ),
topRight: Radius.circular(16), topRight: const Radius.circular(16),
bottomRight: Radius.circular(16), bottomRight: const Radius.circular(16),
), ),
textPadding: EdgeInsets.symmetric( textPadding: EdgeInsets.symmetric(
vertical: 8, vertical: 8,
@@ -1031,7 +1046,7 @@ class _MessageListViewState extends State<MessageListView> {
!message.isEphemeral && !message.isEphemeral &&
widget.onMessageSwiped != null) { widget.onMessageSwiped != null) {
child = Container( child = Container(
decoration: BoxDecoration(), decoration: const BoxDecoration(),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: Swipeable( child: Swipeable(
onSwipeEnd: () { onSwipeEnd: () {
@@ -1059,12 +1074,10 @@ class _MessageListViewState extends State<MessageListView> {
), ),
duration: const Duration(seconds: 3), duration: const Duration(seconds: 3),
onEnd: () => initialMessageHighlightComplete = true, onEnd: () => initialMessageHighlightComplete = true,
builder: (_, color, child) { builder: (_, color, child) => Container(
return Container(
color: color, color: color,
child: child, child: child,
); ),
},
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 4), padding: const EdgeInsets.only(top: 4),
child: child, child: child,
@@ -1124,19 +1137,18 @@ class _MessageListViewState extends State<MessageListView> {
_onThreadTap = (Message message) { _onThreadTap = (Message message) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (_) { MaterialPageRoute(
return StreamBuilder<Message>( builder: (_) => StreamBuilder<Message>(
stream: streamChannel!.channel.state!.messagesStream.map( stream: streamChannel!.channel.state!.messagesStream.map(
(messages) => (messages) =>
messages!.firstWhere((m) => m.id == message.id)), messages!.firstWhere((m) => m.id == message.id)),
initialData: message, initialData: message,
builder: (_, snapshot) { builder: (_, snapshot) => StreamChannel(
return StreamChannel(
channel: streamChannel!.channel, channel: streamChannel!.channel,
child: widget.threadBuilder!(context, snapshot.data), child: widget.threadBuilder!(context, snapshot.data),
); ),
}); ),
}), ),
); );
}; };
} }