refactor(mobile): encapsulate most access to photomanager in repository (#12754)

* refactor(mobile): encapsulate most access to photomanager in repository
This commit is contained in:
Fynn Petersen-Frey 2024-09-18 17:15:52 +02:00 committed by GitHub
parent 6740c67ed8
commit 6995cc2b38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 1205 additions and 500 deletions

View file

@ -5,6 +5,9 @@ import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/interfaces/album_media.interface.dart';
import 'package:immich_mobile/interfaces/file_media.interface.dart';
import 'package:immich_mobile/models/backup/available_album.model.dart';
import 'package:immich_mobile/entities/backup_album.entity.dart';
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
@ -13,6 +16,8 @@ import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
import 'package:immich_mobile/models/backup/error_upload_asset.model.dart';
import 'package:immich_mobile/models/backup/success_upload_asset.model.dart';
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
import 'package:immich_mobile/repositories/album_media.repository.dart';
import 'package:immich_mobile/repositories/file_media.repository.dart';
import 'package:immich_mobile/services/background.service.dart';
import 'package:immich_mobile/services/backup.service.dart';
import 'package:immich_mobile/models/authentication/authentication_state.model.dart';
@ -28,7 +33,7 @@ import 'package:immich_mobile/utils/diff.dart';
import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:photo_manager/photo_manager.dart' show PMProgressHandler;
class BackupNotifier extends StateNotifier<BackUpState> {
BackupNotifier(
@ -38,6 +43,8 @@ class BackupNotifier extends StateNotifier<BackUpState> {
this._backgroundService,
this._galleryPermissionNotifier,
this._db,
this._albumMediaRepository,
this._fileMediaRepository,
this.ref,
) : super(
BackUpState(
@ -86,6 +93,8 @@ class BackupNotifier extends StateNotifier<BackUpState> {
final BackgroundService _backgroundService;
final GalleryPermissionNotifier _galleryPermissionNotifier;
final Isar _db;
final IAlbumMediaRepository _albumMediaRepository;
final IFileMediaRepository _fileMediaRepository;
final Ref ref;
///
@ -224,22 +233,24 @@ class BackupNotifier extends StateNotifier<BackUpState> {
Stopwatch stopwatch = Stopwatch()..start();
// Get all albums on the device
List<AvailableAlbum> availableAlbums = [];
List<AssetPathEntity> albums = await PhotoManager.getAssetPathList(
hasAll: true,
type: RequestType.common,
);
List<Album> albums = await _albumMediaRepository.getAll();
// Map of id -> album for quick album lookup later on.
Map<String, AssetPathEntity> albumMap = {};
Map<String, Album> albumMap = {};
log.info('Found ${albums.length} local albums');
for (AssetPathEntity album in albums) {
AvailableAlbum availableAlbum = AvailableAlbum(albumEntity: album);
for (Album album in albums) {
AvailableAlbum availableAlbum = AvailableAlbum(
album: album,
assetCount: await ref
.read(albumMediaRepositoryProvider)
.getAssetCount(album.localId!),
);
availableAlbums.add(availableAlbum);
albumMap[album.id] = album;
albumMap[album.localId!] = album;
}
state = state.copyWith(availableAlbums: availableAlbums);
@ -248,14 +259,18 @@ class BackupNotifier extends StateNotifier<BackUpState> {
final List<BackupAlbum> selectedBackupAlbums =
await _backupService.selectedAlbumsQuery().findAll();
// Generate AssetPathEntity from id to add to local state
final Set<AvailableAlbum> selectedAlbums = {};
for (final BackupAlbum ba in selectedBackupAlbums) {
final albumAsset = albumMap[ba.id];
if (albumAsset != null) {
selectedAlbums.add(
AvailableAlbum(albumEntity: albumAsset, lastBackup: ba.lastBackup),
AvailableAlbum(
album: albumAsset,
assetCount:
await _albumMediaRepository.getAssetCount(albumAsset.localId!),
lastBackup: ba.lastBackup,
),
);
} else {
log.severe('Selected album not found');
@ -268,7 +283,13 @@ class BackupNotifier extends StateNotifier<BackUpState> {
if (albumAsset != null) {
excludedAlbums.add(
AvailableAlbum(albumEntity: albumAsset, lastBackup: ba.lastBackup),
AvailableAlbum(
album: albumAsset,
assetCount: await ref
.read(albumMediaRepositoryProvider)
.getAssetCount(albumAsset.localId!),
lastBackup: ba.lastBackup,
),
);
} else {
log.severe('Excluded album not found');
@ -297,23 +318,24 @@ class BackupNotifier extends StateNotifier<BackUpState> {
final Set<BackupCandidate> assetsFromExcludedAlbums = {};
for (final album in state.selectedBackupAlbums) {
final assetCount = await album.albumEntity.assetCountAsync;
final assetCount = await ref
.read(albumMediaRepositoryProvider)
.getAssetCount(album.album.localId!);
if (assetCount == 0) {
continue;
}
final assets = await album.albumEntity.getAssetListRange(
start: 0,
end: assetCount,
);
final assets = await ref
.read(albumMediaRepositoryProvider)
.getAssets(album.album.localId!);
// Add album's name to the asset info
for (final asset in assets) {
List<String> albumNames = [album.name];
final existingAsset = assetsFromSelectedAlbums.firstWhereOrNull(
(a) => a.asset.id == asset.id,
(a) => a.asset.localId == asset.localId,
);
if (existingAsset != null) {
@ -331,16 +353,17 @@ class BackupNotifier extends StateNotifier<BackUpState> {
}
for (final album in state.excludedBackupAlbums) {
final assetCount = await album.albumEntity.assetCountAsync;
final assetCount = await ref
.read(albumMediaRepositoryProvider)
.getAssetCount(album.album.localId!);
if (assetCount == 0) {
continue;
}
final assets = await album.albumEntity.getAssetListRange(
start: 0,
end: assetCount,
);
final assets = await ref
.read(albumMediaRepositoryProvider)
.getAssets(album.album.localId!);
for (final asset in assets) {
assetsFromExcludedAlbums.add(
@ -360,14 +383,14 @@ class BackupNotifier extends StateNotifier<BackUpState> {
// Find asset that were backup from selected albums
final Set<String> selectedAlbumsBackupAssets =
Set.from(allUniqueAssets.map((e) => e.asset.id));
Set.from(allUniqueAssets.map((e) => e.asset.localId));
selectedAlbumsBackupAssets
.removeWhere((assetId) => !allAssetsInDatabase.contains(assetId));
// Remove duplicated asset from all unique assets
allUniqueAssets.removeWhere(
(candidate) => duplicatedAssetIds.contains(candidate.asset.id),
(candidate) => duplicatedAssetIds.contains(candidate.asset.localId),
);
if (allUniqueAssets.isEmpty) {
@ -454,7 +477,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
final hasPermission = _galleryPermissionNotifier.hasPermission;
if (hasPermission) {
await PhotoManager.clearFileCache();
await _fileMediaRepository.clearFileCache();
if (state.allUniqueAssets.isEmpty) {
log.info("No Asset On Device - Abort Backup Process");
@ -465,7 +488,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
Set<BackupCandidate> assetsWillBeBackup = Set.from(state.allUniqueAssets);
// Remove item that has already been backed up
for (final assetId in state.allAssetsInDatabase) {
assetsWillBeBackup.removeWhere((e) => e.asset.id == assetId);
assetsWillBeBackup.removeWhere((e) => e.asset.localId == assetId);
}
if (assetsWillBeBackup.isEmpty) {
@ -531,7 +554,8 @@ class BackupNotifier extends StateNotifier<BackUpState> {
state = state.copyWith(
allUniqueAssets: state.allUniqueAssets
.where(
(candidate) => candidate.asset.id != result.candidate.asset.id,
(candidate) =>
candidate.asset.localId != result.candidate.asset.localId,
)
.toSet(),
);
@ -539,11 +563,11 @@ class BackupNotifier extends StateNotifier<BackUpState> {
state = state.copyWith(
selectedAlbumsBackupAssetsIds: {
...state.selectedAlbumsBackupAssetsIds,
result.candidate.asset.id,
result.candidate.asset.localId!,
},
allAssetsInDatabase: [
...state.allAssetsInDatabase,
result.candidate.asset.id,
result.candidate.asset.localId!,
],
);
}
@ -552,7 +576,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
state.selectedAlbumsBackupAssetsIds.length ==
0) {
final latestAssetBackup = state.allUniqueAssets
.map((candidate) => candidate.asset.modifiedDateTime)
.map((candidate) => candidate.asset.fileModifiedAt)
.reduce(
(v, e) => e.isAfter(v) ? e : v,
);
@ -741,6 +765,8 @@ final backupProvider =
ref.watch(backgroundServiceProvider),
ref.watch(galleryPermissionNotifier.notifier),
ref.watch(dbProvider),
ref.watch(albumMediaRepositoryProvider),
ref.watch(fileMediaRepositoryProvider),
ref,
);
});