|
@@ -9,7 +9,6 @@ import 'package:photos/core/constants.dart';
|
|
import "package:photos/generated/l10n.dart";
|
|
import "package:photos/generated/l10n.dart";
|
|
import "package:photos/models/file/extensions/file_props.dart";
|
|
import "package:photos/models/file/extensions/file_props.dart";
|
|
import 'package:photos/models/file/file.dart';
|
|
import 'package:photos/models/file/file.dart';
|
|
-import 'package:photos/models/file/file_type.dart';
|
|
|
|
import "package:photos/models/metadata/file_magic.dart";
|
|
import "package:photos/models/metadata/file_magic.dart";
|
|
import "package:photos/services/file_magic_service.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';
|
|
@@ -19,13 +18,13 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:video_player/video_player.dart';
|
|
import 'package:video_player/video_player.dart';
|
|
|
|
|
|
class ZoomableLiveImage extends StatefulWidget {
|
|
class ZoomableLiveImage extends StatefulWidget {
|
|
- final EnteFile file;
|
|
|
|
|
|
+ final EnteFile enteFile;
|
|
final Function(bool)? shouldDisableScroll;
|
|
final Function(bool)? shouldDisableScroll;
|
|
final String? tagPrefix;
|
|
final String? tagPrefix;
|
|
final Decoration? backgroundDecoration;
|
|
final Decoration? backgroundDecoration;
|
|
|
|
|
|
const ZoomableLiveImage(
|
|
const ZoomableLiveImage(
|
|
- this.file, {
|
|
|
|
|
|
+ this.enteFile, {
|
|
Key? key,
|
|
Key? key,
|
|
this.shouldDisableScroll,
|
|
this.shouldDisableScroll,
|
|
required this.tagPrefix,
|
|
required this.tagPrefix,
|
|
@@ -39,7 +38,7 @@ class ZoomableLiveImage extends StatefulWidget {
|
|
class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
with SingleTickerProviderStateMixin {
|
|
with SingleTickerProviderStateMixin {
|
|
final Logger _logger = Logger("ZoomableLiveImage");
|
|
final Logger _logger = Logger("ZoomableLiveImage");
|
|
- late EnteFile _file;
|
|
|
|
|
|
+ late EnteFile _enteFile;
|
|
bool _showVideo = false;
|
|
bool _showVideo = false;
|
|
bool _isLoadingVideoPlayer = false;
|
|
bool _isLoadingVideoPlayer = false;
|
|
|
|
|
|
@@ -48,7 +47,7 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
|
|
|
|
@override
|
|
@override
|
|
void initState() {
|
|
void initState() {
|
|
- _file = widget.file;
|
|
|
|
|
|
+ _enteFile = widget.enteFile;
|
|
Future.microtask(() => _showHintForMotionPhotoPlay).ignore();
|
|
Future.microtask(() => _showHintForMotionPhotoPlay).ignore();
|
|
super.initState();
|
|
super.initState();
|
|
}
|
|
}
|
|
@@ -77,7 +76,7 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
content = _getVideoPlayer();
|
|
content = _getVideoPlayer();
|
|
} else {
|
|
} else {
|
|
content = ZoomableImage(
|
|
content = ZoomableImage(
|
|
- _file,
|
|
|
|
|
|
+ _enteFile,
|
|
tagPrefix: widget.tagPrefix,
|
|
tagPrefix: widget.tagPrefix,
|
|
shouldDisableScroll: widget.shouldDisableScroll,
|
|
shouldDisableScroll: widget.shouldDisableScroll,
|
|
backgroundDecoration: widget.backgroundDecoration,
|
|
backgroundDecoration: widget.backgroundDecoration,
|
|
@@ -125,27 +124,30 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
_isLoadingVideoPlayer = true;
|
|
_isLoadingVideoPlayer = true;
|
|
- final File? videoFile = _file.fileType == FileType.livePhoto
|
|
|
|
|
|
+ // For non-live photo, with fileType as Image, we still call _getMotionPhoto
|
|
|
|
+ // to check if it is a motion photo. This is needed to handle earlier
|
|
|
|
+ // uploads and upload from desktop
|
|
|
|
+ final File? videoFile = _enteFile.isLivePhoto
|
|
? await _getLivePhotoVideo()
|
|
? await _getLivePhotoVideo()
|
|
: await _getMotionPhotoVideo();
|
|
: await _getMotionPhotoVideo();
|
|
|
|
|
|
if (videoFile != null && videoFile.existsSync()) {
|
|
if (videoFile != null && videoFile.existsSync()) {
|
|
_setVideoPlayerController(file: videoFile);
|
|
_setVideoPlayerController(file: videoFile);
|
|
- } else if (_file.fileType == FileType.livePhoto) {
|
|
|
|
|
|
+ } else if (_enteFile.isLivePhoto) {
|
|
showShortToast(context, S.of(context).downloadFailed);
|
|
showShortToast(context, S.of(context).downloadFailed);
|
|
}
|
|
}
|
|
_isLoadingVideoPlayer = false;
|
|
_isLoadingVideoPlayer = false;
|
|
}
|
|
}
|
|
|
|
|
|
Future<File?> _getLivePhotoVideo() async {
|
|
Future<File?> _getLivePhotoVideo() async {
|
|
- if (_file.isRemoteFile && !(await isFileCached(_file, liveVideo: true))) {
|
|
|
|
|
|
+ if (_enteFile.isRemoteFile && !(await isFileCached(_enteFile, liveVideo: true))) {
|
|
showShortToast(context, S.of(context).downloading);
|
|
showShortToast(context, S.of(context).downloading);
|
|
}
|
|
}
|
|
|
|
|
|
- File? videoFile = await getFile(widget.file, liveVideo: true)
|
|
|
|
|
|
+ File? videoFile = await getFile(widget.enteFile, liveVideo: true)
|
|
.timeout(const Duration(seconds: 15))
|
|
.timeout(const Duration(seconds: 15))
|
|
.onError((dynamic e, s) {
|
|
.onError((dynamic e, s) {
|
|
- _logger.info("getFile failed ${_file.tag}", e);
|
|
|
|
|
|
+ _logger.info("getFile failed ${_enteFile.tag}", e);
|
|
return null;
|
|
return null;
|
|
});
|
|
});
|
|
|
|
|
|
@@ -153,11 +155,11 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
// getFile with liveVideo as true can fail for file with localID when
|
|
// getFile with liveVideo as true can fail for file with localID when
|
|
// the live photo was downloaded from remote.
|
|
// the live photo was downloaded from remote.
|
|
if ((videoFile == null || !videoFile.existsSync()) &&
|
|
if ((videoFile == null || !videoFile.existsSync()) &&
|
|
- _file.uploadedFileID != null) {
|
|
|
|
- videoFile = await getFileFromServer(widget.file, liveVideo: true)
|
|
|
|
|
|
+ _enteFile.uploadedFileID != null) {
|
|
|
|
+ videoFile = await getFileFromServer(widget.enteFile, liveVideo: true)
|
|
.timeout(const Duration(seconds: 15))
|
|
.timeout(const Duration(seconds: 15))
|
|
.onError((dynamic e, s) {
|
|
.onError((dynamic e, s) {
|
|
- _logger.info("getRemoteFile failed ${_file.tag}", e);
|
|
|
|
|
|
+ _logger.info("getRemoteFile failed ${_enteFile.tag}", e);
|
|
return null;
|
|
return null;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
@@ -165,25 +167,25 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
}
|
|
}
|
|
|
|
|
|
Future<File?> _getMotionPhotoVideo() async {
|
|
Future<File?> _getMotionPhotoVideo() async {
|
|
- if (_file.isRemoteFile && !(await isFileCached(_file))) {
|
|
|
|
|
|
+ if (_enteFile.isRemoteFile && !(await isFileCached(_enteFile))) {
|
|
showShortToast(context, S.of(context).downloading);
|
|
showShortToast(context, S.of(context).downloading);
|
|
}
|
|
}
|
|
|
|
|
|
final File? imageFile = await getFile(
|
|
final File? imageFile = await getFile(
|
|
- widget.file,
|
|
|
|
|
|
+ widget.enteFile,
|
|
isOrigin: !Platform.isAndroid,
|
|
isOrigin: !Platform.isAndroid,
|
|
).timeout(const Duration(seconds: 15)).onError((dynamic e, s) {
|
|
).timeout(const Duration(seconds: 15)).onError((dynamic e, s) {
|
|
- _logger.info("getFile failed ${_file.tag}", e);
|
|
|
|
|
|
+ _logger.info("getFile failed ${_enteFile.tag}", e);
|
|
return null;
|
|
return null;
|
|
});
|
|
});
|
|
if (imageFile != null) {
|
|
if (imageFile != null) {
|
|
final motionPhoto = MotionPhotos(imageFile.path);
|
|
final motionPhoto = MotionPhotos(imageFile.path);
|
|
final index = await motionPhoto.getMotionVideoIndex();
|
|
final index = await motionPhoto.getMotionVideoIndex();
|
|
if (index != null) {
|
|
if (index != null) {
|
|
- if (widget.file.pubMagicMetadata?.mvi == null &&
|
|
|
|
- (widget.file.ownerID ?? 0) == Configuration.instance.getUserID()!) {
|
|
|
|
|
|
+ if (widget.enteFile.pubMagicMetadata?.mvi == null &&
|
|
|
|
+ (widget.enteFile.ownerID ?? 0) == Configuration.instance.getUserID()!) {
|
|
FileMagicService.instance.updatePublicMagicMetadata(
|
|
FileMagicService.instance.updatePublicMagicMetadata(
|
|
- [widget.file],
|
|
|
|
|
|
+ [widget.enteFile],
|
|
{motionVideoIndexKey: index.start},
|
|
{motionVideoIndexKey: index.start},
|
|
).ignore();
|
|
).ignore();
|
|
}
|
|
}
|
|
@@ -209,7 +211,7 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
|
|
}
|
|
}
|
|
|
|
|
|
void _showHintForMotionPhotoPlay() async {
|
|
void _showHintForMotionPhotoPlay() async {
|
|
- if (!_file.isLiveOrMotionPhoto) {
|
|
|
|
|
|
+ if (!_enteFile.isLiveOrMotionPhoto) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
final preferences = await SharedPreferences.getInstance();
|
|
final preferences = await SharedPreferences.getInstance();
|