skip to Main Content

I am trying to build a chat app, and have this class called ChatBubble. This also has the ability to have category from a list of topics.
Here is my code:

class _ChatBubbleState extends State<ChatBubble> {
  final topicsDb = TopicsDatabase();
  // Copy text to clipboard
  void _copyToClipboard(String text) {...

  final GlobalKey _key = GlobalKey();

  @override
  Widget build(BuildContext context) {
    //bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
    // get the Topic object using the topicId of the note
    Topic? topic = widget.note.topicId != null
        ? topicsDb.getTopicById(widget.note.topicId!)
        : null;

    double maxWidth = MediaQuery.of(context).size.width * 0.7; //Trying to dynamically change the size and failing. 
    return Container(
      key: _key,
      padding: const EdgeInsets.only(left: 14, right: 14, top: 10, bottom: 10),
      child: Align(
        alignment: (Alignment.topRight),
        child: Container(
          constraints: BoxConstraints(
            maxWidth: maxWidth, // set maximum width to 70% of screen width
          ),
          decoration: BoxDecoration(
            boxShadow: [
              BoxShadow(
                color: Colors.grey.withOpacity(0.2),
                spreadRadius: 1,
                blurRadius: 2,
                offset: const Offset(0, 1),
              ),
            ],
            borderRadius: BorderRadius.circular(20),
            //color: Colors.grey[100],
          ),
          padding: const EdgeInsets.all(12),
          child: Column(
            children: [
              //Add topic if its present
              if (topic != null)
                Row(...
              const SizedBox(
                height: 10,
              ),
              //Messages
              InkWell(
                onLongPress: () {
                  // Provide haptic feedback
                  //HapticFeedback.mediumImpact();
                  showModalBottomSheet(
                    context: context,
                    builder: (context) {
                      return Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: SizedBox(
                          child: Column(
                            mainAxisSize: MainAxisSize.min,
                            children: [
                              ListTile(...
                              ),
                              ListTile(...
                              ),
                              ListTile(
                                trailing: const FaIcon(
                                  FontAwesomeIcons.folderClosed,
                                  size: 16,
                                  color: Colors.blue,
                                ),
                                title: const Text('Topic'),
                                onTap: () async {
                                  //close the bottom modal before navigating
                                  //Navigator.pop(context);

                                  Topic? newTopic =
                                      await _showTopicsDialog(context);

                                  if (newTopic != null && mounted) {
                                    // Check if widget is still in the tree
                                    Note updatedNote = widget.note
                                        .copyWith(topicId: newTopic.id);

                                    // Use a new BuildContext obtained from a Builder widget or a GlobalKey
                                    // instead of the original context that might be deactivated.
                                    final newContext =
                                        GlobalKey().currentContext ?? context;

                                    // Update the topic
                                    Provider.of<NotesProvider>(newContext,
                                            listen: false)
                                        .updateTopic(updatedNote);
                                    // refresh the HomePage if needed
                                  }
                                },
                              ),
                              const ListTile(...,
                              ),
                              ListTile(...
                              ),
                              const SizedBox(
                                height: 20,
                              ),
                            ],
                          ),
                        ),
                      );
                    },
                  );
                },
                child: Text(
                  widget.note.text,
                  style: const TextStyle(fontSize: 15),
                ),
              ),
              const SizedBox(
                height: 8,
              ),
              //Timestamp
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [...],
              ),
            ],
          ),
        ),
      ),
    );
  }

  //go to edit the note
  void goToNoteEditor(Note note, bool isNewNote) {...

  //delete note
  void deleteNote(Note note) {...

  Future<Topic?> _showTopicsDialog(BuildContext context) async {
    List<Topic> topics = await topicsDb.getAllTopics();
    return showDialog<Topic>(
      context: context,
      builder: (BuildContext context) {
        return SimpleDialog(
          title: const Text('Select Topic'),
          children: topics.map((topic) {
            return SimpleDialogOption(
              onPressed: () {
                Navigator.pop(context, topic);
              },
              child: Text(topic.name),
            );
          }).toList(),
        );
      },
    );
  }
}

I have tried a few things here.

  1. Removed the Navigator.pop (commented out) – This works partially. The bottom modal does not close. I still have the warning – which I am sure is not the right way of doing things. "Don’t use ‘BuildContext’s across async gaps.
    Try rewriting the code to not reference the ‘BuildContext’.
    "
  2. I use the global key and passed it to showTopicsDialog and use the key as the context: context: _key.currentContext!,. This gives me an exception as soon as I select a topic from the dialog. I am assuming this is because I have popped the context and I do not have the original context. I am confused, as this is not a scaffold.

Any help I can get here is appreciated. May this code is a bit wonky to start with.
The goal is the following:

  1. User long presses on a chat message.
  2. Bottom modal opens with a bunch of action. One of the action is to assign topics/categories to the message.
  3. Selecting "Topic" should open a dialog, with a list of existing topics from the DB. Which is does. (yay some success here)
  4. Now the user selects one of the topic. Which in turn updates the chat bubble to add the category as a header. Which also it does editing the message.

2

Answers


  1. I saw you are using Stateful widget in this

    So when you are using stateful widgets you can get rid of this warning by just
    wrapping your code with this

    if(mounted){
      // Your code where you are using build context.
    }
    

    And when you will wrap your code inside this if condition the warning will disappear.

    The meaning of mounted is we are telling flutter that the widget if present on the screen.

    Login or Signup to reply.
    • It simply means that the context that you are using for the scoping you provided might have disposed after/before your async call so it may throw an error as this Element would not be part of the tree and so it won’t be able to scope particularly Provider.
    • For more details on how the scoping(.of) of the provider works you can head to this question’s answer.
    • For a detailed explanation of the async context you can head to this official video on Flutter dev’s youtube handle.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search