-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented delete asset on device and on database (#22)
* refactor serving file function asset service * Remove PhotoViewer for now since it creates a problem in 2.10 * Added error message for wrong decode file and logo for failed to load file * Fixed error when read stream cannot be created and crash server * Added method to get all assets as a raw array * Implemented cleaner way of grouping image * Implemented operation to delete assets in the database * Implemented delete on database operation * Implemented delete on device operation * Fixed issue display wrong information when the auto backup is enabled after deleting all assets
- Loading branch information
1 parent
051c958
commit 897d49f
Showing
22 changed files
with
511 additions
and
10,610 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
mobile/lib/modules/home/models/delete_asset_response.model.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import 'dart:convert'; | ||
|
||
class DeleteAssetResponse { | ||
final String id; | ||
final String status; | ||
|
||
DeleteAssetResponse({ | ||
required this.id, | ||
required this.status, | ||
}); | ||
|
||
DeleteAssetResponse copyWith({ | ||
String? id, | ||
String? status, | ||
}) { | ||
return DeleteAssetResponse( | ||
id: id ?? this.id, | ||
status: status ?? this.status, | ||
); | ||
} | ||
|
||
Map<String, dynamic> toMap() { | ||
return { | ||
'id': id, | ||
'status': status, | ||
}; | ||
} | ||
|
||
factory DeleteAssetResponse.fromMap(Map<String, dynamic> map) { | ||
return DeleteAssetResponse( | ||
id: map['id'] ?? '', | ||
status: map['status'] ?? '', | ||
); | ||
} | ||
|
||
String toJson() => json.encode(toMap()); | ||
|
||
factory DeleteAssetResponse.fromJson(String source) => DeleteAssetResponse.fromMap(json.decode(source)); | ||
|
||
@override | ||
String toString() => 'DeleteAssetResponse(id: $id, status: $status)'; | ||
|
||
@override | ||
bool operator ==(Object other) { | ||
if (identical(this, other)) return true; | ||
|
||
return other is DeleteAssetResponse && other.id == id && other.status == status; | ||
} | ||
|
||
@override | ||
int get hashCode => id.hashCode ^ status.hashCode; | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,72 @@ | ||
import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||
import 'package:immich_mobile/modules/home/models/get_all_asset_respose.model.dart'; | ||
import 'package:immich_mobile/modules/home/models/delete_asset_response.model.dart'; | ||
import 'package:immich_mobile/modules/home/services/asset.service.dart'; | ||
import 'package:immich_mobile/shared/models/immich_asset.model.dart'; | ||
import 'package:intl/intl.dart'; | ||
import 'package:immich_mobile/shared/services/device_info.service.dart'; | ||
import 'package:collection/collection.dart'; | ||
import 'package:intl/intl.dart'; | ||
import 'package:photo_manager/photo_manager.dart'; | ||
|
||
class AssetNotifier extends StateNotifier<List<ImmichAssetGroupByDate>> { | ||
class AssetNotifier extends StateNotifier<List<ImmichAsset>> { | ||
final AssetService _assetService = AssetService(); | ||
final DeviceInfoService _deviceInfoService = DeviceInfoService(); | ||
|
||
AssetNotifier() : super([]); | ||
|
||
late String? nextPageKey = ""; | ||
bool isFetching = false; | ||
getAllAsset() async { | ||
List<ImmichAsset>? allAssets = await _assetService.getAllAsset(); | ||
|
||
// Get All assets | ||
getAllAssets() async { | ||
GetAllAssetResponse? res = await _assetService.getAllAsset(); | ||
nextPageKey = res?.nextPageKey; | ||
|
||
if (res != null) { | ||
for (var assets in res.data) { | ||
state = [...state, assets]; | ||
} | ||
if (allAssets != null) { | ||
allAssets.sortByCompare<DateTime>((e) => DateTime.parse(e.createdAt), (a, b) => b.compareTo(a)); | ||
state = allAssets; | ||
} | ||
} | ||
|
||
// Get Asset From The Past | ||
getOlderAsset() async { | ||
if (nextPageKey != null && !isFetching) { | ||
isFetching = true; | ||
GetAllAssetResponse? res = await _assetService.getOlderAsset(nextPageKey); | ||
|
||
if (res != null) { | ||
nextPageKey = res.nextPageKey; | ||
|
||
List<ImmichAssetGroupByDate> previousState = state; | ||
List<ImmichAssetGroupByDate> currentState = []; | ||
|
||
for (var assets in res.data) { | ||
currentState = [...currentState, assets]; | ||
} | ||
clearAllAsset() { | ||
state = []; | ||
} | ||
|
||
if (previousState.last.date == currentState.first.date) { | ||
previousState.last.assets = [...previousState.last.assets, ...currentState.first.assets]; | ||
state = [...previousState, ...currentState.sublist(1)]; | ||
} else { | ||
state = [...previousState, ...currentState]; | ||
deleteAssets(Set<ImmichAsset> deleteAssets) async { | ||
var deviceInfo = await _deviceInfoService.getDeviceInfo(); | ||
var deviceId = deviceInfo["deviceId"]; | ||
List<String> deleteIdList = []; | ||
// Delete asset from device | ||
for (var asset in deleteAssets) { | ||
// Delete asset on device if present | ||
if (asset.deviceId == deviceId) { | ||
AssetEntity? localAsset = await AssetEntity.fromId(asset.deviceAssetId); | ||
|
||
if (localAsset != null) { | ||
deleteIdList.add(localAsset.id); | ||
} | ||
} | ||
|
||
isFetching = false; | ||
} | ||
} | ||
|
||
// Get newer asset from the current time | ||
getNewAsset() async { | ||
if (state.isNotEmpty) { | ||
var latestGroup = state.first; | ||
final List<String> result = await PhotoManager.editor.deleteWithIds(deleteIdList); | ||
print(result); | ||
|
||
// Sort the last asset group and put the lastest asset in front. | ||
latestGroup.assets.sortByCompare<DateTime>((e) => DateTime.parse(e.createdAt), (a, b) => b.compareTo(a)); | ||
var latestAsset = latestGroup.assets.first; | ||
var formatDateTemplate = 'y-MM-dd'; | ||
var latestAssetDateText = DateFormat(formatDateTemplate).format(DateTime.parse(latestAsset.createdAt)); | ||
|
||
List<ImmichAsset> newAssets = await _assetService.getNewAsset(latestAsset.createdAt); | ||
// Delete asset on server | ||
List<DeleteAssetResponse>? deleteAssetResult = await _assetService.deleteAssets(deleteAssets); | ||
if (deleteAssetResult == null) { | ||
return; | ||
} | ||
|
||
if (newAssets.isEmpty) { | ||
return; | ||
for (var asset in deleteAssetResult) { | ||
if (asset.status == 'success') { | ||
state = state.where((immichAsset) => immichAsset.id != asset.id).toList(); | ||
} | ||
|
||
// Grouping by data | ||
var groupByDateList = groupBy<ImmichAsset, String>( | ||
newAssets, (asset) => DateFormat(formatDateTemplate).format(DateTime.parse(asset.createdAt))); | ||
|
||
groupByDateList.forEach((groupDateInFormattedText, assets) { | ||
if (groupDateInFormattedText != latestAssetDateText) { | ||
ImmichAssetGroupByDate newGroup = ImmichAssetGroupByDate(assets: assets, date: groupDateInFormattedText); | ||
state = [newGroup, ...state]; | ||
} else { | ||
latestGroup.assets.insertAll(0, assets); | ||
|
||
state = [latestGroup, ...state.sublist(1)]; | ||
} | ||
}); | ||
} | ||
} | ||
|
||
clearAllAsset() { | ||
state = []; | ||
} | ||
} | ||
|
||
final currentLocalPageProvider = StateProvider<int>((ref) => 0); | ||
|
||
final assetProvider = StateNotifierProvider<AssetNotifier, List<ImmichAssetGroupByDate>>((ref) { | ||
final assetProvider = StateNotifierProvider<AssetNotifier, List<ImmichAsset>>((ref) { | ||
return AssetNotifier(); | ||
}); | ||
|
||
final assetGroupByDateTimeProvider = StateProvider((ref) { | ||
var assetGroup = ref.watch(assetProvider); | ||
|
||
return assetGroup.groupListsBy((element) => DateFormat('y-MM-dd').format(DateTime.parse(element.createdAt))); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.