Main coves client
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(reply): cache FlutterView to prevent crash on screen re-open

View.of(context) was being called in didChangeMetrics() during widget
deactivation, causing "Looking up a deactivated widget's ancestor"
errors. The context becomes invalid before mounted becomes false.

Fixed by caching the FlutterView reference in didChangeDependencies()
for both _ReplyScreenState and _ReplyToolbarState, then using the
cached reference in didChangeMetrics().

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+21 -5
+21 -5
lib/screens/compose/reply_screen.dart
··· 1 import 'dart:async'; 2 import 'dart:math' as math; 3 4 import 'package:flutter/foundation.dart'; 5 import 'package:flutter/material.dart'; ··· 67 bool _authInvalidated = false; 68 double _lastKeyboardHeight = 0; 69 Timer? _bannerDismissTimer; 70 71 @override 72 void initState() { ··· 92 }); 93 } 94 95 void _setupAuthListener() { 96 try { 97 context.read<AuthProvider>().addListener(_onAuthChanged); ··· 151 super.didChangeMetrics(); 152 // Guard against being called after widget is deactivated 153 // (can happen during keyboard animation while navigating away) 154 - if (!mounted) return; 155 156 - final keyboardHeight = View.of(context).viewInsets.bottom; 157 158 // Detect keyboard closing and unfocus text field 159 if (_lastKeyboardHeight > 0 && keyboardHeight == 0) { ··· 495 with WidgetsBindingObserver { 496 final ValueNotifier<double> _keyboardMarginNotifier = ValueNotifier(0); 497 final ValueNotifier<double> _safeAreaBottomNotifier = ValueNotifier(0); 498 499 @override 500 void initState() { ··· 505 @override 506 void didChangeDependencies() { 507 super.didChangeDependencies(); 508 _updateMargins(); 509 } 510 ··· 518 519 @override 520 void didChangeMetrics() { 521 - _updateMargins(); 522 } 523 524 void _updateMargins() { 525 - if (!mounted) { 526 return; 527 } 528 - final view = View.of(context); 529 final devicePixelRatio = view.devicePixelRatio; 530 final keyboardInset = view.viewInsets.bottom / devicePixelRatio; 531 final viewPaddingBottom = view.viewPadding.bottom / devicePixelRatio;
··· 1 import 'dart:async'; 2 import 'dart:math' as math; 3 + import 'dart:ui' show FlutterView; 4 5 import 'package:flutter/foundation.dart'; 6 import 'package:flutter/material.dart'; ··· 68 bool _authInvalidated = false; 69 double _lastKeyboardHeight = 0; 70 Timer? _bannerDismissTimer; 71 + FlutterView? _cachedView; 72 73 @override 74 void initState() { ··· 94 }); 95 } 96 97 + @override 98 + void didChangeDependencies() { 99 + super.didChangeDependencies(); 100 + // Cache the view reference so we can safely use it in didChangeMetrics 101 + // even when the widget is being deactivated 102 + _cachedView = View.of(context); 103 + } 104 + 105 void _setupAuthListener() { 106 try { 107 context.read<AuthProvider>().addListener(_onAuthChanged); ··· 161 super.didChangeMetrics(); 162 // Guard against being called after widget is deactivated 163 // (can happen during keyboard animation while navigating away) 164 + if (!mounted || _cachedView == null) return; 165 166 + final keyboardHeight = _cachedView!.viewInsets.bottom; 167 168 // Detect keyboard closing and unfocus text field 169 if (_lastKeyboardHeight > 0 && keyboardHeight == 0) { ··· 505 with WidgetsBindingObserver { 506 final ValueNotifier<double> _keyboardMarginNotifier = ValueNotifier(0); 507 final ValueNotifier<double> _safeAreaBottomNotifier = ValueNotifier(0); 508 + FlutterView? _cachedView; 509 510 @override 511 void initState() { ··· 516 @override 517 void didChangeDependencies() { 518 super.didChangeDependencies(); 519 + // Cache view reference for safe access in didChangeMetrics 520 + _cachedView = View.of(context); 521 _updateMargins(); 522 } 523 ··· 531 532 @override 533 void didChangeMetrics() { 534 + // Schedule update after frame to ensure context is valid 535 + WidgetsBinding.instance.addPostFrameCallback((_) { 536 + _updateMargins(); 537 + }); 538 } 539 540 void _updateMargins() { 541 + if (!mounted || _cachedView == null) { 542 return; 543 } 544 + final view = _cachedView!; 545 final devicePixelRatio = view.devicePixelRatio; 546 final keyboardInset = view.viewInsets.bottom / devicePixelRatio; 547 final viewPaddingBottom = view.viewPadding.bottom / devicePixelRatio;