Skip to content

Commit 36c2b4d

Browse files
gnpricePIG208
authored andcommitted
log: Support reportErrorToUser* helpers.
The imports in `lib/log.dart` are for the code references in the reportErrorToUser* helpers' dart doc.
1 parent 8813a76 commit 36c2b4d

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

lib/log.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'package:flutter/material.dart';
2+
3+
import 'widgets/app.dart';
14

25
/// Whether [debugLog] should do anything.
36
///
@@ -30,3 +33,45 @@ bool debugLog(String message) {
3033
}());
3134
return true;
3235
}
36+
37+
/// Display an error message.
38+
///
39+
/// This shows a [SnackBar] containing the message after app startup,
40+
/// otherwise logs it to the console.
41+
///
42+
/// See also: [ZulipApp._reportErrorToUserBriefly]
43+
void Function(String message) get reportErrorToUserBriefly => (message) {
44+
_debugLastReportedError = message;
45+
_reportErrorToUserBriefly(message);
46+
};
47+
void Function(String message) _reportErrorToUserBriefly = _defaultReportErrorToUser;
48+
set reportErrorToUserBriefly(void Function(String message) value) => _reportErrorToUserBriefly = value;
49+
50+
/// Display an error message in a dialog.
51+
///
52+
/// This shows a dialog containing the message after app startup,
53+
/// otherwise logs it to the console.
54+
///
55+
/// See also: [ZulipApp._reportErrorToUserInDialog]
56+
void Function(String message) get reportErrorToUserInDialog => (message) {
57+
_debugLastReportedError = message;
58+
_reportErrorToUserInDialog(message);
59+
};
60+
void Function(String message) _reportErrorToUserInDialog = _defaultReportErrorToUser;
61+
set reportErrorToUserInDialog(void Function(String message) value) => _reportErrorToUserInDialog = value;
62+
63+
String? get debugLastReportedError => _debugLastReportedError;
64+
String? _debugLastReportedError;
65+
String? takeLastReportedError() {
66+
final result = _debugLastReportedError;
67+
_debugLastReportedError = null;
68+
return result;
69+
}
70+
71+
void _defaultReportErrorToUser(String message) {
72+
// If this callback is still in place, then the app's widget tree
73+
// hasn't mounted yet even as far as the [Navigator].
74+
// So there's not much we can do to tell the user;
75+
// just log, in case the user is actually a developer watching the console.
76+
assert(debugLog(message));
77+
}

lib/widgets/app.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import 'package:flutter/material.dart';
55
import 'package:flutter/scheduler.dart';
66
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart';
77

8+
import '../log.dart';
89
import '../model/localizations.dart';
910
import '../model/narrow.dart';
1011
import 'about_zulip.dart';
1112
import 'app_bar.dart';
13+
import 'dialog.dart';
1214
import 'inbox.dart';
1315
import 'login.dart';
1416
import 'message_list.dart';
@@ -92,9 +94,21 @@ class ZulipApp extends StatefulWidget {
9294
/// Useful in tests.
9395
final List<NavigatorObserver>? navigatorObservers;
9496

97+
static void _reportErrorToUserBriefly(String message) {
98+
scaffoldMessenger?.showSnackBar(SnackBar(content: Text(message)));
99+
}
100+
101+
static void _reportErrorToUserInDialog(String message) {
102+
final context = navigatorKey.currentContext;
103+
if (context == null) return;
104+
showErrorDialog(context: context, title: 'Error', message: message);
105+
}
106+
95107
void _declareReady() {
96108
assert(navigatorKey.currentContext != null);
97109
_ready.value = true;
110+
reportErrorToUserBriefly = _reportErrorToUserBriefly;
111+
reportErrorToUserInDialog = _reportErrorToUserInDialog;
98112
}
99113

100114
@override

test/widgets/app_test.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:checks/checks.dart';
22
import 'package:flutter/material.dart';
33
import 'package:flutter_test/flutter_test.dart';
4+
import 'package:zulip/log.dart';
45
import 'package:zulip/model/database.dart';
56
import 'package:zulip/widgets/app.dart';
67
import 'package:zulip/widgets/inbox.dart';
@@ -166,5 +167,49 @@ void main() {
166167
check(ZulipApp.scaffoldMessenger).isNotNull();
167168
check(ZulipApp.ready).value.isTrue();
168169
});
170+
171+
testWidgets('reportErrorToUserBriefly shows snack bar', (tester) async {
172+
addTearDown(testBinding.reset);
173+
await tester.pumpWidget(const ZulipApp());
174+
175+
final finder = find.descendant(
176+
of: find.byType(SnackBar),
177+
matching: find.text('test error message'));
178+
179+
// Prior to app startup, reportErrorToUserBriefly only logs.
180+
reportErrorToUserBriefly('test error message');
181+
check(ZulipApp.ready).value.isFalse();
182+
await tester.pump();
183+
check(takeLastReportedError()).equals('test error message');
184+
check(finder.evaluate()).isEmpty();
185+
186+
check(ZulipApp.ready).value.isTrue();
187+
// After app startup, reportErrorToUserBriefly displays a snack bar.
188+
reportErrorToUserBriefly('test error message');
189+
await tester.pump();
190+
check(finder.evaluate()).single;
191+
});
192+
193+
testWidgets('reportErrorToUserInDialog shows dialog', (tester) async {
194+
addTearDown(testBinding.reset);
195+
await tester.pumpWidget(const ZulipApp());
196+
197+
final finder = find.descendant(
198+
of: find.byType(AlertDialog),
199+
matching: find.text('test error message'));
200+
201+
// Prior to app startup, reportErrorToUserInDialog only logs.
202+
reportErrorToUserInDialog('test error message');
203+
check(ZulipApp.ready).value.isFalse();
204+
await tester.pump();
205+
check(takeLastReportedError()).equals('test error message');
206+
check(finder.evaluate()).isEmpty();
207+
208+
check(ZulipApp.ready).value.isTrue();
209+
// After app startup, reportErrorToUserInDialog displays a dialog.
210+
reportErrorToUserInDialog('test error message');
211+
await tester.pump();
212+
check(finder.evaluate()).single;
213+
});
169214
});
170215
}

0 commit comments

Comments
 (0)