diff --git a/Core/Database.lua b/Core/Database.lua
index 533b830..aa1d9b7 100644
--- a/Core/Database.lua
+++ b/Core/Database.lua
@@ -131,6 +131,7 @@ function DB:Initialize()
money = 0,
bags = {},
bank = {},
+ mailbox = {}, -- Add mailbox storage
equipped = {}, -- Add equipped items storage
character = {}, -- Add character info storage
lastUpdate = time(),
@@ -153,6 +154,10 @@ function DB:Initialize()
char.character = {}
addon:Debug("Added character field to existing character")
end
+ if not char.mailbox then
+ char.mailbox = {}
+ addon:Debug("Added mailbox field to existing character")
+ end
end
addon:Debug("Database initialized for %s", fullName)
@@ -215,6 +220,16 @@ function DB:SaveMoney(copper)
end
end
+-- Save mailbox data
+function DB:SaveMailbox(mailboxData)
+ local char = self:GetCurrentCharacter()
+ if char then
+ char.mailbox = mailboxData
+ char.lastUpdate = time()
+ addon:Debug("Saved mailbox data")
+ end
+end
+
-- Get all characters (optionally filter by faction and/or realm)
function DB:GetAllCharacters(sameFactionOnly, currentRealmOnly)
local chars = {}
@@ -256,6 +271,12 @@ function DB:GetCharacterBank(fullName)
return char and char.bank or {}
end
+-- Get character's mailbox
+function DB:GetCharacterMailbox(fullName)
+ local char = Guda_DB.characters[fullName]
+ return char and char.mailbox or {}
+end
+
-- Get character's equipped items
function DB:GetCharacterEquipped(fullName)
local char = Guda_DB.characters[fullName]
diff --git a/Core/Events.lua b/Core/Events.lua
index ec4b7a4..b690f16 100644
--- a/Core/Events.lua
+++ b/Core/Events.lua
@@ -79,3 +79,11 @@ end
function Events:OnPlayerLogout(callback, owner)
self:Register("PLAYER_LOGOUT", callback, owner)
end
+
+function Events:OnMailShow(callback, owner)
+ self:Register("MAIL_SHOW", callback, owner)
+end
+
+function Events:OnMailClosed(callback, owner)
+ self:Register("MAIL_CLOSED", callback, owner)
+end
diff --git a/Core/Init.lua b/Core/Init.lua
index aa68ab4..9066e04 100644
--- a/Core/Init.lua
+++ b/Core/Init.lua
@@ -102,11 +102,13 @@ addon.Modules = {
Tooltip = {},
BagScanner = {},
BankScanner = {},
+ MailboxScanner = {},
MoneyTracker = {},
EquipmentScanner = {},
SortEngine = {},
BagFrame = {},
BankFrame = {},
+ MailboxFrame = {},
QuestItemBar = {},
TrackedItemBar = {},
SettingsPopup = {},
diff --git a/Core/Main.lua b/Core/Main.lua
index 9316884..2025155 100644
--- a/Core/Main.lua
+++ b/Core/Main.lua
@@ -18,6 +18,7 @@ function Main:Initialize()
-- Initialize scanners
addon.Modules.BagScanner:Initialize()
addon.Modules.BankScanner:Initialize()
+ addon.Modules.MailboxScanner:Initialize()
addon.Modules.MoneyTracker:Initialize()
addon.Modules.EquipmentScanner:Initialize()
@@ -25,6 +26,7 @@ function Main:Initialize()
addon:Print("Initializing UI...")
addon.Modules.BagFrame:Initialize()
addon.Modules.BankFrame:Initialize()
+ addon.Modules.MailboxFrame:Initialize()
addon:Debug("Checking QuestItemBar module...")
if addon.Modules.QuestItemBar and addon.Modules.QuestItemBar.isLoaded then
@@ -103,6 +105,10 @@ function Main:SetupSlashCommands()
-- Toggle bank
addon.Modules.BankFrame:Toggle()
+ elseif msg == "mail" or msg == "mailbox" then
+ -- Toggle mailbox
+ addon.Modules.MailboxFrame:Toggle()
+
elseif msg == "sort" then
-- Sort bags
addon.Modules.SortEngine:SortBags()
@@ -143,6 +149,7 @@ function Main:SetupSlashCommands()
addon:Print("Commands:")
addon:Print("/guda - Toggle bags")
addon:Print("/guda bank - Toggle bank")
+ addon:Print("/guda mail - Toggle mailbox")
addon:Print("/guda sort - Sort bags")
addon:Print("/guda sortbank - Sort bank")
addon:Print("/guda track - Toggle item tracking")
diff --git a/Data/MailboxScanner.lua b/Data/MailboxScanner.lua
new file mode 100644
index 0000000..1c484fe
--- /dev/null
+++ b/Data/MailboxScanner.lua
@@ -0,0 +1,126 @@
+-- Guda Mailbox Scanner
+-- Scans and stores mailbox contents
+
+local addon = Guda
+
+local MailboxScanner = {}
+addon.Modules.MailboxScanner = MailboxScanner
+
+local mailboxOpen = false
+
+-- Scan all mailbox items and return data
+function MailboxScanner:ScanMailbox()
+ if not mailboxOpen then
+ addon:Debug("Cannot scan mailbox - not open")
+ return {}
+ end
+
+ local mailboxData = {}
+ local numItems = GetInboxNumItems()
+
+ for i = 1, numItems do
+ mailboxData[i] = self:ScanMailItem(i)
+ end
+
+ return mailboxData
+end
+
+-- Scan a single mail item
+function MailboxScanner:ScanMailItem(index)
+ -- GetInboxItem(index) returns: packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead, wasReturned, textCreated, canReply, isGM
+ local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead, wasReturned, textCreated, canReply, isGM = GetInboxItem(index)
+
+ local itemData = nil
+ if hasItem then
+ addon:Debug("Scanning mail item %d", index)
+ -- In 1.12.1, GetInboxItemLink(index) returns the link
+ local itemLink = GetInboxItemLink(index)
+
+ -- GetInboxItemInfo(index) returns: name, texture, count, quality, canUse
+ local infoName, infoTexture, infoCount, infoQuality, infoCanUse = GetInboxItemInfo(index)
+
+ addon:Debug("Mail item %d: infoName=%s, infoTexture=%s", index, tostring(infoName), tostring(infoTexture))
+
+ -- Even if link is missing (not cached), we can store what we have from GetInboxItemInfo
+ itemData = {
+ link = itemLink,
+ texture = infoTexture or packageIcon or "Interface\\Icons\\INV_Misc_Bag_08",
+ count = infoCount or 1,
+ quality = infoQuality or 0,
+ name = infoName or subject or "Unknown Item",
+ }
+
+ -- If we have a link, try to get more detailed info
+ if itemLink then
+ local itemName, link, itemQuality, iLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture, itemEquipLoc, itemSellPrice = addon.Modules.Utils:GetItemInfo(itemLink)
+ if itemName then
+ itemData.name = itemName
+ itemData.quality = itemQuality or itemData.quality
+ itemData.iLevel = iLevel
+ itemData.type = itemType
+ itemData.class = itemCategory
+ itemData.subclass = itemSubType
+ itemData.equipSlot = itemEquipLoc
+ if itemTexture then itemData.texture = itemTexture end
+ end
+ end
+ end
+
+ return {
+ sender = sender,
+ subject = subject,
+ money = money,
+ CODAmount = CODAmount,
+ daysLeft = daysLeft,
+ hasItem = hasItem,
+ item = itemData,
+ wasRead = wasRead,
+ packageIcon = packageIcon,
+ }
+end
+
+-- Save current mailbox to database
+function MailboxScanner:SaveToDatabase()
+ if not mailboxOpen then
+ return
+ end
+
+ local mailboxData = self:ScanMailbox()
+ addon.Modules.DB:SaveMailbox(mailboxData)
+ addon:Debug("Mailbox data saved")
+end
+
+-- Initialize mailbox scanner
+function MailboxScanner:Initialize()
+ -- Mailbox opened
+ addon.Modules.Events:OnMailShow(function()
+ mailboxOpen = true
+ addon:Debug("Mailbox opened")
+
+ -- Delay scan slightly to ensure item info is available
+ local frame = CreateFrame("Frame")
+ local elapsed = 0
+ frame:SetScript("OnUpdate", function()
+ elapsed = elapsed + arg1
+ if elapsed >= 0.5 then
+ frame:SetScript("OnUpdate", nil)
+ if mailboxOpen then
+ MailboxScanner:SaveToDatabase()
+ end
+ end
+ end)
+ end, "MailboxScanner")
+
+ -- Mailbox closed
+ addon.Modules.Events:OnMailClosed(function()
+ -- Final save on close
+ self:SaveToDatabase()
+ mailboxOpen = false
+ addon:Debug("Mailbox closed")
+ end, "MailboxScanner")
+end
+
+-- Check if mailbox is currently open
+function MailboxScanner:IsMailboxOpen()
+ return mailboxOpen
+end
diff --git a/Guda.toc b/Guda.toc
index 2902f4c..8dddb87 100644
--- a/Guda.toc
+++ b/Guda.toc
@@ -16,6 +16,7 @@ Core\Tooltip.lua
Data\BagScanner.lua
Data\BankScanner.lua
+Data\MailboxScanner.lua
Data\MoneyTracker.lua
Data\EquipmentScanner.lua
@@ -25,12 +26,14 @@ Sorting\SortEngine.lua
UI\ItemButton.lua
UI\BagFrame.lua
UI\BankFrame.lua
+UI\MailboxFrame.lua
UI\QuestItemBar.lua
UI\TrackedItemBar.lua
UI\SettingsPopup.lua
UI\ItemButton.xml
UI\BagFrame.xml
UI\BankFrame.xml
+UI\MailboxFrame.xml
UI\SettingsPopup.xml
Core\Main.lua
diff --git a/UI/BagFrame.lua b/UI/BagFrame.lua
index 3e30964..7e01ff7 100644
--- a/UI/BagFrame.lua
+++ b/UI/BagFrame.lua
@@ -1578,6 +1578,119 @@ local function HideCharacterDropdown()
end
end
+-- Toggle mail dropdown
+function Guda_BagFrame_ToggleMailDropdown(button)
+-- Hide character dropdown if it's shown
+ if characterDropdown and characterDropdown:IsShown() then
+ characterDropdown:Hide()
+ end
+
+ if bankDropdown and bankDropdown:IsShown() then
+ bankDropdown:Hide()
+ end
+
+ if mailDropdown and mailDropdown:IsShown() then
+ mailDropdown:Hide()
+ return
+ end
+
+ if not mailDropdown then
+ -- Create dropdown frame
+ mailDropdown = CreateFrame("Frame", "Guda_MailDropdown", UIParent)
+ mailDropdown:SetFrameStrata("DIALOG")
+ mailDropdown:SetWidth(200)
+ mailDropdown:SetBackdrop({
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
+ tile = true,
+ tileSize = 16,
+ edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 }
+ })
+ mailDropdown:SetBackdropColor(0, 0, 0, 0.95)
+ mailDropdown:EnableMouse(true)
+ mailDropdown:Hide()
+
+ mailDropdown.buttons = {}
+ end
+
+ -- Position dropdown below the button
+ mailDropdown:ClearAllPoints()
+ mailDropdown:SetPoint("TOPLEFT", button, "BOTTOMLEFT", 0, -2)
+ -- Clear existing buttons
+ for _, btn in ipairs(mailDropdown.buttons) do
+ btn:Hide()
+ end
+ mailDropdown.buttons = {}
+
+ -- Get all characters on current realm
+ local chars = addon.Modules.DB:GetAllCharacters(false, true)
+
+ local yOffset = -8
+
+ -- Add character buttons
+ for _, char in ipairs(chars) do
+ -- Capture variables in local scope for closure
+ local charFullName = char.fullName
+ local charName = char.name
+ local charClassToken = char.classToken
+
+ local charButton = CreateFrame("Button", nil, mailDropdown)
+ charButton:SetWidth(188)
+ charButton:SetHeight(20)
+ charButton:SetPoint("TOP", mailDropdown, "TOP", 0, yOffset)
+
+ -- Button background on hover
+ local charBg = charButton:CreateTexture(nil, "BACKGROUND")
+ charBg:SetAllPoints()
+ charBg:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
+ charBg:SetBlendMode("ADD")
+ charBg:SetAlpha(0)
+
+ -- Get class color
+ local classColor = charClassToken and RAID_CLASS_COLORS[charClassToken]
+ local r, g, b = 1, 1, 1
+ if classColor then
+ r, g, b = classColor.r, classColor.g, classColor.b
+ end
+
+ -- Button text
+ local charText = charButton:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
+ charText:SetPoint("LEFT", charButton, "LEFT", 8, 0)
+ charText:SetText(charName)
+ charText:SetTextColor(r, g, b)
+
+ -- Button scripts
+ charButton:SetScript("OnEnter", function()
+ charBg:SetAlpha(0.3)
+ end)
+ charButton:SetScript("OnLeave", function()
+ charBg:SetAlpha(0)
+ end)
+ charButton:SetScript("OnClick", function()
+ if charFullName then
+ -- Show mailbox for this character
+ addon.Modules.MailboxFrame:ShowCharacter(charFullName)
+ if not Guda_MailboxFrame:IsShown() then
+ Guda_MailboxFrame:Show()
+ end
+ mailDropdown:Hide()
+ else
+ addon:Print("Error: Character fullName is nil")
+ end
+ end)
+
+ table.insert(mailDropdown.buttons, charButton)
+ yOffset = yOffset - 20
+ end
+
+ -- Set dropdown height based on content
+ mailDropdown:SetHeight(math.abs(yOffset) + 8)
+
+ -- Show dropdown
+ mailDropdown:Show()
+end
+
-- Toggle bank dropdown
function Guda_BagFrame_ToggleBankDropdown(button)
-- Hide character dropdown if it's shown
diff --git a/UI/BagFrame.xml b/UI/BagFrame.xml
index aa887a5..76d6b7a 100644
--- a/UI/BagFrame.xml
+++ b/UI/BagFrame.xml
@@ -248,6 +248,52 @@
+
+
+
diff --git a/UI/BankFrame.xml b/UI/BankFrame.xml
index 0d22445..5db740e 100644
--- a/UI/BankFrame.xml
+++ b/UI/BankFrame.xml
@@ -107,6 +107,52 @@
+
+
+