Skip to content
This repository has been archived by the owner on Nov 7, 2023. It is now read-only.

Commit

Permalink
fix(home_page): prevent infinite by catching errors
Browse files Browse the repository at this point in the history
  • Loading branch information
zyrouge committed Nov 14, 2021
1 parent 5357844 commit a62829b
Show file tree
Hide file tree
Showing 4 changed files with 516 additions and 327 deletions.
192 changes: 124 additions & 68 deletions lib/ui/components/error_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,39 @@ import '../../modules/helpers/ui.dart';
import '../../modules/translator/translator.dart';
import '../../modules/utils/utils.dart';

typedef ActionsBuilder = List<InlineSpan> Function(
BuildContext,
List<InlineSpan>,
);

class KawaiiErrorWidget extends StatelessWidget {
const KawaiiErrorWidget({
final this.showFace = true,
final this.child,
final this.message,
final this.error,
final this.stack,
final this.actions,
final this.actionsBuilder,
final Key? key,
}) : assert(
(child == null && message != null) ||
(child != null && message == null),
),
assert(
(actionsBuilder == null && actions == null) ||
(actionsBuilder == null && actions != null) ||
(actionsBuilder != null && actions == null),
),
super(key: key);

factory KawaiiErrorWidget.fromErrorInfo({
final bool showFace = true,
final Widget? child,
final String? message,
final ErrorInfo? error,
final List<InlineSpan>? actions,
final ActionsBuilder? actionsBuilder,
final Key? key,
}) =>
KawaiiErrorWidget(
Expand All @@ -32,6 +46,8 @@ class KawaiiErrorWidget extends StatelessWidget {
message: message,
error: error?.error,
stack: error?.stack,
actions: actions,
actionsBuilder: actionsBuilder,
child: child,
);

Expand All @@ -40,6 +56,37 @@ class KawaiiErrorWidget extends StatelessWidget {
final String? message;
final Object? error;
final StackTrace? stack;
final List<InlineSpan>? actions;
final ActionsBuilder? actionsBuilder;

InlineSpan buildCopyError(final BuildContext context) => buildActionButton(
context: context,
icon: const Icon(Icons.content_paste),
child: Text(Translator.t.copyError()),
onTap: () async {
FlutterClipboard.copy(
<String>[
'Message: $message',
if (error != null) 'Error: $error',
if (stack != null) 'Stack trace:\n$stack',
].join('\n'),
);

FunctionUtils.withValue(
context,
(final BuildContext context) =>
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
Translator.t.copiedErrorToClipboard(),
style: Theme.of(context).textTheme.bodyText1,
),
backgroundColor: Theme.of(context).cardColor,
),
),
);
},
);

@override
Widget build(final BuildContext context) => RichText(
Expand All @@ -64,95 +111,104 @@ class KawaiiErrorWidget extends StatelessWidget {
text: '$message\n',
style: Theme.of(context).textTheme.bodyText1,
),
if (error != null) ...<InlineSpan>[
if (error != null ||
actions != null ||
actionsBuilder != null) ...<InlineSpan>[
WidgetSpan(
child: Padding(
padding: EdgeInsets.only(bottom: remToPx(0.1)),
child: const Text(''),
),
),
TextSpan(
text: '$error\n',
text: '${error.toString().trim()}\n',
style: Theme.of(context).textTheme.bodyText1?.copyWith(
color: Colors.red,
),
),
WidgetSpan(
child: Padding(
padding: EdgeInsets.only(bottom: remToPx(0.3)),
padding: EdgeInsets.only(bottom: remToPx(0.5)),
child: const Text(''),
),
),
WidgetSpan(
child: Material(
color: Colors.red,
type: MaterialType.transparency,
child: InkWell(
borderRadius: BorderRadius.circular(remToPx(0.2)),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: remToPx(0.3),
vertical: remToPx(0.1),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.content_paste,
size:
Theme.of(context).textTheme.bodyText1?.fontSize,
color: Theme.of(context)
.textTheme
.bodyText1
?.color
?.withOpacity(0.7),
),
SizedBox(
width: remToPx(0.3),
),
Text(
Translator.t.copyError(),
style:
Theme.of(context).textTheme.bodyText2?.copyWith(
color: Theme.of(context)
.textTheme
.bodyText1
?.color
?.withOpacity(0.8),
),
),
],
),
),
onTap: () async {
FlutterClipboard.copy(
<String>[
'Message: $message',
if (error != null) 'Error: $error',
if (stack != null) 'Stack trace:\n$stack',
].join('\n'),
);

FunctionUtils.withValue(
context,
(final BuildContext context) =>
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
Translator.t.copiedErrorToClipboard(),
style: Theme.of(context).textTheme.bodyText1,
),
backgroundColor: Theme.of(context).cardColor,
),
),
);
},
...ListUtils.insertBetween(
<InlineSpan>[
if (actions != null) ...actions!,
if (actionsBuilder != null)
...actionsBuilder!(
context,
<InlineSpan>[
buildCopyError(context),
],
)
else
buildCopyError(context),
],
WidgetSpan(
child: SizedBox(
width: remToPx(0.3),
),
),
),
],
],
),
);

static InlineSpan buildActionButton({
required final BuildContext context,
required final Widget child,
required final void Function() onTap,
final Widget? icon,
final Color color = Colors.red,
}) =>
WidgetSpan(
child: Material(
color: color,
type: MaterialType.button,
child: InkWell(
borderRadius: BorderRadius.circular(remToPx(0.2)),
onTap: onTap,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: remToPx(0.3),
vertical: remToPx(0.1),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (icon != null) ...<Widget>[
IconTheme(
data: IconThemeData(
color: Theme.of(context)
.textTheme
.bodyText1
?.color
?.withOpacity(0.7),
size: Theme.of(context).textTheme.bodyText1?.fontSize,
),
child: icon,
),
SizedBox(
width: remToPx(0.3),
),
],
DefaultTextStyle(
style: Theme.of(context).textTheme.bodyText2!.copyWith(
color: Theme.of(context)
.textTheme
.bodyText1
?.color
?.withOpacity(0.8),
),
child: child,
),
],
),
),
),
),
);
}

0 comments on commit a62829b

Please sign in to comment.