@@ -33,6 +33,7 @@ import 'package:wger/models/workouts/log.dart';
33
33
import 'package:wger/providers/routines.dart' ;
34
34
35
35
import 'consts.dart' ;
36
+ import 'logs.dart' ;
36
37
37
38
void showHttpExceptionErrorDialog (WgerHttpException exception, {BuildContext ? context}) {
38
39
final logger = Logger ('showHttpExceptionErrorDialog' );
@@ -115,6 +116,7 @@ void showGeneralErrorDialog(dynamic error, StackTrace? stackTrace, {BuildContext
115
116
}
116
117
117
118
final String fullStackTrace = stackTrace? .toString () ?? 'No stack trace available.' ;
119
+ final applicationLogs = InMemoryLogStore ().formattedLogs;
118
120
119
121
showDialog (
120
122
context: dialogContext,
@@ -163,32 +165,32 @@ void showGeneralErrorDialog(dynamic error, StackTrace? stackTrace, {BuildContext
163
165
),
164
166
),
165
167
),
168
+ CopyToClipboardButton (
169
+ text: 'Error Title: $issueTitle \n '
170
+ 'Error Message: $issueErrorMessage \n\n '
171
+ 'Stack Trace:\n $fullStackTrace ' ,
172
+ ),
166
173
const SizedBox (height: 8 ),
167
- TextButton .icon (
168
- icon: const Icon (Icons .copy_all_outlined, size: 18 ),
169
- label: Text (i18n.copyToClipboard),
170
- style: TextButton .styleFrom (
171
- padding: const EdgeInsets .symmetric (horizontal: 8 , vertical: 4 ),
172
- tapTargetSize: MaterialTapTargetSize .shrinkWrap,
174
+ Text (
175
+ i18n.applicationLogs,
176
+ style: const TextStyle (fontWeight: FontWeight .bold),
177
+ ),
178
+ Container (
179
+ alignment: Alignment .topLeft,
180
+ padding: const EdgeInsets .symmetric (vertical: 8.0 ),
181
+ constraints: const BoxConstraints (maxHeight: 250 ),
182
+ child: SingleChildScrollView (
183
+ child: Column (
184
+ children: [
185
+ ...applicationLogs.map ((entry) => Text (
186
+ entry,
187
+ style: TextStyle (fontSize: 12.0 , color: Colors .grey[700 ]),
188
+ ))
189
+ ],
190
+ ),
173
191
),
174
- onPressed: () {
175
- final String clipboardText = 'Error Title: $issueTitle \n '
176
- 'Error Message: $issueErrorMessage \n\n '
177
- 'Stack Trace:\n $fullStackTrace ' ;
178
- Clipboard .setData (ClipboardData (text: clipboardText)).then ((_) {
179
- ScaffoldMessenger .of (context).showSnackBar (
180
- const SnackBar (content: Text ('Error details copied to clipboard!' )),
181
- );
182
- }).catchError ((copyError) {
183
- if (kDebugMode) {
184
- logger.fine ('Error copying to clipboard: $copyError ' );
185
- }
186
- ScaffoldMessenger .of (context).showSnackBar (
187
- const SnackBar (content: Text ('Could not copy details.' )),
188
- );
189
- });
190
- },
191
192
),
193
+ CopyToClipboardButton (text: applicationLogs.join ('\n ' )),
192
194
],
193
195
),
194
196
],
@@ -199,14 +201,19 @@ void showGeneralErrorDialog(dynamic error, StackTrace? stackTrace, {BuildContext
199
201
TextButton (
200
202
child: const Text ('Report issue' ),
201
203
onPressed: () async {
204
+ final logText = applicationLogs.isEmpty
205
+ ? '-- No logs available --'
206
+ : applicationLogs.join ('\n ' );
202
207
final description = Uri .encodeComponent (
203
208
'## Description\n\n '
204
209
'[Please describe what you were doing when the error occurred.]\n\n '
205
210
'## Error details\n\n '
206
211
'Error title: $issueTitle \n '
207
212
'Error message: $issueErrorMessage \n '
208
213
'Stack trace:\n '
209
- '```\n $stackTrace \n ```' ,
214
+ '```\n $stackTrace \n ```\n\n '
215
+ 'App logs (last ${applicationLogs .length } entries):\n '
216
+ '```\n $logText \n ```' ,
210
217
);
211
218
final githubIssueUrl = '$GITHUB_ISSUES_BUG_URL '
212
219
'&title=$issueTitle '
@@ -237,6 +244,47 @@ void showGeneralErrorDialog(dynamic error, StackTrace? stackTrace, {BuildContext
237
244
);
238
245
}
239
246
247
+ class CopyToClipboardButton extends StatelessWidget {
248
+ final logger = Logger ('CopyToClipboardButton' );
249
+ final String text;
250
+
251
+ CopyToClipboardButton ({
252
+ required this .text,
253
+ super .key,
254
+ });
255
+
256
+ @override
257
+ Widget build (BuildContext context) {
258
+ final i18n = AppLocalizations .of (context);
259
+
260
+ return TextButton .icon (
261
+ icon: const Icon (Icons .copy_all_outlined, size: 18 ),
262
+ label: Text (i18n.copyToClipboard),
263
+ style: TextButton .styleFrom (
264
+ padding: const EdgeInsets .symmetric (horizontal: 8 , vertical: 4 ),
265
+ tapTargetSize: MaterialTapTargetSize .shrinkWrap,
266
+ ),
267
+ onPressed: () {
268
+ Clipboard .setData (ClipboardData (text: text)).then ((_) {
269
+ if (context.mounted) {
270
+ ScaffoldMessenger .of (context).showSnackBar (
271
+ const SnackBar (content: Text ('Details copied to clipboard!' )),
272
+ );
273
+ }
274
+ }).catchError ((copyError) {
275
+ logger.warning ('Error copying to clipboard: $copyError ' );
276
+
277
+ if (context.mounted) {
278
+ ScaffoldMessenger .of (context).showSnackBar (
279
+ const SnackBar (content: Text ('Could not copy details.' )),
280
+ );
281
+ }
282
+ });
283
+ },
284
+ );
285
+ }
286
+ }
287
+
240
288
void showDeleteDialog (BuildContext context, String confirmDeleteName, Log log) async {
241
289
final res = await showDialog (
242
290
context: context,
0 commit comments