Code With Bisky

Supercharge Your Flutter Chat App:Implement Chat Message Seen with Appwrite(Firebase Alternative) Episode [18]

Key Topics covered:

  • Implement message read
  • Show double green ticks
  • Design message bubble
  • Update message read to true

Description:

In this tutorial, we will learn how to implement chat message seen functionality in your Flutter app using Appwrite, an exceptional Firebase alternative. Are you looking to enhance your app's chat experience? Look no further! In this in-depth tutorial, we'll guide you through the step-by-step process of integrating real-time chat features with Appwrite, all while designing beautiful message bubbles and displaying accurate timestamps.

Update an extensions file.

  • lib/core/extensions/extensions.dart

Add OnDateTime which extends DateTime


import 'package:intl/intl.dart';

extension OnDateTime on DateTime{

  String get formatDateTime => DateFormat('dd MM yyyy hh:mm a').format(toLocal());
}
        
        

Code Snippet(MessageRepositoryProvider.dart):

  • lib/core/providers/MessageRepositoryProvider.dart

We added MessageRepositoryProvider to have High Cohesion on our code. We created a new method updateMessageSeen()


import 'package:appwrite/appwrite.dart';
import 'package:chat_with_bisky/constant/strings.dart';
import 'package:chat_with_bisky/core/providers/DatabaseProvider.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

final messageRepositoryProvider = Provider((ref) => MessageRepositoryProvider(ref),);

class MessageRepositoryProvider{

  Ref _ref;
  Databases get _databases => _ref.read(databaseProvider);
  MessageRepositoryProvider(this._ref);

  Future<void> updateMessageSeen(String id) async{
    try{
      _databases.updateDocument(databaseId: Strings.databaseId,
          collectionId: Strings.collectionMessagesId,
          documentId: id,
      data: {
        'read':true
      });

    } catch(e){
      print('updateMessageSeen $e');
    }
  }

} 
        

Code Snippet(ChatAppwrite.dart):

  • lib/model/ChatAppwrite.dart

Add below code in ChatAppwrite class


String? messageIdUpstream;
bool? delivered;
String? userId;

Code Snippet(MessageAppwrite.dart):

  • lib/model/MessageAppwrite.dart

Add below code in MessageAppwrite class


bool? delivered;

Code Snippet(ChatRealm.dart):

  • lib/model/db/ChatRealm.dart

Add below code in ChatRealm class


  late String? messageIdUpstream;
  late bool? delivered;
  late String? userId;


Code Snippet(MessageRealm.dart):

  • lib/model/db/MessageRealm.dart

Add below code in MessageRealm class


  String? messageIdUpstream;
  bool? delivered;

Don't forget to run the following command in your terminal to regenerate part Filesdart run realm generate

Code Snippet(RealmProvider.dart) modification:

Increase schema version since we are adding new schemas for chats and friends

  • lib/core/providers/RealmProvider.dart

final config = Configuration.local([....,schemaVersion:3);
        
        

Code Snippet(MessageViewModel.dart):

  • lib/pages/dashboard/chat/MessageViewModel.dart

Add messageId parameter in method createOrUpdateChatHead


Future<void> createOrUpdateChatHead(MessageAppwrite message, String key,
      String friendUserId, String myUserId,String messageId) async {
    ......

    // Update ChatAppwrite Object to have the following properties
    ChatAppwrite chatAppwrite = ChatAppwrite(
        delivered: false,
        messageIdUpstream: messageId,
        userId: state.myUserId,
    .......

    // Update MessageRealm Object to have the following properties
    MessageRealm(id,
     fileName: messageAppwrite.fileName,
     messageIdUpstream: document.$id,
     delivered: false

    ...........
    )
    }


    // In if statement if results exists call this method
    // In case statement case RealtimeNotifier.create: and case RealtimeNotifier.update: call below method after saving message into realm database

     updateMessageRead(message);


Code Snippet(MessageViewModel.dart):

  • lib/pages/dashboard/chat/MessageViewModel.dart

Add below method updateMessageRead to update read to true


        updateMessageRead(MessageRealm message){
            if(!myMessage(message) && message.read != true){
               ref.read(messageRepositoryProvider).updateMessageSeen(message.messageIdUpstream?? "");
             }
        }

        myMessage(MessageRealm message){
           return message.senderUserId == state.myUserId;
        }

Code Snippet(ChatListViewModel.dart):

  • lib/pages/dashboard/chat/list/ChatListViewModel.dart

Add below code


    ChatRealm(ObjectId(),
        .............
        delivered: chatAppwrite.delivered,
        userId: chatAppwrite.userId,
        messageIdUpstream: chatAppwrite.messageIdUpstream,
        sendDate: DateTime.parse(document.$updatedAt),
    )

Code Snippet(ChatMessageItem.dart):

  • lib/widget/ChatMessageItem.dart

Add below code to update message read in Widget build(BuildContext context, WidgetRef ref){


    final theme = Theme.of(context);
    final style = theme.textTheme;
    useEffect((){
      if(!myMessage && message.read != true){
        ref.read(messageRepositoryProvider).updateMessageSeen(message.messageIdUpstream?? "");
      }
      return null;
    });

Code Snippet(ChatMessageItem.dart):

  • lib/widget/ChatMessageItem.dart

Replace return buildChatLayout(message); with the code below. We are designing our message bubble


return Padding(
      padding: const EdgeInsets.all(8.0),
        child: Container(
          decoration: BoxDecoration(
            borderRadius: BorderRadius.only(
              topRight: Radius.circular(myMessage?0:16),
              topLeft: Radius.circular(myMessage?16:0),
              bottomLeft: const Radius.circular(16),
              bottomRight: const Radius.circular(16),

            ),
            color: myMessage ? Colors.grey.shade400: Colors.green.shade200
          ),
            child: Column(
              children: [
                buildChatLayout(message),
                Row(
                  mainAxisAlignment:
                  myMessage? MainAxisAlignment.end: MainAxisAlignment.start,
                  children: [
                    if(myMessage) const Spacer(),
                    Padding(padding: EdgeInsets.all(4),
                    child: Wrap(
                      alignment: WrapAlignment.end,
                      spacing: 8,
                      crossAxisAlignment: WrapCrossAlignment.end,
                      children: [
                        Text(message.sendDate!.formatDateTime,
                        style: style.labelSmall!.copyWith(
                          color: Colors.white,
                          fontSize: 12,
                          fontWeight: FontWeight.bold
                        ),),
                        if(myMessage)
                          Icon(message.read == true?
                          Icons.done_all_rounded : Icons.done_rounded,
                          size: 16,
                              color: message.read == true? Colors.green.shade800:Colors.white,)
                      ],
                    ),
                    )
                  ],
                )
              ],
            )));

Conclusion:

We managed to implement message seen. We used useEffect from riverpod to update message read if not when building the view. In the next tutorial, we are going to implement Chat Message Delivered by showing 2 white double ticks. Don't forget to share and join our Discord Channel. May you please subscribe to our YouTube Channel.