11import 'package:flutter/material.dart' ;
2+ import 'package:flutter/services.dart' ;
23
34import '../logging/error_handler.dart' ;
45import '../model/publish_source.dart' ;
56
67/// A dialog UI that is displayed when something crashes in the SDK. This is
78/// a graceful way of dealing with exceptions.
8- class CodelesslyErrorScreen extends StatelessWidget {
9+ class CodelesslyErrorScreen extends StatefulWidget {
910 final dynamic exception;
1011 final PublishSource publishSource;
1112
@@ -15,14 +16,21 @@ class CodelesslyErrorScreen extends StatelessWidget {
1516 required this .publishSource,
1617 });
1718
19+ @override
20+ State <CodelesslyErrorScreen > createState () => _CodelesslyErrorScreenState ();
21+ }
22+
23+ class _CodelesslyErrorScreenState extends State <CodelesslyErrorScreen > {
24+ bool detailsVisible = false ;
25+
1826 @override
1927 Widget build (BuildContext context) {
2028 // if (!publishSource.isPreview) return const SizedBox.shrink();
2129
2230 final String message;
2331 String ? title;
24- if (exception is CodelesslyException ) {
25- final CodelesslyException ce = exception as CodelesslyException ;
32+ if (widget. exception is CodelesslyException ) {
33+ final CodelesslyException ce = widget. exception as CodelesslyException ;
2634 title = ce.type.label;
2735 switch (ce.type) {
2836 case ErrorType .invalidAuthToken:
@@ -34,7 +42,7 @@ class CodelesslyErrorScreen extends StatelessWidget {
3442 case ErrorType .projectNotFound:
3543 message = '${ce .message ?? 'Project not found!' }'
3644 '\n Please check the provided auth token and try again.' ;
37- case ErrorType .layoutNotFound :
45+ case ErrorType .layoutFailed :
3846 message = '${ce .message ?? 'Layout not found.' }'
3947 '\n Are you sure the layout ID is correct? If yes, are you sure '
4048 'you published it successfully through the Codelessly publish '
@@ -65,18 +73,18 @@ class CodelesslyErrorScreen extends StatelessWidget {
6573 message = '${ce .message ?? 'Failed to connect to the internet.' }'
6674 '\n Please check your internet connection and try again.' ;
6775 case ErrorType .assertionError:
68- message = (exception as CodelesslyException ).message ??
76+ message = (widget. exception as CodelesslyException ).message ??
6977 'Assertion error!\n You used the SDK incorrectly!.' ;
7078 case ErrorType .notInitializedError:
71- message = (exception as CodelesslyException ).message ??
79+ message = (widget. exception as CodelesslyException ).message ??
7280 'Not initialized error!\n You used the SDK incorrectly!.' ;
7381 case ErrorType .other:
74- message = (exception as CodelesslyException ).message ??
82+ message = (widget. exception as CodelesslyException ).message ??
7583 'Unknown error!\n Sorry this happened :(' ;
7684 }
7785 } else {
7886 message =
79- 'An unexpected error happened!${exception != null ? '\n $exception ' : '' }' ;
87+ 'An unexpected error happened!${widget . exception != null ? '\n ${ widget . exception } ' : '' }' ;
8088 }
8189 return Padding (
8290 padding: const EdgeInsets .all (16 ),
@@ -118,13 +126,90 @@ class CodelesslyErrorScreen extends StatelessWidget {
118126 textAlign: TextAlign .left,
119127 style: Theme .of (context).textTheme.bodyMedium,
120128 ),
121- if (exception case CodelesslyException ex)
122- if (ex.originalException != null )
123- Text (
124- ex.originalException.toString (),
125- textAlign: TextAlign .left,
126- style: Theme .of (context).textTheme.bodyMedium,
129+ if (widget.exception case CodelesslyException ex)
130+ if (ex.originalException != null ) ...[
131+ const SizedBox (height: 16 ),
132+ Container (
133+ decoration: BoxDecoration (
134+ color: Theme .of (context)
135+ .colorScheme
136+ .tertiaryContainer,
137+ borderRadius: BorderRadius .circular (8 ),
138+ ),
139+ padding: const EdgeInsets .only (
140+ top: 8 ,
141+ left: 16 ,
142+ right: 16 ,
143+ ),
144+ child: Column (
145+ crossAxisAlignment: CrossAxisAlignment .start,
146+ children: [
147+ Row (
148+ children: [
149+ Expanded (
150+ child: Text (
151+ 'Error Details' ,
152+ style: Theme .of (context)
153+ .textTheme
154+ .titleMedium,
155+ ),
156+ ),
157+ IconButton (
158+ icon: const Icon (Icons .copy),
159+ iconSize: 14 ,
160+ onPressed: () {
161+ Clipboard .setData (
162+ ClipboardData (
163+ text:
164+ '${ex .originalException }\n\n ${ex .stacktrace }' ,
165+ ),
166+ );
167+ },
168+ ),
169+ IconButton (
170+ icon: Icon (
171+ detailsVisible
172+ ? Icons .expand_less
173+ : Icons .expand_more,
174+ ),
175+ iconSize: 14 ,
176+ onPressed: () {
177+ setState (() {
178+ detailsVisible = ! detailsVisible;
179+ });
180+ },
181+ )
182+ ],
183+ ),
184+ const SizedBox (height: 8 ),
185+ ClipRect (
186+ child: AnimatedAlign (
187+ duration:
188+ const Duration (milliseconds: 300 ),
189+ curve: Curves .easeOutQuart,
190+ alignment: Alignment .topCenter,
191+ heightFactor: detailsVisible ? 1 : 0 ,
192+ child: ConstrainedBox (
193+ constraints: const BoxConstraints (
194+ maxHeight: 200 ,
195+ ),
196+ child: SingleChildScrollView (
197+ padding: EdgeInsets .zero,
198+ child: Text (
199+ '${ex .originalException }\n\n ${ex .stacktrace }' ,
200+ textAlign: TextAlign .left,
201+ style: Theme .of (context)
202+ .textTheme
203+ .bodyMedium,
204+ ),
205+ ),
206+ ),
207+ ),
208+ ),
209+ ],
210+ ),
127211 ),
212+ ]
128213 ],
129214 ),
130215 ),
0 commit comments