From 28e053cdd68e265c4090f203bccd4549627021f6 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 14 Apr 2020 21:01:36 +0900 Subject: [PATCH] native call priority management --- lib/main.dart | 4 +- lib/model/image_entry.dart | 11 +++- .../android_app_service.dart | 0 .../android_file_service.dart | 0 .../image_file_service.dart | 35 ++++++----- lib/{model => services}/metadata_service.dart | 47 ++++++++------- lib/services/service_policy.dart | 58 +++++++++++++++++++ lib/{utils => services}/viewer_service.dart | 0 lib/utils/android_file_utils.dart | 4 +- .../album/grid/list_section_layout.dart | 3 +- .../album/grid/tile_extent_manager.dart | 4 ++ .../media_store_collection_provider.dart | 2 +- .../app_icon_image_provider.dart | 2 +- .../image_providers/thumbnail_provider.dart | 2 +- .../image_providers/uri_image_provider.dart | 2 +- .../image_providers/uri_picture_provider.dart | 2 +- .../fullscreen_action_delegate.dart | 4 +- .../fullscreen/info/location_section.dart | 2 +- .../fullscreen/info/metadata_section.dart | 2 +- lib/widgets/fullscreen/overlay/bottom.dart | 2 +- lib/widgets/fullscreen/overlay/video.dart | 2 +- 21 files changed, 135 insertions(+), 53 deletions(-) rename lib/{utils => services}/android_app_service.dart (100%) rename lib/{utils => services}/android_file_service.dart (100%) rename lib/{model => services}/image_file_service.dart (82%) rename lib/{model => services}/metadata_service.dart (58%) create mode 100644 lib/services/service_policy.dart rename lib/{utils => services}/viewer_service.dart (100%) diff --git a/lib/main.dart b/lib/main.dart index 2f59bd02f..d1e119baa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,8 @@ import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/image_file_service.dart'; import 'package:aves/model/settings.dart'; +import 'package:aves/services/image_file_service.dart'; +import 'package:aves/services/viewer_service.dart'; import 'package:aves/utils/android_file_utils.dart'; -import 'package:aves/utils/viewer_service.dart'; import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart'; import 'package:aves/widgets/fullscreen/fullscreen_page.dart'; diff --git a/lib/model/image_entry.dart b/lib/model/image_entry.dart index bb8e17991..7074512c1 100644 --- a/lib/model/image_entry.dart +++ b/lib/model/image_entry.dart @@ -1,7 +1,8 @@ import 'package:aves/model/favourite_repo.dart'; -import 'package:aves/model/image_file_service.dart'; import 'package:aves/model/image_metadata.dart'; -import 'package:aves/model/metadata_service.dart'; +import 'package:aves/services/image_file_service.dart'; +import 'package:aves/services/metadata_service.dart'; +import 'package:aves/services/service_policy.dart'; import 'package:aves/utils/change_notifier.dart'; import 'package:aves/utils/time_utils.dart'; import 'package:flutter/foundation.dart'; @@ -220,7 +221,11 @@ class ImageEntry { final coordinates = Coordinates(latitude, longitude); try { - final addresses = await Geocoder.local.findAddressesFromCoordinates(coordinates); + final addresses = await servicePolicy.call( + () => Geocoder.local.findAddressesFromCoordinates(coordinates), + ServiceCallPriority.background, + 'findAddressesFromCoordinates-$path', + ); if (addresses != null && addresses.isNotEmpty) { final address = addresses.first; addressDetails = AddressDetails( diff --git a/lib/utils/android_app_service.dart b/lib/services/android_app_service.dart similarity index 100% rename from lib/utils/android_app_service.dart rename to lib/services/android_app_service.dart diff --git a/lib/utils/android_file_service.dart b/lib/services/android_file_service.dart similarity index 100% rename from lib/utils/android_file_service.dart rename to lib/services/android_file_service.dart diff --git a/lib/model/image_file_service.dart b/lib/services/image_file_service.dart similarity index 82% rename from lib/model/image_file_service.dart rename to lib/services/image_file_service.dart index 41f528b2b..65cf15e2f 100644 --- a/lib/model/image_file_service.dart +++ b/lib/services/image_file_service.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; import 'package:aves/model/image_entry.dart'; +import 'package:aves/services/service_policy.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -42,21 +43,27 @@ class ImageFileService { return Uint8List(0); } - static Future getThumbnail(ImageEntry entry, int width, int height) async { - if (width > 0 && height > 0) { + static Future getThumbnail(ImageEntry entry, int width, int height) { + return servicePolicy.call( + () async { + if (width > 0 && height > 0) { // debugPrint('getThumbnail width=$width path=${entry.path}'); - try { - final result = await platform.invokeMethod('getThumbnail', { - 'entry': entry.toMap(), - 'width': width, - 'height': height, - }); - return result as Uint8List; - } on PlatformException catch (e) { - debugPrint('getThumbnail failed with code=${e.code}, exception=${e.message}, details=${e.details}'); - } - } - return Uint8List(0); + try { + final result = await platform.invokeMethod('getThumbnail', { + 'entry': entry.toMap(), + 'width': width, + 'height': height, + }); + return result as Uint8List; + } on PlatformException catch (e) { + debugPrint('getThumbnail failed with code=${e.code}, exception=${e.message}, details=${e.details}'); + } + } + return Uint8List(0); + }, + ServiceCallPriority.asapLifo, + 'getThumbnail-${entry.path}', + ); } static Future cancelGetThumbnail(String uri) async { diff --git a/lib/model/metadata_service.dart b/lib/services/metadata_service.dart similarity index 58% rename from lib/model/metadata_service.dart rename to lib/services/metadata_service.dart index bc6923353..9a4f6b223 100644 --- a/lib/model/metadata_service.dart +++ b/lib/services/metadata_service.dart @@ -1,5 +1,6 @@ import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_metadata.dart'; +import 'package:aves/services/service_policy.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -26,26 +27,32 @@ class MetadataService { static Future getCatalogMetadata(ImageEntry entry) async { if (entry.isSvg) return null; - try { - // return map with: - // 'dateMillis': date taken in milliseconds since Epoch (long) - // 'isAnimated': animated gif/webp (bool) - // 'latitude': latitude (double) - // 'longitude': longitude (double) - // 'videoRotation': video rotation degrees (int) - // 'xmpSubjects': ';' separated XMP subjects (string) - // 'xmpTitleDescription': XMP title or XMP description (string) - final result = await platform.invokeMethod('getCatalogMetadata', { - 'mimeType': entry.mimeType, - 'path': entry.path, - 'uri': entry.uri, - }) as Map; - result['contentId'] = entry.contentId; - return CatalogMetadata.fromMap(result); - } on PlatformException catch (e) { - debugPrint('getCatalogMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}'); - } - return null; + return servicePolicy.call( + () async { + try { + // return map with: + // 'dateMillis': date taken in milliseconds since Epoch (long) + // 'isAnimated': animated gif/webp (bool) + // 'latitude': latitude (double) + // 'longitude': longitude (double) + // 'videoRotation': video rotation degrees (int) + // 'xmpSubjects': ';' separated XMP subjects (string) + // 'xmpTitleDescription': XMP title or XMP description (string) + final result = await platform.invokeMethod('getCatalogMetadata', { + 'mimeType': entry.mimeType, + 'path': entry.path, + 'uri': entry.uri, + }) as Map; + result['contentId'] = entry.contentId; + return CatalogMetadata.fromMap(result); + } on PlatformException catch (e) { + debugPrint('getCatalogMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}'); + } + return null; + }, + ServiceCallPriority.background, + 'getCatalogMetadata-${entry.path}', + ); } static Future getOverlayMetadata(ImageEntry entry) async { diff --git a/lib/services/service_policy.dart b/lib/services/service_policy.dart new file mode 100644 index 000000000..dfa7e215e --- /dev/null +++ b/lib/services/service_policy.dart @@ -0,0 +1,58 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:flutter/cupertino.dart'; + +final ServicePolicy servicePolicy = ServicePolicy._private(); + +class ServicePolicy { + final Queue _asapQueue = Queue(), _normalQueue = Queue(), _backgroundQueue = Queue(); + VoidCallback _running; + + ServicePolicy._private(); + + Future call(Future Function() platformCall, [ServiceCallPriority priority = ServiceCallPriority.normal, String debugLabel]) { + Queue q; + switch (priority) { + case ServiceCallPriority.asapFifo: + q = _asapQueue; + break; + case ServiceCallPriority.asapLifo: + q = _asapQueue; + break; + case ServiceCallPriority.background: + q = _backgroundQueue; + break; + case ServiceCallPriority.normal: + default: + q = _normalQueue; + break; + } + final completer = Completer(); + final wrapped = () async { +// if (debugLabel != null) debugPrint('$runtimeType $debugLabel start'); + final result = await platformCall(); + completer.complete(result); +// if (debugLabel != null) debugPrint('$runtimeType $debugLabel completed'); + _running = null; + _pickNext(); + }; + if (priority == ServiceCallPriority.asapLifo) { + q.addFirst(wrapped); + } else { + q.addLast(wrapped); + } + + _pickNext(); + return completer.future; + } + + void _pickNext() { + if (_running != null) return; + final queue = [_asapQueue, _normalQueue, _backgroundQueue].firstWhere((q) => q.isNotEmpty, orElse: () => null); + _running = queue?.removeFirst(); + _running?.call(); + } +} + +enum ServiceCallPriority { asapFifo, asapLifo, normal, background } diff --git a/lib/utils/viewer_service.dart b/lib/services/viewer_service.dart similarity index 100% rename from lib/utils/viewer_service.dart rename to lib/services/viewer_service.dart diff --git a/lib/utils/android_file_utils.dart b/lib/utils/android_file_utils.dart index 9b2f6a8bf..c94cb7149 100644 --- a/lib/utils/android_file_utils.dart +++ b/lib/utils/android_file_utils.dart @@ -1,5 +1,5 @@ -import 'package:aves/utils/android_app_service.dart'; -import 'package:aves/utils/android_file_service.dart'; +import 'package:aves/services/android_app_service.dart'; +import 'package:aves/services/android_file_service.dart'; import 'package:path/path.dart'; final AndroidFileUtils androidFileUtils = AndroidFileUtils._private(); diff --git a/lib/widgets/album/grid/list_section_layout.dart b/lib/widgets/album/grid/list_section_layout.dart index 5e5d8aaaa..5037e8e9d 100644 --- a/lib/widgets/album/grid/list_section_layout.dart +++ b/lib/widgets/album/grid/list_section_layout.dart @@ -4,6 +4,7 @@ import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/widgets/album/grid/header_generic.dart'; import 'package:aves/widgets/album/grid/list_sliver.dart'; +import 'package:aves/widgets/album/grid/tile_extent_manager.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -19,7 +20,7 @@ class SectionedListLayoutProvider extends StatelessWidget { @required this.scrollableWidth, @required this.tileExtent, @required this.child, - }) : columnCount = (scrollableWidth / tileExtent).round(); + }) : columnCount = max((scrollableWidth / tileExtent).round(), TileExtentManager.columnCountMin); @override Widget build(BuildContext context) { diff --git a/lib/widgets/album/grid/tile_extent_manager.dart b/lib/widgets/album/grid/tile_extent_manager.dart index cc6fbefc8..ff85ac095 100644 --- a/lib/widgets/album/grid/tile_extent_manager.dart +++ b/lib/widgets/album/grid/tile_extent_manager.dart @@ -7,8 +7,12 @@ class TileExtentManager { static const int columnCountMin = 2; static const int columnCountDefault = 4; static const double tileExtentMin = 46.0; + static const screenDimensionMin = tileExtentMin * columnCountMin; static double applyTileExtent(Size mqSize, double mqHorizontalPadding, ValueNotifier extentNotifier, {double newExtent}) { + // sanitize screen size (useful when reloading while screen is off, reporting a 0,0 size) + mqSize = Size(max(mqSize.width, screenDimensionMin), max(mqSize.height, screenDimensionMin)); + final availableWidth = mqSize.width - mqHorizontalPadding; var numColumns; if ((newExtent ?? 0) == 0) { diff --git a/lib/widgets/common/data_providers/media_store_collection_provider.dart b/lib/widgets/common/data_providers/media_store_collection_provider.dart index bc229e5c5..29d88fe1b 100644 --- a/lib/widgets/common/data_providers/media_store_collection_provider.dart +++ b/lib/widgets/common/data_providers/media_store_collection_provider.dart @@ -4,9 +4,9 @@ import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/collection_source.dart'; import 'package:aves/model/favourite_repo.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/image_file_service.dart'; import 'package:aves/model/metadata_db.dart'; import 'package:aves/model/settings.dart'; +import 'package:aves/services/image_file_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_native_timezone/flutter_native_timezone.dart'; diff --git a/lib/widgets/common/image_providers/app_icon_image_provider.dart b/lib/widgets/common/image_providers/app_icon_image_provider.dart index 0740e8855..db2ab146e 100644 --- a/lib/widgets/common/image_providers/app_icon_image_provider.dart +++ b/lib/widgets/common/image_providers/app_icon_image_provider.dart @@ -1,6 +1,6 @@ import 'dart:ui' as ui show Codec; -import 'package:aves/utils/android_app_service.dart'; +import 'package:aves/services/android_app_service.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/common/image_providers/thumbnail_provider.dart b/lib/widgets/common/image_providers/thumbnail_provider.dart index dc57ef167..0f748b522 100644 --- a/lib/widgets/common/image_providers/thumbnail_provider.dart +++ b/lib/widgets/common/image_providers/thumbnail_provider.dart @@ -1,7 +1,7 @@ import 'dart:ui' as ui show Codec; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/image_file_service.dart'; +import 'package:aves/services/image_file_service.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/common/image_providers/uri_image_provider.dart b/lib/widgets/common/image_providers/uri_image_provider.dart index c6c452ec7..46c4dc0b7 100644 --- a/lib/widgets/common/image_providers/uri_image_provider.dart +++ b/lib/widgets/common/image_providers/uri_image_provider.dart @@ -1,6 +1,6 @@ import 'dart:ui' as ui show Codec; -import 'package:aves/model/image_file_service.dart'; +import 'package:aves/services/image_file_service.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/common/image_providers/uri_picture_provider.dart b/lib/widgets/common/image_providers/uri_picture_provider.dart index 2b0197d2c..a222f2881 100644 --- a/lib/widgets/common/image_providers/uri_picture_provider.dart +++ b/lib/widgets/common/image_providers/uri_picture_provider.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/image_file_service.dart'; +import 'package:aves/services/image_file_service.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; diff --git a/lib/widgets/fullscreen/fullscreen_action_delegate.dart b/lib/widgets/fullscreen/fullscreen_action_delegate.dart index 0722800b9..4176a2226 100644 --- a/lib/widgets/fullscreen/fullscreen_action_delegate.dart +++ b/lib/widgets/fullscreen/fullscreen_action_delegate.dart @@ -2,8 +2,8 @@ import 'dart:io'; import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/image_file_service.dart'; -import 'package:aves/utils/android_app_service.dart'; +import 'package:aves/services/android_app_service.dart'; +import 'package:aves/services/image_file_service.dart'; import 'package:aves/widgets/common/image_providers/uri_image_provider.dart'; import 'package:aves/widgets/fullscreen/debug.dart'; import 'package:aves/widgets/fullscreen/fullscreen_actions.dart'; diff --git a/lib/widgets/fullscreen/info/location_section.dart b/lib/widgets/fullscreen/info/location_section.dart index d35499a30..c0a452ab9 100644 --- a/lib/widgets/fullscreen/info/location_section.dart +++ b/lib/widgets/fullscreen/info/location_section.dart @@ -2,7 +2,7 @@ import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/filters/location.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/settings.dart'; -import 'package:aves/utils/android_app_service.dart'; +import 'package:aves/services/android_app_service.dart'; import 'package:aves/utils/geo_utils.dart'; import 'package:aves/widgets/common/aves_filter_chip.dart'; import 'package:aves/widgets/common/icons.dart'; diff --git a/lib/widgets/fullscreen/info/metadata_section.dart b/lib/widgets/fullscreen/info/metadata_section.dart index e69a2567f..0279a98ea 100644 --- a/lib/widgets/fullscreen/info/metadata_section.dart +++ b/lib/widgets/fullscreen/info/metadata_section.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:collection'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/metadata_service.dart'; +import 'package:aves/services/metadata_service.dart'; import 'package:aves/utils/color_utils.dart'; import 'package:aves/widgets/common/fx/highlight_decoration.dart'; import 'package:aves/widgets/fullscreen/info/info_page.dart'; diff --git a/lib/widgets/fullscreen/overlay/bottom.dart b/lib/widgets/fullscreen/overlay/bottom.dart index f0c5beaa2..2528b7b3e 100644 --- a/lib/widgets/fullscreen/overlay/bottom.dart +++ b/lib/widgets/fullscreen/overlay/bottom.dart @@ -3,7 +3,7 @@ import 'dart:ui'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_metadata.dart'; -import 'package:aves/model/metadata_service.dart'; +import 'package:aves/services/metadata_service.dart'; import 'package:aves/utils/constants.dart'; import 'package:aves/utils/geo_utils.dart'; import 'package:aves/widgets/common/fx/blurred.dart'; diff --git a/lib/widgets/fullscreen/overlay/video.dart b/lib/widgets/fullscreen/overlay/video.dart index 9b7ad422a..6939f0ade 100644 --- a/lib/widgets/fullscreen/overlay/video.dart +++ b/lib/widgets/fullscreen/overlay/video.dart @@ -1,5 +1,5 @@ import 'package:aves/model/image_entry.dart'; -import 'package:aves/utils/android_app_service.dart'; +import 'package:aves/services/android_app_service.dart'; import 'package:aves/utils/time_utils.dart'; import 'package:aves/widgets/common/fx/blurred.dart'; import 'package:aves/widgets/fullscreen/overlay/common.dart';