How to show last messages in Flutter

1,228

Add descending: true after timestamp.

like Expanded( child: Container( //margin: EdgeInsets.symmetric(horizontal: 5), child: StreamBuilder<QuerySnapshot>( stream: _firestore .collection("messages") .orderBy( "timestamp", descending: true ) .snapshots(), builder: (context, snapshot) { if (!snapshot.hasData) return Center( child: CircularProgressIndicator( backgroundColor: kPrimaryColor, ), );

Share:
1,228
Edgar1102
Author by

Edgar1102

Updated on December 30, 2022

Comments

  • Edgar1102
    Edgar1102 over 1 year

    I have this project I'm working on. It's a chat app. I've been able to handle most of the functionalities but need help with some stuff. I use firebase as backend and all data is stored and retrieved from firestore to display the messages in the chat. I noticed that on opening the chat I dont see the last message automatically the way it shows normally on whatsapp or other chat apps. For instance, if i type a new message, I want that to be the last thing that is shown on the page at the bottom. Please help me check this out. Here's my code:

    import 'package:chat/constants.dart';
    import 'package:chat/utilities/constants.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:emoji_picker/emoji_picker.dart';
    import 'package:flutter/material.dart';
    import 'package:chat/models/auth.dart';
    import 'package:chat/models/message.dart';
    import 'package:font_awesome_flutter/font_awesome_flutter.dart';
    
    class ChatScreen extends StatefulWidget {
      final AuthImplementation auth;
      final VoidCallback signedOut;
    
      ChatScreen({
        this.auth,
        this.signedOut,
      });
    
      @override
      _ChatScreenState createState() => _ChatScreenState();
    }
    
    class _ChatScreenState extends State<ChatScreen> {
      bool show = false;
      FocusNode focusNode = FocusNode();
    
      final Firestore _firestore = Firestore.instance;
    
      TextEditingController messageController = TextEditingController();
      ScrollController scrollController = ScrollController();
    
      String userName;
      @override
      void initState() {
        super.initState();
        widget.auth.getCurrentUserEmail().then((email) {
          setState(() {
            final String userEmail = email;
            final endIndex = userEmail.indexOf("@");
            userName = userEmail.substring(0, endIndex);
            focusNode.addListener(() {
              if (focusNode.hasFocus) {
                setState(() {
                  show = false;
                });
              }
            });
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            leading: new Container(
              padding: new EdgeInsets.all(8.0),
              decoration: new BoxDecoration(
                image: new DecorationImage(
                    image: new AssetImage("assets/images/social-logo.png"),
                    fit: BoxFit.fill),
                color: Colors.white,
                borderRadius: new BorderRadius.all(new Radius.circular(80.0)),
                border: new Border.all(
                  color: Colors.white,
                  width: 1.0,
                ),
              ),
            ),
            title: Text("One Gov FX Signal Room",
                style: TextStyle(
                  fontSize: 20,
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontFamily: 'Spartan',
                )),
            backgroundColor: kPrimaryColor,
            actions: <Widget>[
              IconButton(
                  icon: FaIcon(FontAwesomeIcons.signOutAlt),
                  color: Colors.white,
                  onPressed: logOut),
            ],
          ),
          backgroundColor: antiFlashWhite,
          body: WillPopScope(
              child: Column(
                children: <Widget>[
                  Container(
                    color: Colors.white,
                    padding:
                        EdgeInsets.only(left: 10, right: 0, bottom: 10, top: 10),
                    child: Row(
                      children: [
                        CircleAvatar(
                          backgroundColor: Colors.white,
                          backgroundImage:
                              AssetImage("assets/images/social-logo.png"),
                        ),
                        SizedBox(
                          width: 50,
                        ),
                        Flexible(
                          child: Column(children: const <Widget>[
                            Text('Message From the Admins'),
                            Text(
                                'Keep your messages polite and do not abuse the channel. Try to keep your discussions within the community guidelines'),
                          ]),
                        )
                      ],
                    ),
                  ),
                  Expanded(
                    child: Container(
                      //margin: EdgeInsets.symmetric(horizontal: 5),
                      child: StreamBuilder<QuerySnapshot>(
                          stream: _firestore
                              .collection("messages")
                              .orderBy(
                                "timestamp",
                              )
                              .snapshots(),
                          builder: (context, snapshot) {
                            if (!snapshot.hasData)
                              return Center(
                                child: CircularProgressIndicator(
                                  backgroundColor: kPrimaryColor,
                                ),
                              );
                            List<DocumentSnapshot> docs = snapshot.data.documents;
    
                            List<Widget> messages = docs
                                .map((doc) => Message(
                                      user: doc.data['user'],
                                      text: doc.data['text'],
                                      timestamp: doc.data['timestamp'],
                                      mine: userName == doc.data['user'],
                                    ))
                                .toList();
                            return ListView(
                              controller: scrollController,
                              children: messages,
                            );
                          }),
                    ),
                  ),
                  Container(
                    color: Colors.white,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: [
                        Row(
                          children: <Widget>[
                            IconButton(
                              icon: FaIcon(
                                FontAwesomeIcons.smile,
                                color: kPrimaryColor,
                              ),
                              onPressed: () {
                                focusNode.unfocus();
                                focusNode.canRequestFocus = false;
                                setState(() {
                                  show = !show;
                                });
                              },
                            ),
                            Expanded(
                              child: Padding(
                                padding: const EdgeInsets.all(10),
                                child: TextField(
                                  focusNode: focusNode,
                                  style: TextStyle(
                                    fontFamily: 'Poppins',
                                    fontSize: 15,
                                  ),
                                  onSubmitted: (value) => sendChat(),
                                  controller: messageController,
                                  scrollController: scrollController,
                                  keyboardType: TextInputType.multiline,
                                  textInputAction: TextInputAction.newline,
                                  maxLines: null,
                                  cursorColor: kPrimaryColor,
                                  decoration: InputDecoration(
                                    border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(20)),
                                    filled: true,
                                    hintText: "Say Something. Be Nice...",
                                    hintStyle: TextStyle(
                                        fontFamily: 'Montserrat', fontSize: 12),
                                  ),
                                ),
                              ),
                            ),
                            IconButton(
                              icon: FaIcon(
                                FontAwesomeIcons.file,
                                color: kPrimaryColor,
                              ),
                              onPressed: () {
                                showModalBottomSheet(
                                    backgroundColor: Colors.transparent,
                                    context: context,
                                    builder: (builder) => bottomsheet());
                              },
                            ),
                            IconButton(
                              icon: FaIcon(
                                FontAwesomeIcons.paperPlane,
                                color: kPrimaryColor,
                              ),
                              onPressed: sendChat,
                            ),
                          ],
                        ),
                        show ? emojiSelect() : Container(),
                      ],
                    ),
                  ),
                ],
              ),
              onWillPop: () {
                if (show) {
                  setState(() {
                    show = false;
                  });
                } else {
                  Navigator.pop(context);
                }
                return Future.value(false);
              }),
        );
      }
    
      void logOut() async {
        try {
          await widget.auth.signOut();
          widget.signedOut();
        } catch (e) {
          print("error :" + e.toString());
        }
      }
    
      Future<void> sendChat() async {
        if (messageController.text.length > 0) {
          await _firestore.collection("messages").add({
            'user': userName,
            'text': messageController.text,
            'timestamp': FieldValue.serverTimestamp(),
          });
          messageController.clear();
          scrollController.animateTo(scrollController.position.maxScrollExtent,
              duration: Duration(milliseconds: 300), curve: Curves.easeOut);
        }
      }
    
      Widget bottomsheet() {
        return Container(
          height: 120,
          width: MediaQuery.of(context).size.width,
          child: Card(
            margin: EdgeInsets.all(0),
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  GestureDetector(
                      child: iconcreation(
                    Icons.analytics,
                    Colors.black,
                    "Analysis",
                  )),
                  SizedBox(
                    width: 40,
                  ),
                  iconcreation(Icons.report, Colors.black, "Report User"),
                  SizedBox(
                    width: 40,
                  ),
                  iconcreation(Icons.link, Colors.black, "Link")
                ],
              ),
            ),
          ),
        );
      }
    
      Widget iconcreation(IconData icon, Color color, String text) {
        return InkWell(
          onTap: () {},
          child: Column(
            children: [
              CircleAvatar(
                backgroundColor: color,
                radius: 30,
                child: Icon(
                  icon,
                  size: 29,
                  color: Colors.white,
                ),
              ),
              SizedBox(height: 5),
              Text(text),
            ],
          ),
        );
      }
    
      Widget emojiSelect() {
        return EmojiPicker(
            rows: 4,
            columns: 7,
            onEmojiSelected: (emoji, category) {
              print(emoji);
              setState(() {
                messageController.text = messageController.text + emoji.emoji;
              });
            });
      }
    }
    

    Here is a sample image of the app: Screenshot of App

  • Edgar1102
    Edgar1102 almost 3 years
    This didnt work. It only reversed the order of the messaging. It made my newly writtten messages appear at the top but didnt scroll there
  • Tarik Huber
    Tarik Huber almost 3 years
    Try to remove your scroll controller and leve the reverse.