Merge pull request #93 from Iconica-Development/3.0.1

fix: routing issues
This commit is contained in:
Freek van de Ven 2024-06-17 13:36:12 +02:00 committed by GitHub
commit 15f15748b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 423 additions and 429 deletions

View file

@ -1,3 +1,11 @@
## 3.0.1
- fix bug where you could make multiple groups quickly by routing back to the previous screen
- fix bug where you would route back to the user selection screen insterad of routing back to the chat overview screen
- Add onPopInvoked callback to the userstory to add custom behaviour for the back button on the chatscreen
- Handle overflows for users with a long name.
- Remove the scaffold backgrounds because they should be inherited from the scaffold theme
## 3.0.0
- Add theming

View file

@ -4,11 +4,11 @@
///
library flutter_chat;
export 'package:flutter_chat/src/chat_entry_widget.dart';
export 'package:flutter_chat/src/flutter_chat_navigator_userstory.dart';
export 'package:flutter_chat/src/flutter_chat_userstory.dart';
export 'package:flutter_chat/src/models/chat_configuration.dart';
export 'package:flutter_chat/src/routes.dart';
export 'package:flutter_chat_interface/flutter_chat_interface.dart';
export 'package:flutter_chat_local/local_chat_service.dart';
export 'package:flutter_chat_view/flutter_chat_view.dart';
export "package:flutter_chat/src/chat_entry_widget.dart";
export "package:flutter_chat/src/flutter_chat_navigator_userstory.dart";
export "package:flutter_chat/src/flutter_chat_userstory.dart";
export "package:flutter_chat/src/models/chat_configuration.dart";
export "package:flutter_chat/src/routes.dart";
export "package:flutter_chat_interface/flutter_chat_interface.dart";
export "package:flutter_chat_local/local_chat_service.dart";
export "package:flutter_chat_view/flutter_chat_view.dart";

View file

