Motion Photo Support (#1058)
This commit is contained in:
commit
8894c61d98
8 changed files with 46 additions and 9 deletions
|
@ -285,7 +285,7 @@ class File extends EnteFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
// return 0 if the height is not available
|
// return 0 if the height is not available
|
||||||
int get heigth {
|
int get height {
|
||||||
return pubMagicMetadata?.h ?? 0;
|
return pubMagicMetadata?.h ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ const publicMagicKeyWidth = 'w';
|
||||||
const publicMagicKeyHeight = 'h';
|
const publicMagicKeyHeight = 'h';
|
||||||
const pubMagicKeyLat = "lat";
|
const pubMagicKeyLat = "lat";
|
||||||
const pubMagicKeyLong = "long";
|
const pubMagicKeyLong = "long";
|
||||||
|
const pubMotionVideoIndex = "mvi";
|
||||||
|
|
||||||
class MagicMetadata {
|
class MagicMetadata {
|
||||||
// 0 -> visible
|
// 0 -> visible
|
||||||
|
@ -52,6 +53,9 @@ class PubMagicMetadata {
|
||||||
int? h;
|
int? h;
|
||||||
double? lat;
|
double? lat;
|
||||||
double? long;
|
double? long;
|
||||||
|
// Motion Video Index. Positive value indicates that the file is a motion
|
||||||
|
// photo
|
||||||
|
int? mvi;
|
||||||
|
|
||||||
PubMagicMetadata({
|
PubMagicMetadata({
|
||||||
this.editedTime,
|
this.editedTime,
|
||||||
|
@ -62,6 +66,7 @@ class PubMagicMetadata {
|
||||||
this.h,
|
this.h,
|
||||||
this.lat,
|
this.lat,
|
||||||
this.long,
|
this.long,
|
||||||
|
this.mvi,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory PubMagicMetadata.fromEncodedJson(String encodedJson) =>
|
factory PubMagicMetadata.fromEncodedJson(String encodedJson) =>
|
||||||
|
@ -81,6 +86,7 @@ class PubMagicMetadata {
|
||||||
h: map[publicMagicKeyHeight],
|
h: map[publicMagicKeyHeight],
|
||||||
lat: map[pubMagicKeyLat],
|
lat: map[pubMagicKeyLat],
|
||||||
long: map[pubMagicKeyLong],
|
long: map[pubMagicKeyLong],
|
||||||
|
mvi: map[pubMotionVideoIndex],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,8 +111,9 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||||
}
|
}
|
||||||
if (widget.file!.fileType == FileType.video) {
|
if (widget.file!.fileType == FileType.video) {
|
||||||
contentChildren.add(const VideoOverlayIcon());
|
contentChildren.add(const VideoOverlayIcon());
|
||||||
} else if (widget.file!.fileType == FileType.livePhoto &&
|
} else if (widget.shouldShowLivePhotoOverlay &&
|
||||||
widget.shouldShowLivePhotoOverlay) {
|
(widget.file!.fileType == FileType.livePhoto ||
|
||||||
|
((widget.file!.pubMagicMetadata?.mvi ?? 0) > 0))) {
|
||||||
contentChildren.add(const LivePhotoOverlayIcon());
|
contentChildren.add(const LivePhotoOverlayIcon());
|
||||||
}
|
}
|
||||||
if (widget.shouldShowOwnerAvatar) {
|
if (widget.shouldShowOwnerAvatar) {
|
||||||
|
|
|
@ -276,7 +276,7 @@ class _ZoomableImageState extends State<ZoomableImage>
|
||||||
final int h = imageInfo.image.height, w = imageInfo.image.width;
|
final int h = imageInfo.image.height, w = imageInfo.image.width;
|
||||||
if (h != 0 &&
|
if (h != 0 &&
|
||||||
w != 0 &&
|
w != 0 &&
|
||||||
(h != widget.photo.heigth || w != widget.photo.width)) {
|
(h != widget.photo.height || w != widget.photo.width)) {
|
||||||
_logger.info('Updating aspect ratio for ${widget.photo} to $h:$w');
|
_logger.info('Updating aspect ratio for ${widget.photo} to $h:$w');
|
||||||
await FileMagicService.instance.updatePublicMagicMetadata(
|
await FileMagicService.instance.updatePublicMagicMetadata(
|
||||||
[widget.photo], {publicMagicKeyHeight: h, publicMagicKeyWidth: w});
|
[widget.photo], {publicMagicKeyHeight: h, publicMagicKeyWidth: w});
|
||||||
|
|
|
@ -5,10 +5,13 @@ import 'package:chewie/chewie.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:motion_photos/motion_photos.dart';
|
import 'package:motion_photos/motion_photos.dart';
|
||||||
|
import "package:photos/core/configuration.dart";
|
||||||
import 'package:photos/core/constants.dart';
|
import 'package:photos/core/constants.dart';
|
||||||
import "package:photos/generated/l10n.dart";
|
import "package:photos/generated/l10n.dart";
|
||||||
import 'package:photos/models/file.dart';
|
import 'package:photos/models/file.dart';
|
||||||
import "package:photos/models/file_type.dart";
|
import "package:photos/models/file_type.dart";
|
||||||
|
import "package:photos/models/magic_metadata.dart";
|
||||||
|
import "package:photos/services/file_magic_service.dart";
|
||||||
import 'package:photos/ui/viewer/file/zoomable_image.dart';
|
import 'package:photos/ui/viewer/file/zoomable_image.dart';
|
||||||
import 'package:photos/utils/file_util.dart';
|
import 'package:photos/utils/file_util.dart';
|
||||||
import 'package:photos/utils/toast_util.dart';
|
import 'package:photos/utils/toast_util.dart';
|
||||||
|
@ -177,6 +180,13 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
||||||
final motionPhoto = MotionPhotos(imageFile.path);
|
final motionPhoto = MotionPhotos(imageFile.path);
|
||||||
final index = motionPhoto.getMotionVideoIndex();
|
final index = motionPhoto.getMotionVideoIndex();
|
||||||
if (index != null) {
|
if (index != null) {
|
||||||
|
if (widget.file.pubMagicMetadata?.mvi == null &&
|
||||||
|
(widget.file.ownerID ?? 0) == Configuration.instance.getUserID()!) {
|
||||||
|
FileMagicService.instance.updatePublicMagicMetadata(
|
||||||
|
[widget.file],
|
||||||
|
{pubMotionVideoIndex: index.start},
|
||||||
|
).ignore();
|
||||||
|
}
|
||||||
return motionPhoto.getMotionVideoFile(
|
return motionPhoto.getMotionVideoFile(
|
||||||
index: index,
|
index: index,
|
||||||
);
|
);
|
||||||
|
|
|
@ -458,12 +458,17 @@ class FileUploader {
|
||||||
MetadataRequest? pubMetadataRequest;
|
MetadataRequest? pubMetadataRequest;
|
||||||
if ((mediaUploadData.height ?? 0) != 0 &&
|
if ((mediaUploadData.height ?? 0) != 0 &&
|
||||||
(mediaUploadData.width ?? 0) != 0) {
|
(mediaUploadData.width ?? 0) != 0) {
|
||||||
|
final pubMetadata = {
|
||||||
|
publicMagicKeyHeight: mediaUploadData.height,
|
||||||
|
publicMagicKeyWidth: mediaUploadData.width
|
||||||
|
};
|
||||||
|
if (mediaUploadData.motionPhotoStartIndex != null) {
|
||||||
|
pubMetadata[pubMotionVideoIndex] =
|
||||||
|
mediaUploadData.motionPhotoStartIndex;
|
||||||
|
}
|
||||||
pubMetadataRequest = await getPubMetadataRequest(
|
pubMetadataRequest = await getPubMetadataRequest(
|
||||||
file,
|
file,
|
||||||
{
|
pubMetadata,
|
||||||
publicMagicKeyHeight: mediaUploadData.height,
|
|
||||||
publicMagicKeyWidth: mediaUploadData.width
|
|
||||||
},
|
|
||||||
fileAttributes.key!,
|
fileAttributes.key!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:archive/archive_io.dart';
|
import 'package:archive/archive_io.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
import "package:motion_photos/motion_photos.dart";
|
||||||
import 'package:motionphoto/motionphoto.dart';
|
import 'package:motionphoto/motionphoto.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
@ -33,6 +34,9 @@ class MediaUploadData {
|
||||||
final FileHashData? hashData;
|
final FileHashData? hashData;
|
||||||
final int? height;
|
final int? height;
|
||||||
final int? width;
|
final int? width;
|
||||||
|
// For android motion photos, the startIndex is the index of the first frame
|
||||||
|
// For iOS, this value will be always null.
|
||||||
|
final int? motionPhotoStartIndex;
|
||||||
|
|
||||||
MediaUploadData(
|
MediaUploadData(
|
||||||
this.sourceFile,
|
this.sourceFile,
|
||||||
|
@ -41,6 +45,7 @@ class MediaUploadData {
|
||||||
this.hashData, {
|
this.hashData, {
|
||||||
this.height,
|
this.height,
|
||||||
this.width,
|
this.width,
|
||||||
|
this.motionPhotoStartIndex,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +159,15 @@ Future<MediaUploadData> _getMediaUploadDataFromAssetFile(ente.File file) async {
|
||||||
h = asset.height;
|
h = asset.height;
|
||||||
w = asset.width;
|
w = asset.width;
|
||||||
}
|
}
|
||||||
|
int? motionPhotoStartingIndex;
|
||||||
|
if (io.Platform.isAndroid && asset.type == AssetType.image) {
|
||||||
|
try {
|
||||||
|
motionPhotoStartingIndex =
|
||||||
|
MotionPhotos(sourceFile.path).getMotionVideoIndex()?.start;
|
||||||
|
} catch (e) {
|
||||||
|
_logger.severe('error while detecthing motion photo start index', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
return MediaUploadData(
|
return MediaUploadData(
|
||||||
sourceFile,
|
sourceFile,
|
||||||
thumbnailData,
|
thumbnailData,
|
||||||
|
@ -161,6 +175,7 @@ Future<MediaUploadData> _getMediaUploadDataFromAssetFile(ente.File file) async {
|
||||||
FileHashData(fileHash, zipHash: zipHash),
|
FileHashData(fileHash, zipHash: zipHash),
|
||||||
height: h,
|
height: h,
|
||||||
width: w,
|
width: w,
|
||||||
|
motionPhotoStartIndex: motionPhotoStartingIndex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ description: ente photos application
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
|
|
||||||
version: 0.7.45+445
|
version: 0.7.47+447
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.17.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
|
|
Loading…
Add table
Reference in a new issue