perf: improve full screen media animations

This commit is contained in:
Gordon Hayes
2022-02-21 12:19:36 +01:00
parent d2a0fd603d
commit 2cef539639
@@ -65,24 +65,35 @@ class FullScreenMedia extends StatefulWidget {
class _FullScreenMediaState extends State<FullScreenMedia>
with SingleTickerProviderStateMixin {
bool _optionsShown = true;
late final AnimationController _controller;
late final AnimationController _animationController;
late final PageController _pageController;
late int _currentPage;
late final _curvedAnimation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeOut,
reverseCurve: Curves.easeIn,
);
final _opacityTween = Tween<double>(begin: 1, end: 0);
late final _opacityAnimation = _opacityTween.animate(
CurvedAnimation(
parent: _animationController,
curve: const Interval(0, 0.6, curve: Curves.easeOut),
),
);
late final ValueNotifier<int> _currentPage = ValueNotifier(widget.startIndex);
final videoPackages = <String, VideoPackage>{};
@override
void initState() {
super.initState();
_controller = AnimationController(
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_pageController = PageController(initialPage: widget.startIndex);
_currentPage = widget.startIndex;
for (var i = 0; i < widget.mediaAttachments.length; i++) {
final attachment = widget.mediaAttachments[i];
if (attachment.type != 'video') continue;
@@ -116,14 +127,10 @@ class _FullScreenMediaState extends State<FullScreenMedia>
resizeToAvoidBottomInset: false,
body: Stack(
children: [
AnimatedBuilder(
animation: _controller,
builder: (context, snapshot) => PageView.builder(
PageView.builder(
controller: _pageController,
onPageChanged: (val) {
setState(() {
_currentPage = val;
});
_currentPage.value = val;
if (videoPackages.isEmpty) {
return;
@@ -145,12 +152,13 @@ class _FullScreenMediaState extends State<FullScreenMedia>
},
itemBuilder: (context, index) {
final attachment = widget.mediaAttachments[index];
if (attachment.type == 'image' ||
attachment.type == 'giphy') {
if (attachment.type == 'image' || attachment.type == 'giphy') {
final imageUrl = attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl;
return PhotoView(
return AnimatedBuilder(
animation: _curvedAnimation,
builder: (context, child) => PhotoView(
loadingBuilder: (context, image) => const Offstage(),
imageProvider: (imageUrl == null &&
attachment.localUri != null &&
@@ -166,18 +174,16 @@ class _FullScreenMediaState extends State<FullScreenMedia>
color: ColorTween(
begin: ChannelHeaderTheme.of(context).color,
end: Colors.black,
).lerp(_controller.value),
).lerp(_curvedAnimation.value),
),
onTapUp: (a, b, c) {
setState(() {
_optionsShown = !_optionsShown;
});
if (_controller.isCompleted) {
_controller.reverse();
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_controller.forward();
_animationController.forward();
}
},
),
);
} else if (attachment.type == 'video') {
final controller = videoPackages[attachment.id]!;
@@ -188,13 +194,10 @@ class _FullScreenMediaState extends State<FullScreenMedia>
}
return InkWell(
onTap: () {
setState(() {
_optionsShown = !_optionsShown;
});
if (_controller.isCompleted) {
_controller.reverse();
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_controller.forward();
_animationController.forward();
}
},
child: Padding(
@@ -207,15 +210,15 @@ class _FullScreenMediaState extends State<FullScreenMedia>
),
);
}
return Container();
return const SizedBox();
},
itemCount: widget.mediaAttachments.length,
),
),
AnimatedOpacity(
opacity: _optionsShown ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
child: Column(
FadeTransition(
opacity: _opacityAnimation,
child: ValueListenableBuilder<int>(
valueListenable: _currentPage,
builder: (context, value, child) => Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GalleryHeader(
@@ -228,7 +231,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
Navigator.of(context).pop();
},
message: widget.message,
currentIndex: _currentPage,
currentIndex: value,
onShowMessage: () {
widget.onShowMessage?.call(
widget.message,
@@ -240,32 +243,31 @@ class _FullScreenMediaState extends State<FullScreenMedia>
),
if (!widget.message.isEphemeral)
GalleryFooter(
currentPage: _currentPage,
currentPage: value,
totalPages: widget.mediaAttachments.length,
mediaAttachments: widget.mediaAttachments,
message: widget.message,
mediaSelectedCallBack: (val) {
setState(() {
_currentPage = val;
_currentPage.value = val;
_pageController.animateToPage(
val,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
Navigator.pop(context);
});
},
),
],
),
),
),
],
),
);
@override
void dispose() {
_controller.dispose();
_animationController.dispose();
_pageController.dispose();
for (final package in videoPackages.values) {
package.dispose();