mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-19 10:53:51 +02:00
added pagination
This commit is contained in:
parent
69bafc33e6
commit
ac163a28f8
7 changed files with 278 additions and 105 deletions
|
@ -22,9 +22,14 @@ List<GoRoute> getCommunityChatStoryRoutes(
|
||||||
options: configuration.chatOptionsBuilder(context),
|
options: configuration.chatOptionsBuilder(context),
|
||||||
onNoChats: () async =>
|
onNoChats: () async =>
|
||||||
await context.push(CommunityChatUserStoryRoutes.newChatScreen),
|
await context.push(CommunityChatUserStoryRoutes.newChatScreen),
|
||||||
onPressStartChat: () async =>
|
onPressStartChat: () async {
|
||||||
await configuration.onPressStartChat?.call() ??
|
if (configuration.onPressStartChat != null) {
|
||||||
await context.push(CommunityChatUserStoryRoutes.newChatScreen),
|
return await configuration.onPressStartChat?.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
return await context
|
||||||
|
.push(CommunityChatUserStoryRoutes.newChatScreen);
|
||||||
|
},
|
||||||
onPressChat: (chat) =>
|
onPressChat: (chat) =>
|
||||||
configuration.onPressChat?.call(context, chat) ??
|
configuration.onPressChat?.call(context, chat) ??
|
||||||
context.push(
|
context.push(
|
||||||
|
|
|
@ -15,7 +15,7 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
go_router: ^12.1.1
|
go_router: any
|
||||||
flutter_community_chat_view:
|
flutter_community_chat_view:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_community_chat
|
url: https://github.com/Iconica-Development/flutter_community_chat
|
||||||
|
|
|
@ -13,7 +13,7 @@ import 'package:flutter_community_chat_firebase/dto/firebase_message_document.da
|
||||||
import 'package:flutter_community_chat_interface/flutter_community_chat_interface.dart';
|
import 'package:flutter_community_chat_interface/flutter_community_chat_interface.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class FirebaseMessageService implements MessageService {
|
class FirebaseMessageService with ChangeNotifier implements MessageService {
|
||||||
late final FirebaseFirestore _db;
|
late final FirebaseFirestore _db;
|
||||||
late final FirebaseStorage _storage;
|
late final FirebaseStorage _storage;
|
||||||
late final ChatUserService _userService;
|
late final ChatUserService _userService;
|
||||||
|
@ -25,6 +25,7 @@ class FirebaseMessageService implements MessageService {
|
||||||
List<ChatMessageModel> _cumulativeMessages = [];
|
List<ChatMessageModel> _cumulativeMessages = [];
|
||||||
ChatModel? lastChat;
|
ChatModel? lastChat;
|
||||||
int? chatPageSize;
|
int? chatPageSize;
|
||||||
|
DateTime timestampToFilter = DateTime.now();
|
||||||
|
|
||||||
FirebaseMessageService({
|
FirebaseMessageService({
|
||||||
required ChatUserService userService,
|
required ChatUserService userService,
|
||||||
|
@ -58,12 +59,21 @@ class FirebaseMessageService implements MessageService {
|
||||||
)
|
)
|
||||||
.doc(chat.id);
|
.doc(chat.id);
|
||||||
|
|
||||||
await chatReference
|
var newMessage = await chatReference
|
||||||
.collection(
|
.collection(
|
||||||
_options.messagesCollectionName,
|
_options.messagesCollectionName,
|
||||||
)
|
)
|
||||||
.add(message);
|
.add(message);
|
||||||
|
|
||||||
|
if (_cumulativeMessages.length == 1) {
|
||||||
|
lastMessage = await chatReference
|
||||||
|
.collection(
|
||||||
|
_options.messagesCollectionName,
|
||||||
|
)
|
||||||
|
.doc(newMessage.id)
|
||||||
|
.get();
|
||||||
|
}
|
||||||
|
|
||||||
var metadataReference = _db
|
var metadataReference = _db
|
||||||
.collection(
|
.collection(
|
||||||
_options.chatsMetaDataCollectionName,
|
_options.chatsMetaDataCollectionName,
|
||||||
|
@ -188,14 +198,89 @@ class FirebaseMessageService implements MessageService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<List<ChatMessageModel>> getMessagesStream(
|
Stream<List<ChatMessageModel>> getMessagesStream(ChatModel chat) {
|
||||||
ChatModel chat, int pageSize) {
|
|
||||||
chatPageSize = pageSize;
|
|
||||||
_controller = StreamController<List<ChatMessageModel>>(
|
_controller = StreamController<List<ChatMessageModel>>(
|
||||||
onListen: () {
|
onListen: () {
|
||||||
if (chat.id != null) {
|
var messagesCollection = _db
|
||||||
_subscription = _startListeningForMessages(chat);
|
.collection(_options.chatsCollectionName)
|
||||||
|
.doc(chat.id)
|
||||||
|
.collection(_options.messagesCollectionName)
|
||||||
|
.withConverter<FirebaseMessageDocument>(
|
||||||
|
fromFirestore: (snapshot, _) => FirebaseMessageDocument.fromJson(
|
||||||
|
snapshot.data()!, snapshot.id),
|
||||||
|
toFirestore: (user, _) => user.toJson(),
|
||||||
|
);
|
||||||
|
var query = messagesCollection
|
||||||
|
.where(
|
||||||
|
'timestamp',
|
||||||
|
isGreaterThan: timestampToFilter,
|
||||||
|
)
|
||||||
|
.withConverter<FirebaseMessageDocument>(
|
||||||
|
fromFirestore: (snapshot, _) => FirebaseMessageDocument.fromJson(
|
||||||
|
snapshot.data()!, snapshot.id),
|
||||||
|
toFirestore: (user, _) => user.toJson(),
|
||||||
|
);
|
||||||
|
|
||||||
|
var stream = query.snapshots();
|
||||||
|
// Subscribe to the stream and process the updates
|
||||||
|
_subscription = stream.listen((snapshot) async {
|
||||||
|
var messages = <ChatMessageModel>[];
|
||||||
|
|
||||||
|
for (var messageDoc in snapshot.docs) {
|
||||||
|
var messageData = messageDoc.data();
|
||||||
|
var timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(messageData.timestamp).millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if the message is already in the list to avoid duplicates
|
||||||
|
if (timestampToFilter.isBefore(timestamp)) {
|
||||||
|
if (!messages.any((message) {
|
||||||
|
var timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(messageData.timestamp).millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
return timestamp == message.timestamp;
|
||||||
|
})) {
|
||||||
|
var sender = await _userService.getUser(messageData.sender);
|
||||||
|
|
||||||
|
if (sender != null) {
|
||||||
|
var timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(messageData.timestamp).millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
|
||||||
|
messages.add(
|
||||||
|
messageData.imageUrl != null
|
||||||
|
? ChatImageMessageModel(
|
||||||
|
sender: sender,
|
||||||
|
imageUrl: messageData.imageUrl!,
|
||||||
|
timestamp: timestamp,
|
||||||
|
)
|
||||||
|
: ChatTextMessageModel(
|
||||||
|
sender: sender,
|
||||||
|
text: messageData.text!,
|
||||||
|
timestamp: timestamp,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the filtered messages to the controller
|
||||||
|
_controller?.add(messages);
|
||||||
|
_cumulativeMessages = [
|
||||||
|
..._cumulativeMessages,
|
||||||
|
...messages,
|
||||||
|
];
|
||||||
|
|
||||||
|
// remove all double elements
|
||||||
|
List<ChatMessageModel> uniqueObjects =
|
||||||
|
_cumulativeMessages.toSet().toList();
|
||||||
|
_cumulativeMessages = uniqueObjects;
|
||||||
|
_cumulativeMessages
|
||||||
|
.sort((a, b) => a.timestamp.compareTo(b.timestamp));
|
||||||
|
notifyListeners();
|
||||||
|
timestampToFilter = DateTime.now();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onCancel: () {
|
onCancel: () {
|
||||||
_subscription?.cancel();
|
_subscription?.cancel();
|
||||||
|
@ -203,7 +288,6 @@ class FirebaseMessageService implements MessageService {
|
||||||
debugPrint('Canceling messages stream');
|
debugPrint('Canceling messages stream');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return _controller!.stream;
|
return _controller!.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +342,91 @@ class FirebaseMessageService implements MessageService {
|
||||||
messages.sort((a, b) => a.timestamp.compareTo(b.timestamp));
|
messages.sort((a, b) => a.timestamp.compareTo(b.timestamp));
|
||||||
|
|
||||||
_controller?.add(messages);
|
_controller?.add(messages);
|
||||||
|
notifyListeners();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> fetchMoreMessage(int pageSize, ChatModel chat) async {
|
||||||
|
if (lastChat == null) {
|
||||||
|
lastChat = chat;
|
||||||
|
} else if (lastChat?.id != chat.id) {
|
||||||
|
_cumulativeMessages = [];
|
||||||
|
lastChat = chat;
|
||||||
|
lastMessage = null;
|
||||||
|
}
|
||||||
|
// get the x amount of last messages from the oldest message that is in cumulative messages and add that to the list
|
||||||
|
List<ChatMessageModel> messages = [];
|
||||||
|
QuerySnapshot<FirebaseMessageDocument>? messagesQuerySnapshot;
|
||||||
|
var query = _db
|
||||||
|
.collection(_options.chatsCollectionName)
|
||||||
|
.doc(chat.id)
|
||||||
|
.collection(_options.messagesCollectionName)
|
||||||
|
.orderBy('timestamp', descending: true)
|
||||||
|
.limit(pageSize);
|
||||||
|
if (lastMessage == null) {
|
||||||
|
messagesQuerySnapshot = await query
|
||||||
|
.withConverter<FirebaseMessageDocument>(
|
||||||
|
fromFirestore: (snapshot, _) =>
|
||||||
|
FirebaseMessageDocument.fromJson(snapshot.data()!, snapshot.id),
|
||||||
|
toFirestore: (user, _) => user.toJson(),
|
||||||
|
)
|
||||||
|
.get();
|
||||||
|
if (messagesQuerySnapshot.docs.isNotEmpty) {
|
||||||
|
lastMessage = messagesQuerySnapshot.docs.last;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messagesQuerySnapshot = await query
|
||||||
|
.startAfterDocument(lastMessage!)
|
||||||
|
.withConverter<FirebaseMessageDocument>(
|
||||||
|
fromFirestore: (snapshot, _) =>
|
||||||
|
FirebaseMessageDocument.fromJson(snapshot.data()!, snapshot.id),
|
||||||
|
toFirestore: (user, _) => user.toJson(),
|
||||||
|
)
|
||||||
|
.get();
|
||||||
|
if (messagesQuerySnapshot.docs.isNotEmpty) {
|
||||||
|
lastMessage = messagesQuerySnapshot.docs.last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FirebaseMessageDocument> messageDocuments = messagesQuerySnapshot.docs
|
||||||
|
.map((QueryDocumentSnapshot<FirebaseMessageDocument> doc) => doc.data())
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
for (var message in messageDocuments) {
|
||||||
|
var sender = await _userService.getUser(message.sender);
|
||||||
|
if (sender != null) {
|
||||||
|
var timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(message.timestamp).millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
|
||||||
|
messages.add(
|
||||||
|
message.imageUrl != null
|
||||||
|
? ChatImageMessageModel(
|
||||||
|
sender: sender,
|
||||||
|
imageUrl: message.imageUrl!,
|
||||||
|
timestamp: timestamp,
|
||||||
|
)
|
||||||
|
: ChatTextMessageModel(
|
||||||
|
sender: sender,
|
||||||
|
text: message.text!,
|
||||||
|
timestamp: timestamp,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_cumulativeMessages = [
|
||||||
|
...messages,
|
||||||
|
..._cumulativeMessages,
|
||||||
|
];
|
||||||
|
_cumulativeMessages.sort((a, b) => a.timestamp.compareTo(b.timestamp));
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<ChatMessageModel> getMessages() {
|
||||||
|
return _cumulativeMessages;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_community_chat_interface/flutter_community_chat_interface.dart';
|
import 'package:flutter_community_chat_interface/flutter_community_chat_interface.dart';
|
||||||
|
|
||||||
abstract class MessageService {
|
abstract class MessageService with ChangeNotifier {
|
||||||
Future<void> sendTextMessage({
|
Future<void> sendTextMessage({
|
||||||
required ChatModel chat,
|
required ChatModel chat,
|
||||||
required String text,
|
required String text,
|
||||||
|
@ -14,6 +15,9 @@ abstract class MessageService {
|
||||||
|
|
||||||
Stream<List<ChatMessageModel>> getMessagesStream(
|
Stream<List<ChatMessageModel>> getMessagesStream(
|
||||||
ChatModel chat,
|
ChatModel chat,
|
||||||
int pageSize,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Future<void> fetchMoreMessage(int pageSize, ChatModel chat);
|
||||||
|
|
||||||
|
List<ChatMessageModel> getMessages();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,22 +34,19 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var isNewDate = widget.previousMessage != null &&
|
var isNewDate = widget.previousMessage != null &&
|
||||||
widget.message.timestamp.day != widget.previousMessage!.timestamp.day;
|
widget.message.timestamp.day != widget.previousMessage?.timestamp.day;
|
||||||
|
var isSameSender = widget.previousMessage == null ||
|
||||||
|
widget.previousMessage?.sender.id != widget.message.sender.id;
|
||||||
|
print(isNewDate);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: isNewDate ||
|
top: isNewDate || isSameSender ? 25.0 : 0,
|
||||||
widget.previousMessage == null ||
|
|
||||||
widget.previousMessage?.sender.id != widget.message.sender.id
|
|
||||||
? 25.0
|
|
||||||
: 0,
|
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (isNewDate ||
|
if (isNewDate || isSameSender) ...[
|
||||||
widget.previousMessage == null ||
|
|
||||||
widget.previousMessage?.sender.id !=
|
|
||||||
widget.message.sender.id) ...[
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 10.0),
|
padding: const EdgeInsets.only(left: 10.0),
|
||||||
child: widget.message.sender.imageUrl != null &&
|
child: widget.message.sender.imageUrl != null &&
|
||||||
|
@ -75,10 +72,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (isNewDate ||
|
if (isNewDate || isSameSender)
|
||||||
widget.previousMessage == null ||
|
|
||||||
widget.previousMessage?.sender.id !=
|
|
||||||
widget.message.sender.id)
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -57,34 +57,29 @@ class ChatDetailScreen extends StatefulWidget {
|
||||||
|
|
||||||
class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
||||||
// stream listener that needs to be disposed later
|
// stream listener that needs to be disposed later
|
||||||
StreamSubscription<List<ChatMessageModel>>? _chatMessagesSubscription;
|
|
||||||
Stream<List<ChatMessageModel>>? _chatMessages;
|
|
||||||
ChatModel? chat;
|
|
||||||
ChatUserModel? currentUser;
|
ChatUserModel? currentUser;
|
||||||
ScrollController controller = ScrollController();
|
ScrollController controller = ScrollController();
|
||||||
bool showIndicator = false;
|
bool showIndicator = false;
|
||||||
|
late MessageService messageSubscription;
|
||||||
|
Stream<List<ChatMessageModel>>? stream;
|
||||||
|
ChatMessageModel? previousMessage;
|
||||||
|
List<Widget> detailRows = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// create a broadcast stream from the chat messages
|
messageSubscription = widget.messageService;
|
||||||
|
messageSubscription.addListener(onListen);
|
||||||
if (widget.chat != null) {
|
if (widget.chat != null) {
|
||||||
_chatMessages = widget.messageService
|
stream = widget.messageService.getMessagesStream(widget.chat!);
|
||||||
.getMessagesStream(widget.chat!, widget.pageSize)
|
stream?.listen((event) {});
|
||||||
.asBroadcastStream();
|
|
||||||
}
|
|
||||||
_chatMessagesSubscription = _chatMessages?.listen((event) {
|
|
||||||
// check if the last message is from the current user
|
|
||||||
// if so, set the chat to read
|
|
||||||
Future.delayed(Duration.zero, () async {
|
Future.delayed(Duration.zero, () async {
|
||||||
currentUser = await widget.chatUserService.getCurrentUser();
|
if (detailRows.isEmpty) {
|
||||||
});
|
await widget.messageService
|
||||||
if (event.isNotEmpty &&
|
.fetchMoreMessage(widget.pageSize, widget.chat!);
|
||||||
event.last.sender.id != currentUser?.id &&
|
|
||||||
widget.chat != null) {
|
|
||||||
widget.onReadChat(widget.chat!);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (widget.chat != null) {
|
if (widget.chat != null) {
|
||||||
widget.onReadChat(widget.chat!);
|
widget.onReadChat(widget.chat!);
|
||||||
|
@ -92,9 +87,34 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onListen() {
|
||||||
|
var chatMessages = [];
|
||||||
|
chatMessages = widget.messageService.getMessages();
|
||||||
|
detailRows = [];
|
||||||
|
previousMessage = null;
|
||||||
|
for (var message in chatMessages) {
|
||||||
|
detailRows.add(
|
||||||
|
ChatDetailRow(
|
||||||
|
showTime: true,
|
||||||
|
message: message,
|
||||||
|
translations: widget.translations,
|
||||||
|
userAvatarBuilder: widget.options.userAvatarBuilder,
|
||||||
|
previousMessage: previousMessage,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
previousMessage = message;
|
||||||
|
}
|
||||||
|
detailRows = detailRows.reversed.toList();
|
||||||
|
|
||||||
|
widget.onReadChat(widget.chat!);
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_chatMessagesSubscription?.cancel();
|
messageSubscription.removeListener(onListen);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,41 +190,20 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: StreamBuilder<List<ChatMessageModel>>(
|
child: Listener(
|
||||||
stream: _chatMessages,
|
onPointerMove: (event) async {
|
||||||
builder: (context, snapshot) {
|
|
||||||
var messages = snapshot.data ?? chatModel?.messages ?? [];
|
|
||||||
ChatMessageModel? previousMessage;
|
|
||||||
|
|
||||||
var messageWidgets = <Widget>[];
|
|
||||||
|
|
||||||
for (var message in messages) {
|
|
||||||
messageWidgets.add(
|
|
||||||
ChatDetailRow(
|
|
||||||
previousMessage: previousMessage,
|
|
||||||
showTime: widget.showTime,
|
|
||||||
translations: widget.translations,
|
|
||||||
message: message,
|
|
||||||
userAvatarBuilder: widget.options.userAvatarBuilder,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
previousMessage = message;
|
|
||||||
}
|
|
||||||
return Listener(
|
|
||||||
onPointerMove: (event) {
|
|
||||||
var isTop = controller.position.pixels ==
|
var isTop = controller.position.pixels ==
|
||||||
controller.position.maxScrollExtent;
|
controller.position.maxScrollExtent;
|
||||||
|
|
||||||
if (showIndicator == false &&
|
if (showIndicator == false &&
|
||||||
isTop &&
|
!isTop &&
|
||||||
!(controller.position.userScrollDirection ==
|
controller.position.userScrollDirection ==
|
||||||
ScrollDirection.reverse)) {
|
ScrollDirection.reverse) {
|
||||||
setState(() {
|
setState(() {
|
||||||
showIndicator = true;
|
showIndicator = true;
|
||||||
});
|
});
|
||||||
_chatMessages = widget.messageService
|
await widget.messageService
|
||||||
.getMessagesStream(widget.chat!, widget.pageSize)
|
.fetchMoreMessage(widget.pageSize, widget.chat!);
|
||||||
.asBroadcastStream();
|
|
||||||
Future.delayed(const Duration(seconds: 2), () {
|
Future.delayed(const Duration(seconds: 2), () {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -215,21 +214,24 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: ListView(
|
child: ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
controller: controller,
|
controller: controller,
|
||||||
reverse: true,
|
reverse: true,
|
||||||
padding: const EdgeInsets.only(top: 24.0),
|
padding: const EdgeInsets.only(top: 24.0),
|
||||||
children: [
|
children: [
|
||||||
...messageWidgets.reversed.toList(),
|
...detailRows,
|
||||||
if (snapshot.connectionState !=
|
if (showIndicator) ...[
|
||||||
ConnectionState.active ||
|
const SizedBox(
|
||||||
showIndicator) ...[
|
height: 10,
|
||||||
|
),
|
||||||
const Center(child: CircularProgressIndicator()),
|
const Center(child: CircularProgressIndicator()),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (chatModel != null)
|
if (chatModel != null)
|
||||||
|
|
|
@ -29,8 +29,8 @@ class ChatScreen extends StatefulWidget {
|
||||||
final ChatOptions options;
|
final ChatOptions options;
|
||||||
final ChatTranslations translations;
|
final ChatTranslations translations;
|
||||||
final ChatService service;
|
final ChatService service;
|
||||||
final Function? onPressStartChat;
|
final Function()? onPressStartChat;
|
||||||
final Function? onNoChats;
|
final Function()? onNoChats;
|
||||||
final void Function(ChatModel chat) onDeleteChat;
|
final void Function(ChatModel chat) onDeleteChat;
|
||||||
final void Function(ChatModel chat) onPressChat;
|
final void Function(ChatModel chat) onPressChat;
|
||||||
final int pageSize;
|
final int pageSize;
|
||||||
|
|
Loading…
Reference in a new issue