Fix bugs found in full code audit
- Edit screens (note, task): cache _initFuture in initState instead of
calling _loadExisting() from FutureBuilder on every rebuild. Prevents
race condition where multiple concurrent loads could overwrite edits.
Also removes unnecessary _loaded flag and simplifies the pattern.
- Note editor: remove onChanged: (_) => setState((){}) on the body
TextField — triggered a full rebuild on every keystroke for no reason.
- SSE streaming: use utf8.decode(chunk, allowMalformed: true) so a
malformed byte sequence from the server skips rather than throwing an
unhandled FormatException that escaped all catch blocks.
- Chat provider: guard msgs.isEmpty before accessing msgs.last during
SSE chunk processing to prevent a potential index error on empty state.
- Offline queue drain: check mounted before and after each async gap in
_drainQueue so ref is never accessed on a disposed widget.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,16 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
|
||||
final _contentController = TextEditingController();
|
||||
bool _preview = false;
|
||||
bool _saving = false;
|
||||
bool _loaded = false;
|
||||
|
||||
// Future is created once in initState so FutureBuilder never restarts it.
|
||||
late final Future<void> _initFuture;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initFuture =
|
||||
widget.noteId != null ? _loadExisting() : Future.value();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -30,15 +39,10 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
|
||||
}
|
||||
|
||||
Future<void> _loadExisting() async {
|
||||
if (_loaded || widget.noteId == null) {
|
||||
_loaded = true;
|
||||
return;
|
||||
}
|
||||
final note =
|
||||
await ref.read(notesRepositoryProvider).getOne(widget.noteId!);
|
||||
_titleController.text = note.title;
|
||||
_contentController.text = note.body;
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
Future<void> _delete() async {
|
||||
@@ -97,7 +101,7 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: _loadExisting(),
|
||||
future: _initFuture,
|
||||
builder: (context, snapshot) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
@@ -159,7 +163,6 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
|
||||
expands: true,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textAlignVertical: TextAlignVertical.top,
|
||||
onChanged: (_) => setState(() {}),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user