Flutter Firestore how to show the list of people i have recently chat with

Viewed 45

Hope all are well i am working on a flutter app where i got stuck at chat module the chat is working fine and sending messages as well. But i want to show the persons whom i chat with most recent on chat screen page.

Like messenger whats app when we chat with someone it comes on chat screen like that.

Here is my chatroom screen

import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/services.dart';
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart';
import 'package:uuid/uuid.dart';

class chatroom extends StatelessWidget {
  final Map<String, dynamic> userMap;
  final String chatRoomId;
  chatroom({required this.chatRoomId, required this.userMap});
  final TextEditingController _message = TextEditingController();
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  final FirebaseAuth _auth = FirebaseAuth.instance;

  File? imageFile;

  Future getImage() async {
    ImagePicker _picker = ImagePicker();
    await _picker.pickImage(source: ImageSource.gallery).then((xFile) {
      if (xFile != null) {
        imageFile = File(xFile.path);
        uploadImage();
      }
    });
  }

  Future uploadImage() async {
    String fileName = Uuid().v1();
    int status = 1;
    await _firestore
        .collection("chatroom")
        .doc(chatRoomId)
        .collection('chats')
        .doc(fileName)
        .set({
      "sendBy": _auth.currentUser!.displayName,
      "message":"",
      "type":"img",
      "time": FieldValue.serverTimestamp(),
    });
    var ref =
        FirebaseStorage.instance.ref().child('images').child("$fileName.jpg");
    var uploadTask = await ref.putFile(imageFile!).catchError((error) async{
      await _firestore
          .collection("chatroom")
          .doc(chatRoomId)
          .collection('chats')
          .doc(fileName).delete();

      status = 0 ;

    });
    if(status==1){
      String imageUrl = await uploadTask.ref.getDownloadURL();
      await _firestore
          .collection("chatroom")
          .doc(chatRoomId)
          .collection('chats')
          .doc(fileName).update({
        "message": imageUrl,
      });
      print(imageUrl);
    }

  }

