LCOV - code coverage report
Current view: top level - lib - fullscreen_viewer.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 41 43 95.3 %
Date: 2023-11-20 15:59:28 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:math';
       2             : 
       3             : import 'package:flutter/material.dart';
       4             : 
       5             : class FullscreenViewer extends StatefulWidget {
       6             :   final Animation<double> openAnimation;
       7             :   final Widget? closeWidget;
       8             :   final Widget child;
       9             : 
      10           1 :   const FullscreenViewer({
      11             :     super.key,
      12             :     required this.openAnimation,
      13             :     required this.child,
      14             :     this.closeWidget,
      15             :   });
      16             : 
      17           1 :   @override
      18           1 :   State<FullscreenViewer> createState() => _FullscreenViewerState();
      19             : }
      20             : 
      21             : class _FullscreenViewerState extends State<FullscreenViewer> with TickerProviderStateMixin {
      22           9 :   double get dragCoef => min(1, (min(deltaController.value.abs(), 50) - 50).abs() / 50);
      23             :   double scale = 1;
      24           2 :   late final deltaController = AnimationController(
      25             :     vsync: this,
      26             :     upperBound: 300,
      27             :     lowerBound: -300,
      28             :     value: 0,
      29             :     duration: const Duration(milliseconds: 300),
      30             :   );
      31             : 
      32             :   final transformController = TransformationController();
      33             : 
      34           5 :   bool get scaled => (scale - 1).abs() > 0.01;
      35             :   bool canPop = true;
      36             : 
      37           1 :   @override
      38             :   void dispose() {
      39           2 :     deltaController.dispose();
      40           2 :     transformController.dispose();
      41           1 :     super.dispose();
      42             :   }
      43             : 
      44           1 :   @override
      45             :   Widget build(BuildContext context) {
      46           1 :     return Stack(
      47           1 :       children: [
      48           1 :         AnimatedBuilder(
      49           1 :           animation: deltaController,
      50           2 :           builder: (context, child) => AnimatedBuilder(
      51           2 :             animation: widget.openAnimation,
      52           2 :             builder: (context, _) => Container(
      53           6 :               color: Colors.black87.withOpacity(widget.openAnimation.value * dragCoef),
      54           1 :               child: Transform.translate(
      55           3 :                 offset: Offset(0, deltaController.value),
      56             :                 child: child,
      57             :               ),
      58             :             ),
      59             :           ),
      60           1 :           child: Center(
      61           1 :             child: InteractiveViewer(
      62             :               minScale: 1,
      63           1 :               transformationController: transformController,
      64           1 :               onInteractionEnd: (details) {
      65          11 :                 if (details.velocity.pixelsPerSecond.dy.abs() + deltaController.value.abs() > 50 && !scaled && canPop) {
      66           1 :                   Navigator.pop(context);
      67             :                 } else {
      68           2 :                   deltaController.animateTo(0.0);
      69             :                 }
      70           2 :                 if (details.pointerCount == 0) {
      71           1 :                   canPop = true;
      72             :                 }
      73             :               },
      74           1 :               onInteractionUpdate: (details) {
      75           2 :                 if (details.pointerCount > 1) {
      76           0 :                   canPop = false;
      77           0 :                   scale = details.scale.clamp(1, 2.5);
      78             :                 }
      79           2 :                 if (!scaled && canPop) {
      80           5 :                   deltaController.value += details.focalPointDelta.dy;
      81             :                 }
      82             :               },
      83             :               clipBehavior: Clip.none,
      84           2 :               child: widget.child,
      85             :             ),
      86             :           ),
      87             :         ),
      88           2 :         if (widget.closeWidget != null)
      89           1 :           Positioned(
      90             :             top: 8,
      91             :             right: 8,
      92           1 :             child: SafeArea(
      93           1 :               child: GestureDetector(
      94           2 :                 onTap: () => Navigator.pop(context),
      95           2 :                 child: widget.closeWidget,
      96             :               ),
      97             :             ),
      98             :           ),
      99             :       ],
     100             :     );
     101             :   }
     102             : }

Generated by: LCOV version 1.15