Code With Bisky

Mastering Flutter: Build an Incredible Real-Time Chat App with Local Message Storage Episode [12]

Key Topics covered:

  • Real Configurations
  • Save Messages on local device
  • Realm Query

Description:

In this tutorial, you will learn how to develop a Flutter chat application with real-time messaging and locally saved chat messages for enhanced user experience. In this comprehensive tutorial, we dive into the world of Flutter and explore the process of building a powerful chat app that not only facilitates real-time communication but also ensures message persistence on your local device.

Add the following realm dependency in your pubspec.yaml


dependencies:
  .........
  realm: ^1.3.0
        
        

Code Snippet(RealmProvider.dart):

Add realm configurations

  • lib/core/providers/RealmProvider.dart

import 'package:appwrite/appwrite.dart';
import 'package:chat_with_bisky/core/providers/AppwriteClientProvider.dart';
import 'package:chat_with_bisky/model/db/MessageRealm.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:realm/realm.dart';

final config = Configuration.local([MessageRealm.schema],schemaVersion:0);

final realmProvider=  Provider((ref) => Realm(config));
        
        

Code Snippet(MessageRealm.dart):

Create _MessageRealm class. A realm class must start with underscore and annotated with @RealmModel()

  • Create lib/model/db/MessageRealm.dart

import 'package:realm/realm.dart';

part 'MessageRealm.g.dart';

@RealmModel()
class _MessageRealm {

  @PrimaryKey()
  late ObjectId id;
  String? senderUserId;
  String? receiverUserId;
  String? message;
  String? type;
  DateTime? sendDate;
  bool? read;
  String? localPath;
  String? previewBase64;

}
        
        

Don't forget to run the following command in your terminal to generate MessageRealm.g.dart with messagesdart run realm generate

Code Snippet(MessageState.dart)modification:

Change Set<MessageAppwrite> messages, to List<MessageAppwrite> messages,

  • Update lib/model/MessageState.dart

    @Default([]) List<MessageRealm> messages,
        
        

Don't forget to run the following command in your terminal to regenerate MessageState.freezed.dart with messagesflutter packages pub run build_runner build

Code Snippet(MessageScreen.dart)modification:

Change class MessageAppwrite to MessageRealm for itemBuilder.

  • Update lib/pages/dashboard/chat/MessageScreen.dart

  MessageRealm(ObjectId());
        
        

In initState() method, remove getMessages(), then add below code.


  messageNotifier?.initializeMessages(myUserId, friendUserId);
        
        

Add condition mounted to avoid memory leak in getMessages() method


  if(mounted){
      messageNotifier?.friendUserIdChanged(friendUserId);
      messageNotifier?.myUserIdChanged(myUserId);
      messageNotifier?.getMessages();
    }
        
        

ChatMessage widget and messageWidget must accept MessageRealm object from now on.


  Widget chatMessageItem(MessageRealm documentSnapshot) {

  Widget messageWidget(MessageRealm messageAppwrite) {
        
        

Code Snippet(MessageViewModel.dart) modification:

Add logic to save message into realm database and retrieve messages from local database

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

import 'package:uuid/uuid.dart' as uuid;
import 'package:chat_with_bisky/model/db/MessageRealm.dart';
import 'package:realm/realm.dart';

            // declare _realm
            Realm get _realm => ref.read(realmProvider);

            // change const Uuid().v4(),  to const uuid.Uuid().v4(),

  saveMessage(MessageAppwrite messageAppwrite,Document document ){
    try{
      DateTime dateTime= DateTime.parse(document.$createdAt);
      final id = ObjectId.fromTimestamp(dateTime);
      final message = MessageRealm(id,
        senderUserId:  messageAppwrite.senderUserId,
        receiverUserId: messageAppwrite.receiverUserId,
        message: messageAppwrite.message,
        type: messageAppwrite.type,
        sendDate: dateTime,
        read: messageAppwrite.read,
      );
      final results = _realm.query<MessageRealm>(r'sendDate = $0',[dateTime]);
      if(results.isEmpty){
        _realm.write(() {
          _realm.add(message,update: true);
        });
        state.messages.insert(0, message);
        state = state.copyWith(messages:  state.messages);
      }else{
        MessageRealm messageRealm = results.first;
      }
    }catch(e){
      print(e);
    }
  }

  initializeMessages(String senderUserId,String receiverUserId){

    RealmResults<MessageRealm>  results= _realm.query<MessageRealm>(r'senderUserId == $0 AND receiverUserId == $1 OR senderUserId == $1 AND receiverUserId == $0 SORT(sendDate DESC)',[senderUserId,receiverUserId]);
    if(results.isNotEmpty){

      state = state.copyWith(messages: results.toList());
    }
  }
        
        

Conclusion:

We managed to save messages on local device using realm. We added a logic in MessageViewModel to handle our business logic for getting messages from local device. In the next tutorial, we are going to persist these messages in local storage using realm database. Don't forget to share and join our Discord Channel. May you please subscribe to our YouTube Channel.