Skip to content

Commit

Permalink
feat: show permission denied message, addressing #2403 (comment)
Browse files Browse the repository at this point in the history
  • Loading branch information
EchoEllet committed Dec 2, 2024
1 parent ef4968d commit 230d8f9
Show file tree
Hide file tree
Showing 47 changed files with 353 additions and 60 deletions.
20 changes: 15 additions & 5 deletions flutter_quill_extensions/lib/src/editor/image/image_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,21 @@ class ImageOptionsMenu extends StatelessWidget {
final localizations = context.loc;
Navigator.of(context).pop();

final result = await imageSaver.saveImage(
imageUrl: imageSource,
imageProvider: imageProvider,
prefersGallerySave: prefersGallerySave,
);
SaveImageResult? result;
try {
result = await imageSaver.saveImage(
imageUrl: imageSource,
imageProvider: imageProvider,
prefersGallerySave: prefersGallerySave,
);
} on GalleryImageSaveAccessDeniedException {
messenger.showSnackBar(SnackBar(
content: Text(
localizations.saveImagePermissionDenied,
)));
return;
}

if (result == null) {
messenger.showSnackBar(SnackBar(
content: Text(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ Future<bool> shouldSaveToGallery({required bool prefersGallerySave}) async {
return supportsGallerySave && prefersGallerySave;
}

/// Thrown when the gallery image save operation is denied
/// due to insufficient or denied permissions.
class GalleryImageSaveAccessDeniedException implements Exception {
GalleryImageSaveAccessDeniedException([this.message]);

final String? message;

@override
String toString() =>
message ?? 'Permission to save the image was denied or insufficient.';
}

ImageSaver _imageSaver = ImageSaver();

ImageSaver get imageSaver => _imageSaver;
Expand All @@ -115,7 +127,8 @@ ImageSaver get imageSaver => _imageSaver;
set imageSaver(ImageSaver value) => _imageSaver = value;

class ImageSaver {
// Returns `null` on failure.
// Returns `null` on failure.
// Throws [GalleryImageSaveAccessDeniedException] in case permission was denied or insuffeicnet.
Future<SaveImageResult?> saveImage({
required String imageUrl,
required ImageProvider imageProvider,
Expand Down Expand Up @@ -192,7 +205,7 @@ class ImageSaver {
rethrow;
}

return null;
throw GalleryImageSaveAccessDeniedException(e.toString());
}
rethrow;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,21 +529,28 @@ void main() {
},
);

test('returns null in case permission is denied', () async {
test(
'throws $GalleryImageSaveAccessDeniedException in case permission is denied',
() async {
await mockShouldSaveToGallery(true);

mockLoadImageBytesValue(Uint8List.fromList([1, 2, 2]));

final platformException = PlatformException(code: 'PERMISSION_DENIED');
when(() => mockQuillNativeBridge.saveImageToGallery(any(),
options: any(named: 'options')))
.thenThrow(PlatformException(code: 'PERMISSION_DENIED'));
options: any(named: 'options'))).thenThrow(platformException);

final result = await imageSaver.saveImage(
imageProvider: FakeImageProvider(),
imageUrl: '/foo/bar',
prefersGallerySave: false,
await expectLater(
imageSaver.saveImage(
imageProvider: FakeImageProvider(),
imageUrl: '/foo/bar',
prefersGallerySave: false,
),
throwsA(
isA<GalleryImageSaveAccessDeniedException>().having(
(e) => e.message, 'message', platformException.toString()),
),
);
expect(result, isNull);
});

test(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ void main() {
),
).thenAnswer((_) async => result);

void mockSaveImageThrows(Exception exception) => when(
() => mockImageSaver.saveImage(
imageUrl: any(named: 'imageUrl'),
imageProvider: any(named: 'imageProvider'),
prefersGallerySave: any(named: 'prefersGallerySave'),
),
).thenThrow(exception);

Future<void> tapTargetWidget(WidgetTester tester) async {
await tester.tap(findTargetWidget());
await tester.pump();
Expand Down Expand Up @@ -100,6 +108,46 @@ void main() {
);
}

testWidgets(
'shows permission denied message only when permission is denied',
(tester) async {
mockSaveImageThrows(GalleryImageSaveAccessDeniedException());

await pumpTargetWidget(tester);
await tapTargetWidget(tester);

final localizations = tester.localizationsFromElement(ImageOptionsMenu);

expect(
find.text(localizations.saveImagePermissionDenied),
findsOneWidget,
);
expect(
find.text(localizations.errorUnexpectedSavingImage),
findsNothing,
);
expect(
find.text(localizations.successImageDownloaded),
findsNothing,
);
expect(
find.text(localizations.successImageSavedGallery),
findsNothing,
);
expect(
find.text(localizations.successImageSaved),
findsNothing,
);
expect(
find.text(localizations.openFileLocation),
findsNothing,
);
expect(
find.text(localizations.openGallery),
findsNothing,
);
});

testWidgets('shows error message when saving fails', (tester) async {
mockSaveImageResult(null);

Expand Down
6 changes: 6 additions & 0 deletions lib/src/l10n/generated/quill_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,12 @@ abstract class FlutterQuillLocalizations {
/// In en, this message translates to:
/// **'Open File Location'**
String get openFileLocation;

/// Message shown when the app is unable to save an image because a required permission was denied or skipped.
///
/// In en, this message translates to:
/// **'Couldn’t save the image due to missing permission.'**
String get saveImagePermissionDenied;
}

class _FlutterQuillLocalizationsDelegate
Expand Down
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_ar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,8 @@ class FlutterQuillLocalizationsAr extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_bg.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,8 @@ class FlutterQuillLocalizationsBg extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_bn.dart
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,8 @@ class FlutterQuillLocalizationsBn extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_ca.dart
Original file line number Diff line number Diff line change
Expand Up @@ -327,4 +327,8 @@ class FlutterQuillLocalizationsCa extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_cs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,8 @@ class FlutterQuillLocalizationsCs extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_da.dart
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,8 @@ class FlutterQuillLocalizationsDa extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,8 @@ class FlutterQuillLocalizationsDe extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_el.dart
Original file line number Diff line number Diff line change
Expand Up @@ -330,4 +330,8 @@ class FlutterQuillLocalizationsEl extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ class FlutterQuillLocalizationsEn extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}

/// The translations for English, as used in the United States (`en_US`).
Expand Down
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_es.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,8 @@ class FlutterQuillLocalizationsEs extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_fa.dart
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,8 @@ class FlutterQuillLocalizationsFa extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_fr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,8 @@ class FlutterQuillLocalizationsFr extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_he.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,8 @@ class FlutterQuillLocalizationsHe extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_hi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,8 @@ class FlutterQuillLocalizationsHi extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_hu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -330,4 +330,8 @@ class FlutterQuillLocalizationsHu extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_id.dart
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,8 @@ class FlutterQuillLocalizationsId extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,8 @@ class FlutterQuillLocalizationsIt extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_ja.dart
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,8 @@ class FlutterQuillLocalizationsJa extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_km.dart
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,8 @@ class FlutterQuillLocalizationsKm extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_ko.dart
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,8 @@ class FlutterQuillLocalizationsKo extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_ku.dart
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ class FlutterQuillLocalizationsKu extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}

/// The translations for Kurdish (`ku_CKB`).
Expand Down
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_ms.dart
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,8 @@ class FlutterQuillLocalizationsMs extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_ne.dart
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,8 @@ class FlutterQuillLocalizationsNe extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
4 changes: 4 additions & 0 deletions lib/src/l10n/generated/quill_localizations_nl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -327,4 +327,8 @@ class FlutterQuillLocalizationsNl extends FlutterQuillLocalizations {

@override
String get openFileLocation => 'Open File Location';

@override
String get saveImagePermissionDenied =>
'Couldn’t save the image due to missing permission.';
}
Loading

0 comments on commit 230d8f9

Please sign in to comment.