Merge pull request #45 from Iconica-Development/bugfix/feedback

fix: feedback
This commit is contained in:
Gorter-dev 2024-01-23 14:39:24 +01:00 committed by GitHub
commit da7d639e05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 351 additions and 10 deletions

View file

@ -1,3 +1,9 @@
## 1.0.0
- Added pagination for the ChatDetailScreen
- Added routes with Go_router and Navigator
- Added ChatEntryWidget
## 0.6.0 - December 1 2023
- Made the message controller nullable

View file

@ -18,7 +18,7 @@ To use this package, add flutter_chat as a dependency in your pubspec.yaml file:
path: packages/flutter_chat
```
If you are going to use Firebase as the back-end of the Community Chat, you should also add the following package as a dependency to your pubspec.yaml file:
If you are going to use Firebase as the back-end of the Chat, you should also add the following package as a dependency to your pubspec.yaml file:
```
flutter_chat_firebase:
@ -29,6 +29,35 @@ If you are going to use Firebase as the back-end of the Community Chat, you shou
Create a Firebase project for your application and add firebase firestore and storage.
make sure you are authenticated using the `Firebase_auth` package or adjust your firebase rules, otherwise you won't be able to retreive data.
Also make sure you have the corresponding collections in your firebase project as defined in `FirebaseChatOptions`, you can override the
default paths as you wish, also the structure of your data should be equal to our predefined models, you can implement any model by making your own model and implementing one of the predefined interfaces like so:
```
class ChatMessageModel implements ChatMessageModelInterface {
ChatMessageModel({
required this.sender,
required this.timestamp,
});
@override
final ChatUserModel sender;
@override
final DateTime timestamp;
}
```
below a list of interfaces you can implement;
`ChatUserModelInterface`,
`ChatImageMessageModelInterface`,
`ChatTextMessageModelInterface`
`ChatMessageModelInterface`,
`ChatModelInterface`,
`GroupChatModelInterface`,
`PersonalChatModelInterface`,
To use the camera or photo library to send photos add the following to your project:
For ios add the following lines to your info.plist:
@ -63,6 +92,8 @@ List<GoRoute> getChatRoutes() => getChatStoryRoutes(
);
```
You can override any method in the `ChatUserStoryConfiguration`.
Add the `getChatRoutes()` to your go_router routes like so:
```
@ -81,12 +112,55 @@ final GoRouter _router = GoRouter(
);
```
To use the module within your Flutter-application without predefined `Go_router` routes add the following code to the build-method of a chosen widget:
The routes that can be used to navigate are:
The `ChatScreen` shows all chats that you currently have with their latest messages.
For routing to the `ChatScreen`:
```
static const String chatScreen = '/chat';
```
For routing to the `ChatDetailScreen`:
```
static String chatDetailViewPath(String chatId) => '/chat-detail/$chatId';
static const String chatDetailScreen = '/chat-detail/:id';
```
For routing to the `NewChatScreen`:
```
static const String newChatScreen = '/new-chat';
```
For routing to the `ChatProfileScreen`:
you can see the information about a person or group you started a chat with.
If the userId is null a group profile screen will be shown otherwise the profile of a single person will be shown.
```
static String chatProfileScreenPath(String chatId, String? userId) =>
'/chat-profile/$chatId/$userId';
static const String chatProfileScreen = '/chat-profile/:id/:userId';
```
To use the module within your Flutter-application without predefined `Go_router` routes but with Navigator routes add the following code to the build-method of a chosen widget:
```
chatNavigatorUserStory(
ChatUserStoryConfiguration(
chatService: ChatService,
chatOptionsBuilder: (ctx) => const ChatOptions(),
),
context,
);
```
Just like with the `Go_router` routes you can override any methods in the `ChatUserStoryConfiguration`.
Or create your own routing using the Screens:
To add the `ChatScreen` add the following code:
````
```
ChatScreen(
options: options,
onPressStartChat: onPressStartChat,
@ -121,10 +195,22 @@ NewChatScreen(
);
```
On the `ChatProfileScreen` you can see the information about a person or group you started a chat with.
If the userId is null a group profile screen will be shown otherwise the profile of a single person will be shown.
```
ChatProfileScreen(
chatService: chatservice,
chatId: chatId,
translations: translations,
onTapUser: onTapUser,
userId: userId,
);
```
The `ChatEntryWidget` is a widget you can put anywhere in your app.
It displays the amount of unread messages you currently have.
You can choose to add a onTap to the `ChatEntryWidget` so it routes to the `ChatScreen`,
where all your chats are shown.
You can choose to add a onTap to the `ChatEntryWidget` so it routes to the `ChatScreen`.
To add the `ChatEntryWidget` add the follwoing code:
@ -158,4 +244,3 @@ If you would like to contribute to the plugin (e.g. by improving the documentati
## Author
This `flutter_chat` for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl>
````

View file

@ -9,3 +9,4 @@ export 'package:flutter_chat_interface/flutter_chat_interface.dart';
export 'package:flutter_chat/src/routes.dart';
export 'package:flutter_chat/src/models/chat_configuration.dart';
export 'package:flutter_chat/src/flutter_chat_userstory.dart';
export 'package:flutter_chat/src/flutter_chat_navigator_userstory.dart';

View file

@ -0,0 +1,160 @@
// SPDX-FileCopyrightText: 2023 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat/flutter_chat.dart';
Widget chatNavigatorUserStory(
ChatUserStoryConfiguration configuration, BuildContext context) {
return _chatScreenRoute(configuration, context);
}
Widget _chatScreenRoute(
ChatUserStoryConfiguration configuration, BuildContext context) {
return ChatScreen(
service: configuration.chatService,
options: configuration.chatOptionsBuilder(context),
onNoChats: () async => await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _newChatScreenRoute(
configuration,
context,
),
),
),
onPressStartChat: () async {
if (configuration.onPressStartChat != null) {
return await configuration.onPressStartChat?.call();
}
return await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _newChatScreenRoute(
configuration,
context,
),
),
);
},
onPressChat: (chat) async =>
configuration.onPressChat?.call(context, chat) ??
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _chatDetailScreenRoute(
configuration,
context,
chat.id!,
),
),
),
onDeleteChat: (chat) =>
configuration.onDeleteChat?.call(context, chat) ??
configuration.chatService.chatOverviewService.deleteChat(chat),
deleteChatDialog: configuration.deleteChatDialog,
translations: configuration.translations,
);
}
Widget _chatDetailScreenRoute(ChatUserStoryConfiguration configuration,
BuildContext context, String chatId) {
return ChatDetailScreen(
pageSize: configuration.messagePageSize,
options: configuration.chatOptionsBuilder(context),
translations: configuration.translations,
service: configuration.chatService,
chatId: chatId,
onMessageSubmit: (message) async {
configuration.onMessageSubmit?.call(message) ??
configuration.chatService.chatDetailService
.sendTextMessage(chatId: chatId, text: message);
configuration.afterMessageSent?.call(chatId);
},
onUploadImage: (image) async {
configuration.onUploadImage?.call(image) ??
configuration.chatService.chatDetailService
.sendImageMessage(chatId: chatId, image: image);
configuration.afterMessageSent?.call(chatId);
},
onReadChat: (chat) =>
configuration.onReadChat?.call(chat) ??
configuration.chatService.chatOverviewService.readChat(chat),
onPressChatTitle: (context, chat) async {
if (configuration.onPressChatTitle?.call(context, chat) != null) {
return configuration.onPressChatTitle?.call(context, chat);
}
return await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _chatProfileScreenRoute(
configuration,
context,
chatId,
null,
),
),
);
},
iconColor: configuration.iconColor,
);
}
Widget _chatProfileScreenRoute(ChatUserStoryConfiguration configuration,
BuildContext context, String chatId, String? userId) {
return ChatProfileScreen(
translations: configuration.translations,
chatService: configuration.chatService,
chatId: chatId,
userId: userId,
onTapUser: (user) async {
if (configuration.onPressUserProfile != null) {
return configuration.onPressUserProfile!.call();
}
return Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _chatProfileScreenRoute(
configuration,
context,
chatId,
userId,
),
),
);
},
);
}
Widget _newChatScreenRoute(
ChatUserStoryConfiguration configuration, BuildContext context) {
return NewChatScreen(
options: configuration.chatOptionsBuilder(context),
translations: configuration.translations,
service: configuration.chatService,
onPressCreateChat: (user) async {
configuration.onPressCreateChat?.call(user);
if (configuration.onPressCreateChat != null) return;
var chat = await configuration.chatService.chatOverviewService
.getChatByUser(user);
if (chat.id == null) {
chat =
await configuration.chatService.chatOverviewService.storeChatIfNot(
PersonalChatModel(
user: user,
),
);
}
if (context.mounted) {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _chatDetailScreenRoute(
configuration,
context,
chat.id!,
),
),
);
}
},
);
}

View file

@ -105,7 +105,7 @@ List<GoRoute> getChatStoryRoutes(
service: configuration.chatService,
onPressCreateChat: (user) async {
configuration.onPressCreateChat?.call(user);
if (configuration.onPressChat != null) return;
if (configuration.onPressCreateChat != null) return;
var chat = await configuration.chatService.chatOverviewService
.getChatByUser(user);
if (chat.id == null) {

View file

@ -12,7 +12,6 @@ class ChatUserStoryConfiguration {
const ChatUserStoryConfiguration({
required this.chatService,
required this.chatOptionsBuilder,
this.pageSize = 10,
this.onPressStartChat,
this.onPressChat,
this.onDeleteChat,
@ -47,7 +46,6 @@ class ChatUserStoryConfiguration {
/// 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;

View file

@ -163,8 +163,22 @@ class FirebaseChatOverviewService implements ChatOverviewService {
for (ChatModel chatModel in chats) {
if (uniqueIds.add(chatModel.id!)) {
uniqueChatModels.add(chatModel);
} else {
var index = uniqueChatModels.indexWhere(
(element) => element.id == chatModel.id,
);
if (index != -1) {
if (chatModel.lastUsed != null &&
uniqueChatModels[index].lastUsed != null) {
if (chatModel.lastUsed!
.isAfter(uniqueChatModels[index].lastUsed!)) {
uniqueChatModels[index] = chatModel;
}
}
}
}
}
uniqueChatModels.sort(
(a, b) => (b.lastUsed ?? DateTime.now()).compareTo(
a.lastUsed ?? DateTime.now(),

View file

@ -0,0 +1,75 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_chat_firebase/config/firebase_chat_options.dart';
import 'package:flutter_chat_firebase/flutter_chat_firebase.dart';
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
class FirebaseChatService implements ChatService {
FirebaseChatService({
this.options,
this.app,
this.firebaseChatDetailService,
this.firebaseChatOverviewService,
this.firebaseChatUserService,
}) {
firebaseChatDetailService ??= FirebaseChatDetailService(
userService: chatUserService,
options: options,
app: app,
);
firebaseChatOverviewService ??= FirebaseChatOverviewService(
userService: chatUserService,
options: options,
app: app,
);
firebaseChatUserService ??= FirebaseChatUserService(
options: options,
app: app,
);
}
final FirebaseChatOptions? options;
final FirebaseApp? app;
ChatDetailService? firebaseChatDetailService;
ChatOverviewService? firebaseChatOverviewService;
ChatUserService? firebaseChatUserService;
@override
ChatDetailService get chatDetailService {
if (firebaseChatDetailService != null) {
return firebaseChatDetailService!;
} else {
return FirebaseChatDetailService(
userService: chatUserService,
options: options,
app: app,
);
}
}
@override
ChatOverviewService get chatOverviewService {
if (firebaseChatOverviewService != null) {
return firebaseChatOverviewService!;
} else {
return FirebaseChatOverviewService(
userService: chatUserService,
options: options,
app: app,
);
}
}
@override
ChatUserService get chatUserService {
if (firebaseChatUserService != null) {
return firebaseChatUserService!;
} else {
return FirebaseChatUserService(
options: options,
app: app,
);
}
}
}

View file

@ -1,3 +1,4 @@
export 'package:flutter_chat_firebase/service/firebase_chat_user_service.dart';
export 'package:flutter_chat_firebase/service/firebase_chat_detail_service.dart';
export 'package:flutter_chat_firebase/service/firebase_chat_overview_service.dart';
export 'package:flutter_chat_firebase/service/firebase_chat_service.dart';

View file

@ -17,6 +17,7 @@ class ChatProfileService extends ProfileService {
@override
FutureOr<void> uploadImage(
BuildContext context, {
// ignore: avoid_positional_boolean_parameters
required Function(bool isUploading) onUploadStateChanged,
}) {
throw UnimplementedError();