mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-18 18:33:49 +02:00
feat: group chat UI changes
This commit is contained in:
parent
b99bdfd081
commit
35d89faf04
4 changed files with 170 additions and 110 deletions
|
@ -18,13 +18,21 @@ class MyStatefulWidget extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
|
||||
static final pietUser = ChatUserModel(
|
||||
firstName: 'Piet',
|
||||
lastName: 'Jansen',
|
||||
imageUrl: 'https://xsgames.co/randomusers/avatar.php?g=female',
|
||||
);
|
||||
|
||||
static final janUser = ChatUserModel(
|
||||
firstName: 'Jan',
|
||||
lastName: 'Jansen',
|
||||
imageUrl: 'https://xsgames.co/randomusers/avatar.php?g=male',
|
||||
);
|
||||
|
||||
static final messages = [
|
||||
ChatTextMessageModel(
|
||||
sender: ChatUserModel(
|
||||
firstName: 'Piet',
|
||||
lastName: 'Jansen',
|
||||
imageUrl: 'https://xsgames.co/randomusers/avatar.php?g=female',
|
||||
),
|
||||
sender: pietUser,
|
||||
text: 'Hoe gaat het?',
|
||||
timestamp: DateTime.now(),
|
||||
),
|
||||
|
@ -48,13 +56,19 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
|
|||
messages: messages,
|
||||
);
|
||||
|
||||
Stream<List<PersonalChatModel>> get chatStream => (() {
|
||||
late StreamController<List<PersonalChatModel>> controller;
|
||||
controller = StreamController<List<PersonalChatModel>>(
|
||||
static final groupChat = GroupChatModel(
|
||||
title: 'Group chat',
|
||||
imageUrl: 'https://xsgames.co/randomusers/avatar.php?g=male',
|
||||
users: [pietUser, janUser],
|
||||
messages: messages);
|
||||
|
||||
Stream<List<ChatModel>> get chatStream => (() {
|
||||
late StreamController<List<ChatModel>> controller;
|
||||
controller = StreamController<List<ChatModel>>(
|
||||
onListen: () {
|
||||
controller.add([
|
||||
chat,
|
||||
chat,
|
||||
groupChat,
|
||||
chat,
|
||||
]);
|
||||
},
|
||||
|
|
|
@ -15,6 +15,7 @@ class ChatOptions {
|
|||
this.imagePickerContainerBuilder = _createImagePickerContainer,
|
||||
this.scaffoldBuilder = _createScaffold,
|
||||
this.userAvatarBuilder = _createUserAvatar,
|
||||
this.groupAvatarBuilder = _createGroupAvatar,
|
||||
this.noChatsPlaceholderBuilder = _createNoChatsPlaceholder,
|
||||
});
|
||||
|
||||
|
@ -24,6 +25,7 @@ class ChatOptions {
|
|||
final ImagePickerContainerBuilder imagePickerContainerBuilder;
|
||||
final ScaffoldBuilder scaffoldBuilder;
|
||||
final UserAvatarBuilder userAvatarBuilder;
|
||||
final GroupAvatarBuilder groupAvatarBuilder;
|
||||
final NoChatsPlaceholderBuilder noChatsPlaceholderBuilder;
|
||||
}
|
||||
|
||||
|
@ -101,6 +103,14 @@ Widget _createUserAvatar(
|
|||
image: user.imageUrl,
|
||||
size: size,
|
||||
);
|
||||
Widget _createGroupAvatar(
|
||||
String imageUrl,
|
||||
double size,
|
||||
) =>
|
||||
ChatImage(
|
||||
image: imageUrl,
|
||||
size: size,
|
||||
);
|
||||
|
||||
Widget _createNoChatsPlaceholder(
|
||||
ChatTranslations translations,
|
||||
|
@ -147,6 +157,11 @@ typedef UserAvatarBuilder = Widget Function(
|
|||
double size,
|
||||
);
|
||||
|
||||
typedef GroupAvatarBuilder = Widget Function(
|
||||
String imageUrl,
|
||||
double size,
|
||||
);
|
||||
|
||||
typedef NoChatsPlaceholderBuilder = Widget Function(
|
||||
ChatTranslations translations,
|
||||
);
|
||||
|
|
|
@ -22,7 +22,7 @@ class ChatDetailScreen extends StatelessWidget {
|
|||
super.key,
|
||||
});
|
||||
|
||||
final PersonalChatModel? chat;
|
||||
final ChatModel? chat;
|
||||
final ChatOptions options;
|
||||
final ChatTranslations translations;
|
||||
final Stream<List<ChatMessageModel>>? chatMessages;
|
||||
|
@ -64,15 +64,27 @@ class ChatDetailScreen extends StatelessWidget {
|
|||
children: chat == null
|
||||
? []
|
||||
: [
|
||||
options.userAvatarBuilder(
|
||||
chat!.user,
|
||||
36.0,
|
||||
),
|
||||
if (chat is GroupChatModel) ...[
|
||||
options.groupAvatarBuilder(
|
||||
(chat! as GroupChatModel).imageUrl,
|
||||
36.0,
|
||||
),
|
||||
] else if (chat is PersonalChatModel) ...[
|
||||
options.userAvatarBuilder(
|
||||
(chat! as PersonalChatModel).user,
|
||||
36.0,
|
||||
),
|
||||
] else
|
||||
...[],
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 15.5),
|
||||
child: Text(
|
||||
chat!.user.fullName,
|
||||
(chat is GroupChatModel)
|
||||
? (chat! as GroupChatModel).title
|
||||
: (chat is PersonalChatModel)
|
||||
? (chat! as PersonalChatModel).user.fullName
|
||||
: '',
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -19,10 +19,10 @@ class ChatScreen extends StatefulWidget {
|
|||
|
||||
final ChatOptions options;
|
||||
final ChatTranslations translations;
|
||||
final Stream<List<PersonalChatModel>> chats;
|
||||
final Stream<List<ChatModel>> chats;
|
||||
final VoidCallback? onPressStartChat;
|
||||
final void Function(PersonalChatModel chat) onDeleteChat;
|
||||
final void Function(PersonalChatModel chat) onPressChat;
|
||||
final void Function(ChatModel chat) onDeleteChat;
|
||||
final void Function(ChatModel chat) onPressChat;
|
||||
|
||||
@override
|
||||
State<ChatScreen> createState() => _ChatScreenState();
|
||||
|
@ -32,109 +32,128 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
final DateFormatter _dateFormatter = DateFormatter();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => widget.options.scaffoldBuilder(
|
||||
AppBar(
|
||||
title: Text(widget.translations.chatsTitle),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.only(top: 15.0),
|
||||
children: [
|
||||
StreamBuilder<List<PersonalChatModel>>(
|
||||
stream: widget.chats,
|
||||
builder: (BuildContext context, snapshot) => Column(
|
||||
children: [
|
||||
for (PersonalChatModel chat in snapshot.data ?? [])
|
||||
Builder(
|
||||
builder: (context) => Dismissible(
|
||||
confirmDismiss: (_) => showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text(
|
||||
widget.translations.deleteChatModalTitle,
|
||||
),
|
||||
content: Text(
|
||||
widget.translations
|
||||
.deleteChatModalDescription,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
widget
|
||||
.translations.deleteChatModalCancel,
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(false),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(true),
|
||||
child: Text(
|
||||
widget.translations
|
||||
.deleteChatModalConfirm,
|
||||
),
|
||||
),
|
||||
],
|
||||
Widget build(BuildContext context) {
|
||||
return widget.options.scaffoldBuilder(
|
||||
AppBar(
|
||||
title: Text(widget.translations.chatsTitle),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.only(top: 15.0),
|
||||
children: [
|
||||
StreamBuilder<List<ChatModel>>(
|
||||
stream: widget.chats,
|
||||
builder: (BuildContext context, snapshot) => Column(
|
||||
children: [
|
||||
for (ChatModel chat in snapshot.data ?? []) ...[
|
||||
Builder(
|
||||
builder: (context) => Dismissible(
|
||||
confirmDismiss: (_) => showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text(
|
||||
widget.translations.deleteChatModalTitle,
|
||||
),
|
||||
),
|
||||
onDismissed: (_) => widget.onDeleteChat(chat),
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
content: Text(
|
||||
widget
|
||||
.translations.deleteChatModalDescription,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
widget.translations.deleteChatButton,
|
||||
widget.translations.deleteChatModalCancel,
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(false),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(true),
|
||||
child: Text(
|
||||
widget
|
||||
.translations.deleteChatModalConfirm,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
key: Key(
|
||||
chat.id.toString(),
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.onPressChat(chat),
|
||||
child: widget.options.chatRowContainerBuilder(
|
||||
ChatRow(
|
||||
avatar: widget.options.userAvatarBuilder(
|
||||
chat.user,
|
||||
40.0,
|
||||
),
|
||||
title: chat.user.fullName,
|
||||
subTitle: chat.lastMessage != null
|
||||
? chat.lastMessage
|
||||
is ChatTextMessageModel
|
||||
? (chat.lastMessage!
|
||||
as ChatTextMessageModel)
|
||||
.text
|
||||
: '📷 ${widget.translations.image}'
|
||||
: null,
|
||||
lastUsed: chat.lastUsed != null
|
||||
? _dateFormatter.format(
|
||||
date: chat.lastUsed!,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
onDismissed: (_) => widget.onDeleteChat(chat),
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
widget.translations.deleteChatButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
key: ValueKey(
|
||||
chat.id.toString(),
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.onPressChat(chat),
|
||||
child: widget.options.chatRowContainerBuilder(
|
||||
(chat is PersonalChatModel)
|
||||
? ChatRow(
|
||||
avatar:
|
||||
widget.options.userAvatarBuilder(
|
||||
chat.user,
|
||||
40.0,
|
||||
),
|
||||
title: chat.user.fullName,
|
||||
subTitle: chat.lastMessage != null &&
|
||||
chat.lastMessage
|
||||
is ChatTextMessageModel
|
||||
? (chat.lastMessage!
|
||||
as ChatTextMessageModel)
|
||||
.text
|
||||
: '📷 ${widget.translations.image}',
|
||||
lastUsed: chat.lastUsed != null
|
||||
? _dateFormatter.format(
|
||||
date: chat.lastUsed!,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: ChatRow(
|
||||
title: (chat as GroupChatModel).title,
|
||||
subTitle: chat.lastMessage != null &&
|
||||
chat.lastMessage
|
||||
is ChatTextMessageModel
|
||||
? (chat.lastMessage!
|
||||
as ChatTextMessageModel)
|
||||
.text
|
||||
: '📷 '
|
||||
'${widget.translations.image}',
|
||||
avatar:
|
||||
widget.options.groupAvatarBuilder(
|
||||
chat.imageUrl,
|
||||
40.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.onPressStartChat != null)
|
||||
widget.options.newChatButtonBuilder(
|
||||
context,
|
||||
widget.onPressStartChat!,
|
||||
widget.translations,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
),
|
||||
if (widget.onPressStartChat != null)
|
||||
widget.options.newChatButtonBuilder(
|
||||
context,
|
||||
widget.onPressStartChat!,
|
||||
widget.translations,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue