skip to Main Content

I’m trying to make this chat app where i want to add an unsend option (allowing the users to delete the messages they sent). I succeeded in getting the unsend option selected but now I cant figure out how to do these few things.

  1. delete message (somehow get document id of selected message and delete it)
  2. see if the message to be deleted was sent by the logged in user (this i can figure out on my own ig)

I cant seem to get hang of how to figure out the document id.

Heres the chat screen’s code:

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

final _fireStore = FirebaseFirestore.instance;
late User loggedInUser;

class ChatScreen extends StatefulWidget {
  const ChatScreen({super.key});

  static String id = '/chat';

  @override
  State<ChatScreen> createState() => _ChatScreenState();
}

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

  late String messageText;

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: null,
        actions: <Widget>[
          IconButton(
              icon: const Icon(Icons.close),
              onPressed: () {
                _auth.signOut();
                Navigator.pop(context);
              }),
        ],
        title: const Text('⚡️Chat'),
        backgroundColor: Colors.lightBlueAccent,
      ),
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            const MessagesStream(),
            Container(
              decoration: kMessageContainerDecoration,
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  Expanded(
                    child: TextField(
                      controller: messageTextController,
                      onChanged: (value) {
                        messageText = value;
                      },
                      decoration: kTextFieldDecoration,
                    ),
                  ),
                  TextButton(
                    onPressed: () {
                      messageTextController.clear();
                      _fireStore.collection('messages').add({
                        'text': messageText,
                        'sender': loggedInUser.email,
                        'timestamp': FieldValue.serverTimestamp(),
                      });
                    },
                    child: const Text(
                      'Send',
                      style: kSendButtonTextStyle,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream:
          _fireStore.collection('messages').orderBy('timestamp').snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return const Center(
            child: CircularProgressIndicator(
              backgroundColor: Colors.lightBlueAccent,
            ),
          );
        }
        final messages = snapshot.data!.docs.reversed;
        List<Messagebubble> messageBubbles = [];
        for (var message in messages) {
          final messageText = message.get('text');
          final messageSender = message.get('sender');

          final currentUser = loggedInUser.email;

          final messageBubble = Messagebubble(
            sender: messageSender,
            text: messageText,
            isMe: currentUser == messageSender,
          );
          messageBubbles.add(messageBubble);
        }

        return Expanded(
          child: ListView(
            reverse: true,
            padding: const EdgeInsets.symmetric(
              horizontal: 10.0,
              vertical: 20.0,
            ),
            children: messageBubbles,
          ),
        );
      },
    );
  }
}

class Messagebubble extends StatefulWidget {
  const Messagebubble(
      {required this.sender,
      required this.text,
      required this.isMe,
      super.key});

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

  @override
  State<Messagebubble> createState() => _MessagebubbleState();
}

class _MessagebubbleState extends State<Messagebubble> {
  late Offset tapXY;
  late RenderBox overlay;

  // void _getTapPosition(TapDownDetails details) {
  //   final RenderBox referenceBox = context.findRenderObject() as RenderBox;
  //   setState(() {
  //     tapXY = referenceBox.globalToLocal(details.globalPosition);
  //   });
  // }

  void _getTapPosition(TapDownDetails detail) {
    tapXY = detail.globalPosition;
  }

  void _showContextMenu(BuildContext context) async {
    final RenderObject? overlay =
        Overlay.of(context)?.context.findRenderObject();

    final result = await showMenu(
        context: context,

        // Show the context menu at the tap location
        position: RelativeRect.fromRect(
            Rect.fromLTWH(tapXY.dx, tapXY.dy, 30, 30),
            Rect.fromLTWH(0, 0, overlay!.paintBounds.size.width,
                overlay.paintBounds.size.height)),

        // set a list of choices for the context menu
        items: [
          const PopupMenuItem(
            value: 'unsend',
            child: Text('Unsend Message'),
          ),
        ]);

    // Implement the logic for each choice here
    switch (result) {
      case 'unsend':
        debugPrint('Add To Favorites');
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(10.0),
      child: Column(
        crossAxisAlignment:
            widget.isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
        children: [
          Text(
            widget.sender,
            style: const TextStyle(
              fontSize: 12.0,
              color: Colors.black,
            ),
          ),
          GestureDetector(
            onTapDown: (details) => _getTapPosition(details),
            onLongPress: () => _showContextMenu(context),
            child: Material(
              elevation: 5.0,
              borderRadius: BorderRadius.only(
                topLeft: widget.isMe
                    ? const Radius.circular(30)
                    : const Radius.circular(0),
                topRight: widget.isMe
                    ? const Radius.circular(0)
                    : const Radius.circular(30),
                bottomLeft: const Radius.circular(30),
                bottomRight: const Radius.circular(30),
              ),
              color: widget.isMe ? Colors.lightBlueAccent : Colors.white,
              child: Padding(
                padding: const EdgeInsets.symmetric(
                    vertical: 10.0, horizontal: 10.0),
                child: Text(
                  widget.text,
                  style: const TextStyle(
                    fontSize: 15.0,
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

2

Answers


  1. You need the ID of the message you want to delete.

    Future<void> deleteMessage(String msgId) async {
      return await _fireStore.collection('messages').doc(msgId).delete();
    }
    

    See also the docs for deleting Firestore data and the references.

    Login or Signup to reply.
  2. first, let’s say you have a DocuemntQuery calles doc_ref, and we gor the snapshot from it :

    DocumentSnapshot docSnap = await doc_ref.get();
    

    you can get the documentId from the DocumentSnapshot like this :

    var doc_id = docSnap.reference.documentID;
    

    then you can delete that document with that id :

    await _fireStore.collection(CollectioName).doc(doc_id).delete();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search