From 74fb9d8dd83441d27a715f1c7f3529b3090f3824 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 8 Apr 2021 13:22:21 +0530 Subject: [PATCH] added non-nullability for core --- .../lib/src/channel_list_core.dart | 36 +++++++-------- .../lib/src/channels_bloc.dart | 39 ++++++++-------- .../lib/src/lazy_load_scroll_view.dart | 24 +++++----- .../lib/src/message_list_core.dart | 34 +++++++------- .../lib/src/message_search_bloc.dart | 33 +++++++------- .../lib/src/message_search_list_core.dart | 36 +++++++-------- .../lib/src/stream_channel.dart | 40 ++++++++--------- .../lib/src/stream_chat_core.dart | 28 ++++++------ .../lib/src/typedef.dart | 2 +- .../lib/src/user_list_core.dart | 45 ++++++++++--------- .../lib/src/users_bloc.dart | 26 +++++------ .../stream_chat_flutter_core/pubspec.yaml | 7 +-- .../test/matchers/channel_matcher.dart | 4 +- .../get_message_response_matcher.dart | 4 +- .../test/matchers/message_matcher.dart | 4 +- .../test/matchers/users_matcher.dart | 4 +- 16 files changed, 185 insertions(+), 181 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 3adea312..70d97df7 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -57,11 +57,11 @@ import 'package:stream_chat_flutter_core/src/typedef.dart'; class ChannelListCore extends StatefulWidget { /// Instantiate a new ChannelListView const ChannelListCore({ - Key key, - @required this.errorBuilder, - @required this.emptyBuilder, - @required this.loadingBuilder, - @required this.listBuilder, + Key? key, + required this.errorBuilder, + required this.emptyBuilder, + required this.loadingBuilder, + required this.listBuilder, this.filter, this.options, this.sort, @@ -91,7 +91,7 @@ class ChannelListCore extends StatefulWidget { /// Use [ChannelListController.loadData] and /// [ChannelListController.paginateData] respectively for reloading and /// pagination. - final ChannelListController channelListController; + final ChannelListController? channelListController; /// The builder that will be used in case of error final ErrorBuilder errorBuilder; @@ -100,7 +100,7 @@ class ChannelListCore extends StatefulWidget { final WidgetBuilder loadingBuilder; /// The builder which is used when list of channels loads - final Function(BuildContext, List) listBuilder; + final Function(BuildContext, List) listBuilder; /// The builder used when the channel list is empty. final WidgetBuilder emptyBuilder; @@ -108,20 +108,20 @@ class ChannelListCore extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map filter; + final Map? filter; /// Query channels options. /// /// state: if true returns the Channel state /// watch: if true listen to changes to this Channel in real time. - final Map options; + final Map? options; /// The sorting used for the channels matching the filters. /// Sorting is based on field and direction, multiple sorting options can be /// provided. /// You can sort based on last_updated, last_message_at, updated_at, created /// _at or member_count. Direction can be ascending or descending. - final List> sort; + final List>? sort; /// Pagination parameters /// limit: the number of channels to return (max is 30) @@ -142,10 +142,10 @@ class ChannelListCoreState extends State { return _buildListView(channelsBloc); } - StreamBuilder> _buildListView( + StreamBuilder> _buildListView( ChannelsBlocState channelsBlocState, ) => - StreamBuilder>( + StreamBuilder>( stream: channelsBlocState.channelsStream, builder: (context, snapshot) { if (snapshot.hasError) { @@ -154,7 +154,7 @@ class ChannelListCoreState extends State { if (!snapshot.hasData) { return widget.loadingBuilder(context); } - final channels = snapshot.data; + final channels = snapshot.data!; if (channels.isEmpty) { return widget.emptyBuilder(context); } @@ -186,7 +186,7 @@ class ChannelListCoreState extends State { ); } - StreamSubscription _subscription; + late StreamSubscription _subscription; @override void initState() { @@ -203,8 +203,8 @@ class ChannelListCoreState extends State { .listen((event) => loadData()); if (widget.channelListController != null) { - widget.channelListController.loadData = loadData; - widget.channelListController.paginateData = paginateData; + widget.channelListController!.loadData = loadData; + widget.channelListController!.paginateData = paginateData; } } @@ -233,10 +233,10 @@ class ChannelListCoreState extends State { class ChannelListController { /// This function calls Stream's servers to load a list of channels. /// If there is existing data, calling this function causes a reload. - AsyncCallback loadData; + AsyncCallback? loadData; /// This function is used to load another page of data. Note, [loadData] /// should be used to populate the initial page of data. Calling /// [paginateData] performs a query to load subsequent pages. - AsyncCallback paginateData; + AsyncCallback? paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index 2b4968eb..2e42c0af 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -20,8 +20,8 @@ class ChannelsBloc extends StatefulWidget { /// Creates a new [ChannelsBloc]. The parameter [child] must be supplied and /// not null. const ChannelsBloc({ - Key key, - @required this.child, + Key? key, + required this.child, this.lockChannelsOrder = false, this.channelsComparator, this.shouldAddChannel, @@ -36,18 +36,18 @@ class ChannelsBloc extends StatefulWidget { final bool lockChannelsOrder; /// Comparator used to sort the channels when a message.new event is received - final Comparator channelsComparator; + final Comparator? channelsComparator; /// Function used to evaluate if a channel should be added to the list when a /// message.new event is received - final bool Function(Event) shouldAddChannel; + final bool Function(Event)? shouldAddChannel; @override ChannelsBlocState createState() => ChannelsBlocState(); /// Use this method to get the current [ChannelsBlocState] instance static ChannelsBlocState of(BuildContext context) { - ChannelsBlocState streamChatState; + ChannelsBlocState? streamChatState; streamChatState = context.findAncestorStateOfType(); @@ -69,14 +69,15 @@ class ChannelsBlocState extends State } /// The current channel list - List get channels => _channelsController.value; + List? get channels => _channelsController.value as List?; /// The current channel list as a stream - Stream> get channelsStream => _channelsController.stream; + Stream> get channelsStream => _channelsController.stream; final _queryChannelsLoadingController = BehaviorSubject.seeded(false); - final _channelsController = BehaviorSubject>(); + final BehaviorSubject> _channelsController = + BehaviorSubject>(); /// The stream notifying the state of queryChannel call Stream get queryChannelsLoading => @@ -88,10 +89,10 @@ class ChannelsBlocState extends State /// Calls [client.queryChannels] updating [queryChannelsLoading] stream Future queryChannels({ - Map filter, - List> sortOptions, - PaginationParams paginationParams, - Map options, + Map? filter, + List>? sortOptions, + PaginationParams? paginationParams, + Map? options, }) async { final client = StreamChatCore.of(context).client; @@ -110,10 +111,10 @@ class ChannelsBlocState extends State final oldChannels = List.from(channels ?? []); var newChannels = []; await for (final channels in client.queryChannels( - filter: filter, - sort: sortOptions, - options: options, - paginationParams: paginationParams, + filter: filter!, + sort: sortOptions!, + options: options!, + paginationParams: paginationParams!, )) { newChannels = channels; if (clear) { @@ -123,7 +124,7 @@ class ChannelsBlocState extends State _channelsController.add(temp); } if (_channelsController.hasValue && - _queryChannelsLoadingController.value) { + _queryChannelsLoadingController.value!) { _queryChannelsLoadingController.sink.add(false); } } @@ -149,8 +150,8 @@ class ChannelsBlocState extends State if (!widget.lockChannelsOrder) { _subscriptions.add(client.on(EventType.messageNew).listen((e) { - final newChannels = List.from(channels ?? []); - final index = newChannels.indexWhere((c) => c.cid == e.cid); + final newChannels = List.from(channels ?? []); + final index = newChannels.indexWhere((c) => c!.cid == e.cid); if (index != -1) { if (index > 0) { final channel = newChannels.removeAt(index); diff --git a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart index 808c1dae..1f07c8ce 100644 --- a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart @@ -9,8 +9,8 @@ class LazyLoadScrollView extends StatefulWidget { /// Creates a new instance of [LazyLoadScrollView]. The parameter [child] /// must be supplied and not null. const LazyLoadScrollView({ - Key key, - @required this.child, + Key? key, + required this.child, this.onStartOfPage, this.onEndOfPage, this.onPageScrollStart, @@ -24,19 +24,19 @@ class LazyLoadScrollView extends StatefulWidget { final Widget child; /// Called when the [child] reaches the start of the list - final AsyncCallback onStartOfPage; + final AsyncCallback? onStartOfPage; /// Called when the [child] reaches the end of the list - final AsyncCallback onEndOfPage; + final AsyncCallback? onEndOfPage; /// Called when the list scrolling starts - final VoidCallback onPageScrollStart; + final VoidCallback? onPageScrollStart; /// Called when the list scrolling ends - final VoidCallback onPageScrollEnd; + final VoidCallback? onPageScrollEnd; /// Called every time the [child] is in-between the list - final VoidCallback onInBetweenOfPage; + final VoidCallback? onInBetweenOfPage; /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels final double scrollOffset; @@ -59,13 +59,13 @@ class _LazyLoadScrollViewState extends State { bool _onNotification(ScrollNotification notification) { if (notification is ScrollStartNotification) { if (widget.onPageScrollStart != null) { - widget.onPageScrollStart(); + widget.onPageScrollStart!(); return true; } } if (notification is ScrollEndNotification) { if (widget.onPageScrollEnd != null) { - widget.onPageScrollEnd(); + widget.onPageScrollEnd!(); return true; } } @@ -78,7 +78,7 @@ class _LazyLoadScrollViewState extends State { if (pixels > (minScrollExtent + scrollOffset) && pixels < (maxScrollExtent - scrollOffset)) { if (widget.onInBetweenOfPage != null) { - widget.onInBetweenOfPage(); + widget.onInBetweenOfPage!(); return true; } } @@ -117,7 +117,7 @@ class _LazyLoadScrollViewState extends State { if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.stable) { if (widget.onEndOfPage != null) { _loadMoreStatus = _LoadingStatus.loading; - widget.onEndOfPage().whenComplete(() { + widget.onEndOfPage!().whenComplete(() { _loadMoreStatus = _LoadingStatus.stable; }); } @@ -128,7 +128,7 @@ class _LazyLoadScrollViewState extends State { if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.stable) { if (widget.onStartOfPage != null) { _loadMoreStatus = _LoadingStatus.loading; - widget.onStartOfPage().whenComplete(() { + widget.onStartOfPage!().whenComplete(() { _loadMoreStatus = _LoadingStatus.stable; }); } diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 53844447..65209297 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -61,11 +61,11 @@ import 'package:stream_chat_flutter_core/src/typedef.dart'; class MessageListCore extends StatefulWidget { /// Instantiate a new [MessageListView]. const MessageListCore({ - Key key, - @required this.loadingBuilder, - @required this.emptyBuilder, - @required this.messageListBuilder, - @required this.errorWidgetBuilder, + Key? key, + required this.loadingBuilder, + required this.emptyBuilder, + required this.messageListBuilder, + required this.errorWidgetBuilder, this.showScrollToBottom = true, this.parentMessage, this.messageListController, @@ -84,7 +84,7 @@ class MessageListCore extends StatefulWidget { /// A [MessageListController] allows pagination. /// Use [ChannelListController.paginateData] pagination. - final MessageListController messageListController; + final MessageListController? messageListController; /// Function called when messages are fetched final Widget Function(BuildContext, List) messageListBuilder; @@ -108,10 +108,10 @@ class MessageListCore extends StatefulWidget { /// If the current message belongs to a `thread`, this property represents the /// first message or the parent of the conversation. - final Message parentMessage; + final Message? parentMessage; /// Predicate used to filter messages - final bool Function(Message) messageFilter; + final bool Function(Message)? messageFilter; @override MessageListCoreState createState() => MessageListCoreState(); @@ -119,7 +119,7 @@ class MessageListCore extends StatefulWidget { /// The current state of the [MessageListCore]. class MessageListCoreState extends State { - StreamChannelState _streamChannel; + late StreamChannelState _streamChannel; bool get _upToDate => _streamChannel.channel.state.isUpToDate; @@ -133,8 +133,8 @@ class MessageListCoreState extends State { Widget build(BuildContext context) { final messagesStream = _isThreadConversation ? _streamChannel.channel.state.threadsStream - .where((threads) => threads.containsKey(widget.parentMessage.id)) - .map((threads) => threads[widget.parentMessage.id]) + .where((threads) => threads.containsKey(widget.parentMessage!.id)) + .map((threads) => threads[widget.parentMessage!.id]) : _streamChannel.channel.state?.messagesStream; bool defaultFilter(Message m) { @@ -144,7 +144,7 @@ class MessageListCoreState extends State { return true; } - return StreamBuilder>( + return StreamBuilder?>( stream: messagesStream?.map((messages) => messages?.where(widget.messageFilter ?? defaultFilter)?.toList()), builder: (context, snapshot) { @@ -171,11 +171,11 @@ class MessageListCoreState extends State { /// /// Optionally pass the fetch direction, defaults to [QueryDirection.bottom] Future paginateData( - {QueryDirection direction = QueryDirection.bottom}) { + {QueryDirection? direction = QueryDirection.bottom}) { if (!_isThreadConversation) { return _streamChannel.queryMessages(direction: direction); } else { - return _streamChannel.getReplies(widget.parentMessage.id); + return _streamChannel.getReplies(widget.parentMessage!.id); } } @@ -184,11 +184,11 @@ class MessageListCoreState extends State { _streamChannel = StreamChannel.of(context); if (_isThreadConversation) { - _streamChannel.getReplies(widget.parentMessage.id); + _streamChannel.getReplies(widget.parentMessage!.id); } if (widget.messageListController != null) { - widget.messageListController.paginateData = paginateData; + widget.messageListController!.paginateData = paginateData; } super.initState(); @@ -206,5 +206,5 @@ class MessageListCoreState extends State { /// Controller used for paginating data in [ChannelListView] class MessageListController { /// Call this function to load further data - Future Function({QueryDirection direction}) paginateData; + Future Function({QueryDirection? direction})? paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index 1c5c78de..d41086cd 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -13,9 +13,9 @@ import 'package:stream_chat_flutter_core/src/stream_chat_core.dart'; class MessageSearchBloc extends StatefulWidget { /// Instantiate a new MessageSearchBloc const MessageSearchBloc({ - Key key, - @required this.child, - }) : assert(child != null, 'Parameter child should not be null.'), + Key? key, + required this.child, + }) : assert(child != null, 'Parameter child should not be null.'), super(key: key); /// The widget child @@ -26,7 +26,7 @@ class MessageSearchBloc extends StatefulWidget { /// Use this method to get the current [MessageSearchBlocState] instance static MessageSearchBlocState of(BuildContext context) { - MessageSearchBlocState state; + MessageSearchBlocState? state; state = context.findAncestorStateOfType(); @@ -42,7 +42,7 @@ class MessageSearchBloc extends StatefulWidget { class MessageSearchBlocState extends State with AutomaticKeepAliveClientMixin { /// The current messages list - List get messageResponses => _messageResponses.value; + List? get messageResponses => _messageResponses.value; /// The current messages list as a stream Stream> get messagesStream => @@ -59,11 +59,11 @@ class MessageSearchBlocState extends State /// Calls [StreamChatClient.search] updating /// [messagesStream] and [queryMessagesLoading] stream Future search({ - Map filter, - Map messageFilter, - List sort, - String query, - PaginationParams pagination, + Map? filter, + Map? messageFilter, + List? sort, + String? query, + PaginationParams? pagination, }) async { final client = StreamChatCore.of(context).client; @@ -80,11 +80,11 @@ class MessageSearchBlocState extends State final oldMessages = List.from(messageResponses ?? []); final messages = await client.search( - filter, - sort: sort, - query: query, - paginationParams: pagination, - messageFilters: messageFilter, + filter!, + sort: sort!, + query: query!, + paginationParams: pagination!, + messageFilters: messageFilter!, ); if (clear) { @@ -93,7 +93,8 @@ class MessageSearchBlocState extends State final temp = oldMessages + messages.results; _messageResponses.add(temp); } - if (_messageResponses.hasValue && _queryMessagesLoadingController.value) { + if (_messageResponses.hasValue && + _queryMessagesLoadingController.value!) { _queryMessagesLoadingController.add(false); } } catch (e, stk) { diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index 72c5ea86..67019677 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -42,11 +42,11 @@ class MessageSearchListCore extends StatefulWidget { /// * [loadingBuilder] /// * [childBuilder] const MessageSearchListCore({ - Key key, - @required this.emptyBuilder, - @required this.errorBuilder, - @required this.loadingBuilder, - @required this.childBuilder, + Key? key, + required this.emptyBuilder, + required this.errorBuilder, + required this.loadingBuilder, + required this.childBuilder, this.messageQuery, this.filters, this.sortOptions, @@ -63,36 +63,36 @@ class MessageSearchListCore extends StatefulWidget { /// Use [MessageSearchListController.loadData] and /// [MessageSearchListController.paginateData] respectively for reloading and /// pagination. - final MessageSearchListController messageSearchListController; + final MessageSearchListController? messageSearchListController; /// Message String to search on - final String messageQuery; + final String? messageQuery; /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map filters; + final Map? filters; /// The sorting used for the channels matching the filters. /// Sorting is based on field and direction, multiple sorting options can be /// provided. /// You can sort based on last_updated, last_message_at, updated_at, created_ /// at or member_count. Direction can be ascending or descending. - final List sortOptions; + final List? sortOptions; /// Pagination parameters /// limit: the number of users to return (max is 30) /// offset: the offset (max is 1000) /// message_limit: how many messages should be included to each channel - final PaginationParams paginationParams; + final PaginationParams? paginationParams; /// The message query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map messageFilters; + final Map? messageFilters; /// The builder that is used when the search messages are fetched - final Widget Function(List) childBuilder; + final Widget Function(List?) childBuilder; /// The builder used when the channel list is empty. final WidgetBuilder emptyBuilder; @@ -114,8 +114,8 @@ class MessageSearchListCoreState extends State { super.didChangeDependencies(); loadData(); if (widget.messageSearchListController != null) { - widget.messageSearchListController.loadData = loadData; - widget.messageSearchListController.paginateData = paginateData; + widget.messageSearchListController!.loadData = loadData; + widget.messageSearchListController!.paginateData = paginateData; } } @@ -135,7 +135,7 @@ class MessageSearchListCoreState extends State { if (!snapshot.hasData) { return widget.loadingBuilder(context); } - final items = snapshot.data; + final items = snapshot.data!; if (items.isEmpty) { return widget.emptyBuilder(context); } @@ -161,7 +161,7 @@ class MessageSearchListCoreState extends State { return messageSearchBloc.search( filter: widget.filters, sort: widget.sortOptions, - pagination: widget.paginationParams.copyWith( + pagination: widget.paginationParams!.copyWith( offset: messageSearchBloc.messageResponses?.length ?? 0, ), query: widget.messageQuery, @@ -187,8 +187,8 @@ class MessageSearchListCoreState extends State { /// Controller used for paginating data in [ChannelListView] class MessageSearchListController { /// Call this function to reload data - AsyncCallback loadData; + AsyncCallback? loadData; /// Call this function to load further data - AsyncCallback paginateData; + AsyncCallback? paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart index 58a47d0a..f4b6e6c7 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; @@ -21,9 +22,9 @@ class StreamChannel extends StatefulWidget { /// Creates a new instance of [StreamChannel]. Both [child] and [client] must /// be supplied and not null. const StreamChannel({ - Key key, - @required this.child, - @required this.channel, + Key? key, + required this.child, + required this.channel, this.showLoading = true, this.initialMessageId, }) : assert(child != null, 'Child should not be null'), @@ -40,11 +41,11 @@ class StreamChannel extends StatefulWidget { final bool showLoading; /// If passed the channel will load from this particular message. - final String initialMessageId; + final String? initialMessageId; /// Use this method to get the current [StreamChannelState] instance static StreamChannelState of(BuildContext context) { - StreamChannelState streamChannelState; + StreamChannelState? streamChannelState; streamChannelState = context.findAncestorStateOfType(); @@ -67,7 +68,7 @@ class StreamChannelState extends State { Channel get channel => widget.channel; /// InitialMessageId - String get initialMessageId => widget.initialMessageId; + String? get initialMessageId => widget.initialMessageId; /// Current channel state stream Stream get channelStateStream => @@ -146,7 +147,7 @@ class StreamChannelState extends State { } /// Calls [channel.query] updating [queryMessage] stream - Future queryMessages({QueryDirection direction = QueryDirection.top}) { + Future queryMessages({QueryDirection? direction = QueryDirection.top}) { if (direction == QueryDirection.top) return _queryTopMessages(); return _queryBottomMessages(); } @@ -157,12 +158,12 @@ class StreamChannelState extends State { int limit = 50, bool preferOffline = false, }) async { - if (_topPaginationEnded || _queryTopMessagesController.value) return; + if (_topPaginationEnded || _queryTopMessagesController.value!) return; _queryTopMessagesController.add(true); - Message message; + late Message message; if (channel.state.threads.containsKey(parentId)) { - final thread = channel.state.threads[parentId]; + final thread = channel.state.threads[parentId]!; if (thread.isNotEmpty) { message = thread.first; } @@ -202,7 +203,7 @@ class StreamChannelState extends State { /// Loads channel at specific message Future loadChannelAtMessage( - String messageId, { + String? messageId, { int before = 20, int after = 20, bool preferOffline = false, @@ -214,13 +215,13 @@ class StreamChannelState extends State { preferOffline: preferOffline, ); - Future _queryAtMessage({ - String messageId, + Future> _queryAtMessage({ + String? messageId, int before = 20, int after = 20, bool preferOffline = false, }) async { - if (channel.state == null) return; + if (channel.state == null) return []; channel.state.isUpToDate = false; channel.state.truncate(); @@ -232,7 +233,7 @@ class StreamChannelState extends State { preferOffline: preferOffline, ); channel.state.isUpToDate = true; - return; + return []; } return Future.wait([ @@ -284,9 +285,8 @@ class StreamChannelState extends State { /// Future getMessage(String messageId) async { - var message = channel.state.messages.firstWhere( + var message = channel.state.messages.firstWhereOrNull( (it) => it.id == messageId, - orElse: () => null, ); if (message == null) { final response = await channel.getMessagesById([messageId]); @@ -298,7 +298,7 @@ class StreamChannelState extends State { /// Reloads the channel with latest message Future reloadChannel() => _queryAtMessage(before: 30); - List> _futures; + late List> _futures; Future get _loadChannelAtMessage async { try { @@ -358,9 +358,9 @@ class StreamChannelState extends State { } return Center(child: Text(message)); } - final initialized = snapshot.data[0]; + final initialized = snapshot.data![0]; // ignore: avoid_bool_literals_in_conditional_expressions - final dataLoaded = initialMessageId == null ? true : snapshot.data[1]; + final dataLoaded = initialMessageId == null ? true : snapshot.data![1]; if (widget.showLoading && (!initialized || !dataLoaded)) { return const Center( child: CircularProgressIndicator(), diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index 15c2ddf3..42ec8a21 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -38,9 +38,9 @@ class StreamChatCore extends StatefulWidget { /// [StreamChatCore] is a stateful widget which reacts to system events and /// updates Stream's connection status accordingly. const StreamChatCore({ - Key key, - @required this.client, - @required this.child, + Key? key, + required this.client, + required this.child, this.onBackgroundEventReceived, this.backgroundKeepAlive = const Duration(minutes: 1), }) : assert(client != null, 'Stream Chat Client should not be null'), @@ -61,14 +61,14 @@ class StreamChatCore extends StatefulWidget { /// Handler called whenever the [client] receives a new [Event] while the app /// is in background. Can be used to display various notifications depending /// upon the [Event.type] - final EventHandler onBackgroundEventReceived; + final EventHandler? onBackgroundEventReceived; @override StreamChatCoreState createState() => StreamChatCoreState(); /// Use this method to get the current [StreamChatCoreState] instance static StreamChatCoreState of(BuildContext context) { - StreamChatCoreState streamChatState; + StreamChatCoreState? streamChatState; streamChatState = context.findAncestorStateOfType(); @@ -87,24 +87,24 @@ class StreamChatCoreState extends State /// Initialized client used throughout the application. StreamChatClient get client => widget.client; - Timer _disconnectTimer; + Timer? _disconnectTimer; @override Widget build(BuildContext context) => widget.child; /// The current user - User get user => client.state?.user; + User? get user => client.state?.user; /// The current user as a stream - Stream get userStream => client.state?.userStream; + Stream? get userStream => client.state?.userStream; @override void initState() { super.initState(); - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance!.addObserver(this); } - StreamSubscription _eventSubscription; + StreamSubscription? _eventSubscription; @override void didChangeAppLifecycleState(AppLifecycleState state) { @@ -119,15 +119,15 @@ class StreamChatCoreState extends State ); void onTimerComplete() { - _eventSubscription.cancel(); + _eventSubscription!.cancel(); client.disconnect(); } _disconnectTimer = Timer(widget.backgroundKeepAlive, onTimerComplete); } else if (state == AppLifecycleState.resumed) { if (_disconnectTimer?.isActive == true) { - _eventSubscription.cancel(); - _disconnectTimer.cancel(); + _eventSubscription!.cancel(); + _disconnectTimer!.cancel(); } else { if (client.wsConnectionStatus == ConnectionStatus.disconnected) { client.connect(); @@ -139,7 +139,7 @@ class StreamChatCoreState extends State @override void dispose() { - WidgetsBinding.instance.removeObserver(this); + WidgetsBinding.instance!.removeObserver(this); _eventSubscription?.cancel(); _disconnectTimer?.cancel(); super.dispose(); diff --git a/packages/stream_chat_flutter_core/lib/src/typedef.dart b/packages/stream_chat_flutter_core/lib/src/typedef.dart index ace8d7e6..d5e7af2c 100644 --- a/packages/stream_chat_flutter_core/lib/src/typedef.dart +++ b/packages/stream_chat_flutter_core/lib/src/typedef.dart @@ -4,7 +4,7 @@ import 'package:stream_chat/stream_chat.dart'; /// A signature for a callback which exposes an error and returns a function. /// This Callback can be used in cases where an API failure occurs and the /// widget is unable to render data. -typedef ErrorBuilder = Widget Function(BuildContext context, Object error); +typedef ErrorBuilder = Widget Function(BuildContext context, Object? error); /// A Signature for a handler function which will expose a [event]. typedef EventHandler = void Function(Event event); diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index f1bd68ee..d2412b97 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -57,11 +57,11 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; class UserListCore extends StatefulWidget { /// Instantiate a new [UserListCore] const UserListCore({ - @required this.errorBuilder, - @required this.emptyBuilder, - @required this.loadingBuilder, - @required this.listBuilder, - Key key, + required this.errorBuilder, + required this.emptyBuilder, + required this.loadingBuilder, + required this.listBuilder, + Key? key, this.filter, this.options, this.sort, @@ -77,10 +77,10 @@ class UserListCore extends StatefulWidget { /// A [UserListController] allows reloading and pagination. /// Use [UserListController.loadData] and [UserListController.paginateData] /// respectively for reloading and pagination. - final UserListController userListController; + final UserListController? userListController; /// The builder that will be used in case of error - final Widget Function(Object error) errorBuilder; + final Widget Function(Object? error) errorBuilder; /// The builder that will be used to build the list final Widget Function(BuildContext context, List users) listBuilder; @@ -94,25 +94,25 @@ class UserListCore extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map filter; + final Map? filter; /// Query channels options. /// /// state: if true returns the Channel state /// watch: if true listen to changes to this Channel in real time. - final Map options; + final Map? options; /// The sorting used for the channels matching the filters. /// Sorting is based on field and direction, multiple sorting options can be /// provided. You can sort based on last_updated, last_message_at, updated_at, /// created_at or member_count. Direction can be ascending or descending. - final List sort; + final List? sort; /// Pagination parameters /// limit: the number of users to return (max is 30) /// offset: the offset (max is 1000) /// message_limit: how many messages should be included to each channel - final PaginationParams pagination; + final PaginationParams? pagination; /// Set it to true to group users by their first character /// @@ -131,8 +131,8 @@ class UserListCoreState extends State super.didChangeDependencies(); loadData(); if (widget.userListController != null) { - widget.userListController.loadData = loadData; - widget.userListController.paginateData = paginateData; + widget.userListController!.loadData = loadData; + widget.userListController!.paginateData = paginateData; } } @@ -158,14 +158,14 @@ class UserListCoreState extends State } final groupedUsers = >{}; for (final e in temp) { - final alphabet = e.name[0]?.toUpperCase(); + final alphabet = e.name[0].toUpperCase(); groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; } final items = []; for (final key in groupedUsers.keys) { items ..add(ListHeaderItem(key)) - ..addAll(groupedUsers[key].map((e) => ListUserItem(e))); + ..addAll(groupedUsers[key]!.map((e) => ListUserItem(e))); } return items; } @@ -185,7 +185,7 @@ class UserListCoreState extends State if (!snapshot.hasData) { return widget.loadingBuilder(context); } - final items = snapshot.data; + final items = snapshot.data!; if (items.isEmpty) { return widget.emptyBuilder(context); } @@ -210,7 +210,7 @@ class UserListCoreState extends State return _usersBloc.queryUsers( filter: widget.filter, sort: widget.sort, - pagination: widget.pagination.copyWith( + pagination: widget.pagination!.copyWith( offset: _usersBloc.users?.length ?? 0, ), options: widget.options, @@ -235,7 +235,7 @@ class UserListCoreState extends State /// with `USER`. abstract class ListItem { /// Unique key per list item - String get key { + String? get key { if (this is ListHeaderItem) { final header = (this as ListHeaderItem).heading; return 'HEADER-${header.toLowerCase()}'; @@ -250,8 +250,8 @@ abstract class ListItem { /// Helper function to build widget based on ListItem type // ignore: missing_return Widget when({ - @required Widget Function(String heading) headerItem, - @required Widget Function(User user) userItem, + required Widget Function(String heading) headerItem, + required Widget Function(User user) userItem, }) { if (this is ListHeaderItem) { return headerItem((this as ListHeaderItem).heading); @@ -259,6 +259,7 @@ abstract class ListItem { if (this is ListUserItem) { return userItem((this as ListUserItem).user); } + return Container(); } } @@ -283,8 +284,8 @@ class ListUserItem extends ListItem { /// Controller used for paginating data in [ChannelListView] class UserListController { /// Call this function to reload data - AsyncCallback loadData; + AsyncCallback? loadData; /// Call this function to load further data - AsyncCallback paginateData; + AsyncCallback? paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart index 92881619..2470fba7 100644 --- a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -14,8 +14,8 @@ class UsersBloc extends StatefulWidget { /// Instantiate a new [UsersBloc]. The parameter [child] must be supplied and /// not null. const UsersBloc({ - @required this.child, - Key key, + required this.child, + Key? key, }) : assert( child != null, 'When constructing a UsersBloc, the parameter ' @@ -30,7 +30,7 @@ class UsersBloc extends StatefulWidget { /// Use this method to get the current [UsersBlocState] instance static UsersBlocState of(BuildContext context) { - UsersBlocState state; + UsersBlocState? state; state = context.findAncestorStateOfType(); @@ -46,7 +46,7 @@ class UsersBloc extends StatefulWidget { class UsersBlocState extends State with AutomaticKeepAliveClientMixin { /// The current users list - List get users => _usersController.value; + List? get users => _usersController.value; /// The current users list as a stream Stream> get usersStream => _usersController.stream; @@ -62,10 +62,10 @@ class UsersBlocState extends State /// online/offline. /// [API Reference](https://getstream.io/chat/docs/flutter-dart/query_users/?language=dart) Future queryUsers({ - Map filter, - List sort, - Map options, - PaginationParams pagination, + Map? filter, + List? sort, + Map? options, + PaginationParams? pagination, }) async { final client = StreamChatCore.of(context).client; @@ -83,10 +83,10 @@ class UsersBlocState extends State final oldUsers = List.from(users ?? []); final usersResponse = await client.queryUsers( - filter: filter, - sort: sort, - options: options, - pagination: pagination, + filter: filter!, + sort: sort!, + options: options!, + pagination: pagination!, ); if (clear) { @@ -95,7 +95,7 @@ class UsersBlocState extends State final temp = oldUsers + usersResponse.users; _usersController.add(temp); } - if (_usersController.hasValue && _queryUsersLoadingController.value) { + if (_usersController.hasValue && _queryUsersLoadingController.value!) { _queryUsersLoadingController.add(false); } } catch (e, stk) { diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 4b3d81de..195c4ee3 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -8,7 +8,7 @@ issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues publish_to: none environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' flutter: ">=1.17.0" dependencies: @@ -17,14 +17,15 @@ dependencies: meta: ^1.2.4 rxdart: ^0.26.0 stream_chat: ^1.5.0 + collection: ^1.15.0-nullsafety.4 dependency_overrides: stream_chat: path: ../stream_chat dev_dependencies: - fake_async: ^1.1.0 + fake_async: ^1.2.0 flutter_test: sdk: flutter - mockito: ^4.1.3 + mockito: ^5.0.3 diff --git a/packages/stream_chat_flutter_core/test/matchers/channel_matcher.dart b/packages/stream_chat_flutter_core/test/matchers/channel_matcher.dart index f371acff..f6d7fb50 100644 --- a/packages/stream_chat_flutter_core/test/matchers/channel_matcher.dart +++ b/packages/stream_chat_flutter_core/test/matchers/channel_matcher.dart @@ -7,7 +7,7 @@ Matcher isSameChannelAs(Channel targetChannel) => class _IsSameChannelAs extends Matcher { const _IsSameChannelAs({ - @required this.targetChannel, + required this.targetChannel, }) : assert(targetChannel != null, ''); final Channel targetChannel; @@ -26,7 +26,7 @@ Matcher isSameChannelListAs(List targetChannelList) => class _IsSameChannelListAs extends Matcher { const _IsSameChannelListAs({ - @required this.targetChannelList, + required this.targetChannelList, }) : assert(targetChannelList != null, ''); final List targetChannelList; diff --git a/packages/stream_chat_flutter_core/test/matchers/get_message_response_matcher.dart b/packages/stream_chat_flutter_core/test/matchers/get_message_response_matcher.dart index bd89420b..42ea0d34 100644 --- a/packages/stream_chat_flutter_core/test/matchers/get_message_response_matcher.dart +++ b/packages/stream_chat_flutter_core/test/matchers/get_message_response_matcher.dart @@ -7,7 +7,7 @@ Matcher isSameMessageResponseAs(GetMessageResponse targetResponse) => class _IsSameMessageResponseAs extends Matcher { const _IsSameMessageResponseAs({ - @required this.targetResponse, + required this.targetResponse, }) : assert(targetResponse != null, ''); final GetMessageResponse targetResponse; @@ -28,7 +28,7 @@ Matcher isSameMessageResponseListAs( class _IsSameMessageResponseListAs extends Matcher { const _IsSameMessageResponseListAs({ - @required this.targetResponseList, + required this.targetResponseList, }) : assert(targetResponseList != null, ''); final List targetResponseList; diff --git a/packages/stream_chat_flutter_core/test/matchers/message_matcher.dart b/packages/stream_chat_flutter_core/test/matchers/message_matcher.dart index 12a3e19d..69a24f49 100644 --- a/packages/stream_chat_flutter_core/test/matchers/message_matcher.dart +++ b/packages/stream_chat_flutter_core/test/matchers/message_matcher.dart @@ -7,7 +7,7 @@ Matcher isSameMessageAs(Message targetMessage) => class _IsSameMessageAs extends Matcher { const _IsSameMessageAs({ - @required this.targetMessage, + required this.targetMessage, }) : assert(targetMessage != null, ''); final Message targetMessage; @@ -26,7 +26,7 @@ Matcher isSameMessageListAs(List targetMessageList) => class _IsSameMessageListAs extends Matcher { const _IsSameMessageListAs({ - @required this.targetMessageList, + required this.targetMessageList, }) : assert(targetMessageList != null, ''); final List targetMessageList; diff --git a/packages/stream_chat_flutter_core/test/matchers/users_matcher.dart b/packages/stream_chat_flutter_core/test/matchers/users_matcher.dart index 3816fa24..38e25a64 100644 --- a/packages/stream_chat_flutter_core/test/matchers/users_matcher.dart +++ b/packages/stream_chat_flutter_core/test/matchers/users_matcher.dart @@ -6,7 +6,7 @@ Matcher isSameUserAs(User targetUser) => _IsSameUserAs(targetUser: targetUser); class _IsSameUserAs extends Matcher { const _IsSameUserAs({ - @required this.targetUser, + required this.targetUser, }) : assert(targetUser != null, ''); final User targetUser; @@ -24,7 +24,7 @@ Matcher isSameUserListAs(List targetUserList) => class _IsSameUserListAs extends Matcher { const _IsSameUserListAs({ - @required this.targetUserList, + required this.targetUserList, }) : assert(targetUserList != null, ''); final List targetUserList;