1
1
import 'package:flutter/material.dart' ;
2
+ import 'package:flutter/services.dart' ;
2
3
3
4
import '../logging/error_handler.dart' ;
4
5
import '../model/publish_source.dart' ;
5
6
6
7
/// A dialog UI that is displayed when something crashes in the SDK. This is
7
8
/// a graceful way of dealing with exceptions.
8
- class CodelesslyErrorScreen extends StatelessWidget {
9
+ class CodelesslyErrorScreen extends StatefulWidget {
9
10
final dynamic exception;
10
11
final PublishSource publishSource;
11
12
@@ -15,14 +16,21 @@ class CodelesslyErrorScreen extends StatelessWidget {
15
16
required this .publishSource,
16
17
});
17
18
19
+ @override
20
+ State <CodelesslyErrorScreen > createState () => _CodelesslyErrorScreenState ();
21
+ }
22
+
23
+ class _CodelesslyErrorScreenState extends State <CodelesslyErrorScreen > {
24
+ bool detailsVisible = false ;
25
+
18
26
@override
19
27
Widget build (BuildContext context) {
20
28
// if (!publishSource.isPreview) return const SizedBox.shrink();
21
29
22
30
final String message;
23
31
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 ;
26
34
title = ce.type.label;
27
35
switch (ce.type) {
28
36
case ErrorType .invalidAuthToken:
@@ -34,7 +42,7 @@ class CodelesslyErrorScreen extends StatelessWidget {
34
42
case ErrorType .projectNotFound:
35
43
message = '${ce .message ?? 'Project not found!' }'
36
44
'\n Please check the provided auth token and try again.' ;
37
- case ErrorType .layoutNotFound :
45
+ case ErrorType .layoutFailed :
38
46
message = '${ce .message ?? 'Layout not found.' }'
39
47
'\n Are you sure the layout ID is correct? If yes, are you sure '
40
48
'you published it successfully through the Codelessly publish '
@@ -65,18 +73,18 @@ class CodelesslyErrorScreen extends StatelessWidget {
65
73
message = '${ce .message ?? 'Failed to connect to the internet.' }'
66
74
'\n Please check your internet connection and try again.' ;
67
75
case ErrorType .assertionError:
68
- message = (exception as CodelesslyException ).message ??
76
+ message = (widget. exception as CodelesslyException ).message ??
69
77
'Assertion error!\n You used the SDK incorrectly!.' ;
70
78
case ErrorType .notInitializedError:
71
- message = (exception as CodelesslyException ).message ??
79
+ message = (widget. exception as CodelesslyException ).message ??
72
80
'Not initialized error!\n You used the SDK incorrectly!.' ;
73
81
case ErrorType .other:
74
- message = (exception as CodelesslyException ).message ??
82
+ message = (widget. exception as CodelesslyException ).message ??
75
83
'Unknown error!\n Sorry this happened :(' ;
76
84
}
77
85
} else {
78
86
message =
79
- 'An unexpected error happened!${exception != null ? '\n $exception ' : '' }' ;
87
+ 'An unexpected error happened!${widget . exception != null ? '\n ${ widget . exception } ' : '' }' ;
80
88
}
81
89
return Padding (
82
90
padding: const EdgeInsets .all (16 ),
@@ -118,13 +126,90 @@ class CodelesslyErrorScreen extends StatelessWidget {
118
126
textAlign: TextAlign .left,
119
127
style: Theme .of (context).textTheme.bodyMedium,
120
128
),
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
+ ),
127
211
),
212
+ ]
128
213
],
129
214
),
130
215
),
0 commit comments