mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-19 02:43:50 +02:00
feat: add pagination
This commit is contained in:
parent
4fd823511f
commit
69bafc33e6
20 changed files with 566 additions and 193 deletions
|
@ -17,19 +17,21 @@ List<GoRoute> getCommunityChatStoryRoutes(
|
|||
path: CommunityChatUserStoryRoutes.chatScreen,
|
||||
pageBuilder: (context, state) {
|
||||
var chatScreen = ChatScreen(
|
||||
pageSize: configuration.pageSize,
|
||||
service: configuration.service,
|
||||
options: configuration.chatOptionsBuilder(context),
|
||||
onNoChats: () =>
|
||||
context.push(CommunityChatUserStoryRoutes.newChatScreen),
|
||||
onPressStartChat: () =>
|
||||
configuration.onPressStartChat?.call() ??
|
||||
context.push(CommunityChatUserStoryRoutes.newChatScreen),
|
||||
onNoChats: () async =>
|
||||
await context.push(CommunityChatUserStoryRoutes.newChatScreen),
|
||||
onPressStartChat: () async =>
|
||||
await configuration.onPressStartChat?.call() ??
|
||||
await context.push(CommunityChatUserStoryRoutes.newChatScreen),
|
||||
onPressChat: (chat) =>
|
||||
configuration.onPressChat?.call(context, chat) ??
|
||||
context.push(
|
||||
CommunityChatUserStoryRoutes.chatDetailViewPath(chat.id!)),
|
||||
onDeleteChat: (chat) =>
|
||||
configuration.onDeleteChat?.call(context, chat),
|
||||
configuration.onDeleteChat?.call(context, chat) ??
|
||||
configuration.service.deleteChat(chat),
|
||||
deleteChatDialog: configuration.deleteChatDialog,
|
||||
translations: configuration.translations,
|
||||
);
|
||||
|
@ -52,6 +54,7 @@ List<GoRoute> getCommunityChatStoryRoutes(
|
|||
var chatId = state.pathParameters['id'];
|
||||
var chat = PersonalChatModel(user: ChatUserModel(), id: chatId);
|
||||
var chatDetailScreen = ChatDetailScreen(
|
||||
pageSize: configuration.messagePageSize,
|
||||
options: configuration.chatOptionsBuilder(context),
|
||||
translations: configuration.translations,
|
||||
chatUserService: configuration.userService,
|
||||
|
@ -110,8 +113,9 @@ List<GoRoute> getCommunityChatStoryRoutes(
|
|||
);
|
||||
}
|
||||
if (context.mounted) {
|
||||
context.push(CommunityChatUserStoryRoutes.chatDetailViewPath(
|
||||
chat.id ?? ''));
|
||||
await context.push(
|
||||
CommunityChatUserStoryRoutes.chatDetailViewPath(
|
||||
chat.id ?? ''));
|
||||
}
|
||||
});
|
||||
return buildScreenWithoutTransition(
|
||||
|
|
|
@ -14,6 +14,7 @@ class CommunityChatUserStoryConfiguration {
|
|||
required this.messageService,
|
||||
required this.service,
|
||||
required this.chatOptionsBuilder,
|
||||
this.pageSize = 10,
|
||||
this.onPressStartChat,
|
||||
this.onPressChat,
|
||||
this.onDeleteChat,
|
||||
|
@ -29,6 +30,7 @@ class CommunityChatUserStoryConfiguration {
|
|||
this.chatPageBuilder,
|
||||
this.onPressChatTitle,
|
||||
this.afterMessageSent,
|
||||
this.messagePageSize = 20,
|
||||
});
|
||||
final ChatService service;
|
||||
final ChatUserService userService;
|
||||
|
@ -48,6 +50,8 @@ class CommunityChatUserStoryConfiguration {
|
|||
|
||||
/// If true, the user will be routed to the new chat screen if there are no chats.
|
||||
final bool routeToNewChatIfEmpty;
|
||||
final int pageSize;
|
||||
final int messagePageSize;
|
||||
|
||||
final Future<bool?> Function(BuildContext, ChatModel)? deleteChatDialog;
|
||||
final Function(BuildContext context, ChatModel chat)? onPressChatTitle;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_community_chat
|
||||
description: A new Flutter package project.
|
||||
version: 0.6.0
|
||||
version: 1.0.0
|
||||
|
||||
publish_to: none
|
||||
|
||||
|
@ -20,12 +20,12 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_community_chat
|
||||
path: packages/flutter_community_chat_view
|
||||
ref: 0.6.0
|
||||
ref: 1.0.0
|
||||
flutter_community_chat_interface:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_community_chat
|
||||
path: packages/flutter_community_chat_interface
|
||||
ref: 0.6.0
|
||||
ref: 1.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^2.0.0
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
sdk.dir=/Users/mikedoornenbal/Library/Android/sdk
|
||||
flutter.sdk=/opt/homebrew/Caskroom/flutter/3.10.2/flutter
|
|
@ -11,18 +11,26 @@ class FirebaseChatOptions {
|
|||
this.chatsCollectionName = 'chats',
|
||||
this.messagesCollectionName = 'messages',
|
||||
this.usersCollectionName = 'users',
|
||||
this.chatsMetaDataCollectionName = 'chat_metadata',
|
||||
this.userChatsCollectionName = 'chats',
|
||||
});
|
||||
|
||||
final String groupChatsCollectionName;
|
||||
final String chatsCollectionName;
|
||||
final String messagesCollectionName;
|
||||
final String usersCollectionName;
|
||||
final String chatsMetaDataCollectionName;
|
||||
|
||||
///This is the collection inside the user document.
|
||||
final String userChatsCollectionName;
|
||||
|
||||
FirebaseChatOptions copyWith({
|
||||
String? groupChatsCollectionName,
|
||||
String? chatsCollectionName,
|
||||
String? messagesCollectionName,
|
||||
String? usersCollectionName,
|
||||
String? chatsMetaDataCollectionName,
|
||||
String? userChatsCollectionName,
|
||||
}) {
|
||||
return FirebaseChatOptions(
|
||||
groupChatsCollectionName:
|
||||
|
@ -31,6 +39,10 @@ class FirebaseChatOptions {
|
|||
messagesCollectionName:
|
||||
messagesCollectionName ?? this.messagesCollectionName,
|
||||
usersCollectionName: usersCollectionName ?? this.usersCollectionName,
|
||||
chatsMetaDataCollectionName:
|
||||
chatsMetaDataCollectionName ?? this.chatsMetaDataCollectionName,
|
||||
userChatsCollectionName:
|
||||
userChatsCollectionName ?? this.userChatsCollectionName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@ class FirebaseChatService implements ChatService {
|
|||
late FirebaseStorage _storage;
|
||||
late ChatUserService _userService;
|
||||
late FirebaseChatOptions _options;
|
||||
DocumentSnapshot<Object?>? lastUserDocument;
|
||||
String? lastGroupId;
|
||||
List<String> chatIds = [];
|
||||
int pageNumber = 1;
|
||||
|
||||
FirebaseChatService({
|
||||
required ChatUserService userService,
|
||||
|
@ -37,7 +41,7 @@ class FirebaseChatService implements ChatService {
|
|||
var snapshots = _db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(userId)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.doc(chatId)
|
||||
.snapshots();
|
||||
|
||||
|
@ -52,7 +56,7 @@ class FirebaseChatService implements ChatService {
|
|||
Function(List<ChatModel>) onReceivedChats,
|
||||
) {
|
||||
var snapshots = _db
|
||||
.collection(_options.chatsCollectionName)
|
||||
.collection(_options.chatsMetaDataCollectionName)
|
||||
.where(
|
||||
FieldPath.documentId,
|
||||
whereIn: chatIds,
|
||||
|
@ -228,19 +232,29 @@ class FirebaseChatService implements ChatService {
|
|||
}
|
||||
|
||||
@override
|
||||
Stream<List<ChatModel>> getChatsStream() {
|
||||
Stream<List<ChatModel>> getChatsStream(int pageSize) {
|
||||
late StreamController<List<ChatModel>> controller;
|
||||
StreamSubscription? chatsSubscription;
|
||||
controller = StreamController(
|
||||
onListen: () async {
|
||||
QuerySnapshot<Map<String, dynamic>> userSnapshot;
|
||||
List<String> userChatIds;
|
||||
var currentUser = await _userService.getCurrentUser();
|
||||
|
||||
var userSnapshot = await _db
|
||||
var userQuery = _db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(currentUser?.id)
|
||||
.collection('chats')
|
||||
.get();
|
||||
var userChatIds = userSnapshot.docs.map((chat) => chat.id).toList();
|
||||
.collection(_options.userChatsCollectionName);
|
||||
if (lastUserDocument == null) {
|
||||
userSnapshot = await userQuery.limit(pageSize).get();
|
||||
userChatIds = userSnapshot.docs.map((chat) => chat.id).toList();
|
||||
} else {
|
||||
userSnapshot = await userQuery
|
||||
.limit(pageSize)
|
||||
.startAfterDocument(lastUserDocument!)
|
||||
.get();
|
||||
userChatIds = userSnapshot.docs.map((chat) => chat.id).toList();
|
||||
}
|
||||
|
||||
var userGroupChatIds = await _db
|
||||
.collection(_options.usersCollectionName)
|
||||
|
@ -248,10 +262,27 @@ class FirebaseChatService implements ChatService {
|
|||
.get()
|
||||
.then((userCollection) =>
|
||||
userCollection.data()?[_options.groupChatsCollectionName])
|
||||
.then((groupChatLabels) => groupChatLabels?.cast<String>());
|
||||
.then((groupChatLabels) => groupChatLabels?.cast<String>())
|
||||
.then((groupChatIds) {
|
||||
var startIndex = (pageNumber - 1) * pageSize;
|
||||
var endIndex = startIndex + pageSize;
|
||||
|
||||
var chatsStream =
|
||||
_getSpecificChatsStream([...userChatIds, ...userGroupChatIds]);
|
||||
if (startIndex >= groupChatIds.length) {
|
||||
return [];
|
||||
}
|
||||
var groupIds = groupChatIds.sublist(
|
||||
startIndex, endIndex.clamp(0, groupChatIds.length));
|
||||
lastGroupId = groupIds.last;
|
||||
return groupIds;
|
||||
});
|
||||
|
||||
if (userSnapshot.docs.isNotEmpty) {
|
||||
lastUserDocument = userSnapshot.docs.last;
|
||||
}
|
||||
|
||||
pageNumber++;
|
||||
chatIds.addAll([...userChatIds, ...userGroupChatIds]);
|
||||
var chatsStream = _getSpecificChatsStream(chatIds);
|
||||
|
||||
chatsSubscription = chatsStream.listen((event) {
|
||||
controller.add(event);
|
||||
|
@ -270,7 +301,7 @@ class FirebaseChatService implements ChatService {
|
|||
var collection = await _db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(currentUser?.id)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.where('users', arrayContains: user.id)
|
||||
.get();
|
||||
|
||||
|
@ -288,7 +319,7 @@ class FirebaseChatService implements ChatService {
|
|||
var chatCollection = await _db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(currentUser?.id)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.doc(chatId)
|
||||
.get();
|
||||
|
||||
|
@ -333,7 +364,7 @@ class FirebaseChatService implements ChatService {
|
|||
@override
|
||||
Future<void> deleteChat(ChatModel chat) async {
|
||||
var chatCollection = await _db
|
||||
.collection(_options.chatsCollectionName)
|
||||
.collection(_options.chatsMetaDataCollectionName)
|
||||
.doc(chat.id)
|
||||
.withConverter(
|
||||
fromFirestore: (snapshot, _) =>
|
||||
|
@ -349,7 +380,7 @@ class FirebaseChatService implements ChatService {
|
|||
_db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(userId)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.doc(chat.id)
|
||||
.delete();
|
||||
}
|
||||
|
@ -387,7 +418,7 @@ class FirebaseChatService implements ChatService {
|
|||
];
|
||||
|
||||
var reference = await _db
|
||||
.collection(_options.chatsCollectionName)
|
||||
.collection(_options.chatsMetaDataCollectionName)
|
||||
.withConverter(
|
||||
fromFirestore: (snapshot, _) =>
|
||||
FirebaseChatDocument.fromJson(snapshot.data()!, snapshot.id),
|
||||
|
@ -406,12 +437,13 @@ class FirebaseChatService implements ChatService {
|
|||
await _db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(userId)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.doc(reference.id)
|
||||
.set({'users': userIds});
|
||||
}
|
||||
|
||||
chat.id = reference.id;
|
||||
chatIds.add(chat.id!);
|
||||
} else if (chat is GroupChatModel) {
|
||||
if (currentUser?.id == null) {
|
||||
return chat;
|
||||
|
@ -448,6 +480,7 @@ class FirebaseChatService implements ChatService {
|
|||
}
|
||||
|
||||
chat.id = reference.id;
|
||||
chatIds.add(chat.id!);
|
||||
} else {
|
||||
throw Exception('Chat type not supported for firebase');
|
||||
}
|
||||
|
@ -467,7 +500,7 @@ class FirebaseChatService implements ChatService {
|
|||
var userSnapshot = _db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(currentUser?.id)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.snapshots();
|
||||
|
||||
unreadChatSubscription = userSnapshot.listen((event) {
|
||||
|
@ -498,7 +531,7 @@ class FirebaseChatService implements ChatService {
|
|||
await _db
|
||||
.collection(_options.usersCollectionName)
|
||||
.doc(currentUser!.id!)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.doc(chat.id)
|
||||
.set({'amount_unread_messages': 0}, SetOptions(merge: true));
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ class FirebaseMessageService implements MessageService {
|
|||
|
||||
StreamController<List<ChatMessageModel>>? _controller;
|
||||
StreamSubscription<QuerySnapshot>? _subscription;
|
||||
DocumentSnapshot<Object>? lastMessage;
|
||||
List<ChatMessageModel> _cumulativeMessages = [];
|
||||
ChatModel? lastChat;
|
||||
int? chatPageSize;
|
||||
|
||||
FirebaseMessageService({
|
||||
required ChatUserService userService,
|
||||
|
@ -60,7 +64,13 @@ class FirebaseMessageService implements MessageService {
|
|||
)
|
||||
.add(message);
|
||||
|
||||
await chatReference.update({
|
||||
var metadataReference = _db
|
||||
.collection(
|
||||
_options.chatsMetaDataCollectionName,
|
||||
)
|
||||
.doc(chat.id);
|
||||
|
||||
await metadataReference.update({
|
||||
'last_used': DateTime.now(),
|
||||
'last_message': message,
|
||||
});
|
||||
|
@ -76,7 +86,7 @@ class FirebaseMessageService implements MessageService {
|
|||
// update the chat counter for the other users
|
||||
// get all users from the chat
|
||||
// there is a field in the chat document called users that has a list of user ids
|
||||
var fetchedChat = await chatReference.get();
|
||||
var fetchedChat = await metadataReference.get();
|
||||
var chatUsers = fetchedChat.data()?['users'] as List<dynamic>;
|
||||
// for all users except the message sender update the unread counter
|
||||
for (var userId in chatUsers) {
|
||||
|
@ -86,7 +96,7 @@ class FirebaseMessageService implements MessageService {
|
|||
_options.usersCollectionName,
|
||||
)
|
||||
.doc(userId)
|
||||
.collection('chats')
|
||||
.collection(_options.userChatsCollectionName)
|
||||
.doc(chat.id);
|
||||
// what if the amount_unread_messages field does not exist?
|
||||
// it should be created when the chat is create
|
||||
|
@ -110,13 +120,14 @@ class FirebaseMessageService implements MessageService {
|
|||
Future<void> sendTextMessage({
|
||||
required String text,
|
||||
required ChatModel chat,
|
||||
}) =>
|
||||
_sendMessage(
|
||||
chat,
|
||||
{
|
||||
'text': text,
|
||||
},
|
||||
);
|
||||
}) {
|
||||
return _sendMessage(
|
||||
chat,
|
||||
{
|
||||
'text': text,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> sendImageMessage({
|
||||
|
@ -144,19 +155,42 @@ class FirebaseMessageService implements MessageService {
|
|||
);
|
||||
}
|
||||
|
||||
Query<FirebaseMessageDocument> _getMessagesQuery(ChatModel chat) => _db
|
||||
.collection(_options.chatsCollectionName)
|
||||
.doc(chat.id)
|
||||
.collection(_options.messagesCollectionName)
|
||||
.orderBy('timestamp', descending: false)
|
||||
.withConverter<FirebaseMessageDocument>(
|
||||
Query<FirebaseMessageDocument> _getMessagesQuery(ChatModel chat) {
|
||||
if (lastChat == null) {
|
||||
lastChat = chat;
|
||||
} else if (lastChat?.id != chat.id) {
|
||||
_cumulativeMessages = [];
|
||||
lastChat = chat;
|
||||
lastMessage = null;
|
||||
}
|
||||
|
||||
var query = _db
|
||||
.collection(_options.chatsCollectionName)
|
||||
.doc(chat.id)
|
||||
.collection(_options.messagesCollectionName)
|
||||
.orderBy('timestamp', descending: true)
|
||||
.limit(chatPageSize!);
|
||||
|
||||
if (lastMessage == null) {
|
||||
return query.withConverter<FirebaseMessageDocument>(
|
||||
fromFirestore: (snapshot, _) =>
|
||||
FirebaseMessageDocument.fromJson(snapshot.data()!, snapshot.id),
|
||||
toFirestore: (user, _) => user.toJson(),
|
||||
);
|
||||
}
|
||||
return query
|
||||
.startAfterDocument(lastMessage!)
|
||||
.withConverter<FirebaseMessageDocument>(
|
||||
fromFirestore: (snapshot, _) =>
|
||||
FirebaseMessageDocument.fromJson(snapshot.data()!, snapshot.id),
|
||||
toFirestore: (user, _) => user.toJson(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<ChatMessageModel>> getMessagesStream(ChatModel chat) {
|
||||
Stream<List<ChatMessageModel>> getMessagesStream(
|
||||
ChatModel chat, int pageSize) {
|
||||
chatPageSize = pageSize;
|
||||
_controller = StreamController<List<ChatMessageModel>>(
|
||||
onListen: () {
|
||||
if (chat.id != null) {
|
||||
|
@ -175,39 +209,54 @@ class FirebaseMessageService implements MessageService {
|
|||
|
||||
StreamSubscription<QuerySnapshot> _startListeningForMessages(ChatModel chat) {
|
||||
debugPrint('Start listening for messages in chat ${chat.id}');
|
||||
|
||||
var snapshots = _getMessagesQuery(chat).snapshots();
|
||||
|
||||
return snapshots.listen(
|
||||
(snapshot) async {
|
||||
var messages = <ChatMessageModel>[];
|
||||
List<ChatMessageModel> messages =
|
||||
List<ChatMessageModel>.from(_cumulativeMessages);
|
||||
|
||||
for (var messageDoc in snapshot.docs) {
|
||||
var messageData = messageDoc.data();
|
||||
if (snapshot.docs.isNotEmpty) {
|
||||
lastMessage = snapshot.docs.last;
|
||||
|
||||
var sender = await _userService.getUser(messageData.sender);
|
||||
for (var messageDoc in snapshot.docs) {
|
||||
var messageData = messageDoc.data();
|
||||
|
||||
if (sender != null) {
|
||||
var timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||
(messageData.timestamp).millisecondsSinceEpoch,
|
||||
);
|
||||
// Check if the message is already in the list to avoid duplicates
|
||||
if (!messages.any((message) {
|
||||
var timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||
(messageData.timestamp).millisecondsSinceEpoch,
|
||||
);
|
||||
return timestamp == message.timestamp;
|
||||
})) {
|
||||
var sender = await _userService.getUser(messageData.sender);
|
||||
|
||||
messages.add(
|
||||
messageData.imageUrl != null
|
||||
? ChatImageMessageModel(
|
||||
sender: sender,
|
||||
imageUrl: messageData.imageUrl!,
|
||||
timestamp: timestamp,
|
||||
)
|
||||
: ChatTextMessageModel(
|
||||
sender: sender,
|
||||
text: messageData.text!,
|
||||
timestamp: timestamp,
|
||||
),
|
||||
);
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_cumulativeMessages = messages;
|
||||
|
||||
messages.sort((a, b) => a.timestamp.compareTo(b.timestamp));
|
||||
|
||||
_controller?.add(messages);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_community_chat_firebase
|
||||
description: A new Flutter package project.
|
||||
version: 0.6.0
|
||||
version: 1.0.0
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
@ -23,7 +23,7 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_community_chat
|
||||
path: packages/flutter_community_chat_interface
|
||||
ref: 0.6.0
|
||||
ref: 1.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^2.0.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter_community_chat_interface/flutter_community_chat_interface.dart';
|
||||
|
||||
abstract class ChatService {
|
||||
Stream<List<ChatModel>> getChatsStream();
|
||||
Stream<List<ChatModel>> getChatsStream(int pageSize);
|
||||
Future<ChatModel> getChatByUser(ChatUserModel user);
|
||||
Future<ChatModel> getChatById(String id);
|
||||
Future<void> deleteChat(ChatModel chat);
|
||||
|
|
|
@ -14,5 +14,6 @@ abstract class MessageService {
|
|||
|
||||
Stream<List<ChatMessageModel>> getMessagesStream(
|
||||
ChatModel chat,
|
||||
int pageSize,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_community_chat_interface
|
||||
description: A new Flutter package project.
|
||||
version: 0.6.0
|
||||
version: 1.0.0
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=/opt/homebrew/Caskroom/flutter/3.10.2/flutter
|
||||
FLUTTER_APPLICATION_PATH=/Users/mikedoornenbal/Documents/iconica/flutter_community_chat/packages/flutter_community_chat_view
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_TARGET=lib/main.dart
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=0.6.0
|
||||
FLUTTER_BUILD_NUMBER=0.6.0
|
||||
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
|
||||
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
PACKAGE_CONFIG=.dart_tool/package_config.json
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/opt/homebrew/Caskroom/flutter/3.10.2/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/mikedoornenbal/Documents/iconica/flutter_community_chat/packages/flutter_community_chat_view"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_TARGET=lib/main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=0.6.0"
|
||||
export "FLUTTER_BUILD_NUMBER=0.6.0"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
export "PACKAGE_CONFIG=.dart_tool/package_config.json"
|
41
packages/flutter_community_chat_view/ios/Podfile
Normal file
41
packages/flutter_community_chat_view/ios/Podfile
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GeneratedPluginRegistrant_h
|
||||
#define GeneratedPluginRegistrant_h
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GeneratedPluginRegistrant : NSObject
|
||||
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
#endif /* GeneratedPluginRegistrant_h */
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
|
||||
#if __has_include(<cloud_firestore/FLTFirebaseFirestorePlugin.h>)
|
||||
#import <cloud_firestore/FLTFirebaseFirestorePlugin.h>
|
||||
#else
|
||||
@import cloud_firestore;
|
||||
#endif
|
||||
|
||||
#if __has_include(<firebase_auth/FLTFirebaseAuthPlugin.h>)
|
||||
#import <firebase_auth/FLTFirebaseAuthPlugin.h>
|
||||
#else
|
||||
@import firebase_auth;
|
||||
#endif
|
||||
|
||||
#if __has_include(<firebase_core/FLTFirebaseCorePlugin.h>)
|
||||
#import <firebase_core/FLTFirebaseCorePlugin.h>
|
||||
#else
|
||||
@import firebase_core;
|
||||
#endif
|
||||
|
||||
#if __has_include(<firebase_storage/FLTFirebaseStoragePlugin.h>)
|
||||
#import <firebase_storage/FLTFirebaseStoragePlugin.h>
|
||||
#else
|
||||
@import firebase_storage;
|
||||
#endif
|
||||
|
||||
#if __has_include(<image_picker_ios/FLTImagePickerPlugin.h>)
|
||||
#import <image_picker_ios/FLTImagePickerPlugin.h>
|
||||
#else
|
||||
@import image_picker_ios;
|
||||
#endif
|
||||
|
||||
#if __has_include(<path_provider_foundation/PathProviderPlugin.h>)
|
||||
#import <path_provider_foundation/PathProviderPlugin.h>
|
||||
#else
|
||||
@import path_provider_foundation;
|
||||
#endif
|
||||
|
||||
#if __has_include(<sqflite/SqflitePlugin.h>)
|
||||
#import <sqflite/SqflitePlugin.h>
|
||||
#else
|
||||
@import sqflite;
|
||||
#endif
|
||||
|
||||
@implementation GeneratedPluginRegistrant
|
||||
|
||||
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
|
||||
[FLTFirebaseFirestorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseFirestorePlugin"]];
|
||||
[FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]];
|
||||
[FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]];
|
||||
[FLTFirebaseStoragePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseStoragePlugin"]];
|
||||
[FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]];
|
||||
[PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]];
|
||||
[SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]];
|
||||
}
|
||||
|
||||
@end
|
|
@ -6,6 +6,7 @@ import 'dart:async';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_community_chat_view/flutter_community_chat_view.dart';
|
||||
import 'package:flutter_community_chat_view/src/components/chat_bottom.dart';
|
||||
import 'package:flutter_community_chat_view/src/components/chat_detail_row.dart';
|
||||
|
@ -20,6 +21,7 @@ class ChatDetailScreen extends StatefulWidget {
|
|||
required this.service,
|
||||
required this.chatUserService,
|
||||
required this.messageService,
|
||||
required this.pageSize,
|
||||
this.translations = const ChatTranslations(),
|
||||
this.chat,
|
||||
this.onPressChatTitle,
|
||||
|
@ -47,6 +49,7 @@ class ChatDetailScreen extends StatefulWidget {
|
|||
final ChatService service;
|
||||
final ChatUserService chatUserService;
|
||||
final MessageService messageService;
|
||||
final int pageSize;
|
||||
|
||||
@override
|
||||
State<ChatDetailScreen> createState() => _ChatDetailScreenState();
|
||||
|
@ -58,6 +61,8 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
Stream<List<ChatMessageModel>>? _chatMessages;
|
||||
ChatModel? chat;
|
||||
ChatUserModel? currentUser;
|
||||
ScrollController controller = ScrollController();
|
||||
bool showIndicator = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -65,7 +70,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
// create a broadcast stream from the chat messages
|
||||
if (widget.chat != null) {
|
||||
_chatMessages = widget.messageService
|
||||
.getMessagesStream(widget.chat!)
|
||||
.getMessagesStream(widget.chat!, widget.pageSize)
|
||||
.asBroadcastStream();
|
||||
}
|
||||
_chatMessagesSubscription = _chatMessages?.listen((event) {
|
||||
|
@ -121,7 +126,6 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
future: widget.service.getChatById(widget.chat?.id ?? ''),
|
||||
builder: (context, AsyncSnapshot<ChatModel> snapshot) {
|
||||
var chatModel = snapshot.data;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
|
@ -186,11 +190,44 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
);
|
||||
previousMessage = message;
|
||||
}
|
||||
return Listener(
|
||||
onPointerMove: (event) {
|
||||
var isTop = controller.position.pixels ==
|
||||
controller.position.maxScrollExtent;
|
||||
|
||||
return ListView(
|
||||
reverse: true,
|
||||
padding: const EdgeInsets.only(top: 24.0),
|
||||
children: messageWidgets.reversed.toList(),
|
||||
if (showIndicator == false &&
|
||||
isTop &&
|
||||
!(controller.position.userScrollDirection ==
|
||||
ScrollDirection.reverse)) {
|
||||
setState(() {
|
||||
showIndicator = true;
|
||||
});
|
||||
_chatMessages = widget.messageService
|
||||
.getMessagesStream(widget.chat!, widget.pageSize)
|
||||
.asBroadcastStream();
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
showIndicator = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
child: ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: controller,
|
||||
reverse: true,
|
||||
padding: const EdgeInsets.only(top: 24.0),
|
||||
children: [
|
||||
...messageWidgets.reversed.toList(),
|
||||
if (snapshot.connectionState !=
|
||||
ConnectionState.active ||
|
||||
showIndicator) ...[
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_community_chat_view/flutter_community_chat_view.dart';
|
||||
import 'package:flutter_community_chat_view/src/services/date_formatter.dart';
|
||||
|
||||
|
@ -15,6 +18,7 @@ class ChatScreen extends StatefulWidget {
|
|||
required this.onPressChat,
|
||||
required this.onDeleteChat,
|
||||
required this.service,
|
||||
required this.pageSize,
|
||||
this.onNoChats,
|
||||
this.deleteChatDialog,
|
||||
this.translations = const ChatTranslations(),
|
||||
|
@ -25,10 +29,11 @@ class ChatScreen extends StatefulWidget {
|
|||
final ChatOptions options;
|
||||
final ChatTranslations translations;
|
||||
final ChatService service;
|
||||
final VoidCallback? onPressStartChat;
|
||||
final VoidCallback? onNoChats;
|
||||
final Function? onPressStartChat;
|
||||
final Function? onNoChats;
|
||||
final void Function(ChatModel chat) onDeleteChat;
|
||||
final void Function(ChatModel chat) onPressChat;
|
||||
final int pageSize;
|
||||
|
||||
/// Disable the swipe to dismiss feature for chats that are not deletable
|
||||
final bool disableDismissForPermanentChats;
|
||||
|
@ -42,6 +47,28 @@ class ChatScreen extends StatefulWidget {
|
|||
class _ChatScreenState extends State<ChatScreen> {
|
||||
final DateFormatter _dateFormatter = DateFormatter();
|
||||
bool _hasCalledOnNoChats = false;
|
||||
ScrollController controller = ScrollController();
|
||||
bool showIndicator = false;
|
||||
Stream<List<ChatModel>>? chats;
|
||||
List<String> deletedChats = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
getChats();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void getChats() {
|
||||
setState(() {
|
||||
chats = widget.service.getChatsStream(widget.pageSize);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -72,145 +99,197 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.only(top: 15.0),
|
||||
children: [
|
||||
StreamBuilder<List<ChatModel>>(
|
||||
stream: widget.service.getChatsStream(),
|
||||
builder: (BuildContext context, snapshot) {
|
||||
// if the stream is done, empty and noChats is set we should call that
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
(snapshot.data?.isEmpty ?? true)) {
|
||||
if (widget.onNoChats != null && !_hasCalledOnNoChats) {
|
||||
_hasCalledOnNoChats = true; // Set the flag to true
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.onNoChats!.call();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_hasCalledOnNoChats =
|
||||
false; // Reset the flag if there are chats
|
||||
child: Listener(
|
||||
onPointerMove: (event) {
|
||||
var isTop = controller.position.pixels ==
|
||||
controller.position.maxScrollExtent;
|
||||
|
||||
if (showIndicator == false &&
|
||||
!isTop &&
|
||||
controller.position.userScrollDirection ==
|
||||
ScrollDirection.reverse) {
|
||||
setState(() {
|
||||
showIndicator = true;
|
||||
});
|
||||
getChats();
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
showIndicator = false;
|
||||
});
|
||||
}
|
||||
return Column(
|
||||
children: [
|
||||
for (ChatModel chat in snapshot.data ?? []) ...[
|
||||
Builder(
|
||||
builder: (context) => !(widget
|
||||
.disableDismissForPermanentChats &&
|
||||
!chat.canBeDeleted)
|
||||
? Dismissible(
|
||||
confirmDismiss: (_) =>
|
||||
widget.deleteChatDialog
|
||||
?.call(context, chat) ??
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
chat.canBeDeleted
|
||||
? translations
|
||||
.deleteChatModalTitle
|
||||
: translations
|
||||
.chatCantBeDeleted,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (chat.canBeDeleted)
|
||||
});
|
||||
}
|
||||
},
|
||||
child: ListView(
|
||||
controller: controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.only(top: 15.0),
|
||||
children: [
|
||||
StreamBuilder<List<ChatModel>>(
|
||||
stream: chats,
|
||||
builder: (BuildContext context, snapshot) {
|
||||
// if the stream is done, empty and noChats is set we should call that
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
(snapshot.data?.isEmpty ?? true)) {
|
||||
if (widget.onNoChats != null && !_hasCalledOnNoChats) {
|
||||
_hasCalledOnNoChats = true; // Set the flag to true
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) async {
|
||||
await widget.onNoChats!.call();
|
||||
getChats();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_hasCalledOnNoChats =
|
||||
false; // Reset the flag if there are chats
|
||||
}
|
||||
return Column(
|
||||
children: [
|
||||
for (ChatModel chat in (snapshot.data ?? []).where(
|
||||
(chat) => !deletedChats.contains(chat.id),
|
||||
)) ...[
|
||||
Builder(
|
||||
builder: (context) => !(widget
|
||||
.disableDismissForPermanentChats &&
|
||||
!chat.canBeDeleted)
|
||||
? Dismissible(
|
||||
confirmDismiss: (_) async =>
|
||||
widget.deleteChatDialog
|
||||
?.call(context, chat) ??
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
translations
|
||||
.deleteChatModalDescription,
|
||||
chat.canBeDeleted
|
||||
? translations
|
||||
.deleteChatModalTitle
|
||||
: translations
|
||||
.chatCantBeDeleted,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontSize: 20,
|
||||
fontWeight:
|
||||
FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
translations
|
||||
.deleteChatModalCancel,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (chat.canBeDeleted)
|
||||
Text(
|
||||
translations
|
||||
.deleteChatModalDescription,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(context)
|
||||
.pop(false),
|
||||
),
|
||||
if (chat.canBeDeleted)
|
||||
ElevatedButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(true),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
translations
|
||||
.deleteChatModalConfirm,
|
||||
.deleteChatModalCancel,
|
||||
style:
|
||||
const TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(false),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
if (chat.canBeDeleted)
|
||||
ElevatedButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(true),
|
||||
child: Text(
|
||||
translations
|
||||
.deleteChatModalConfirm,
|
||||
style:
|
||||
const TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onDismissed: (_) {
|
||||
setState(() {
|
||||
deletedChats.add(chat.id!);
|
||||
});
|
||||
widget.onDeleteChat(chat);
|
||||
},
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
translations.deleteChatButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
onDismissed: (_) =>
|
||||
widget.onDeleteChat(chat),
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
translations.deleteChatButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
key: ValueKey(
|
||||
chat.id.toString(),
|
||||
),
|
||||
child: ChatListItem(
|
||||
key: ValueKey(
|
||||
chat.id.toString(),
|
||||
),
|
||||
child: ChatListItem(
|
||||
widget: widget,
|
||||
chat: chat,
|
||||
translations: translations,
|
||||
dateFormatter: _dateFormatter,
|
||||
),
|
||||
)
|
||||
: ChatListItem(
|
||||
widget: widget,
|
||||
chat: chat,
|
||||
translations: translations,
|
||||
dateFormatter: _dateFormatter,
|
||||
),
|
||||
)
|
||||
: ChatListItem(
|
||||
widget: widget,
|
||||
chat: chat,
|
||||
translations: translations,
|
||||
dateFormatter: _dateFormatter,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (showIndicator &&
|
||||
snapshot.connectionState !=
|
||||
ConnectionState.done) ...[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.onPressStartChat != null)
|
||||
widget.options.newChatButtonBuilder(
|
||||
context,
|
||||
widget.onPressStartChat!,
|
||||
() async {
|
||||
await widget.onPressStartChat!.call();
|
||||
getChats();
|
||||
},
|
||||
translations,
|
||||
),
|
||||
],
|
||||
|
|
|
@ -122,7 +122,9 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||
title: user.fullName ?? widget.translations.anonymousUser,
|
||||
),
|
||||
),
|
||||
onTap: () => widget.onPressCreateChat(user),
|
||||
onTap: () async {
|
||||
await widget.onPressCreateChat(user);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_community_chat_view
|
||||
description: A standard flutter package.
|
||||
version: 0.6.0
|
||||
version: 1.0.0
|
||||
|
||||
publish_to: none
|
||||
|
||||
|
@ -20,7 +20,7 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_community_chat
|
||||
path: packages/flutter_community_chat_interface
|
||||
ref: 0.6.0
|
||||
ref: 1.0.0
|
||||
cached_network_image: ^3.2.2
|
||||
flutter_image_picker:
|
||||
git:
|
||||
|
|
Loading…
Reference in a new issue