Skip to content

Commit b5e8358

Browse files
dialog: Add error haptic feedback to showErrorDialog.
Previously, showErrorDialog provided only visual feedback when displaying an error. This can make error notifications easier to miss on devices that support haptic feedback. Call HapticFeedback.errorNotification() when showing an error dialog so users receive platform-appropriate tactile feedback in addition to the visual dialog. Fixes #2338.
1 parent 01907d8 commit b5e8358

3 files changed

Lines changed: 28 additions & 0 deletions

File tree

lib/widgets/dialog.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:flutter/cupertino.dart';
22
import 'package:flutter/foundation.dart';
33
import 'package:flutter/material.dart';
4+
import 'package:flutter/services.dart';
45

56
import '../generated/l10n/zulip_localizations.dart';
67
import '../model/settings.dart';
@@ -165,6 +166,7 @@ DialogStatus<void> showErrorDialog({
165166
String? message,
166167
Uri? learnMoreButtonUrl,
167168
}) {
169+
HapticFeedback.errorNotification();
168170
final zulipLocalizations = ZulipLocalizations.of(context);
169171
final future = showDialog<void>(
170172
context: context,

test/flutter_checks.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ extension TextEditingValueChecks on Subject<TextEditingValue> {
6262
Subject<TextRange> get composing => has((x) => x.composing, 'composing');
6363
}
6464

65+
extension MethodCallChecks on Subject<MethodCall> {
66+
Subject<String> get method => has((c) => c.method, 'method');
67+
Subject<Object?> get arguments => has((c) => c.arguments as Object?, 'arguments');
68+
}
69+
6570
//|//////////////////////////////////////////////////////////////
6671
// From 'package:flutter/animation.dart'.
6772
//

test/widgets/dialog_test.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import 'package:checks/checks.dart';
22
import 'package:flutter/foundation.dart';
33
import 'package:flutter/material.dart';
4+
import 'package:flutter/services.dart';
45
import 'package:flutter_checks/flutter_checks.dart';
56
import 'package:flutter_test/flutter_test.dart';
67
import 'package:url_launcher/url_launcher.dart';
78
import 'package:zulip/model/settings.dart';
89
import 'package:zulip/widgets/app.dart';
910
import 'package:zulip/widgets/dialog.dart';
1011

12+
import '../flutter_checks.dart';
1113
import '../model/binding.dart';
1214
import 'dialog_checks.dart';
1315
import 'test_app.dart';
@@ -38,6 +40,25 @@ void main() {
3840
checkErrorDialog(tester, expectedTitle: title, expectedMessage: message);
3941
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
4042

43+
testWidgets('triggers error haptic feedback', (tester) async {
44+
await prepare(tester);
45+
46+
final calls = <MethodCall>[];
47+
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
48+
SystemChannels.platform,
49+
(methodCall) async {
50+
calls.add(methodCall);
51+
return null;
52+
});
53+
54+
showErrorDialog(context: context, title: title, message: message);
55+
await tester.pump();
56+
57+
check(calls).single
58+
..method.equals('HapticFeedback.vibrate')
59+
..arguments.equals('HapticFeedbackType.errorNotification');
60+
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
61+
4162
testWidgets('user closes error dialog', (tester) async {
4263
await prepare(tester);
4364

0 commit comments

Comments
 (0)