1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

fix(mobile): live / motion photo download (#5607)

* reverts: 5566

* fix: stitch livePhoto only in iOS

* fix: PMProgressHandler only on iOS

* ios: fallback to saving image if livephoto fails

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong 2023-12-10 15:56:39 +00:00 committed by GitHub
parent 33529d1d9b
commit 960b68b02f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 16 deletions

View File

@ -19,9 +19,11 @@ class ImageViewerService {
ImageViewerService(this._apiService);
Future<bool> downloadAssetToDevice(Asset asset) async {
File? imageFile;
File? videoFile;
try {
// Download LivePhotos image and motion part
if (asset.isImage && asset.livePhotoVideoId != null) {
if (asset.isImage && asset.livePhotoVideoId != null && Platform.isIOS) {
var imageResponse = await _apiService.assetApi.downloadFileWithHttpInfo(
asset.remoteId!,
);
@ -40,11 +42,11 @@ class ImageViewerService {
return false;
}
final AssetEntity? entity;
AssetEntity? entity;
final tempDir = await getTemporaryDirectory();
File videoFile = await File('${tempDir.path}/livephoto.mov').create();
File imageFile = await File('${tempDir.path}/livephoto.heic').create();
videoFile = await File('${tempDir.path}/livephoto.mov').create();
imageFile = await File('${tempDir.path}/livephoto.heic').create();
videoFile.writeAsBytesSync(motionReponse.bodyBytes);
imageFile.writeAsBytesSync(imageResponse.bodyBytes);
@ -54,6 +56,17 @@ class ImageViewerService {
title: asset.fileName,
);
if (entity == null) {
_log.warning(
"Asset cannot be saved as a live photo. This is most likely a motion photo. Saving only the image file",
);
entity = await PhotoManager.editor.saveImage(
imageResponse.bodyBytes,
title: asset.fileName,
);
}
return entity != null;
} else {
var res = await _apiService.assetApi
@ -75,17 +88,20 @@ class ImageViewerService {
);
} else {
final tempDir = await getTemporaryDirectory();
File tempFile =
await File('${tempDir.path}/${asset.fileName}').create();
tempFile.writeAsBytesSync(res.bodyBytes);
videoFile = await File('${tempDir.path}/${asset.fileName}').create();
videoFile.writeAsBytesSync(res.bodyBytes);
entity = await PhotoManager.editor
.saveVideo(tempFile, title: asset.fileName);
.saveVideo(videoFile, title: asset.fileName);
}
return entity != null;
}
} catch (error, stack) {
_log.severe("Error saving file ${error.toString()}", error, stack);
return false;
} finally {
// Clear temp files
imageFile?.delete();
videoFile?.delete();
}
}
}

View File

@ -453,7 +453,7 @@ class BackgroundService {
);
_cancellationToken = CancellationToken();
final pmProgressHandler = PMProgressHandler();
final pmProgressHandler = Platform.isIOS ? PMProgressHandler() : null;
final bool ok = await backupService.backupAsset(
toUpload,

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:cancellation_token_http/http.dart';
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
@ -447,9 +449,9 @@ class BackupNotifier extends StateNotifier<BackUpState> {
// Perform Backup
state = state.copyWith(cancelToken: CancellationToken());
final pmProgressHandler = PMProgressHandler();
final pmProgressHandler = Platform.isIOS ? PMProgressHandler() : null;
pmProgressHandler.stream.listen((event) {
pmProgressHandler?.stream.listen((event) {
final double progress = event.progress;
state = state.copyWith(iCloudDownloadProgress: progress);
});

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:cancellation_token_http/http.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/widgets.dart';
@ -208,7 +210,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
state.totalAssetsToUpload == 1;
state =
state.copyWith(showDetailedNotification: showDetailedNotification);
final pmProgressHandler = PMProgressHandler();
final pmProgressHandler = Platform.isIOS ? PMProgressHandler() : null;
final bool ok = await ref.read(backupServiceProvider).backupAsset(
allUploadAssets,

View File

@ -206,7 +206,7 @@ class BackupService {
Future<bool> backupAsset(
Iterable<AssetEntity> assetList,
http.CancellationToken cancelToken,
PMProgressHandler pmProgressHandler,
PMProgressHandler? pmProgressHandler,
Function(String, String, bool) uploadSuccessCb,
Function(int, int) uploadProgressCb,
Function(CurrentUploadAsset) setCurrentUploadAssetCb,

View File

@ -3,7 +3,6 @@ import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/ui/transparent_image.dart';
@ -35,11 +34,10 @@ class UserCircleAvatar extends ConsumerWidget {
color: isDarkTheme && user.avatarColor == AvatarColorEnum.primary
? Colors.black
: Colors.white,
backgroundColor: user.avatarColor.toColor(),
),
);
return CircleAvatar(
backgroundColor: context.primaryColor,
backgroundColor: user.avatarColor.toColor(),
radius: radius,
child: user.profileImagePath.isEmpty
? textIcon