Skip to content

Commit

Permalink
feat: StackTrace for ExceptionWidget
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustl22 committed Mar 10, 2024
1 parent bb1a8e0 commit c0b1231
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 36 deletions.
1 change: 1 addition & 0 deletions wrestling_scoreboard_client/lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"mandatoryField": "Das ist ein Pflichtfeld.",
"actionSuccessful": "Die Aktion war erfolgreich.",
"noWebSocketConnection": "Die Verbindung zum Server konnte nicht aufgebaut werden oder wurde unterbrochen.",
"errorOccurred": "Etwas ist schief gelaufen :/",
"notFoundException": "Element wurde nicht gefunden :/",
"invalidParameterException": "Die Änderung war nicht erfolgreich, bitte überprüfe deine Eingabeparameter.",
"warningBoutGenerate": "Diese Aktion überschreibt alle existierenden Kämpfe dieser Begegnung. Um einzelne Kämpfe zu bearbeiten, nutze die Seite zur Kampf-Bearbeitung. Bist du sicher, dass du fortfahren möchtest?",
Expand Down
1 change: 1 addition & 0 deletions wrestling_scoreboard_client/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"mandatoryField": "This is a mandatory field.",
"actionSuccessful": "The action was successful.",
"noWebSocketConnection": "The connection to the server could not be established or was interrupted.",
"errorOccurred": "Something went wrong :/",
"notFoundException": "Element was not found :/",
"invalidParameterException": "The change was not successful, please check your input parameters.",
"warningBoutGenerate": "This action overrides all existing bouts of this match. To edit single bouts, use the bout editing page. Are you sure, you want to continue?",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class TeamMatchOverview extends ConsumerWidget {
showExceptionDialog(
context: context,
exception: Exception('Please select a report provider in the settings'),
stackTrace: null,
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions wrestling_scoreboard_client/lib/view/widgets/consumer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ class SingleConsumer<T extends DataObject> extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (id == null && initialData == null) {
return ExceptionWidget(AppLocalizations.of(context)!.notFoundException);
return ExceptionWidget(AppLocalizations.of(context)!.notFoundException, stackTrace: null);
}
return NullableSingleConsumer(
builder: (BuildContext context, T? data) {
if (data == null) {
return ExceptionWidget(AppLocalizations.of(context)!.notFoundException);
return ExceptionWidget(AppLocalizations.of(context)!.notFoundException, stackTrace: null);
}
return builder(context, data);
},
Expand Down
20 changes: 6 additions & 14 deletions wrestling_scoreboard_client/lib/view/widgets/dialogs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:wrestling_scoreboard_client/services/network/remote/rest.dart';
import 'package:wrestling_scoreboard_client/view/utils.dart';
import 'package:wrestling_scoreboard_client/view/widgets/duration_picker.dart';
import 'package:wrestling_scoreboard_client/view/widgets/exception.dart';

class OkDialog extends StatelessWidget {
final Widget child;
Expand Down Expand Up @@ -80,29 +81,20 @@ Future<T?> showOkCanelDialog<T>({
);
}

Future<void> showExceptionDialog({required BuildContext context, required Object exception}) async {
final localizations = AppLocalizations.of(context)!;
Future<void> showExceptionDialog(
{required BuildContext context, required Object exception, required StackTrace? stackTrace}) async {
await showOkDialog(
context: context,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (exception is RestException) SelectableText(localizations.invalidParameterException),
SelectableText(
exception.toString(),
style: TextStyle(color: Theme.of(context).disabledColor, fontSize: 10),
),
],
),
child: ExceptionInfo(exception, stackTrace: stackTrace),
);
}

Future<void> catchAsync(BuildContext context, Future<void> Function() doAsync) async {
try {
await doAsync();
} catch (exception) {
} catch (exception, stackTrace) {
if (context.mounted) {
showExceptionDialog(context: context, exception: exception);
showExceptionDialog(context: context, exception: exception, stackTrace: stackTrace);
}
}
}
Expand Down
65 changes: 47 additions & 18 deletions wrestling_scoreboard_client/lib/view/widgets/exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,63 @@ import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:wrestling_scoreboard_client/services/network/remote/rest.dart';
import 'package:wrestling_scoreboard_client/view/widgets/card.dart';

class ExceptionWidget extends StatelessWidget {
final Object exception;
final StackTrace? stackTrace;
final Function()? onRetry;

const ExceptionWidget(this.exception, {this.onRetry, super.key});
const ExceptionWidget(this.exception, {this.onRetry, super.key, required this.stackTrace});

@override
Widget build(BuildContext context) {
final errorText = exception is SocketException
? SelectableText(
AppLocalizations.of(context)!.noWebSocketConnection,
)
: SelectableText(exception.toString(), style: TextStyle(color: Theme.of(context).colorScheme.error));
return Center(
child: PaddedCard(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
errorText,
if (onRetry != null) const SizedBox(height: 16),
if (onRetry != null) OutlinedButton(onPressed: onRetry, child: Text(AppLocalizations.of(context)!.retry))
],
),
),
child: PaddedCard(child: ExceptionInfo(exception, stackTrace: stackTrace, onRetry: onRetry)),
);
}
}

class ExceptionInfo extends StatelessWidget {
final Object exception;
final StackTrace? stackTrace;
final Function()? onRetry;

const ExceptionInfo(this.exception, {this.onRetry, super.key, required this.stackTrace});

@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;

String title;
if (exception is RestException) {
title = localizations.invalidParameterException;
} else if (exception is SocketException) {
title = localizations.noWebSocketConnection;
} else {
title = localizations.errorOccurred;
}
final disabledColor = Theme.of(context).disabledColor;

final expansionTile = ExpansionTile(
title: Text(title),
childrenPadding: const EdgeInsets.all(16),
children: [
SelectableText(exception.toString(), style: TextStyle(color: disabledColor, fontSize: 14)),
if (stackTrace != null)
SelectableText(stackTrace!.toString(), style: TextStyle(color: disabledColor, fontSize: 11)),
],
);
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
expansionTile,
if (onRetry != null) const SizedBox(height: 16),
if (onRetry != null) OutlinedButton(onPressed: onRetry, child: Text(AppLocalizations.of(context)!.retry))
],
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class LoadingBuilder<T> extends ConsumerWidget {
future: ref.read(networkTimeoutNotifierProvider).then((timeout) => future.timeout(timeout)),
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
if (snapshot.hasError) {
return ExceptionWidget(snapshot.error!, onRetry: onRetry);
return ExceptionWidget(snapshot.error!, stackTrace: snapshot.stackTrace, onRetry: onRetry);
}
if (initialData != null) {
return builder(context, initialData as T);
Expand Down Expand Up @@ -58,7 +58,7 @@ class LoadingStreamBuilder<T> extends StatelessWidget {
initialData: initialData,
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
if (snapshot.hasError) {
return ExceptionWidget(snapshot.error!, onRetry: onRetry);
return ExceptionWidget(snapshot.error!, onRetry: onRetry, stackTrace: snapshot.stackTrace);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
Expand Down

0 comments on commit c0b1231

Please sign in to comment.