content: import 'dart:math' as math;
  import 'dart:ui';
  
  import 'package:flutter/material.dart';
  import 'package:flutter_screenutil/flutter_screenutil.dart';
  import 'package:sail/constant/app_colors.dart';
  
  double minHeight = ScreenUtil().setHeight(260);
  const double iconStartSize = 44;
  const double iconEndSize = 120;
  const double iconStartMarginTop = 36;
  const double iconEndMarginTop = 80;
  const double iconsVerticalSpacing = 24;
  const double iconsHorizontalSpacing = 16;
  
  class RecentConnectionBottomSheet extends StatefulWidget {
    const RecentConnectionBottomSheet({Key? key}) : super(key: key);
  
    @override
    RecentConnectionBottomSheetState createState() => RecentConnectionBottomSheetState();
  }
  
  class RecentConnectionBottomSheetState extends State<RecentConnectionBottomSheet> with SingleTickerProviderStateMixin {
    late AnimationController _controller;
  
    double get maxHeight => MediaQuery.of(context).size.height;
  
    double? get headerTopMargin => lerp(20, 20 + MediaQuery.of(context).padding.top);
  
    double? get headerFontSize => lerp(14, 24);
  
    double? get itemBorderRadius => lerp(8, 24);
  
    double? get iconLeftBorderRadius => itemBorderRadius;
  
    double? get iconRightBorderRadius => lerp(8, 0);
  
    double? get iconSize => lerp(iconStartSize, iconEndSize);
  
    double? iconTopMargin(int index) =>
        lerp(iconStartMarginTop, iconEndMarginTop + index * (iconsVerticalSpacing + iconEndSize))! + headerTopMargin!;
  
    double? iconLeftMargin(int index) => lerp(index * (iconsHorizontalSpacing + iconStartSize), 0);
  
    @override
    void initState() {
      super.initState();
      _controller = AnimationController(
        vsync: this,
        duration: const Duration(milliseconds: 600),
      );
    }
  
    @override
    void dispose() {
      _controller.dispose();
      super.dispose();
    }
  
    double? lerp(double min, double max) => lerpDouble(min, max, _controller.value);
  
    @override
    Widget build(BuildContext context) {
      return AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
          return Positioned(
            height: lerp(minHeight, maxHeight),
            left: 0,
            right: 0,
            bottom: 0,
            child: GestureDetector(
              onTap: _toggle,
              onVerticalDragUpdate: _handleDragUpdate,
              onVerticalDragEnd: _handleDragEnd,
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 32),
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                      colors: [AppColors.themeColor, Colors.pink], begin: Alignment.topLeft, end: Alignment.bottomRight),
                  borderRadius: BorderRadius.vertical(top: Radius.circular(32)),
                ),
                child: Stack(
                  children: <Widget>[
                    const MenuButton(),
                    SheetHeader(
                      fontSize: headerFontSize,
                      topMargin: headerTopMargin,
                    ),
                    for (Event event in events) _buildFullItem(event),
                    for (Event event in events) _buildIcon(event),
                  ],
                ),
              ),
            ),
          );
        },
      );
    }
  
    Widget _buildIcon(Event event) {
      int index = events.indexOf(event);
      return Positioned(
        height: iconSize,
        width: iconSize,
        top: iconTopMargin(index),
        left: iconLeftMargin(index),
        child: ClipRRect(
          borderRadius: BorderRadius.horizontal(
            left: Radius.circular(iconLeftBorderRadius!),
            right: Radius.circular(iconRightBorderRadius!),
          ),
          child: Image.asset(
            'assets/${event.assetName}',
            fit: BoxFit.cover,
            alignment: Alignment(lerp(1, 0)!, 0),
          ),
        ),
      );
    }
  
    Widget _buildFullItem(Event event) {
      int index = events.indexOf(event);
      return ExpandedEventItem(
        topMargin: iconTopMargin(index),
        leftMargin: iconLeftMargin(index),
        height: iconSize,
        isVisible: _controller.status == AnimationStatus.completed,
        borderRadius: itemBorderRadius,
        title: event.title,
        date: event.date,
      );
    }
  
    void _toggle() {
      final bool isOpen = _controller.status == AnimationStatus.completed;
      _controller.fling(velocity: isOpen ? -2 : 2);
    }
  
    void _handleDragUpdate(DragUpdateDetails details) {
      _controller.value -= details.primaryDelta! / maxHeight;
    }
  
    void _handleDragEnd(DragEndDetails details) {
      if (_controller.isAnimating || _controller.status == AnimationStatus.completed) return;
  
      final double flingVelocity = details.velocity.pixelsPerSecond.dy / maxHeight;
      if (flingVelocity < 0.0) {
        _controller.fling(velocity: math.max(2.0, -flingVelocity));
      } else if (flingVelocity > 0.0) {
        _controller.fling(velocity: math.min(-2.0, -flingVelocity));
      } else {
        _controller.fling(velocity: _controller.value < 0.5 ? -2.0 : 2.0);
      }
    }
  }
  
  class ExpandedEventItem extends StatelessWidget {
    final double? topMargin;
    final double? leftMargin;
    final double? height;
    final bool isVisible;
    final double? borderRadius;
    final String title;
    final String date;
  
    const ExpandedEventItem(
        {Key? key,
        required this.topMargin,
        required this.height,
        required this.isVisible,
        required this.borderRadius,
        required this.title,
        required this.date,
        required this.leftMargin})
        : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return Positioned(
        top: topMargin,
        left: leftMargin,
        right: 0,
        height: height,
        child: AnimatedOpacity(
          opacity: isVisible ? 1 : 0,
          duration: const Duration(milliseconds: 200),
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(borderRadius!),
              color: Colors.white,
            ),
            padding: EdgeInsets.only(left: height!).add(const EdgeInsets.all(8)),
            child: _buildContent(),
          ),
        ),
      );
    }
  
    Widget _buildContent() {
      return Column(
        children: <Widget>[
          Text(title, style: const TextStyle(fontSize: 16)),
          const SizedBox(height: 8),
          Row(
            children: <Widget>[
              Text(
                '1 ticket',
                style: TextStyle(
                  fontWeight: FontWeight.w500,
                  fontSize: 12,
                  color: Colors.grey.shade600,
                ),
              ),
              const SizedBox(width: 8),
              Text(
                date,
                style: const TextStyle(
                  fontWeight: FontWeight.w300,
                  fontSize: 12,
                  color: Colors.grey,
                ),
              ),
            ],
          ),
          const Spacer(),
          Row(
            children: <Widget>[
              Icon(Icons.place, color: Colors.grey.shade400, size: 16),
              Text(
                'Science Park 10 25A',
                style: TextStyle(color: Colors.grey.shade400, fontSize: 13),
              )
            ],
          )
        ],
      );
    }
  }
  
  final List<Event> events = [
    Event('steve-johnson.jpeg', 'Shenzhen GLOBAL DESIGN AWARD 2018', '4.20-30'),
    Event('efe-kurnaz.jpg', 'Shenzhen GLOBAL DESIGN AWARD 2018', '4.20-30'),
    Event('rodion-kutsaev.jpeg', 'Dawan District Guangdong Hong Kong', '4.28-31'),
  ];
  
  class Event {
    final String assetName;
    final String title;
    final String date;
  
    Event(this.assetName, this.title, this.date);
  }
  
  class SheetHeader extends StatelessWidget {
    final double? fontSize;
    final double? topMargin;
  
    const SheetHeader({Key? key, required this.fontSize, required this.topMargin}) : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return Positioned(
        top: topMargin,
        child: Text(
          '最近连接节点',
          style: TextStyle(
            color: Colors.grey[100],
            fontSize: fontSize,
            fontWeight: FontWeight.w500,
          ),
        ),
      );
    }
  }
  
  class MenuButton extends StatelessWidget {
    const MenuButton({Key? key}) : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return const Positioned(
        right: 0,
        bottom: 24,
        child: Icon(
          Icons.menu,
          color: Colors.white,
          size: 28,
        ),
      );
    }
  }
  