Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Message sorting not working as intended. #1

Open
ak2766 opened this issue Feb 7, 2020 · 16 comments
Open

Message sorting not working as intended. #1

ak2766 opened this issue Feb 7, 2020 · 16 comments

Comments

@ak2766
Copy link

ak2766 commented Feb 7, 2020

Just wanted to state that my final chat_screen code is exactly identical to your final project but the sorting of messages isn't working as intended - both on the emulator and on my Galaxy S8+. See screenshots below. There's something very odd happening here.

Will try and fix it on my own and report back here.

I've included a number (1-8) either at the beginning or at the end of the chat message to allow you to follow message post chronology.

Emulator:
Selection_00182

Galaxy S8:
Selection_00183

@ak2766
Copy link
Author

ak2766 commented Feb 7, 2020

After thinking this through a little bit before embarking on coding (just by looking at the order in which they appear in Firebase), it seems the real solution is to add a timestamp to each message, then on retrieval, sort the messages based on the timestamp before adding them to the messageBubbles list.

@FadyWaheed11
Copy link

can you share the code after your update @ak2766

@koorosh-k98
Copy link

koorosh-k98 commented Feb 26, 2020

I added timestamp into the code and it worked. @FadyWaheed11
chat_screen.txt

@farzintava
Copy link

I used DateTime into the code and it works well.
chat_screen.txt

@ak2766
Copy link
Author

ak2766 commented Mar 3, 2020

@FadyWaheed11

can you share the code after your update @ak2766

Apologies, I got busy and haven't returned to this, but I see others had the same idea and already have a solution. Hopefully that works for you too.

@FadyWaheed11
Copy link

Thanks bro it works @ak2766

@Elsrougy
Copy link

Hello guys, I know it's been a while but can I add something?

With the method you proposed, if someone with a phone clock which is not accurate it will mess up the order, right? I know that will be rare but it's something we should think about.

@farzintava
Copy link

Hello guys, I know it's been a while but can I add something?

With the method you proposed, if someone with a phone clock which is not accurate it will mess up the order, right? I know that will be rare but it's something we should think about.

If use unix time instead of phone clock it works well.

@Raj-kar
Copy link

Raj-kar commented Jun 17, 2020

Use This Code after clearing your all old Database message and Data from firebase cloud DataBase . Once you clear all the previous data from database, you can you this code .
credit :- @koorosh-k98,

`import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../constants.dart';

final _firestore = Firestore.instance;
FirebaseUser loggedInUser;

class ChatScreen extends StatefulWidget {
static const String id = 'chat_screen';
@OverRide
_ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State {
final messageTextController = TextEditingController();
final _auth = FirebaseAuth.instance;

String messageText;

@OverRide
void initState() {
super.initState();

getCurrentUser();

}

void getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: [
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
MessagesStream(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
messageTextController.clear();
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
'date and time': DateTime.now().toString(),
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}

class MessagesStream extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return StreamBuilder(
stream: _firestore.collection('messages').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final messages = snapshot.data.documents.reversed;
List messageBubbles = [];
for (var message in messages) {
final messageText = message.data['text'];
final messageSender = message.data['sender'];
final messageDateTime = message.data['date and time'];

      final currentUser = loggedInUser.email;

      final messageBubble = MessageBubble(
        sender: messageSender,
        text: messageText,
        isMe: currentUser == messageSender,
        dateTime: messageDateTime,
      );

      messageBubbles.add(messageBubble);
       messageBubbles.sort((a, b) =>
          DateTime.parse(b.dateTime).compareTo(DateTime.parse(a.dateTime)));
    }
    return Expanded(
      child: ListView(
        reverse: true,
        padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
        children: messageBubbles,
      ),
    );
  },
);

}
}

class MessageBubble extends StatelessWidget {
MessageBubble({this.sender, this.text, this.isMe, this.dateTime});

final String sender;
final String text;
final String dateTime;
final bool isMe;

@OverRide
Widget build(BuildContext context) {
print(dateTime);
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Text(
sender,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
Material(
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30.0),
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0))
: BorderRadius.only(
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
elevation: 5.0,
color: isMe ? Colors.lightBlueAccent : Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Text(
text,
style: TextStyle(
color: isMe ? Colors.white : Colors.black54,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
`

@Heipi
Copy link

Heipi commented Jul 15, 2020

Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
messageText = value;
},

very good,Thanks

@RahiPatel25
Copy link

TimeStamp or DateTime is not proper method to sorting messages because i give one example, So there are two Devices, DeviceA and DeviceB both install this App but DeviceA's time is 10:45 and DeviceB's time is 10:50 so messages not sorting properly, my suggestion is to use this below method to work properly...

