import 'dart:io'; import 'package:fluro/fluro.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:yumi/modules/room/background/room_background_preview_page.dart'; import 'package:yumi/modules/room/background/room_background_select_page.dart'; import 'package:yumi/modules/room/background/room_background_upload_page.dart'; import 'package:yumi/modules/room/edit/room_edit_page.dart'; import 'package:yumi/modules/room/music/room_music_page.dart'; import 'package:yumi/modules/room/rocket/room_rocket_rank_page.dart'; import 'package:yumi/modules/room/them/room_theme_page.dart'; import 'package:yumi/modules/room/voice_room_page.dart'; import 'package:yumi/app/routes/sc_router_init.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import 'package:yumi/services/audio/rtm_manager.dart'; import 'package:yumi/services/gift/gift_animation_manager.dart'; import 'package:yumi/shared/data_sources/sources/local/floating_screen_manager.dart'; import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart'; import 'package:yumi/shared/tools/sc_room_effect_scheduler.dart'; import 'package:yumi/ui_kit/widgets/room/anim/room_entrance_widget.dart'; class VoiceRoomRoute implements SCIRouterProvider { static String voiceRoom = '/room'; static String roomEdit = '/room/roomEdit'; static String roomTheme = '/room/roomTheme'; static String roomBackgroundSelect = '/room/background/select'; static String roomBackgroundPreview = '/room/background/preview'; static String roomBackgroundUpload = '/room/background/upload'; static String roomMusic = '/room/music'; static String roomRocketRank = '/room/rocket/rank'; static int _voiceRoomRouteDepth = 0; static bool get isVoiceRoomOpen => _voiceRoomRouteDepth > 0; static Route _buildRoute(Widget page, {RouteSettings? settings}) { if (Platform.isIOS) { return CupertinoPageRoute(builder: (_) => page, settings: settings); } return MaterialPageRoute(builder: (_) => page, settings: settings); } static Route _buildDarkRoute(Widget page, {RouteSettings? settings}) { return PageRouteBuilder( settings: settings, opaque: true, barrierColor: const Color(0xFF071F1B), transitionDuration: const Duration(milliseconds: 180), reverseTransitionDuration: const Duration(milliseconds: 160), pageBuilder: (context, animation, secondaryAnimation) => ColoredBox(color: const Color(0xFF071F1B), child: page), transitionsBuilder: (context, animation, secondaryAnimation, child) { final tween = Tween( begin: const Offset(1, 0), end: Offset.zero, ).chain(CurveTween(curve: Curves.easeOutCubic)); return SlideTransition(position: animation.drive(tween), child: child); }, ); } static Future _pushBackgroundRoute( BuildContext context, Route route, { bool rootNavigator = false, }) { final restoreEffects = _pauseRoomVisualEffects(context); return Navigator.of( context, rootNavigator: rootNavigator, ).push(route).whenComplete(restoreEffects); } static VoidCallback _pauseRoomVisualEffects(BuildContext context) { final rtcProvider = context.read(); final rtmProvider = context.read(); final giftAnimationManager = context.read(); final wasEnabled = rtcProvider.roomVisualEffectsEnabled; final floatingGiftListener = rtmProvider.msgFloatingGiftListener; final luckyGiftRewardTickerListener = rtmProvider.msgLuckyGiftRewardTickerListener; final currentRoomId = rtcProvider.currenRoom?.roomProfile?.roomProfile?.id?.trim() ?? ''; rtcProvider.setRoomVisualEffectsEnabled(false); rtmProvider.msgFloatingGiftListener = null; rtmProvider.msgLuckyGiftRewardTickerListener = null; RoomEntranceHelper.clearQueue(); giftAnimationManager.clearActiveAnimations(); OverlayManager().removeRoom(roomId: currentRoomId); SCRoomEffectScheduler().clearDeferredTasks(reason: 'room_background_route'); SCGiftVapSvgaManager().stopPlayback(); return () { if (!context.mounted || rtcProvider.currenRoom == null) { return; } rtcProvider.setRoomVisualEffectsEnabled(wasEnabled); if (wasEnabled) { rtmProvider.msgFloatingGiftListener ??= floatingGiftListener; rtmProvider.msgLuckyGiftRewardTickerListener ??= luckyGiftRewardTickerListener; } }; } static Future openVoiceRoom( BuildContext context, { bool replace = false, bool rootNavigator = false, }) { final navigator = Navigator.of(context, rootNavigator: rootNavigator); if (!replace && isVoiceRoomOpen) { return Future.value(); } final route = _buildRoute( const VoiceRoomPage(), settings: RouteSettings(name: voiceRoom), ); _voiceRoomRouteDepth = replace ? 1 : _voiceRoomRouteDepth + 1; Future routeFuture; if (replace) { routeFuture = navigator.pushReplacement(route); } else { routeFuture = navigator.push(route); } return routeFuture.whenComplete(() { if (_voiceRoomRouteDepth > 0) { _voiceRoomRouteDepth -= 1; } }); } static void popVoiceRoomToPrevious( BuildContext context, { bool rootNavigator = false, }) { popVoiceRoomToPreviousOn( Navigator.of(context, rootNavigator: rootNavigator), ); } static void popVoiceRoomToPreviousOn(NavigatorState navigator) { if (!isVoiceRoomOpen) { return; } var removedVoiceRoom = false; navigator.popUntil((route) { if (route.settings.name == voiceRoom) { removedVoiceRoom = true; return false; } return removedVoiceRoom || route.isFirst; }); } static Future openRoomEdit( BuildContext context, { required bool needRestCurrentRoomInfo, bool rootNavigator = true, }) { return Navigator.of(context, rootNavigator: rootNavigator).push( _buildRoute( RoomEditPage( needRestCurrentRoomInfo: needRestCurrentRoomInfo ? "true" : "false", ), ), ); } static Future openRoomTheme( BuildContext context, { bool rootNavigator = false, }) { return Navigator.of( context, rootNavigator: rootNavigator, ).push(_buildRoute(RoomThemePage())); } static Future openRoomBackgroundSelect( BuildContext context, { bool rootNavigator = false, }) { return _pushBackgroundRoute( context, _buildDarkRoute( const RoomBackgroundSelectPage(), settings: RouteSettings(name: roomBackgroundSelect), ), rootNavigator: rootNavigator, ); } static Future openRoomBackgroundUpload( BuildContext context, { bool rootNavigator = false, }) { return _pushBackgroundRoute( context, _buildDarkRoute( const RoomBackgroundUploadPage(), settings: RouteSettings(name: roomBackgroundUpload), ), rootNavigator: rootNavigator, ); } static Future openRoomBackgroundPreview( BuildContext context, { String? backgroundPath, bool rootNavigator = false, }) { return _pushBackgroundRoute( context, _buildDarkRoute( RoomBackgroundPreviewPage(backgroundPath: backgroundPath), settings: RouteSettings(name: roomBackgroundPreview), ), rootNavigator: rootNavigator, ); } static Future openRoomMusic( BuildContext context, { bool rootNavigator = false, }) { return Navigator.of(context, rootNavigator: rootNavigator).push( _buildDarkRoute( const RoomMusicPage(), settings: RouteSettings(name: roomMusic), ), ); } static Future openRoomRocketRank( BuildContext context, { String? roomId, int initialLevel = 0, bool rootNavigator = false, }) { return Navigator.of(context, rootNavigator: rootNavigator).push( _buildDarkRoute( RoomRocketRankPage(roomId: roomId, initialLevel: initialLevel), settings: RouteSettings(name: roomRocketRank), ), ); } static Future openRoomRocketRankOn( NavigatorState navigator, { String? roomId, int initialLevel = 0, }) { return navigator.push( _buildDarkRoute( RoomRocketRankPage(roomId: roomId, initialLevel: initialLevel), settings: RouteSettings(name: roomRocketRank), ), ); } @override void initRouter(FluroRouter router) { router.define( voiceRoom, handler: Handler(handlerFunc: (_, params) => VoiceRoomPage()), ); router.define( roomTheme, handler: Handler(handlerFunc: (_, params) => RoomThemePage()), ); router.define( roomBackgroundSelect, handler: Handler( handlerFunc: (_, params) => const RoomBackgroundSelectPage(), ), ); router.define( roomBackgroundPreview, handler: Handler( handlerFunc: (_, params) => const RoomBackgroundPreviewPage(), ), ); router.define( roomBackgroundUpload, handler: Handler( handlerFunc: (_, params) => const RoomBackgroundUploadPage(), ), ); router.define( roomMusic, handler: Handler(handlerFunc: (_, params) => const RoomMusicPage()), ); router.define( roomRocketRank, handler: Handler(handlerFunc: (_, params) => const RoomRocketRankPage()), ); router.define( roomEdit, handler: Handler( handlerFunc: (_, params) => RoomEditPage( needRestCurrentRoomInfo: params['need']?.first ?? "false", ), ), ); } }