From 0d56c636a27afd8789680762aee365c8098f556d Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 1 May 2023 16:17:31 +0530 Subject: [PATCH] Support for playing motion photos --- lib/ui/viewer/file/file_widget.dart | 19 ++++----- lib/ui/viewer/file/zoomable_live_image.dart | 45 ++++++++++++++++++--- pubspec.lock | 15 +++++-- pubspec.yaml | 2 + 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/lib/ui/viewer/file/file_widget.dart b/lib/ui/viewer/file/file_widget.dart index cebba16b8..af05e972e 100644 --- a/lib/ui/viewer/file/file_widget.dart +++ b/lib/ui/viewer/file/file_widget.dart @@ -3,7 +3,6 @@ import 'package:logging/logging.dart'; import 'package:photos/models/file.dart'; import 'package:photos/models/file_type.dart'; import 'package:photos/ui/viewer/file/video_widget.dart'; -import 'package:photos/ui/viewer/file/zoomable_image.dart'; import 'package:photos/ui/viewer/file/zoomable_live_image.dart'; class FileWidget extends StatelessWidget { @@ -26,14 +25,16 @@ class FileWidget extends StatelessWidget { @override Widget build(BuildContext context) { - if (file.fileType == FileType.image) { - return ZoomableImage( - file, - shouldDisableScroll: shouldDisableScroll, - tagPrefix: tagPrefix, - backgroundDecoration: backgroundDecoration, - ); - } else if (file.fileType == FileType.livePhoto) { + // if (file.fileType == FileType.image) { + // return ZoomableImage( + // file, + // shouldDisableScroll: shouldDisableScroll, + // tagPrefix: tagPrefix, + // backgroundDecoration: backgroundDecoration, + // ); + // } + if (file.fileType == FileType.livePhoto || + file.fileType == FileType.image) { return ZoomableLiveImage( file, shouldDisableScroll: shouldDisableScroll, diff --git a/lib/ui/viewer/file/zoomable_live_image.dart b/lib/ui/viewer/file/zoomable_live_image.dart index a646f2149..929e95847 100644 --- a/lib/ui/viewer/file/zoomable_live_image.dart +++ b/lib/ui/viewer/file/zoomable_live_image.dart @@ -1,11 +1,14 @@ import 'dart:io' as io; +import "dart:io"; import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; +import 'package:motion_photos/motion_photos.dart'; import 'package:photos/core/constants.dart'; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file.dart'; +import "package:photos/models/file_type.dart"; import 'package:photos/ui/viewer/file/zoomable_image.dart'; import 'package:photos/utils/file_util.dart'; import 'package:photos/utils/toast_util.dart'; @@ -119,6 +122,19 @@ class _ZoomableLiveImageState extends State return; } _isLoadingVideoPlayer = true; + io.File? videoFile = _file.fileType == FileType.livePhoto + ? await _getLivePhotoVideo() + : await _getMotionPhotoVideo(); + + if (videoFile != null && videoFile.existsSync()) { + _setVideoPlayerController(file: videoFile); + } else if (_file.fileType == FileType.livePhoto) { + showShortToast(context, S.of(context).downloadFailed); + } + _isLoadingVideoPlayer = false; + } + + Future _getLivePhotoVideo() async { if (_file.isRemoteFile && !(await isFileCached(_file, liveVideo: true))) { showShortToast(context, S.of(context).downloading); } @@ -142,13 +158,32 @@ class _ZoomableLiveImageState extends State return null; }); } + return videoFile; + } - if (videoFile != null && videoFile.existsSync()) { - _setVideoPlayerController(file: videoFile); - } else { - showShortToast(context, S.of(context).downloadFailed); + Future _getMotionPhotoVideo() async { + if (_file.isRemoteFile && !(await isFileCached(_file))) { + showShortToast(context, S.of(context).downloading); } - _isLoadingVideoPlayer = false; + + final io.File? imageFile = await getFile( + widget.file, + isOrigin: !Platform.isAndroid, + ).timeout(const Duration(seconds: 15)).onError((dynamic e, s) { + _logger.info("getFile failed ${_file.tag}", e); + return null; + }); + if (imageFile != null) { + final motionPhoto = MotionPhotos(imageFile.path); + final index = motionPhoto.getMotionVideoIndex(); + if (index != null) { + return motionPhoto.getMotionVideoFile( + index: index, + ); + } + } + + return null; } VideoPlayerController _setVideoPlayerController({required io.File file}) { diff --git a/pubspec.lock b/pubspec.lock index 71935b381..cba57acc4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1180,6 +1180,15 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0-pre" + motion_photos: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: ceeaff6e16bd9e3c98e7da2b1109dc04a93098b9 + url: "https://github.com/ente-io/motion_photo.git" + source: git + version: "0.0.1" motionphoto: dependency: "direct main" description: @@ -1337,10 +1346,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: c7edf82217d4b2952b2129a61d3ad60f1075b9299e629e149a8d2e39c2e6aad4 url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.14" path_provider_android: dependency: transitive description: @@ -2169,5 +2178,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.19.0 <3.0.0" + dart: ">=2.19.2 <3.0.0" flutter: ">=3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2b2e436ac..b38dbdacf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -83,6 +83,8 @@ dependencies: lottie: ^1.2.2 media_extension: ^1.0.1 modal_bottom_sheet: ^3.0.0-pre + motion_photos: + git: "https://github.com/ente-io/motion_photo.git" motionphoto: git: "https://github.com/ente-io/motionphoto.git" move_to_background: ^1.0.2