@ -1,7 +1,7 @@
import 'dart:async';
import "dart:async";
import 'package:flutter/material.dart';
import 'package:flutter_chat/flutter_chat.dart';
import "package:flutter/material.dart";
import "package:flutter_chat/flutter_chat.dart";
/// A widget representing an entry point for a chat UI.
class ChatEntryWidget extends StatefulWidget {
@ -104,7 +104,7 @@ class _ChatEntryWidgetState extends State<ChatEntryWidget> {
),
child: Center(
child: Text(
'${snapshot.data ?? 0}',
"${snapshot.data ?? 0}",
style: widget.textStyle,
),
),

View file

@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat/flutter_chat.dart';
import "package:flutter/material.dart";
import "package:flutter_chat/flutter_chat.dart";
/// Navigates to the chat user story screen.
///
@ -30,48 +30,53 @@ Widget _chatScreenRoute(
ChatUserStoryConfiguration configuration,
BuildContext context,
) =>
ChatScreen(
unreadMessageTextStyle: configuration.unreadMessageTextStyle,
service: configuration.chatService,
options: configuration.chatOptionsBuilder(context),
onNoChats: () async => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _newChatScreenRoute(
configuration,
context,
),
),
),
onPressStartChat: () async {
if (configuration.onPressStartChat != null) {
return await configuration.onPressStartChat?.call();
}
return Navigator.of(context).push(
PopScope(
canPop: configuration.onPopInvoked == null,
onPopInvoked: (didPop) =>
configuration.onPopInvoked?.call(didPop, context),
child: ChatScreen(
unreadMessageTextStyle: configuration.unreadMessageTextStyle,
service: configuration.chatService,
options: configuration.chatOptionsBuilder(context),
onNoChats: () async => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _newChatScreenRoute(
configuration,
context,
),
),
);
},
onPressChat: (chat) async =>
configuration.onPressChat?.call(context, chat) ??
await Navigator.of(context).push(
),
onPressStartChat: () async {
if (configuration.onPressStartChat != null) {
return await configuration.onPressStartChat?.call();
}
return Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _chatDetailScreenRoute(
builder: (context) => _newChatScreenRoute(
configuration,
context,
chat.id!,
),
),
),
onDeleteChat: (chat) async =>
configuration.onDeleteChat?.call(context, chat) ??
configuration.chatService.chatOverviewService.deleteChat(chat),
deleteChatDialog: configuration.deleteChatDialog,
translations: configuration.translations,
);
},
onPressChat: (chat) async =>
configuration.onPressChat?.call(context, chat) ??
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _chatDetailScreenRoute(
configuration,
context,
chat.id!,
),
),
),
onDeleteChat: (chat) async =>
configuration.onDeleteChat?.call(context, chat) ??
configuration.chatService.chatOverviewService.deleteChat(chat),
deleteChatDialog: configuration.deleteChatDialog,
translations: configuration.translations,
),
);
/// Constructs the chat detail screen route widget.
@ -218,7 +223,7 @@ Widget _newChatScreenRoute(
if (configuration.onPressCreateChat != null) return;
var chat = await configuration.chatService.chatOverviewService
.getChatByUser(user);
debugPrint('Chat is ${chat.id}');
debugPrint("Chat is ${chat.id}");
if (chat.id == null) {
chat = await configuration.chatService.chatOverviewService
.storeChatIfNot(
@ -230,10 +235,13 @@ Widget _newChatScreenRoute(
if (context.mounted) {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => _chatDetailScreenRoute(
configuration,
context,
chat.id!,
builder: (context) => PopScope(
canPop: false,
child: _chatDetailScreenRoute(
configuration,
context,
chat.id!,
),
),
),
);
@ -279,17 +287,20 @@ Widget _newGroupChatOverviewScreenRoute(
GroupChatModel(
canBeDeleted: true,
title: groupChatName,
imageUrl: 'https://picsum.photos/200/300',
imageUrl: "https://picsum.photos/200/300",
users: users,
),
);
if (context.mounted) {
await Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => _chatDetailScreenRoute(
configuration,
context,
chat.id!,
builder: (context) => PopScope(
canPop: false,
child: _chatDetailScreenRoute(
configuration,
context,
chat.id!,
),
),
),
);

View file

@ -2,10 +2,10 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat/flutter_chat.dart';
import 'package:flutter_chat/src/go_router.dart';
import 'package:go_router/go_router.dart';
import "package:flutter/material.dart";
import "package:flutter_chat/flutter_chat.dart";
import "package:flutter_chat/src/go_router.dart";
import "package:go_router/go_router.dart";
List<GoRoute> getChatStoryRoutes(
ChatUserStoryConfiguration configuration,
@ -14,7 +14,6 @@ List<GoRoute> getChatStoryRoutes(
GoRoute(
path: ChatUserStoryRoutes.chatScreen,
pageBuilder: (context, state) {
var theme = Theme.of(context);
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var chatScreen = ChatScreen(
@ -43,24 +42,27 @@ List<GoRoute> getChatStoryRoutes(
return buildScreenWithoutTransition(
context: context,
state: state,
child: configuration.chatPageBuilder?.call(
context,
chatScreen,
) ??
Scaffold(
backgroundColor: theme.colorScheme.surface,
body: chatScreen,
),
child: PopScope(
canPop: configuration.onPopInvoked == null,
onPopInvoked: (didPop) =>
configuration.onPopInvoked?.call(didPop, context),
child: configuration.chatPageBuilder?.call(
context,
chatScreen,
) ??
Scaffold(
body: chatScreen,
),
),
);
},
),
GoRoute(
path: ChatUserStoryRoutes.chatDetailScreen,
pageBuilder: (context, state) {
var chatId = state.pathParameters['id'];
var chatId = state.pathParameters["id"];
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var theme = Theme.of(context);
var chatDetailScreen = ChatDetailScreen(
chatTitleBuilder: configuration.chatTitleBuilder,
@ -122,7 +124,6 @@ List<GoRoute> getChatStoryRoutes(
chatDetailScreen,
) ??
Scaffold(
backgroundColor: theme.colorScheme.surface,
body: chatDetailScreen,
),
);
@ -133,7 +134,6 @@ List<GoRoute> getChatStoryRoutes(
pageBuilder: (context, state) {
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var theme = Theme.of(context);
var newChatScreen = NewChatScreen(
options: configuration.chatOptionsBuilder(context),
@ -156,7 +156,7 @@ List<GoRoute> getChatStoryRoutes(
}
if (context.mounted) {
await context.push(
ChatUserStoryRoutes.chatDetailViewPath(chat.id ?? ''),
ChatUserStoryRoutes.chatDetailViewPath(chat.id ?? ""),
);
}
},
@ -172,7 +172,6 @@ List<GoRoute> getChatStoryRoutes(
newChatScreen,
) ??
Scaffold(
backgroundColor: theme.colorScheme.surface,
body: newChatScreen,
),
);
@ -183,7 +182,6 @@ List<GoRoute> getChatStoryRoutes(
pageBuilder: (context, state) {
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var theme = Theme.of(context);
var newGroupChatScreen = NewGroupChatScreen(
options: configuration.chatOptionsBuilder(context),
@ -203,7 +201,6 @@ List<GoRoute> getChatStoryRoutes(
newGroupChatScreen,
) ??
Scaffold(
backgroundColor: theme.colorScheme.surface,
body: newGroupChatScreen,
),
);
@ -215,7 +212,6 @@ List<GoRoute> getChatStoryRoutes(
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var users = state.extra! as List<ChatUserModel>;
var theme = Theme.of(context);
var newGroupChatOverviewScreen = NewGroupChatOverviewScreen(
options: configuration.chatOptionsBuilder(context),
@ -231,13 +227,13 @@ List<GoRoute> getChatStoryRoutes(
GroupChatModel(
canBeDeleted: true,
title: groupChatName,
imageUrl: 'https://picsum.photos/200/300',
imageUrl: "https://picsum.photos/200/300",
users: users,
),
);
if (context.mounted) {
context.go(
ChatUserStoryRoutes.chatDetailViewPath(chat.id ?? ''),
ChatUserStoryRoutes.chatDetailViewPath(chat.id ?? ""),
);
}
},
@ -250,7 +246,6 @@ List<GoRoute> getChatStoryRoutes(
newGroupChatOverviewScreen,
) ??
Scaffold(
backgroundColor: theme.colorScheme.surface,
body: newGroupChatOverviewScreen,
),
);
@ -259,12 +254,11 @@ List<GoRoute> getChatStoryRoutes(
GoRoute(
path: ChatUserStoryRoutes.chatProfileScreen,
pageBuilder: (context, state) {
var chatId = state.pathParameters['id'];
var userId = state.pathParameters['userId'];
var id = userId == 'null' ? null : userId;
var chatId = state.pathParameters["id"];
var userId = state.pathParameters["userId"];
var id = userId == "null" ? null : userId;
var service = configuration.chatServiceBuilder?.call(context) ??
configuration.chatService;
var theme = Theme.of(context);
var profileScreen = ChatProfileScreen(
translations: configuration.translationsBuilder?.call(context) ??
@ -290,7 +284,6 @@ List<GoRoute> getChatStoryRoutes(
profileScreen,
) ??
Scaffold(
backgroundColor: theme.colorScheme.surface,
body: profileScreen,
),
);

View file

@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import "package:flutter/material.dart";
import "package:go_router/go_router.dart";
/// Builds a screen with a fade transition.
///

View file

@ -2,10 +2,10 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'dart:typed_data';
import "dart:typed_data";
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
/// `ChatUserStoryConfiguration` is a class that configures the chat user story.
@immutable
@ -21,6 +21,7 @@ class ChatUserStoryConfiguration {
this.onMessageSubmit,
this.onReadChat,
this.onUploadImage,
this.onPopInvoked,
this.onPressCreateChat,
this.onPressCreateGroupChat,
this.onPressCompleteGroupChatCreation,
@ -118,6 +119,11 @@ class ChatUserStoryConfiguration {
/// Callback function triggered when user profile is pressed.
final Function(BuildContext context, ChatUserModel user)? onPressUserProfile;
/// Callback function triggered when the popscope on the chat
/// homepage is triggered.
// ignore: avoid_positional_boolean_parameters
final Function(bool didPop, BuildContext context)? onPopInvoked;
final double? textfieldBottomPadding;
final Color? iconDisabledColor;

View file

@ -4,19 +4,19 @@
/// Provides route paths for the chat user story.
mixin ChatUserStoryRoutes {
static const String chatScreen = '/chat';
static const String chatScreen = "/chat";
/// Constructs the path for the chat detail view.
static String chatDetailViewPath(String chatId) => '/chat-detail/$chatId';
static String chatDetailViewPath(String chatId) => "/chat-detail/$chatId";
static const String chatDetailScreen = '/chat-detail/:id';
static const String newChatScreen = '/new-chat';
static const String chatDetailScreen = "/chat-detail/:id";
static const String newChatScreen = "/new-chat";
/// Constructs the path for the chat profile screen.
static const String newGroupChatScreen = '/new-group-chat';
static const String newGroupChatOverviewScreen = '/new-group-chat-overview';
static const String newGroupChatScreen = "/new-group-chat";
static const String newGroupChatOverviewScreen = "/new-group-chat-overview";
static String chatProfileScreenPath(String chatId, String? userId) =>
'/chat-profile/$chatId/$userId';
"/chat-profile/$chatId/$userId";
static const String chatProfileScreen = '/chat-profile/:id/:userId';
static const String chatProfileScreen = "/chat-profile/:id/:userId";
}

View file

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

View file

@ -2,19 +2,19 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import "package:flutter/material.dart";
/// Options for Firebase chat configuration.
@immutable
class FirebaseChatOptions {
/// Creates a new instance of `FirebaseChatOptions`.
const FirebaseChatOptions({
this.groupChatsCollectionName = 'group_chats',
this.chatsCollectionName = 'chats',
this.messagesCollectionName = 'messages',
this.usersCollectionName = 'users',
this.chatsMetaDataCollectionName = 'chat_metadata',
this.userChatsCollectionName = 'chats',
this.groupChatsCollectionName = "group_chats",
this.chatsCollectionName = "chats",
this.messagesCollectionName = "messages",
this.usersCollectionName = "users",
this.chatsMetaDataCollectionName = "chat_metadata",
this.userChatsCollectionName = "chats",
});
/// The collection name for group chats.

View file

@ -2,9 +2,9 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_chat_firebase/dto/firebase_message_document.dart';
import "package:cloud_firestore/cloud_firestore.dart";
import "package:flutter/material.dart";
import "package:flutter_chat_firebase/dto/firebase_message_document.dart";
/// Represents a chat document in Firebase.
@immutable
@ -23,16 +23,16 @@ class FirebaseChatDocument {
/// Constructs a FirebaseChatDocument from JSON.
FirebaseChatDocument.fromJson(Map<String, dynamic> json, this.id)
: title = json['title'],
imageUrl = json['image_url'],
personal = json['personal'],
canBeDeleted = json['can_be_deleted'] ?? true,
lastUsed = json['last_used'],
users = json['users'] != null ? List<String>.from(json['users']) : [],
lastMessage = json['last_message'] == null
: title = json["title"],
imageUrl = json["image_url"],
personal = json["personal"],
canBeDeleted = json["can_be_deleted"] ?? true,
lastUsed = json["last_used"],
users = json["users"] != null ? List<String>.from(json["users"]) : [],
lastMessage = json["last_message"] == null
? null
: FirebaseMessageDocument.fromJson(
json['last_message'],
json["last_message"],
null,
);
@ -62,11 +62,11 @@ class FirebaseChatDocument {
/// Converts the FirebaseChatDocument to JSON format.
Map<String, dynamic> toJson() => {
'title': title,
'image_url': imageUrl,
'personal': personal,
'last_used': lastUsed,
'can_be_deleted': canBeDeleted,
'users': users,
"title": title,
"image_url": imageUrl,
"personal": personal,
"last_used": lastUsed,
"can_be_deleted": canBeDeleted,
"users": users,
};
}

View file

@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import "package:cloud_firestore/cloud_firestore.dart";
import "package:flutter/material.dart";
/// Represents a message document in Firebase.
@immutable
@ -19,10 +19,10 @@ class FirebaseMessageDocument {
/// Constructs a FirebaseMessageDocument from JSON.
FirebaseMessageDocument.fromJson(Map<String, dynamic> json, this.id)
: sender = json['sender'],
text = json['text'],
imageUrl = json['image_url'],
timestamp = json['timestamp'];
: sender = json["sender"],
text = json["text"],
imageUrl = json["image_url"],
timestamp = json["timestamp"];
/// The unique identifier of the message document.
final String? id;
@ -41,9 +41,9 @@ class FirebaseMessageDocument {
/// Converts the FirebaseMessageDocument to JSON format.
Map<String, dynamic> toJson() => {
'sender': sender,
'text': text,
'image_url': imageUrl,
'timestamp': timestamp,
"sender": sender,
"text": text,
"image_url": imageUrl,
"timestamp": timestamp,
};
}

View file

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import "package:flutter/material.dart";
/// Represents a user document in Firebase.
@immutable
@ -22,11 +22,11 @@ class FirebaseUserDocument {
) : this(
id: id,
firstName:
json['first_name'] == null ? '' : json['first_name']! as String,
json["first_name"] == null ? "" : json["first_name"]! as String,
lastName:
json['last_name'] == null ? '' : json['last_name']! as String,
json["last_name"] == null ? "" : json["last_name"]! as String,
imageUrl:
json['image_url'] == null ? null : json['image_url']! as String,
json["image_url"] == null ? null : json["image_url"]! as String,
);
/// The first name of the user.
@ -43,8 +43,8 @@ class FirebaseUserDocument {
/// Converts the FirebaseUserDocument to JSON format.
Map<String, Object?> toJson() => {
'first_name': firstName,
'last_name': lastName,
'image_url': imageUrl,
"first_name": firstName,
"last_name": lastName,
"image_url": imageUrl,
};
}

View file

@ -4,4 +4,4 @@
///
library flutter_chat_firebase;
export 'package:flutter_chat_firebase/service/service.dart';
export "package:flutter_chat_firebase/service/service.dart";

View file

@ -2,16 +2,16 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'dart:async';
import 'dart:typed_data';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_chat_firebase/config/firebase_chat_options.dart';
import 'package:flutter_chat_firebase/dto/firebase_message_document.dart';
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
import 'package:uuid/uuid.dart';
import "dart:async";
import "dart:typed_data";
import "package:cloud_firestore/cloud_firestore.dart";
import "package:firebase_core/firebase_core.dart";
import "package:firebase_storage/firebase_storage.dart";
import "package:flutter/material.dart";
import "package:flutter_chat_firebase/config/firebase_chat_options.dart";
import "package:flutter_chat_firebase/dto/firebase_message_document.dart";
import "package:flutter_chat_interface/flutter_chat_interface.dart";
import "package:uuid/uuid.dart";
/// Service class for managing chat details using Firebase.
class FirebaseChatDetailService
@ -56,8 +56,8 @@ class FirebaseChatDetailService
}
var message = {
'sender': currentUser.id,
'timestamp': DateTime.now(),
"sender": currentUser.id,
"timestamp": DateTime.now(),
...data,
};
@ -89,8 +89,8 @@ class FirebaseChatDetailService
.doc(chatId);
await metadataReference.update({
'last_used': DateTime.now(),
'last_message': message,
"last_used": DateTime.now(),
"last_message": message,
});
// update the chat counter for the other users
@ -98,7 +98,7 @@ class FirebaseChatDetailService
// there is a field in the chat document called users that has a
// list of user ids
var fetchedChat = await metadataReference.get();
var chatUsers = fetchedChat.data()?['users'] as List<dynamic>;
var chatUsers = fetchedChat.data()?["users"] as List<dynamic>;
// for all users except the message sender update the unread counter
for (var userId in chatUsers) {
if (userId != currentUser.id) {
@ -113,15 +113,15 @@ class FirebaseChatDetailService
// it should be created when the chat is create
if ((await userReference.get())
.data()
?.containsKey('amount_unread_messages') ??
?.containsKey("amount_unread_messages") ??
false) {
await userReference.update({
'amount_unread_messages': FieldValue.increment(1),
"amount_unread_messages": FieldValue.increment(1),
});
} else {
await userReference.set(
{
'amount_unread_messages': 1,
"amount_unread_messages": 1,
},
SetOptions(merge: true),
);
@ -142,7 +142,7 @@ class FirebaseChatDetailService
_sendMessage(
chatId,
{
'text': text,
"text": text,
},
);
@ -156,7 +156,7 @@ class FirebaseChatDetailService
required Uint8List image,
}) async {
var ref = _storage
.ref('${_options.chatsCollectionName}/$chatId/${const Uuid().v4()}');
.ref("${_options.chatsCollectionName}/$chatId/${const Uuid().v4()}");
return ref.putData(image).then(
(_) => ref.getDownloadURL().then(
@ -164,7 +164,7 @@ class FirebaseChatDetailService
_sendMessage(
chatId,
{
'image_url': url,
"image_url": url,
},
);
},
@ -186,7 +186,7 @@ class FirebaseChatDetailService
.doc(chatId)
.collection(_options.messagesCollectionName)
.where(
'timestamp',
"timestamp",
isGreaterThan: timestampToFilter,
)
.withConverter<FirebaseMessageDocument>(
@ -241,7 +241,7 @@ class FirebaseChatDetailService
_cumulativeMessages = [];
lastChat = chatId;
lastMessage = null;
debugPrint('Canceling messages stream');
debugPrint("Canceling messages stream");
},
);
@ -280,7 +280,7 @@ class FirebaseChatDetailService
.collection(_options.chatsCollectionName)
.doc(chatId)
.collection(_options.messagesCollectionName)
.orderBy('timestamp', descending: true)
.orderBy("timestamp", descending: true)
.limit(pageSize);
if (lastMessage == null) {
messagesQuerySnapshot = await query

View file

@ -3,14 +3,14 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'dart:async';
import "dart:async";
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter_chat_firebase/config/firebase_chat_options.dart';
import 'package:flutter_chat_firebase/dto/firebase_chat_document.dart';
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
import "package:cloud_firestore/cloud_firestore.dart";
import "package:firebase_core/firebase_core.dart";
import "package:firebase_storage/firebase_storage.dart";
import "package:flutter_chat_firebase/config/firebase_chat_options.dart";
import "package:flutter_chat_firebase/dto/firebase_chat_document.dart";
import "package:flutter_chat_interface/flutter_chat_interface.dart";
/// Service class for managing chat overviews using Firebase.
class FirebaseChatOverviewService implements ChatOverviewService {
@ -49,7 +49,7 @@ class FirebaseChatOverviewService implements ChatOverviewService {
.doc(chatId)
.get();
return snapshots.data()?['amount_unread_messages'];
return snapshots.data()?["amount_unread_messages"];
}
/// Retrieves a stream of chat overviews.
@ -144,8 +144,8 @@ class FirebaseChatOverviewService implements ChatOverviewService {
}
chatModel = GroupChatModel(
id: chat.id,
title: chat.title ?? '',
imageUrl: chat.imageUrl ?? '',
title: chat.title ?? "",
imageUrl: chat.imageUrl ?? "",
unreadMessages: unread,
users: users,
lastMessage: chat.lastMessage != null && otherUser != null
@ -226,7 +226,7 @@ class FirebaseChatOverviewService implements ChatOverviewService {
.collection(_options.usersCollectionName)
.doc(currentUser?.id)
.collection(_options.userChatsCollectionName)
.where('users', arrayContains: user.id)
.where("users", arrayContains: user.id)
.get();
var doc = collection.docs.isNotEmpty ? collection.docs.first : null;
@ -250,16 +250,16 @@ class FirebaseChatOverviewService implements ChatOverviewService {
.doc(chatId)
.get();
if (chatCollection.exists && chatCollection.data()?['users'] != null) {
if (chatCollection.exists && chatCollection.data()?["users"] != null) {
// ignore: avoid_dynamic_calls
var otherUser = chatCollection.data()?['users'].firstWhere(
var otherUser = chatCollection.data()?["users"].firstWhere(
(element) => element != currentUser?.id,
);
var user = await _userService.getUser(otherUser);
return PersonalChatModel(
id: chatId,
user: user!,
canBeDeleted: chatCollection.data()?['can_be_deleted'] ?? true,
canBeDeleted: chatCollection.data()?["can_be_deleted"] ?? true,
);
} else {
var groupChatCollection = await _db
@ -281,8 +281,8 @@ class FirebaseChatOverviewService implements ChatOverviewService {
}
return GroupChatModel(
id: chat?.id ?? chatId,
title: chat?.title ?? '',
imageUrl: chat?.imageUrl ?? '',
title: chat?.title ?? "",
imageUrl: chat?.imageUrl ?? "",
users: users,
canBeDeleted: chat?.canBeDeleted ?? true,
);
@ -373,7 +373,7 @@ class FirebaseChatOverviewService implements ChatOverviewService {
.doc(userId)
.collection(_options.userChatsCollectionName)
.doc(reference.id)
.set({'users': userIds}, SetOptions(merge: true));
.set({"users": userIds}, SetOptions(merge: true));
}
chat.id = reference.id;
@ -411,11 +411,11 @@ class FirebaseChatOverviewService implements ChatOverviewService {
.doc(userId)
.collection(_options.groupChatsCollectionName)
.doc(reference.id)
.set({'users': userIds}, SetOptions(merge: true));
.set({"users": userIds}, SetOptions(merge: true));
}
chat.id = reference.id;
} else {
throw Exception('Chat type not supported for firebase');
throw Exception("Chat type not supported for firebase");
}
}
@ -443,7 +443,7 @@ class FirebaseChatOverviewService implements ChatOverviewService {
// every chat has a field called amount_unread_messages, combine all
// of these fields to get the total amount of unread messages
var unreadChats = event.docs
.map((chat) => chat.data()['amount_unread_messages'] ?? 0)
.map((chat) => chat.data()["amount_unread_messages"] ?? 0)
.toList();
var totalUnreadChats = unreadChats.fold<int>(
0,
@ -476,6 +476,6 @@ class FirebaseChatOverviewService implements ChatOverviewService {
.doc(currentUser!.id)
.collection(_options.userChatsCollectionName)
.doc(chat.id)
.set({'amount_unread_messages': 0}, SetOptions(merge: true));
.set({"amount_unread_messages": 0}, SetOptions(merge: true));
}
}

View file

@ -1,7 +1,7 @@
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';
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";
/// Service class for managing chat services using Firebase.
class FirebaseChatService implements ChatService {

View file

@ -2,12 +2,12 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_chat_firebase/config/firebase_chat_options.dart';
import 'package:flutter_chat_firebase/dto/firebase_user_document.dart';
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
import "package:cloud_firestore/cloud_firestore.dart";
import "package:firebase_auth/firebase_auth.dart";
import "package:firebase_core/firebase_core.dart";
import "package:flutter_chat_firebase/config/firebase_chat_options.dart";
import "package:flutter_chat_firebase/dto/firebase_user_document.dart";
import "package:flutter_chat_interface/flutter_chat_interface.dart";
/// Service class for managing chat users using Firebase.
class FirebaseChatUserService implements ChatUserService {

View file

@ -1,4 +1,4 @@
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';
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";
export "package:flutter_chat_firebase/service/firebase_chat_user_service.dart";

View file

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

View file

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

View file

@ -1,7 +1,7 @@
///
library local_chat_service;
export 'service/local_chat_detail_service.dart';
export 'service/local_chat_overview_service.dart';
export 'service/local_chat_service.dart';
export 'service/local_chat_user_service.dart';
export "service/local_chat_detail_service.dart";
export "service/local_chat_overview_service.dart";
export "service/local_chat_service.dart";
export "service/local_chat_user_service.dart";

View file

@ -1,8 +1,8 @@
import 'dart:async';
import "dart:async";
import 'package:flutter/foundation.dart';
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
import 'package:flutter_chat_local/local_chat_service.dart';
import "package:flutter/foundation.dart";
import "package:flutter_chat_interface/flutter_chat_interface.dart";
import "package:flutter_chat_local/local_chat_service.dart";
/// A class providing local chat detail service implementation.
class LocalChatDetailService with ChangeNotifier implements ChatDetailService {
@ -69,13 +69,13 @@ class LocalChatDetailService with ChangeNotifier implements ChatDetailService {
.firstWhere((element) => element.id == chatId);
var message = ChatImageMessageModel(
sender: const ChatUserModel(
id: '3',
firstName: 'ico',
lastName: 'nica',
imageUrl: 'https://picsum.photos/100/200',
id: "3",
firstName: "ico",
lastName: "nica",
imageUrl: "https://picsum.photos/100/200",
),
timestamp: DateTime.now(),
imageUrl: 'https://picsum.photos/200/300',
imageUrl: "https://picsum.photos/200/300",
);
await (chatOverviewService as LocalChatOverviewService).updateChat(
@ -102,10 +102,10 @@ class LocalChatDetailService with ChangeNotifier implements ChatDetailService {
.firstWhere((element) => element.id == chatId);
var message = ChatTextMessageModel(
sender: const ChatUserModel(
id: '3',
firstName: 'ico',
lastName: 'nica',
imageUrl: 'https://picsum.photos/100/200',
id: "3",
firstName: "ico",
lastName: "nica",
imageUrl: "https://picsum.photos/100/200",
),
timestamp: DateTime.now(),
text: text,

View file

@ -1,7 +1,7 @@
import 'dart:async';
import "dart:async";
import 'package:flutter/foundation.dart';
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
import "package:flutter/foundation.dart";
import "package:flutter_chat_interface/flutter_chat_interface.dart";
/// A class providing local chat overview service implementation.
class LocalChatOverviewService
@ -22,7 +22,7 @@ class LocalChatOverviewService
_chats[index] = chat;
_chatsController.addStream(Stream.value(_chats));
notifyListeners();
debugPrint('Chat updated: $chat');
debugPrint("Chat updated: $chat");
return Future.value();
}
@ -31,15 +31,15 @@ class LocalChatOverviewService
_chats.removeWhere((element) => element.id == chat.id);
_chatsController.add(_chats);
notifyListeners();
debugPrint('Chat deleted: $chat');
debugPrint("Chat deleted: $chat");
return Future.value();
}
@override
Future<ChatModel> getChatById(String id) {
var chat = _chats.firstWhere((element) => element.id == id);
debugPrint('Retrieved chat by ID: $chat');
debugPrint('Messages are: ${chat.messages?.length}');
debugPrint("Retrieved chat by ID: $chat");
debugPrint("Messages are: ${chat.messages?.length}");
return Future.value(chat);
}
@ -55,11 +55,11 @@ class LocalChatOverviewService
chat = PersonalChatModel(
user: user,
messages: [],
id: '',
id: "",
);
chat.id = chat.hashCode.toString();
_chats.add(chat);
debugPrint('New chat created: $chat');
debugPrint("New chat created: $chat");
}
_chatsController.add([..._chats]);
@ -85,9 +85,9 @@ class LocalChatOverviewService
_chats.add(chat);
_chatsController.add([..._chats]);
notifyListeners();
debugPrint('Chat stored: $chat');
debugPrint("Chat stored: $chat");
} else {
debugPrint('Chat already exists: $chat');
debugPrint("Chat already exists: $chat");
}
return Future.value(chat);

View file

@ -1,7 +1,7 @@
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
import 'package:flutter_chat_local/service/local_chat_detail_service.dart';
import 'package:flutter_chat_local/service/local_chat_overview_service.dart';
import 'package:flutter_chat_local/service/local_chat_user_service.dart';
import "package:flutter_chat_interface/flutter_chat_interface.dart";
import "package:flutter_chat_local/service/local_chat_detail_service.dart";
import "package:flutter_chat_local/service/local_chat_overview_service.dart";
import "package:flutter_chat_local/service/local_chat_user_service.dart";
/// Service class for managing local chat services.
class LocalChatService implements ChatService {

View file

@ -1,32 +1,32 @@
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
import "package:flutter_chat_interface/flutter_chat_interface.dart";
/// Service class for managing local chat users.
class LocalChatUserService implements ChatUserService {
/// List of predefined chat users.
List<ChatUserModel> users = [
const ChatUserModel(
id: '1',
firstName: 'John',
lastName: 'Doe',
imageUrl: 'https://picsum.photos/200/300',
id: "1",
firstName: "John",
lastName: "Doe",
imageUrl: "https://picsum.photos/200/300",
),
const ChatUserModel(
id: '2',
firstName: 'Jane',
lastName: 'Doe',
imageUrl: 'https://picsum.photos/200/300',
id: "2",
firstName: "Jane",
lastName: "Doe",
imageUrl: "https://picsum.photos/200/300",
),
const ChatUserModel(
id: '3',
firstName: 'ico',
lastName: 'nica',
imageUrl: 'https://picsum.photos/100/200',
id: "3",
firstName: "ico",
lastName: "nica",
imageUrl: "https://picsum.photos/100/200",
),
];
@override
Future<List<ChatUserModel>> getAllUsers() =>
Future.value(users.where((element) => element.id != '3').toList());
Future.value(users.where((element) => element.id != "3").toList());
@override
Future<ChatUserModel?> getCurrentUser() =>

View file

@ -1,6 +1,6 @@
name: flutter_chat_local
description: "A new Flutter package project."
version: 3.0.0
version: 3.0.1
publish_to: none
environment:
@ -14,7 +14,7 @@ dependencies:
git:
url: https://github.com/Iconica-Development/flutter_chat
path: packages/flutter_chat_interface
ref: 3.0.0
ref: 3.0.1
dev_dependencies:
flutter_test:

View file

@ -4,14 +4,14 @@
///
library flutter_chat_view;
export 'package:flutter_chat_interface/flutter_chat_interface.dart';
export "package:flutter_chat_interface/flutter_chat_interface.dart";
export 'src/components/chat_row.dart';
export 'src/config/chat_options.dart';
export 'src/config/chat_translations.dart';
export 'src/screens/chat_detail_screen.dart';
export 'src/screens/chat_profile_screen.dart';
export 'src/screens/chat_screen.dart';
export 'src/screens/new_chat_screen.dart';
export 'src/screens/new_group_chat_overview_screen.dart';
export 'src/screens/new_group_chat_screen.dart';
export "src/components/chat_row.dart";
export "src/config/chat_options.dart";
export "src/config/chat_translations.dart";
export "src/screens/chat_detail_screen.dart";
export "src/screens/chat_profile_screen.dart";
export "src/screens/chat_screen.dart";
export "src/screens/new_chat_screen.dart";
export "src/screens/new_group_chat_overview_screen.dart";
export "src/screens/new_group_chat_screen.dart";

View file

@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
class ChatBottom extends StatefulWidget {
const ChatBottom({

View file

@ -2,11 +2,11 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import 'package:flutter_chat_view/src/components/chat_image.dart';
import 'package:flutter_chat_view/src/services/date_formatter.dart';
import "package:cached_network_image/cached_network_image.dart";
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
import "package:flutter_chat_view/src/components/chat_image.dart";
import "package:flutter_chat_view/src/services/date_formatter.dart";
class ChatDetailRow extends StatefulWidget {
const ChatDetailRow({
@ -46,6 +46,8 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var isNewDate = widget.previousMessage != null &&
widget.message.timestamp.day != widget.previousMessage?.timestamp.day;
var isSameSender = widget.previousMessage == null ||
@ -54,7 +56,6 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
widget.message.timestamp.minute ==
widget.previousMessage?.timestamp.minute;
var hasHeader = isNewDate || isSameSender;
var theme = Theme.of(context);
return Padding(
padding: EdgeInsets.only(
top: isNewDate || isSameSender ? 25.0 : 0,
@ -69,8 +70,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
),
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: widget.message.sender.imageUrl != null &&
widget.message.sender.imageUrl!.isNotEmpty
child: widget.message.sender.imageUrl?.isNotEmpty ?? false
? ChatImage(
image: widget.message.sender.imageUrl!,
)
@ -92,27 +92,24 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (isNewDate || isSameSender)
if (isNewDate || isSameSender) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (widget.usernameBuilder != null)
widget.usernameBuilder!(
widget.message.sender.fullName ?? '',
)
else
Text(
widget.message.sender.fullName ??
widget.translations.anonymousUser,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w800,
color: Theme.of(context)
.textTheme
.labelMedium
?.color,
),
),
Expanded(
child: widget.usernameBuilder?.call(
widget.message.sender.fullName ?? "",
) ??
Text(
widget.message.sender.fullName ??
widget.translations.anonymousUser,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w800,
color: theme.textTheme.labelMedium?.color,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text(
@ -129,6 +126,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
),
],
),
],
Padding(
padding: const EdgeInsets.only(top: 3.0),
child: widget.message is ChatTextMessageModel
@ -141,10 +139,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
(widget.message as ChatTextMessageModel).text,
style: TextStyle(
fontSize: 16,
color: Theme.of(context)
.textTheme
.labelMedium
?.color,
color: theme.textTheme.labelMedium?.color,
),
),
),
@ -158,7 +153,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
date: widget.message.timestamp,
showFullDate: true,
)
.split(' ')
.split(" ")
.last,
style: theme.textTheme.bodySmall,
textAlign: TextAlign.end,

View file

@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import "package:cached_network_image/cached_network_image.dart";
import "package:flutter/material.dart";
/// A stateless widget representing an image in the chat.
class ChatImage extends StatelessWidget {

View file

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import "package:flutter/material.dart";
class ChatRow extends StatelessWidget {
const ChatRow({

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
SnackBar getImageLoadingSnackbar(ChatTranslations translations) => SnackBar(
duration: const Duration(minutes: 1),

View file

@ -2,11 +2,11 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import 'package:flutter_chat_view/src/components/chat_image.dart';
import 'package:flutter_image_picker/flutter_image_picker.dart';
import 'package:flutter_profile/flutter_profile.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
import "package:flutter_chat_view/src/components/chat_image.dart";
import "package:flutter_image_picker/flutter_image_picker.dart";
import "package:flutter_profile/flutter_profile.dart";
class ChatOptions {
const ChatOptions({
@ -133,7 +133,7 @@ Widget _createChatRowContainer(
vertical: 12.0,
horizontal: 10.0,
),
child: Container(
child: ColoredBox(
color: Colors.transparent,
child: chatRow,
),
@ -177,6 +177,7 @@ Scaffold _createScaffold(
Scaffold(
appBar: appbar,
body: body,
backgroundColor: backgroundColor,
);
Widget _createUserAvatar(

View file

@ -44,39 +44,39 @@ class ChatTranslations {
/// Default translations for the chat component view
const ChatTranslations.empty({
this.chatsTitle = 'Chats',
this.chatsUnread = 'unread',
this.newChatButton = 'Start chat',
this.newGroupChatButton = 'Create a group chat',
this.newChatTitle = 'Start a chat',
this.image = 'Image',
this.searchPlaceholder = 'Search...',
this.startTyping = 'Start typing to find a user to chat with',
this.cancelImagePickerBtn = 'Cancel',
this.messagePlaceholder = 'Write your message here...',
this.writeMessageToStartChat = 'Write a message to start the chat',
this.chatsTitle = "Chats",
this.chatsUnread = "unread",
this.newChatButton = "Start chat",
this.newGroupChatButton = "Create a group chat",
this.newChatTitle = "Start a chat",
this.image = "Image",
this.searchPlaceholder = "Search...",
this.startTyping = "Start typing to find a user to chat with",
this.cancelImagePickerBtn = "Cancel",
this.messagePlaceholder = "Write your message here...",
this.writeMessageToStartChat = "Write a message to start the chat",
this.writeFirstMessageInGroupChat =
'Write the first message in this group chat',
this.imageUploading = 'Image is uploading...',
this.deleteChatButton = 'Delete',
this.deleteChatModalTitle = 'Delete chat',
"Write the first message in this group chat",
this.imageUploading = "Image is uploading...",
this.deleteChatButton = "Delete",
this.deleteChatModalTitle = "Delete chat",
this.deleteChatModalDescription =
'Are you sure you want to delete this chat?',
this.deleteChatModalCancel = 'Cancel',
this.deleteChatModalConfirm = 'Delete',
this.noUsersFound = 'No users were found to start a chat with',
this.noChatsFound = 'Click on \'Start a chat\' to create a new chat',
this.anonymousUser = 'Anonymous user',
this.chatCantBeDeleted = 'This chat can\'t be deleted',
this.chatProfileUsers = 'Users:',
this.imagePickerTitle = 'Do you want to upload a file or take a picture?',
this.uploadFile = 'UPLOAD FILE',
this.takePicture = 'TAKE PICTURE',
this.groupNameHintText = 'Group chat name',
this.groupNameValidatorEmpty = 'Please enter a group chat name',
"Are you sure you want to delete this chat?",
this.deleteChatModalCancel = "Cancel",
this.deleteChatModalConfirm = "Delete",
this.noUsersFound = "No users were found to start a chat with",
this.noChatsFound = "Click on 'Start a chat' to create a new chat",
this.anonymousUser = "Anonymous user",
this.chatCantBeDeleted = "This chat can't be deleted",
this.chatProfileUsers = "Users:",
this.imagePickerTitle = "Do you want to upload a file or take a picture?",
this.uploadFile = "UPLOAD FILE",
this.takePicture = "TAKE PICTURE",
this.groupNameHintText = "Group chat name",
this.groupNameValidatorEmpty = "Please enter a group chat name",
this.groupNameValidatorTooLong =
'Group name is too long, max 15 characters',
this.newGroupChatTitle = 'New Group Chat',
"Group name is too long, max 15 characters",
this.newGroupChatTitle = "New Group Chat",
});
final String chatsTitle;

View file

@ -2,14 +2,14 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'dart:async';
import 'dart:typed_data';
import "dart:async";
import "dart:typed_data";
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import 'package:flutter_chat_view/src/components/chat_bottom.dart';
import 'package:flutter_chat_view/src/components/chat_detail_row.dart';
import 'package:flutter_chat_view/src/components/image_loading_snackbar.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
import "package:flutter_chat_view/src/components/chat_bottom.dart";
import "package:flutter_chat_view/src/components/chat_detail_row.dart";
import "package:flutter_chat_view/src/components/image_loading_snackbar.dart";
class ChatDetailScreen extends StatefulWidget {
const ChatDetailScreen({
@ -167,8 +167,13 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
future: widget.service.chatOverviewService.getChatById(widget.chatId),
builder: (context, AsyncSnapshot<ChatModel> snapshot) {
var chatModel = snapshot.data;
var chatTitle = (chatModel is GroupChatModel)
? chatModel.title
: (chatModel is PersonalChatModel)
? chatModel.user.firstName ?? widget.translations.anonymousUser
: "";
return Scaffold(
backgroundColor: theme.colorScheme.surface,
appBar: AppBar(
backgroundColor: theme.appBarTheme.backgroundColor,
iconTheme: theme.appBarTheme.iconTheme ??
@ -184,36 +189,12 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
),
title: GestureDetector(
onTap: () => widget.onPressChatTitle.call(context, chatModel!),
child: Row(
mainAxisSize: MainAxisSize.min,
children: chat == null
? []
: [
Padding(
padding: (chatModel is GroupChatModel)
? const EdgeInsets.only(left: 15.5)
: EdgeInsets.zero,
child: widget.chatTitleBuilder != null
? widget.chatTitleBuilder!.call(
(chatModel is GroupChatModel)
? chatModel.title
: (chatModel is PersonalChatModel)
? chatModel.user.firstName ??
widget.translations.anonymousUser
: '',
)
: Text(
(chatModel is GroupChatModel)
? chatModel.title
: (chatModel is PersonalChatModel)
? chatModel.user.firstName ??
widget.translations.anonymousUser
: '',
style: theme.appBarTheme.titleTextStyle,
),
),
],
),
child: widget.chatTitleBuilder?.call(chatTitle) ??
Text(
chatTitle,
style: theme.appBarTheme.titleTextStyle,
overflow: TextOverflow.ellipsis,
),
),
),
body: Stack(
@ -251,7 +232,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
reverse: detailRows.isNotEmpty,
padding: const EdgeInsets.only(top: 24.0),
children: [
if (detailRows.isEmpty)
if (detailRows.isEmpty && !showIndicator) ...[
Center(
child: Text(
(chatModel is GroupChatModel)
@ -262,12 +243,13 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
style: theme.textTheme.bodySmall,
),
),
],
...detailRows,
],
),
),
),
if (chatModel != null)
if (chatModel != null) ...[
ChatBottom(
chat: chatModel,
messageInputBuilder: widget.options.messageInputBuilder,
@ -277,12 +259,13 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
iconColor: widget.iconColor,
iconDisabledColor: widget.iconDisabledColor,
),
],
SizedBox(
height: widget.textfieldBottomPadding,
),
],
),
if (showIndicator)
if (showIndicator) ...[
widget.loadingWidgetBuilder?.call(context) ??
const Column(
children: [
@ -295,6 +278,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
),
],
),
],
],
),
);

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import 'package:flutter_profile/flutter_profile.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
import "package:flutter_profile/flutter_profile.dart";
class ChatProfileScreen extends StatefulWidget {
const ChatProfileScreen({
@ -66,7 +66,6 @@ class _ProfileScreenState extends State<ChatProfileScreen> {
);
}
return Scaffold(
backgroundColor: theme.colorScheme.surface,
appBar: AppBar(
backgroundColor: theme.appBarTheme.backgroundColor,
iconTheme: theme.appBarTheme.iconTheme ??
@ -75,10 +74,10 @@ class _ProfileScreenState extends State<ChatProfileScreen> {
(data is ChatUserModel)
? '${data.firstName ?? ''} ${data.lastName ?? ''}'
: (data is PersonalChatModel)
? data.user.fullName ?? ''
? data.user.fullName ?? ""
: (data is GroupChatModel)
? data.title
: '',
: "",
style: theme.appBarTheme.titleTextStyle,
),
),
@ -111,8 +110,8 @@ class _ProfileScreenState extends State<ChatProfileScreen> {
),
...data.users.map((e) {
var user = User(
firstName: e.firstName ?? '',
lastName: e.lastName ?? '',
firstName: e.firstName ?? "",
lastName: e.lastName ?? "",
imageUrl: e.imageUrl,
);
return Padding(

View file

@ -4,11 +4,11 @@
// ignore_for_file: lines_longer_than_80_chars
import 'dart:async';
import "dart:async";
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import 'package:flutter_chat_view/src/services/date_formatter.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
import "package:flutter_chat_view/src/services/date_formatter.dart";
class ChatScreen extends StatefulWidget {
const ChatScreen({
@ -94,7 +94,7 @@ class _ChatScreenState extends State<ChatScreen> {
child: Padding(
padding: const EdgeInsets.only(right: 22.0),
child: Text(
'${snapshot.data ?? 0} ${translations.chatsUnread}',
"${snapshot.data ?? 0} ${translations.chatsUnread}",
style: widget.unreadMessageTextStyle ??
const TextStyle(
color: Colors.white,
@ -143,13 +143,11 @@ class _ChatScreenState extends State<ChatScreen> {
for (ChatModel chat in (snapshot.data ?? []).where(
(chat) => !deletedChats.contains(chat.id),
)) ...[
Container(
DecoratedBox(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context)
.colorScheme
.secondary
color: theme.colorScheme.secondary
.withOpacity(0.3),
width: 0.5,
),
@ -269,7 +267,7 @@ class _ChatScreenState extends State<ChatScreen> {
});
widget.onDeleteChat(chat);
},
background: Container(
background: ColoredBox(
color: Colors.red,
child: Align(
alignment: Alignment.centerRight,
@ -354,9 +352,9 @@ class ChatListItem extends StatelessWidget {
subTitle: chat.lastMessage != null
? chat.lastMessage is ChatTextMessageModel
? (chat.lastMessage! as ChatTextMessageModel).text
: '📷 '
'${translations.image}'
: '',
: "📷 "
"${translations.image}"
: "",
lastUsed: chat.lastUsed != null
? _dateFormatter.format(
date: chat.lastUsed!,
@ -369,9 +367,9 @@ class ChatListItem extends StatelessWidget {
subTitle: chat.lastMessage != null
? chat.lastMessage is ChatTextMessageModel
? (chat.lastMessage! as ChatTextMessageModel).text
: '📷 '
'${translations.image}'
: '',
: "📷 "
"${translations.image}"
: "",
avatar: widget.options.groupAvatarBuilder(
(chat as GroupChatModel).title,
(chat as GroupChatModel).imageUrl,

View file

@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
class NewChatScreen extends StatefulWidget {
const NewChatScreen({
@ -41,13 +41,12 @@ class NewChatScreen extends StatefulWidget {
class _NewChatScreenState extends State<NewChatScreen> {
final FocusNode _textFieldFocusNode = FocusNode();
bool _isSearching = false;
String query = '';
String query = "";
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
return Scaffold(
backgroundColor: theme.colorScheme.surface,
appBar: AppBar(
iconTheme: theme.appBarTheme.iconTheme ??
const IconThemeData(color: Colors.white),
@ -111,7 +110,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
return Text("Error: ${snapshot.error}");
} else if (snapshot.hasData) {
return _buildUserList(snapshot.data!);
} else {
@ -162,7 +161,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
onPressed: () {
setState(() {
_isSearching = !_isSearching;
query = '';
query = "";
});
if (_isSearching) {
@ -207,7 +206,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
itemCount: filteredUsers.length,
itemBuilder: (context, index) {
var user = filteredUsers[index];
return Container(
return DecoratedBox(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
@ -221,7 +220,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
Padding(
padding: widget.options.paddingAroundChatList ??
const EdgeInsets.symmetric(vertical: 8, horizontal: 28),
child: Container(
child: ColoredBox(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),

View file

@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
class NewGroupChatOverviewScreen extends StatefulWidget {
const NewGroupChatOverviewScreen({

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
import 'package:flutter_chat_view/flutter_chat_view.dart';
import "package:flutter/material.dart";
import "package:flutter_chat_view/flutter_chat_view.dart";
class NewGroupChatScreen extends StatefulWidget {
const NewGroupChatScreen({
@ -26,7 +26,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
List<ChatUserModel> selectedUserList = [];
bool _isSearching = false;
String query = '';
String query = "";
@override
Widget build(BuildContext context) {
@ -49,7 +49,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
return Text("Error: ${snapshot.error}");
} else if (snapshot.hasData) {
return _buildUserList(snapshot.data!);
}
@ -103,7 +103,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
onPressed: () {
setState(() {
_isSearching = !_isSearching;
query = '';
query = "";
});
if (_isSearching) {
@ -174,7 +174,7 @@ class _UserListState extends State<UserList> {
var isSelected = widget.selectedUserList
.any((selectedUser) => selectedUser == user);
var theme = Theme.of(context);
return Container(
return DecoratedBox(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
@ -196,7 +196,7 @@ class _UserListState extends State<UserList> {
child: Padding(
padding: widget.options.paddingAroundChatList ??
const EdgeInsets.fromLTRB(28, 8, 28, 8),
child: Container(
child: ColoredBox(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.symmetric(

View file

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:intl/intl.dart';
import "package:intl/intl.dart";
class DateFormatter {
final _now = DateTime.now();
@ -28,6 +28,6 @@ class DateFormatter {
bool showFullDate = false,
}) =>
DateFormat(
_isToday(date) ? 'HH:mm' : 'dd-MM-yyyy${showFullDate ? ' HH:mm' : ''}',
_isToday(date) ? "HH:mm" : 'dd-MM-yyyy${showFullDate ? ' HH:mm' : ''}',
).format(date);
}

View file

@ -1,7 +1,7 @@
import 'dart:async';
import "dart:async";
import 'package:flutter/material.dart';
import 'package:flutter_profile/flutter_profile.dart';
import "package:flutter/material.dart";
import "package:flutter_profile/flutter_profile.dart";
class ChatProfileService extends ProfileService {
@override

View file

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

View file

@ -3,10 +3,10 @@
// SPDX-License-Identifier: BSD-3-Clause
// SPDX-License-Identifier: GPL-3.0-or-later
import 'package:flutter_test/flutter_test.dart';
import "package:flutter_test/flutter_test.dart";
void main() {
test('test', () {
test("test", () {
expect(true, true);
});
}