import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:provider/provider.dart'; import 'package:yumi/modules/gift/gift_page.dart'; import 'package:yumi/services/gift/room_gift_combo_send_controller.dart'; import 'package:yumi/ui_kit/widgets/room/bottom/room_bottom_chat_entry.dart'; import 'package:yumi/ui_kit/widgets/room/bottom/room_bottom_circle_action.dart'; import 'package:yumi/ui_kit/widgets/room/bottom/room_bottom_gift_button.dart'; import 'package:yumi/ui_kit/widgets/room/bottom/room_gift_combo_floating_button.dart'; import 'package:yumi/ui_kit/widgets/room/room_menu_dialog.dart'; import 'package:yumi/ui_kit/widgets/room/room_msg_input.dart'; import 'package:yumi/ui_kit/components/text/sc_text.dart'; import 'package:yumi/shared/tools/sc_room_utils.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import '../../../app/routes/sc_fluro_navigator.dart'; import '../../../modules/index/main_route.dart'; import '../../../services/audio/rtm_manager.dart'; import '../../components/sc_debounce_widget.dart'; class RoomBottomWidget extends StatefulWidget { const RoomBottomWidget({super.key}); @override State createState() => _RoomBottomWidgetState(); } class _RoomBottomWidgetState extends State { int roomMenuStime1 = 0; static const double _bottomBarHeight = 72; static const double _floatingButtonHostHeight = 122; static const double _floatingButtonWidth = RoomGiftComboFloatingButton.hostSize; static const double _floatingButtonBottomOffset = 54; static const double _giftActionWidth = 52; static const double _circleActionWidth = 46; static const double _compactGap = 14; static const double _horizontalPadding = 16; @override void dispose() { RoomGiftComboSendController().hide(); super.dispose(); } @override Widget build(BuildContext context) { return SizedBox( height: _floatingButtonHostHeight.w, child: Consumer( builder: (context, rtcProvider, child) { final showMic = _shouldShowMic(rtcProvider); return LayoutBuilder( builder: (context, constraints) { final inputWidth = constraints.maxWidth / 3; final giftCenterX = _resolveGiftCenterX( maxWidth: constraints.maxWidth, inputWidth: inputWidth, showMic: showMic, ); return Stack( clipBehavior: Clip.none, children: [ Positioned( left: giftCenterX - (_floatingButtonWidth.w / 2), bottom: _floatingButtonBottomOffset.w, child: const RoomGiftComboFloatingButton(), ), Positioned( left: 0, right: 0, bottom: 0, child: SizedBox( height: _bottomBarHeight.w, child: _buildBottomBar( rtcProvider: rtcProvider, inputWidth: inputWidth, showMic: showMic, ), ), ), ], ); }, ); }, ), ); } Widget _buildChatEntry(double inputWidth) { return RoomBottomChatEntry( width: inputWidth, onTap: () { if (SCRoomUtils.touristCanMsg(context)) { Navigator.push(context, PopRoute(child: RoomMsgInput())); } }, ); } Widget _buildBottomBar({ required RtcProvider rtcProvider, required double inputWidth, required bool showMic, }) { final giftAction = _buildGiftAction(); final messageAction = _buildMessageAction(); final menuAction = _buildMenuAction(); return Padding( padding: EdgeInsetsDirectional.only( start: _horizontalPadding.w, end: _horizontalPadding.w, ), child: showMic ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ _buildChatEntry(inputWidth), giftAction, _buildMicAction(rtcProvider), menuAction, messageAction, ], ) : Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ _buildChatEntry(inputWidth), const Spacer(), giftAction, SizedBox(width: _compactGap.w), menuAction, SizedBox(width: _compactGap.w), messageAction, ], ), ); } Widget _buildGiftAction() { return SizedBox( width: _giftActionWidth.w, height: _giftActionWidth.w, child: RoomBottomGiftButton(onTap: _showGiftPanel), ); } double _resolveGiftCenterX({ required double maxWidth, required double inputWidth, required bool showMic, }) { final contentWidth = maxWidth - (_horizontalPadding.w * 2); if (showMic) { final occupiedWidth = inputWidth + _giftActionWidth.w + _circleActionWidth.w * 3; final gapCount = 4; final gap = ((contentWidth - occupiedWidth) / gapCount).clamp( 0.0, double.infinity, ); return _horizontalPadding.w + inputWidth + gap + (_giftActionWidth.w / 2); } final fixedWidth = inputWidth + _giftActionWidth.w + _circleActionWidth.w * 2 + _compactGap.w * 2; final spacerWidth = (contentWidth - fixedWidth).clamp(0.0, double.infinity); return _horizontalPadding.w + inputWidth + spacerWidth + (_giftActionWidth.w / 2); } void _showGiftPanel() { SmartDialog.show( tag: "showGiftControl", alignment: Alignment.bottomCenter, maskColor: Colors.transparent, animationType: SmartAnimationType.fade, clickMaskDismiss: true, builder: (_) { return GiftPage(); }, ); } Widget _buildMenuAction() { return SCDebounceWidget( onTap: () { SmartDialog.show( tag: "showRoomMenuDialog", alignment: Alignment.bottomCenter, debounce: true, animationType: SmartAnimationType.fade, maskColor: Colors.transparent, clickMaskDismiss: true, builder: (_) { return RoomMenuDialog(roomMenuStime1, (eTime) { roomMenuStime1 = eTime; }); }, ); }, child: RoomBottomCircleAction( child: Image.asset( "sc_images/room/sc_icon_botton_menu.png", width: 20.w, height: 20.w, fit: BoxFit.contain, ), ), ); } Widget _buildMessageAction() { return SCDebounceWidget( onTap: () { SCNavigatorUtils.push( context, "${SCMainRoute.message}?isFromRoom=true", ); }, child: Selector( selector: (c, p) => p.allUnReadCount, shouldRebuild: (prev, next) => prev != next, builder: (_, allUnReadCount, __) { final action = RoomBottomCircleAction( child: Image.asset( "sc_images/room/sc_icon_botton_message_custom.png", width: 22.w, height: 22.w, fit: BoxFit.contain, ), ); if (allUnReadCount <= 0) { return action; } return Badge( backgroundColor: Colors.red, label: text( "${allUnReadCount > 99 ? "99+" : allUnReadCount}", fontSize: 9.sp, textColor: Colors.white, fontWeight: FontWeight.w600, ), alignment: AlignmentDirectional.topEnd, child: action, ); }, ), ); } Widget _buildMicAction(RtcProvider provider) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { setState(() { provider.isMic = !provider.isMic; provider.roomWheatMap.forEach((k, v) { if (v.user?.id == AccountStorage().getCurrentUser()?.userProfile?.id && !provider.roomWheatMap[k]!.micMute!) { if (!provider.isMic) { provider.engine?.adjustRecordingSignalVolume(100); provider.engine?.setClientRole( role: ClientRoleType.clientRoleBroadcaster, ); provider.engine?.muteLocalAudioStream(false); } else { if (provider.isMusicPlaying) { provider.engine?.adjustRecordingSignalVolume(0); } else { provider.engine?.setClientRole( role: ClientRoleType.clientRoleAudience, ); provider.engine?.muteLocalAudioStream(provider.isMic); } } } }); }); }, child: RoomBottomCircleAction( child: Image.asset( "sc_images/room/${provider.isMic ? 'sc_icon_botton_mic_close' : 'sc_icon_botton_mic_open'}.png", width: 30.w, height: 30.w, fit: BoxFit.contain, gaplessPlayback: true, ), ), ); } bool _shouldShowMic(RtcProvider provider) { var show = false; provider.roomWheatMap.forEach((k, v) { if (v.user?.id == AccountStorage().getCurrentUser()?.userProfile?.id) { show = true; } }); return show; } }