  void onSendMessage() async {
    if (_message.text.isNotEmpty) {
      Map<String, dynamic> messages = {
        "sendBy": _auth.currentUser!.displayName,
        "message": _message.text,
        "type": "text",
        "time": FieldValue.serverTimestamp(),
      };
      await _firestore
          .collection('chatroom')
          .doc(chatRoomId)
          .collection('chats')
          .add(messages);
      _message.clear();
    } else {
      print("Enter Some Text");
    }
  }

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(
        elevation: 0.0,
        backgroundColor: Colors.black,
        title: Padding(
          padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
          child: StreamBuilder<DocumentSnapshot>(
            stream: _firestore
                .collection("registration")
                .doc(userMap['uid'])
                .snapshots(),
            builder: (context, snapshot) {
              if (snapshot.data != null) {
                return Container(
                  child: Column(
                    children: [
                      Text(
                        userMap['name'],
                        style: GoogleFonts.roboto(
                          color: Colors.white,
                          fontSize: 18,
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(right: 100),
                        child: Text(
                          snapshot.data!['status'],
                          style: GoogleFonts.roboto(
                            color: Colors.white,
                            fontSize: 14,
                          ),
                        ),
                      ),
                    ],
                  ),
                );
              } else {
                return Container();
              }
            },
          ),
        ),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Container(
              height: size.height / 1.25,
              width: size.width,
              child: StreamBuilder<QuerySnapshot>(
                stream: _firestore
                    .collection('chatroom')
                    .doc(chatRoomId)
                    .collection('chats')
                    .orderBy("time", descending: false)
                    .snapshots(),
                builder: (BuildContext context,
                    AsyncSnapshot<QuerySnapshot> snapshot) {
                  if (snapshot.data != null) {
                    return ListView.builder(
                      itemCount: snapshot.data?.docs.length,
                      itemBuilder: (context, index) {
                        Map<String, dynamic> map = snapshot.data!.docs[index]
                            .data() as Map<String, dynamic>;
                        return messages(size, map,context);
                      },
                    );
                  } else {
                    return Container();
                  }
                },
              ),
            ),
          ],
        ),
      ),
      bottomNavigationBar: Container(
        color: Colors.white,
        height: size.height / 10,
        width: size.width,
        alignment: Alignment.center,
        child: Container(
          height: size.height / 12,
          width: size.width / 1.1,
          child: Row(
            children: [
              Container(
                height: size.height / 17,
                width: size.width / 1.3,
                child: TextField(
                  controller: _message,
                  decoration: InputDecoration(
                    suffixIcon: IconButton(
                      onPressed: () => getImage(),
                      icon: Icon(Icons.photo),
                    ),
                    hintText: "Send Message",
                    border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(8),
                    ),
                  ),
                ),
              ),
              IconButton(
                onPressed: onSendMessage,
                icon: Icon(Icons.send),
              )
            ],
          ),
        ),
      ),
    );
  }

  Widget messages(Size size, Map<String, dynamic> map, BuildContext context) {
    return map['type'] == "text"
        ? Container(
            width: size.width,
            alignment: map['sendBy'] == _auth.currentUser!.displayName
                ? Alignment.centerRight
                : Alignment.centerLeft,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Container(
                padding: EdgeInsets.symmetric(vertical: 10, horizontal: 14),
                margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(15),
                  color: Colors.blue,
                ),
                child: Text(
                  map['message'],
                  style: GoogleFonts.roboto(
                    color: Colors.white,
                    fontSize: 16,
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ),
            ),
          )
        : Container(
            height: size.height / 2.5,
            width: size.width,
      padding: EdgeInsets.symmetric(vertical: 5,horizontal: 5),
            alignment: map['sendBy'] == _auth.currentUser!.displayName
                ? Alignment.centerRight
                : Alignment.centerLeft,
            child: InkWell(
              onTap: () => Navigator.of(context).push(
                MaterialPageRoute(builder: (_)=> ShowImage(imageURl: map['message'],
                ),
                ),
              ),
              child: Container(
                height: size.height / 2.5,
                width: size.width / 2,
                decoration: BoxDecoration(
                  border: Border.all(),
                ),
                alignment: map['message']!="" ? null :Alignment.center,
                child: map['message'] != ""
                    ? Image.network(map['message'],fit: BoxFit.cover,)
                    : CircularProgressIndicator(),
              ),
            ),
          );
  }
}

class ShowImage extends StatelessWidget {
  final imageURl;
  const ShowImage({required this.imageURl, Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    return Scaffold(
      body: Container(
        height: size.height,
        width: size.width,
        color: Colors.black,
        child: Image.network(imageURl),
      ),
    );
  }
}

here is my chathome screen

    import 'package:bpe_application/chat/chatroom.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';

class Conversation extends StatefulWidget {
  @override
  _ConversationState createState() => _ConversationState();
}

class _ConversationState extends State<Conversation> with WidgetsBindingObserver {
  late final String chatRoomId;


  final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    setStatus("Online");
  }

  void setStatus(String status) async{
    await _firestore.collection('registration').doc(_auth.currentUser!.uid).update({
      "status": status,
    });


  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state){
    if (state == AppLifecycleState.resumed){
      //online
      setStatus("Online");
    }else{
      //offline
      setStatus("Offline");
    }

  }

  final FirebaseAuth _auth = FirebaseAuth.instance;
  Map<String, dynamic>? userMap;
  bool isLoading= false;
  final TextEditingController _search = TextEditingController();
  ScrollController scrollController = ScrollController();

  String chatroomId(String user1, String user2){
   if(user1[0].toLowerCase().codeUnits[0] > user2.toLowerCase().codeUnits[0]){
     return "$user1$user2";
   }else{
     return "$user2$user1";
   }
  }


