调整布局、新增导航栏,调整页面跳转逻辑
This commit is contained in:
@@ -30,7 +30,7 @@ import { PayToTalkSubpanel } from "./PayToTalkSubpanel";
|
||||
import { DataId, DataManager } from "../../data/DataManager";
|
||||
import { GirlData } from "../../data/GirlData";
|
||||
import { SceneBgVideoLayer } from "../../../Sub/UI/SceneBgVideoLayer";
|
||||
import { NavigationManager } from "../../manager/NavigationManager";
|
||||
import { NavigationManager, PanelType } from "../../manager/NavigationManager";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("ChatPanel")
|
||||
@@ -79,22 +79,79 @@ export class ChatPanel extends li_BaseView implements IChatPanelCallback {
|
||||
this.girlName.string = LanguageUtils.getText(this.nameKey);
|
||||
};
|
||||
|
||||
openUIDataCT(data) {
|
||||
const newRoleId =
|
||||
typeof data === "object" && data.roleId !== undefined
|
||||
? data.roleId
|
||||
: data;
|
||||
targetSize;
|
||||
videoAreaPos;
|
||||
onLoadCT() {
|
||||
Utils.parseNode(this.node, this._nodeTab);
|
||||
|
||||
// 获取 videoArea 的尺寸和位置
|
||||
this.targetSize = this.videoArea.contentSize;
|
||||
this.videoAreaPos = new Vec3(540, 1170, 0);
|
||||
|
||||
this.register();
|
||||
//this.refresh();
|
||||
this.payToTalkPanel.node.active = false;
|
||||
|
||||
// 检查 SceneBgVideoLayer 是否可用
|
||||
if (!this.videoLayer) {
|
||||
console.error("ChatPanel: SceneBgVideoLayer.handle 未初始化");
|
||||
} else {
|
||||
console.log("ChatPanel: 成功获取 SceneBgVideoLayer 实例");
|
||||
}
|
||||
}
|
||||
|
||||
register() {
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.LanguageChange,
|
||||
this,
|
||||
this.onLanguageChangeCallback
|
||||
);
|
||||
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.Chat_EmotionInitialized,
|
||||
this,
|
||||
this.onEmotionInitialized
|
||||
);
|
||||
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.ChatTotalCountChange,
|
||||
this,
|
||||
this.onChatCountChange
|
||||
);
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.LanguageChange,
|
||||
this,
|
||||
this.onLanguageChangeCallback
|
||||
);
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.ChatTotalCountChange,
|
||||
this,
|
||||
this.onChatCountChange
|
||||
);
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.Chat_EmotionInitialized,
|
||||
this,
|
||||
this.onEmotionInitialized
|
||||
);
|
||||
|
||||
// 解绑ChatController(不销毁,因为它是单例)
|
||||
if (this.chatController) {
|
||||
this.chatController.unbindView();
|
||||
this.chatController = null;
|
||||
}
|
||||
}
|
||||
refresh() {
|
||||
const newRoleId = NavigationManager.Instance.getSelectedGirlId();
|
||||
|
||||
// 检查是否是切换角色
|
||||
const isRoleSwitch = this.id && this.id !== newRoleId;
|
||||
|
||||
this.id = newRoleId;
|
||||
this.categoryId = data.categoryId;
|
||||
// 如果标记了需要滑入动画,则执行动画
|
||||
// 延迟一帧执行动画,确保节点已正确加载到场景中
|
||||
this.scheduleOnce(() => {
|
||||
UITransitionHelper.slideInFromRight(this.node, 0.3);
|
||||
}, 0);
|
||||
this.categoryId =
|
||||
NavigationManager.Instance.getSelectedThemeId().toString();
|
||||
|
||||
// 获取ChatController单例并绑定当前Panel
|
||||
this.chatController = ChatController.Instance;
|
||||
@@ -119,83 +176,7 @@ export class ChatPanel extends li_BaseView implements IChatPanelCallback {
|
||||
this.chatController.initialize(this.categoryId, this.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
targetSize;
|
||||
videoAreaPos;
|
||||
onLoadCT() {
|
||||
Utils.parseNode(this.node, this._nodeTab);
|
||||
|
||||
// 获取 videoArea 的尺寸和位置
|
||||
this.targetSize = this.videoArea.contentSize;
|
||||
this.videoAreaPos = new Vec3(540, 1170, 0);
|
||||
|
||||
this.register();
|
||||
this.refresh();
|
||||
this.payToTalkPanel.node.active = false;
|
||||
|
||||
// 检查 SceneBgVideoLayer 是否可用
|
||||
if (!this.videoLayer) {
|
||||
console.error("ChatPanel: SceneBgVideoLayer.handle 未初始化");
|
||||
} else {
|
||||
console.log("ChatPanel: 成功获取 SceneBgVideoLayer 实例");
|
||||
}
|
||||
}
|
||||
|
||||
register() {
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.Chat_DialogRefresh,
|
||||
this,
|
||||
this.onDialogUpdate
|
||||
);
|
||||
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.LanguageChange,
|
||||
this,
|
||||
this.onLanguageChangeCallback
|
||||
);
|
||||
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.Chat_EmotionInitialized,
|
||||
this,
|
||||
this.onEmotionInitialized
|
||||
);
|
||||
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.ChatTotalCountChange,
|
||||
this,
|
||||
this.onChatCountChange
|
||||
);
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.Chat_DialogRefresh,
|
||||
this,
|
||||
this.onDialogUpdate
|
||||
);
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.LanguageChange,
|
||||
this,
|
||||
this.onLanguageChangeCallback
|
||||
);
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.ChatTotalCountChange,
|
||||
this,
|
||||
this.onChatCountChange
|
||||
);
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.Chat_EmotionInitialized,
|
||||
this,
|
||||
this.onEmotionInitialized
|
||||
);
|
||||
|
||||
// 解绑ChatController(不销毁,因为它是单例)
|
||||
if (this.chatController) {
|
||||
this.chatController.unbindView();
|
||||
this.chatController = null;
|
||||
}
|
||||
}
|
||||
refresh() {
|
||||
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
||||
|
||||
this.nameKey = girlData.getGrilName(this.categoryId, this.id);
|
||||
@@ -372,6 +353,8 @@ export class ChatPanel extends li_BaseView implements IChatPanelCallback {
|
||||
}
|
||||
protected onEnable(): void {
|
||||
if (!this.manager) this.manager = DialogManager.getInstance();
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
public async OnClickSend() {
|
||||
@@ -465,11 +448,7 @@ export class ChatPanel extends li_BaseView implements IChatPanelCallback {
|
||||
|
||||
returnBtn() {
|
||||
// Navigate back to GirlDetailPanel with current girlId using smooth transition
|
||||
NavigationManager.Instance.navigateToGirlDetail(
|
||||
this.id,
|
||||
NavigationManager.getTransitionPresets().SLIDE_RIGHT_TO_LEFT,
|
||||
this
|
||||
);
|
||||
NavigationManager.Instance.switchToPanel(PanelType.GIRL_DETAIL);
|
||||
}
|
||||
onClickRecord() {
|
||||
ViewManager.I.openBundlesView("RecordPanel", this.id);
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import li_BaseView from "db://assets/Scripts/Main/Common/li_BaseView";
|
||||
import ResManager from "db://assets/Scripts/Main/Manager/ResManager";
|
||||
import { DetailImageItem } from "../../uiitems/DetailImageItem";
|
||||
import { NavigationManager } from "../../manager/NavigationManager";
|
||||
import { NavigationManager, PanelType } from "../../manager/NavigationManager";
|
||||
import { ConfigManager } from "../../manager/ConfigManager";
|
||||
import LanguageUtils from "../../../Main/Common/LanguageUtils";
|
||||
import Utils from "../../../Main/Common/Utils";
|
||||
@@ -71,36 +71,16 @@ export class GirlDetailPanel extends li_BaseView {
|
||||
@property(Node)
|
||||
imgsLayout: Node;
|
||||
|
||||
openUIDataCT(data) {
|
||||
this.id = data;
|
||||
}
|
||||
videoAreaPos;
|
||||
|
||||
protected onEnable(): void {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
onLoadCT() {
|
||||
super.onLoadCT();
|
||||
this.imgItemInst.node.active = false;
|
||||
this.videoAreaPos = new Vec3(540, 1384);
|
||||
|
||||
const pos = new Vec3(
|
||||
this.descContent.position.x,
|
||||
this.descContent.position.y,
|
||||
this.descContent.position.z
|
||||
);
|
||||
this.descContent.position = new Vec3(pos.x, pos.y - 1000, pos.z);
|
||||
//this.node.scale = Vec3.ZERO;
|
||||
tween(this.descContent)
|
||||
.to(0.3, { position: pos }, { easing: "quadOut" })
|
||||
.start();
|
||||
|
||||
// 检查 SceneBgVideoLayer 是否可用
|
||||
if (!this.videoLayer) {
|
||||
console.error("GirlDetailPanel: SceneBgVideoLayer.handle 未初始化");
|
||||
} else {
|
||||
console.log("GirlDetailPanel: 成功获取 SceneBgVideoLayer 实例");
|
||||
// 初始化视频显示位置
|
||||
//this.initVideoPosition();
|
||||
}
|
||||
|
||||
this.refresh(this.id);
|
||||
//this.refresh();
|
||||
|
||||
Utils.addInnerEL(InnerMsgCode.LanguageChange, this, () => {
|
||||
this.girlName.string = LanguageUtils.getText(this.nameKey);
|
||||
@@ -153,7 +133,32 @@ export class GirlDetailPanel extends li_BaseView {
|
||||
tagKey: string;
|
||||
descKey: string;
|
||||
category: number;
|
||||
async refresh(index: number) {
|
||||
async refresh() {
|
||||
this.id = NavigationManager.Instance.getSelectedGirlId();
|
||||
|
||||
this.imgItemInst.node.active = false;
|
||||
this.videoAreaPos = new Vec3(540, 1384);
|
||||
|
||||
const pos = new Vec3(
|
||||
this.descContent.position.x,
|
||||
this.descContent.position.y,
|
||||
this.descContent.position.z
|
||||
);
|
||||
this.descContent.position = new Vec3(pos.x, pos.y - 1000, pos.z);
|
||||
//this.node.scale = Vec3.ZERO;
|
||||
tween(this.descContent)
|
||||
.to(0.3, { position: pos }, { easing: "quadOut" })
|
||||
.start();
|
||||
|
||||
// 检查 SceneBgVideoLayer 是否可用
|
||||
if (!this.videoLayer) {
|
||||
console.error("GirlDetailPanel: SceneBgVideoLayer.handle 未初始化");
|
||||
} else {
|
||||
console.log("GirlDetailPanel: 成功获取 SceneBgVideoLayer 实例");
|
||||
// 初始化视频显示位置
|
||||
//this.initVideoPosition();
|
||||
}
|
||||
|
||||
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
||||
this.category = girlData.getGrilCategoryById(this.id);
|
||||
// 请求详细数据
|
||||
@@ -305,18 +310,11 @@ export class GirlDetailPanel extends li_BaseView {
|
||||
|
||||
OnClickChatBtn() {
|
||||
// 使用带过渡动画的导航方法
|
||||
NavigationManager.Instance.navigateToChatWithTransition(
|
||||
this.category.toString(),
|
||||
this.id,
|
||||
this
|
||||
);
|
||||
// 注意:不在这里直接调用onClose,而是在动画完成后由NavigationManager调用
|
||||
NavigationManager.Instance.switchToPanel(PanelType.CHAT);
|
||||
}
|
||||
|
||||
returnBtn() {
|
||||
this.onClose();
|
||||
NavigationManager.Instance.navigateToGirlList(this.category);
|
||||
//ViewManager.I.openBundlesView("GirlListPanel");
|
||||
NavigationManager.Instance.switchToPanel(PanelType.THEME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ import { GirlData } from "../../data/GirlData";
|
||||
import proto from "db://assets/Scripts/proto/proto.pb.js";
|
||||
import GameRootUI from "../../../Main/Common/GameRootUI";
|
||||
import { UITransitionHelper } from "../../utils/UITransitionHelper";
|
||||
import { NavigationManager, PanelType } from "../../manager/NavigationManager";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@@ -23,14 +24,19 @@ export class GirlListPanel extends li_BaseView {
|
||||
cache: GirlListItem[] = [];
|
||||
|
||||
category: number;
|
||||
openUIDataCT(data) {
|
||||
// 支持新的数据格式:既可以是单纯的数字,也可以是包含过渡动画信息的对象
|
||||
this.category =
|
||||
typeof data === "object" && data.category !== undefined
|
||||
? data.category
|
||||
: data;
|
||||
private parentPanelName: string = null;
|
||||
|
||||
const withAnimation = typeof data === "object" && data.withTransition;
|
||||
openUIDataCT(data) {
|
||||
console.log("[GirlListPanel] openUIDataCT called with data:", data);
|
||||
|
||||
// 支持新的数据格式:既可以是单纯的数字,也可以是包含主题ID和父页面信息的对象
|
||||
if (typeof data === "object") {
|
||||
this.category = data.themeId;
|
||||
this.parentPanelName = data.parentPanel;
|
||||
console.log("[GirlListPanel] Set parent panel:", this.parentPanelName);
|
||||
} else {
|
||||
this.category = data;
|
||||
}
|
||||
}
|
||||
onLoadCT() {
|
||||
Utils.parseNode(this.node, this._nodeTab);
|
||||
@@ -76,37 +82,7 @@ export class GirlListPanel extends li_BaseView {
|
||||
GButton.BandClick(this._nodeTab.ReturnBtn, this.Return, this);
|
||||
}
|
||||
Return() {
|
||||
console.log("GirlListPanel: Return button clicked");
|
||||
|
||||
// 执行同步的过渡动画:GirlListPanel向右滑出,ThemePanel从左滑入
|
||||
const duration = 0.1;
|
||||
let animationsCompleted = 0;
|
||||
const totalAnimations = 2;
|
||||
|
||||
const onAnimationComplete = (source: string) => {
|
||||
console.log(`GirlListPanel: Animation completed from ${source}`);
|
||||
animationsCompleted++;
|
||||
console.log(
|
||||
`GirlListPanel: ${animationsCompleted}/${totalAnimations} animations completed`
|
||||
);
|
||||
|
||||
if (animationsCompleted >= totalAnimations) {
|
||||
console.log("GirlListPanel: All animations completed, closing panel");
|
||||
// 所有动画完成后关闭当前面板
|
||||
this.onClose();
|
||||
}
|
||||
};
|
||||
|
||||
// 1. GirlListPanel向右滑出
|
||||
console.log("GirlListPanel: Starting slideOutToRight animation");
|
||||
UITransitionHelper.slideOutToRight(this.node, duration, () =>
|
||||
onAnimationComplete("slideOutToRight")
|
||||
);
|
||||
|
||||
// 2. ThemePanel从左侧滑入
|
||||
console.log("GirlListPanel: Starting ThemePanel slide_left animation");
|
||||
GameRootUI.I.showDefaultViewWithTransition("slide_left", duration, () =>
|
||||
onAnimationComplete("ThemePanel_slide_left")
|
||||
);
|
||||
// 直接关闭,不需要动画
|
||||
this.node.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
import { _decorator, Component, Label, Node } from "cc";
|
||||
import li_BaseView from "db://assets/Scripts/Main/Common/li_BaseView";
|
||||
import Utils from "db://assets/Scripts/Main/Common/Utils";
|
||||
import { GButton } from "db://assets/Scripts/Main/Common/GButton";
|
||||
import { ViewManager } from "db://assets/Scripts/Main/Manager/ViewManager";
|
||||
import {
|
||||
NavigationManager,
|
||||
PageTransitionType,
|
||||
PanelType,
|
||||
} from "../../manager/NavigationManager";
|
||||
import { InnerMsgCode } from "../../../Main/Config/InnerMsgCode";
|
||||
import GameRootUI from "../../../Main/Common/GameRootUI";
|
||||
import { UITransitionHelper } from "../../utils/UITransitionHelper";
|
||||
import { ThemePanel } from "./ThemePanel";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("NavigationPanel")
|
||||
export class NavigationPanel extends li_BaseView {
|
||||
private _nodeTab: any = {};
|
||||
private currentActivePanel: PanelType = PanelType.THEME;
|
||||
|
||||
private themeBtn: Node;
|
||||
private girlDetailBtn: Node;
|
||||
private chatBtn: Node;
|
||||
private settingBtn: Node;
|
||||
|
||||
private loadingView: Node;
|
||||
|
||||
onLoadCT() {
|
||||
Utils.parseNode(this.node, this._nodeTab);
|
||||
|
||||
this.themeBtn = this._nodeTab.themeBtn;
|
||||
this.girlDetailBtn = this._nodeTab.girlDetailBtn;
|
||||
this.chatBtn = this._nodeTab.chatBtn;
|
||||
this.settingBtn = this._nodeTab.settingBtn;
|
||||
this.loadingView = this._nodeTab.loadingView;
|
||||
|
||||
this.hideLoading();
|
||||
|
||||
// 注册到NavigationManager
|
||||
NavigationManager.Instance.registerNavigationPanel(this);
|
||||
|
||||
this.registerListener();
|
||||
this.updateButtonStates(PanelType.THEME);
|
||||
|
||||
// 初次打开时通过NavigationManager切换到主题面板
|
||||
this.initializeFirstPanel();
|
||||
}
|
||||
|
||||
private registerListener() {
|
||||
// 所有按钮点击都通过NavigationManager处理
|
||||
GButton.BandClick(
|
||||
this.themeBtn,
|
||||
() => NavigationManager.Instance.switchToPanel(PanelType.THEME),
|
||||
this
|
||||
);
|
||||
GButton.BandClick(
|
||||
this.girlDetailBtn,
|
||||
() => NavigationManager.Instance.switchToPanel(PanelType.GIRL_DETAIL),
|
||||
this
|
||||
);
|
||||
GButton.BandClick(
|
||||
this.chatBtn,
|
||||
() => NavigationManager.Instance.switchToPanel(PanelType.CHAT),
|
||||
this
|
||||
);
|
||||
GButton.BandClick(
|
||||
this.settingBtn,
|
||||
() => NavigationManager.Instance.switchToPanel(PanelType.SETTING),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新按钮状态(公开方法,供NavigationManager调用)
|
||||
* @param activePanel 当前激活的面板类型
|
||||
*/
|
||||
public updateButtonStates(activePanel: PanelType) {
|
||||
this.currentActivePanel = activePanel;
|
||||
this._nodeTab.CurrentPanel.getComponent(Label).string =
|
||||
this.currentActivePanel;
|
||||
this.refreshButtonVisuals();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新按钮的视觉状态
|
||||
*/
|
||||
private refreshButtonVisuals() {
|
||||
// TODO: 实现按钮状态更新的视觉效果
|
||||
// 根据 currentActivePanel 更新按钮的选中状态
|
||||
console.log(
|
||||
"[NavigationPanel] Button states updated for:",
|
||||
this.currentActivePanel
|
||||
);
|
||||
}
|
||||
|
||||
private initializeFirstPanel() {
|
||||
// 初次打开时通过NavigationManager切换到主题面板
|
||||
NavigationManager.Instance.switchToPanel(PanelType.THEME, true);
|
||||
}
|
||||
|
||||
public showPanel() {
|
||||
this.node.active = true;
|
||||
}
|
||||
|
||||
public hidePanel() {
|
||||
this.node.active = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示加载状态(公开方法,供NavigationManager调用)
|
||||
*/
|
||||
public showLoading() {
|
||||
if (this.loadingView) {
|
||||
this.loadingView.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏加载状态(公开方法,供NavigationManager调用)
|
||||
*/
|
||||
public hideLoading() {
|
||||
if (this.loadingView) {
|
||||
this.loadingView.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(): void {}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "58d92549-54a9-4f98-94af-5c0c3ac2f853",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export class PurchasePanel extends li_BaseView {
|
||||
this._nodeTab.ReturnBtn,
|
||||
() => {
|
||||
this.onClose();
|
||||
GameRootUI.I.showDefaultView();
|
||||
// NavigationPanel 始终显示,不需要显示 DefaultView
|
||||
},
|
||||
this
|
||||
);
|
||||
|
||||
@@ -286,7 +286,7 @@ export class RecordPanel extends li_BaseView {
|
||||
}
|
||||
|
||||
protected onEnable(): void {
|
||||
GameRootUI.I.hideDefaultView();
|
||||
// NavigationPanel 始终显示,不需要隐藏 DefaultView
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,11 @@ import Utils from "db://assets/Scripts/Main/Common/Utils";
|
||||
import { GButton } from "db://assets/Scripts/Main/Common/GButton";
|
||||
import ResManager from "db://assets/Scripts/Main/Manager/ResManager";
|
||||
import { ThemeItem } from "../../uiitems/ThemeItem";
|
||||
import { NavigationManager, PageTransitionType } from "../../manager/NavigationManager";
|
||||
import {
|
||||
NavigationManager,
|
||||
PageTransitionType,
|
||||
PanelType,
|
||||
} from "../../manager/NavigationManager";
|
||||
import { GirlListItem } from "../../uiitems/GirlListItem";
|
||||
import LanguageUtils from "../../../Main/Common/LanguageUtils";
|
||||
import { ViewManager } from "../../../Main/Manager/ViewManager";
|
||||
@@ -29,6 +33,7 @@ import { AccountData } from "../../data/AccountData";
|
||||
import { ShopData } from "../../data/ShopData";
|
||||
import proto from "db://assets/Scripts/proto/proto.pb.js";
|
||||
import GameRootUI from "../../../Main/Common/GameRootUI";
|
||||
import { MainController } from "../../core/MainController";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@@ -38,7 +43,7 @@ export class ThemePanel extends li_BaseView {
|
||||
|
||||
coinNum: Label;
|
||||
uid: Label;
|
||||
itemInst: GirlListItem;
|
||||
itemInst: ThemeItem;
|
||||
content: Node;
|
||||
private vipLeftTime: Label;
|
||||
recId: number;
|
||||
@@ -47,6 +52,14 @@ export class ThemePanel extends li_BaseView {
|
||||
|
||||
cache: ThemeItem[] = [];
|
||||
|
||||
// 子页面管理
|
||||
private currentChildPanel: any = null;
|
||||
|
||||
// 加载状态保护
|
||||
private isLoading: boolean = false;
|
||||
private loadingPromise: Promise<void> | null = null;
|
||||
private abortController: AbortController | null = null;
|
||||
|
||||
onLoadCT() {
|
||||
Utils.parseNode(this.node, this._nodeTab);
|
||||
|
||||
@@ -65,67 +78,206 @@ export class ThemePanel extends li_BaseView {
|
||||
}
|
||||
|
||||
rectNameKey: string;
|
||||
async Show() {
|
||||
this._nodeTab.loadingRec.active = true;
|
||||
//some temp data
|
||||
this.refreshCoinNum();
|
||||
this.refreshVipExpire();
|
||||
const accountData = DataManager.I.getDataById<AccountData>(DataId.Account);
|
||||
this.uid.string = "uid: " + accountData.accId;
|
||||
this.recId = 1;
|
||||
if (this.cache) {
|
||||
for (let i = this.cache.length - 1; i >= 0; i--) {
|
||||
this.cache[i].node.destroy();
|
||||
async Show(forceRefresh: boolean = false) {
|
||||
// 防止重复加载
|
||||
if (this.isLoading) {
|
||||
console.log("[ThemePanel] 已在加载中,等待当前加载完成");
|
||||
if (this.loadingPromise) {
|
||||
await this.loadingPromise;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
this.loadingPromise = this._showInternal(forceRefresh);
|
||||
|
||||
try {
|
||||
await this.loadingPromise;
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
this.loadingPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
private async _showInternal(forceRefresh: boolean = false) {
|
||||
// 创建新的AbortController用于取消操作
|
||||
this.abortController = new AbortController();
|
||||
const signal = this.abortController.signal;
|
||||
|
||||
try {
|
||||
this._nodeTab.loadingRec.active = true;
|
||||
//some temp data
|
||||
this.refreshCoinNum();
|
||||
this.refreshVipExpire();
|
||||
const accountData = DataManager.I.getDataById<AccountData>(
|
||||
DataId.Account
|
||||
);
|
||||
this.uid.string = "uid: " + accountData.accId;
|
||||
this.recId = 1;
|
||||
|
||||
// 检查是否已被取消
|
||||
if (signal.aborted) {
|
||||
throw new Error("Operation was aborted");
|
||||
}
|
||||
|
||||
// 清理旧的cache节点(每次都清理,解决内存泄漏问题)
|
||||
this.clearCache();
|
||||
|
||||
// 如果需要强制刷新,先刷新数据
|
||||
if (forceRefresh) {
|
||||
console.log("[ThemePanel] 开始强制刷新数据");
|
||||
await Promise.all([
|
||||
MainController.I.refreshThemeData(),
|
||||
MainController.I.refreshDailyRecommend(),
|
||||
]);
|
||||
console.log("[ThemePanel] 数据刷新完成");
|
||||
|
||||
// 再次检查是否已被取消
|
||||
if (signal.aborted) {
|
||||
throw new Error("Operation was aborted");
|
||||
}
|
||||
}
|
||||
|
||||
// 优先使用MainController中预加载的数据
|
||||
const preloadStatus = MainController.I.getPreloadStatus();
|
||||
console.log("[ThemePanel] 预加载状态:", preloadStatus);
|
||||
|
||||
// 处理主题数据
|
||||
await this.handleThemeData(preloadStatus.themeData);
|
||||
|
||||
// 检查是否已被取消
|
||||
if (signal.aborted) {
|
||||
throw new Error("Operation was aborted");
|
||||
}
|
||||
|
||||
// 处理每日推荐数据
|
||||
await this.handleDailyRecommendData(preloadStatus.dailyRecommend);
|
||||
|
||||
// 检查是否已被取消
|
||||
if (signal.aborted) {
|
||||
throw new Error("Operation was aborted");
|
||||
}
|
||||
|
||||
this._nodeTab.loadingRec.active = false;
|
||||
|
||||
// 处理商品列表数据
|
||||
await this.handleShopListData(preloadStatus.shopList);
|
||||
} catch (error) {
|
||||
console.error("[ThemePanel] Show操作出错:", error);
|
||||
this._nodeTab.loadingRec.active = false;
|
||||
|
||||
// 如果不是取消操作导致的错误,可以考虑显示错误提示
|
||||
if (error.message !== "Operation was aborted") {
|
||||
// 这里可以添加错误提示逻辑
|
||||
console.error("[ThemePanel] 数据加载失败,请稍后重试");
|
||||
}
|
||||
} finally {
|
||||
this.abortController = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理主题数据
|
||||
*/
|
||||
private async handleThemeData(isPreloaded: boolean): Promise<void> {
|
||||
if (isPreloaded) {
|
||||
console.log("[ThemePanel] 使用预加载的主题数据");
|
||||
// 直接使用预加载的数据渲染界面
|
||||
const themeData = DataManager.I.getDataById<ThemeData>(DataId.Theme);
|
||||
if (themeData && themeData.themes) {
|
||||
this.renderThemeData(themeData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 请求主题数据
|
||||
|
||||
// 如果没有预加载数据,则请求数据
|
||||
console.log("[ThemePanel] 请求主题数据");
|
||||
const reqData = {};
|
||||
let res = await ThemeService.I.reqHallTheme(reqData);
|
||||
if (res && res.code === proto.cs.EnmRetCode.SUCCESS) {
|
||||
// 保存数据
|
||||
const themeData = DataManager.I.getDataById<ThemeData>(DataId.Theme);
|
||||
themeData.themes = res.data;
|
||||
// 根据数据,刷新界面
|
||||
const themeIds = themeData.themeIds;
|
||||
for (let id of themeIds) {
|
||||
let newNode = instantiate(this.itemInst.node);
|
||||
let item = newNode.getComponent(ThemeItem);
|
||||
item.refresh(id, this);
|
||||
newNode.active = true;
|
||||
this.cache.push(item);
|
||||
this.content.addChild(newNode);
|
||||
this.renderThemeData(themeData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染主题数据
|
||||
*/
|
||||
private renderThemeData(themeData: ThemeData): void {
|
||||
const themeIds = themeData.themeIds;
|
||||
for (let id of themeIds) {
|
||||
let newNode = instantiate(this.itemInst.node);
|
||||
let item = newNode.getComponent(ThemeItem);
|
||||
item.refresh(id, this);
|
||||
newNode.active = true;
|
||||
this.cache.push(item);
|
||||
this.content.addChild(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理每日推荐数据
|
||||
*/
|
||||
private async handleDailyRecommendData(isPreloaded: boolean): Promise<void> {
|
||||
if (isPreloaded) {
|
||||
console.log("[ThemePanel] 使用预加载的每日推荐数据");
|
||||
// 直接使用预加载的数据渲染界面
|
||||
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
||||
if (girlData) {
|
||||
this.renderDailyRecommendData(girlData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 请求每日推荐
|
||||
const reqData2 = {};
|
||||
let res2 = await GirlService.I.reqDailyRecommend(reqData2);
|
||||
if (res2 && res2.code === proto.cs.EnmRetCode.SUCCESS) {
|
||||
// 如果没有预加载数据,则请求数据
|
||||
console.log("[ThemePanel] 请求每日推荐数据");
|
||||
const reqData = {};
|
||||
let res = await GirlService.I.reqDailyRecommend(reqData);
|
||||
if (res && res.code === proto.cs.EnmRetCode.SUCCESS) {
|
||||
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
||||
girlData.setDailyRecommend(res2.data);
|
||||
// 根据数据,刷新界面
|
||||
this.recId = girlData.getRecommendGirlId();
|
||||
this.rectNameKey = girlData.getRecommendGrilName();
|
||||
let avatarPath = girlData.getRecommendGrilAvatar();
|
||||
this.recName.string = LanguageUtils.getText(this.rectNameKey);
|
||||
ResManager.I.changeBundleSpriteFrame(
|
||||
this.recSprite,
|
||||
avatarPath,
|
||||
"Girls",
|
||||
() => {
|
||||
let sizeTran = this.recSprite.node.parent.getComponent(UITransform);
|
||||
Utils.adjustBgPixelRatioToSize(
|
||||
sizeTran.contentSize,
|
||||
this.recSprite.node,
|
||||
1
|
||||
);
|
||||
}
|
||||
);
|
||||
girlData.setDailyRecommend(res.data);
|
||||
this.renderDailyRecommendData(girlData);
|
||||
}
|
||||
this._nodeTab.loadingRec.active = false;
|
||||
}
|
||||
|
||||
// 获取商品列表,提前把数据拿下来
|
||||
this.reqShopList();
|
||||
/**
|
||||
* 渲染每日推荐数据
|
||||
*/
|
||||
private renderDailyRecommendData(girlData: GirlData): void {
|
||||
this.recId = girlData.getRecommendGirlId();
|
||||
this.rectNameKey = girlData.getRecommendGrilName();
|
||||
let avatarPath = girlData.getRecommendGrilAvatar();
|
||||
this.recName.string = LanguageUtils.getText(this.rectNameKey);
|
||||
ResManager.I.changeBundleSpriteFrame(
|
||||
this.recSprite,
|
||||
avatarPath,
|
||||
"Girls",
|
||||
() => {
|
||||
let sizeTran = this.recSprite.node.parent.getComponent(UITransform);
|
||||
Utils.adjustBgPixelRatioToSize(
|
||||
sizeTran.contentSize,
|
||||
this.recSprite.node,
|
||||
1
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理商品列表数据
|
||||
*/
|
||||
private async handleShopListData(isPreloaded: boolean): Promise<void> {
|
||||
if (isPreloaded) {
|
||||
console.log("[ThemePanel] 商品列表数据已预加载");
|
||||
// 数据已经在DataManager中,不需要额外处理
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果没有预加载数据,则请求数据
|
||||
console.log("[ThemePanel] 请求商品列表数据");
|
||||
await this.reqShopList();
|
||||
}
|
||||
|
||||
private registerListener() {
|
||||
@@ -136,15 +288,13 @@ export class ThemePanel extends li_BaseView {
|
||||
|
||||
GButton.BandClick(this._nodeTab.ShopPanelEntry, this.enterShop, this);
|
||||
|
||||
Utils.addInnerEL(InnerMsgCode.LanguageChange, this, () => {
|
||||
this.recName.string = LanguageUtils.getText(this.rectNameKey);
|
||||
});
|
||||
Utils.addInnerEL(InnerMsgCode.BalanceChange, this, () => {
|
||||
this.refreshCoinNum();
|
||||
});
|
||||
Utils.addInnerEL(InnerMsgCode.VipExpireChange, this, () => {
|
||||
this.refreshVipExpire();
|
||||
});
|
||||
Utils.addInnerEL(InnerMsgCode.LanguageChange, this, this.onLanguageChange);
|
||||
Utils.addInnerEL(InnerMsgCode.BalanceChange, this, this.onBalanceChange);
|
||||
Utils.addInnerEL(
|
||||
InnerMsgCode.VipExpireChange,
|
||||
this,
|
||||
this.onVipExpireChange
|
||||
);
|
||||
}
|
||||
|
||||
enterShop() {
|
||||
@@ -165,9 +315,11 @@ export class ThemePanel extends li_BaseView {
|
||||
this.recId
|
||||
) == 0;
|
||||
if (isRelease || isFree) {
|
||||
const transitionConfig = NavigationManager.getTransitionPresets().SLIDE_LEFT_TO_RIGHT;
|
||||
NavigationManager.Instance.navigateToGirlDetail(this.recId, transitionConfig, this);
|
||||
GameRootUI.I.hideDefaultView();
|
||||
NavigationManager.Instance.setSelectedGirlId(this.recId);
|
||||
NavigationManager.Instance.setSelectedThemeId(
|
||||
girlData.getGrilCategoryById(this.recId)
|
||||
);
|
||||
NavigationManager.Instance.switchToPanel(PanelType.GIRL_DETAIL);
|
||||
} else {
|
||||
//未解锁
|
||||
ViewManager.I.openBundlesPopupView("GirlListPopupPanel", {
|
||||
@@ -179,7 +331,8 @@ export class ThemePanel extends li_BaseView {
|
||||
}
|
||||
|
||||
openSetting() {
|
||||
ViewManager.I.openBundlesView("SettingPanel");
|
||||
// 通过NavigationManager切换到设置面板,保持动画和状态同步
|
||||
NavigationManager.Instance.switchToPanel(PanelType.SETTING);
|
||||
}
|
||||
|
||||
openMsgBox() {
|
||||
@@ -216,11 +369,107 @@ export class ThemePanel extends li_BaseView {
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
Utils.removeInnerEL(InnerMsgCode.LanguageChange, this, () => {
|
||||
this.recName.string = LanguageUtils.getText(this.rectNameKey);
|
||||
});
|
||||
Utils.removeInnerEL(InnerMsgCode.BalanceChange, this, () => {});
|
||||
Utils.removeInnerEL(InnerMsgCode.VipExpireChange, this, () => {});
|
||||
/**
|
||||
* 清理缓存节点
|
||||
*/
|
||||
private clearCache(): void {
|
||||
if (this.cache && this.cache.length > 0) {
|
||||
console.log(`[ThemePanel] 清理 ${this.cache.length} 个缓存节点`);
|
||||
for (let i = this.cache.length - 1; i >= 0; i--) {
|
||||
if (this.cache[i] && this.cache[i].node && this.cache[i].node.isValid) {
|
||||
this.cache[i].node.destroy();
|
||||
}
|
||||
}
|
||||
this.cache = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置子页面
|
||||
* @param panel 子页面实例
|
||||
*/
|
||||
public setChildPanel(panel: any): void {
|
||||
console.log("[ThemePanel] Setting child panel:", panel);
|
||||
// 先关闭旧的子页面
|
||||
this.closeChildPanel();
|
||||
this.currentChildPanel = panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭子页面
|
||||
*/
|
||||
public closeChildPanel(): void {
|
||||
if (this.currentChildPanel) {
|
||||
console.log("[ThemePanel] Closing child panel");
|
||||
if (this.currentChildPanel.onClose) {
|
||||
this.currentChildPanel.onClose();
|
||||
} else if (this.currentChildPanel.destroy) {
|
||||
this.currentChildPanel.destroy();
|
||||
}
|
||||
this.currentChildPanel = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面被隐藏时调用
|
||||
*/
|
||||
public onHide(): void {
|
||||
console.log("[ThemePanel] onHide called");
|
||||
this.closeChildPanel();
|
||||
this.cancelCurrentOperation();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消当前操作
|
||||
*/
|
||||
private cancelCurrentOperation(): void {
|
||||
if (this.abortController) {
|
||||
console.log("[ThemePanel] 取消当前操作");
|
||||
this.abortController.abort();
|
||||
this.abortController = null;
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
console.log("[ThemePanel] onDestroy called");
|
||||
|
||||
// 取消当前操作
|
||||
this.cancelCurrentOperation();
|
||||
|
||||
// 关闭子页面
|
||||
this.closeChildPanel();
|
||||
|
||||
// 清理缓存
|
||||
this.clearCache();
|
||||
|
||||
// 重置加载状态
|
||||
this.isLoading = false;
|
||||
this.loadingPromise = null;
|
||||
|
||||
// 移除事件监听器(修复回调函数引用问题)
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.LanguageChange,
|
||||
this,
|
||||
this.onLanguageChange
|
||||
);
|
||||
Utils.removeInnerEL(InnerMsgCode.BalanceChange, this, this.onBalanceChange);
|
||||
Utils.removeInnerEL(
|
||||
InnerMsgCode.VipExpireChange,
|
||||
this,
|
||||
this.onVipExpireChange
|
||||
);
|
||||
}
|
||||
|
||||
// 事件回调函数(避免匿名函数导致的内存泄漏)
|
||||
private onLanguageChange = () => {
|
||||
this.recName.string = LanguageUtils.getText(this.rectNameKey);
|
||||
};
|
||||
|
||||
private onBalanceChange = () => {
|
||||
this.refreshCoinNum();
|
||||
};
|
||||
|
||||
private onVipExpireChange = () => {
|
||||
this.refreshVipExpire();
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user