content: import 'package:fl_clash/common/common.dart';
  import 'package:fl_clash/enum/enum.dart';
  import 'package:fl_clash/models/models.dart';
  import 'package:fl_clash/state.dart';
  import 'package:flutter/material.dart';
  
  class BaseNavigator {
    static Future<T?> push<T>(BuildContext context, Widget child) async {
      if (globalState.appState.viewMode != ViewMode.mobile) {
        return await Navigator.of(context).push<T>(
          CommonDesktopRoute(
            builder: (context) => child,
          ),
        );
      }
      return await Navigator.of(context).push<T>(
        CommonRoute(
          builder: (context) => child,
        ),
      );
    }
  }
  
  class CommonDesktopRoute<T> extends PageRoute<T> {
    final Widget Function(BuildContext context) builder;
  
    CommonDesktopRoute({
      required this.builder,
    });
  
    @override
    Color? get barrierColor => null;
  
    @override
    String? get barrierLabel => null;
  
    @override
    Widget buildPage(
      BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
    ) {
      final Widget result = builder(context);
      return Semantics(
        scopesRoute: true,
        explicitChildNodes: true,
        child: FadeTransition(
          opacity: animation,
          child: result,
        ),
      );
    }
  
    @override
    bool get maintainState => true;
  
    @override
    Duration get transitionDuration => Duration(milliseconds: 200);
  
    @override
    Duration get reverseTransitionDuration => Duration(milliseconds: 200);
  }
  
  class CommonRoute<T> extends MaterialPageRoute<T> {
    CommonRoute({
      required super.builder,
    });
  
    @override
    Duration get transitionDuration => const Duration(milliseconds: 500);
  
    @override
    Duration get reverseTransitionDuration => const Duration(milliseconds: 500);
  }
  
  final Animatable<Offset> _kRightMiddleTween = Tween<Offset>(
    begin: const Offset(1.0, 0.0),
    end: Offset.zero,
  );
  final Animatable<Offset> _kMiddleLeftTween = Tween<Offset>(
    begin: Offset.zero,
    end: const Offset(-1.0 / 3.0, 0.0),
  );
  
  class CommonPageTransitionsBuilder extends PageTransitionsBuilder {
    const CommonPageTransitionsBuilder();
  
    @override
    Widget buildTransitions<T>(
      PageRoute<T> route,
      BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
      Widget child,
    ) {
      return CommonPageTransition(
        context: context,
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: false,
        child: child,
      );
    }
  }
  
  class CommonPageTransition extends StatefulWidget {
    const CommonPageTransition({
      super.key,
      required this.context,
      required this.primaryRouteAnimation,
      required this.secondaryRouteAnimation,
      required this.child,
      required this.linearTransition,
    });
  
    final Widget child;
  
    final Animation<double> primaryRouteAnimation;
  
    final Animation<double> secondaryRouteAnimation;
  
    final BuildContext context;
  
    final bool linearTransition;
  
    static Widget? delegatedTransition(
        BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
        bool allowSnapshotting,
        Widget? child) {
      final Animation<Offset> delegatedPositionAnimation = CurvedAnimation(
        parent: secondaryAnimation,
        curve: Curves.linearToEaseOut,
        reverseCurve: Curves.easeInToLinear,
      ).drive(_kMiddleLeftTween);
  
      assert(debugCheckHasDirectionality(context));
      final TextDirection textDirection = Directionality.of(context);
      return SlideTransition(
        position: delegatedPositionAnimation,
        textDirection: textDirection,
        transformHitTests: false,
        child: child,
      );
    }
  
    @override
    State<CommonPageTransition> createState() => _CommonPageTransitionState();
  }
  
  class _CommonPageTransitionState extends State<CommonPageTransition> {
    late Animation<Offset> _primaryPositionAnimation;
    late Animation<Offset> _secondaryPositionAnimation;
    late Animation<Decoration> _primaryShadowAnimation;
    CurvedAnimation? _primaryPositionCurve;
    CurvedAnimation? _secondaryPositionCurve;
    CurvedAnimation? _primaryShadowCurve;
  
    @override
    void initState() {
      super.initState();
      _setupAnimation();
    }
  
    @override
    void didUpdateWidget(covariant CommonPageTransition oldWidget) {
      super.didUpdateWidget(oldWidget);
      if (oldWidget.primaryRouteAnimation != widget.primaryRouteAnimation ||
          oldWidget.secondaryRouteAnimation != widget.secondaryRouteAnimation ||
          oldWidget.linearTransition != widget.linearTransition) {
        _disposeCurve();
        _setupAnimation();
      }
    }
  
    @override
    void dispose() {
      _disposeCurve();
      super.dispose();
    }
  
    void _disposeCurve() {
      _primaryPositionCurve?.dispose();
      _secondaryPositionCurve?.dispose();
      _primaryShadowCurve?.dispose();
      _primaryPositionCurve = null;
      _secondaryPositionCurve = null;
      _primaryShadowCurve = null;
    }
  
    void _setupAnimation() {
      if (!widget.linearTransition) {
        _primaryPositionCurve = CurvedAnimation(
          parent: widget.primaryRouteAnimation,
          curve: Curves.fastEaseInToSlowEaseOut,
          reverseCurve: Curves.fastEaseInToSlowEaseOut.flipped,
        );
        _secondaryPositionCurve = CurvedAnimation(
          parent: widget.secondaryRouteAnimation,
          curve: Curves.linearToEaseOut,
          reverseCurve: Curves.easeInToLinear,
        );
        _primaryShadowCurve = CurvedAnimation(
          parent: widget.primaryRouteAnimation,
          curve: Curves.linearToEaseOut,
        );
      }
      _primaryPositionAnimation =
          (_primaryPositionCurve ?? widget.primaryRouteAnimation)
              .drive(_kRightMiddleTween);
      _secondaryPositionAnimation =
          (_secondaryPositionCurve ?? widget.secondaryRouteAnimation)
              .drive(_kMiddleLeftTween);
      _primaryShadowAnimation =
          (_primaryShadowCurve ?? widget.primaryRouteAnimation).drive(
        DecorationTween(
          begin: const _CommonEdgeShadowDecoration(),
          end: _CommonEdgeShadowDecoration(
            <Color>[
              widget.context.colorScheme.inverseSurface
                  .withAlpha((0.02 * 255).round()),
              Colors.transparent,
            ],
          ),
        ),
      );
    }
  
    @override
    Widget build(BuildContext context) {
      assert(debugCheckHasDirectionality(context));
      final TextDirection textDirection = Directionality.of(context);
      return SlideTransition(
        position: _secondaryPositionAnimation,
        textDirection: textDirection,
        transformHitTests: false,
        child: SlideTransition(
          position: _primaryPositionAnimation,
          textDirection: textDirection,
          child: DecoratedBoxTransition(
            decoration: _primaryShadowAnimation,
            child: widget.child,
          ),
        ),
      );
    }
  }
  
  class _CommonEdgeShadowDecoration extends Decoration {
    final List<Color>? _colors;
  
    const _CommonEdgeShadowDecoration([this._colors]);
  
    @override
    BoxPainter createBoxPainter([VoidCallback? onChanged]) {
      return _CommonEdgeShadowPainter(this, onChanged);
    }
  }
  
  class _CommonEdgeShadowPainter extends BoxPainter {
    _CommonEdgeShadowPainter(
      this._decoration,
      super.onChanged,
    ) : assert(_decoration._colors == null || _decoration._colors!.length > 1);
  
    final _CommonEdgeShadowDecoration _decoration;
  
    @override
    void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
      final List<Color>? colors = _decoration._colors;
      if (colors == null) {
        return;
      }
  
      final double shadowWidth = 1 * configuration.size!.width;
      final double shadowHeight = configuration.size!.height;
      final double bandWidth = shadowWidth / (colors.length - 1);
  
      final TextDirection? textDirection = configuration.textDirection;
      assert(textDirection != null);
      final (double shadowDirection, double start) = switch (textDirection!) {
        TextDirection.rtl => (1, offset.dx + configuration.size!.width),
        TextDirection.ltr => (-1, offset.dx),
      };
  
      int bandColorIndex = 0;
      for (int dx = 0; dx < shadowWidth; dx += 1) {
        if (dx ~/ bandWidth != bandColorIndex) {
          bandColorIndex += 1;
        }
        final Paint paint = Paint()
          ..color = Color.lerp(colors[bandColorIndex], colors[bandColorIndex + 1],
              (dx % bandWidth) / bandWidth)!;
        final double x = start + shadowDirection * dx;
        canvas.drawRect(
            Rect.fromLTWH(x - 1.0, offset.dy, 1.0, shadowHeight), paint);
      }
    }
  }
  