onAssetsChanged method

  1. @override
Future<void> onAssetsChanged(
  1. MethodCall call,
  2. StateSetter setState
)
override

Called when assets changed and obtained notifications from the OS. 系统发出资源变更的通知时调用的方法

Implementation

@override
Future<void> onAssetsChanged(MethodCall call, StateSetter setState) async {
  final permission = permissionNotifier.value;

  bool predicate() {
    final path = provider.currentPath?.path;
    if (assetsChangeRefreshPredicate != null) {
      return assetsChangeRefreshPredicate!(permission, call, path);
    }
    return path?.isAll ?? true;
  }

  if (!predicate()) {
    return;
  }

  assetsChangeCallback?.call(permission, call, provider.currentPath?.path);

  final createIds = <String>[];
  final updateIds = <String>[];
  final deleteIds = <String>[];
  int newCount = 0;
  int oldCount = 0;

  // Typically for iOS.
  if (call.arguments case final Map arguments) {
    if (arguments['newCount'] case final int count) {
      newCount = count;
    }
    if (arguments['oldCount'] case final int count) {
      oldCount = count;
    }
    for (final e in (arguments['create'] as List?) ?? []) {
      if (e['id'] case final String id) {
        createIds.add(id);
      }
    }
    for (final e in (arguments['update'] as List?) ?? []) {
      if (e['id'] case final String id) {
        updateIds.add(id);
      }
    }
    for (final e in (arguments['delete'] as List?) ?? []) {
      if (e['id'] case final String id) {
        deleteIds.add(id);
      }
    }
    if (createIds.isEmpty &&
        updateIds.isEmpty &&
        deleteIds.isEmpty &&
        // Updates with limited permission on iOS does not provide any IDs.
        // Counting on length changes is not reliable.
        (newCount == oldCount && permission != PermissionState.limited)) {
      return;
    }
  }
  // Throttle handling.
  if (onAssetsChangedLock case final lock?) {
    return lock.future;
  }
  final lock = Completer<void>();
  onAssetsChangedLock = lock;

  Future<void>(() async {
    // Replace the updated assets if update only.
    if (updateIds.isNotEmpty && createIds.isEmpty && deleteIds.isEmpty) {
      await Future.wait(
        updateIds.map((id) async {
          final i = provider.currentAssets.indexWhere((e) => e.id == id);
          if (i != -1) {
            final asset =
                await provider.currentAssets[i].obtainForNewProperties();
            provider.currentAssets[i] = asset!;
          }
        }),
      );
      return;
    }

    await provider.getPaths(keepPreviousCount: true);
    provider.currentPath = provider.paths.first;
    final currentWrapper = provider.currentPath;
    if (currentWrapper != null) {
      final newPath = await currentWrapper.path.obtainForNewProperties();
      final assetCount = await newPath.assetCountAsync;
      final newPathWrapper = PathWrapper<AssetPathEntity>(
        path: newPath,
        assetCount: assetCount,
      );
      if (newPath.isAll) {
        await provider.getAssetsFromCurrentPath();
        final entitiesShouldBeRemoved = <AssetEntity>[];
        for (final entity in provider.selectedAssets) {
          if (!provider.currentAssets.contains(entity)) {
            entitiesShouldBeRemoved.add(entity);
          }
        }
        entitiesShouldBeRemoved.forEach(provider.selectedAssets.remove);
      }
      provider
        ..currentPath = newPathWrapper
        ..hasAssetsToDisplay = assetCount != 0
        ..isAssetsEmpty = assetCount == 0
        ..totalAssetsCount = assetCount
        ..getThumbnailFromPath(newPathWrapper);
    }
    isSwitchingPath.value = false;
  }).then(lock.complete).catchError(lock.completeError).whenComplete(() {
    onAssetsChangedLock = null;
  });
}