950 lines
26 KiB
TypeScript
950 lines
26 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";
|
|
import { logger } from "db://assets/Scripts/Main/Common/Logger";
|
|
|
|
/**
|
|
* 页面过渡动画类型枚举
|
|
*/
|
|
export enum PageTransitionType {
|
|
NONE = "none",
|
|
SLIDE_LEFT = "slide_left",
|
|
SLIDE_RIGHT = "slide_right",
|
|
SLIDE_UP = "slide_up",
|
|
SLIDE_DOWN = "slide_down",
|
|
FADE = "fade",
|
|
SCALE = "scale",
|
|
}
|
|
|
|
/**
|
|
* NavigationPanel面板类型枚举
|
|
*/
|
|
export enum PanelType {
|
|
THEME = "ThemePanel",
|
|
GIRL_DETAIL = "GirlDetailPanel",
|
|
PAST_GIRL_LIST = "PastGirlListPanel",
|
|
PERSONAL = "PersonalPanel",
|
|
}
|
|
|
|
/**
|
|
* 页面过渡动画配置接口
|
|
*/
|
|
export interface PageTransitionConfig {
|
|
incomingTransition: PageTransitionType;
|
|
outgoingTransition: PageTransitionType;
|
|
duration?: number;
|
|
simultaneous?: boolean;
|
|
}
|
|
|
|
/**
|
|
* 子面板动画配置接口
|
|
*/
|
|
export interface SubPanelAnimationConfig {
|
|
openAnimation: PageTransitionType;
|
|
closeAnimation: PageTransitionType;
|
|
duration?: number;
|
|
}
|
|
|
|
/**
|
|
* 导航管理器
|
|
*
|
|
* 负责管理游戏中的页面导航和路由,将导航逻辑从业务逻辑中分离出来
|
|
* 统一管理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.PAST_GIRL_LIST;
|
|
private currentActivePanel: Node = null; // 初始化为null
|
|
private panelCache: Map<PanelType, Node> = new Map(); // 面板缓存
|
|
|
|
// 选中的角色相关信息
|
|
private selectedGirlId: number = 10002; // 当前选中的角色ID
|
|
private selectedCategoryId: number = -1; // 当前选中的主题ID
|
|
|
|
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 = 10016;
|
|
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;
|
|
logger.log("[NavigationManager] NavigationPanel registered");
|
|
}
|
|
|
|
/**
|
|
* 统一的面板切换方法
|
|
* @param panelType 目标面板类型
|
|
*/
|
|
public switchToPanel(
|
|
panelType: PanelType,
|
|
force: boolean = false,
|
|
callback: Function = null
|
|
): Node {
|
|
if (!panelType) {
|
|
logger.error("[NavigationManager] switchToPanel: panelType is invalid");
|
|
return null;
|
|
}
|
|
|
|
if (this.currentActivePanelType === panelType && !force) {
|
|
logger.log(
|
|
`[NavigationManager] Already on ${panelType}, skipping switch`
|
|
);
|
|
return this.currentActivePanel;
|
|
}
|
|
|
|
if (!this.navigationPanel) {
|
|
logger.warn(
|
|
"[NavigationManager] NavigationPanel not registered, fallback to direct ViewManager call"
|
|
);
|
|
//this.fallbackSwitchPanel(panelType);
|
|
return null;
|
|
}
|
|
|
|
// 切换面板前先关闭所有弹窗
|
|
this.closeAllPopups();
|
|
|
|
// 通知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";
|
|
|
|
// 隐藏当前面板(包括子页面)
|
|
if (this.currentActivePanel && this.currentActivePanel.isValid) {
|
|
this.hidePanelWithAnimation(this.currentActivePanel, hideDirection);
|
|
}
|
|
|
|
// 加载并显示目标面板
|
|
this.loadOrGetPanel(panelType, (panel: Node) => {
|
|
// 清理当前面板的subPanel(在hidePanelWithAnimation中已经清理,这里不需要重复)
|
|
|
|
this.currentActivePanelType = panelType;
|
|
|
|
// 更新NavigationPanel按钮状态
|
|
this.navigationPanel.updateButtonStates?.(panelType);
|
|
|
|
// 显示面板
|
|
this.showPanelWithAnimation(panel, showDirection, () => {
|
|
this.currentActivePanel = panel;
|
|
this.navigationPanel.hideLoading?.();
|
|
if (callback instanceof Function) callback(panel);
|
|
});
|
|
});
|
|
}
|
|
|
|
private subPanelDic: Map<Node, Node[]> = new Map();
|
|
private subPanelMapping: Map<Node, PanelType> = new Map();
|
|
private subPanelAnimationConfigs: Map<Node, SubPanelAnimationConfig> =
|
|
new Map();
|
|
|
|
// 弹窗管理相关属性
|
|
private popupPanels: Set<Node> = new Set(); // 管理所有打开的弹窗
|
|
|
|
// 动画锁,防止动画中重复操作
|
|
private isAnimating: boolean = false;
|
|
|
|
/**
|
|
* 带动画的子面板清理方法
|
|
* @param basePanel 主面板节点
|
|
* @param callback 所有动画完成后的回调
|
|
*/
|
|
private clearSubPanelsWithAnimation(
|
|
basePanel: Node,
|
|
callback?: Function
|
|
): void {
|
|
if (!basePanel || !basePanel.isValid) {
|
|
callback && callback();
|
|
return;
|
|
}
|
|
|
|
const subPanels = this.subPanelDic.get(basePanel);
|
|
if (!subPanels || subPanels.length === 0) {
|
|
callback && callback();
|
|
return;
|
|
}
|
|
|
|
let completedCount = 0;
|
|
const totalCount = subPanels.length;
|
|
|
|
// 完成动画的回调
|
|
const onAnimationComplete = () => {
|
|
completedCount++;
|
|
if (completedCount >= totalCount) {
|
|
// 清理subPanelDic
|
|
this.subPanelDic.delete(basePanel);
|
|
callback && callback();
|
|
}
|
|
};
|
|
|
|
// 同时播放所有子面板的关闭动画
|
|
for (let i = subPanels.length - 1; i >= 0; i--) {
|
|
const subPanel = subPanels[i];
|
|
if (subPanel && subPanel.isValid) {
|
|
// 获取动画配置
|
|
let config = this.subPanelAnimationConfigs.get(subPanel);
|
|
if (!config) {
|
|
config = {
|
|
openAnimation: PageTransitionType.SCALE,
|
|
closeAnimation: PageTransitionType.SCALE,
|
|
duration: 0.2,
|
|
};
|
|
}
|
|
|
|
// 播放关闭动画
|
|
this.playSubPanelCloseAnimation(subPanel, config, () => {
|
|
// 清理映射
|
|
this.subPanelMapping.delete(subPanel);
|
|
this.subPanelAnimationConfigs.delete(subPanel);
|
|
|
|
// 销毁节点
|
|
const baseView = subPanel.getComponent(li_BaseView);
|
|
if (baseView) {
|
|
baseView.close();
|
|
} else {
|
|
subPanel.destroy();
|
|
}
|
|
|
|
onAnimationComplete();
|
|
});
|
|
} else {
|
|
onAnimationComplete();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 统一的subPanel清理方法
|
|
* @param basePanel 主面板节点
|
|
* @param destroyPanels 是否销毁面板,默认为true
|
|
*/
|
|
private clearSubPanels(basePanel: Node, destroyPanels: boolean = true): void {
|
|
if (!basePanel || !basePanel.isValid) {
|
|
return;
|
|
}
|
|
|
|
const subPanels = this.subPanelDic.get(basePanel);
|
|
if (!subPanels || subPanels.length === 0) {
|
|
return;
|
|
}
|
|
|
|
// 清理所有子面板
|
|
for (let i = subPanels.length - 1; i >= 0; i--) {
|
|
const subPanel = subPanels[i];
|
|
if (subPanel && subPanel.isValid) {
|
|
// 清理subPanelMapping
|
|
this.subPanelMapping.delete(subPanel);
|
|
|
|
// 清理动画配置
|
|
this.subPanelAnimationConfigs.delete(subPanel);
|
|
|
|
if (destroyPanels) {
|
|
const baseView = subPanel.getComponent(li_BaseView);
|
|
if (baseView) {
|
|
baseView.close();
|
|
} else {
|
|
subPanel.destroy();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 清理subPanelDic
|
|
this.subPanelDic.delete(basePanel);
|
|
}
|
|
public openSubPanel(
|
|
panelName: string,
|
|
basePanel: Node,
|
|
data: any = null,
|
|
animationConfig?: SubPanelAnimationConfig
|
|
) {
|
|
if (!panelName) {
|
|
console.error("[NavigationManager] openSubPanel: panelName is empty");
|
|
return;
|
|
}
|
|
|
|
if (!basePanel || !basePanel.isValid) {
|
|
console.error("[NavigationManager] openSubPanel: basePanel is invalid");
|
|
return;
|
|
}
|
|
|
|
// 使用默认动画配置
|
|
const defaultConfig: SubPanelAnimationConfig = {
|
|
openAnimation: PageTransitionType.SCALE,
|
|
closeAnimation: PageTransitionType.SCALE,
|
|
duration: 0.3,
|
|
};
|
|
const config = animationConfig || defaultConfig;
|
|
|
|
const callback = (n: Node) => {
|
|
if (!n || !n.isValid) {
|
|
console.error(
|
|
"[NavigationManager] openSubPanel: created panel is invalid"
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (!this.subPanelDic.has(basePanel)) {
|
|
this.subPanelDic.set(basePanel, []);
|
|
}
|
|
|
|
const subPanels = this.subPanelDic.get(basePanel);
|
|
subPanels.push(n);
|
|
|
|
const basePanelType = this.getPanelType(basePanel);
|
|
if (basePanelType) {
|
|
this.subPanelMapping.set(n, basePanelType);
|
|
} else {
|
|
console.warn(
|
|
`[NavigationManager] 无法确定basePanel类型: ${basePanel.name}`
|
|
);
|
|
}
|
|
// 存储动画配置
|
|
this.subPanelAnimationConfigs.set(n, config);
|
|
|
|
// 执行打开动画
|
|
this.playSubPanelOpenAnimation(n, config);
|
|
};
|
|
|
|
ViewManager.I.openBundlesView(panelName, data, callback);
|
|
}
|
|
|
|
/**
|
|
* 支持自定义动画方向的面板切换方法
|
|
* @param panelType 目标面板类型
|
|
* @param transitionConfig 过渡动画配置
|
|
* @param force 是否强制切换
|
|
*/
|
|
public switchToPanelWithTransition(
|
|
panelType: PanelType,
|
|
transitionConfig: PageTransitionConfig,
|
|
force: boolean = false
|
|
): Node {
|
|
if (!panelType) {
|
|
logger.error(
|
|
"[NavigationManager] switchToPanelWithTransition: panelType is invalid"
|
|
);
|
|
return null;
|
|
}
|
|
|
|
if (this.currentActivePanelType === panelType && !force) {
|
|
logger.log(
|
|
`[NavigationManager] Already on ${panelType}, skipping switch`
|
|
);
|
|
return this.currentActivePanel;
|
|
}
|
|
|
|
if (!this.navigationPanel) {
|
|
logger.warn(
|
|
"[NavigationManager] NavigationPanel not registered, fallback to direct ViewManager call"
|
|
);
|
|
return null;
|
|
}
|
|
|
|
// 切换面板前先关闭所有弹窗
|
|
this.closeAllPopups();
|
|
|
|
// 通知NavigationPanel显示加载状态
|
|
this.navigationPanel.showLoading?.();
|
|
|
|
// 获取动画方向
|
|
const hideDirection = this.getDirectionFromTransitionType(
|
|
transitionConfig.outgoingTransition
|
|
);
|
|
const showDirection = this.getDirectionFromTransitionType(
|
|
transitionConfig.incomingTransition
|
|
);
|
|
|
|
// 隐藏当前面板(包括子页面)
|
|
if (this.currentActivePanel && this.currentActivePanel.isValid) {
|
|
this.hidePanelWithAnimation(this.currentActivePanel, hideDirection);
|
|
}
|
|
|
|
// 加载并显示目标面板
|
|
this.loadOrGetPanel(panelType, (panel: Node) => {
|
|
this.currentActivePanelType = panelType;
|
|
|
|
// 更新NavigationPanel按钮状态
|
|
this.navigationPanel.updateButtonStates?.(panelType);
|
|
|
|
// 显示面板
|
|
this.showPanelWithAnimation(panel, showDirection, () => {
|
|
this.currentActivePanel = panel;
|
|
this.navigationPanel.hideLoading?.();
|
|
});
|
|
});
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 将过渡类型转换为方向字符串
|
|
*/
|
|
private getDirectionFromTransitionType(
|
|
transitionType: PageTransitionType
|
|
): "left" | "right" | "up" | "down" {
|
|
switch (transitionType) {
|
|
case PageTransitionType.SLIDE_LEFT:
|
|
return "left";
|
|
case PageTransitionType.SLIDE_RIGHT:
|
|
return "right";
|
|
case PageTransitionType.SLIDE_UP:
|
|
return "up";
|
|
case PageTransitionType.SLIDE_DOWN:
|
|
return "down";
|
|
default:
|
|
return "left"; // 默认向左
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 执行子面板打开动画
|
|
*/
|
|
private playSubPanelOpenAnimation(
|
|
panel: Node,
|
|
config: SubPanelAnimationConfig
|
|
): void {
|
|
if (!panel || !panel.isValid) {
|
|
return;
|
|
}
|
|
|
|
const duration = config.duration || 0.3;
|
|
//panel.active = false;
|
|
|
|
switch (config.openAnimation) {
|
|
case PageTransitionType.SCALE:
|
|
UITransitionHelper.scaleIn(panel, duration);
|
|
break;
|
|
case PageTransitionType.FADE:
|
|
UITransitionHelper.fadeIn(panel, duration);
|
|
break;
|
|
case PageTransitionType.SLIDE_UP:
|
|
UITransitionHelper.slideInFromBottom(panel, duration);
|
|
break;
|
|
case PageTransitionType.SLIDE_DOWN:
|
|
UITransitionHelper.slideInFromTop(panel, duration);
|
|
break;
|
|
case PageTransitionType.SLIDE_LEFT:
|
|
UITransitionHelper.slideInFromRight(panel, duration);
|
|
break;
|
|
case PageTransitionType.SLIDE_RIGHT:
|
|
UITransitionHelper.slideInFromLeft(panel, duration);
|
|
break;
|
|
default:
|
|
// 无动画,直接显示
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 执行子面板关闭动画
|
|
*/
|
|
private playSubPanelCloseAnimation(
|
|
panel: Node,
|
|
config: SubPanelAnimationConfig,
|
|
callback?: Function
|
|
): void {
|
|
if (!panel || !panel.isValid) {
|
|
callback && callback();
|
|
return;
|
|
}
|
|
|
|
const duration = config.duration || 0.3;
|
|
|
|
switch (config.closeAnimation) {
|
|
case PageTransitionType.SCALE:
|
|
UITransitionHelper.scaleOut(panel, duration, callback);
|
|
break;
|
|
case PageTransitionType.FADE:
|
|
UITransitionHelper.fadeOut(panel, duration, callback);
|
|
break;
|
|
case PageTransitionType.SLIDE_UP:
|
|
UITransitionHelper.slideOutToTop(panel, duration, callback);
|
|
break;
|
|
case PageTransitionType.SLIDE_DOWN:
|
|
UITransitionHelper.slideOutToBottom(panel, duration, callback);
|
|
break;
|
|
case PageTransitionType.SLIDE_LEFT:
|
|
UITransitionHelper.slideOutToLeft(panel, duration, callback);
|
|
break;
|
|
case PageTransitionType.SLIDE_RIGHT:
|
|
UITransitionHelper.slideOutToRight(panel, duration, callback);
|
|
break;
|
|
default:
|
|
// 无动画,直接执行回调
|
|
callback && callback();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 打开弹窗面板
|
|
* @param panelName 弹窗面板名称
|
|
* @param data 传递的数据
|
|
* @param callback 可选的回调函数
|
|
*/
|
|
public openPopupPanel(
|
|
panelName: string,
|
|
data: any = null,
|
|
callback?: Function
|
|
): void {
|
|
if (!panelName) {
|
|
logger.error("[NavigationManager] openPopupPanel: panelName is empty");
|
|
return;
|
|
}
|
|
|
|
const popupCallback = (panel: Node) => {
|
|
if (!panel || !panel.isValid) {
|
|
logger.error(
|
|
"[NavigationManager] openPopupPanel: created panel is invalid"
|
|
);
|
|
return;
|
|
}
|
|
|
|
// 将弹窗添加到管理集合中
|
|
this.popupPanels.add(panel);
|
|
logger.log(
|
|
`[NavigationManager] Popup panel opened: ${panelName}, total popups: ${this.popupPanels.size}`
|
|
);
|
|
|
|
if (callback) {
|
|
callback(panel);
|
|
}
|
|
};
|
|
|
|
ViewManager.I.openBundlesPopupView(panelName, data, popupCallback);
|
|
}
|
|
|
|
/**
|
|
* 关闭弹窗面板
|
|
* @param panel 要关闭的弹窗节点
|
|
*/
|
|
public closePopupPanel(panel: Node): void {
|
|
if (!panel || !panel.isValid) {
|
|
logger.warn("[NavigationManager] closePopupPanel: panel is invalid");
|
|
return;
|
|
}
|
|
|
|
// 从弹窗管理集合中移除
|
|
if (this.popupPanels.has(panel)) {
|
|
this.popupPanels.delete(panel);
|
|
logger.log(
|
|
`[NavigationManager] Popup panel closed: ${panel.name}, total popups: ${this.popupPanels.size}`
|
|
);
|
|
}
|
|
|
|
// 关闭面板
|
|
try {
|
|
const baseView = panel.getComponent(li_BaseView);
|
|
if (baseView) {
|
|
baseView.close();
|
|
} else {
|
|
panel.destroy();
|
|
}
|
|
} catch (error) {
|
|
logger.error("[NavigationManager] closePopupPanel error:", error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 关闭所有弹窗
|
|
*/
|
|
private closeAllPopups(): void {
|
|
if (this.popupPanels.size === 0) {
|
|
return;
|
|
}
|
|
|
|
logger.log(
|
|
`[NavigationManager] Closing all popups, count: ${this.popupPanels.size}`
|
|
);
|
|
|
|
// 复制Set以避免在迭代过程中修改
|
|
const popupPanelsToClose = Array.from(this.popupPanels);
|
|
|
|
for (const panel of popupPanelsToClose) {
|
|
if (panel && panel.isValid) {
|
|
this.closePopupPanel(panel);
|
|
}
|
|
}
|
|
|
|
// 确保清空集合
|
|
this.popupPanels.clear();
|
|
}
|
|
public closeSubPanel(
|
|
panel: Node | li_BaseView,
|
|
animationConfig?: SubPanelAnimationConfig
|
|
) {
|
|
if (!panel) {
|
|
logger.warn(
|
|
"[NavigationManager] closeSubPanel: panel is null or undefined"
|
|
);
|
|
return;
|
|
}
|
|
|
|
let panelNode: Node;
|
|
if (panel instanceof Node) {
|
|
panelNode = panel;
|
|
} else {
|
|
panelNode = panel.node;
|
|
}
|
|
|
|
if (!panelNode || !panelNode.isValid) {
|
|
console.warn("[NavigationManager] closeSubPanel: panelNode is invalid");
|
|
return;
|
|
}
|
|
|
|
// 获取动画配置(优先使用传入的配置,然后使用存储的配置,最后使用默认配置)
|
|
let config = animationConfig;
|
|
if (!config && this.subPanelAnimationConfigs.has(panelNode)) {
|
|
config = this.subPanelAnimationConfigs.get(panelNode);
|
|
}
|
|
if (!config) {
|
|
config = {
|
|
openAnimation: PageTransitionType.SCALE,
|
|
closeAnimation: PageTransitionType.SCALE,
|
|
duration: 0.3,
|
|
};
|
|
}
|
|
|
|
// 执行关闭动画
|
|
this.playSubPanelCloseAnimation(panelNode, config, () => {
|
|
// 从管理映射中移除
|
|
this.removeSubPanelFromMappings(panelNode);
|
|
|
|
// 销毁或关闭panel
|
|
try {
|
|
if (panel instanceof Node) {
|
|
panel.destroy();
|
|
} else {
|
|
panel.close();
|
|
}
|
|
} catch (error) {
|
|
console.error("[NavigationManager] closeSubPanel error:", error);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 从管理映射中移除子面板
|
|
*/
|
|
private removeSubPanelFromMappings(panelNode: Node): void {
|
|
// 从subPanelMapping和subPanelDic中移除
|
|
if (this.subPanelMapping.has(panelNode)) {
|
|
const baseType = this.subPanelMapping.get(panelNode);
|
|
const baseNode = this.panelCache.get(baseType);
|
|
|
|
if (baseNode && this.subPanelDic.has(baseNode)) {
|
|
const subPanels = this.subPanelDic.get(baseNode);
|
|
const index = subPanels.indexOf(panelNode);
|
|
if (index !== -1) {
|
|
subPanels.splice(index, 1);
|
|
// 如果subPanels为空,删除整个条目
|
|
if (subPanels.length === 0) {
|
|
this.subPanelDic.delete(baseNode);
|
|
}
|
|
} else {
|
|
console.warn(
|
|
`[NavigationManager] ${panelNode.name} 不在子页面列表中`
|
|
);
|
|
}
|
|
}
|
|
|
|
this.subPanelMapping.delete(panelNode);
|
|
}
|
|
|
|
// 移除动画配置
|
|
if (this.subPanelAnimationConfigs.has(panelNode)) {
|
|
this.subPanelAnimationConfigs.delete(panelNode);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取面板索引(用于动画方向计算)
|
|
*/
|
|
private getPanelIndex(panelType: PanelType): number {
|
|
switch (panelType) {
|
|
case PanelType.THEME:
|
|
return 0;
|
|
case PanelType.GIRL_DETAIL:
|
|
return 1;
|
|
case PanelType.PAST_GIRL_LIST:
|
|
return 2;
|
|
case PanelType.PERSONAL:
|
|
return 3;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
private getPanelType(node: Node): PanelType {
|
|
if (!node || !node.isValid) {
|
|
console.warn("[NavigationManager] getPanelType: node is invalid");
|
|
return null;
|
|
}
|
|
|
|
switch (node.name) {
|
|
case "ThemePanel":
|
|
return PanelType.THEME;
|
|
case "GirlDetailPanel":
|
|
return PanelType.GIRL_DETAIL;
|
|
case "PastGirlListPanel":
|
|
return PanelType.PAST_GIRL_LIST;
|
|
case "PersonalPanel":
|
|
return PanelType.PERSONAL;
|
|
default:
|
|
console.warn(
|
|
`[NavigationManager] Unknown panel type for node: ${node.name}`
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取面板名称
|
|
*/
|
|
private getPanelName(panelType: PanelType): string {
|
|
return panelType as string;
|
|
}
|
|
|
|
/**
|
|
* 获取面板数据
|
|
*/
|
|
private getPanelData(panelType: PanelType): any {
|
|
switch (panelType) {
|
|
case PanelType.GIRL_DETAIL:
|
|
return 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) {
|
|
// 确保缓存panel的subPanel状态正确,清理可能残留的subPanel引用
|
|
this.clearSubPanels(cachedPanel, false); // 不销毁panel,只清理引用
|
|
|
|
// 特殊处理:主题面板刷新(避免重复调用Show)
|
|
if (panelType === PanelType.THEME) {
|
|
const themePanel = cachedPanel.getComponent(ThemePanel);
|
|
if (themePanel) {
|
|
// 不在这里调用Show(),因为ThemePanel已经有加载状态保护
|
|
// 只在必要时调用onHide()确保子页面状态正确
|
|
if (typeof themePanel.onHide === "function") {
|
|
logger.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);
|
|
callback(panel);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 隐藏面板动画
|
|
*/
|
|
private hidePanelWithAnimation(
|
|
panel: Node,
|
|
direction: "left" | "right" | "up" | "down",
|
|
callback?: Function
|
|
) {
|
|
if (!panel || !panel.isValid) {
|
|
callback && callback();
|
|
return;
|
|
}
|
|
|
|
// 同时开始子面板的关闭动画
|
|
this.clearSubPanelsWithAnimation(panel);
|
|
|
|
if (!panel.active) panel.active = true;
|
|
|
|
const animationCallback = () => {
|
|
panel.active = false;
|
|
callback && callback();
|
|
};
|
|
|
|
// 主面板动画
|
|
switch (direction) {
|
|
case "left":
|
|
UITransitionHelper.slideOutToLeft(panel, 0.3, animationCallback);
|
|
break;
|
|
case "right":
|
|
UITransitionHelper.slideOutToRight(panel, 0.3, animationCallback);
|
|
break;
|
|
case "up":
|
|
UITransitionHelper.slideOutToTop(panel, 0.3, animationCallback);
|
|
break;
|
|
case "down":
|
|
UITransitionHelper.slideOutToBottom(panel, 0.3, animationCallback);
|
|
break;
|
|
default:
|
|
// 默认左侧滑出
|
|
UITransitionHelper.slideOutToLeft(panel, 0.3, animationCallback);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 显示面板动画
|
|
*/
|
|
private showPanelWithAnimation(
|
|
panel: Node,
|
|
direction: "left" | "right" | "up" | "down",
|
|
callback?: Function
|
|
) {
|
|
if (!panel || !panel.isValid) {
|
|
callback && callback();
|
|
return;
|
|
}
|
|
|
|
panel.active = true;
|
|
|
|
switch (direction) {
|
|
case "left":
|
|
UITransitionHelper.slideInFromLeft(panel, 0.3, callback);
|
|
break;
|
|
case "right":
|
|
UITransitionHelper.slideInFromRight(panel, 0.3, callback);
|
|
break;
|
|
case "up":
|
|
UITransitionHelper.slideInFromTop(panel, 0.3, callback);
|
|
break;
|
|
case "down":
|
|
UITransitionHelper.slideInFromBottom(panel, 0.3, callback);
|
|
break;
|
|
default:
|
|
// 默认从右侧滑入
|
|
UITransitionHelper.slideInFromRight(panel, 0.3, callback);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取当前激活的面板类型
|
|
*/
|
|
public getCurrentActivePanel(): PanelType {
|
|
return this.currentActivePanelType;
|
|
}
|
|
|
|
/**
|
|
* 获取当前激活的面板节点
|
|
*/
|
|
public getCurrentActivePanelNode(): Node {
|
|
return this.currentActivePanel;
|
|
}
|
|
|
|
/**
|
|
* 设置选中的角色ID
|
|
* @param girlId 角色ID
|
|
*/
|
|
public setSelectedGirlId(girlId: number): void {
|
|
this.selectedGirlId = girlId;
|
|
sys.localStorage.setItem(NavigationManager.LastSelectGirlID, girlId);
|
|
logger.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;
|
|
logger.log("[NavigationManager] Selected theme ID set to:", themeId);
|
|
}
|
|
|
|
/**
|
|
* 获取当前选中的主题ID
|
|
* @returns 当前选中的主题ID
|
|
*/
|
|
public getSelectedCategoryId(): number {
|
|
return this.selectedCategoryId;
|
|
}
|
|
}
|