feat: group chat UI changes

This commit is contained in:
Freek van de Ven 2023-03-31 14:20:28 +02:00
parent b99bdfd081
commit 35d89faf04
4 changed files with 170 additions and 110 deletions

View file

@ -18,13 +18,21 @@ class MyStatefulWidget extends StatefulWidget {
} }
class _MyStatefulWidgetState extends State<MyStatefulWidget> { class _MyStatefulWidgetState extends State<MyStatefulWidget> {
static final messages = [ static final pietUser = ChatUserModel(
ChatTextMessageModel(
sender: ChatUserModel(
firstName: 'Piet', firstName: 'Piet',
lastName: 'Jansen', lastName: 'Jansen',
imageUrl: 'https://xsgames.co/randomusers/avatar.php?g=female', 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: pietUser,
text: 'Hoe gaat het?', text: 'Hoe gaat het?',
timestamp: DateTime.now(), timestamp: DateTime.now(),
), ),
@ -48,13 +56,19 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
messages: messages, messages: messages,
); );
Stream<List<PersonalChatModel>> get chatStream => (() { static final groupChat = GroupChatModel(
late StreamController<List<PersonalChatModel>> controller; title: 'Group chat',
controller = StreamController<List<PersonalChatModel>>( 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: () { onListen: () {
controller.add([ controller.add([
chat, chat,
chat, groupChat,
chat, chat,
]); ]);
}, },

View file

@ -15,6 +15,7 @@ class ChatOptions {
this.imagePickerContainerBuilder = _createImagePickerContainer, this.imagePickerContainerBuilder = _createImagePickerContainer,
this.scaffoldBuilder = _createScaffold, this.scaffoldBuilder = _createScaffold,
this.userAvatarBuilder = _createUserAvatar, this.userAvatarBuilder = _createUserAvatar,
this.groupAvatarBuilder = _createGroupAvatar,
this.noChatsPlaceholderBuilder = _createNoChatsPlaceholder, this.noChatsPlaceholderBuilder = _createNoChatsPlaceholder,
}); });
@ -24,6 +25,7 @@ class ChatOptions {
final ImagePickerContainerBuilder imagePickerContainerBuilder; final ImagePickerContainerBuilder imagePickerContainerBuilder;
final ScaffoldBuilder scaffoldBuilder; final ScaffoldBuilder scaffoldBuilder;
final UserAvatarBuilder userAvatarBuilder; final UserAvatarBuilder userAvatarBuilder;
final GroupAvatarBuilder groupAvatarBuilder;
final NoChatsPlaceholderBuilder noChatsPlaceholderBuilder; final NoChatsPlaceholderBuilder noChatsPlaceholderBuilder;
} }
@ -101,6 +103,14 @@ Widget _createUserAvatar(
image: user.imageUrl, image: user.imageUrl,
size: size, size: size,
); );
Widget _createGroupAvatar(
String imageUrl,
double size,
) =>
ChatImage(
image: imageUrl,
size: size,
);
Widget _createNoChatsPlaceholder( Widget _createNoChatsPlaceholder(
ChatTranslations translations, ChatTranslations translations,
@ -147,6 +157,11 @@ typedef UserAvatarBuilder = Widget Function(
double size, double size,
); );
typedef GroupAvatarBuilder = Widget Function(
String imageUrl,
double size,
);
typedef NoChatsPlaceholderBuilder = Widget Function( typedef NoChatsPlaceholderBuilder = Widget Function(
ChatTranslations translations, ChatTranslations translations,
); );

View file

@ -22,7 +22,7 @@ class ChatDetailScreen extends StatelessWidget {
super.key, super.key,
}); });
final PersonalChatModel? chat; final ChatModel? chat;
final ChatOptions options; final ChatOptions options;
final ChatTranslations translations; final ChatTranslations translations;
final Stream<List<ChatMessageModel>>? chatMessages; final Stream<List<ChatMessageModel>>? chatMessages;
@ -64,15 +64,27 @@ class ChatDetailScreen extends StatelessWidget {
children: chat == null children: chat == null
? [] ? []
: [ : [
options.userAvatarBuilder( if (chat is GroupChatModel) ...[
chat!.user, options.groupAvatarBuilder(
(chat! as GroupChatModel).imageUrl,
36.0, 36.0,
), ),
] else if (chat is PersonalChatModel) ...[
options.userAvatarBuilder(
(chat! as PersonalChatModel).user,
36.0,
),
] else
...[],
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 15.5), padding: const EdgeInsets.only(left: 15.5),
child: Text( 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), style: const TextStyle(fontSize: 18),
), ),
), ),

View file

