Skip to content

Commit

Permalink
action_sheet: Have "Share" button give feedback on sharing failure
Browse files Browse the repository at this point in the history
Or at least, on `ShareResultStatus.unavailable`, which the plugin
just defines as "The status can not be determined".
  • Loading branch information
chrisbobbe committed Oct 27, 2023
1 parent f2a847a commit f014ba8
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 7 deletions.
4 changes: 4 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@
"message": {"type": "String", "example": "Invalid format"}
}
},
"errorSharingFailed": "Sharing failed",
"@errorSharingFailed": {
"description": "Error message when sharing a message failed."
},
"successLinkCopied": "Link copied",
"@successLinkCopied": {
"description": "Success message after copy link action completed."
Expand Down
23 changes: 18 additions & 5 deletions lib/widgets/action_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,20 @@ class ShareButton extends MessageActionSheetMenuItemButton {

@override get onPressed => (BuildContext context) async {
// Close the message action sheet; we're about to show the share
// sheet. (We could do this after the sharing Future settles, but
// on iOS I get impatient with how slowly our action sheet
// dismisses in that case.)
// sheet. (We could do this after the sharing Future settles
// with [ShareResultStatus.success], but on iOS I get impatient with
// how slowly our action sheet dismisses in that case.)
// TODO(#24): Fix iOS bug where this call causes the keyboard to
// reopen (if it was open at the time of this
// `showMessageActionSheet` call) and cover a large part of the
// share sheet.
Navigator.of(context).pop();
final zulipLocalizations = ZulipLocalizations.of(messageListContext);

final rawContent = await fetchRawContentWithFeedback(
context: messageListContext,
messageId: message.id,
errorDialogTitle: 'Sharing failed',
errorDialogTitle: zulipLocalizations.errorSharingFailed,
);

if (rawContent == null) return;
Expand All @@ -100,7 +101,19 @@ class ShareButton extends MessageActionSheetMenuItemButton {
// https://pub.dev/packages/share_plus#ipad
// Perhaps a wart in the API; discussion:
// https://github.com/zulip/zulip-flutter/pull/12#discussion_r1130146231
await Share.shareWithResult(rawContent);
final result = await Share.shareWithResult(rawContent);

switch (result.status) {
// The plugin isn't very helpful: "The status can not be determined".
// Until we learn otherwise, assume something wrong happened.
case ShareResultStatus.unavailable:
if (!messageListContext.mounted) return;
await showErrorDialog(context: messageListContext,
title: zulipLocalizations.errorSharingFailed);
case ShareResultStatus.success:
case ShareResultStatus.dismissed:
// nothing to do
}
};
}

Expand Down
6 changes: 5 additions & 1 deletion test/test_share_plus.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import 'package:flutter/services.dart';
import 'package:share_plus/share_plus.dart';

class MockSharePlus {
MockSharePlus();

/// The mock [ShareResult.raw] that `shareWithResult` should give.
String resultString = 'some-success-response';

/// The last string that `shareWithResult` was called with.
String? sharedString;

Expand All @@ -13,7 +17,7 @@ class MockSharePlus {
// `arguments`'s type; logging runtimeType gives _Map<Object?, Object?>.
final arguments = methodCall.arguments as Map;
sharedString = arguments['text'] as String;
return 'some-success-response';
return resultString;
default:
throw UnimplementedError();
}
Expand Down
18 changes: 17 additions & 1 deletion test/widgets/action_sheet_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ void main() {
await tester.pump(); // [MenuItemButton.onPressed] called in a post-frame callback: flutter/flutter@e4a39fa2e
}

testWidgets('success', (WidgetTester tester) async {
testWidgets('request succeeds; sharing succeeds', (WidgetTester tester) async {
final mockSharePlus = setupMockSharePlus();
final message = eg.streamMessage();
await setupToMessageActionSheet(tester, message: message, narrow: TopicNarrow.ofMessage(message));
Expand All @@ -128,6 +128,22 @@ void main() {
check(mockSharePlus.sharedString).equals('Hello world');
});

testWidgets('request succeeds; sharing fails', (WidgetTester tester) async {
final mockSharePlus = setupMockSharePlus();
final message = eg.streamMessage();
await setupToMessageActionSheet(tester, message: message, narrow: TopicNarrow.ofMessage(message));
final store = await TestZulipBinding.instance.globalStore.perAccount(eg.selfAccount.id);

prepareRawContentResponseSuccess(store, message: message, rawContent: 'Hello world');
mockSharePlus.resultString = 'dev.fluttercommunity.plus/share/unavailable';
await tapShareButton(tester);
await tester.pump(Duration.zero);
check(mockSharePlus.sharedString).equals('Hello world');
await tester.pump();
await tester.tap(find.byWidget(checkErrorDialog(tester,
expectedTitle: 'Sharing failed')));
});

testWidgets('request has an error', (WidgetTester tester) async {
final mockSharePlus = setupMockSharePlus();
final message = eg.streamMessage();
Expand Down

0 comments on commit f014ba8

Please sign in to comment.