类型 'Null' 不是类型 'Timestamp' 的子类型 Flutter

Type 'Null' is not a subtype of type 'Timestamp' Flutter

在聊天屏幕中,我希望当地时间与聊天消息一起发布。它正在发布,但我每次 post 聊天时都会收到错误消息。

构建 StreamBuilder> 时抛出了以下 _TypeError(脏,状态:_StreamBuilderBaseState,AsyncSnapshot>>#433c7): 类型 'Null' 不是类型 'Timestamp'

的子类型

如何解决这个错误?

这是聊天屏幕的代码:

import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import '../../animated_texts.dart'; import '../../constants.dart'; import '../../services/auth.dart';

import 'package:grouped_list/grouped_list.dart'; import 'package:intl/intl.dart';

final FirebaseFirestore _firestore = FirebaseFirestore.instance; late User loggedInUser;

class ChatScreen extends StatefulWidget {   const ChatScreen({Key? key}) : super(key: key);

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

class _ChatScreenState extends State<ChatScreen> {   final messageTextController = TextEditingController();   late String messageTexts;   final FirebaseAuth _authService = FirebaseAuth.instance;   final AuthService _authLogOut = AuthService();

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

  void getCurrentUser() {
    try {
      final user = _authService.currentUser;
      if (user != null) {
        loggedInUser = user;
        //print(loggedInUser.uid.substring(loggedInUser.uid.length - 5));
      }
    } catch (e) {
      //print('The Error : $e');
    }   }

  @override   Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.black,
        shadowColor: Colors.transparent,
        leading: IconButton(
            icon: const Icon(
              Icons.arrow_back_ios,
              color: Colors.white,
            ),
            onPressed: () {
              Navigator.maybePop(context);
            }),
        actions: <Widget>[
          IconButton(
              icon: const Icon(
                Icons.exit_to_app,
                color: Colors.white,
              ),
              onPressed: () {
                openDialog();
              }),
        ],
        centerTitle: true,
        title: const AnimatedTitle(
          text: 'AnonC',
          fontSize: 25.0,
        ),
      ),
      body: SafeArea(
        child: Container(
          color: Colors.black,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              const MessagesStream(),
              Container(
                color: Colors.green,
                //blueGrey[900],
                padding: const EdgeInsets.all(10),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Expanded(
                      child: TextField(
                        controller: messageTextController,
                        maxLines: null,
                        keyboardType: TextInputType.multiline,
                        textInputAction: TextInputAction.newline,
                        textCapitalization: TextCapitalization.sentences,
                        autocorrect: true,
                        enableSuggestions: true,
                        onChanged: (value) {
                          messageTexts = value;
                        },
                        decoration: kMessageTextFieldDecoration,
                      ),
                    ),
                    Container(
                      padding: const EdgeInsets.all(3),
                      decoration: const BoxDecoration(
                        color: Colors.white54,
                        shape: BoxShape.circle,
                      ),
                      child: TextButton(
                        onPressed: () {
                          messageTextController.clear();
                          _firestore.collection('chatMessages').add({
                            'messages': messageTexts,
                            'name': 'Anon - ' +
                                loggedInUser.uid
                                    .substring(loggedInUser.uid.length - 5),
                            'userEmoji': 'user emoji',
                            'timestamp': FieldValue.serverTimestamp(),
                          });
                          // messageTexts + loggedInUser;
                        },
                        child: Icon(
                          Icons.send_outlined,
                          size: 35,
                          color: Colors.blueGrey.shade900,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );   }

  Future openDialog() => showDialog(
        context: context,
        builder: (context) => AlertDialog(
          backgroundColor: Colors.lightGreenAccent,
          shape: const RoundedRectangleBorder(
              borderRadius: BorderRadius.all(Radius.circular(18.0))),
          title: const Text(
            "Are You sure you want to Log out?",
            style: TextStyle(
              color: Colors.black,
              fontSize: 18,
            ),
          ),
          content: const Text(
            "Would Love to Welcome You back again!",
            style: TextStyle(
              color: Colors.black,
              fontStyle: FontStyle.italic,
              fontSize: 18,
            ),
          ),
          actions: [
            TextButton(
              child: const Text("Yes"),
              onPressed: () {
                _authLogOut.signOut();
                Navigator.pop(context, '/');
              },
            ),
            TextButton(
              child: const Text("No"),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ); }

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

  @override   Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
        stream: _firestore
            .collection('chatMessages')
            .orderBy('timestamp', descending: true)
            .snapshots(),
        builder: (context, snapshot) {
          List<MessageBubble> messages = [];

          if (!snapshot.hasData) {
            return const Center(
              child: CircularProgressIndicator(
                backgroundColor: Colors.orange,
              ),
            );
          }
          final chatMessages = snapshot.data!.docs;

          for (var message in chatMessages) {
            final messageText = message['messages'];
            final messageSender = message['name'];
            final currentUser =
                loggedInUser.uid.substring(loggedInUser.uid.length - 5);
            final timeStamps = message['timestamp'];
            if (currentUser == messageSender) {
              currentUser;
              //   //The message is from the logged in user
            }

            final messageHolder = MessageBubble(
              sender: messageSender,
              date: DateTime.now().subtract(const Duration(minutes: 1)),
              text: messageText,
              isME: currentUser == messageSender,
              time: timeStamps,
            );
            messages.add(messageHolder);
          }
          return Expanded(
            child: Padding(
              padding: const EdgeInsets.only(top: 1),
              child: Container(
                padding: const EdgeInsets.all(5),
                decoration: const BoxDecoration(
                  color: Colors.green,
                  //blueGrey[900],
                  borderRadius: BorderRadius.only(
                    topRight: Radius.circular(55),
                    topLeft: Radius.circular(55),
                  ),
                ),
                // child: ListView(
                //   physics: const BouncingScrollPhysics(),
                //   reverse: true,
                //   // ignore: prefer_const_constructors
                //   padding: EdgeInsets.all(15),
                //   children: messageHolders,
                // ),

                child: GroupedListView<MessageBubble, DateTime>(
                  padding: const EdgeInsets.all(15),
                  reverse: true,
                  //order: GroupedListOrder.DESC,
                  //padding: const EdgeInsets.only(top: 1),
                  elements: messages,
                  groupBy: (messages) => DateTime(
                    messages.date.year,
                    messages.date.month,
                    messages.date.day,
                  ),
                  groupHeaderBuilder: (messages) => SizedBox(
                    height: 50,
                    child: Center(
                      child: Card(
                        color: Colors.lightBlueAccent,
                        child: Padding(
                          padding: const EdgeInsets.all(4),
                          child: Text(
                            DateFormat.yMMMd().format(messages.date),
                            style: const TextStyle(color: Colors.white),
                          ),
                        ),
                      ),
                    ),
                  ),
                  physics: const BouncingScrollPhysics(),
                  useStickyGroupSeparators: true,
                  floatingHeader: true,
                  itemBuilder: (context, MessageBubble messages) => messages,
                ),
              ),
            ),
          );
        });   } }

class MessageBubble extends StatelessWidget {   final String text;   final DateTime date;   final bool isME;   final String sender;   final Timestamp time;

  // ignore: use_key_in_widget_constructors   const MessageBubble({
    required this.text,
    required this.date,
    required this.isME,
    required this.sender,
    required this.time,   });

  @override   Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(11.0),
      child: Column(
        crossAxisAlignment:
            isME ? CrossAxisAlignment.start : CrossAxisAlignment.end,
        children: [
          Text(sender),
          const SizedBox(height: 10),
          Material(
            color: isME ? Colors.lightGreenAccent[100] : Colors.brown[100],
            elevation: 10,
            borderRadius: isME
                ? const BorderRadius.only(
                    topLeft: Radius.circular(-50),
                    bottomRight: Radius.circular(10),
                    bottomLeft: Radius.circular(10),
                    topRight: Radius.circular(10),
                  )
                : const BorderRadius.only(
                    topRight: Radius.circular(-50),
                    bottomRight: Radius.circular(10),
                    bottomLeft: Radius.circular(10),
                    topLeft: Radius.circular(10),
                  ),
            child: Padding(
              padding: const EdgeInsets.all(12.0),
              child: Text(
                text,
                style: TextStyle(
                    color: isME ? Colors.blueGrey : Colors.black,
                    fontWeight: FontWeight.normal),
              ),
            ),
          ),
          const SizedBox(height: 10),
          Text(
            DateFormat.jm().format(DateTime.now()),
            //DateTime.now().toLocal().toString(),
            //DateFormat.jm().format(DateTime.now().toLocal()),
            //DateTime.now().subtract(const Duration(minutes: 1)).toString(),
            //hour.toString()),
            //DateFormat.jm().format(DateTime.now()),
            //.format(messages.timeStamp)
          ),
        ],
      ),
    );   } }

问题是 timeStamps 会在几毫秒内得到一个空值,在那段时间你可以用 currentTime 代替

final currentTime = Timestamp.fromMicrosecondsSinceEpoch(DateTime.now().millisecondsSinceEpoch);
final timeStamps = message['timestamp'] == null ? currentTime : message['timestamp'] as Timestamp;