592 lines
16 KiB
TypeScript
592 lines
16 KiB
TypeScript
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<PanelType, Node> = 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);
|
||
if (subs) {
|
||
subs.forEach((n) => {
|
||
if (n.name != "") {
|
||
n.getComponent(li_BaseView)?.close();
|
||
} else {
|
||
//n.destroy();
|
||
}
|
||
});
|
||
}
|
||
|
||
this.subPanelDic.delete(this.currentActivePanel);
|
||
}
|
||
// 更新NavigationPanel按钮状态
|
||
this.navigationPanel.updateButtonStates?.(panelType);
|
||
|
||
// 显示面板
|
||
this.showPanelWithAnimation(panel, showDirection, () => {
|
||
this.currentActivePanel = panel;
|
||
this.navigationPanel.hideLoading?.();
|
||
});
|
||
});
|
||
}
|
||
|
||
private subPanelDic: Map<Node, Node[]> = 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();
|
||
}
|
||
}
|
||
}
|
||
}
|