Files
18xchat/assets/Scripts/chat18x/manager/NavigationManager.ts
T
2025-09-17 16:12:54 +08:00

588 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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) => {
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<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();
}
}
}
}