@ -19,10 +19,10 @@ class ChatScreen extends StatefulWidget {
final ChatOptions options; final ChatOptions options;
final ChatTranslations translations; final ChatTranslations translations;
final Stream<List<PersonalChatModel>> chats; final Stream<List<ChatModel>> chats;
final VoidCallback? onPressStartChat; final VoidCallback? onPressStartChat;
final void Function(PersonalChatModel chat) onDeleteChat; final void Function(ChatModel chat) onDeleteChat;
final void Function(PersonalChatModel chat) onPressChat; final void Function(ChatModel chat) onPressChat;
@override @override
State<ChatScreen> createState() => _ChatScreenState(); State<ChatScreen> createState() => _ChatScreenState();
@ -32,7 +32,8 @@ class _ChatScreenState extends State<ChatScreen> {
final DateFormatter _dateFormatter = DateFormatter(); final DateFormatter _dateFormatter = DateFormatter();
@override @override
Widget build(BuildContext context) => widget.options.scaffoldBuilder( Widget build(BuildContext context) {
return widget.options.scaffoldBuilder(
AppBar( AppBar(
title: Text(widget.translations.chatsTitle), title: Text(widget.translations.chatsTitle),
), ),
@ -42,11 +43,11 @@ class _ChatScreenState extends State<ChatScreen> {
child: ListView( child: ListView(
padding: const EdgeInsets.only(top: 15.0), padding: const EdgeInsets.only(top: 15.0),
children: [ children: [
StreamBuilder<List<PersonalChatModel>>( StreamBuilder<List<ChatModel>>(
stream: widget.chats, stream: widget.chats,
builder: (BuildContext context, snapshot) => Column( builder: (BuildContext context, snapshot) => Column(
children: [ children: [
for (PersonalChatModel chat in snapshot.data ?? []) for (ChatModel chat in snapshot.data ?? []) ...[
Builder( Builder(
builder: (context) => Dismissible( builder: (context) => Dismissible(
confirmDismiss: (_) => showDialog( confirmDismiss: (_) => showDialog(
@ -56,14 +57,13 @@ class _ChatScreenState extends State<ChatScreen> {
widget.translations.deleteChatModalTitle, widget.translations.deleteChatModalTitle,
), ),
content: Text( content: Text(
widget.translations widget
.deleteChatModalDescription, .translations.deleteChatModalDescription,
), ),
actions: [ actions: [
TextButton( TextButton(
child: Text( child: Text(
widget widget.translations.deleteChatModalCancel,
.translations.deleteChatModalCancel,
), ),
onPressed: () => onPressed: () =>
Navigator.of(context).pop(false), Navigator.of(context).pop(false),
@ -72,8 +72,8 @@ class _ChatScreenState extends State<ChatScreen> {
onPressed: () => onPressed: () =>
Navigator.of(context).pop(true), Navigator.of(context).pop(true),
child: Text( child: Text(
widget.translations widget
.deleteChatModalConfirm, .translations.deleteChatModalConfirm,
), ),
), ),
], ],
@ -92,36 +92,54 @@ class _ChatScreenState extends State<ChatScreen> {
), ),
), ),
), ),
key: Key( key: ValueKey(
chat.id.toString(), chat.id.toString(),
), ),
child: GestureDetector( child: GestureDetector(
onTap: () => widget.onPressChat(chat), onTap: () => widget.onPressChat(chat),
child: widget.options.chatRowContainerBuilder( child: widget.options.chatRowContainerBuilder(
ChatRow( (chat is PersonalChatModel)
avatar: widget.options.userAvatarBuilder( ? ChatRow(
avatar:
widget.options.userAvatarBuilder(
chat.user, chat.user,
40.0, 40.0,
), ),
title: chat.user.fullName, title: chat.user.fullName,
subTitle: chat.lastMessage != null subTitle: chat.lastMessage != null &&
? chat.lastMessage chat.lastMessage
is ChatTextMessageModel is ChatTextMessageModel
? (chat.lastMessage! ? (chat.lastMessage!
as ChatTextMessageModel) as ChatTextMessageModel)
.text .text
: '📷 ${widget.translations.image}' : '📷 ${widget.translations.image}',
: null,
lastUsed: chat.lastUsed != null lastUsed: chat.lastUsed != null
? _dateFormatter.format( ? _dateFormatter.format(
date: chat.lastUsed!, date: chat.lastUsed!,
) )
: null, : 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,
), ),
), ),
), ),
), ),
), ),
),
],
], ],
), ),
), ),
@ -137,4 +155,5 @@ class _ChatScreenState extends State<ChatScreen> {
], ],
), ),
); );
}
} }