import 'dart:convert'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_debouncer/flutter_debouncer.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:yumi/app_localizations.dart'; import 'package:yumi/ui_kit/components/sc_compontent.dart'; import 'package:yumi/ui_kit/components/text/sc_text.dart'; import 'package:yumi/ui_kit/components/sc_tts.dart'; import 'package:yumi/ui_kit/theme/socialchat_theme.dart'; import 'package:yumi/app/constants/sc_global_config.dart'; import 'package:yumi/app/config/business_logic_strategy.dart'; import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_room_repository_imp.dart'; import 'package:yumi/shared/business_logic/models/res/login_res.dart'; import 'package:yumi/main.dart'; import 'package:provider/provider.dart'; import 'package:yumi/app/constants/sc_room_msg_type.dart'; import 'package:yumi/app/constants/sc_screen.dart'; import 'package:yumi/app/routes/sc_fluro_navigator.dart'; import 'package:yumi/shared/tools/sc_dialog_utils.dart'; import 'package:yumi/shared/data_sources/sources/local/floating_screen_manager.dart'; import 'package:yumi/shared/business_logic/models/res/gift_res.dart'; import 'package:yumi/shared/business_logic/models/res/mic_res.dart'; import 'package:yumi/services/general/sc_app_general_manager.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import 'package:yumi/services/audio/rtm_manager.dart'; import 'package:yumi/services/auth/user_profile_manager.dart'; import 'package:yumi/ui_kit/widgets/countdown_timer.dart'; import 'package:yumi/ui_kit/widgets/room/room_msg_item.dart'; import 'package:yumi/modules/wallet/wallet_route.dart'; import 'package:yumi/modules/gift/gift_tab_page.dart'; import '../../shared/data_sources/models/enum/sc_gift_type.dart'; import '../../shared/data_sources/models/message/sc_floating_message.dart'; import '../../shared/business_logic/usecases/sc_fixed_width_tabIndicator.dart'; class _GiftPageTabItem { const _GiftPageTabItem({required this.type, required this.label}); final String type; final String label; } class GiftPage extends StatefulWidget { SocialChatUserProfile? toUser; GiftPage({super.key, this.toUser}); @override _GiftPageState createState() => _GiftPageState(); } class _GiftPageState extends State with SingleTickerProviderStateMixin { static const List _preferredGiftTabOrder = [ "ALL", "ACTIVITY", "LUCKY_GIFT", "CP", "MAGIC", "CUSTOMIZED", "NSCIONAL_FLAG", ]; TabController? _tabController; List _tabTypes = []; /// 业务逻辑策略访问器 BusinessLogicStrategy get _strategy => SCGlobalConfig.businessLogicStrategy; // int checkedIndex = 0; SocialChatGiftRes? checkedGift; final Map _selectedGiftByTab = {}; RtcProvider? rtcProvider; bool isAll = false; List listMai = []; bool noShowNumber = false; ///选中人员 Set set = {}; ///数量的箭头是否朝上 bool isNumberUp = true; ///数量 int number = 1; int giveType = 1; int giftType = 0; Debouncer debouncer = Debouncer(); void _giftFxLog(String message) { debugPrint('[GiftFX][Send] $message'); } void _applyGiftSelection(SocialChatGiftRes? gift, {bool notify = true}) { checkedGift = gift; if (gift != null && (gift.giftSourceUrl ?? "").isNotEmpty && scGiftHasFullScreenEffect(gift.special)) { SCGiftVapSvgaManager().preload(gift.giftSourceUrl!, highPriority: true); _giftFxLog( 'preload selected gift ' 'giftId=${gift.id} ' 'giftName=${gift.giftName} ' 'giftSourceUrl=${gift.giftSourceUrl} ' 'special=${gift.special}', ); } number = 1; noShowNumber = false; giftType = _giftTypeFromTab(gift?.giftTab); if (notify) { setState(() {}); } } void _handleGiftSelected(String tabType, SocialChatGiftRes? gift) { _selectedGiftByTab[tabType] = gift; _applyGiftSelection(gift); } @override void initState() { super.initState(); rtcProvider = Provider.of(context, listen: false); Provider.of(context, listen: false).giftList(); Provider.of(context, listen: false).giftActivityList(); // Provider.of(context, listen: false).giftBackpack(); Provider.of(context, listen: false).balance(); rtcProvider?.roomWheatMap.forEach((k, v) { if (v.user != null) { if (v.user?.id == AccountStorage().getCurrentUser()?.userProfile?.id) { listMai.add(HeadSelect(true, v)); } else { listMai.add(HeadSelect(false, v)); } } isAll = true; for (var mai in listMai) { if (!mai.isSelect) { isAll = false; } } }); } @override void dispose() { _tabController?.removeListener(_handleTabChanged); _tabController?.dispose(); super.dispose(); } void _handleTabChanged() { final controller = _tabController; if (!mounted || controller == null || controller.index >= _tabTypes.length) { return; } final ref = Provider.of(context, listen: false); _syncSelectedGiftForTab(ref, _tabTypes[controller.index]); } List<_GiftPageTabItem> _buildGiftTabs( BuildContext context, SCAppGeneralManager ref, ) { final localizations = SCAppLocalizations.of(context)!; final availableTypes = ref.giftByTab.entries .where((entry) => entry.value.isNotEmpty) .map((entry) => entry.key) .toList(); final orderedTypes = []; for (final type in _preferredGiftTabOrder) { if (availableTypes.remove(type)) { orderedTypes.add(type); } } orderedTypes.addAll(availableTypes); if (orderedTypes.isEmpty) { orderedTypes.add("ALL"); } return orderedTypes .map( (type) => _GiftPageTabItem( type: type, label: _giftTabLabel(localizations, type), ), ) .toList(); } void _ensureTabController( SCAppGeneralManager ref, List<_GiftPageTabItem> tabs, ) { final nextTypes = tabs.map((tab) => tab.type).toList(); if (_tabController != null && listEquals(_tabTypes, nextTypes)) { return; } final currentType = (_tabController != null && _tabTypes.isNotEmpty && _tabController!.index < _tabTypes.length) ? _tabTypes[_tabController!.index] : null; final nextIndex = currentType != null ? nextTypes.indexOf(currentType) : 0; _tabController?.removeListener(_handleTabChanged); _tabController?.dispose(); _tabTypes = nextTypes; _tabController = TabController( length: tabs.length, vsync: this, initialIndex: nextIndex >= 0 ? nextIndex : 0, )..addListener(_handleTabChanged); _syncSelectedGiftForTab( ref, _tabTypes[_tabController!.index], notify: false, ); } void _syncSelectedGiftForTab( SCAppGeneralManager ref, String tabType, { bool notify = true, }) { final gifts = ref.giftByTab[tabType] ?? const []; final gift = _resolveSelectedGift(tabType, gifts); _selectedGiftByTab[tabType] = gift; _applyGiftSelection(gift, notify: notify); } void _ensureCurrentTabSelection(SCAppGeneralManager ref, String tabType) { final gifts = ref.giftByTab[tabType] ?? const []; if (_matchesCurrentGift(gifts)) { return; } final gift = _resolveSelectedGift(tabType, gifts); _selectedGiftByTab[tabType] = gift; _applyGiftSelection(gift, notify: false); } SocialChatGiftRes? _resolveSelectedGift( String tabType, List gifts, ) { if (gifts.isEmpty) { return null; } final selectedGift = _selectedGiftByTab[tabType]; if (selectedGift?.id != null) { for (final gift in gifts) { if (gift.id == selectedGift!.id) { return gift; } } } if (tabType == "CUSTOMIZED") { return gifts.length > 1 ? gifts[1] : null; } return gifts.first; } bool _matchesCurrentGift(List gifts) { final currentGiftId = checkedGift?.id; if (currentGiftId == null) { return gifts.isEmpty; } return gifts.any((gift) => gift.id == currentGiftId); } String _giftTabLabel(SCAppLocalizations localizations, String tabType) { switch (tabType) { case "ALL": return localizations.all; case "ACTIVITY": return localizations.activity; case "LUCK": case "LUCKY_GIFT": return localizations.luck; case "CP": return "CP"; case "MAGIC": return localizations.magic; case "CUSTOMIZED": return localizations.customized; case "NSCIONAL_FLAG": return localizations.country; default: return tabType .toLowerCase() .split("_") .map( (word) => word.isEmpty ? word : "${word[0].toUpperCase()}${word.substring(1)}", ) .join(" "); } } int _giftTypeFromTab(String? tabType) { switch (tabType) { case "ACTIVITY": return 1; case "LUCK": case "LUCKY_GIFT": return 2; case "CP": return 3; case "MAGIC": return 5; default: return 0; } } @override Widget build(BuildContext context) { return Consumer( builder: (context, ref, child) { final giftTabs = _buildGiftTabs(context, ref); _ensureTabController(ref, giftTabs); final tabController = _tabController; if (tabController == null) { return const SizedBox.shrink(); } _ensureCurrentTabSelection(ref, giftTabs[tabController.index].type); return SafeArea( top: false, child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.end, children: [ SCGlobalConfig.isReview ? Container() : ((AccountStorage() .getCurrentUser() ?.userProfile ?.firstRecharge ?? false) ? GestureDetector( child: Stack( alignment: AlignmentDirectional.bottomEnd, children: [ Transform.flip( flipX: SCGlobalConfig.lang == "ar" ? true : false, // 水平翻转 flipY: false, // 垂直翻转设为 false child: Image.asset( _strategy .getGiftPageFirstRechargeRoomTagIcon(), height: 75.w, ), ), SCGlobalConfig.lang == "ar" ? PositionedDirectional( end: 22.w, bottom: 38.w, child: Image.asset( _strategy .getGiftPageFirstRechargeTextIcon( 'ar', ), height: 13.w, ), ) : PositionedDirectional( end: 16.w, bottom: 38.w, child: Image.asset( _strategy .getGiftPageFirstRechargeTextIcon( 'en', ), height: 13.w, ), ), PositionedDirectional( end: 34.w, bottom: 13.w, child: CountdownTimer( expiryDate: DateTime.fromMillisecondsSinceEpoch( AccountStorage() .getCurrentUser() ?.userProfile ?.firstRechargeEndTime ?? 0, ), color: Colors.white, fontSize: 12.w, ), ), ], ), onTap: () { SCDialogUtils.showFirstRechargeDialog( navigatorKey.currentState!.context, ); }, ) : Container()), ], ), _buildGiftHead(), ClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0), ), child: BackdropFilter( filter: ui.ImageFilter.blur(sigmaX: 15, sigmaY: 15), child: Container( color: const Color(0xff09372E).withValues(alpha: 0.5), constraints: BoxConstraints(maxHeight: 430.w), child: Column( children: [ SizedBox(height: 12.w), Row( children: [ SizedBox(width: 8.w), widget.toUser == null ? Builder( builder: (ct) { return GestureDetector( child: Image.asset( isAll ? "sc_images/room/sc_icon_gift_all_en.png" : "sc_images/room/sc_icon_gift_all_no.png", width: 28.w, height: 28.w, ), onTap: () { isAll = !isAll; for (var mai in listMai) { mai.isSelect = isAll; } setState(() {}); // showGiveTypeDialog(ct); }, ); }, ) : Container(), SizedBox(width: 8.w), widget.toUser == null ? Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: listMai .map((e) => _maiHead(e)) .toList(), ), ), ) : Stack( alignment: AlignmentDirectional.center, children: [ Container( padding: EdgeInsets.all(2.w), child: netImage( url: widget.toUser?.userAvatar ?? "", width: 26.w, defaultImg: _strategy .getMePageDefaultAvatarImage(), shape: BoxShape.circle, ), ), PositionedDirectional( bottom: 0, end: 0, child: Image.asset( "sc_images/login/sc_icon_login_ser_select.png", width: 10.w, height: 10.w, ), ), ], ), SizedBox(width: 12.w), ], ), Row( children: [ SizedBox(width: 5.w), Expanded( child: SizedBox( height: 28.w, child: TabBar( tabAlignment: TabAlignment.start, labelPadding: EdgeInsets.symmetric( horizontal: 8.w, ), labelColor: SocialChatTheme.primaryLight, indicatorWeight: 0, isScrollable: true, indicator: SCFixedWidthTabIndicator( width: 15.w, color: SocialChatTheme.primaryLight, ), unselectedLabelColor: Colors.white54, labelStyle: TextStyle(fontSize: 14.sp), unselectedLabelStyle: TextStyle( fontSize: 12.sp, ), indicatorColor: Colors.transparent, dividerColor: Colors.transparent, controller: tabController, tabs: giftTabs .map((tab) => Tab(text: tab.label)) .toList(), ), ), ), SizedBox(width: 5.w), ], ), Expanded( child: TabBarView( physics: NeverScrollableScrollPhysics(), controller: tabController, children: giftTabs .map( (tab) => GiftTabPage( key: ValueKey(tab.type), tab.type, (gift) => _handleGiftSelected(tab.type, gift), ), ) .toList(), ), ), Row( children: [ SizedBox(width: 15.w), GestureDetector( onTap: () { SmartDialog.dismiss(tag: "showGiftControl"); SCNavigatorUtils.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(5), ), child: Row( children: [ Image.asset( _strategy.getGiftPageGoldCoinIcon(), width: 14.w, height: 14.w, ), SizedBox(width: 5.w), Consumer( builder: (context, ref, child) { return Expanded( child: text( "${ref.myBalance}", fontSize: 12.sp, ), ); }, ), 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: () { if (noShowNumber) { return; } isNumberUp = false; _showNumber(ct); setState(() {}); }, child: Container( decoration: BoxDecoration( color: Colors.white10, borderRadius: BorderRadius.circular(5), ), 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( padding: EdgeInsets.symmetric( vertical: 8.w, horizontal: 20.w, ), decoration: BoxDecoration( color: SocialChatTheme.primaryLight, borderRadius: BorderRadius.circular(5), ), child: text( SCAppLocalizations.of( context, )!.send, fontSize: 14.sp, ), ), ), ], ), ), ); }, ), SizedBox(width: 15.w), ], ), SizedBox(height: 15.w), ], ), ), ), ), ], ), ); }, ); } void showGiveTypeDialog(BuildContext ct) { SmartDialog.showAttach( tag: "showGiveType", targetContext: ct, alignment: Alignment.bottomCenter, animationType: SmartAnimationType.fade, scalePointBuilder: (selfSize) => Offset(selfSize.width, 10), builder: (_) { return Container( height: 135.w, width: 200.w, decoration: BoxDecoration( image: DecorationImage( image: AssetImage(_strategy.getGiftPageGiveTypeBackground()), fit: BoxFit.fill, ), ), padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.w), child: Column( children: [ SizedBox(height: 5.w), Expanded( child: GestureDetector( child: Row( children: [ Image.asset( _strategy.getGiftPageAllOnMicrophoneIcon(), height: 18.w, width: 18.w, ), SizedBox(width: 8.w), Expanded( child: text( SCAppLocalizations.of(context)!.allOnMicrophone, fontSize: 14.sp, textColor: Colors.white54, ), ), SizedBox(width: 8.w), Image.asset( giveType == 0 ? _strategy.getCommonSelectIcon() : _strategy.getCommonUnselectIcon(), width: 15.w, height: 15.w, ), ], ), onTap: () { giveType = 0; SmartDialog.dismiss(tag: "showGiveType"); selecteAllMicUsers(); setState(() {}); }, ), ), Expanded( child: GestureDetector( child: Row( children: [ Image.asset( _strategy.getGiftPageUsersOnMicrophoneIcon(), height: 18.w, width: 18.w, ), SizedBox(width: 8.w), Expanded( child: text( SCAppLocalizations.of(context)!.usersOnMicrophone, fontSize: 14.sp, textColor: Colors.white54, ), ), SizedBox(width: 8.w), Image.asset( giveType == 1 ? _strategy.getCommonSelectIcon() : _strategy.getCommonUnselectIcon(), width: 15.w, height: 15.w, ), ], ), onTap: () { giveType = 1; SmartDialog.dismiss(tag: "showGiveType"); setState(() {}); }, ), ), Expanded( child: GestureDetector( onTap: () { giveType = 2; SmartDialog.dismiss(tag: "showGiveType"); setState(() {}); }, behavior: HitTestBehavior.opaque, child: Row( children: [ Image.asset( _strategy.getGiftPageAllInTheRoomIcon(), height: 18.w, width: 18.w, ), SizedBox(width: 8.w), Expanded( child: text( SCAppLocalizations.of(context)!.allInTheRoom, fontSize: 14.sp, textColor: Colors.white54, ), ), SizedBox(width: 8.w), Image.asset( giveType == 2 ? _strategy.getCommonSelectIcon() : _strategy.getCommonUnselectIcon(), width: 15.w, height: 15.w, ), ], ), ), ), ], ), ); }, ); } Widget _maiHead(HeadSelect shead) { // 是否选中 return GestureDetector( onTap: () { isAll = true; for (var mai in listMai) { if (shead.mic?.user?.id == mai.mic?.user?.id) { mai.isSelect = !mai.isSelect; } if (!mai.isSelect) { isAll = false; } } setState(() {}); }, child: Stack( alignment: Alignment.bottomCenter, clipBehavior: Clip.none, children: [ Stack( alignment: AlignmentDirectional.center, children: [ Container( padding: EdgeInsets.all(2.w), child: netImage( url: shead.mic?.user?.userAvatar ?? "", width: 26.w, defaultImg: _strategy.getMePageDefaultAvatarImage(), shape: BoxShape.circle, ), ), PositionedDirectional( bottom: 0, end: 0, child: Container( alignment: AlignmentDirectional.center, width: 12.w, height: 12.w, decoration: BoxDecoration( color: Colors.black38, shape: BoxShape.circle, border: shead.isSelect ? Border.all( color: SocialChatTheme.primaryLight, width: 1.w, ) : null, ), child: text( "${shead.mic?.micIndex}", textColor: Colors.white, fontSize: 8.sp, ), ), ), shead.isSelect ? PositionedDirectional( bottom: 0, end: 0, child: Image.asset( "sc_images/login/sc_icon_login_ser_select.png", width: 12.w, height: 12.w, ), ) : Container(), ], ), ], ), ); } ///数量选项 void _showNumber(BuildContext ct) { SmartDialog.showAttach( tag: "showNumber", targetContext: ct, maskColor: Colors.transparent, alignment: Alignment.topLeft, animationType: SmartAnimationType.fade, scalePointBuilder: (selfSize) => Offset(selfSize.width, 10), onDismiss: () { isNumberUp = true; setState(() {}); }, builder: (_) { return Transform.translate( offset: Offset(SCGlobalConfig.lang == "ar" ? 20 : -20, -5), child: CheckNumber( onNumberChanged: (number) { this.number = number; isNumberUp = true; setState(() {}); }, ), ); }, ); } ///选中所有在座位上的用户 void selecteAllMicUsers() { for (var mai in listMai) { mai.isSelect = true; } } ///赠送礼物 void giveGifts() { List acceptUserIds = []; List acceptUsers = []; if (widget.toUser != null) { acceptUserIds.add(widget.toUser?.id ?? ""); acceptUsers.add(MicRes(user: widget.toUser)); } else { ///所有在线 if (giveType == 2) { for (var value in Provider.of(context, listen: false).onlineUsers) { acceptUsers.add(MicRes(user: value)); acceptUserIds.add(value.id ?? ""); } } else { for (var mu in listMai) { if (mu.isSelect) { acceptUsers.add(mu.mic!); acceptUserIds.add(mu.mic!.user!.id ?? ""); } } } } if (acceptUserIds.isEmpty) { SCTts.show(SCAppLocalizations.of(context)!.pleaseSelectTheRecipient); return; } if (checkedGift == null) { return; } SCChatRoomRepository() .giveGift( acceptUserIds, checkedGift!.id ?? "", number, false, roomId: rtcProvider?.currenRoom?.roomProfile?.roomProfile?.id ?? "", ) .then((result) { _giftFxLog( 'giveGift success giftId=${checkedGift?.id} ' 'giftName=${checkedGift?.giftName} ' 'giftSourceUrl=${checkedGift?.giftSourceUrl} ' 'special=${checkedGift?.special} ' 'giftTab=${checkedGift?.giftTab} ' 'number=$number ' 'acceptUserIds=${acceptUserIds.join(",")} ' 'roomId=${rtcProvider?.currenRoom?.roomProfile?.roomProfile?.id}', ); // SCTts.show(SCAppLocalizations.of(context)!.giftGivingSuccessful); sendGiftMsg(acceptUsers); Provider.of( context, listen: false, ).updateBalance(result); }) .catchError((e) { _giftFxLog( 'giveGift failed giftId=${checkedGift?.id} ' 'giftName=${checkedGift?.giftName} ' 'error=$e', ); }); } void sendGiftMsg(List acceptUsers) { ///发送一条IM消息 for (var u in acceptUsers) { final special = checkedGift?.special ?? ""; final giftSourceUrl = checkedGift?.giftSourceUrl ?? ""; final hasSource = giftSourceUrl.isNotEmpty; final hasAnimation = scGiftHasAnimationSpecial(special); final hasGlobalGift = special.contains(SCGiftType.GLOBAL_GIFT.name); final hasFullScreenEffect = scGiftHasFullScreenEffect(special); _giftFxLog( 'dispatch gift msg ' 'giftId=${checkedGift?.id} ' 'giftName=${checkedGift?.giftName} ' 'toUserId=${u.user?.id} ' 'toUserName=${u.user?.userNickname} ' 'giftSourceUrl=$giftSourceUrl ' 'special=$special ' 'hasSource=$hasSource ' 'hasAnimation=$hasAnimation ' 'hasGlobalGift=$hasGlobalGift ' 'hasFullScreenEffect=$hasFullScreenEffect ' 'effectsEnabled=${SCGlobalConfig.isGiftSpecialEffects}', ); Provider.of( navigatorKey.currentState!.context, listen: false, ).dispatchMessage( Msg( groupId: rtcProvider?.currenRoom?.roomProfile?.roomProfile?.roomAccount, gift: checkedGift, user: AccountStorage().getCurrentUser()?.userProfile, toUser: u.user, number: number, type: SCRoomMsgType.gift, role: Provider.of( navigatorKey.currentState!.context, listen: false, ).currenRoom?.entrants?.roles ?? "", msg: rtcProvider?.currenRoom?.roomProfile?.roomProfile?.id ?? "", ), addLocal: true, ); if (rtcProvider?.currenRoom?.roomProfile?.roomSetting?.showHeartbeat ?? false) { debouncer.debounce( duration: Duration(milliseconds: 350), onDebounce: () { Provider.of( navigatorKey.currentState!.context, listen: false, ).retrieveMicrophoneList(); }, ); } num coins = checkedGift!.giftCandy! * number; if (coins > 9999) { var fMsg = SCFloatingMessage( type: 1, userAvatarUrl: AccountStorage().getCurrentUser()?.userProfile?.userAvatar ?? "", userName: AccountStorage().getCurrentUser()?.userProfile?.userNickname ?? "", toUserName: u.user?.userNickname ?? "", giftUrl: checkedGift?.giftPhoto ?? "", roomId: rtcProvider?.currenRoom?.roomProfile?.roomProfile?.id ?? "", coins: coins, number: number, ); OverlayManager().addMessage(fMsg); } if (checkedGift!.giftSourceUrl != null && checkedGift!.special != null) { if (scGiftHasFullScreenEffect(checkedGift!.special)) { if (SCGlobalConfig.isGiftSpecialEffects) { _giftFxLog( 'local trigger player play ' 'path=${checkedGift!.giftSourceUrl} ' 'giftId=${checkedGift?.id} ' 'giftName=${checkedGift?.giftName}', ); SCGiftVapSvgaManager().play(checkedGift!.giftSourceUrl!); } else { _giftFxLog( 'skip local play because isGiftSpecialEffects=false ' 'giftId=${checkedGift?.id}', ); } } else { _giftFxLog( 'skip local play because special does not include ' '${SCGiftType.ANIMSCION.name}/$kSCGiftAnimationSpecialAlias/${SCGiftType.GLOBAL_GIFT.name} ' 'giftId=${checkedGift?.id} special=${checkedGift?.special}', ); } } else { _giftFxLog( 'skip local play because giftSourceUrl or special is null ' 'giftId=${checkedGift?.id} ' 'giftSourceUrl=${checkedGift?.giftSourceUrl} ' 'special=${checkedGift?.special}', ); } } } /// 将数字giftType转换为字符串类型,用于活动礼物头部背景 String _giftTypeToString(int giftType) { switch (giftType) { case 1: // ACTIVITY return 'ACTIVITY'; case 2: // LUCKY_GIFT -> LUCK return 'LUCK'; case 3: // CP return 'CP'; case 5: // MAGIC return 'MAGIC'; default: return 'ACTIVITY'; } } _buildGiftHead() { if (giftType == 1 || giftType == 2 || giftType == 3 || giftType == 5) { // 获取基础路径 String basePath = _strategy.getGiftPageActivityGiftHeadBackground( _giftTypeToString(giftType), ); // 添加语言后缀 String imagePath; if (SCGlobalConfig.lang == "ar") { // 移除扩展名,添加 _ar 后缀,然后重新添加扩展名 if (basePath.endsWith('.png')) { imagePath = basePath.substring(0, basePath.length - 4) + '_ar.png'; } else { imagePath = basePath + '_ar'; } } else { if (basePath.endsWith('.png')) { imagePath = basePath.substring(0, basePath.length - 4) + '_en.png'; } else { imagePath = basePath + '_en'; } } // 确定高度 double height = giftType == 5 ? 80.w : 65.w; return Container( margin: EdgeInsets.symmetric(horizontal: 10.w), child: Image.asset(imagePath, height: height, fit: BoxFit.fill), ); } return Container(); } ///发送一条消息,幸运礼物,房间里所有人都能看到礼物飘向麦位的动画 void sendLuckGiftAnimOtherMsg(List acceptUsers) { Provider.of( navigatorKey.currentState!.context, listen: false, ).dispatchMessage( Msg( groupId: rtcProvider?.currenRoom?.roomProfile?.roomProfile?.roomAccount, gift: checkedGift, type: SCRoomMsgType.luckGiftAnimOther, msg: jsonEncode(acceptUsers.map((u) => u.user?.id).toList()), ), addLocal: false, ); } } 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 Container( alignment: AlignmentDirectional.topEnd, margin: EdgeInsets.only(right: width(22)), child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(12.w)), child: BackdropFilter( filter: ui.ImageFilter.blur(sigmaX: 25, sigmaY: 25), child: Container( decoration: BoxDecoration( color: Colors.white10, borderRadius: BorderRadius.all(Radius.circular(height(6))), ), width: width(75), 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( mainAxisAlignment: MainAxisAlignment.center, 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)), ], ), ), ); } } class HeadSelect { bool isSelect = false; MicRes? mic; HeadSelect(this.isSelect, this.mic); }