  void onSearch() async {
    FirebaseFirestore _firestore = FirebaseFirestore.instance;
    setState(() {
      isLoading = true;
    });
    await _firestore.collection("registration").
    where("email", isEqualTo: _search.text).
    get().then((value) {
       setState(() {
        userMap= value.docs[0].data();
        isLoading=false;
      });
      print(userMap);

    }
    );

  }
  void listView() async {
    FirebaseFirestore _firestore = FirebaseFirestore.instance;
    setState(() {
      isLoading = true;
    });
    await _firestore.collection("registration").
    where("email", isEqualTo: _search.text).
    get().then((value) {
      setState(() {
        userMap= value.docs[0].data();
        isLoading=false;
      });
      print(userMap);

    }
    );

  }
  @override
  Widget build(BuildContext context) {
    final size= MediaQuery.of(context).size;
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
      statusBarColor: Colors.transparent, //top bar color
      systemNavigationBarColor: Colors.black, //bottom bar color
      systemNavigationBarIconBrightness: Brightness.dark,
    ));
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        elevation: 0.0,
        backgroundColor: Colors.transparent,
        title: Padding(
          padding: const EdgeInsets.fromLTRB(70, 0, 0, 0),
          child: Text(
            "Chat",
            style: GoogleFonts.limelight(color: Colors.white),
          ),
        ),
      ),
      body: isLoading? Center(
        child: Container(
        height: size.height/20,
          width: size.width/20,
          child: CircularProgressIndicator(),
      ),
      )
          : ClipRRect(
        borderRadius: new BorderRadius.only(
          topLeft: const Radius.circular(40.0),
          topRight: const Radius.circular(40.0),
        ),
        child: Container(
          height: 800.0,
          width: double.infinity,
          color: Colors.grey.shade200,
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(mainAxisSize: MainAxisSize.min, children: [
              SizedBox(
                height: 10,
              ),
              Container(
                height: size.height/14,
                width: size.width,
                alignment: Alignment.center,
                child: Container(
                  height: size.height/14,
                  width: size.width/1.2,
                  child: TextField(
                    controller: _search,
                    decoration: InputDecoration(
                      hintText: "Search",
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10),
                      )
                    ),
                  ),
                ),
              ),
              SizedBox(
                height: size.height/70,
              ),
              ElevatedButton(
                  onPressed: onSearch,
                  child: Text(
                    "Search",style: GoogleFonts.roboto(
                    color: Colors.white,
                  ),
              ),
              ),
              SizedBox(
                height: size.height/60,
              ),
              userMap != null
                  ? ListTile(
                onTap: () {
                  String roomId = chatroomId(
                      _auth.currentUser!.displayName!,
                      userMap!['name']);

                  Navigator.of(context).push(
                    MaterialPageRoute(
                      builder: (_) => chatroom(
                        chatRoomId: roomId,
                        userMap: userMap!,
                      ),
                    ),
                  );
                },

                leading: Icon(
                  Icons.account_box,
                  color: Colors.black,
                ),
                title: Text(
                  userMap!['name'],
                  style: GoogleFonts.roboto(
                  color: Colors.black,
                    fontSize: 17,
                    fontWeight: FontWeight.w500,
                  ),
                ),
                subtitle: Text(userMap!['email']),
                trailing: Icon(
                  Icons.chat,
                  color: Colors.black,
                ),
              )
                  : Container(),

            ],
            ),
          ),
        ),
      ),
    );
  }

}

I am not using shared preference it's without shared preferences and only show persons when i searched for them. Want to show recent persons i chat with with searched feature as well.

Firebase Image enter image description here

Please note again i am not using shared preferences

1 Answers

Just as the commentators commented and in addition:

Each time you are sending a message to a recipient, always extract the recipient's userID, then store the recipientUserId in a collection, like this:

_firestore.collection("users")
  .doc(your_uid)
  .collection(<your_conversation_subcollection>)
  .document(recipientUserID).set(recipientDetails);

You can use a timestamp field in recipientDetails to keep a track of when the message was sent.

You can then query the sub collection of messages for all of the recipients you have chatted with so far, by using their recipientUserId.

You can order results by timestamp with .orderBy('timestamp')

See The Docs for more info.

Related