aves/lib/widgets/common/action_delegates/permission_aware.dart
2020-07-05 16:18:53 +09:00

59 lines
2.3 KiB
Dart

import 'package:aves/model/image_entry.dart';
import 'package:aves/services/android_file_service.dart';
import 'package:aves/utils/android_file_utils.dart';
import 'package:flutter/material.dart';
import 'package:tuple/tuple.dart';
mixin PermissionAwareMixin {
Future<bool> checkStoragePermission(BuildContext context, Iterable<ImageEntry> entries) {
return checkStoragePermissionForPaths(context, entries.where((e) => e.path != null).map((e) => e.path));
}
Future<bool> checkStoragePermissionForPaths(BuildContext context, Iterable<String> paths) async {
final volumes = paths.map(androidFileUtils.getStorageVolume).toSet();
final ungrantedVolumes = (await Future.wait<Tuple2<StorageVolume, bool>>(
volumes.map(
(volume) => AndroidFileService.requireVolumeAccessDialog(volume.path).then(
(granted) => Tuple2(volume, granted),
),
),
))
.where((t) => t.item2)
.map((t) => t.item1)
.toList();
while (ungrantedVolumes.isNotEmpty) {
final volume = ungrantedVolumes.first;
final confirmed = await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Storage Volume Access'),
content: Text('Please select the root directory of “${volume.description}” in the next screen, so that this app can access it and complete your request.'),
actions: [
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel'.toUpperCase()),
),
FlatButton(
onPressed: () => Navigator.pop(context, true),
child: Text('OK'.toUpperCase()),
),
],
);
},
);
// abort if the user cancels in Flutter
if (confirmed == null || !confirmed) return false;
final granted = await AndroidFileService.requestVolumeAccess(volume.path);
debugPrint('$runtimeType _checkStoragePermission with volume=${volume.path} got granted=$granted');
if (granted) {
ungrantedVolumes.remove(volume);
} else {
// abort if the user denies access from the native dialog
return false;
}
}
return true;
}
}