merge main

This commit is contained in:
shenlong-tanwen
2026-05-14 01:11:26 +05:30
480 changed files with 19769 additions and 4914 deletions
+12
View File
@@ -108,6 +108,18 @@ class ActionService {
await _remoteAssetRepository.restoreTrash(ids);
}
Future<int> emptyTrash(String userId) async {
final count = await _assetApiRepository.emptyTrash();
await _remoteAssetRepository.emptyTrash(userId);
return count;
}
Future<int> restoreAllTrash(String userId) async {
final count = await _assetApiRepository.restoreAllTrash();
await _remoteAssetRepository.restoreAllTrash(userId);
return count;
}
Future<void> trashRemoteAndDeleteLocal(List<String> remoteIds, List<String> localIds) async {
await _assetApiRepository.delete(remoteIds, false);
await _remoteAssetRepository.trash(remoteIds);
+3 -1
View File
@@ -183,7 +183,9 @@ class ApiService {
urls.add(localEndpoint);
}
for (final url in network.externalEndpointList) {
if (url.isNotEmpty) urls.add(url);
if (url.isNotEmpty) {
urls.add(url);
}
}
return urls;
}
@@ -82,7 +82,9 @@ class UploadTaskMetadata {
@override
bool operator ==(covariant UploadTaskMetadata other) {
if (identical(this, other)) return true;
if (identical(this, other)) {
return true;
}
return other.localAssetId == localAssetId &&
other.isLivePhotos == isLivePhotos &&
@@ -396,6 +398,7 @@ class BackgroundUploadService {
final (baseDirectory, directory, filename) = await Task.split(filePath: file.path);
final fieldsMap = {
'filename': originalFileName ?? filename,
// deviceAssetId/deviceId required by server v2.7.5 and below (drop in v4.0 per #27818).
'deviceAssetId': deviceAssetId ?? '',
'deviceId': deviceId,
'fileCreatedAt': createdAt.toUtc().toIso8601String(),
+11 -38
View File
@@ -45,21 +45,12 @@ class DeepLinkService {
this._currentUser,
);
DeepLink _handleColdStart(PageRouteInfo<dynamic> route, bool isColdStart) {
return DeepLink([
// we need something to segue back to if the app was cold started
// TODO: use MainTimelineRoute this when beta is default
if (isColdStart) const TabShellRoute(),
route,
]);
}
Future<DeepLink> handleScheme(PlatformDeepLink link, WidgetRef ref, bool isColdStart) async {
Future<PageRouteInfo?> handleScheme(PlatformDeepLink link, WidgetRef ref) async {
// get everything after the scheme, since Uri cannot parse path
final intent = link.uri.host;
final queryParams = link.uri.queryParameters;
PageRouteInfo<dynamic>? deepLinkRoute = switch (intent) {
return switch (intent) {
"memory" => await _buildMemoryDeepLink(queryParams['id'] ?? ''),
"asset" => await _buildAssetDeepLink(queryParams['id'] ?? '', ref),
"album" => await _buildAlbumDeepLink(queryParams['id'] ?? ''),
@@ -67,20 +58,9 @@ class DeepLinkService {
"activity" => await _buildActivityDeepLink(queryParams['albumId'] ?? ''),
_ => null,
};
// Deep link resolution failed, safely handle it based on the app state
if (deepLinkRoute == null) {
if (isColdStart) {
return DeepLink.defaultPath;
}
return DeepLink.none;
}
return _handleColdStart(deepLinkRoute, isColdStart);
}
Future<DeepLink> handleMyImmichApp(PlatformDeepLink link, WidgetRef ref, bool isColdStart) async {
Future<PageRouteInfo?> handleMyImmichApp(PlatformDeepLink link, WidgetRef ref) async {
final path = link.uri.path;
const uuidRegex = r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
@@ -88,27 +68,20 @@ class DeepLinkService {
final albumRegex = RegExp('/albums/($uuidRegex)');
final peopleRegex = RegExp('/people/($uuidRegex)');
PageRouteInfo<dynamic>? deepLinkRoute;
if (assetRegex.hasMatch(path)) {
final assetId = assetRegex.firstMatch(path)?.group(1) ?? '';
deepLinkRoute = await _buildAssetDeepLink(assetId, ref);
} else if (albumRegex.hasMatch(path)) {
return _buildAssetDeepLink(assetId, ref);
}
if (albumRegex.hasMatch(path)) {
final albumId = albumRegex.firstMatch(path)?.group(1) ?? '';
deepLinkRoute = await _buildAlbumDeepLink(albumId);
} else if (peopleRegex.hasMatch(path)) {
return _buildAlbumDeepLink(albumId);
}
if (peopleRegex.hasMatch(path)) {
final peopleId = peopleRegex.firstMatch(path)?.group(1) ?? '';
deepLinkRoute = await _buildPeopleDeepLink(peopleId);
} else if (path == "/memory") {
deepLinkRoute = await _buildMemoryDeepLink(null);
return _buildPeopleDeepLink(peopleId);
}
// Deep link resolution failed, safely handle it based on the app state
if (deepLinkRoute == null) {
if (isColdStart) return DeepLink.defaultPath;
return DeepLink.none;
}
return _handleColdStart(deepLinkRoute, isColdStart);
return null;
}
Future<PageRouteInfo?> _buildMemoryDeepLink(String? memoryId) async {
+3 -1
View File
@@ -21,7 +21,9 @@ class FolderService {
Map<String, List<RecursiveFolder>> folderMap = {};
for (String fullPath in paths) {
if (fullPath == '/') continue;
if (fullPath == '/') {
continue;
}
// Ensure the path starts with a slash
if (!fullPath.startsWith('/')) {
@@ -324,12 +324,13 @@ class ForegroundUploadService {
final deviceId = Store.get(StoreKey.deviceId);
final fields = {
// deviceAssetId/deviceId required by server v2.7.5 and below (drop in v4.0 per #27818).
'deviceAssetId': asset.localId!,
'deviceId': deviceId,
'fileCreatedAt': asset.createdAt.toUtc().toIso8601String(),
'fileModifiedAt': asset.updatedAt.toUtc().toIso8601String(),
'isFavorite': asset.isFavorite.toString(),
'duration': asset.duration.toString(),
'duration': (asset.durationMs ?? 0).toString(),
};
// Upload live photo video first if available
@@ -431,6 +432,7 @@ class ForegroundUploadService {
final filename = p.basename(file.path);
final fields = {
// deviceAssetId/deviceId required by server v2.7.5 and below (drop in v4.0 per #27818).
'deviceAssetId': deviceAssetId,
'deviceId': Store.get(StoreKey.deviceId),
'fileCreatedAt': fileCreatedAt.toUtc().toIso8601String(),