onPressed: () {
messageTextController.clear();
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
'timestamp': FieldValue.serverTimestamp(),

                    });
                  },

class MessagesStream extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return StreamBuilder(
stream: _firestore
.collection('messages')
.orderBy('timestamp', descending: false)
.snapshots(),
// ignore: missing_return
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}

(
Highlight of Sorting method above code:-
'timestamp': FieldValue.serverTimestamp(),

_firestore
.collection('messages')
.orderBy('timestamp', descending: false)
.snapshots(),
)
I used this this methos and its work properly, I hope this will help you! Thank you

@jjjvvvvv
Copy link

jjjvvvvv commented Oct 28, 2020

@RahiPatel25 Thank you. This fixed the sorting issue as well as an issue with messages grouping together out of order, AND by the sender. For the sake of making your comment a little easier to read I will include the code that worked for me below...

The two major components being:

'timestamp': FieldValue.serverTimestamp(),

and

.orderBy('timestamp', descending: false)

In your chat_screen.dart file...

                    onPressed: () {
                      messageTextController.clear();
                      _firestore.collection('messages').add({
                        'text': messageText,
                        'sender': loggedInUser.email,
                        'timestamp': FieldValue.serverTimestamp(),
                      });
                    },
                    child: Text(
                      'Send',
                      style: kSendButtonTextStyle,
                    ),
                  ),

// further down in your code...

return StreamBuilder<QuerySnapshot>(
      stream: _firestore
          .collection('messages')
          .orderBy('timestamp', descending: false)
          .snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return Center(
            child: CircularProgressIndicator(
              backgroundColor: Colors.lightBlueAccent,
            ),
          );

@ygzkrmtc
Copy link

ygzkrmtc commented Jan 8, 2021

I even could not open, when I run code, and tried to open on my phone it stoppes doesnt open why this could be?

@suprimpoudel
Copy link

suprimpoudel commented May 23, 2021

Flutter has changed many things over the past few years along with class names and different objects. Use this code to sort the most recent messages
import 'package:flutter/material.dart';
import 'package:chat_application/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

final _fireStore = FirebaseFirestore.instance;
final _auth = FirebaseAuth.instance;
User loggedInUser;

class ChatScreen extends StatefulWidget {
static const String id = 'chat_screen';

@OverRide
_ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State {
final messageTextController = TextEditingController();

String messageText;

@OverRide
void initState() {
super.initState();
getCurrentUser();
}

void getCurrentUser() async {
try {
final user = _auth.currentUser;
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}

void messagesStream() async {
await for (var snapshot in _fireStore.collection('messages').snapshots()) {
for (var message in snapshot.docs) {
print(message.data());
}
}
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: [
IconButton(
icon: Icon(Icons.power_settings_new),
onPressed: () {
messagesStream();
_auth.signOut();
Navigator.pop(context);
},
),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
MessagesStream(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
TextButton(
onPressed: () {
messageTextController.clear();
try {
_fireStore.collection('messages').add(
{
'sender': loggedInUser.email,
'text': messageText,
'date and time': DateTime.now().toString(),
},
);
} catch (e) {
print(e);
}
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}

class MessagesStream extends StatelessWidget {
const MessagesStream({Key key}) : super(key: key);

@OverRide
Widget build(BuildContext context) {
return StreamBuilder(
stream: _fireStore.collection('messages').snapshots(),
// ignore: missing_return
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.blue,
),
);
}
final messages = snapshot.data.docs.reversed;
List messageList = [];
for (var message in messages) {
final messageText = message.get('text');
final messageSender = message.get('sender');
final dateTime = message.get('date and time');
print(_auth.currentUser.email);
final messageBubble = MessageBubble(messageText, messageSender,
_auth.currentUser.email == messageSender, dateTime);
// currentUser == messageSender
messageList.add(messageBubble);
messageList.sort(
(a, b) => DateTime.parse(b.dateTime).compareTo(
DateTime.parse(a.dateTime),
),
);
}
return Expanded(
child: ListView(
reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
children: messageList,
),
);
},
);
}
}

class MessageBubble extends StatelessWidget {
final String sender;
final String text;
final String dateTime;
final bool isMe;
MessageBubble(this.text, this.sender, this.isMe, this.dateTime);
@OverRide
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Text(
sender,
style: TextStyle(
color: Colors.black54,
fontSize: 12.0,
),
),
Material(
color: isMe ? Colors.lightBlueAccent : Colors.white,
elevation: 5.0,
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30.0),
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
)
: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Text(
text,
style: TextStyle(
color: isMe ? Colors.white : Colors.black,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}

@besharman
Copy link

Hey I'm working on an almost same app, the order is still very unpredictable even with those two reverse conditions.

@Abdusamad98
Copy link

Great , it works ,and me also Thanks guys

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests