mirror of
https://github.com/Lacustat/Freewood-OctoWoW-Mail.git
synced 2026-10-30 15:41:00 +00:00
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016onJCSHLwhs9udhC9ZLzk9
230 lines
9.2 KiB
Lua
230 lines
9.2 KiB
Lua
-- Freewood-OctoWoW-Mail: Archiv der entfernten Briefe (eigenes Fenster mit Suche nach Betreff und Absender).
|
|
-- Geoeffnet ueber den Knopf "Archiv" im Briefkasten-Fenster, in den Einstellungen oder mit /fwmail archive.
|
|
-- Eintraege: { t, sender, subject, body, money, items, char }. Loeschen nach X Tagen: Einstellung (Standard: nie).
|
|
|
|
local ADDON, NS = ...
|
|
|
|
local FW = _G.Freewood
|
|
local Mail = NS.Mail
|
|
if not FW or not Mail then
|
|
return
|
|
end
|
|
|
|
local UI = FW.UI
|
|
local W, H = 720, 500
|
|
local LIST_W = 290
|
|
local ROW_H, ROW_GAP = 40, 4
|
|
|
|
local win
|
|
local rows = {}
|
|
local filter = ""
|
|
local selected -- gewaehlter Eintrag (Tabelle)
|
|
local clearConfirm = false
|
|
|
|
local function T(key) return FW.L[key] or key end
|
|
local function Stamp(t) return date and date("%d.%m.%y %H:%M", t or 0) or "" end
|
|
|
|
local function Matches(e, q)
|
|
if q == "" then return true end
|
|
q = q:lower()
|
|
return (tostring(e.subject or ""):lower():find(q, 1, true) or tostring(e.sender or ""):lower():find(q, 1, true)) and true or false
|
|
end
|
|
|
|
local function Build()
|
|
local f = UI.CreatePanel(UIParent, "bgDeep", "gold")
|
|
f:SetSize(W, H)
|
|
f:SetFrameStrata("DIALOG")
|
|
f:SetClampedToScreen(true)
|
|
f:EnableMouse(true)
|
|
f:SetMovable(true)
|
|
f:RegisterForDrag("LeftButton")
|
|
f:SetScript("OnDragStart", function(self) self:StartMoving() end)
|
|
f:SetScript("OnDragStop", function(self)
|
|
self:StopMovingOrSizing()
|
|
local left, top = self:GetLeft(), self:GetTop()
|
|
if left and top then Mail.db.settings.archivePos = { x = left, y = top } end
|
|
end)
|
|
local pos = Mail.db.settings.archivePos
|
|
f:ClearAllPoints()
|
|
if pos and pos.x and pos.y then
|
|
f:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", pos.x, pos.y)
|
|
else
|
|
f:SetPoint("CENTER", UIParent, "CENTER", 60, 0)
|
|
end
|
|
|
|
local title = UI.CreateLabel(f, T("MAIL_ARCH_TITLE"), { font = "heading", size = 16, color = "goldLight" })
|
|
title:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -12)
|
|
local close = UI.CreateButton(f, "X", 26, 24, function() f:Hide() end, "danger")
|
|
close:SetPoint("TOPRIGHT", f, "TOPRIGHT", -10, -10)
|
|
local div = UI.CreateDivider(f)
|
|
div:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -40)
|
|
div:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -40)
|
|
|
|
-- Suche
|
|
local box = UI.CreatePanel(f, "bgDeep", "bronze")
|
|
box:SetSize(LIST_W, 26)
|
|
box:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -52)
|
|
local edit = CreateFrame("EditBox", nil, box)
|
|
edit:SetAutoFocus(false)
|
|
edit:SetPoint("TOPLEFT", box, "TOPLEFT", 8, -2)
|
|
edit:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -8, 2)
|
|
edit:SetMaxLetters(60)
|
|
if not edit:SetFont(UI.GetFontPath("body"), 12, "") then edit:SetFont("Fonts\\FRIZQT__.TTF", 12, "") end
|
|
edit:SetTextColor(UI.Color("text"))
|
|
edit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
|
|
edit:SetScript("OnEnterPressed", function(self) self:ClearFocus() end)
|
|
local hint = UI.CreateLabel(box, T("MAIL_ARCH_SEARCH"), { size = 12, color = "textDim" })
|
|
hint:SetPoint("LEFT", box, "LEFT", 10, 0)
|
|
edit:SetScript("OnTextChanged", function(self)
|
|
filter = self:GetText() or ""
|
|
if filter == "" then hint:Show() else hint:Hide() end
|
|
if f.Refresh then f.Refresh() end
|
|
end)
|
|
f.count = UI.CreateLabel(f, "", { size = 11, color = "textDim" })
|
|
f.count:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -84)
|
|
|
|
-- Liste
|
|
f.scroll = UI.CreateScrollFrame(f)
|
|
f.scroll:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -102)
|
|
f.scroll:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 16, 16)
|
|
f.scroll:SetWidth(LIST_W)
|
|
f.empty = UI.CreateLabel(f.scroll.child, T("MAIL_ARCH_EMPTY"), { size = 12, color = "textDim" })
|
|
f.empty:SetPoint("TOPLEFT", f.scroll.child, "TOPLEFT", 4, -6)
|
|
|
|
-- Lesefenster
|
|
local d = UI.CreatePanel(f, "card", "bronze")
|
|
d:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 28, -52)
|
|
d:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -16, 16)
|
|
d.subj = UI.CreateLabel(d, "", { font = "heading", size = 14, color = "goldLight" })
|
|
d.subj:SetPoint("TOPLEFT", d, "TOPLEFT", 12, -10)
|
|
d.subj:SetPoint("RIGHT", d, "RIGHT", -12, 0)
|
|
d.subj:SetWordWrap(false)
|
|
d.meta = UI.CreateLabel(d, "", { size = 11, color = "textDim" })
|
|
d.meta:SetPoint("TOPLEFT", d, "TOPLEFT", 12, -32)
|
|
d.meta:SetPoint("RIGHT", d, "RIGHT", -12, 0)
|
|
d.meta:SetWordWrap(false)
|
|
d.taken = UI.CreateLabel(d, "", { size = 12 })
|
|
d.taken:SetPoint("TOPLEFT", d, "TOPLEFT", 12, -52)
|
|
d.taken:SetPoint("RIGHT", d, "RIGHT", -12, 0)
|
|
d.taken:SetWordWrap(false)
|
|
d.bodyScroll = UI.CreateScrollFrame(d)
|
|
d.bodyScroll:SetPoint("TOPLEFT", d, "TOPLEFT", 12, -76)
|
|
d.bodyScroll:SetPoint("BOTTOMRIGHT", d, "BOTTOMRIGHT", -12, 50)
|
|
d.body = UI.CreateLabel(d.bodyScroll.child, "", { size = 12, justifyV = "TOP" })
|
|
d.body:SetPoint("TOPLEFT", d.bodyScroll.child, "TOPLEFT", 2, -2)
|
|
d.del = UI.CreateButton(d, T("MAIL_ARCH_DELETE"), 130, 26, function()
|
|
if not selected then return end
|
|
local a = Mail.db.archive
|
|
for i, e in ipairs(a) do
|
|
if e == selected then table.remove(a, i) break end
|
|
end
|
|
selected = nil
|
|
f.Refresh()
|
|
end, "danger")
|
|
d.del:SetPoint("BOTTOMLEFT", d, "BOTTOMLEFT", 12, 12)
|
|
d.clear = UI.CreateButton(d, T("MAIL_ARCH_CLEAR"), 210, 26, function()
|
|
if not clearConfirm then
|
|
clearConfirm = true
|
|
f.Refresh()
|
|
return
|
|
end
|
|
clearConfirm = false
|
|
for i = #Mail.db.archive, 1, -1 do table.remove(Mail.db.archive, i) end
|
|
selected = nil
|
|
f.Refresh()
|
|
end, "default")
|
|
d.clear:SetPoint("BOTTOMRIGHT", d, "BOTTOMRIGHT", -12, 12)
|
|
|
|
local function Row(i)
|
|
local row = rows[i]
|
|
if row then return row end
|
|
row = UI.CreatePanel(f.scroll.child, "card", "bronze")
|
|
row:SetHeight(ROW_H)
|
|
row:EnableMouse(true)
|
|
row.l1 = UI.CreateLabel(row, "", { size = 12 })
|
|
row.l1:SetPoint("TOPLEFT", row, "TOPLEFT", 10, -6)
|
|
row.l1:SetPoint("RIGHT", row, "RIGHT", -10, 0)
|
|
row.l1:SetWordWrap(false)
|
|
row.l2 = UI.CreateLabel(row, "", { size = 11, color = "textDim" })
|
|
row.l2:SetPoint("TOPLEFT", row, "TOPLEFT", 10, -22)
|
|
row.l2:SetPoint("RIGHT", row, "RIGHT", -10, 0)
|
|
row.l2:SetWordWrap(false)
|
|
row:SetScript("OnMouseUp", function()
|
|
selected = row.entry
|
|
clearConfirm = false
|
|
f.Refresh()
|
|
end)
|
|
rows[i] = row
|
|
return row
|
|
end
|
|
|
|
function f.Refresh()
|
|
local all = Mail.db.archive
|
|
local list = {}
|
|
for _, e in ipairs(all) do
|
|
if Matches(e, filter) then list[#list + 1] = e end
|
|
end
|
|
local w = math.max(200, (f.scroll:GetWidth() or 0) - 14)
|
|
for i, e in ipairs(list) do
|
|
local row = Row(i)
|
|
row.entry = e
|
|
row:ClearAllPoints()
|
|
row:SetPoint("TOPLEFT", f.scroll.child, "TOPLEFT", 0, -((i - 1) * (ROW_H + ROW_GAP)))
|
|
row:SetWidth(w)
|
|
row.l1:SetText(e.subject ~= "" and e.subject or T("MAIL_ARCH_NOSUBJECT"))
|
|
row.l2:SetText(tostring(e.sender or "?") .. " " .. Stamp(e.t))
|
|
UI.SetBorderColor(row, e == selected and "gold" or "bronze")
|
|
row:Show()
|
|
end
|
|
for i = #list + 1, #rows do rows[i].entry = nil rows[i]:Hide() end
|
|
f.empty:SetShown(#list == 0)
|
|
f.scroll:SetContentHeight(#list * (ROW_H + ROW_GAP) + 4)
|
|
f.count:SetText(string.format(T("MAIL_ARCH_COUNT"), #list, #all))
|
|
|
|
if selected then
|
|
local e = selected
|
|
d.subj:SetText(e.subject ~= "" and e.subject or T("MAIL_ARCH_NOSUBJECT"))
|
|
d.meta:SetText(string.format(T("MAIL_DETAIL_FROM"), tostring(e.sender or "?")) .. " " .. Stamp(e.t) ..
|
|
(e.char and (" " .. string.format(T("MAIL_ARCH_CHAR"), e.char)) or ""))
|
|
local parts = {}
|
|
if (e.money or 0) > 0 then parts[#parts + 1] = Mail.Money(e.money) end
|
|
for _, it in ipairs(e.items or {}) do parts[#parts + 1] = it end
|
|
d.taken:SetText(#parts > 0 and string.format(T("MAIL_ARCH_TAKEN"), table.concat(parts, ", ")) or "")
|
|
local text = e.body or ""
|
|
d.body:SetText(text ~= "" and text or "|cff8a8f9a" .. T("MAIL_DETAIL_NOTEXT") .. "|r")
|
|
local bw = math.max(200, (d.bodyScroll:GetWidth() or 0) - 22)
|
|
local h = UI.FitLabel(d.body, bw, 20)
|
|
d.bodyScroll:SetContentHeight(h + 8)
|
|
end
|
|
for _, wdg in ipairs({ d.subj, d.meta, d.taken, d.bodyScroll, d.del }) do wdg:SetShown(selected ~= nil) end
|
|
d.clear:SetLabel(clearConfirm and T("MAIL_ARCH_CLEAR_CONFIRM") or T("MAIL_ARCH_CLEAR"))
|
|
d.clear:SetButtonEnabled(#all > 0)
|
|
end
|
|
|
|
f:SetScript("OnShow", function() f.Refresh() end)
|
|
f:Hide()
|
|
return f
|
|
end
|
|
|
|
function Mail.OpenArchive(toggle)
|
|
if not win then
|
|
local ok, err = pcall(function() win = Build() end)
|
|
if not ok then
|
|
if FW.Print then FW:Print("Mail archive: " .. tostring(err)) end
|
|
return
|
|
end
|
|
end
|
|
if toggle and win:IsShown() then
|
|
win:Hide()
|
|
return
|
|
end
|
|
pcall(Mail.Purge, Mail)
|
|
win:Show()
|
|
win:Raise()
|
|
win.Refresh()
|
|
end
|
|
|
|
FW:On("MAIL_ARCHIVE_CHANGED", function()
|
|
if win and win:IsShown() then win.Refresh() end
|
|
end, {})
|