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.
- 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’." - 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:
- User long presses on a chat message.
- Bottom modal opens with a bunch of action. One of the action is to assign topics/categories to the message.
- Selecting "Topic" should open a dialog, with a list of existing topics from the DB. Which is does. (yay some success here)
- 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
I saw you are using
Stateful widget
in thisSo when you are using stateful widgets you can get rid of this warning by just
wrapping your code with this
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.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 thisElement
would not be part of the tree and so it won’t be able to scope particularlyProvider
..of
) of the provider works you can head to this question’s answer.