feat: add error builder to chat detail screen for failed to load messages

This commit is contained in:
Joey Boerwinkel 2025-02-27 16:50:12 +01:00 committed by FlutterJoey
parent d3f839dc94
commit 6ecf073f15
5 changed files with 119 additions and 17 deletions

View file

@ -1,15 +1,14 @@
// exceptions
export "src/exceptions/chat.dart";
// Interfaces // Interfaces
export "src/interfaces/chat_repostory_interface.dart"; export "src/interfaces/chat_repostory_interface.dart";
export "src/interfaces/user_repository_interface.dart"; export "src/interfaces/user_repository_interface.dart";
// Local implementations // Local implementations
export "src/local/local_chat_repository.dart"; export "src/local/local_chat_repository.dart";
export "src/local/local_user_repository.dart"; export "src/local/local_user_repository.dart";
// Models // Models
export "src/models/chat_model.dart"; export "src/models/chat_model.dart";
export "src/models/message_model.dart"; export "src/models/message_model.dart";
export "src/models/user_model.dart"; export "src/models/user_model.dart";
// Services // Services
export "src/services/chat_service.dart"; export "src/services/chat_service.dart";

View file

@ -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;
}

View file

@ -1,17 +1,15 @@
import "dart:typed_data"; import "dart:typed_data";
import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_translations.dart"; import "package:flutter_chat/flutter_chat.dart";
import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/screens/chat_detail/widgets/default_loader.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"; import "package:flutter_chat/src/screens/creation/widgets/default_image_picker.dart";
/// The chat builders /// The chat builders
class ChatBuilders { class ChatBuilders {
/// The chat builders constructor /// The chat builders constructor
const ChatBuilders({ const ChatBuilders({
this.chatMessagesErrorBuilder,
this.baseScreenBuilder, this.baseScreenBuilder,
this.chatScreenBuilder, this.chatScreenBuilder,
this.messageInputBuilder, this.messageInputBuilder,
@ -99,6 +97,10 @@ class ChatBuilders {
/// This is displayed in the list of chat messages when loading more messages /// This is displayed in the list of chat messages when loading more messages
/// can be above and below the list /// can be above and below the list
final WidgetBuilder loadingChatMessageBuilder; final WidgetBuilder loadingChatMessageBuilder;
/// Errorbuilder for when messages are not loading correctly on the detail
/// screen of a chat.
final ChatErrorBuilder? chatMessagesErrorBuilder;
} }
/// The button builder /// The button builder
@ -189,3 +191,11 @@ typedef NoUsersPlaceholderBuilder = Widget Function(
BuildContext context, BuildContext context,
ChatTranslations translations, ChatTranslations translations,
); );
/// Builder for when there is an error on a chatscreen
typedef ChatErrorBuilder = Widget Function(
BuildContext context,
Object error,
StackTrace stackTrace,
ChatOptions options,
);

View file

@ -48,6 +48,7 @@ class ChatTranslations {
required this.selectedMembersHeader, required this.selectedMembersHeader,
required this.createGroupChatButton, required this.createGroupChatButton,
required this.groupNameEmpty, required this.groupNameEmpty,
required this.messagesLoadingError,
required this.next, required this.next,
}); });
@ -92,6 +93,7 @@ class ChatTranslations {
this.selectedMembersHeader = "Members: ", this.selectedMembersHeader = "Members: ",
this.createGroupChatButton = "Create groupchat", this.createGroupChatButton = "Create groupchat",
this.groupNameEmpty = "Group", this.groupNameEmpty = "Group",
this.messagesLoadingError = "Error loading messages, you can reload below:",
this.next = "Next", this.next = "Next",
}); });
@ -134,6 +136,10 @@ class ChatTranslations {
final String groupBioValidatorEmpty; final String groupBioValidatorEmpty;
final String groupNameEmpty; 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; final String next;
// copyWith method to override the default values // copyWith method to override the default values
@ -174,6 +180,7 @@ class ChatTranslations {
String? selectedMembersHeader, String? selectedMembersHeader,
String? createGroupChatButton, String? createGroupChatButton,
String? groupNameEmpty, String? groupNameEmpty,
String? messagesLoadingError,
String? next, String? next,
}) => }) =>
ChatTranslations( ChatTranslations(
@ -225,6 +232,7 @@ class ChatTranslations {
createGroupChatButton: createGroupChatButton:
createGroupChatButton ?? this.createGroupChatButton, createGroupChatButton ?? this.createGroupChatButton,
groupNameEmpty: groupNameEmpty ?? this.groupNameEmpty, groupNameEmpty: groupNameEmpty ?? this.groupNameEmpty,
messagesLoadingError: messagesLoadingError ?? this.messagesLoadingError,
next: next ?? this.next, next: next ?? this.next,
); );
} }

View file

@ -3,6 +3,7 @@ import "dart:typed_data";
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.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/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_bottom.dart";
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_widgets.dart"; import "package:flutter_chat/src/screens/chat_detail/widgets/chat_widgets.dart";
@ -393,6 +394,41 @@ class _ChatBody extends HookWidget {
[autoScrollEnabled.value], [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 = <String, UserModel>{}; var userMap = <String, UserModel>{};
for (var u in chatUsers) { for (var u in chatUsers) {
userMap[u.id] = u; userMap[u.id] = u;
@ -449,17 +485,43 @@ class _ChatBody extends HookWidget {
), ),
), ),
], ],
ChatBottomInputSection( chatBottomInputSection,
chat: chat,
isLoading: chatIsLoading,
onPressSelectImage: () async => onPressSelectImage(
context,
options,
onUploadImage,
),
onMessageSubmit: onMessageSubmit,
),
], ],
); );
} }
} }
/// 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,
],
);
}