import 'dart:ui' as ui; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:aslan/app_localizations.dart'; import 'package:aslan/chatvibe_ui/components/text/at_text.dart'; import 'package:aslan/chatvibe_core/constants/at_global_config.dart'; import 'package:aslan/main.dart'; import 'package:aslan/chatvibe_managers/app_general_manager.dart'; import 'package:aslan/chatvibe_managers/user_profile_manager.dart'; import 'package:provider/provider.dart'; import 'package:aslan/chatvibe_ui/components/at_compontent.dart'; import 'package:aslan/chatvibe_core/constants/at_screen.dart'; import 'package:aslan/chatvibe_core/routes/at_fluro_navigator.dart'; import 'package:aslan/chatvibe_data/sources/repositories/room_repository_imp.dart'; import 'package:aslan/chatvibe_domain/models/res/gift_res.dart'; import 'package:aslan/chatvibe_features/wallet/wallet_route.dart'; import 'package:aslan/chatvibe_features/gift/gift_tab_page.dart'; class CommentGiftPage extends StatefulWidget { String toUserId; String dynamicContentId; Function(int count)? sendGiftCallBack; CommentGiftPage(this.toUserId, this.dynamicContentId, {super.key,this.sendGiftCallBack}); @override _CommentGiftPageState createState() => _CommentGiftPageState(); } class _CommentGiftPageState extends State with TickerProviderStateMixin { late TabController _tabController; bool isAnimating = false; final GlobalKey _sourceKey1 = GlobalKey(); final GlobalKey _targetKey1 = GlobalKey(); ChatVibeGiftRes? checkedGift; final List _pages = []; final List _tabs = []; ///数量的箭头是否朝上 bool isNumberUp = true; ///数量 int number = 1; int giveType = 1; int giftType = 0; @override void initState() { super.initState(); Provider.of(context, listen: false).giftList(); Provider.of(context, listen: false).balance(); _pages.add( GiftTabPage("ALL", (int checkedI) { checkedGift = null; var all = Provider.of( context, listen: false, ).giftByTab["ALL"]; if (all != null) { checkedGift = all[checkedI]; } setState(() { giftType = 0; }); }, isDark: true), ); _pages.add( GiftTabPage("NATIONAL_FLAG", (int checkedI) { checkedGift = null; var flag = Provider.of( context, listen: false, ).giftByTab["NATIONAL_FLAG"]; if (flag != null) { checkedGift = flag[checkedI]; } setState(() { giftType = 0; }); }), ); _tabController = TabController(length: _pages.length, vsync: this); _tabController.addListener(() {}); // 监听切换 } @override Widget build(BuildContext context) { _tabs.clear(); _tabs.add(Tab(text: ATAppLocalizations.of(context)!.gift)); _tabs.add(Tab(text: ATAppLocalizations.of(context)!.country)); return Consumer( builder: (context, ref, child) { return SafeArea( top: false, child: Column( mainAxisSize: MainAxisSize.min, children: [ Container(width: 50.w, height: 50.w, key: _targetKey1), ClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0), ), child: Material( color: Color(0xff232126), child: Container( child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( constraints: BoxConstraints(maxHeight: 350.w), child: Column( children: [ Row( children: [ SizedBox(width: 5.w), Expanded( child: TabBar( tabAlignment: TabAlignment.start, labelPadding: EdgeInsets.symmetric( horizontal: 8.w, ), labelColor: Colors.white, isScrollable: true, indicator: BoxDecoration(), unselectedLabelColor: Colors.white54, labelStyle: TextStyle( fontSize: 14.sp, fontFamily: 'MyCustomFont', ), unselectedLabelStyle: TextStyle( fontSize: 12.sp, fontFamily: 'MyCustomFont', ), indicatorColor: Colors.transparent, dividerColor: Colors.transparent, controller: _tabController, tabs: _tabs, ), ), SizedBox(width: 5.w), ], ), Expanded( child: Stack( children: [ TabBarView( physics: NeverScrollableScrollPhysics(), controller: _tabController, children: _pages, ), isAnimating ? GestureDetector( child: Container( color: Colors.transparent, alignment: Alignment.center, ), onTap: () {}, ) : Container(), ], ), ), Row( children: [ SizedBox(width: 15.w), GestureDetector( onTap: () { SmartDialog.dismiss( tag: "showGiftControl", ); ATNavigatorUtils.push( navigatorKey.currentState!.context, WalletRoute.recharge, replace: false, ); }, child: Container( padding: EdgeInsets.symmetric( vertical: 8.w, horizontal: 8.w, ), width: 120.w, decoration: BoxDecoration( color: Colors.white10, borderRadius: BorderRadius.circular(18), ), child: Row( children: [ Image.asset( "atu_images/general/at_icon_jb.png", width: 14.w, height: 14.w, ), SizedBox(width: 5.w), Consumer( builder: (context, ref, child) { return Expanded( child: text( "${ref.myBalance}", fontSize: 12.sp, textColor: Colors.white, ), ); }, ), SizedBox(width: 5.w), Icon( Icons.arrow_forward_ios, color: Colors.white, size: 14.w, ), ], ), ), ), Spacer(), Builder( builder: (ct) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { isNumberUp = false; _showNumber(ct); setState(() {}); }, child: Container( decoration: BoxDecoration( color: Colors.white10, borderRadius: BorderRadius.circular( 18, ), ), child: Row( children: [ SizedBox(width: 10.w), text("$number", fontSize: 12.sp), Icon( isNumberUp ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, color: Colors.white, size: 20.w, ), SizedBox(width: 5.w), GestureDetector( onTap: () { giveGifts(); }, child: Container( key: _sourceKey1, padding: EdgeInsets.symmetric( vertical: 8.w, horizontal: 20.w, ), decoration: BoxDecoration( gradient: LinearGradient( colors: [ Color(0xffF5A8B7), Color(0xffD61F3F), ], begin: Alignment.topCenter, end: Alignment .bottomCenter, ), borderRadius: BorderRadius.circular( 18, ), ), child: text( ATAppLocalizations.of( context, )!.send, fontSize: 14.sp, ), ), ), ], ), ), ); }, ), SizedBox(width: 15.w), ], ), SizedBox(height: 15.w), ], ), ), ], ), ), ), ), ], ), ); }, ); } ///数量选项 void _showNumber(BuildContext ct) { SmartDialog.showAttach( tag: "showNumber", targetContext: ct, alignment: Alignment.topLeft, animationType: SmartAnimationType.fade, scalePointBuilder: (selfSize) => Offset(selfSize.width, 10), builder: (_) { return Transform.translate( offset: Offset(ATGlobalConfig.lang == "ar" ? 20 : -20, -5), child: CheckNumber( onNumberChanged: (number) { this.number = number; isNumberUp = true; setState(() {}); }, ), ); }, ); } void giveGifts() { ChatRoomRepository() .giveGift( [widget.toUserId], checkedGift!.id ?? "", number, false, dynamicContentId: widget.dynamicContentId, ) .then((result) { _startA1(); widget.sendGiftCallBack?.call(number); Provider.of( context, listen: false, ).updateBalance(result); }) .catchError((e) {}); } void _startA1() { setState(() { isAnimating = true; }); // 确保上下文有效 if (_sourceKey1.currentContext == null) return; AnimationController? _controllerX1; Animation? _scaleAnimationX1; Animation? _scaleAnimationX2; Animation? _positionAnimationX1; OverlayEntry? _overlayEntryX1; // 获取源控件位置和大小 final RenderBox sourceBox = _sourceKey1.currentContext!.findRenderObject() as RenderBox; final Offset sourcePosition = sourceBox.localToGlobal(Offset.zero); final Size sourceSize = sourceBox.size; // 计算源控件中心点 Offset sourceCenter = Offset( sourcePosition.dx + sourceSize.width / 2, sourcePosition.dy + sourceSize.height / 2, ); // 获取目标控件位置和大小 if (_targetKey1?.currentContext == null) return; final RenderBox targetBox = _targetKey1!.currentContext!.findRenderObject() as RenderBox; final Offset targetPosition = targetBox.localToGlobal(Offset.zero); final Size targetSize = targetBox.size; // 计算目标控件中心点 final Offset targetCenter = Offset( targetPosition.dx + targetSize.width / 2, targetPosition.dy + targetSize.height / 2, ); // 计算图片中心点偏移(使图片中心对准控件中心) final double imageOffsetX = 55.w / 2; final double imageOffsetY = 55.w / 2; _controllerX1 = AnimationController( vsync: this, duration: Duration(milliseconds: 350), )..addStatusListener((status) { if (status == AnimationStatus.completed) { if (_overlayEntryX1 != null) { _overlayEntryX1?.remove(); _overlayEntryX1 = null; } setState(() { isAnimating = false; }); } }); // 创建位置动画:从起始位置到目标位置 _positionAnimationX1 = Tween( begin: Offset( sourceCenter.dx - imageOffsetX, sourceCenter.dy - imageOffsetY, ), end: Offset( targetCenter.dx - imageOffsetX, targetCenter.dy - imageOffsetY, ), ).animate( CurvedAnimation( parent: _controllerX1!, curve: const Interval(0.2, 0.4, curve: Curves.easeIn), ), ); // 创建缩放动画 _scaleAnimationX1 = Tween( begin: 0.5, end: 1.1, // 可以根据需要调整 ).animate( CurvedAnimation( parent: _controllerX1!, curve: const Interval(0, 0.2, curve: Curves.easeIn), ), ); // 创建缩放动画 _scaleAnimationX2 = Tween( begin: 1, end: 1.5, // 可以根据需要调整 ).animate( CurvedAnimation( parent: _controllerX1!, curve: const Interval(0.4, 0.7, curve: Curves.easeIn), ), ); // 创建浮动控件 _overlayEntryX1 = OverlayEntry( builder: (context) => AnimatedBuilder( animation: _controllerX1!, builder: (context, child) { return Positioned( left: _positionAnimationX1!.value.dx, top: _positionAnimationX1!.value.dy, child: Transform.scale( scale: _scaleAnimationX1!.value, child: Transform.scale( scale: _scaleAnimationX2!.value, child: netImage( url: checkedGift?.giftPhoto ?? "", width: 55.w, height: 55.w, ), ), ), ); }, ), ); // 插入Overlay并启动动画 Overlay.of(context).insert(_overlayEntryX1!); _controllerX1.forward(from: 0); } } class CheckNumber extends StatelessWidget { final Function(int) onNumberChanged; late BuildContext context; CheckNumber({super.key, required this.onNumberChanged}); @override Widget build(BuildContext context) { this.context = context; return Material( color: Colors.transparent, child: Container( alignment: AlignmentDirectional.topEnd, margin: EdgeInsets.only(right: width(22)), child: Container( decoration: BoxDecoration( color: Colors.black87, borderRadius: BorderRadius.all(Radius.circular(height(10))), ), width: width(80), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: height(10)), _item(1), _item(7), _item(17), _item(77), _item(777), _item(7777), SizedBox(height: height(10)), ], ), ), ), ); } _item(int number) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { SmartDialog.dismiss(tag: "showNumber"); onNumberChanged(number); }, child: SizedBox( height: height(24), child: Row( children: [ SizedBox(width: width(10)), Text( "$number", style: TextStyle( fontSize: sp(14), color: Colors.white, fontWeight: FontWeight.w400, decoration: TextDecoration.none, ), ), SizedBox(width: width(10)), ], ), ), ); } }