Merge branch 'internal-15_06_2025' of https://github.com/ente-io/auth into internal-15_06_2025

This commit is contained in:
Neeraj Gupta
2025-06-06 12:33:48 +05:30
12 changed files with 534 additions and 150 deletions

View File

@@ -1,20 +1,25 @@
import "dart:async";
import "dart:io";
import "dart:math";
import "dart:ui";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:photos/core/configuration.dart";
import "package:photos/models/file/file_type.dart";
import "package:photos/models/memories/memory.dart";
import "package:photos/service_locator.dart";
import "package:photos/services/smart_memories_service.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/theme/text_style.dart";
import "package:photos/ui/actions/file/file_actions.dart";
import "package:photos/ui/home/memories/memory_progress_indicator.dart";
import "package:photos/ui/viewer/file/file_widget.dart";
import "package:photos/ui/viewer/file/thumbnail_widget.dart";
import "package:photos/ui/viewer/file_details/favorite_widget.dart";
import "package:photos/utils/file_util.dart";
import "package:photos/utils/share_util.dart";
import "package:step_progress_indicator/step_progress_indicator.dart";
// import "package:step_progress_indicator/step_progress_indicator.dart";
//There are two states of variables that FullScreenMemory depends on:
//1. The list of memories
@@ -131,6 +136,10 @@ class FullScreenMemory extends StatefulWidget {
class _FullScreenMemoryState extends State<FullScreenMemory> {
PageController? _pageController;
final _showTitle = ValueNotifier<bool>(true);
AnimationController? _progressAnimationController;
AnimationController? _zoomAnimationController;
final ValueNotifier<Duration> durationNotifier =
ValueNotifier(const Duration(seconds: 5));
@override
void initState() {
@@ -148,13 +157,48 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
void dispose() {
_pageController?.dispose();
_showTitle.dispose();
durationNotifier.dispose();
super.dispose();
}
void _toggleAnimation(bool pause) {
if (_progressAnimationController != null) {
if (pause) {
_progressAnimationController!.stop();
} else {
_progressAnimationController!.forward();
}
}
if (_zoomAnimationController != null) {
if (pause) {
_zoomAnimationController!.stop();
} else {
_zoomAnimationController!.forward();
}
}
}
void onFinalFileLoad(int duration) {
if (_progressAnimationController!.isAnimating == true) {
_progressAnimationController!.stop();
}
durationNotifier.value = Duration(seconds: duration);
_progressAnimationController
?..stop()
..reset()
..duration = durationNotifier.value
..forward();
_zoomAnimationController
?..stop()
..reset()
..forward();
}
@override
Widget build(BuildContext context) {
final inheritedData = FullScreenMemoryData.of(context)!;
final showStepProgressIndicator = inheritedData.memories.length < 60;
return Scaffold(
backgroundColor: Colors.black,
extendBodyBehindAppBar: true,
@@ -180,17 +224,34 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
showStepProgressIndicator
? StepProgressIndicator(
totalSteps: inheritedData.memories.length,
currentStep: value + 1,
size: 2,
selectedColor: Colors.white, //same for both themes
unselectedColor: Colors.white.withOpacity(0.4),
? ValueListenableBuilder<Duration>(
valueListenable: durationNotifier,
builder: (context, duration, _) {
return NewProgressIndicator(
totalSteps: inheritedData.memories.length,
currentIndex: value,
selectedColor: Colors.white,
unselectedColor: Colors.white.withOpacity(0.4),
duration: duration,
animationController: (controller) {
_progressAnimationController = controller;
},
onComplete: () {
final currentIndex =
inheritedData.indexNotifier.value;
if (currentIndex <
inheritedData.memories.length - 1) {
_pageController!.nextPage(
duration: const Duration(milliseconds: 250),
curve: Curves.ease,
);
}
},
);
},
)
: const SizedBox.shrink(),
const SizedBox(
height: 10,
),
const SizedBox(height: 10),
Row(
children: [
child!,
@@ -231,16 +292,20 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
body: Stack(
alignment: Alignment.bottomCenter,
children: [
const MemoryBackDrop(),
PageView.builder(
controller: _pageController ??= PageController(
initialPage: widget.initialIndex,
),
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
if (index < inheritedData.memories.length - 1) {
final nextFile = inheritedData.memories[index + 1].file;
preloadThumbnail(nextFile);
preloadFile(nextFile);
}
final currentFile = inheritedData.memories[index].file;
final isVideo = currentFile.fileType == FileType.video;
return GestureDetector(
onTapDown: (TapDownDetails details) {
final screenWidth = MediaQuery.of(context).size.width;
@@ -262,17 +327,39 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
}
}
},
child: FileWidget(
inheritedData.memories[index].file,
autoPlay: false,
tagPrefix: "memories",
backgroundDecoration: const BoxDecoration(
color: Colors.transparent,
onLongPress: () {
_toggleAnimation(true);
},
onLongPressUp: () {
_toggleAnimation(false);
},
child: MemoriesZoomWidget(
scaleController: (controller) {
_zoomAnimationController = controller;
},
zoomIn: index % 2 == 0,
isVideo: isVideo,
child: FileWidget(
inheritedData.memories[index].file,
autoPlay: false,
tagPrefix: "memories",
backgroundDecoration: const BoxDecoration(
color: Colors.transparent,
),
isFromMemories: true,
playbackCallback: (isPlaying) {
isPlaying
? _toggleAnimation(false)
: _toggleAnimation(true);
},
onFinalFileLoad: (duration) {
onFinalFileLoad(duration);
},
),
),
);
},
onPageChanged: (index) {
onPageChanged: (index) async {
unawaited(
memoriesCacheService.markMemoryAsSeen(
inheritedData.memories[index],
@@ -450,3 +537,148 @@ class BottomGradient extends StatelessWidget {
);
}
}
class MemoryBackDrop extends StatelessWidget {
const MemoryBackDrop({super.key});
@override
Widget build(BuildContext context) {
final inheritedData = FullScreenMemoryData.of(context)!;
return ValueListenableBuilder(
valueListenable: inheritedData.indexNotifier,
builder: (context, value, _) {
final currentFile = inheritedData.memories[value].file;
if (currentFile.fileType == FileType.video ||
currentFile.fileType == FileType.livePhoto) {
return const SizedBox.shrink();
}
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: Stack(
children: [
Container(
width: double.infinity,
height: double.infinity,
color: Colors.transparent,
),
ThumbnailWidget(
currentFile,
shouldShowSyncStatus: false,
shouldShowFavoriteIcon: false,
),
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 100,
sigmaY: 100,
),
child: Container(
color: Colors.transparent,
),
),
],
),
);
},
);
}
}
class MemoriesZoomWidget extends StatefulWidget {
final Widget child;
final bool isVideo;
final void Function(AnimationController)? scaleController;
final bool zoomIn;
const MemoriesZoomWidget({
super.key,
required this.child,
required this.isVideo,
required this.zoomIn,
this.scaleController,
});
@override
State<MemoriesZoomWidget> createState() => _MemoriesZoomWidgetState();
}
class _MemoriesZoomWidgetState extends State<MemoriesZoomWidget>
with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _scaleAnimation;
late Animation<Offset> _panAnimation;
Random random = Random();
@override
void initState() {
super.initState();
_initAnimation();
}
void _initAnimation() {
_controller = AnimationController(
vsync: this,
duration: const Duration(
seconds: 5,
),
);
final startScale = widget.zoomIn ? 1.05 : 1.15;
final endScale = widget.zoomIn ? 1.15 : 1.05;
final startX = (random.nextDouble() - 0.5) * 0.1;
final startY = (random.nextDouble() - 0.5) * 0.1;
final endX = (random.nextDouble() - 0.5) * 0.1;
final endY = (random.nextDouble() - 0.5) * 0.1;
_scaleAnimation = Tween<double>(
begin: startScale,
end: endScale,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
_panAnimation = Tween<Offset>(
begin: Offset(startX, startY),
end: Offset(endX, endY),
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
if (widget.scaleController != null) {
widget.scaleController!(_controller);
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.isVideo
? widget.child
: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.scale(
scale: _scaleAnimation.value,
child: Transform.translate(
offset: Offset(
_panAnimation.value.dx * 100,
_panAnimation.value.dy * 100,
),
child: widget.child,
),
);
},
);
}
}

View File

@@ -130,17 +130,11 @@ class _MemoriesWidgetState extends State<MemoriesWidget> {
controller: _controller,
itemCount: collatedMemories.length,
itemBuilder: (context, itemIndex) {
final maxScaleOffsetX =
_maxWidth + MemoryCoverWidget.horizontalPadding * 2;
final offsetOfItem =
(_maxWidth + MemoryCoverWidget.horizontalPadding * 2) * itemIndex;
return MemoryCoverWidget(
memories: collatedMemories[itemIndex].$1,
controller: _controller,
offsetOfItem: offsetOfItem,
maxHeight: _maxHeight,
maxWidth: _maxWidth,
maxScaleOffsetX: maxScaleOffsetX,
title: collatedMemories[itemIndex].$2,
);
},

View File

@@ -11,22 +11,18 @@ import "package:photos/utils/navigation_util.dart";
class MemoryCoverWidget extends StatefulWidget {
final List<Memory> memories;
final ScrollController controller;
final double offsetOfItem;
final double maxHeight;
final double maxWidth;
static const outerStrokeWidth = 1.0;
static const aspectRatio = 0.68;
static const horizontalPadding = 2.5;
final double maxScaleOffsetX;
final String title;
const MemoryCoverWidget({
required this.memories,
required this.controller,
required this.offsetOfItem,
required this.maxHeight,
required this.maxWidth,
required this.maxScaleOffsetX,
required this.title,
super.key,
});
@@ -44,7 +40,6 @@ class _MemoryCoverWidgetState extends State<MemoryCoverWidget> {
return const SizedBox.shrink();
}
final widthOfScreen = MediaQuery.sizeOf(context).width;
final index = _getNextMemoryIndex();
final title = widget.title;
@@ -56,9 +51,6 @@ class _MemoryCoverWidgetState extends State<MemoryCoverWidget> {
return AnimatedBuilder(
animation: widget.controller,
builder: (context, child) {
final diff = (widget.controller.offset - widget.offsetOfItem) +
widget.maxScaleOffsetX;
final scale = 1 - (diff / widthOfScreen).abs() / 3.7;
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: MemoryCoverWidget.horizontalPadding,
@@ -81,8 +73,8 @@ class _MemoryCoverWidgetState extends State<MemoryCoverWidget> {
child: Row(
children: [
Container(
height: widget.maxHeight * scale,
width: widget.maxWidth * scale,
height: widget.maxHeight ,
width: widget.maxWidth ,
decoration: BoxDecoration(
boxShadow: brightness == Brightness.dark
? [
@@ -122,29 +114,26 @@ class _MemoryCoverWidgetState extends State<MemoryCoverWidget> {
),
),
Positioned(
bottom: 8 * scale,
child: Transform.scale(
scale: scale,
child: SizedBox(
width: widget.maxWidth,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
),
child: Hero(
tag: title,
child: Center(
child: Text(
title,
style: getEnteTextTheme(context)
.miniBold
.copyWith(
color: isSeen
? textFaintDark
: Colors.white,
),
textAlign: TextAlign.left,
),
bottom: 8 ,
child: SizedBox(
width: widget.maxWidth,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
),
child: Hero(
tag: title,
child: Center(
child: Text(
title,
style: getEnteTextTheme(context)
.miniBold
.copyWith(
color: isSeen
? textFaintDark
: Colors.white,
),
textAlign: TextAlign.left,
),
),
),
@@ -173,27 +162,24 @@ class _MemoryCoverWidgetState extends State<MemoryCoverWidget> {
),
),
Positioned(
bottom: 8 * scale,
child: Transform.scale(
scale: scale,
child: SizedBox(
width: widget.maxWidth,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
),
child: Hero(
tag: title,
child: Center(
child: Text(
title,
style: getEnteTextTheme(context)
.miniBold
.copyWith(
color: Colors.white,
),
textAlign: TextAlign.left,
),
bottom: 8 ,
child: SizedBox(
width: widget.maxWidth,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
),
child: Hero(
tag: title,
child: Center(
child: Text(
title,
style: getEnteTextTheme(context)
.miniBold
.copyWith(
color: Colors.white,
),
textAlign: TextAlign.left,
),
),
),

View File

@@ -0,0 +1,106 @@
import "package:flutter/material.dart";
class NewProgressIndicator extends StatefulWidget {
final int totalSteps;
final int currentIndex;
final Duration duration;
final Color selectedColor;
final Color unselectedColor;
final double height;
final double gap;
final void Function(AnimationController)? animationController;
final VoidCallback? onComplete;
const NewProgressIndicator({
super.key,
required this.totalSteps,
required this.currentIndex,
this.duration = const Duration(seconds: 5),
this.selectedColor = Colors.white,
this.unselectedColor = Colors.white54,
this.height = 2.0,
this.gap = 4.0,
this.animationController,
this.onComplete,
});
@override
State<NewProgressIndicator> createState() => _NewProgressIndicatorState();
}
class _NewProgressIndicatorState extends State<NewProgressIndicator>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: widget.duration,
);
_animation =
Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
if (widget.animationController != null) {
widget.animationController!(_animationController);
}
_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed && widget.onComplete != null) {
widget.onComplete!();
}
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Row(
children: List.generate(widget.totalSteps, (index) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 4, right: 4),
child: index < widget.currentIndex
? Container(
height: widget.height,
decoration: BoxDecoration(
color: widget.selectedColor,
borderRadius: BorderRadius.circular(2),
),
)
: index == widget.currentIndex
? AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return LinearProgressIndicator(
value: _animation.value,
backgroundColor: widget.unselectedColor,
valueColor: AlwaysStoppedAnimation<Color>(
widget.selectedColor,
),
minHeight: widget.height,
borderRadius: BorderRadius.circular(2),
);
},
)
: Container(
height: widget.height,
decoration: BoxDecoration(
color: widget.unselectedColor,
borderRadius: BorderRadius.circular(2),
),
),
),
);
}),
);
}
}

View File

@@ -12,6 +12,8 @@ class FileWidget extends StatelessWidget {
final Function(bool)? playbackCallback;
final BoxDecoration? backgroundDecoration;
final bool? autoPlay;
final bool? isFromMemories;
final Function(int)? onFinalFileLoad;
const FileWidget(
this.file, {
@@ -20,6 +22,8 @@ class FileWidget extends StatelessWidget {
this.playbackCallback,
required this.tagPrefix,
this.backgroundDecoration,
this.isFromMemories = false,
this.onFinalFileLoad,
super.key,
});
@@ -37,7 +41,9 @@ class FileWidget extends StatelessWidget {
shouldDisableScroll: shouldDisableScroll,
tagPrefix: tagPrefix,
backgroundDecoration: backgroundDecoration,
isFromMemories: isFromMemories ?? false,
key: key ?? ValueKey(fileKey),
onFinalFileLoad: onFinalFileLoad,
);
} else if (file.fileType == FileType.video) {
// use old video widget on iOS simulator as the new one crashes while
@@ -54,6 +60,8 @@ class FileWidget extends StatelessWidget {
file,
tagPrefix: tagPrefix,
playbackCallback: playbackCallback,
onFinalFileLoad: onFinalFileLoad,
isFromMemories: isFromMemories ?? false,
key: key ?? ValueKey(fileKey),
);
} else {

View File

@@ -23,10 +23,15 @@ class VideoWidget extends StatefulWidget {
final EnteFile file;
final String? tagPrefix;
final Function(bool)? playbackCallback;
final Function(int)? onFinalFileLoad;
final bool isFromMemories;
const VideoWidget(
this.file, {
this.tagPrefix,
this.playbackCallback,
this.onFinalFileLoad,
this.isFromMemories = false,
super.key,
});
@@ -149,6 +154,7 @@ class _VideoWidgetState extends State<VideoWidget> {
playbackCallback: widget.playbackCallback,
playlistData: playlistData,
selectedPreview: playPreview,
isFromMemories: widget.isFromMemories,
onStreamChange: () {
setState(() {
selectPreviewForPlay = !selectPreviewForPlay;
@@ -162,6 +168,7 @@ class _VideoWidgetState extends State<VideoWidget> {
);
});
},
onFinalFileLoad: widget.onFinalFileLoad,
);
}
return VideoWidgetMediaKitNew(
@@ -171,6 +178,7 @@ class _VideoWidgetState extends State<VideoWidget> {
playbackCallback: widget.playbackCallback,
preview: playlistData?.preview,
selectedPreview: playPreview,
isFromMemories: widget.isFromMemories,
onStreamChange: () {
setState(() {
selectPreviewForPlay = !selectPreviewForPlay;
@@ -184,6 +192,7 @@ class _VideoWidgetState extends State<VideoWidget> {
);
});
},
onFinalFileLoad: widget.onFinalFileLoad,
);
}
}

View File

@@ -100,6 +100,7 @@ class _VideoWidgetState extends State<VideoWidget> {
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (widget.isFromMemories) return;
showControlsNotifier.value = !showControlsNotifier.value;
if (widget.playbackCallback != null) {
widget.playbackCallback!(
@@ -107,48 +108,62 @@ class _VideoWidgetState extends State<VideoWidget> {
);
}
},
onLongPress: () {
if (widget.isFromMemories) {
widget.controller.player.stop();
}
},
onLongPressUp: () {
if (widget.isFromMemories) {
widget.controller.player.play();
}
},
child: Container(
constraints: const BoxConstraints.expand(),
),
),
IgnorePointer(
ignoring: !value,
child: PlayPauseButtonMediaKit(widget.controller),
),
Positioned(
bottom: verticalMargin,
right: 0,
left: 0,
child: IgnorePointer(
ignoring: !value,
child: SafeArea(
top: false,
left: false,
right: false,
child: Padding(
padding: EdgeInsets.only(
bottom: widget.isFromMemories ? 32 : 0,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
VideoStreamChangeWidget(
showControls: value,
file: widget.file,
isPreviewPlayer: widget.isPreviewPlayer,
onStreamChange: widget.onStreamChange,
widget.isFromMemories
? const SizedBox.shrink()
: IgnorePointer(
ignoring: !value,
child: PlayPauseButtonMediaKit(widget.controller),
),
widget.isFromMemories
? const SizedBox.shrink()
: Positioned(
bottom: verticalMargin,
right: 0,
left: 0,
child: IgnorePointer(
ignoring: !value,
child: SafeArea(
top: false,
left: false,
right: false,
child: Padding(
padding: EdgeInsets.only(
bottom: widget.isFromMemories ? 32 : 0,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
VideoStreamChangeWidget(
showControls: value,
file: widget.file,
isPreviewPlayer: widget.isPreviewPlayer,
onStreamChange: widget.onStreamChange,
),
SeekBarAndDuration(
controller: widget.controller,
isSeekingNotifier: _isSeekingNotifier,
file: widget.file,
),
],
),
),
SeekBarAndDuration(
controller: widget.controller,
isSeekingNotifier: _isSeekingNotifier,
file: widget.file,
),
],
),
),
),
),
),
),
],
),
);

View File

@@ -36,6 +36,7 @@ class VideoWidgetMediaKitNew extends StatefulWidget {
final void Function() onStreamChange;
final File? preview;
final bool selectedPreview;
final Function(int)? onFinalFileLoad;
const VideoWidgetMediaKitNew(
this.file, {
@@ -45,6 +46,7 @@ class VideoWidgetMediaKitNew extends StatefulWidget {
required this.onStreamChange,
this.preview,
required this.selectedPreview,
this.onFinalFileLoad,
super.key,
});
@@ -307,6 +309,8 @@ class _VideoWidgetMediaKitNewState extends State<VideoWidgetMediaKitNew>
}
player.open(Media(url), play: _isAppInFG);
});
final duration = controller!.player.state.duration.inSeconds;
widget.onFinalFileLoad?.call(duration);
}
}
}

View File

@@ -46,6 +46,7 @@ class VideoWidgetNative extends StatefulWidget {
final void Function()? onStreamChange;
final PlaylistData? playlistData;
final bool selectedPreview;
final Function(int)? onFinalFileLoad;
const VideoWidgetNative(
this.file, {
@@ -55,6 +56,7 @@ class VideoWidgetNative extends StatefulWidget {
required this.onStreamChange,
super.key,
this.playlistData,
this.onFinalFileLoad,
required this.selectedPreview,
});
@@ -302,12 +304,23 @@ class _VideoWidgetNativeState extends State<VideoWidgetNative>
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (widget.isFromMemories) return;
_showControls.value = !_showControls.value;
if (widget.playbackCallback != null) {
widget.playbackCallback!(!_showControls.value);
}
_elTooltipController.hide();
},
onLongPress: () {
if (widget.isFromMemories) {
_controller?.pause();
}
},
onLongPressUp: () {
if (widget.isFromMemories) {
_controller?.play();
}
},
child: Container(
constraints: const BoxConstraints.expand(),
),
@@ -331,32 +344,38 @@ class _VideoWidgetNativeState extends State<VideoWidgetNative>
),
)
: const SizedBox.shrink(),
Positioned.fill(
child: Center(
child: ValueListenableBuilder(
builder: (BuildContext context, bool value, _) {
return value
? ValueListenableBuilder(
builder: (context, bool value, _) {
return AnimatedOpacity(
duration:
const Duration(milliseconds: 200),
opacity: value ? 1 : 0,
curve: Curves.easeInOutQuad,
child: IgnorePointer(
ignoring: !value,
child: PlayPauseButton(_controller),
),
);
},
valueListenable: _showControls,
)
: const SizedBox();
},
valueListenable: _isPlaybackReady,
),
),
),
widget.isFromMemories
? const SizedBox.shrink()
: Positioned.fill(
child: Center(
child: ValueListenableBuilder(
builder:
(BuildContext context, bool value, _) {
return value
? ValueListenableBuilder(
builder: (context, bool value, _) {
return AnimatedOpacity(
duration: const Duration(
milliseconds: 200,
),
opacity: value ? 1 : 0,
curve: Curves.easeInOutQuad,
child: IgnorePointer(
ignoring: !value,
child: PlayPauseButton(
_controller,
),
),
);
},
valueListenable: _showControls,
)
: const SizedBox();
},
valueListenable: _isPlaybackReady,
),
),
),
Positioned(
bottom: verticalMargin,
right: 0,
@@ -394,7 +413,7 @@ class _VideoWidgetNativeState extends State<VideoWidgetNative>
valueListenable: _isPlaybackReady,
builder:
(BuildContext context, bool value, _) {
return value
return value && !widget.isFromMemories
? _SeekBarAndDuration(
controller: _controller,
duration: duration,
@@ -525,6 +544,8 @@ class _VideoWidgetNativeState extends State<VideoWidgetNative>
Future<void> _onPlaybackReady() async {
if (_isPlaybackReady.value) return;
await _controller!.play();
final durationInSeconds = durationToSeconds(duration) ?? 0;
widget.onFinalFileLoad?.call(durationInSeconds);
unawaited(_controller!.setVolume(1));
_isPlaybackReady.value = true;
}
@@ -739,11 +760,7 @@ class _SeekBarAndDuration extends StatelessWidget {
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: showControls,
builder: (
BuildContext context,
bool value,
_,
) {
builder: (BuildContext context, bool value, _) {
return AnimatedOpacity(
duration: const Duration(
milliseconds: 200,

View File

@@ -31,6 +31,7 @@ class ZoomableImage extends StatefulWidget {
final Decoration? backgroundDecoration;
final bool shouldCover;
final bool isGuestView;
final Function(int)? onFinalFileLoad;
const ZoomableImage(
this.photo, {
@@ -40,6 +41,7 @@ class ZoomableImage extends StatefulWidget {
this.backgroundDecoration,
this.shouldCover = false,
this.isGuestView = false,
this.onFinalFileLoad,
});
@override
@@ -426,6 +428,9 @@ class _ZoomableImageState extends State<ZoomableImage> {
_loadedFinalImage = true;
_logger.info("Final image loaded");
});
if (_imageProvider != null) {
widget.onFinalFileLoad?.call(5);
}
}
Future<void> _updatePhotoViewController({

View File

@@ -23,6 +23,8 @@ class ZoomableLiveImageNew extends StatefulWidget {
final Function(bool)? shouldDisableScroll;
final String? tagPrefix;
final Decoration? backgroundDecoration;
final bool isFromMemories;
final Function(int)? onFinalFileLoad;
const ZoomableLiveImageNew(
this.enteFile, {
@@ -30,6 +32,8 @@ class ZoomableLiveImageNew extends StatefulWidget {
this.shouldDisableScroll,
required this.tagPrefix,
this.backgroundDecoration,
this.isFromMemories = false,
this.onFinalFileLoad,
});
@override
@@ -94,13 +98,17 @@ class _ZoomableLiveImageNewState extends State<ZoomableLiveImageNew>
shouldDisableScroll: widget.shouldDisableScroll,
backgroundDecoration: widget.backgroundDecoration,
isGuestView: isGuestView,
onFinalFileLoad: widget.onFinalFileLoad,
);
}
return GestureDetector(
onLongPressStart: (_) => {_onLongPressEvent(true)},
onLongPressEnd: (_) => {_onLongPressEvent(false)},
child: content,
);
if (!widget.isFromMemories) {
return GestureDetector(
onLongPressStart: (_) => _onLongPressEvent(true),
onLongPressEnd: (_) => _onLongPressEvent(false),
child: content,
);
}
return content;
}
@override

View File

@@ -12,7 +12,7 @@ description: ente photos application
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.2+1055
version: 1.1.2+1056
publish_to: none
environment: