import { ViewManager } from "db://assets/Scripts/Main/Manager/ViewManager"; import { UITransitionHelper } from "../utils/UITransitionHelper"; import GameRootUI from "../../Main/Common/GameRootUI"; import { Node, sys } from "cc"; import li_EventManager from "../../Main/Common/li_EventManager"; import { InnerMsgCode } from "../../Main/Config/InnerMsgCode"; import { ThemePanel } from "../ui/panels/ThemePanel"; import { GirlListPanel } from "../ui/panels/GirlListPanel"; import li_BaseView from "../../Main/Common/li_BaseView"; /** * 页面过渡动画类型枚举 */ export enum PageTransitionType { NONE = "none", SLIDE_LEFT = "slide_left", SLIDE_RIGHT = "slide_right", } /** * NavigationPanel面板类型枚举 */ export enum PanelType { THEME = "ThemePanel", GIRL_DETAIL = "GirlDetailPanel", CHAT = "ChatPanel", PERSONAL = "PersonalPanel", } /** * 页面过渡动画配置接口 */ export interface PageTransitionConfig { incomingTransition: PageTransitionType; outgoingTransition: PageTransitionType; duration?: number; simultaneous?: boolean; } /** * 导航管理器 * * 负责管理游戏中的页面导航和路由,将导航逻辑从业务逻辑中分离出来 * 统一管理NavigationPanel和其他面板的切换 * * @author AI Chat System * @version 1.0.0 */ export class NavigationManager { private static _instance: NavigationManager; // NavigationPanel相关属性 private navigationPanel: any = null; // NavigationPanel实例引用 private currentActivePanelType: PanelType = PanelType.THEME; private currentActivePanel: Node; private panelCache: Map = new Map(); // 面板缓存 private currentVisiblePanel: Node = null; // 选中的角色相关信息 private selectedGirlId: number = 10002; // 当前选中的角色ID private selectedCategoryId: number = -1; // 当前选中的主题ID private themePanel: ThemePanel = null; private girlListPanel: GirlListPanel = null; private static LastSelectGirlID = "LastSelectGirlID"; /** * 获取NavigationManager的单例实例 * * @returns {NavigationManager} 导航管理器实例 * @static */ public static get Instance(): NavigationManager { if (!this._instance) { this._instance = new NavigationManager(); //初始化默认选的girl let cacheGirlId = sys.localStorage.getItem(this.LastSelectGirlID); if (!cacheGirlId) { cacheGirlId = 10002; sys.localStorage.setItem(this.LastSelectGirlID, cacheGirlId); } this._instance.selectedGirlId = Number(cacheGirlId); let cacheCategoryId = sys.localStorage.getItem("LastSelectCategoryId"); if (!cacheCategoryId) { cacheCategoryId = 0; sys.localStorage.setItem("LastSelectCategoryId", cacheCategoryId); } this._instance.selectedCategoryId = cacheCategoryId; } return this._instance; } private constructor() { // 初始化事件监听 this.initEventListeners(); } /** * 初始化事件监听 */ private initEventListeners(): void { // } /** * 注册NavigationPanel实例 * @param panel NavigationPanel实例 */ public registerNavigationPanel(panel: any): void { this.navigationPanel = panel; console.log("[NavigationManager] NavigationPanel registered"); } /** * 统一的面板切换方法 * @param panelType 目标面板类型 */ public switchToPanel(panelType: PanelType, force: boolean = false): void { if (this.currentActivePanelType === panelType && !force) { if (panelType === PanelType.THEME) { this.girlListPanel.hide(); } return; } if (!this.navigationPanel) { console.warn( "[NavigationManager] NavigationPanel not registered, fallback to direct ViewManager call" ); this.fallbackSwitchPanel(panelType); return; } // 通知NavigationPanel显示加载状态 this.navigationPanel.showLoading?.(); // 计算动画方向 const currentIndex = this.getPanelIndex(this.currentActivePanelType); const targetIndex = this.getPanelIndex(panelType); const isMovingRight = currentIndex < targetIndex; const hideDirection = isMovingRight ? "left" : "right"; const showDirection = isMovingRight ? "right" : "left"; // 隐藏当前面板(包括子页面) this.hideCurrentPanelWithChildren(hideDirection); // 加载并显示目标面板 this.loadOrGetPanel(panelType, (panel: Node) => { this.currentActivePanelType = panelType; this.currentVisiblePanel = panel; if (this.subPanelDic.has(this.currentActivePanel)) { //如果有子页面,关闭掉 let subs = this.subPanelDic.get(this.currentActivePanel); subs.forEach((n) => { n.getComponent(li_BaseView).close(); }); this.subPanelDic.delete(this.currentActivePanel); } // 更新NavigationPanel按钮状态 this.navigationPanel.updateButtonStates?.(panelType); // 显示面板 this.showPanelWithAnimation(panel, showDirection, () => { this.currentActivePanel = panel; this.navigationPanel.hideLoading?.(); }); }); } private subPanelDic: Map = new Map(); public openSubPanel(panelName: string, basePanel: Node, data: any = null) { const callback = (n: Node) => { if (!this.subPanelDic.has(basePanel)) { this.subPanelDic.set(basePanel, []); } this.subPanelDic.get(basePanel).push(n); }; ViewManager.I.openBundlesView(panelName, data, callback); } /** * 获取面板索引(用于动画方向计算) */ private getPanelIndex(panelType: PanelType): number { switch (panelType) { case PanelType.THEME: return 0; case PanelType.GIRL_DETAIL: return 1; case PanelType.CHAT: return 2; case PanelType.PERSONAL: return 3; default: return 0; } } /** * 获取面板名称 */ private getPanelName(panelType: PanelType): string { return panelType as string; } /** * 获取面板数据 */ private getPanelData(panelType: PanelType): any { switch (panelType) { case PanelType.GIRL_DETAIL: return this.selectedGirlId; // 使用当前选中的角色ID case PanelType.CHAT: return { girlId: this.selectedGirlId }; // 使用当前选中的角色ID default: return null; } } /** * 加载或获取面板 */ private loadOrGetPanel( panelType: PanelType, callback: (panel: Node) => void ) { // 检查缓存 if (this.panelCache.has(panelType)) { const cachedPanel = this.panelCache.get(panelType); if (cachedPanel && cachedPanel.isValid) { // 特殊处理:主题面板刷新(避免重复调用Show) if (panelType === PanelType.THEME) { const themePanel = cachedPanel.getComponent(ThemePanel); if (themePanel) { // 不在这里调用Show(),因为ThemePanel已经有加载状态保护 // 只在必要时调用onHide()确保子页面状态正确 if (typeof themePanel.onHide === "function") { console.log("[NavigationManager] 确保主题面板子页面状态正确"); themePanel.onHide(); } } } callback(cachedPanel); return; } else { this.panelCache.delete(panelType); } } // 加载新面板 const panelName = this.getPanelName(panelType); const openData = this.getPanelData(panelType); ViewManager.I.openBundlesView(panelName, openData, (panel: Node) => { if (panel && panel.isValid) { this.panelCache.set(panelType, panel); if (panelName === "ThemePanel") { this.themePanel = panel.getComponent(ThemePanel); } callback(panel); } }); } /** * 隐藏当前面板及其子页面 */ private hideCurrentPanelWithChildren(direction: "left" | "right") { if (!this.currentVisiblePanel) { return; } // 如果当前是ThemePanel,需要同时处理可能的子页面(GirlListPanel) if (this.currentActivePanelType === PanelType.THEME) { // 查找并隐藏GirlListPanel子页面 this.hideThemePanelChildren(direction); // 隐藏ThemePanel主面板 this.hidePanelWithAnimation(this.currentVisiblePanel, direction); } else { // 其他面板直接隐藏 this.hidePanelWithAnimation(this.currentVisiblePanel, direction); } } /** * 隐藏ThemePanel的子页面 */ private hideThemePanelChildren(direction: "left" | "right") { const themePanel = this.findThemePanelNode(); if (themePanel) { // 获取子页面节点 const childPanel = this.getThemePanelChildNode(themePanel); if (childPanel && childPanel.active) { console.log( "[NavigationManager] Hiding ThemePanel child with animation" ); this.hidePanelWithAnimation(childPanel, direction); } } } /** * 获取ThemePanel的子页面节点 */ private getThemePanelChildNode(themePanel: ThemePanel): Node | null { try { // ThemePanel存储子页面在currentChildPanel属性中 const childPanel = themePanel.getChildPanel(); if (childPanel) return childPanel.node; return null; } catch (error) { console.error( "[NavigationManager] Error getting child panel node:", error ); return null; } } /** * 隐藏面板动画 */ private hidePanelWithAnimation( panel: Node, direction: "left" | "right", callback?: Function ) { if (!panel || !panel.isValid || !panel.active) { callback && callback(); return; } if (direction === "left") { UITransitionHelper.slideOutToLeft(panel, 0.3, () => { panel.active = false; callback && callback(); }); } else { UITransitionHelper.slideOutToRight(panel, 0.3, () => { panel.active = false; callback && callback(); }); } } /** * 显示面板动画 */ private showPanelWithAnimation( panel: Node, direction: "left" | "right", callback?: Function ) { if (!panel || !panel.isValid) { callback && callback(); return; } panel.active = true; if (panel.name === "ThemePanel" && this.girlListPanel) { this.showPanelWithAnimation(this.girlListPanel.node, direction, callback); } if (direction === "right") { UITransitionHelper.slideInFromRight(panel, 0.3, () => { callback && callback(); }); } else { UITransitionHelper.slideInFromLeft(panel, 0.3, () => { callback && callback(); }); } } /** * 后备切换方法(当NavigationPanel未注册时) */ private fallbackSwitchPanel(panelType: PanelType): void { const panelName = this.getPanelName(panelType); const openData = this.getPanelData(panelType); ViewManager.I.openBundlesView(panelName, openData); } /** * 获取当前激活的面板类型 */ public getCurrentActivePanel(): PanelType { return this.currentActivePanelType; } /** * 设置选中的角色ID * @param girlId 角色ID */ public setSelectedGirlId(girlId: number): void { this.selectedGirlId = girlId; sys.localStorage.setItem(NavigationManager.LastSelectGirlID, girlId); console.log("[NavigationManager] Selected girl ID set to:", girlId); } /** * 获取当前选中的角色ID * @returns 当前选中的角色ID */ public getSelectedGirlId(): number { return this.selectedGirlId; } /** * 设置选中的主题ID * @param themeId 主题ID */ public setSelectedCategoryId(themeId: number): void { this.selectedCategoryId = themeId; console.log("[NavigationManager] Selected theme ID set to:", themeId); } /** * 获取当前选中的主题ID * @returns 当前选中的主题ID */ public getSelectedCategoryId(): number { return this.selectedCategoryId; } /** * 进入角色列表页面(作为 ThemePanel 的子页面) * * @param {number} themeId - 主题ID,用于筛选角色 * * @example * ```typescript * NavigationManager.Instance.navigateToGirlList(1); * ``` */ public navigateToGirlList(themeId: number): void { if (themeId == null || themeId < 0) { console.warn("Invalid theme ID for girl list navigation:", themeId); return; } // 更新选中的主题ID this.setSelectedCategoryId(themeId); console.log( `[NavigationManager] Navigating to girl list with theme ID: ${themeId}` ); // 先检查是否已有GirlListPanel存在 const existingGirlListPanel = this.findExistingGirlListPanel(); if (existingGirlListPanel) { // 如果面板已存在,重新显示并刷新数据 console.log("[NavigationManager] Reactivating existing GirlListPanel"); this.reactivateGirlListPanel(existingGirlListPanel); } else { // 如果面板不存在,创建新的 console.log("[NavigationManager] Creating new GirlListPanel"); ViewManager.I.openBundlesView( "GirlListPanel", { themeId: themeId, parentPanel: "ThemePanel", // 标记父页面 }, (girlListPanelNode) => { this.girlListPanel = girlListPanelNode.getComponent(GirlListPanel); // 获取 ThemePanel 实例并设置子页面关系 console.log( "[NavigationManager] GirlListPanel opened, setting up parent-child relationship" ); this.setupParentChildRelationship(girlListPanelNode); } ); } } /** * 查找已存在的GirlListPanel */ private findExistingGirlListPanel(): GirlListPanel { if (this.girlListPanel) return this.girlListPanel; else return null; } /** * 重新激活已存在的GirlListPanel */ private reactivateGirlListPanel(panel: GirlListPanel): void { try { // 重新激活面板 panel.node.active = true; // 获取面板组件并刷新数据 //const girlListComponent = panelNode.getComponent("GirlListPanel"); if (panel) { // 如果有刷新方法,调用它来更新主题数据 panel.refresh(); console.log( "[NavigationManager] GirlListPanel reactivated with theme:", this.selectedCategoryId ); } // 重新建立父子关系 this.setupParentChildRelationship(panel); } catch (error) { console.error( "[NavigationManager] Error reactivating GirlListPanel:", error ); } } /** * 建立父子页面关系的私有方法 * @private * @param girlListPanelNode GirlListPanel 节点 */ private setupParentChildRelationship(girlListPanelNode: any): void { try { // 查找 ThemePanel 实例 const themePanel = this.findThemePanelNode(); if (themePanel) { const girlListPanelComponent = girlListPanelNode.getComponent(GirlListPanel); if (themePanel && girlListPanelComponent) { console.log( "[NavigationManager] Setting up parent-child relationship" ); this.themePanel.setChildPanel(girlListPanelComponent); } else { console.warn("[NavigationManager] Failed to get panel components"); } } else { console.warn("[NavigationManager] ThemePanel not found"); } } catch (error) { console.error( "[NavigationManager] Error setting up parent-child relationship:", error ); } } /** * 查找 ThemePanel 节点的私有方法 * @private * @returns ThemePanel 节点或 null */ private findThemePanelNode(): ThemePanel { if (this.themePanel) return this.themePanel; return null; } /** * 处理导航时 ThemePanel 子页面的隐藏逻辑 * @private */ private handleThemePanelChildPanelsOnNavigation(): void { console.log( "[NavigationManager] Handling ThemePanel child panels on navigation" ); const themePanelNode = this.findThemePanelNode(); if (themePanelNode) { if (themePanelNode && themePanelNode.hideChildPanel) { console.log("[NavigationManager] Closing ThemePanel child panels"); themePanelNode.hideChildPanel(); } } } }