Line data Source code
1 : import 'package:flutter/material.dart'; 2 : import 'package:rxdart/rxdart.dart'; 3 : import 'package:stream_chat/stream_chat.dart'; 4 : import 'package:stream_chat_flutter_core/src/stream_chat_core.dart'; 5 : 6 : /// [MessageSearchBloc] is used to manage a list of messages with pagination. 7 : /// This class can be used to load messages, perform queries, etc. 8 : /// 9 : /// [MessageSearchBloc] can be access at anytime by using the static [of] method 10 : /// using Flutter's [BuildContext]. 11 : /// 12 : /// API docs: https://getstream.io/chat/docs/flutter-dart/send_message/ 13 : class MessageSearchBloc extends StatefulWidget { 14 : /// Instantiate a new MessageSearchBloc 15 2 : const MessageSearchBloc({ 16 : Key? key, 17 : required this.child, 18 2 : }) : super(key: key); 19 : 20 : /// The widget child 21 : final Widget child; 22 : 23 2 : @override 24 2 : MessageSearchBlocState createState() => MessageSearchBlocState(); 25 : 26 : /// Use this method to get the current [MessageSearchBlocState] instance 27 1 : static MessageSearchBlocState of(BuildContext context) { 28 : MessageSearchBlocState? state; 29 : 30 1 : state = context.findAncestorStateOfType<MessageSearchBlocState>(); 31 : 32 : assert( 33 1 : state != null, 34 : 'You must have a MessageSearchBloc widget as ancestor', 35 : ); 36 : 37 : return state!; 38 : } 39 : } 40 : 41 : /// The current state of the [MessageSearchBloc] 42 : class MessageSearchBlocState extends State<MessageSearchBloc> 43 : with AutomaticKeepAliveClientMixin { 44 : late StreamChatCoreState _streamChatCoreState; 45 : 46 : /// The current messages list 47 2 : List<GetMessageResponse>? get messageResponses => 48 4 : _messageResponses.valueOrNull; 49 : 50 : /// The current messages list as a stream 51 2 : Stream<List<GetMessageResponse>> get messagesStream => 52 4 : _messageResponses.stream; 53 : 54 : final _messageResponses = BehaviorSubject<List<GetMessageResponse>>(); 55 : 56 : final _queryMessagesLoadingController = BehaviorSubject.seeded(false); 57 : 58 : /// The stream notifying the state of queryUsers call 59 1 : Stream<bool> get queryMessagesLoading => 60 2 : _queryMessagesLoadingController.stream; 61 : 62 : /// Calls [StreamChatClient.search] updating 63 : /// [messagesStream] and [queryMessagesLoading] stream 64 2 : Future<void> search({ 65 : required Filter filter, 66 : Filter? messageFilter, 67 : List<SortOption>? sort, 68 : String? query, 69 : PaginationParams? pagination, 70 : }) async { 71 4 : final client = _streamChatCoreState.client; 72 : 73 6 : if (_queryMessagesLoadingController.value == true) return; 74 : 75 4 : if (_messageResponses.hasValue) { 76 4 : _queryMessagesLoadingController.add(true); 77 : } 78 : try { 79 4 : final clear = pagination == null || pagination.offset == 0; 80 : 81 6 : final oldMessages = List<GetMessageResponse>.from(messageResponses ?? []); 82 : 83 4 : final messages = await client.search( 84 : filter, 85 : sort: sort, 86 : query: query, 87 : paginationParams: pagination, 88 : messageFilters: messageFilter, 89 : ); 90 : 91 : if (clear) { 92 6 : _messageResponses.add(messages.results); 93 : } else { 94 4 : final temp = oldMessages + messages.results; 95 4 : _messageResponses.add(temp); 96 : } 97 8 : if (_messageResponses.hasValue && _queryMessagesLoadingController.value) { 98 4 : _queryMessagesLoadingController.add(false); 99 : } 100 : } catch (e, stk) { 101 4 : if (_messageResponses.hasValue) { 102 2 : _queryMessagesLoadingController.addError(e, stk); 103 : } else { 104 4 : _messageResponses.addError(e, stk); 105 : } 106 : } 107 : } 108 : 109 2 : @override 110 : Widget build(BuildContext context) { 111 2 : super.build(context); 112 4 : return widget.child; 113 : } 114 : 115 2 : @override 116 : void didChangeDependencies() { 117 6 : _streamChatCoreState = StreamChatCore.of(context); 118 2 : super.didChangeDependencies(); 119 : } 120 : 121 2 : @override 122 : void dispose() { 123 4 : _messageResponses.close(); 124 4 : _queryMessagesLoadingController.close(); 125 2 : super.dispose(); 126 : } 127 : 128 2 : @override 129 : bool get wantKeepAlive => true; 130 : }