native call priority management

This commit is contained in:
Thibault Deckers 2020-04-14 21:01:36 +09:00
parent 6a5603a116
commit 28e053cdd6
21 changed files with 135 additions and 53 deletions

View file

@ -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';

View file

@ -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(

View file

@ -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<Uint8List> getThumbnail(ImageEntry entry, int width, int height) async {
if (width > 0 && height > 0) {
static Future<Uint8List> 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', <String, dynamic>{
'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', <String, dynamic>{
'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<void> cancelGetThumbnail(String uri) async {

View file

@ -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<CatalogMetadata> 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', <String, dynamic>{
'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', <String, dynamic>{
'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<OverlayMetadata> getOverlayMetadata(ImageEntry entry) async {

View 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 }

View file

@ -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();

View file

@ -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) {

View file

@ -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<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;
var numColumns;
if ((newExtent ?? 0) == 0) {

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';