Merge pull request #68 from Iconica-Development/2.0.0

Improve flutter_chat for usage in safino
This commit is contained in:
Gorter-dev 2024-05-29 15:37:26 +02:00 committed by GitHub
commit 3d3153d2ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 263 additions and 99 deletions

View file

@ -12,3 +12,4 @@ jobs:
permissions: write-all permissions: write-all
with: with:
subfolder: '.' # add optional subfolder to run workflow in subfolder: '.' # add optional subfolder to run workflow in
flutter_version: 3.19.6

View file

@ -1,3 +1,14 @@
## 2.0.0
- Add a serviceBuilder to the userstory configuration
- Add a translationsBuilder to the userstory configuration
- Change onPressUserProfile callback to use a ChatUserModel instead of a String
- Add a enableGroupChatCreation boolean to the userstory configuration to enable or disable group chat creation
- Change the ChatTranslations constructor to require all translations or use the ChatTranslations.empty constructor if you don't want to specify all translations
- Remove the Divider between the users on the new chat screen
- Add option to set a custom padding around the list of chats
- Fix nullpointer when firstWhere returns null because there is only 1 person in a groupchat
## 1.4.3 ## 1.4.3
- Added default styling. - Added default styling.

View file

@ -4,7 +4,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_chat/flutter_chat.dart'; import 'package:flutter_chat/flutter_chat.dart';
import 'package:uuid/uuid.dart';
/// Navigates to the chat user story screen. /// Navigates to the chat user story screen.
/// ///
@ -96,9 +95,9 @@ Widget _chatDetailScreenRoute(
service: configuration.chatService, service: configuration.chatService,
chatId: chatId, chatId: chatId,
textfieldBottomPadding: configuration.textfieldBottomPadding ?? 0, textfieldBottomPadding: configuration.textfieldBottomPadding ?? 0,
onPressUserProfile: (userId) async { onPressUserProfile: (user) async {
if (configuration.onPressUserProfile != null) { if (configuration.onPressUserProfile != null) {
return configuration.onPressUserProfile?.call(); return configuration.onPressUserProfile?.call(context, user);
} }
return Navigator.of(context).push( return Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
@ -106,7 +105,7 @@ Widget _chatDetailScreenRoute(
configuration, configuration,
context, context,
chatId, chatId,
userId, user.id,
), ),
), ),
); );
@ -172,7 +171,7 @@ Widget _chatProfileScreenRoute(
userId: userId, userId: userId,
onTapUser: (user) async { onTapUser: (user) async {
if (configuration.onPressUserProfile != null) { if (configuration.onPressUserProfile != null) {
return configuration.onPressUserProfile!.call(); return configuration.onPressUserProfile!.call(context, user);
} }
return Navigator.of(context).push( return Navigator.of(context).push(
@ -200,6 +199,7 @@ Widget _newChatScreenRoute(
options: configuration.chatOptionsBuilder(context), options: configuration.chatOptionsBuilder(context),
translations: configuration.translations, translations: configuration.translations,
service: configuration.chatService, service: configuration.chatService,
showGroupChatButton: configuration.enableGroupChatCreation,
onPressCreateGroupChat: () async { onPressCreateGroupChat: () async {
configuration.onPressCreateGroupChat?.call(); configuration.onPressCreateGroupChat?.call();
if (context.mounted) { if (context.mounted) {

View file

@ -14,9 +14,11 @@ List<GoRoute> getChatStoryRoutes(
GoRoute( GoRoute(
path: ChatUserStoryRoutes.chatScreen, path: ChatUserStoryRoutes.chatScreen,
pageBuilder: (context, state) { pageBuilder: (context, state) {
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var chatScreen = ChatScreen( var chatScreen = ChatScreen(
unreadMessageTextStyle: configuration.unreadMessageTextStyle, unreadMessageTextStyle: configuration.unreadMessageTextStyle,
service: configuration.chatService, service: service,
options: configuration.chatOptionsBuilder(context), options: configuration.chatOptionsBuilder(context),
onNoChats: () async => onNoChats: () async =>
context.push(ChatUserStoryRoutes.newChatScreen), context.push(ChatUserStoryRoutes.newChatScreen),
@ -34,7 +36,8 @@ List<GoRoute> getChatStoryRoutes(
configuration.onDeleteChat?.call(context, chat) ?? configuration.onDeleteChat?.call(context, chat) ??
configuration.chatService.chatOverviewService.deleteChat(chat), configuration.chatService.chatOverviewService.deleteChat(chat),
deleteChatDialog: configuration.deleteChatDialog, deleteChatDialog: configuration.deleteChatDialog,
translations: configuration.translations, translations: configuration.translationsBuilder?.call(context) ??
configuration.translations,
); );
return buildScreenWithoutTransition( return buildScreenWithoutTransition(
context: context, context: context,
@ -53,6 +56,8 @@ List<GoRoute> getChatStoryRoutes(
path: ChatUserStoryRoutes.chatDetailScreen, path: ChatUserStoryRoutes.chatDetailScreen,
pageBuilder: (context, state) { pageBuilder: (context, state) {
var chatId = state.pathParameters['id']; var chatId = state.pathParameters['id'];
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var chatDetailScreen = ChatDetailScreen( var chatDetailScreen = ChatDetailScreen(
chatTitleBuilder: configuration.chatTitleBuilder, chatTitleBuilder: configuration.chatTitleBuilder,
usernameBuilder: configuration.usernameBuilder, usernameBuilder: configuration.usernameBuilder,
@ -60,16 +65,17 @@ List<GoRoute> getChatStoryRoutes(
iconDisabledColor: configuration.iconDisabledColor, iconDisabledColor: configuration.iconDisabledColor,
pageSize: configuration.messagePageSize, pageSize: configuration.messagePageSize,
options: configuration.chatOptionsBuilder(context), options: configuration.chatOptionsBuilder(context),
translations: configuration.translations, translations: configuration.translationsBuilder?.call(context) ??
service: configuration.chatService, configuration.translations,
service: service,
chatId: chatId!, chatId: chatId!,
textfieldBottomPadding: configuration.textfieldBottomPadding ?? 0, textfieldBottomPadding: configuration.textfieldBottomPadding ?? 0,
onPressUserProfile: (userId) async { onPressUserProfile: (user) async {
if (configuration.onPressUserProfile != null) { if (configuration.onPressUserProfile != null) {
return configuration.onPressUserProfile?.call(); return configuration.onPressUserProfile?.call(context, user);
} }
return context.push( return context.push(
ChatUserStoryRoutes.chatProfileScreenPath(chatId, userId), ChatUserStoryRoutes.chatProfileScreenPath(chatId, user.id),
); );
}, },
onMessageSubmit: (message) async { onMessageSubmit: (message) async {
@ -120,10 +126,14 @@ List<GoRoute> getChatStoryRoutes(
GoRoute( GoRoute(
path: ChatUserStoryRoutes.newChatScreen, path: ChatUserStoryRoutes.newChatScreen,
pageBuilder: (context, state) { pageBuilder: (context, state) {
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var newChatScreen = NewChatScreen( var newChatScreen = NewChatScreen(
options: configuration.chatOptionsBuilder(context), options: configuration.chatOptionsBuilder(context),
translations: configuration.translations, translations: configuration.translationsBuilder?.call(context) ??
service: configuration.chatService, configuration.translations,
service: service,
showGroupChatButton: configuration.enableGroupChatCreation,
onPressCreateChat: (user) async { onPressCreateChat: (user) async {
configuration.onPressCreateChat?.call(user); configuration.onPressCreateChat?.call(user);
if (configuration.onPressCreateChat != null) return; if (configuration.onPressCreateChat != null) return;
@ -163,10 +173,13 @@ List<GoRoute> getChatStoryRoutes(
GoRoute( GoRoute(
path: ChatUserStoryRoutes.newGroupChatScreen, path: ChatUserStoryRoutes.newGroupChatScreen,
pageBuilder: (context, state) { pageBuilder: (context, state) {
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var newGroupChatScreen = NewGroupChatScreen( var newGroupChatScreen = NewGroupChatScreen(
options: configuration.chatOptionsBuilder(context), options: configuration.chatOptionsBuilder(context),
translations: configuration.translations, translations: configuration.translationsBuilder?.call(context) ??
service: configuration.chatService, configuration.translations,
service: service,
onPressGroupChatOverview: (users) async => context.push( onPressGroupChatOverview: (users) async => context.push(
ChatUserStoryRoutes.newGroupChatOverviewScreen, ChatUserStoryRoutes.newGroupChatOverviewScreen,
extra: users, extra: users,
@ -188,11 +201,14 @@ List<GoRoute> getChatStoryRoutes(
GoRoute( GoRoute(
path: ChatUserStoryRoutes.newGroupChatOverviewScreen, path: ChatUserStoryRoutes.newGroupChatOverviewScreen,
pageBuilder: (context, state) { pageBuilder: (context, state) {
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var users = state.extra! as List<ChatUserModel>; var users = state.extra! as List<ChatUserModel>;
var newGroupChatOverviewScreen = NewGroupChatOverviewScreen( var newGroupChatOverviewScreen = NewGroupChatOverviewScreen(
options: configuration.chatOptionsBuilder(context), options: configuration.chatOptionsBuilder(context),
translations: configuration.translations, translations: configuration.translationsBuilder?.call(context) ??
service: configuration.chatService, configuration.translations,
service: service,
users: users, users: users,
onPressCompleteGroupChatCreation: (users, groupChatName) async { onPressCompleteGroupChatCreation: (users, groupChatName) async {
configuration.onPressCompleteGroupChatCreation configuration.onPressCompleteGroupChatCreation
@ -232,18 +248,21 @@ List<GoRoute> getChatStoryRoutes(
var chatId = state.pathParameters['id']; var chatId = state.pathParameters['id'];
var userId = state.pathParameters['userId']; var userId = state.pathParameters['userId'];
var id = userId == 'null' ? null : userId; var id = userId == 'null' ? null : userId;
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var profileScreen = ChatProfileScreen( var profileScreen = ChatProfileScreen(
translations: configuration.translations, translations: configuration.translationsBuilder?.call(context) ??
chatService: configuration.chatService, configuration.translations,
chatService: service,
chatId: chatId!, chatId: chatId!,
userId: id, userId: id,
onTapUser: (user) async { onTapUser: (user) async {
if (configuration.onPressUserProfile != null) { if (configuration.onPressUserProfile != null) {
return configuration.onPressUserProfile!.call(); return configuration.onPressUserProfile!.call(context, user);
} }
return context.push( return context.push(
ChatUserStoryRoutes.chatProfileScreenPath(chatId, user), ChatUserStoryRoutes.chatProfileScreenPath(chatId, user.id),
); );
}, },
); );

View file

@ -14,6 +14,7 @@ class ChatUserStoryConfiguration {
const ChatUserStoryConfiguration({ const ChatUserStoryConfiguration({
required this.chatService, required this.chatService,
required this.chatOptionsBuilder, required this.chatOptionsBuilder,
this.chatServiceBuilder,
this.onPressStartChat, this.onPressStartChat,
this.onPressChat, this.onPressChat,
this.onDeleteChat, this.onDeleteChat,
@ -27,7 +28,9 @@ class ChatUserStoryConfiguration {
this.deleteChatDialog, this.deleteChatDialog,
this.disableDismissForPermanentChats = false, this.disableDismissForPermanentChats = false,
this.routeToNewChatIfEmpty = true, this.routeToNewChatIfEmpty = true,
this.translations = const ChatTranslations(), this.enableGroupChatCreation = true,
this.translations = const ChatTranslations.empty(),
this.translationsBuilder,
this.chatPageBuilder, this.chatPageBuilder,
this.onPressChatTitle, this.onPressChatTitle,
this.afterMessageSent, this.afterMessageSent,
@ -44,6 +47,9 @@ class ChatUserStoryConfiguration {
/// The service responsible for handling chat-related functionalities. /// The service responsible for handling chat-related functionalities.
final ChatService chatService; final ChatService chatService;
/// A method to get the chat service only when needed and with a context.
final ChatService Function(BuildContext context)? chatServiceBuilder;
/// Callback function triggered when a chat is pressed. /// Callback function triggered when a chat is pressed.
final Function(BuildContext, ChatModel)? onPressChat; final Function(BuildContext, ChatModel)? onPressChat;
@ -53,6 +59,9 @@ class ChatUserStoryConfiguration {
/// Translations for internationalization/localization support. /// Translations for internationalization/localization support.
final ChatTranslations translations; final ChatTranslations translations;
/// Translations builder because context might be needed for translations.
final ChatTranslations Function(BuildContext context)? translationsBuilder;
/// Determines whether dismissing is disabled for permanent chats. /// Determines whether dismissing is disabled for permanent chats.
final bool disableDismissForPermanentChats; final bool disableDismissForPermanentChats;
@ -74,7 +83,10 @@ class ChatUserStoryConfiguration {
/// Builder for chat options based on context. /// Builder for chat options based on context.
final Function(List<ChatUserModel>, String)? onPressCompleteGroupChatCreation; final Function(List<ChatUserModel>, String)? onPressCompleteGroupChatCreation;
final Function()? onPressCreateGroupChat; final Function()? onPressCreateGroupChat;
/// Builder for the chat options which can be used to style the UI of the chat
final ChatOptions Function(BuildContext context) chatOptionsBuilder; final ChatOptions Function(BuildContext context) chatOptionsBuilder;
/// If true, the user will be routed to the new chat screen if there are /// If true, the user will be routed to the new chat screen if there are
@ -84,6 +96,10 @@ class ChatUserStoryConfiguration {
/// The size of each page of messages. /// The size of each page of messages.
final int messagePageSize; final int messagePageSize;
/// Whether to enable group chat creation for the user. If false,
/// the button will be hidden
final bool enableGroupChatCreation;
/// Dialog for confirming chat deletion. /// Dialog for confirming chat deletion.
final Future<bool?> Function(BuildContext, ChatModel)? deleteChatDialog; final Future<bool?> Function(BuildContext, ChatModel)? deleteChatDialog;
@ -100,11 +116,18 @@ class ChatUserStoryConfiguration {
final Function()? onPressStartChat; final Function()? onPressStartChat;
/// Callback function triggered when user profile is pressed. /// Callback function triggered when user profile is pressed.
final Function()? onPressUserProfile; final Function(BuildContext context, ChatUserModel user)? onPressUserProfile;
final double? textfieldBottomPadding; final double? textfieldBottomPadding;
final Color? iconDisabledColor; final Color? iconDisabledColor;
/// The text style used for the unread message counter.
final TextStyle? unreadMessageTextStyle; final TextStyle? unreadMessageTextStyle;
final Widget? Function(BuildContext context)? loadingWidgetBuilder; final Widget? Function(BuildContext context)? loadingWidgetBuilder;
final Widget Function(String userFullName)? usernameBuilder; final Widget Function(String userFullName)? usernameBuilder;
final Widget Function(String chatTitle)? chatTitleBuilder; final Widget Function(String chatTitle)? chatTitleBuilder;
} }

View file

@ -4,7 +4,7 @@
name: flutter_chat name: flutter_chat
description: A new Flutter package project. description: A new Flutter package project.
version: 1.4.3 version: 2.0.0
publish_to: none publish_to: none
@ -20,17 +20,17 @@ dependencies:
git: git:
url: https://github.com/Iconica-Development/flutter_chat url: https://github.com/Iconica-Development/flutter_chat
path: packages/flutter_chat_view path: packages/flutter_chat_view
ref: 1.4.3 ref: 2.0.0
flutter_chat_interface: flutter_chat_interface:
git: git:
url: https://github.com/Iconica-Development/flutter_chat url: https://github.com/Iconica-Development/flutter_chat
path: packages/flutter_chat_interface path: packages/flutter_chat_interface
ref: 1.4.3 ref: 2.0.0
flutter_chat_local: flutter_chat_local:
git: git:
url: https://github.com/Iconica-Development/flutter_chat url: https://github.com/Iconica-Development/flutter_chat
path: packages/flutter_chat_local path: packages/flutter_chat_local
ref: 1.4.3 ref: 2.0.0
uuid: ^4.3.3 uuid: ^4.3.3
dev_dependencies: dev_dependencies:

View file

@ -91,11 +91,15 @@ class FirebaseChatOverviewService implements ChatOverviewService {
var chat = element.doc.data(); var chat = element.doc.data();
if (chat == null) return; if (chat == null) return;
var otherUser = await _userService.getUser( var otherUser = chat.users.any(
(element) => element != currentUser?.id,
)
? await _userService.getUser(
chat.users.firstWhere( chat.users.firstWhere(
(element) => element != currentUser?.id, (element) => element != currentUser?.id,
), ),
); )
: null;
var unread = var unread =
await _addUnreadChatSubscription(chat.id!, currentUser!.id!); await _addUnreadChatSubscription(chat.id!, currentUser!.id!);
@ -144,10 +148,10 @@ class FirebaseChatOverviewService implements ChatOverviewService {
imageUrl: chat.imageUrl ?? '', imageUrl: chat.imageUrl ?? '',
unreadMessages: unread, unreadMessages: unread,
users: users, users: users,
lastMessage: chat.lastMessage != null lastMessage: chat.lastMessage != null && otherUser != null
? chat.lastMessage!.imageUrl == null ? chat.lastMessage!.imageUrl == null
? ChatTextMessageModel( ? ChatTextMessageModel(
sender: otherUser!, sender: otherUser,
text: chat.lastMessage!.text!, text: chat.lastMessage!.text!,
timestamp: DateTime.fromMillisecondsSinceEpoch( timestamp: DateTime.fromMillisecondsSinceEpoch(
chat.lastMessage!.timestamp chat.lastMessage!.timestamp
@ -155,7 +159,7 @@ class FirebaseChatOverviewService implements ChatOverviewService {
), ),
) )
: ChatImageMessageModel( : ChatImageMessageModel(
sender: otherUser!, sender: otherUser,
imageUrl: chat.lastMessage!.imageUrl!, imageUrl: chat.lastMessage!.imageUrl!,
timestamp: DateTime.fromMillisecondsSinceEpoch( timestamp: DateTime.fromMillisecondsSinceEpoch(
chat.lastMessage!.timestamp chat.lastMessage!.timestamp

View file

@ -4,7 +4,7 @@
name: flutter_chat_firebase name: flutter_chat_firebase
description: A new Flutter package project. description: A new Flutter package project.
version: 1.4.3 version: 2.0.0
publish_to: none publish_to: none
environment: environment:
@ -23,7 +23,7 @@ dependencies:
git: git:
url: https://github.com/Iconica-Development/flutter_chat url: https://github.com/Iconica-Development/flutter_chat
path: packages/flutter_chat_interface path: packages/flutter_chat_interface
ref: 1.4.3 ref: 2.0.0
dev_dependencies: dev_dependencies:
flutter_iconica_analysis: flutter_iconica_analysis:

View file

@ -4,7 +4,7 @@
name: flutter_chat_interface name: flutter_chat_interface
description: A new Flutter package project. description: A new Flutter package project.
version: 1.4.3 version: 2.0.0
publish_to: none publish_to: none
environment: environment:

View file

@ -1,8 +1,7 @@
name: flutter_chat_local name: flutter_chat_local
description: "A new Flutter package project." description: "A new Flutter package project."
version: 1.4.3 version: 2.0.0
publish_to: none publish_to: none
homepage:
environment: environment:
sdk: ">=3.2.5 <4.0.0" sdk: ">=3.2.5 <4.0.0"
@ -15,7 +14,7 @@ dependencies:
git: git:
url: https://github.com/Iconica-Development/flutter_chat url: https://github.com/Iconica-Development/flutter_chat
path: packages/flutter_chat_interface path: packages/flutter_chat_interface
ref: 1.4.3 ref: 2.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -31,7 +31,7 @@ class ChatDetailRow extends StatefulWidget {
/// The previous chat message model. /// The previous chat message model.
final ChatMessageModel? previousMessage; final ChatMessageModel? previousMessage;
final Function(String? userId) onPressUserProfile; final Function(ChatUserModel user) onPressUserProfile;
final Widget Function(String userFullName)? usernameBuilder; final Widget Function(String userFullName)? usernameBuilder;
/// Flag indicating whether to show the time. /// Flag indicating whether to show the time.
@ -65,7 +65,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
if (isNewDate || isSameSender) ...[ if (isNewDate || isSameSender) ...[
GestureDetector( GestureDetector(
onTap: () => widget.onPressUserProfile( onTap: () => widget.onPressUserProfile(
widget.message.sender.id, widget.message.sender,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 10.0), padding: const EdgeInsets.only(left: 10.0),

View file

@ -19,6 +19,7 @@ class ChatOptions {
this.groupAvatarBuilder = _createGroupAvatar, this.groupAvatarBuilder = _createGroupAvatar,
this.noChatsPlaceholderBuilder = _createNoChatsPlaceholder, this.noChatsPlaceholderBuilder = _createNoChatsPlaceholder,
this.noUsersPlaceholderBuilder = _createNoUsersPlaceholder, this.noUsersPlaceholderBuilder = _createNoUsersPlaceholder,
this.paddingAroundChatList,
}); });
/// Builder function for the new chat button. /// Builder function for the new chat button.
@ -47,6 +48,9 @@ class ChatOptions {
/// Builder function for the placeholder shown when no users are available. /// Builder function for the placeholder shown when no users are available.
final NoUsersPlaceholderBuilder noUsersPlaceholderBuilder; final NoUsersPlaceholderBuilder noUsersPlaceholderBuilder;
/// The padding around the chat list.
final EdgeInsets? paddingAroundChatList;
} }
Widget _createNewChatButton( Widget _createNewChatButton(

View file

@ -2,12 +2,48 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
/// Class that holds all the translations for the chat component view and
/// the corresponding userstory
class ChatTranslations { class ChatTranslations {
/// ChatTranslations constructor where everything is required use this
/// if you want to be sure to have all translations specified
/// If you just want the default values use the empty constructor
/// and optionally override the values with the copyWith method
const ChatTranslations({ const ChatTranslations({
required this.chatsTitle,
required this.chatsUnread,
required this.newChatButton,
required this.newGroupChatButton,
required this.newChatTitle,
required this.deleteChatButton,
required this.image,
required this.searchPlaceholder,
required this.startTyping,
required this.cancelImagePickerBtn,
required this.messagePlaceholder,
required this.writeMessageToStartChat,
required this.writeFirstMessageInGroupChat,
required this.imageUploading,
required this.deleteChatModalTitle,
required this.deleteChatModalDescription,
required this.deleteChatModalCancel,
required this.deleteChatModalConfirm,
required this.noUsersFound,
required this.noChatsFound,
required this.chatCantBeDeleted,
required this.chatProfileUsers,
required this.imagePickerTitle,
required this.uploadFile,
required this.takePicture,
required this.anonymousUser,
});
/// Default translations for the chat component view
const ChatTranslations.empty({
this.chatsTitle = 'Chats', this.chatsTitle = 'Chats',
this.chatsUnread = 'unread', this.chatsUnread = 'unread',
this.newChatButton = 'Start a chat', this.newChatButton = 'Start a chat',
this.newGroupChatButton = 'Start group chat', this.newGroupChatButton = 'Create a group chat',
this.newChatTitle = 'Start a chat', this.newChatTitle = 'Start a chat',
this.image = 'Image', this.image = 'Image',
this.searchPlaceholder = 'Search...', this.searchPlaceholder = 'Search...',
@ -62,4 +98,67 @@ class ChatTranslations {
/// Shown when the user has no name /// Shown when the user has no name
final String anonymousUser; final String anonymousUser;
// copyWith method to override the default values
ChatTranslations copyWith({
String? chatsTitle,
String? chatsUnread,
String? newChatButton,
String? newGroupChatButton,
String? newChatTitle,
String? deleteChatButton,
String? image,
String? searchPlaceholder,
String? startTyping,
String? cancelImagePickerBtn,
String? messagePlaceholder,
String? writeMessageToStartChat,
String? writeFirstMessageInGroupChat,
String? imageUploading,
String? deleteChatModalTitle,
String? deleteChatModalDescription,
String? deleteChatModalCancel,
String? deleteChatModalConfirm,
String? noUsersFound,
String? noChatsFound,
String? chatCantBeDeleted,
String? chatProfileUsers,
String? imagePickerTitle,
String? uploadFile,
String? takePicture,
String? anonymousUser,
}) =>
ChatTranslations(
chatsTitle: chatsTitle ?? this.chatsTitle,
chatsUnread: chatsUnread ?? this.chatsUnread,
newChatButton: newChatButton ?? this.newChatButton,
newGroupChatButton: newGroupChatButton ?? this.newGroupChatButton,
newChatTitle: newChatTitle ?? this.newChatTitle,
deleteChatButton: deleteChatButton ?? this.deleteChatButton,
image: image ?? this.image,
searchPlaceholder: searchPlaceholder ?? this.searchPlaceholder,
startTyping: startTyping ?? this.startTyping,
cancelImagePickerBtn: cancelImagePickerBtn ?? this.cancelImagePickerBtn,
messagePlaceholder: messagePlaceholder ?? this.messagePlaceholder,
writeMessageToStartChat:
writeMessageToStartChat ?? this.writeMessageToStartChat,
writeFirstMessageInGroupChat:
writeFirstMessageInGroupChat ?? this.writeFirstMessageInGroupChat,
imageUploading: imageUploading ?? this.imageUploading,
deleteChatModalTitle: deleteChatModalTitle ?? this.deleteChatModalTitle,
deleteChatModalDescription:
deleteChatModalDescription ?? this.deleteChatModalDescription,
deleteChatModalCancel:
deleteChatModalCancel ?? this.deleteChatModalCancel,
deleteChatModalConfirm:
deleteChatModalConfirm ?? this.deleteChatModalConfirm,
noUsersFound: noUsersFound ?? this.noUsersFound,
noChatsFound: noChatsFound ?? this.noChatsFound,
chatCantBeDeleted: chatCantBeDeleted ?? this.chatCantBeDeleted,
chatProfileUsers: chatProfileUsers ?? this.chatProfileUsers,
imagePickerTitle: imagePickerTitle ?? this.imagePickerTitle,
uploadFile: uploadFile ?? this.uploadFile,
takePicture: takePicture ?? this.takePicture,
anonymousUser: anonymousUser ?? this.anonymousUser,
);
} }

View file

@ -26,7 +26,7 @@ class ChatDetailScreen extends StatefulWidget {
this.chatTitleBuilder, this.chatTitleBuilder,
this.usernameBuilder, this.usernameBuilder,
this.loadingWidgetBuilder, this.loadingWidgetBuilder,
this.translations = const ChatTranslations(), this.translations = const ChatTranslations.empty(),
this.iconColor, this.iconColor,
this.iconDisabledColor, this.iconDisabledColor,
this.showTime = false, this.showTime = false,
@ -53,7 +53,7 @@ class ChatDetailScreen extends StatefulWidget {
final int pageSize; final int pageSize;
final double textfieldBottomPadding; final double textfieldBottomPadding;
final Color? iconDisabledColor; final Color? iconDisabledColor;
final Function(String? userId) onPressUserProfile; final Function(ChatUserModel user) onPressUserProfile;
// ignore: avoid_positional_boolean_parameters // ignore: avoid_positional_boolean_parameters
final Widget? Function(BuildContext context)? loadingWidgetBuilder; final Widget? Function(BuildContext context)? loadingWidgetBuilder;
final Widget Function(String userFullName)? usernameBuilder; final Widget Function(String userFullName)? usernameBuilder;

View file

@ -26,7 +26,7 @@ class ChatProfileScreen extends StatefulWidget {
final String? userId; final String? userId;
/// Callback function for tapping on a user. /// Callback function for tapping on a user.
final Function(String userId) onTapUser; final Function(ChatUserModel user) onTapUser;
@override @override
State<ChatProfileScreen> createState() => _ProfileScreenState(); State<ChatProfileScreen> createState() => _ProfileScreenState();
@ -124,7 +124,7 @@ class _ProfileScreenState extends State<ChatProfileScreen> {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0), padding: const EdgeInsets.symmetric(vertical: 4.0),
child: GestureDetector( child: GestureDetector(
onTap: () => widget.onTapUser.call(e.id!), onTap: () => widget.onTapUser.call(e),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View file

@ -20,7 +20,7 @@ class ChatScreen extends StatefulWidget {
this.unreadMessageTextStyle, this.unreadMessageTextStyle,
this.onNoChats, this.onNoChats,
this.deleteChatDialog, this.deleteChatDialog,
this.translations = const ChatTranslations(), this.translations = const ChatTranslations.empty(),
this.disableDismissForPermanentChats = false, this.disableDismissForPermanentChats = false,
super.key, super.key,
}); });
@ -119,7 +119,8 @@ class _ChatScreenState extends State<ChatScreen> {
child: ListView( child: ListView(
controller: controller, controller: controller,
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.fromLTRB(28, 16, 28, 0), padding: widget.options.paddingAroundChatList ??
const EdgeInsets.fromLTRB(28, 16, 28, 0),
children: [ children: [
StreamBuilder<List<ChatModel>>( StreamBuilder<List<ChatModel>>(
stream: widget.service.chatOverviewService.getChatsStream(), stream: widget.service.chatOverviewService.getChatsStream(),
@ -384,7 +385,6 @@ class ChatListItem extends StatelessWidget {
), ),
), ),
), ),
const Divider(),
], ],
); );
} }

View file

@ -11,7 +11,8 @@ class NewChatScreen extends StatefulWidget {
required this.onPressCreateChat, required this.onPressCreateChat,
required this.service, required this.service,
required this.onPressCreateGroupChat, required this.onPressCreateGroupChat,
this.translations = const ChatTranslations(), this.showGroupChatButton = true,
this.translations = const ChatTranslations.empty(),
super.key, super.key,
}); });
@ -23,8 +24,13 @@ class NewChatScreen extends StatefulWidget {
/// Callback function for creating a new chat with a user. /// Callback function for creating a new chat with a user.
final Function(ChatUserModel) onPressCreateChat; final Function(ChatUserModel) onPressCreateChat;
/// Callback function for creating a new group chat.
final Function() onPressCreateGroupChat; final Function() onPressCreateGroupChat;
/// Option to enable the group chat creation button.
final bool showGroupChatButton;
/// Translations for the chat. /// Translations for the chat.
final ChatTranslations translations; final ChatTranslations translations;
@ -52,6 +58,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
), ),
body: Column( body: Column(
children: [ children: [
if (widget.showGroupChatButton) ...[
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
await widget.onPressCreateGroupChat(); await widget.onPressCreateGroupChat();
@ -80,9 +87,9 @@ class _NewChatScreenState extends State<NewChatScreen> {
}, },
), ),
), ),
const Text( Text(
'Create group chat', widget.translations.newGroupChatButton,
style: TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 16.0, fontSize: 16.0,
), ),
@ -94,6 +101,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
), ),
), ),
), ),
],
Expanded( Expanded(
child: FutureBuilder<List<ChatUserModel>>( child: FutureBuilder<List<ChatUserModel>>(
// ignore: discarded_futures // ignore: discarded_futures
@ -213,12 +221,8 @@ class _NewChatScreenState extends State<NewChatScreen> {
return widget.options.noChatsPlaceholderBuilder(widget.translations); return widget.options.noChatsPlaceholderBuilder(widget.translations);
} }
return ListView.separated( return ListView.builder(
itemCount: filteredUsers.length, itemCount: filteredUsers.length,
separatorBuilder: (context, index) => const Padding(
padding: EdgeInsets.symmetric(horizontal: 28.0),
child: Divider(),
),
itemBuilder: (context, index) { itemBuilder: (context, index) {
var user = filteredUsers[index]; var user = filteredUsers[index];
return GestureDetector( return GestureDetector(

View file

@ -11,7 +11,7 @@ class NewGroupChatOverviewScreen extends StatefulWidget {
required this.onPressCompleteGroupChatCreation, required this.onPressCompleteGroupChatCreation,
required this.service, required this.service,
required this.users, required this.users,
this.translations = const ChatTranslations(), this.translations = const ChatTranslations.empty(),
super.key, super.key,
}); });

View file

@ -8,7 +8,7 @@ class NewGroupChatScreen extends StatefulWidget {
required this.options, required this.options,
required this.onPressGroupChatOverview, required this.onPressGroupChatOverview,
required this.service, required this.service,
this.translations = const ChatTranslations(), this.translations = const ChatTranslations.empty(),
super.key, super.key,
}); });

View file

@ -4,7 +4,7 @@
name: flutter_chat_view name: flutter_chat_view
description: A standard flutter package. description: A standard flutter package.
version: 1.4.3 version: 2.0.0
publish_to: none publish_to: none
@ -20,7 +20,7 @@ dependencies:
git: git:
url: https://github.com/Iconica-Development/flutter_chat url: https://github.com/Iconica-Development/flutter_chat
path: packages/flutter_chat_interface path: packages/flutter_chat_interface
ref: 1.4.3 ref: 2.0.0
cached_network_image: ^3.2.2 cached_network_image: ^3.2.2
flutter_image_picker: flutter_image_picker:
git: git: