Files
2025-12-02 20:37:18 +07:00

770 lines
21 KiB
Lua

local uiCtrl = require_ex('UI/Panels/Base/UICtrl')
local PANEL_ID = PanelId.Mail
MailCtrl = HL.Class('MailCtrl', uiCtrl.UICtrl)
local ASYNC_TEXTINFO_LINKINFO = 0.1
MailCtrl.s_messages = HL.StaticField(HL.Table) << {
[MessageConst.ON_ALL_MAIL_INITED] = 'OnAllMailInited',
[MessageConst.ON_READ_MAIL] = 'OnReadMail',
[MessageConst.ON_GET_MAIL_ATTACHMENT] = 'OnGetMailAttachment',
[MessageConst.ON_DEL_MAILS] = 'OnDelMails',
[MessageConst.ON_GET_NEW_MAILS] = 'OnGetNewMails',
[MessageConst.ON_MARK_STAR_MAIL] = 'OnStarMail',
[MessageConst.ON_GET_LOST_AND_FOUND] = 'OnGetLostAndFound',
[MessageConst.ON_ADD_LOST_AND_FOUND] = 'OnAddLostAndFound'
}
MailCtrl.m_inLoading = HL.Field(HL.Boolean) << false
MailCtrl.m_getMailCell = HL.Field(HL.Function)
MailCtrl.m_curMails = HL.Field(HL.Table)
MailCtrl.m_curMailIndex = HL.Field(HL.Number) << 1
MailCtrl.m_naviToHyperLinkBindingId = HL.Field(HL.Number) << -1
MailCtrl.m_skipClickOnce = HL.Field(HL.Boolean) << false
MailCtrl.OnCreate = HL.Override(HL.Any) << function(self, arg)
self.view.btnClose.onClick:AddListener(function()
self:_OnClickClose()
end)
self:BindInputPlayerAction("common_open_mail", function()
self:_OnClickClose()
end)
self.view.helpBtn.onClick:AddListener(function()
UIManager:Open(PanelId.InstructionBook, "mail")
end)
self.view.getBtn.onClick:AddListener(function()
self:_OnClickGet()
end)
self.view.delBtn.onClick:AddListener(function()
self:_OnClickDel()
end)
self.view.getAllBtn.onClick:AddListener(function()
self:_OnClickGetAll()
end)
self.view.delReadBtn.onClick:AddListener(function()
self:_OnClickDelAll()
end)
self.view.lostAndFoundBtn.onClick:AddListener(function()
self:_OnClickLostAndFound()
end)
self.view.contentTxt.onClickLink:AddListener(function(value)
self:_OnClickLink(value)
end)
self.m_getMailCell = UIUtils.genCachedCellFunction(self.view.mailList)
self.view.mailList.onUpdateCell:AddListener(function(obj, csIndex)
self:_OnUpdateCell(self.m_getMailCell(obj), LuaIndex(csIndex))
end)
self.view.filterBtn.view.normalBtn.onClick:AddListener(function()
self:_OnClickStar()
end)
self.view.filterBtn.view.selectedBtn.onClick:AddListener(function()
self:_OnClickStar()
end)
self.view.monthlyPassBtnNode.buyBtn.onClick:AddListener(function()
self:_OnClickMonthlyPassBtn()
end)
self.view.lostAndFoundRedDot:InitRedDot("LostAndFoundBtn")
self.view.getAllBtnRedDot:InitRedDot("MailTabGetAllBtn")
local mailSys = GameInstance.player.mail
if mailSys:IsAllMailInited() then
self:_OnLoadingFinished()
else
self:_ToggleLoading(true)
mailSys:GetAllMails()
end
self:_StartCoroutine(function()
while true do
coroutine.wait(UIConst.FAC_COMMON_UI_UPDATE_INTERVAL)
self:_CheckExpiredMail()
end
end)
self.m_naviToHyperLinkBindingId = InputManagerInst:CreateBindingByActionId("mail_focus_hyperlink", function()
self:_NaviToHyperLink()
end, self.view.inputGroup.groupId)
InputManagerInst:ToggleBinding(self.m_naviToHyperLinkBindingId, false)
self.view.controllerHintPlaceholder:InitControllerHintPlaceholder({ self.view.inputGroup.groupId })
end
MailCtrl.OnShow = HL.Override() << function(self)
self:RefreshLostAndFoundBtn()
end
MailCtrl.OnGetLostAndFound = HL.Method(HL.Table) << function(self, args)
self:RefreshLostAndFoundBtn()
end
MailCtrl.OnAddLostAndFound = HL.Method() << function(self)
self:RefreshLostAndFoundBtn()
end
MailCtrl.RefreshLostAndFoundBtn = HL.Method() << function(self)
local lostAndFound = GameInstance.player.inventory.lostAndFound
local isEmpty = lostAndFound:IsEmpty()
if isEmpty then
self.view.lostAndFoundBtn.gameObject:SetActive(false)
else
self.view.lostAndFoundBtn.gameObject:SetActive(true)
self.view.lostAndFoundNum.text = tostring(lostAndFound:GetUsedGridCount())
self.view.lostAndFoundMax.text = tostring(Const.MAX_LOST_AND_FOUND_COUNT)
end
end
MailCtrl._OnClickClose = HL.Method() << function(self)
self.view.mailContentNode:ClearTween()
PhaseManager:PopPhase(PhaseId.Mail)
end
MailCtrl.OnAnimationInFinished = HL.Override() << function(self)
end
MailCtrl._OnLoadingFinished = HL.Method() << function(self)
self:_ToggleLoading(false)
self:_OnClickTab(nil, nil)
end
MailCtrl._OnClickTab = HL.Method(HL.Opt(HL.Number, HL.Any)) << function(self, mailIndex, mailId)
self.m_curMails = {}
local mailSys = GameInstance.player.mail
for _, mail in pairs(mailSys.mails) do
if mail.inited and not mail.isExpired then
local info = { mail = mail, }
setmetatable(info, { __index = mail })
info.starOrder = mail.isStar and 0 or 1
info.readOrder = (mail.isRead and mail.collected) and 1 or 0
info.sendTimeOrder = -mail.sendTime
if info.itemList then
info.items = {}
local originiumItem
for _, v in pairs(info.itemList) do
local data = Tables.itemTable[v.id]
if data.id == Tables.globalConst.originiumItemId then
if not originiumItem then
originiumItem = {
id = v.id,
count = v.count,
sortId1 = data.sortId1,
sortId2 = data.sortId2,
rarity = data.rarity,
}
table.insert(info.items, originiumItem)
else
originiumItem.count = originiumItem.count + v.count
end
else
table.insert(info.items, {
id = v.id,
count = v.count,
sortId1 = data.sortId1,
sortId2 = data.sortId2,
rarity = data.rarity,
})
end
end
table.sort(info.items, Utils.genSortFunction(UIConst.COMMON_ITEM_SORT_KEYS))
end
table.insert(self.m_curMails, info)
end
end
table.sort(self.m_curMails, Utils.genSortFunction({ "starOrder", "readOrder", "sendTimeOrder", "title" }, true))
local count = #self.m_curMails
local isEmpty = count == 0
local isFull = count >= Const.MAX_MAIL_COUNT
local countTxt = string.format("<color=%s>%d</color>/%d", isFull and "red" or "white", count, Const.MAX_MAIL_COUNT)
self.view.listCountText.text = countTxt
if isEmpty then
self.view.mailContentNode.gameObject:SetActive(false)
self.view.mailListNode.gameObject:SetActive(false)
self.view.emptyNode.gameObject:SetActive(true)
else
self.view.mailContentNode.gameObject:SetActive(true)
self.view.mailListNode.gameObject:SetActive(true)
self.view.emptyNode.gameObject:SetActive(false)
self.view.listTitleTxt.text = Language.LUA_MAIL_TAB_TITLE
self.view.mailList:UpdateCount(count)
if mailId then
for k, v in ipairs(self.m_curMails) do
if v.id == mailId then
mailIndex = k
break
end
end
else
if mailIndex then
mailIndex = lume.clamp(mailIndex, 1, count)
else
mailIndex = 1
end
end
if DeviceInfo.usingController then
self.view.mailListNaviGroup:NaviToThisGroup()
end
self:_OnClickMail(mailIndex)
end
end
MailCtrl._OnUpdateCell = HL.Method(HL.Any, HL.Number) << function(self, cell, index)
local info = self.m_curMails[index]
cell.title.text = info.mail.title
cell.iconSelected:LoadSprite(info.senderIcon)
cell.iconUnselected:LoadSprite(info.senderIcon)
if DeviceInfo.usingController then
cell.button.onIsNaviTargetChanged = function(isTarget, isGroupChanged)
if isTarget and not isGroupChanged then
if self.m_skipClickOnce then
self.m_skipClickOnce = false
else
self:_OnClickMail(index)
end
end
end
else
cell.button.onClick:RemoveAllListeners()
cell.button.onClick:AddListener(function()
self:_OnClickMail(index)
end)
end
if info.items then
cell.item:InitItem(info.items[1])
cell.item.view.rewardedCover.gameObject:SetActive(info.collected)
cell.item.gameObject:SetActive(true)
else
cell.item.gameObject:SetActive(false)
end
if info.expireTime > 0 then
cell.expireTime.gameObject:SetActive(true)
cell.expireTime.text = string.format(Language.LUA_MAIL_CELL_EXPIRED_TIME_FORMAT,
UIUtils.getLeftTime(info.expireTime - DateTimeUtils.GetCurrentTimestampBySeconds()))
else
cell.expireTime.gameObject:SetActive(false)
end
if info.isStar then
cell.starSelected.gameObject:SetActive(true)
cell.starUnselected.gameObject:SetActive(true)
else
cell.starSelected.gameObject:SetActive(false)
cell.starUnselected.gameObject:SetActive(false)
end
cell.animator:SetBool("IsSelected", index == self.m_curMailIndex)
cell.readMask.gameObject:SetActive(info.isRead and info.collected)
cell.redDot:InitRedDot("SingleMail", info.id)
cell.gameObject.name = "MailCell-" .. index
end
MailCtrl._OnClickMail = HL.Method(HL.Number) << function(self, index)
if self.m_curMailIndex ~= index then
local oldCell = self.m_getMailCell(self.m_curMailIndex)
if oldCell then
oldCell.animator:SetBool("IsSelected", false)
end
end
self.m_curMailIndex = index
local cell = self.m_getMailCell(index)
if cell then
cell.animator:SetBool("IsSelected", true)
end
self:_ShowContent(index)
end
MailCtrl._ShowContent = HL.Method(HL.Number) << function(self, index)
local info = self.m_curMails[index]
self.view.mailName.text = info.mail.title
self.view.sendTimeTxt.text = os.date("!" .. Language.LUA_MAIL_SEND_TIME_FORMAT, info.sendTime + Utils.getClientTimeZoneOffsetSeconds())
self.view.senderNameTxt.text = string.format(Language.LUA_MAIL_SENDER_FORMAT, info.senderName)
local analyzedContentInfo = MailUtils.AnalyzeMailContent(info.mail)
self.view.contentTxt:SetAndResolveTextStyle(analyzedContentInfo.content)
self.view.contentTxt:ShrinkLinkTags()
if DeviceInfo.usingController then
coroutine.start(function()
coroutine.wait(ASYNC_TEXTINFO_LINKINFO)
InputManagerInst:ToggleBinding(self.m_naviToHyperLinkBindingId, self.view.contentTxt.textInfo.linkCount > 0)
end)
end
if info.expireTime > 0 then
self.view.expireTxt.gameObject:SetActive(true)
self.view.expireTxt.text = string.format(Language.LUA_MAIL_CELL_EXPIRED_TIME_FORMAT,
UIUtils.getLeftTime(info.expireTime - DateTimeUtils.GetCurrentTimestampByMilliseconds() / 1000))
else
self.view.expireTxt.gameObject:SetActive(false)
end
if info.items then
self.view.rewardItems:InitRewardItems(info.items, info.collected, {
enableItemHoverTips = false
})
self.view.rewardsNode.gameObject:SetActive(true)
self.view.getBtn.gameObject:SetActive(not info.collected)
self.view.delBtn.gameObject:SetActive(info.collected)
else
self.view.rewardsNode.gameObject:SetActive(false)
self.view.getBtn.gameObject:SetActive(false)
self.view.delBtn.gameObject:SetActive(true)
end
if info.isStar then
self.view.filterBtn.view.normalBtn.gameObject:SetActive(false)
self.view.filterBtn.view.selectedBtn.gameObject:SetActive(true)
else
self.view.filterBtn.view.normalBtn.gameObject:SetActive(true)
self.view.filterBtn.view.selectedBtn.gameObject:SetActive(false)
end
self.view.monthlyPassBtnNode.gameObject:SetActive(info.mail.subType == GEnums.MailSubType.MonthlyPassExpired)
self:_RefreshContentGachaPoolNode(info.mail, analyzedContentInfo.specialParamTable)
if not info.isRead then
GameInstance.player.mail:ReadMail(info.id)
end
self.view.mailContentNode:ClearTween()
self.view.mailContentNode:PlayInAnimation()
end
MailCtrl._RefreshContentGachaPoolNode = HL.Method(CS.Beyond.Gameplay.MailSystem.Mail, HL.Any) << function(self, mail, specialParamTable)
local gachaPoolNode = self.view.gachaPoolNode
gachaPoolNode.jumpGachaPoolBtn.onClick:RemoveAllListeners()
if not specialParamTable then
gachaPoolNode.gameObject:SetActive(false)
return
end
local isGachaLTTicket = mail.subType == GEnums.MailSubType.GachaLTTicket
if not isGachaLTTicket then
gachaPoolNode.gameObject:SetActive(false)
return
end
local info = specialParamTable[MailUtils.specialParamKey.GachaLTTicket][1]
local ticketId = info.itemId
local hasCfg, cfg = Tables.gachaLtTicket2PoolTable:TryGetValue(ticketId)
if not hasCfg then
logger.error(string.format("邮件类型为【%s】但卡池表中找不到itemId为【%s】的限时抽卡券", GEnums.MailSubType.GachaLTTicket, ticketId))
gachaPoolNode.gameObject:SetActive(false)
return
end
gachaPoolNode.gameObject:SetActive(true)
gachaPoolNode.itemIcon:InitItemIcon(ticketId)
local openedPoolId
for i, poolId in pairs(cfg.poolIdList) do
local hasInfo, poolInfo = GameInstance.player.gacha.poolInfos:TryGetValue(poolId)
if hasInfo and poolInfo.isOpenValid then
openedPoolId = poolId
break
end
end
local targetPoolId
if openedPoolId then
targetPoolId = openedPoolId
else
targetPoolId = cfg.poolIdList[0]
end
local _, poolCfg = Tables.gachaCharPoolTable:TryGetValue(targetPoolId)
gachaPoolNode.bannerBgImg:LoadSprite(UIConst.UI_SPRITE_GACHA_POOL, poolCfg.mailBannerImage)
gachaPoolNode.jumpGachaPoolBtn.onClick:AddListener(function()
local hasInfo, poolInfo = GameInstance.player.gacha.poolInfos:TryGetValue(targetPoolId)
if hasInfo and poolInfo.isOpenValid then
PhaseManager:OpenPhase(PhaseId.GachaPool, { poolId = targetPoolId })
else
Notify(MessageConst.SHOW_TOAST, Language.LUA_GACHA_MAIL_JUMP_FAIL)
end
end)
end
MailCtrl._OnClickGet = HL.Method() << function(self)
local info = self.m_curMails[self.m_curMailIndex]
GameInstance.player.mail:GetMailAttachment(info.id)
AudioAdapter.PostEvent("au_ui_g_confirm_button_get_mail")
end
MailCtrl._OnClickGetAll = HL.Method() << function(self)
for _, v in pairs(self.m_curMails) do
if not v.collected then
GameInstance.player.mail:GetAllMailAttachments()
return
end
end
Notify(MessageConst.SHOW_TOAST, Language.LUA_MAIL_NO_ATTACHMENT)
AudioAdapter.PostEvent("au_ui_g_confirm_button_get_all_mail")
end
MailCtrl._OnClickDel = HL.Method() << function(self)
local info = self.m_curMails[self.m_curMailIndex]
if info.items and not info.collected then
return
end
local hint
if info.isStar then
hint = Language.LUA_MAIL_HINT_DEL_STAR
else
hint = Language.LUA_MAIL_HINT_DEL_NORMAL
end
Notify(MessageConst.SHOW_POP_UP, {
content = hint,
onConfirm = function()
GameInstance.player.mail:DelMail(info.id)
AudioAdapter.PostEvent("au_ui_mail_delete")
end
})
self.m_skipClickOnce = true
end
MailCtrl._OnClickDelAll = HL.Method() << function(self)
Notify(MessageConst.SHOW_POP_UP, {
content = Language.LUA_MAIL_HINT_DEL_ALL,
onConfirm = function()
local canDelAll = false
for i, mail in ipairs(self.m_curMails) do
if mail.isRead and not mail.isStar and not (mail.items and not mail.collected) then
canDelAll = true
break
end
end
if not canDelAll then
return
end
GameInstance.player.mail:DelAllMails()
AudioAdapter.PostEvent("au_ui_mail_delete")
end
})
end
MailCtrl._OnClickLostAndFound = HL.Method() << function(self)
PhaseManager:OpenPhase(PhaseId.LostAndFound)
self.m_skipClickOnce = true
end
MailCtrl._OnClickStar = HL.Method() << function(self)
local info = self.m_curMails[self.m_curMailIndex]
GameInstance.player.mail:StarMail(info.id, not info.isStar)
end
MailCtrl._OnClickMonthlyPassBtn = HL.Method() << function(self)
PhaseManager:OpenPhase(PhaseId.CashShop, {
shopGroupId = CashShopConst.CashShopCategoryType.Pack,
cashShopId = "MCard",
})
end
MailCtrl.OnAllMailInited = HL.Method() << function(self)
if self.m_inLoading then
self:_OnLoadingFinished()
else
local curMail = self.m_curMails[self.m_curMailIndex]
self:_OnClickTab(nil, curMail and curMail.id)
end
end
MailCtrl.OnReadMail = HL.Method(HL.Table) << function(self, args)
local id = unpack(args)
for k, v in ipairs(self.m_curMails) do
if v.id == id then
local cell = self.m_getMailCell(k)
if cell then
self:_OnUpdateCell(cell, k)
end
return
end
end
end
MailCtrl.OnGetMailAttachment = HL.Method(HL.Table) << function(self, args)
local rewardPack = unpack(args)
local items = rewardPack.itemBundleList
if items.Count == 0 then
return
end
self:_OnClickTab(self.m_curMailIndex, nil)
Notify(MessageConst.SHOW_SYSTEM_REWARDS, {
title = Language.LUA_MAIL_GET_ITEM_SUCC_TITLE,
icon = "icon_mail_obtain",
items = items,
chars = rewardPack.chars,
})
end
MailCtrl.OnStarMail = HL.Method(HL.Table) << function(self, args)
local id = unpack(args)
for k, v in ipairs(self.m_curMails) do
if v.id == id then
local cell = self.m_getMailCell(k)
if cell then
self:_OnUpdateCell(cell, k)
end
if k == self.m_curMailIndex then
if v.isStar then
self.view.filterBtn.view.normalBtn.gameObject:SetActive(false)
self.view.filterBtn.view.selectedBtn.gameObject:SetActive(true)
else
self.view.filterBtn.view.normalBtn.gameObject:SetActive(true)
self.view.filterBtn.view.selectedBtn.gameObject:SetActive(false)
end
end
return
end
end
end
MailCtrl.OnDelMails = HL.Method() << function(self)
self:_OnClickTab(self.m_curMailIndex, nil)
if self.m_curMails ~= nil and #self.m_curMails == 0 then
AudioAdapter.PostEvent("Au_UI_Event_MailEmpty")
end
end
MailCtrl.OnGetNewMails = HL.Method() << function(self)
GameInstance.player.mail:GetAllMails()
end
MailCtrl._ToggleLoading = HL.Method(HL.Boolean) << function(self, active)
self.m_inLoading = active
self.view.contentNode.gameObject:SetActive(not active)
self.view.loadingNode.gameObject:SetActive(active)
end
MailCtrl._OnClickLink = HL.Method(HL.String) << function(self, value)
logger.info("_OnClickLink", value)
CS.Beyond.UI.WebApplication.Start(value)
end
MailCtrl._CheckExpiredMail = HL.Method() << function(self)
if not self.m_curMails then
return
end
for _, v in ipairs(self.m_curMails) do
if v.isExpired then
self:_OnClickTab(nil, nil)
return
end
end
end
MailCtrl._NaviToHyperLink = HL.Method() << function(self)
local textInfo = self.view.contentTxt.textInfo
local linkLength = textInfo.linkCount
if linkLength > 0 then
local actionMenuInfos = {}
for luaIndex = 1, linkLength do
local csIndex = CSIndex(luaIndex)
local actionText = textInfo.linkInfo[csIndex]:GetLinkText()
local _, linkId = self.view.contentTxt:TryGetLinkId(csIndex)
table.insert(actionMenuInfos, {
text = actionText,
action = function()
self:_OnClickLink(linkId)
end,
})
end
self.m_skipClickOnce = true
self.view.actionMenuNode.gameObject:SetActiveIfNecessary(true)
Notify(MessageConst.SHOW_NAVI_TARGET_ACTION_MENU, {
transform = self.view.actionMenuNode,
actions = actionMenuInfos,
onClose = function()
self.view.actionMenuNode.gameObject:SetActiveIfNecessary(false)
end,
posType = UIConst.UI_TIPS_POS_TYPE.LeftTop,
})
end
end
HL.Commit(MailCtrl)