diff --git a/packages/chat_repository_interface/lib/chat_repository_interface.dart b/packages/chat_repository_interface/lib/chat_repository_interface.dart index c8b2805..5aab41d 100644 --- a/packages/chat_repository_interface/lib/chat_repository_interface.dart +++ b/packages/chat_repository_interface/lib/chat_repository_interface.dart @@ -1,15 +1,14 @@ +// exceptions +export "src/exceptions/chat.dart"; // Interfaces export "src/interfaces/chat_repostory_interface.dart"; export "src/interfaces/user_repository_interface.dart"; - // Local implementations export "src/local/local_chat_repository.dart"; export "src/local/local_user_repository.dart"; - // Models export "src/models/chat_model.dart"; export "src/models/message_model.dart"; export "src/models/user_model.dart"; - // Services export "src/services/chat_service.dart"; diff --git a/packages/chat_repository_interface/lib/src/exceptions/chat.dart b/packages/chat_repository_interface/lib/src/exceptions/chat.dart new file mode 100644 index 0000000..0117ebf --- /dev/null +++ b/packages/chat_repository_interface/lib/src/exceptions/chat.dart @@ -0,0 +1,23 @@ +/// An exception that is used to indicate the failure to load a chat for given +/// [chatId] +class ChatNotFoundException implements Exception { + /// Create an instance of the chat not found exception + const ChatNotFoundException({ + required this.chatId, + }); + + /// The chat that was attempted to load, but never found. + final String chatId; +} + +/// An exception that is used to indicate the failure to load the messages for a +/// given [chatId] +class ChatMessagesNotFoundException implements Exception { + /// Create an instance of the chatmessages not found exception + const ChatMessagesNotFoundException({ + required this.chatId, + }); + + /// The chat for which messages were attempted to load, but never found. + final String chatId; +} diff --git a/packages/flutter_chat/lib/src/config/chat_builders.dart b/packages/flutter_chat/lib/src/config/chat_builders.dart index 026c15c..c741e0d 100644 --- a/packages/flutter_chat/lib/src/config/chat_builders.dart +++ b/packages/flutter_chat/lib/src/config/chat_builders.dart @@ -1,17 +1,15 @@ import "dart:typed_data"; -import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:flutter/material.dart"; -import "package:flutter_chat/src/config/chat_translations.dart"; -import "package:flutter_chat/src/config/screen_types.dart"; +import "package:flutter_chat/flutter_chat.dart"; import "package:flutter_chat/src/screens/chat_detail/widgets/default_loader.dart"; -import "package:flutter_chat/src/screens/chat_detail/widgets/default_message_builder.dart"; import "package:flutter_chat/src/screens/creation/widgets/default_image_picker.dart"; /// The chat builders class ChatBuilders { /// The chat builders constructor const ChatBuilders({ + this.chatMessagesErrorBuilder, this.baseScreenBuilder, this.chatScreenBuilder, this.messageInputBuilder, @@ -99,6 +97,10 @@ class ChatBuilders { /// This is displayed in the list of chat messages when loading more messages /// can be above and below the list final WidgetBuilder loadingChatMessageBuilder; + + /// Errorbuilder for when messages are not loading correctly on the detail + /// screen of a chat. + final ChatErrorBuilder? chatMessagesErrorBuilder; } /// The button builder @@ -189,3 +191,11 @@ typedef NoUsersPlaceholderBuilder = Widget Function( BuildContext context, ChatTranslations translations, ); + +/// Builder for when there is an error on a chatscreen +typedef ChatErrorBuilder = Widget Function( + BuildContext context, + Object error, + StackTrace stackTrace, + ChatOptions options, +); diff --git a/packages/flutter_chat/lib/src/config/chat_translations.dart b/packages/flutter_chat/lib/src/config/chat_translations.dart index fb0685f..9685c59 100644 --- a/packages/flutter_chat/lib/src/config/chat_translations.dart +++ b/packages/flutter_chat/lib/src/config/chat_translations.dart @@ -48,6 +48,7 @@ class ChatTranslations { required this.selectedMembersHeader, required this.createGroupChatButton, required this.groupNameEmpty, + required this.messagesLoadingError, required this.next, }); @@ -92,6 +93,7 @@ class ChatTranslations { this.selectedMembersHeader = "Members: ", this.createGroupChatButton = "Create groupchat", this.groupNameEmpty = "Group", + this.messagesLoadingError = "Error loading messages, you can reload below:", this.next = "Next", }); @@ -134,6 +136,10 @@ class ChatTranslations { final String groupBioValidatorEmpty; final String groupNameEmpty; + /// message shown in the default chat screen when the chat messages are unable + /// to be loaded. + final String messagesLoadingError; + final String next; // copyWith method to override the default values @@ -174,6 +180,7 @@ class ChatTranslations { String? selectedMembersHeader, String? createGroupChatButton, String? groupNameEmpty, + String? messagesLoadingError, String? next, }) => ChatTranslations( @@ -225,6 +232,7 @@ class ChatTranslations { createGroupChatButton: createGroupChatButton ?? this.createGroupChatButton, groupNameEmpty: groupNameEmpty ?? this.groupNameEmpty, + messagesLoadingError: messagesLoadingError ?? this.messagesLoadingError, next: next ?? this.next, ); } diff --git a/packages/flutter_chat/lib/src/screens/chat_detail/chat_detail_screen.dart b/packages/flutter_chat/lib/src/screens/chat_detail/chat_detail_screen.dart index a0bb666..aa7fdc7 100644 --- a/packages/flutter_chat/lib/src/screens/chat_detail/chat_detail_screen.dart +++ b/packages/flutter_chat/lib/src/screens/chat_detail/chat_detail_screen.dart @@ -3,6 +3,7 @@ import "dart:typed_data"; import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:flutter/material.dart"; +import "package:flutter_chat/src/config/chat_options.dart"; import "package:flutter_chat/src/config/screen_types.dart"; import "package:flutter_chat/src/screens/chat_detail/widgets/chat_bottom.dart"; import "package:flutter_chat/src/screens/chat_detail/widgets/chat_widgets.dart"; @@ -393,6 +394,41 @@ class _ChatBody extends HookWidget { [autoScrollEnabled.value], ); + var chatBottomInputSection = ChatBottomInputSection( + chat: chat, + isLoading: chatIsLoading && !messagesSnapshot.hasData, + onPressSelectImage: () async => onPressSelectImage( + context, + options, + onUploadImage, + ), + onMessageSubmit: onMessageSubmit, + ); + + if (messagesSnapshot.hasError) { + var errorBuilder = options.builders.chatMessagesErrorBuilder; + if (errorBuilder != null) { + return Column( + children: [ + Expanded( + child: errorBuilder( + context, + messagesSnapshot.error!, + messagesSnapshot.stackTrace!, + options, + ), + ), + chatBottomInputSection, + ], + ); + } + + return ErrorLoadingMessages( + options: options, + chatBottomInputSection: chatBottomInputSection, + ); + } + var userMap = {}; for (var u in chatUsers) { userMap[u.id] = u; @@ -449,17 +485,43 @@ class _ChatBody extends HookWidget { ), ), ], - ChatBottomInputSection( - chat: chat, - isLoading: chatIsLoading, - onPressSelectImage: () async => onPressSelectImage( - context, - options, - onUploadImage, - ), - onMessageSubmit: onMessageSubmit, - ), + chatBottomInputSection, ], ); } } + +/// Default widget used when displaying an error for chats. +class ErrorLoadingMessages extends StatelessWidget { + /// Create default error displaying widget for error in loading messages + const ErrorLoadingMessages({ + required this.options, + required this.chatBottomInputSection, + super.key, + }); + + /// the options of the current chat userstory + final ChatOptions options; + + /// The widget + final ChatBottomInputSection chatBottomInputSection; + + @override + Widget build(BuildContext context) => Column( + children: [ + Expanded( + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + options.translations.messagesLoadingError, + ), + ], + ), + ), + ), + chatBottomInputSection, + ], + ); +}