-- Settings. local MAX_SEND_ATTACHMENTS = MAIL_MAX_ATTACHED_ITEMS local EMPTY_ATTACHMENT_ICON = "EsoUI/Art/Mail/Gamepad/gp_mailMenu_attachItem.dds" local SEND_GOLD_ICON = "EsoUI/Art/Mail/Gamepad/gp_mailMenu_sendGold.dds" local REQUEST_GOLD_ICON = "EsoUI/Art/Mail/Gamepad/gp_mailMenu_requestGold.dds" local ATTACHING_GOLD = "attach" local REQUESTING_GOLD = "request" -- For a given inventory item, return the attachment slot index, or nil if the item is not attached. local function GetItemAttachedIndex(bagId, slotIndex) for i = 1, MAIL_MAX_ATTACHED_ITEMS do local queuedBagId, queuedSlotIndex = GetQueuedItemAttachmentInfo(i) if queuedBagId == bagId and queuedSlotIndex == slotIndex then return i end end return nil -- Item not attached. end -- Returns whether the specified inventory item is attached. local function IsItemAttached(bagId, slotIndex) if GetItemAttachedIndex(bagId, slotIndex) then return true else return false end end -- Returns the next open attachment slot index, or nil if all attachment slots are full. local function GetNextOpenAttachIndex() for i = 1, MAIL_MAX_ATTACHED_ITEMS do local queuedFromBag = GetQueuedItemAttachmentInfo(i) if queuedFromBag == 0 then -- Slot is open. return i end end return nil -- No open slots. end -- Returns whether there is any item attached. local function IsAnyItemAttached(bagId, slotIndex) for i = 1, MAIL_MAX_ATTACHED_ITEMS do local queuedFromBag = GetQueuedItemAttachmentInfo(i) if queuedFromBag ~= 0 then -- Slot is filled. return true end end return false end -- Removes the item attached in the specified slot, behaving as design requested. local function RemoveQueuedAttachment(attachmentIndex) RemoveQueuedItemAttachment(attachmentIndex) for i = attachmentIndex + 1, MAIL_MAX_ATTACHED_ITEMS do local queuedBagId, queuedSlotIndex = GetQueuedItemAttachmentInfo(i) if queuedBagId ~= 0 then -- Slot is filled. RemoveQueuedItemAttachment(i) QueueItemAttachment(queuedBagId, queuedSlotIndex, i-1) end end end -- Returns the proper platform-dependent text for the "To" field local function GetDefaultAddresseeText() local addresseeText if IsConsoleUI() then addresseeText = zo_strformat(GetString(SI_GAMEPAD_MAIL_DEFAULT_ADDRESSEE), ZO_GetPlatformAccountLabel()) else addresseeText = GetString(SI_REQUEST_NAME_DEFAULT_TEXT) end return addresseeText end -- The main class. ZO_MailSend_Gamepad = ZO_InitializingObject:Subclass() function ZO_MailSend_Gamepad:Initialize(control) self.control = control self.sendControl = self.control:GetNamedChild("Send") self:InitializeFragment() end function ZO_MailSend_Gamepad:OnShowing() self:PerformDeferredInitialization() local TRIGGER_CALLBACK = true self.inventoryList:RefreshList(TRIGGER_CALLBACK) self:PopulateMainList() self:ConnectShownEvents() self:EnterOutbox() self:UpdateMoneyAttachment() ZO_MailSend_Shared.RestorePendingMail(self) if self.initialContact or self.initialSubject then self:ClearFields() self.mailView:Display(nil, nil, self.initialContact, self.initialSubject) self.initialContact = nil self.initialSubject = nil end if self.initialBodyInsertText then self.mailView.bodyEdit.edit:InsertText(self.initialBodyInsertText) self.initialBodyInsertText = nil end self:HighlightActiveTextField() end function ZO_MailSend_Gamepad:OnHidden() self:Reset() self:DisconnectShownEvent() MAIL_GAMEPAD:DeactivateTextSearch() end function ZO_MailSend_Gamepad:PerformDeferredInitialization() if self.initialized then return end self.initialized = true self:InitializeControls() self:InitializeInventoryList() self:InitializeHeader() self:InitializeMainList() self:InitializeContactsList() self:InitializeEvents() self:InitializeKeybindDescriptors() end function ZO_MailSend_Gamepad:InitializeControls() -- Sending Mail self.loadingBox = self.control:GetNamedChild("Loading") self.loadingLabel = self.loadingBox:GetNamedChild("ContainerText") -- Mail View self.mailView = self.sendControl:GetNamedChild("RightPane"):GetNamedChild("Container"):GetNamedChild("MailView") local IS_OUTBOX = true self.mailView:Initialize(GetString(SI_GAMEPAD_MAIL_SEND_TO), EMPTY_ATTACHMENT_ICON, IS_OUTBOX, ZO_MAIL_COD_MONEY_OPTIONS_GAMEPAD, ZO_MAIL_ATTACHED_MONEY_OPTIONS_GAMEPAD, MAX_SEND_ATTACHMENTS) self.mailView:Clear() self.mailView.subjectEdit.edit:SetMaxInputChars(MAIL_MAX_SUBJECT_CHARACTERS) self.mailView.bodyEdit.edit:SetMaxInputChars(MAIL_MAX_BODY_CHARACTERS) -- Gold Slider self.goldSliderControl = self.sendControl:GetNamedChild("GoldSliderBox") self.goldSlider = ZO_CurrencySelector_Gamepad:New(self.goldSliderControl:GetNamedChild("Selector")) self.goldSlider:SetCurrencyType(CURT_MONEY) self.goldSlider:SetClampValues(true) self.goldSlider:RegisterCallback("OnValueChanged", function() MAIL_GAMEPAD:RefreshKeybind() end) end function ZO_MailSend_Gamepad:InitializeFragment() GAMEPAD_MAIL_SEND_FRAGMENT = ZO_FadeSceneFragment:New(ZO_Mail_Gamepad_TopLevelSend) GAMEPAD_MAIL_SEND_FRAGMENT:RegisterCallback("StateChange", function(oldState, newState) if newState == SCENE_FRAGMENT_SHOWING then self:OnShowing() elseif newState == SCENE_SHOWN then if self.pendingMailChanged then ZO_Dialogs_ShowGamepadDialog("MAIL_ATTACHMENTS_CHANGED") self.pendingMailChanged = nil end elseif newState == SCENE_FRAGMENT_HIDDEN then ZO_MailSend_Shared.SavePendingMail() self:OnHidden() end end) end function ZO_MailSend_Gamepad:ConnectShownEvents() self.control:RegisterForEvent(EVENT_MAIL_COD_CHANGED, function() self:UpdateMoneyAttachment() end) self.control:RegisterForEvent(EVENT_MAIL_ATTACHED_MONEY_CHANGED, function() self:UpdateMoneyAttachment() end) self.control:RegisterForEvent(EVENT_MONEY_UPDATE, function() self:UpdatePostageMoney() end) local function HandleInventoryChanged() self:PopulateMainList() end self.control:RegisterForEvent(EVENT_INVENTORY_FULL_UPDATE, HandleInventoryChanged) self.control:RegisterForEvent(EVENT_INVENTORY_SINGLE_SLOT_UPDATE, HandleInventoryChanged) end function ZO_MailSend_Gamepad:DisconnectShownEvent() self.control:UnregisterForEvent(EVENT_MAIL_COD_CHANGED) self.control:UnregisterForEvent(EVENT_MAIL_ATTACHED_MONEY_CHANGED) self.control:UnregisterForEvent(EVENT_MONEY_UPDATE) self.control:UnregisterForEvent(EVENT_INVENTORY_FULL_UPDATE) self.control:UnregisterForEvent(EVENT_INVENTORY_SINGLE_SLOT_UPDATE) end function ZO_MailSend_Gamepad:InitializeEvents() self.control:RegisterForEvent(EVENT_MAIL_ATTACHMENT_ADDED, function(_, attachSlot) self:OnMailAttachmentAdded(attachSlot) end) self.control:RegisterForEvent(EVENT_MAIL_ATTACHMENT_REMOVED, function(_, attachSlot) self:OnMailAttachmentRemoved(attachSlot) end) self.control:RegisterForEvent(EVENT_MAIL_SEND_SUCCESS, function() self:OnMailSendSuccess() end) self.control:RegisterForEvent(EVENT_MAIL_SEND_FAILED, function(_, ...) self:OnMailSendFailure(...) end) end --Global API function ZO_MailSend_Gamepad:ComposeMailTo(address, subject) self.initialContact = address self.initialSubject = subject local PUSH_SCENE = true MAIL_GAMEPAD:ShowTab(ZO_MAIL_TAB_INDEX.SEND, PUSH_SCENE) end function ZO_MailSend_Gamepad:InsertBodyText(text) self.initialBodyInsertText = text local PUSH_SCENE = true MAIL_GAMEPAD:ShowTab(ZO_MAIL_TAB_INDEX.SEND, PUSH_SCENE) end function ZO_MailSend_Gamepad:IsMailValid() local to = self.mailView:GetAddress() if (not to) or (to == "") then return false end local subject = self.mailView:GetSubject() local hasSubject = subject and (subject ~= "") local body = self.mailView:GetBody() local hasBody = body and (body ~= "") return hasSubject or hasBody or (GetQueuedMoneyAttachment() > 0) or IsAnyItemAttached() end function ZO_MailSend_Gamepad:InitializeKeybindDescriptors() -- Main list. self.mainKeybindDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, -- Back KEYBIND_STRIP:GetDefaultGamepadBackButtonDescriptor(), -- Select { name = GetString(SI_GAMEPAD_SELECT_OPTION), keybind = "UI_SHORTCUT_PRIMARY", callback = function() local targetData = self.mainList:GetTargetData() if targetData and targetData.actionFunction then targetData:actionFunction() end end, enabled = function() local isEnabled = true local targetData = self.mainList:GetTargetData() local validEntry = self:IsMailValid() if targetData and targetData.text == GetString(SI_MAIL_SEND_SEND) then isEnabled = validEntry end for i = 1, self.mainList:GetNumItems() do local itemData = self.mainList:GetDataForDataIndex(i) if itemData.text and itemData.text == GetString(SI_MAIL_SEND_SEND) then itemData.disabled = not validEntry break end end return isEnabled end, }, { keybind = "UI_SHORTCUT_SECONDARY", name = function() local targetData = self.mainList:GetTargetData() return targetData.secondaryCallbackName end, callback = function() local targetData = self.mainList:GetTargetData() targetData:secondaryCallback() end, visible = function() local targetData = self.mainList:GetTargetData() return targetData and targetData.secondaryCallback ~= nil end, }, -- Clear { name = GetString(SI_GAMEPAD_MAIL_SEND_CLEAR), keybind = "UI_SHORTCUT_TERTIARY", callback = function() ZO_Dialogs_ShowGamepadDialog("CONFIRM_CLEAR_MAIL_COMPOSE", { callback = function() self:ClearFields() end }) end }, } ZO_Gamepad_AddListTriggerKeybindDescriptors(self.mainKeybindDescriptor, self.mainList) -- Slider Edit self.sliderKeybindDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, -- Accept { name = GetString(SI_GAMEPAD_MAIL_SEND_ACCEPT_MONEY), keybind = "UI_SHORTCUT_PRIMARY", callback = function() if self.goldMode == ATTACHING_GOLD then QueueCOD(0) QueueMoneyAttachment(self.goldSlider:GetValue()) elseif self.goldMode == REQUESTING_GOLD then QueueMoneyAttachment(0) QueueCOD(self.goldSlider:GetValue()) end PlaySound(SOUNDS.ITEM_MONEY_CHANGED) self:UpdatePostageMoney() self:EnterOutbox() local targetControl = self.mainList:GetTargetControl() targetControl:SetHidden(false) end, visible = function() return self.goldSlider:GetValue() <= self.goldSlider:GetMaxValue() end, }, -- Cancel KEYBIND_STRIP:GenerateGamepadBackButtonDescriptor(function() self.mainList:WhenInactiveSetTargetControlHidden(true) self:UpdateMoneyAttachment() self:EnterOutbox() end), } -- Contacts List self.contactsKeybindDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, -- Accept { name = GetString(SI_GAMEPAD_MAIL_SEND_ACCEPT_MONEY), keybind = "UI_SHORTCUT_PRIMARY", callback = function() self:EnterOutbox() local selectedItem = self.contactsList:GetTargetData() if selectedItem.actionFunction then selectedItem.actionFunction(selectedItem) end end, }, -- Cancel KEYBIND_STRIP:GenerateGamepadBackButtonDescriptor(function() self:UpdateMoneyAttachment() self:EnterOutbox() end), } ZO_Gamepad_AddListTriggerKeybindDescriptors(self.contactsKeybindDescriptor, self.contactsList) -- Inventory self.inventoryKeybindDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, -- Add to Mail/Remove from Mail { name = function() local selectedItem = self.inventoryList:GetTargetData() if IsItemAttached(selectedItem.bagId, selectedItem.slotIndex) then return GetString(SI_GAMEPAD_MAIL_SEND_DETACH_ITEM) else return GetString(SI_GAMEPAD_MAIL_SEND_ATTACH_ITEM) end end, keybind = "UI_SHORTCUT_PRIMARY", callback = function() local selectedItem = self.inventoryList:GetTargetData() local bagId = selectedItem.bagId local slotIndex = selectedItem.slotIndex local attachedSlotIndex = GetItemAttachedIndex(bagId, slotIndex) if attachedSlotIndex then -- Item is attached, detach it. RemoveQueuedAttachment(attachedSlotIndex) local soundCategory = GetItemSoundCategory(bagId, slotIndex) PlayItemSound(soundCategory, ITEM_SOUND_ACTION_UNEQUIP) else -- Item is not attached, attach it. attachedSlotIndex = GetNextOpenAttachIndex() if attachedSlotIndex then QueueItemAttachment(bagId, slotIndex, attachedSlotIndex) local soundCategory = GetItemSoundCategory(bagId, slotIndex) PlayItemSound(soundCategory, ITEM_SOUND_ACTION_EQUIP) end end SCREEN_NARRATION_MANAGER:QueueParametricListEntry(self.inventoryList.list) end, visible = function() local selectedItem = self.inventoryList:GetTargetData() if not selectedItem then return false end local bagId = selectedItem.bagId local slotIndex = selectedItem.slotIndex if IsItemAttached(bagId, slotIndex) then return true -- Can always remove an attached item. end local attachedSlotIndex = GetNextOpenAttachIndex() if not attachedSlotIndex then return false end local canAttach = CanQueueItemAttachment(bagId, slotIndex, attachedSlotIndex) return canAttach end, }, -- Back KEYBIND_STRIP:GenerateGamepadBackButtonDescriptor(function() self:OnInventoryListBackButtonClicked() end), } end function ZO_MailSend_Gamepad:OnInventoryListBackButtonClicked() self:UpdatePostageMoney() self:EnterOutbox() end local function UpdatePlayerGold(control) ZO_CurrencyControl_SetSimpleCurrency(control, CURT_MONEY, GetCurrencyAmount(CURT_MONEY, CURRENCY_LOCATION_CHARACTER), ZO_MAIL_HEADER_MONEY_OPTIONS_GAMEPAD) return true end local function UpdatePostage(control) ZO_CurrencyControl_SetSimpleCurrency(control, CURT_MONEY, GetQueuedMailPostage(), ZO_MAIL_HEADER_MONEY_OPTIONS_GAMEPAD) return true end local function GetPostageNarration() return ZO_Currency_FormatGamepad(CURT_MONEY, GetQueuedMailPostage(), ZO_CURRENCY_FORMAT_AMOUNT_NAME) end function ZO_MailSend_Gamepad:InitializeHeader() self.mainHeaderData = { data1HeaderText = GetString(SI_GAMEPAD_MAIL_INBOX_PLAYER_GOLD), data1Text = UpdatePlayerGold, data1TextNarration = ZO_Currency_GetPlayerCarriedGoldCurrencyNameNarration, data2HeaderText = GetString(SI_GAMEPAD_MAIL_SEND_POSTAGE_LABEL), data2Text = UpdatePostage, data2TextNarration = GetPostageNarration, tabBarEntries = MAIL_GAMEPAD.tabBarEntries, } self.setFieldHeaderData = { data1HeaderText = GetString(SI_GAMEPAD_MAIL_INBOX_PLAYER_GOLD), data1Text = UpdatePlayerGold, data1TextNarration = ZO_Currency_GetPlayerCarriedGoldCurrencyNameNarration, data2HeaderText = GetString(SI_GAMEPAD_MAIL_SEND_POSTAGE_LABEL), data2Text = UpdatePostage, data2TextNarration = GetPostageNarration, } end local function InventorySetupFunction(entryData) entryData.isMailAttached = IsItemAttached(entryData.bagId, entryData.slotIndex) entryData:SetIgnoreTraitInformation(true) end local function ItemFilterFunction(entryData) local bagId = entryData.bagId local slotIndex = entryData.slotIndex return (CanQueueItemAttachment(bagId, slotIndex) or IsItemAttached(bagId, slotIndex)) and not entryData.isPlayerLocked end local SETUP_LOCALLY = true function ZO_MailSend_Gamepad:InitializeInventoryList() local function OnRefreshList(list) if list:GetNumItems() == 0 then MAIL_GAMEPAD:RequestEnterHeader() else MAIL_GAMEPAD:RequestLeaveHeader() end end self.inventoryList = MAIL_GAMEPAD:AddList("Inventory", SETUP_LOCALLY, ZO_GamepadInventoryList, BAG_BACKPACK, SLOT_TYPE_ITEM, function(...) self:InventorySelectionChanged(...) end, InventorySetupFunction) self.inventoryList:SetOnRefreshListCallback(OnRefreshList) self.inventoryList:SetSearchContext("mailTextSearch") self.inventoryList:SetItemFilterFunction(ItemFilterFunction) self.inventoryList:SetNoItemText(GetString(SI_GAMEPAD_INVENTORY_EMPTY)) MAIL_GAMEPAD:SetOnBackButtonCallback(function() self:OnInventoryListBackButtonClicked() end) MAIL_GAMEPAD:SetTextSearchEntryHidden(true) self.inventoryListControl = self.inventoryList:GetControl() end function ZO_MailSend_Gamepad:AddMainListEntry(text, header, icon, callback, secondaryCallbackName, secondaryCallback, narrationText) local newEntry = ZO_GamepadEntryData:New(text, icon) newEntry.actionFunction = callback newEntry.secondaryCallbackName = secondaryCallbackName newEntry.secondaryCallback = secondaryCallback newEntry.narrationText = narrationText local template if header then newEntry:SetHeader(header) template = "ZO_GamepadMenuEntryTemplateWithHeader" else template = "ZO_GamepadMenuEntryTemplate" end newEntry:SetIconTintOnSelection(true) self.mainList:AddEntry(template, newEntry) end function ZO_MailSend_Gamepad:PopulateMainList() local function RefreshKeybind() MAIL_GAMEPAD:RefreshKeybind() end self.mainList:Clear() self.onUserListDialogIdSelectedForMailTo = function(hasResult, displayName, consoleId) local editControl = self.mailView.addressEdit.edit if hasResult then editControl:SetText(displayName) end end local NO_HEADER = nil local NO_ICON = nil local NO_SECONDARY_CALLBACK_NAME = nil local NO_SECONDARY_CALLBACK = nil do local userListCallback = function() local INCLUDE_ONLINE_FRIENDS = true local INCLUDE_OFFLINE_FRIENDS = true PLAYER_CONSOLE_INFO_REQUEST_MANAGER:RequestIdFromUserListDialog(self.onUserListDialogIdSelectedForMailTo, GetString(SI_GAMEPAD_CONSOLE_SELECT_FOR_MAIL), INCLUDE_ONLINE_FRIENDS, INCLUDE_OFFLINE_FRIENDS) end local editBoxCallback = function() self.mailView.addressEdit.edit:TakeFocus() end local mailSendNarrationText = function(entryData, entryControl) return ZO_FormatEditBoxNarrationText(self.mailView.addressEdit.edit, entryData.text) end if ZO_IsPlaystationPlatform() then self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_SEND_TO), NO_HEADER, NO_ICON, userListCallback, NO_SECONDARY_CALLBACK_NAME, NO_SECONDARY_CALLBACK, mailSendNarrationText) elseif GetUIPlatform() == UI_PLATFORM_XBOX then if GetNumberConsoleFriends() > 0 then self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_SEND_TO), NO_HEADER, NO_ICON, editBoxCallback, GetString(SI_GAMEPAD_CONSOLE_CHOOSE_FRIEND), userListCallback, mailSendNarrationText) else self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_SEND_TO), NO_HEADER, NO_ICON, editBoxCallback, GetString(SI_GAMEPAD_CONSOLE_CHOOSE_FRIEND), NO_SECONDARY_CALLBACK, mailSendNarrationText) end else self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_SEND_TO), NO_HEADER, NO_ICON, editBoxCallback, NO_SECONDARY_CALLBACK_NAME, NO_SECONDARY_CALLBACK, mailSendNarrationText) end end local mailSubjectNarrationText = function(entryData, entryControl) return ZO_FormatEditBoxNarrationText(self.mailView.subjectEdit.edit, entryData.text) end local mailBodyNarrationText = function(entryData, entryControl) return ZO_FormatEditBoxNarrationText(self.mailView.bodyEdit.edit, entryData.text) end local mailGoldNarrationText = function(entryData, entryControl) local narrations = {} local queuedCOD = GetQueuedCOD() local queuedMoney = GetQueuedMoneyAttachment() local moneyHeader local moneyText if queuedMoney > 0 then moneyHeader = GetString(SI_MAIL_READ_SENT_GOLD_LABEL) moneyText = ZO_Currency_FormatGamepad(CURT_MONEY, queuedMoney, ZO_CURRENCY_FORMAT_AMOUNT_NAME) elseif queuedCOD > 0 then moneyHeader = GetString(SI_MAIL_READ_COD_LABEL) moneyText = ZO_Currency_FormatGamepad(CURT_MONEY, queuedCOD, ZO_CURRENCY_FORMAT_AMOUNT_NAME) else moneyHeader = GetString(SI_MAIL_READ_SENT_GOLD_LABEL) moneyText = GetString(SI_GAMEPAD_MAIL_INBOX_NO_ATTACHED_GOLD) end ZO_AppendNarration(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(entryData.text)) ZO_AppendNarration(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(moneyHeader)) ZO_AppendNarration(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(moneyText)) return narrations end self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_SUBJECT_LABEL), NO_HEADER, NO_ICON, function() self.mailView.subjectEdit.edit:TakeFocus() end, NO_SECONDARY_CALLBACK_NAME, NO_SECONDARY_CALLBACK, mailSubjectNarrationText) self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_BODY_LABEL), NO_HEADER, NO_ICON, function() self.mailView.bodyEdit.edit:TakeFocus() end, NO_SECONDARY_CALLBACK_NAME, NO_SECONDARY_CALLBACK, mailBodyNarrationText) self:AddMainListEntry(GetString(SI_MAIL_SEND_ATTACH_MONEY), GetString(SI_GAMEPAD_MAIL_SEND_GOLD_HEADER), SEND_GOLD_ICON, function() self:ShowSliderControl(ATTACHING_GOLD, GetQueuedMoneyAttachment(), GetCurrencyAmount(CURT_MONEY, CURRENCY_LOCATION_CHARACTER)) end, NO_SECONDARY_CALLBACK_NAME, NO_SECONDARY_CALLBACK, mailGoldNarrationText) self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_SEND_COD), NO_HEADER, REQUEST_GOLD_ICON, function() self:ShowSliderControl(REQUESTING_GOLD, GetQueuedCOD(), MAX_PLAYER_CURRENCY) end, NO_SECONDARY_CALLBACK_NAME, NO_SECONDARY_CALLBACK, mailGoldNarrationText) self.mailView.subjectEdit.edit:SetHandler("OnFocusLost", function(editBox) RefreshKeybind() ZO_GamepadEditBox_FocusLost(editBox) --Re-narrate the edit box when we are done typing in it SCREEN_NARRATION_MANAGER:QueueParametricListEntry(MAIL_GAMEPAD:GetCurrentList()) end) self.mailView.addressEdit.edit:SetHandler("OnFocusLost", function(editBox) RefreshKeybind() ZO_GamepadEditBox_FocusLost(editBox) --Re-narrate the edit box when we are done typing in it SCREEN_NARRATION_MANAGER:QueueParametricListEntry(MAIL_GAMEPAD:GetCurrentList()) end) self.mailView.bodyEdit.edit:SetHandler("OnFocusLost", function(editBox) RefreshKeybind() ZO_GamepadEditBox_FocusLost(editBox) --Re-narrate the edit box when we are done typing in it SCREEN_NARRATION_MANAGER:QueueParametricListEntry(MAIL_GAMEPAD:GetCurrentList()) end) if not self.inventoryList:IsEmpty() then local mailAttachedItemsNarrationText = function(entryData, entryControl) local narrations = {} ZO_AppendNarration(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(entryData.text)) local totalAttachments = 0 for i = 1, MAIL_MAX_ATTACHED_ITEMS do local queuedFromBag, slotIndex, icon, stack = GetQueuedItemAttachmentInfo(i) if queuedFromBag ~= 0 then -- Slot is filled. totalAttachments = totalAttachments + stack else break end end ZO_AppendNarration(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(GetString(SI_MAIL_ATTACHMENTS_HEADER))) if totalAttachments > 0 then ZO_AppendNarration(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(totalAttachments)) else ZO_AppendNarration(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(GetString(SI_GAMEPAD_MAIL_INBOX_NO_ATTACHMENTS))) end return narrations end self:AddMainListEntry(GetString(SI_GAMEPAD_MAIL_SEND_ATTACH), GetString(SI_GAMEPAD_MAIL_SEND_ITEMS_HEADER), EMPTY_ATTACHMENT_ICON, function() self:EnterInventoryList() end, NO_SECONDARY_CALLBACK_NAME, NO_SECONDARY_CALLBACK, mailAttachedItemsNarrationText) end local function AttemptSendMail() local to = self.mailView:GetAddress() local subject = self.mailView:GetSubject() local body = self.mailView:GetBody() if IsConsoleUI() then ZO_ConsoleAttemptCommunicateOrError(function(success) if success then SendMail(to, subject, body) self:EnterSending() end end, to, ZO_PLAYER_CONSOLE_INFO_REQUEST_BLOCK, ZO_CONSOLE_CAN_COMMUNICATE_ERROR_DIALOG, ZO_ID_REQUEST_TYPE_DISPLAY_NAME, to) else SendMail(to, subject, body) self:EnterSending() end end self:AddMainListEntry(GetString(SI_MAIL_SEND_SEND), GetString(SI_MAIL_SEND_SEND), ZO_GAMEPAD_SUBMIT_ENTRY_ICON, AttemptSendMail) self.mainList:Commit() end function ZO_MailSend_Gamepad:InitializeMainList() self.mainList = MAIL_GAMEPAD:GetMainList() self.mainList:SetOnSelectedDataChangedCallback(function(...) self:OnListMovement(...) end) self:PopulateMainList() end function ZO_MailSend_Gamepad:OnListMovement(list, isMoving) self.mailView.addressEdit.edit:LoseFocus() self.mailView.subjectEdit.edit:LoseFocus() self.mailView.bodyEdit.edit:LoseFocus() self:HighlightActiveTextField() KEYBIND_STRIP:UpdateKeybindButtonGroup(self.mainKeybindDescriptor) end function ZO_MailSend_Gamepad:HighlightActiveTextField() local textFieldToControl = { [GetString(SI_GAMEPAD_MAIL_SEND_TO)] = self.mailView.addressEdit, [GetString(SI_GAMEPAD_MAIL_SUBJECT_LABEL)] = self.mailView.subjectEdit, [GetString(SI_GAMEPAD_MAIL_BODY_LABEL)] = self.mailView.bodyEdit } for _, control in pairs(textFieldToControl) do control.highlight:SetHidden(true) end local textField = self.mainList:GetTargetData().text local currentEditControl = textFieldToControl[textField] if currentEditControl then currentEditControl.highlight:SetHidden(false) end KEYBIND_STRIP:UpdateKeybindButtonGroup(self.mainKeybindDescriptor) end function ZO_MailSend_Gamepad:InitializeContactsList() self.contactsList = MAIL_GAMEPAD:AddList("Contacts") self.contactsListControl = self.contactsList:GetControl() end function ZO_MailSend_Gamepad:ClearFields() self:Clear() self:EnterOutbox() end function ZO_MailSend_Gamepad:Reset() if (not self.inventoryListControl:IsHidden()) or (not self.goldSliderControl:IsHidden()) or (not self.contactsListControl:IsHidden()) then PlaySound(SOUNDS.GAMEPAD_MENU_BACK) end self.goldSliderControl:SetHidden(true) self.mainList:WhenInactiveSetTargetControlHidden(false) GAMEPAD_TOOLTIPS:ClearTooltip(GAMEPAD_LEFT_TOOLTIP) self.loadingBox:SetHidden(true) self.goldSlider:Deactivate() self.goldMode = nil self.inSendMode = false MAIL_GAMEPAD:RequestLeaveHeader() end function ZO_MailSend_Gamepad:SwitchToSendTab() MAIL_GAMEPAD:SwitchToHeader(self.mainHeaderData, ZO_MAIL_TAB_INDEX.SEND) end function ZO_MailSend_Gamepad:EnterSending() self.inSendMode = true self:Reset() MAIL_GAMEPAD:SwitchToKeybind(nil) -- Remove keybinds as they are invaild when sending. self.loadingLabel:SetText(GetString(SI_GAMEPAD_MAIL_SEND_SENDING)) self.loadingBox:SetHidden(false) MAIL_GAMEPAD:DeactivateTextSearch() MAIL_GAMEPAD:SetCurrentList(nil) self:EnableMailEditboxes(false) end function ZO_MailSend_Gamepad:EnterOutbox() self:Reset() if self.inSendMode then self:EnterSending() else self:SwitchToSendTab() MAIL_GAMEPAD:DeactivateTextSearch() MAIL_GAMEPAD:SetCurrentList(self.mainList) MAIL_GAMEPAD:SwitchToKeybind(self.mainKeybindDescriptor) self:EnableMailEditboxes(true) end end function ZO_MailSend_Gamepad:EnableMailEditboxes(enabled) self.mailView.addressEdit.edit:SetMouseEnabled(enabled) self.mailView.subjectEdit.edit:SetMouseEnabled(enabled) self.mailView.bodyEdit.edit:SetMouseEnabled(enabled) end function ZO_MailSend_Gamepad:AddContact(text, header, callback) local newEntry = ZO_GamepadEntryData:New(text) newEntry.actionFunction = callback local template if header then newEntry:SetHeader(header) template = "ZO_GamepadMenuEntryTemplateWithHeader" else template = "ZO_GamepadMenuEntryTemplate" end self.contactsList:AddEntry(template, newEntry) end local RECIPIENT_HEADER_TEXT = GetString(SI_GAMEPAD_MAIL_SEND_RECIPIENT) function ZO_MailSend_Gamepad:EnterContactsList() self.contactsList:Clear() -- Text edit self:AddContact(GetString(SI_GAMEPAD_MAIL_SEND_ENTER_NAME), nil, function() self.mailView.addressEdit.edit:TakeFocus() end) self.contactsList:Commit() self.setFieldHeaderData.titleText = RECIPIENT_HEADER_TEXT MAIL_GAMEPAD:SwitchToHeader(self.setFieldHeaderData) MAIL_GAMEPAD:SwitchToKeybind(self.contactsKeybindDescriptor) MAIL_GAMEPAD:DeactivateTextSearch() MAIL_GAMEPAD:SetCurrentList(self.contactsList) self:EnableMailEditboxes(true) PlaySound(SOUNDS.GAMEPAD_MENU_FORWARD) end function ZO_MailSend_Gamepad:ShowSliderControl(mode, value, maxValue) MAIL_GAMEPAD:DeactivateCurrentList() self.mainList:WhenInactiveSetTargetControlHidden(true) self.goldSlider:SetMaxValue(maxValue) self.goldSlider:SetValue(value) MAIL_GAMEPAD:SwitchToKeybind(self.sliderKeybindDescriptor) self.goldSlider:Activate() self.goldMode = mode self.goldSliderControl:SetHidden(false) PlaySound(SOUNDS.GAMEPAD_MENU_FORWARD) end local ATTACHMENT_HEADER_TEXT = GetString(SI_GAMEPAD_MAIL_SEND_ATTACH) function ZO_MailSend_Gamepad:EnterInventoryList() self:Reset() self.setFieldHeaderData.titleText = ATTACHMENT_HEADER_TEXT MAIL_GAMEPAD:SwitchToHeader(self.setFieldHeaderData) MAIL_GAMEPAD:SwitchToKeybind(self.inventoryKeybindDescriptor) MAIL_GAMEPAD:SetCurrentList(self.inventoryList) MAIL_GAMEPAD:ActivateTextSearch() self:EnableMailEditboxes(true) if self.inventoryList and self.inventoryList:GetNumItems() == 0 then MAIL_GAMEPAD:RequestEnterHeader() end PlaySound(SOUNDS.GAMEPAD_MENU_FORWARD) end function ZO_MailSend_Gamepad:InventorySelectionChanged(list, selectedData) if MAIL_GAMEPAD:GetCurrentList() == self.inventoryList then GAMEPAD_TOOLTIPS:ClearLines(GAMEPAD_LEFT_TOOLTIP) if selectedData then GAMEPAD_TOOLTIPS:LayoutBagItem(GAMEPAD_LEFT_TOOLTIP, selectedData.bagId, selectedData.slotIndex) end MAIL_GAMEPAD:RefreshKeybind() end end function ZO_MailSend_Gamepad:Clear() ClearQueuedMail() self.mailView:Clear() self:UpdateMoneyAttachment() end function ZO_MailSend_Gamepad:UpdateMoneyAttachment() local queuedCOD = GetQueuedCOD() local queuedMoney = GetQueuedMoneyAttachment() self.mailView:Display(queuedCOD, queuedMoney) self:UpdatePostageMoney() end function ZO_MailSend_Gamepad:IsAttachingItems() return not self.sendControl:IsHidden() end function ZO_MailSend_Gamepad:UpdatePostageMoney() MAIL_GAMEPAD:RefreshHeader() end function ZO_MailSend_Gamepad:OnMailAttachmentAdded(attachSlot) local _, _, icon, stack = GetQueuedItemAttachmentInfo(attachSlot) self.mailView:SetAttachment(attachSlot, stack, icon) self:UpdatePostageMoney() MAIL_GAMEPAD:RefreshKeybind() self.inventoryList:RefreshList() end function ZO_MailSend_Gamepad:OnMailAttachmentRemoved(attachSlot) self.mailView:ClearAttachment(attachSlot) self:UpdatePostageMoney() MAIL_GAMEPAD:RefreshKeybind() self.inventoryList:RefreshList() end function ZO_MailSend_Gamepad:OnMailSendSuccess() PlaySound(SOUNDS.MAIL_SENT) self.inSendMode = false self:Clear() if not self.sendControl:IsHidden() then self:EnterOutbox() end end function ZO_MailSend_Gamepad:OnMailSendFailure(failureReason) self.inSendMode = false if not self.sendControl:IsHidden() then self:EnterOutbox() end end -- XML Handlers function ZO_MailView_Initialize_Send_Fields_Gamepad(control) control.addressEdit.edit:SetDefaultText(GetDefaultAddresseeText()) control.subjectEdit.edit:SetDefaultText(GetString(SI_MAIL_SUBJECT_DEFAULT_TEXT)) end