2026-07-01 18:25:58 +08:00

548 lines
21 KiB
Dart

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<CommentGiftPage>
with TickerProviderStateMixin {
late TabController _tabController;
bool isAnimating = false;
final GlobalKey _sourceKey1 = GlobalKey();
final GlobalKey _targetKey1 = GlobalKey();
ChatVibeGiftRes? checkedGift;
final List<Widget> _pages = [];
final List<Widget> _tabs = [];
///数量的箭头是否朝上
bool isNumberUp = true;
///数量
int number = 1;
int giveType = 1;
int giftType = 0;
@override
void initState() {
super.initState();
Provider.of<AppGeneralManager>(context, listen: false).giftList();
Provider.of<ChatVibeUserProfileManager>(context, listen: false).balance();
_pages.add(
GiftTabPage("ALL", (int checkedI) {
checkedGift = null;
var all =
Provider.of<AppGeneralManager>(
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<AppGeneralManager>(
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<AppGeneralManager>(
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<ChatVibeUserProfileManager>(
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<ChatVibeUserProfileManager>(
context,
listen: false,
).updateBalance(result);
})
.catchError((e) {});
}
void _startA1() {
setState(() {
isAnimating = true;
});
// 确保上下文有效
if (_sourceKey1.currentContext == null) return;
AnimationController? _controllerX1;
Animation<double>? _scaleAnimationX1;
Animation<double>? _scaleAnimationX2;
Animation<Offset>? _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<Offset>(
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<double>(
begin: 0.5,
end: 1.1, // 可以根据需要调整
).animate(
CurvedAnimation(
parent: _controllerX1!,
curve: const Interval(0, 0.2, curve: Curves.easeIn),
),
);
// 创建缩放动画
_scaleAnimationX2 = Tween<double>(
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: <Widget>[
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: <Widget>[
SizedBox(width: width(10)),
Text(
"$number",
style: TextStyle(
fontSize: sp(14),
color: Colors.white,
fontWeight: FontWeight.w400,
decoration: TextDecoration.none,
),
),
SizedBox(width: width(10)),
],
),
),
);
}
}