diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index ed7067fc6..dd5e3e29b 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -55,11 +55,22 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -77,7 +88,7 @@
-
sharedEntryMap;
+ private Map intentDataMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -60,23 +60,47 @@ public class MainActivity extends FlutterActivity {
new MethodChannel(messenger, VIEWER_CHANNEL).setMethodCallHandler(
(call, result) -> {
- if (call.method.contentEquals("getSharedEntry")) {
- result.success(sharedEntryMap);
- sharedEntryMap = null;
+ if (call.method.contentEquals("getIntentData")) {
+ result.success(intentDataMap);
+ intentDataMap = null;
+ } else if (call.method.contentEquals("pick")) {
+ result.success(intentDataMap);
+ intentDataMap = null;
+ String resultUri = call.argument("uri");
+ if (resultUri != null) {
+ Intent data = new Intent();
+ data.setData(Uri.parse(resultUri));
+ setResult(RESULT_OK, data);
+ finish();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
}
});
}
private void handleIntent(Intent intent) {
Log.i(LOG_TAG, "handleIntent intent=" + intent);
- if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
- Uri uri = intent.getData();
- String mimeType = intent.getType();
- if (uri != null && mimeType != null) {
- sharedEntryMap = new HashMap<>();
- sharedEntryMap.put("uri", uri.toString());
- sharedEntryMap.put("mimeType", mimeType);
- }
+ if (intent == null) return;
+ String action = intent.getAction();
+ if (action == null) return;
+ switch (action) {
+ case Intent.ACTION_VIEW:
+ Uri uri = intent.getData();
+ String mimeType = intent.getType();
+ if (uri != null && mimeType != null) {
+ intentDataMap = new HashMap<>();
+ intentDataMap.put("action", "view");
+ intentDataMap.put("uri", uri.toString());
+ intentDataMap.put("mimeType", mimeType);
+ }
+ break;
+ case Intent.ACTION_GET_CONTENT:
+ case Intent.ACTION_PICK:
+ intentDataMap = new HashMap<>();
+ intentDataMap.put("action", "pick");
+ break;
}
}
diff --git a/lib/main.dart b/lib/main.dart
index 4a1a963da..0ff76ab3d 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -20,7 +20,11 @@ void main() {
runApp(AvesApp());
}
+enum AppMode { main, pick, view }
+
class AvesApp extends StatelessWidget {
+ static AppMode mode = AppMode.main;
+
@override
Widget build(BuildContext context) {
return MaterialApp(
@@ -56,7 +60,7 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State {
MediaStoreSource _mediaStore;
- ImageEntry _sharedEntry;
+ ImageEntry _viewerEntry;
Future _appSetup;
@override
@@ -87,18 +91,36 @@ class _HomePageState extends State {
await settings.init(); // <20ms
- final sharedExtra = await ViewerService.getSharedEntry();
- if (sharedExtra != null) {
- _sharedEntry = await ImageFileService.getImageEntry(sharedExtra['uri'], sharedExtra['mimeType']);
- // cataloging is essential for geolocation and video rotation
- await _sharedEntry.catalog();
- unawaited(_sharedEntry.locate());
- } else {
+ final intentData = await ViewerService.getIntentData();
+ if (intentData != null) {
+ final action = intentData['action'];
+ switch (action) {
+ case 'view':
+ AvesApp.mode = AppMode.view;
+ await _initViewerEntry(
+ uri: intentData['uri'],
+ mimeType: intentData['mimeType'],
+ );
+ break;
+ case 'pick':
+ AvesApp.mode = AppMode.pick;
+ break;
+ }
+ }
+
+ if (AvesApp.mode != AppMode.view) {
_mediaStore = MediaStoreSource();
unawaited(_mediaStore.fetch());
}
}
+ Future _initViewerEntry({@required String uri, @required String mimeType}) async {
+ _viewerEntry = await ImageFileService.getImageEntry(uri, mimeType);
+ // cataloging is essential for geolocation and video rotation
+ await _viewerEntry.catalog();
+ unawaited(_viewerEntry.locate());
+ }
+
@override
Widget build(BuildContext context) {
return FutureBuilder(
@@ -107,8 +129,8 @@ class _HomePageState extends State {
if (snapshot.hasError) return const Icon(AIcons.error);
if (snapshot.connectionState != ConnectionState.done) return const SizedBox.shrink();
debugPrint('$runtimeType app setup future complete');
- if (_sharedEntry != null) {
- return SingleFullscreenPage(entry: _sharedEntry);
+ if (AvesApp.mode == AppMode.view) {
+ return SingleFullscreenPage(entry: _viewerEntry);
}
if (_mediaStore != null) {
return CollectionPage(CollectionLens(
diff --git a/lib/model/filters/album.dart b/lib/model/filters/album.dart
index 07d9a0ce5..c9a638fca 100644
--- a/lib/model/filters/album.dart
+++ b/lib/model/filters/album.dart
@@ -37,7 +37,7 @@ class AlbumFilter extends CollectionFilter {
Future color(BuildContext context) {
// do not use async/await and rely on `SynchronousFuture`
// to prevent rebuilding of the `FutureBuilder` listening on this future
- if (androidFileUtils.getAlbumType(album) == AlbumType.App) {
+ if (androidFileUtils.getAlbumType(album) == AlbumType.app) {
if (_appColors.containsKey(album)) return SynchronousFuture(_appColors[album]);
return PaletteGenerator.fromImageProvider(
diff --git a/lib/services/viewer_service.dart b/lib/services/viewer_service.dart
index cbaab3a26..175874e6d 100644
--- a/lib/services/viewer_service.dart
+++ b/lib/services/viewer_service.dart
@@ -4,13 +4,23 @@ import 'package:flutter/services.dart';
class ViewerService {
static const platform = MethodChannel('deckers.thibault/aves/viewer');
- static Future