native call priority management
This commit is contained in:
parent
6a5603a116
commit
28e053cdd6
21 changed files with 135 additions and 53 deletions
|
@ -1,8 +1,8 @@
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/model/image_file_service.dart';
|
|
||||||
import 'package:aves/model/settings.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/android_file_utils.dart';
|
||||||
import 'package:aves/utils/viewer_service.dart';
|
|
||||||
import 'package:aves/widgets/album/collection_page.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/common/data_providers/media_store_collection_provider.dart';
|
||||||
import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
|
import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import 'package:aves/model/favourite_repo.dart';
|
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/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/change_notifier.dart';
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -220,7 +221,11 @@ class ImageEntry {
|
||||||
|
|
||||||
final coordinates = Coordinates(latitude, longitude);
|
final coordinates = Coordinates(latitude, longitude);
|
||||||
try {
|
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) {
|
if (addresses != null && addresses.isNotEmpty) {
|
||||||
final address = addresses.first;
|
final address = addresses.first;
|
||||||
addressDetails = AddressDetails(
|
addressDetails = AddressDetails(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
|
import 'package:aves/services/service_policy.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
@ -42,21 +43,27 @@ class ImageFileService {
|
||||||
return Uint8List(0);
|
return Uint8List(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Uint8List> getThumbnail(ImageEntry entry, int width, int height) async {
|
static Future<Uint8List> getThumbnail(ImageEntry entry, int width, int height) {
|
||||||
if (width > 0 && height > 0) {
|
return servicePolicy.call(
|
||||||
|
() async {
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
// debugPrint('getThumbnail width=$width path=${entry.path}');
|
// debugPrint('getThumbnail width=$width path=${entry.path}');
|
||||||
try {
|
try {
|
||||||
final result = await platform.invokeMethod('getThumbnail', <String, dynamic>{
|
final result = await platform.invokeMethod('getThumbnail', <String, dynamic>{
|
||||||
'entry': entry.toMap(),
|
'entry': entry.toMap(),
|
||||||
'width': width,
|
'width': width,
|
||||||
'height': height,
|
'height': height,
|
||||||
});
|
});
|
||||||
return result as Uint8List;
|
return result as Uint8List;
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
debugPrint('getThumbnail failed with code=${e.code}, exception=${e.message}, details=${e.details}');
|
debugPrint('getThumbnail failed with code=${e.code}, exception=${e.message}, details=${e.details}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Uint8List(0);
|
return Uint8List(0);
|
||||||
|
},
|
||||||
|
ServiceCallPriority.asapLifo,
|
||||||
|
'getThumbnail-${entry.path}',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> cancelGetThumbnail(String uri) async {
|
static Future<void> cancelGetThumbnail(String uri) async {
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/model/image_metadata.dart';
|
import 'package:aves/model/image_metadata.dart';
|
||||||
|
import 'package:aves/services/service_policy.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
@ -26,26 +27,32 @@ class MetadataService {
|
||||||
static Future<CatalogMetadata> getCatalogMetadata(ImageEntry entry) async {
|
static Future<CatalogMetadata> getCatalogMetadata(ImageEntry entry) async {
|
||||||
if (entry.isSvg) return null;
|
if (entry.isSvg) return null;
|
||||||
|
|
||||||
try {
|
return servicePolicy.call(
|
||||||
// return map with:
|
() async {
|
||||||
// 'dateMillis': date taken in milliseconds since Epoch (long)
|
try {
|
||||||
// 'isAnimated': animated gif/webp (bool)
|
// return map with:
|
||||||
// 'latitude': latitude (double)
|
// 'dateMillis': date taken in milliseconds since Epoch (long)
|
||||||
// 'longitude': longitude (double)
|
// 'isAnimated': animated gif/webp (bool)
|
||||||
// 'videoRotation': video rotation degrees (int)
|
// 'latitude': latitude (double)
|
||||||
// 'xmpSubjects': ';' separated XMP subjects (string)
|
// 'longitude': longitude (double)
|
||||||
// 'xmpTitleDescription': XMP title or XMP description (string)
|
// 'videoRotation': video rotation degrees (int)
|
||||||
final result = await platform.invokeMethod('getCatalogMetadata', <String, dynamic>{
|
// 'xmpSubjects': ';' separated XMP subjects (string)
|
||||||
'mimeType': entry.mimeType,
|
// 'xmpTitleDescription': XMP title or XMP description (string)
|
||||||
'path': entry.path,
|
final result = await platform.invokeMethod('getCatalogMetadata', <String, dynamic>{
|
||||||
'uri': entry.uri,
|
'mimeType': entry.mimeType,
|
||||||
}) as Map;
|
'path': entry.path,
|
||||||
result['contentId'] = entry.contentId;
|
'uri': entry.uri,
|
||||||
return CatalogMetadata.fromMap(result);
|
}) as Map;
|
||||||
} on PlatformException catch (e) {
|
result['contentId'] = entry.contentId;
|
||||||
debugPrint('getCatalogMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
|
return CatalogMetadata.fromMap(result);
|
||||||
}
|
} on PlatformException catch (e) {
|
||||||
return null;
|
debugPrint('getCatalogMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
ServiceCallPriority.background,
|
||||||
|
'getCatalogMetadata-${entry.path}',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<OverlayMetadata> getOverlayMetadata(ImageEntry entry) async {
|
static Future<OverlayMetadata> getOverlayMetadata(ImageEntry entry) async {
|
58
lib/services/service_policy.dart
Normal file
58
lib/services/service_policy.dart
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
final ServicePolicy servicePolicy = ServicePolicy._private();
|
||||||
|
|
||||||
|
class ServicePolicy {
|
||||||
|
final Queue<VoidCallback> _asapQueue = Queue(), _normalQueue = Queue(), _backgroundQueue = Queue();
|
||||||
|
VoidCallback _running;
|
||||||
|
|
||||||
|
ServicePolicy._private();
|
||||||
|
|
||||||
|
Future<T> call<T>(Future<T> Function() platformCall, [ServiceCallPriority priority = ServiceCallPriority.normal, String debugLabel]) {
|
||||||
|
Queue<VoidCallback> 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<T>();
|
||||||
|
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 }
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:aves/utils/android_app_service.dart';
|
import 'package:aves/services/android_app_service.dart';
|
||||||
import 'package:aves/utils/android_file_service.dart';
|
import 'package:aves/services/android_file_service.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
|
|
||||||
final AndroidFileUtils androidFileUtils = AndroidFileUtils._private();
|
final AndroidFileUtils androidFileUtils = AndroidFileUtils._private();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:aves/model/collection_lens.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/widgets/album/grid/header_generic.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/list_sliver.dart';
|
||||||
|
import 'package:aves/widgets/album/grid/tile_extent_manager.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ class SectionedListLayoutProvider extends StatelessWidget {
|
||||||
@required this.scrollableWidth,
|
@required this.scrollableWidth,
|
||||||
@required this.tileExtent,
|
@required this.tileExtent,
|
||||||
@required this.child,
|
@required this.child,
|
||||||
}) : columnCount = (scrollableWidth / tileExtent).round();
|
}) : columnCount = max((scrollableWidth / tileExtent).round(), TileExtentManager.columnCountMin);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -7,8 +7,12 @@ class TileExtentManager {
|
||||||
static const int columnCountMin = 2;
|
static const int columnCountMin = 2;
|
||||||
static const int columnCountDefault = 4;
|
static const int columnCountDefault = 4;
|
||||||
static const double tileExtentMin = 46.0;
|
static const double tileExtentMin = 46.0;
|
||||||
|
static const screenDimensionMin = tileExtentMin * columnCountMin;
|
||||||
|
|
||||||
static double applyTileExtent(Size mqSize, double mqHorizontalPadding, ValueNotifier<double> extentNotifier, {double newExtent}) {
|
static double applyTileExtent(Size mqSize, double mqHorizontalPadding, ValueNotifier<double> 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;
|
final availableWidth = mqSize.width - mqHorizontalPadding;
|
||||||
var numColumns;
|
var numColumns;
|
||||||
if ((newExtent ?? 0) == 0) {
|
if ((newExtent ?? 0) == 0) {
|
||||||
|
|
|
@ -4,9 +4,9 @@ import 'package:aves/model/collection_lens.dart';
|
||||||
import 'package:aves/model/collection_source.dart';
|
import 'package:aves/model/collection_source.dart';
|
||||||
import 'package:aves/model/favourite_repo.dart';
|
import 'package:aves/model/favourite_repo.dart';
|
||||||
import 'package:aves/model/image_entry.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/metadata_db.dart';
|
||||||
import 'package:aves/model/settings.dart';
|
import 'package:aves/model/settings.dart';
|
||||||
|
import 'package:aves/services/image_file_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
|
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'dart:ui' as ui show Codec;
|
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/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'dart:ui' as ui show Codec;
|
import 'dart:ui' as ui show Codec;
|
||||||
|
|
||||||
import 'package:aves/model/image_entry.dart';
|
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/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'dart:ui' as ui show Codec;
|
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/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:aves/model/collection_lens.dart';
|
import 'package:aves/model/collection_lens.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/model/image_file_service.dart';
|
import 'package:aves/services/android_app_service.dart';
|
||||||
import 'package:aves/utils/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/common/image_providers/uri_image_provider.dart';
|
||||||
import 'package:aves/widgets/fullscreen/debug.dart';
|
import 'package:aves/widgets/fullscreen/debug.dart';
|
||||||
import 'package:aves/widgets/fullscreen/fullscreen_actions.dart';
|
import 'package:aves/widgets/fullscreen/fullscreen_actions.dart';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:aves/model/collection_lens.dart';
|
||||||
import 'package:aves/model/filters/location.dart';
|
import 'package:aves/model/filters/location.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/model/settings.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/utils/geo_utils.dart';
|
||||||
import 'package:aves/widgets/common/aves_filter_chip.dart';
|
import 'package:aves/widgets/common/aves_filter_chip.dart';
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
import 'package:aves/widgets/common/icons.dart';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:aves/model/image_entry.dart';
|
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/utils/color_utils.dart';
|
||||||
import 'package:aves/widgets/common/fx/highlight_decoration.dart';
|
import 'package:aves/widgets/common/fx/highlight_decoration.dart';
|
||||||
import 'package:aves/widgets/fullscreen/info/info_page.dart';
|
import 'package:aves/widgets/fullscreen/info/info_page.dart';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/model/image_metadata.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/constants.dart';
|
||||||
import 'package:aves/utils/geo_utils.dart';
|
import 'package:aves/utils/geo_utils.dart';
|
||||||
import 'package:aves/widgets/common/fx/blurred.dart';
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:aves/model/image_entry.dart';
|
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/utils/time_utils.dart';
|
||||||
import 'package:aves/widgets/common/fx/blurred.dart';
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
import 'package:aves/widgets/fullscreen/overlay/common.dart';
|
import 'package:aves/widgets/fullscreen/overlay/common.dart';
|
||||||
|
|
Loading…
Reference in a new issue