11part of 'app_runner.dart' ;
22
3+ const double _kMaxWidth = 100000.0 ;
4+ const double _kMaxHeight = 100000.0 ;
5+
36/// {@template ErrorHandlerWidget}
47/// Widget that catches and handles widget errors
58/// {@endtemplate}
6- class ErrorHandlerWidget extends StatelessWidget {
9+ class ErrorHandlerWidget extends LeafRenderObjectWidget {
710 /// {@macro ErrorHandlerWidget}
811 ErrorHandlerWidget ({
912 required this .errorDetails,
@@ -15,89 +18,134 @@ class ErrorHandlerWidget extends StatelessWidget {
1518 final FlutterErrorDetails errorDetails;
1619
1720 /// Widget for error handling in debug and profile mode
18- final ErrorWidgetBuilder ? errorBuilder;
21+ final ErrorRenderObjectBuilder ? errorBuilder;
1922
2023 /// Widget for error handling in release mode
21- final WidgetBuilder ? releaseErrorBuilder;
24+ final RenderObjectBuilder ? releaseErrorBuilder;
2225
2326 @override
24- Widget build (BuildContext context) {
27+ RenderObject createRenderObject (BuildContext context) {
2528 if (kReleaseMode) {
26- final WidgetBuilder ? _releaseErrorBuilder = releaseErrorBuilder;
29+ final RenderObjectBuilder ? _releaseErrorBuilder = releaseErrorBuilder;
2730 if (_releaseErrorBuilder != null ) {
2831 return _releaseErrorBuilder (context);
2932 }
3033
31- return const _ReleaseErrorWidget ( );
34+ return _RenderReleaseErrorBox (context.reloadWidget );
3235 }
3336
34- final ErrorWidgetBuilder ? _errorBuilder = errorBuilder;
37+ final ErrorRenderObjectBuilder ? _errorBuilder = errorBuilder;
3538 if (_errorBuilder != null ) {
3639 return _errorBuilder (context, errorDetails);
3740 }
3841
39- return _ErrorWidget (errorDetails: errorDetails );
42+ return _RenderErrorBox (errorDetails, context.reloadWidget );
4043 }
4144}
4245
43- class _ReleaseErrorWidget extends StatelessWidget {
44- const _ReleaseErrorWidget ({
45- Key ? key,
46- }) : super (key: key);
46+ class _RenderReleaseErrorBox extends RenderBox {
47+ _RenderReleaseErrorBox (this .onTap) {
48+ try {
49+ final ui.ParagraphBuilder builder = ui.ParagraphBuilder (paragraphStyle);
50+ builder.pushStyle (textStyle);
51+ builder.addText ('Something went wrong\n\n Tap to reload application' );
52+ _paragraph = builder.build ();
53+ } catch (_) {
54+ // If an error happens here we're in a terrible state, so we really should
55+ // just forget about it and let the developer deal with the already-reported
56+ // errors. It's unlikely that these errors are going to help with that.
57+ }
58+ }
59+
60+ final ui.ParagraphStyle paragraphStyle = ui.ParagraphStyle (
61+ textDirection: TextDirection .ltr,
62+ textAlign: TextAlign .center,
63+ );
64+
65+ final ui.TextStyle textStyle = ui.TextStyle (
66+ fontSize: 18.0 ,
67+ );
68+
69+ late final ui.Paragraph _paragraph;
70+
71+ final VoidCallback onTap;
4772
4873 @override
49- Widget build (BuildContext context) {
50- return Scaffold (
51- body: Center (
52- child: Column (
53- mainAxisAlignment: MainAxisAlignment .center,
54- children: < Widget > [
55- const Text ('Something went wrong' ),
56- Padding (
57- padding: const EdgeInsets .all (8.0 ),
58- child: ElevatedButton (
59- onPressed: () => context.reloadWidget (),
60- child: const Text ('Reload application' ),
61- ),
62- ),
63- ],
64- ),
65- ),
66- );
74+ double computeMaxIntrinsicWidth (double height) {
75+ return _kMaxWidth;
6776 }
68- }
6977
70- class _ErrorWidget extends StatelessWidget {
71- const _ErrorWidget ({Key ? key, required this .errorDetails}) : super (key: key);
78+ @override
79+ double computeMaxIntrinsicHeight (double width) {
80+ return _kMaxHeight;
81+ }
7282
73- final FlutterErrorDetails errorDetails;
83+ @override
84+ bool get sizedByParent => true ;
7485
7586 @override
76- Widget build (BuildContext context) {
77- return Scaffold (
78- body: Padding (
79- padding: const EdgeInsets .all (10 ),
80- child: ListView (
81- children: < Widget > [
82- Center (
83- child: ElevatedButton (
84- onPressed: () => context.reloadWidget (),
85- child: const Text ('Reload Widgets' ),
86- ),
87- ),
88- Text ('Library: ${errorDetails .toStringShort ()}' ),
89- const Divider (),
90- Text ('DiagnosticsNode: ${errorDetails .context ?.toDescription ()}' ),
91- const Divider (),
92- Text ('ErrorDetails: ${_stringify (errorDetails .exception )}' ),
93- const Divider (),
94- Text ('StackTrace: ${errorDetails .stack .toString ()}' ),
95- ],
96- ),
97- ),
98- );
87+ bool hitTestSelf (Offset position) {
88+ onTap ();
89+ return true ;
9990 }
10091
92+ @override
93+ Size computeDryLayout (BoxConstraints constraints) {
94+ return constraints.constrain (const Size (_kMaxWidth, _kMaxHeight));
95+ }
96+
97+ @override
98+ void paint (PaintingContext context, Offset offset) {
99+ try {
100+ context.canvas.drawRect (
101+ offset & size,
102+ Paint ()..color = const ui.Color (0xEC2E2E2E ),
103+ );
104+
105+ _paragraph.layout (ui.ParagraphConstraints (width: size.width));
106+ context.canvas.drawParagraph (_paragraph, size.centerLeft (offset));
107+ } catch (_) {
108+ // If an error happens here we're in a terrible state, so we really should
109+ // just forget about it and let the developer deal with the already-reported
110+ // errors. It's unlikely that these errors are going to help with that.
111+ }
112+ }
113+ }
114+
115+ class _RenderErrorBox extends RenderBox {
116+ _RenderErrorBox (final FlutterErrorDetails errorDetails, this .onTap) {
117+ try {
118+ final ui.ParagraphBuilder builder = ui.ParagraphBuilder (paragraphStyle);
119+ builder.pushStyle (textStyle);
120+ builder.addText ('''
121+ Library: ${errorDetails .toStringShort ()}
122+ DiagnosticsNode: ${errorDetails .context ?.toDescription ()}
123+
124+ ErrorDetails: ${_stringify (errorDetails .exception )}
125+
126+ StackTrace: \n ${errorDetails .stack .toString ()}
127+ ''' );
128+ _paragraph = builder.build ();
129+ } catch (_) {
130+ // If an error happens here we're in a terrible state, so we really should
131+ // just forget about it and let the developer deal with the already-reported
132+ // errors. It's unlikely that these errors are going to help with that.
133+ }
134+ }
135+
136+ final ui.ParagraphStyle paragraphStyle = ui.ParagraphStyle (
137+ textDirection: TextDirection .ltr,
138+ textAlign: TextAlign .left,
139+ );
140+
141+ final ui.TextStyle textStyle = ui.TextStyle (
142+ fontSize: 14.0 ,
143+ );
144+
145+ late final ui.Paragraph _paragraph;
146+
147+ final VoidCallback onTap;
148+
101149 String _stringify (Object exception) {
102150 try {
103151 return exception.toString ();
@@ -106,4 +154,45 @@ class _ErrorWidget extends StatelessWidget {
106154 }
107155 return 'Error' ;
108156 }
157+
158+ @override
159+ double computeMaxIntrinsicWidth (double height) {
160+ return _kMaxWidth;
161+ }
162+
163+ @override
164+ double computeMaxIntrinsicHeight (double width) {
165+ return _kMaxHeight;
166+ }
167+
168+ @override
169+ bool get sizedByParent => true ;
170+
171+ @override
172+ bool hitTestSelf (Offset position) {
173+ onTap ();
174+ return true ;
175+ }
176+
177+ @override
178+ Size computeDryLayout (BoxConstraints constraints) {
179+ return constraints.constrain (const Size (_kMaxWidth, _kMaxHeight));
180+ }
181+
182+ @override
183+ void paint (PaintingContext context, Offset offset) {
184+ try {
185+ context.canvas.drawRect (
186+ offset & size,
187+ Paint ()..color = const ui.Color (0xEC2E2E2E ),
188+ );
189+
190+ _paragraph.layout (ui.ParagraphConstraints (width: size.width - 20 ));
191+ context.canvas.drawParagraph (_paragraph, offset + const Offset (10 , 28 ));
192+ } catch (_) {
193+ // If an error happens here we're in a terrible state, so we really should
194+ // just forget about it and let the developer deal with the already-reported
195+ // errors. It's unlikely that these errors are going to help with that.
196+ }
197+ }
109198}
0 commit comments