Quantcast

- Profile changes to add Post and Gold info

urnati [12-29-25 - 02:47]
- Profile changes to add Post and Gold info
- XP time played text output fix
- Gold API for Config
- Post API for Config
Filename
Titan/Titan.lua
Titan/TitanConfig.lua
Titan/TitanGlobal.lua
TitanGold/TitanGold.lua
TitanPost/Localization.lua
TitanPost/TitanPost.lua
TitanPost/TitanPost.toc
TitanPost/artwork/Mail.blp
TitanPost/artwork/mail_here.mp3
TitanXP/TitanXP.lua
diff --git a/Titan/Titan.lua b/Titan/Titan.lua
index 601a835..9ccf8ef 100644
--- a/Titan/Titan.lua
+++ b/Titan/Titan.lua
@@ -263,7 +263,8 @@ local function RegisterAddonCompartment()
 				notCheckable = true,
 				func = function(button, menuInputData, menu)
 					TitanUpdateConfig("init")
-					Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About)
+					AceConfigDialog:Open("Titan Panel Main")
+--					Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About)
 				end,
 				funcOnEnter = function(button)
 					MenuUtil.ShowTooltip(button, function(tooltip)
@@ -732,8 +733,9 @@ local function handle_giu_cmds(cmd_list)
 		return
 	end

+	AceConfigDialog:Open("Titan Panel Panel Control")
 	-- DF changed how options are called. The best I get is the Titan 'about', not deeper.
-	Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About, TITAN_PANEL_CONFIG.topic.scale)
+--	Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About, TITAN_PANEL_CONFIG.topic.scale)
 	-- so the below does not work as expected...
 end

@@ -1952,6 +1954,7 @@ local function BuildMainMenu(frame)
 		info.func = function()
 			TitanUpdateConfig("init")
 			Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.About)
+--			AceConfigDialog:Open("Titan Panel Main")
 		end
 		TitanPanelRightClickMenu_AddButton(info);
 	end
diff --git a/Titan/TitanConfig.lua b/Titan/TitanConfig.lua
index 44e8958..5a67e09 100644
--- a/Titan/TitanConfig.lua
+++ b/Titan/TitanConfig.lua
@@ -1383,8 +1383,10 @@ local function TitanUpdateChars()
 		-- - green for custom profiles
 		if server == TITAN_CUSTOM_PROFILE_POSTFIX then
 			this_toon.fancy_name = TitanUtils_GetGreenText((index or "?"))
+			this_toon.is_custom = true
 		else
 			this_toon.fancy_name = TitanUtils_GetGoldText((index or "?"))
+			this_toon.is_custom = false
 		end

 		this_toon.name = index
@@ -1802,6 +1804,74 @@ local function TitanUpdateChars()
 			order = position,
 		}

+		position = position + 1
+		p_args[tostring(position)] = {
+			type = "header",
+			name = TitanUtils_GetGoldText("TitanPost"),
+			cmdHidden = true,
+			order = position,
+		}
+
+		local post_str = ""
+		local post_button = TitanUtils_GetButton("Post")
+		if post_button and post_button:IsShown() then
+			-- It is enabled
+			if this_toon.is_custom then
+				-- can not log in to custom so NA
+				post_str = L["TITAN_PANEL_NA"]
+			else
+				post_str = TitanPost.GetMailInfo(this_toon.name)
+			end
+		else
+			-- not enabled
+			post_str = L["TITAN_PANEL_MENU_DISABLED"]
+		end
+
+		position = position + 1
+		p_args[tostring(position)] = {
+			name = post_str,
+			order = position,
+			type = "description",
+		}
+		position = position + 1
+		p_args[tostring(position)] = {
+			type = "description",
+			name = "",
+			cmdHidden = true,
+			order = position,
+		}
+
+		position = position + 1
+		p_args[tostring(position)] = {
+			type = "header",
+			name = TitanUtils_GetGoldText("TitanGold"),
+			cmdHidden = true,
+			order = position,
+		}
+
+		local gold_str = ""
+		local gold_button = TitanUtils_GetButton("Gold")
+		if gold_button and gold_button:IsShown() then
+			-- It is enabled
+			if this_toon.is_custom then
+				-- can not log in to custom so NA
+				gold_str = L["TITAN_PANEL_NA"]
+			else
+				local name, server = TitanUtils_ParseName(this_toon.name)
+				local faction = UnitFactionGroup("Player")
+				gold_str = tostring(TitanPanel_GoldGetGold(name, server, faction))
+			end
+		else
+			-- not enabled
+			gold_str = L["TITAN_PANEL_MENU_DISABLED"]
+		end
+
+		position = position + 1
+		p_args[tostring(position)] = {
+			name = gold_str,
+			order = position,
+			type = "description",
+		}
 --[[		--====
 		--==== Summary section
 		position = position + 1
diff --git a/Titan/TitanGlobal.lua b/Titan/TitanGlobal.lua
index 9b0508b..6df6d9b 100644
--- a/Titan/TitanGlobal.lua
+++ b/Titan/TitanGlobal.lua
@@ -41,6 +41,14 @@ else
 	Titan_Global.switch.classic_era  = false
 end

+Titan_Global.switch.chat_class  = true -- if chat routines moved into ChatFrameUtil
+if ChatFrameUtil and ChatFrameUtil.DisplayTimePlayed then
+	Titan_Global.switch.chat_class  = true -- started in 11.* somewhere
+else
+	Titan_Global.switch.chat_class  = false -- older version
+end
+
+
 Titan_Global.AdjList = {         -- TODO : localize
 	["UIWidgetTopCenterContainerFrame"] = {
 		frame_name = "UIWidgetTopCenterContainerFrame",
diff --git a/TitanGold/TitanGold.lua b/TitanGold/TitanGold.lua
index 9581fc6..fc83d0a 100644
--- a/TitanGold/TitanGold.lua
+++ b/TitanGold/TitanGold.lua
@@ -1342,6 +1342,21 @@ local function OnClick(self, button)
 	end
 end

+function TitanPanel_GoldGetGold(player, server, faction)
+	local res = ""
+	-- Gold was written WAY before the profile changes so translate the index
+	local idx = CreateIndex(player, server, faction)
+	if _G[TITAN_BUTTON]:IsShown()
+	and GoldSave[idx]
+	then
+		res = NiceCash(GoldSave[idx].gold, true, false)
+	else
+		res = "?"
+	end
+
+	return res
+end
+
 ---local Create required Gold frames
 local function Create_Frames()
 	if _G[TITAN_BUTTON] then
diff --git a/TitanPost/Localization.lua b/TitanPost/Localization.lua
new file mode 100644
index 0000000..af8c108
--- /dev/null
+++ b/TitanPost/Localization.lua
@@ -0,0 +1,302 @@
+---     English     ---
+--- by Tekkub ---
+TITAN_POST_MENU_TEXT = "Mail";
+TITAN_POST_RIGHT_MENU_TEXT = "Mail (Right)";
+TITAN_POST_BUTTON_TEXT_NOMAIL = "No mail ";
+TITAN_POST_BUTTON_TEXT_MAIL = "New Mail ";
+TITAN_POST_BUTTON_TEXT_ALERT = "AH Alert! ";
+
+TITAN_POST_CHAT_NEW = "New Mail Received ";
+
+TITAN_POST_TOOLTIP = "Mail";
+TITAN_POST_TOOLTIP_NEW = " new mail items\n";
+TITAN_POST_TOOLTIP_TOTAL = " total mail items";
+TITAN_POST_TOOLTIP_OUTBID = "Outbid: ";
+TITAN_POST_TOOLTIP_WON = "Won: ";
+TITAN_POST_TOOLTIP_EXPIRED = "Expired: ";
+TITAN_POST_TOOLTIP_CANCELLED = "Cancelled: ";
+TITAN_POST_TOOLTIP_SOLD = "Sold: ";
+
+TITAN_POST_MENU_HIDEMM = "Hide Minimap Icon";
+TITAN_POST_MENU_COMPACT = "Compact Mode";
+TITAN_POST_MENU_CHAT = "Chat Alert";
+TITAN_POST_MENU_SOUND = "Use Sound";
+TITAN_POST_MENU_STEXT = "Show Text";
+TITAN_POST_MENU_SHOW_ICON = "Show Icon";
+TITAN_POST_MENU_COUNT = "Show Count";
+TITAN_POST_MENU_ALTICON = "Alt. AH Icon";
+TITAN_POST_MENU_NOICONNOMAIL = "No icon if no mail";
+
+---  German  ---
+--- by Lunox ---
+if ( GetLocale() == "deDE") then
+	TITAN_POST_MENU_TEXT = "Post";
+  TITAN_POST_RIGHT_MENU_TEXT = "Post (Rechts)";
+	TITAN_POST_BUTTON_TEXT_NOMAIL = "Keine Post ";
+	TITAN_POST_BUTTON_TEXT_MAIL = "Neue Post ";
+	TITAN_POST_BUTTON_TEXT_ALERT = "AH-Alarm! ";
+
+	TITAN_POST_CHAT_NEW = "Neue Post erhalten ";
+
+	TITAN_POST_TOOLTIP = "Post";
+	TITAN_POST_TOOLTIP_NEW = " neue Nachrichten\n";
+	TITAN_POST_TOOLTIP_TOTAL = " Nachrichten insgesamt";
+	TITAN_POST_TOOLTIP_OUTBID = "\195\156berboten: ";
+	TITAN_POST_TOOLTIP_WON = "Gewonnen: ";
+	TITAN_POST_TOOLTIP_EXPIRED = "Abgelaufen: ";
+	TITAN_POST_TOOLTIP_CANCELLED = "Abgebrochen: ";
+	TITAN_POST_TOOLTIP_SOLD = "Verkauft: ";
+
+	TITAN_POST_MENU_HIDEMM  = "Verstecke Minimap-Symbol";
+	TITAN_POST_MENU_COMPACT = "Kompakt-Modus";
+	TITAN_POST_MENU_CHAT = "Chat-Alarm";
+	TITAN_POST_MENU_SOUND = "Sound verwenden";
+  TITAN_POST_MENU_STEXT = "Text Anzeigen";
+  TITAN_POST_MENU_SHOW_ICON = "Symbol Anzeigen";
+  TITAN_POST_MENU_COUNT = "Anzahl Anzeigen";
+  TITAN_POST_MENU_ALTICON = "Alternatives AH-Symbol";
+  TITAN_POST_MENU_NOICONNOMAIL = "Kein Symbol, wenn keine Post";
+end
+
+---   French   ---
+--- by Apsalar ---
+if ( GetLocale() == "frFR") then
+	TITAN_POST_MENU_TEXT = "Courrier";
+  TITAN_POST_RIGHT_MENU_TEXT = "Courrier (Droite)";
+	TITAN_POST_BUTTON_TEXT_NOMAIL = "Aucun courrier";
+	TITAN_POST_BUTTON_TEXT_MAIL = "Nouveau courrier";
+	TITAN_POST_BUTTON_TEXT_ALERT = "Alerte AH!";
+
+  TITAN_POST_CHAT_NEW = "Nouveau courrier reçu";
+
+	TITAN_POST_TOOLTIP = "Courrier";
+  TITAN_POST_TOOLTIP_NEW = " nouveaux courriers\n";
+  TITAN_POST_TOOLTIP_TOTAL = " nombre total d'articles de courrier";
+	TITAN_POST_TOOLTIP_OUTBID = "Vous devez surench\195\169rir sur";
+	TITAN_POST_TOOLTIP_WON = "Vous avez gagn\195\169 l'ench\195\168re pour";
+	TITAN_POST_TOOLTIP_EXPIRED = "a expir\195\169.";
+	TITAN_POST_TOOLTIP_CANCELLED = "a \195\169t\195\169 annul\195\169e par le vendeur";
+	TITAN_POST_TOOLTIP_SOLD = " vendu.";
+
+	TITAN_POST_MENU_HIDEMM = "Cacher l'ic\195\180ne de la minicarte";
+	TITAN_POST_MENU_COMPACT = "Mode compact";
+	TITAN_POST_MENU_CHAT = "Alerte de chat";
+	TITAN_POST_MENU_SOUND = "Utiliser le son";
+	TITAN_POST_MENU_STEXT = "Afficher le texte";
+	TITAN_POST_MENU_SHOW_ICON = "Afficher l'icône";
+	TITAN_POST_MENU_COUNT = "Afficher le nombre";
+	TITAN_POST_MENU_ALTICON = "Autre icône AH";
+	TITAN_POST_MENU_NOICONNOMAIL = "Aucune icône si pas de courrier";
+end
+
+---   Italian   ---
+if ( GetLocale() == "itIT") then
+  TITAN_POST_MENU_TEXT = "Posta";
+  TITAN_POST_RIGHT_MENU_TEXT = "Posta (Destra)";
+  TITAN_POST_BUTTON_TEXT_NOMAIL = "Niente posta ";
+  TITAN_POST_BUTTON_TEXT_MAIL = "Nuova posta ";
+  TITAN_POST_BUTTON_TEXT_ALERT = "AH Allarme! ";
+
+  TITAN_POST_CHAT_NEW = "Nuova posta ricevuta ";
+
+  TITAN_POST_TOOLTIP = "Posta";
+  TITAN_POST_TOOLTIP_NEW = " nuovi elementi di posta\n";
+  TITAN_POST_TOOLTIP_TOTAL = " invii postali totali";
+  TITAN_POST_TOOLTIP_OUTBID = "Supera l'offerta: ";
+  TITAN_POST_TOOLTIP_WON = "Vinto: ";
+  TITAN_POST_TOOLTIP_EXPIRED = "Scaduto: ";
+  TITAN_POST_TOOLTIP_CANCELLED = "Annullato: ";
+  TITAN_POST_TOOLTIP_SOLD = "Venduto: ";
+
+  TITAN_POST_MENU_HIDEMM = "Nascondi icona minimappa";
+  TITAN_POST_MENU_COMPACT = "Modalità compatta";
+  TITAN_POST_MENU_CHAT = "Avviso Chat";
+  TITAN_POST_MENU_SOUND = "Usa il suono";
+  TITAN_POST_MENU_STEXT = "Mostra testo";
+  TITAN_POST_MENU_SHOW_ICON = "Mostra icona";
+  TITAN_POST_MENU_COUNT = "Mostra conteggio";
+  TITAN_POST_MENU_ALTICON = "Alt. Icona AH";
+  TITAN_POST_MENU_NOICONNOMAIL = "Nessuna icona se nessuna posta";
+end
+
+---   Korean   ---
+if ( GetLocale() == "koKR") then
+  TITAN_POST_MENU_TEXT = "우편";
+  TITAN_POST_RIGHT_MENU_TEXT = "메일 (오른쪽)";
+  TITAN_POST_BUTTON_TEXT_NOMAIL = "메일 없음 ";
+  TITAN_POST_BUTTON_TEXT_MAIL = "새 메일 ";
+  TITAN_POST_BUTTON_TEXT_ALERT = "아 경고! ";
+
+  TITAN_POST_CHAT_NEW = "새 메일 수신됨 ";
+
+  TITAN_POST_TOOLTIP = "우편";
+  TITAN_POST_TOOLTIP_NEW = " 새 메일 항목\n";
+  TITAN_POST_TOOLTIP_TOTAL = " 총 메일 항목";
+  TITAN_POST_TOOLTIP_OUTBID = "더 높은 입찰가: ";
+  TITAN_POST_TOOLTIP_WON = "이겼다: ";
+  TITAN_POST_TOOLTIP_EXPIRED = "만료됨: ";
+  TITAN_POST_TOOLTIP_CANCELLED = "취소 된: ";
+  TITAN_POST_TOOLTIP_SOLD = "판매된: ";
+
+  TITAN_POST_MENU_HIDEMM = "미니맵 아이콘 숨기기";
+  TITAN_POST_MENU_COMPACT = "컴팩트 모드";
+  TITAN_POST_MENU_CHAT = "채팅 알림";
+  TITAN_POST_MENU_SOUND = "사운드 사용";
+  TITAN_POST_MENU_STEXT = "텍스트 표시";
+  TITAN_POST_MENU_SHOW_ICON = "아이콘 표시";
+  TITAN_POST_MENU_COUNT = "카운트 표시";
+  TITAN_POST_MENU_ALTICON = "대체 AH 아이콘";
+  TITAN_POST_MENU_NOICONNOMAIL = "메일이 없으면 아이콘 없음";
+end
+
+---    Chinese    ---
+--- by Yeachan  ---
+if ( GetLocale() == "zhCN") then
+  TITAN_POST_MENU_TEXT = "郵件";
+  TITAN_POST_RIGHT_MENU_TEXT = "邮件 (右侧)";
+  TITAN_POST_BUTTON_TEXT_NOMAIL = "没有邮件 ";
+  TITAN_POST_BUTTON_TEXT_MAIL = "有新邮件";
+  TITAN_POST_BUTTON_TEXT_ALERT = "拍卖行信件! ";
+  TITAN_POST_CHAT_NEW = "收到新邮件";
+
+  TITAN_POST_TOOLTIP = "邮件助手";
+  TITAN_POST_TOOLTIP_NEW = "有新邮寄物品\n";
+  TITAN_POST_TOOLTIP_TOTAL = " 所有邮件附件物品";
+  TITAN_POST_TOOLTIP_OUTBID = "竞标失败: ";
+  TITAN_POST_TOOLTIP_WON = "竞标获胜: ";
+  TITAN_POST_TOOLTIP_EXPIRED = "拍卖到期: ";
+  TITAN_POST_TOOLTIP_CANCELLED = "拍卖取消: ";
+  TITAN_POST_TOOLTIP_SOLD = "已售出: ";
+
+  TITAN_POST_MENU_HIDEMM = "隐藏小地图邮件图标";
+  TITAN_POST_MENU_COMPACT = "简洁模式";
+  TITAN_POST_MENU_CHAT = "聊天窗口通告";
+  TITAN_POST_MENU_SOUND = "使用声音报告";
+  TITAN_POST_MENU_STEXT = "显示内容";
+  TITAN_POST_MENU_SHOW_ICON = "显示图标";
+  TITAN_POST_MENU_COUNT = "显示数目";
+  TITAN_POST_MENU_ALTICON = "改变拍卖行图标";
+  TITAN_POST_MENU_NOICONNOMAIL = "如无邮件则不显示图标";
+end
+
+if ( GetLocale() == "zhTW") then
+  TITAN_POST_MENU_TEXT = "郵件";
+  TITAN_POST_RIGHT_MENU_TEXT = "郵件(右)";
+  TITAN_POST_BUTTON_TEXT_NOMAIL = "沒有郵件 ";
+  TITAN_POST_BUTTON_TEXT_MAIL = "新郵件 ";
+  TITAN_POST_BUTTON_TEXT_ALERT = "啊警報!";
+
+  TITAN_POST_CHAT_NEW = "收到新郵件 ";
+
+  TITAN_POST_TOOLTIP = "郵件";
+  TITAN_POST_TOOLTIP_NEW = "有新郵寄物品\n";
+  TITAN_POST_TOOLTIP_TOTAL = " 所有郵件附件物品";
+  TITAN_POST_TOOLTIP_OUTBID = "競標失敗: ";
+  TITAN_POST_TOOLTIP_WON = "競標獲勝: ";
+  TITAN_POST_TOOLTIP_EXPIRED = "拍賣到期: ";
+  TITAN_POST_TOOLTIP_CANCELLED = "拍賣取消: ";
+  TITAN_POST_TOOLTIP_SOLD = "已售出: ";
+
+  TITAN_POST_MENU_HIDEMM = "隱藏小地圖郵件圖標";
+  TITAN_POST_MENU_COMPACT = "簡潔模式";
+  TITAN_POST_MENU_CHAT = "聊天窗口通告";
+  TITAN_POST_MENU_SOUND = "使用聲音報告";
+  TITAN_POST_MENU_STEXT = "顯示內容";
+  TITAN_POST_MENU_SHOW_ICON = "顯示圖標";
+  TITAN_POST_MENU_COUNT = "顯示數目";
+  TITAN_POST_MENU_ALTICON = "改變拍賣行圖標";
+  TITAN_POST_MENU_NOICONNOMAIL = "如無郵件則不顯示圖標";
+end
+
+-------   Russian   ----------------
+------- by Mikhailo ----------------
+if ( GetLocale() == "ruRU") then
+  TITAN_POST_MENU_TEXT = "Сообщение";
+  TITAN_POST_RIGHT_MENU_TEXT = "Сообщение (Правый)";
+  TITAN_POST_BUTTON_TEXT_NOMAIL = "Нет сообщений ";
+  TITAN_POST_BUTTON_TEXT_MAIL = "Новое сообщение ";
+  TITAN_POST_BUTTON_TEXT_ALERT = "Сообщение с Аукциона! ";
+
+  TITAN_POST_CHAT_NEW = "Получено новое сообщение ";
+
+  TITAN_POST_TOOLTIP = "Сообщение";
+  TITAN_POST_TOOLTIP_NEW = " новое сообщение\n";
+  TITAN_POST_TOOLTIP_TOTAL = " всего сообщений";
+  TITAN_POST_TOOLTIP_OUTBID = "Выкуплено: ";
+  TITAN_POST_TOOLTIP_WON = "Выиграно: ";
+  TITAN_POST_TOOLTIP_EXPIRED = "Истекло: ";
+  TITAN_POST_TOOLTIP_CANCELLED = "Отменено: ";
+  TITAN_POST_TOOLTIP_SOLD = "Продано: ";
+
+  TITAN_POST_MENU_HIDEMM = "Скрыть иконку на миникарте";
+  TITAN_POST_MENU_COMPACT = "Компактный режим";
+  TITAN_POST_MENU_CHAT = "Предупреждать в чат";
+  TITAN_POST_MENU_SOUND = "Использовать звук";
+  TITAN_POST_MENU_STEXT = "Показывать текст";
+  TITAN_POST_MENU_SHOW_ICON = "Показать значок";
+  TITAN_POST_MENU_COUNT = "Показывать счётчик";
+  TITAN_POST_MENU_ALTICON = "Альт. иконка Аукциона";
+  TITAN_POST_MENU_NOICONNOMAIL = "Нет иконки если нет сообщений";
+end
+
+--- Portuguese Brazil ---
+--- by Caracalho ---
+if ( GetLocale() == "ptBR") then
+  TITAN_POST_MENU_TEXT = "Caixa de Correio";
+  TITAN_POST_RIGHT_MENU_TEXT = "Correspondência a (Direita)";
+  TITAN_POST_BUTTON_TEXT_NOMAIL = "Sem Correspondência ";
+  TITAN_POST_BUTTON_TEXT_MAIL = "Nova(s) Correspondência(s) ";
+  TITAN_POST_BUTTON_TEXT_ALERT = "Casa de Leilao! ";
+
+  TITAN_POST_CHAT_NEW = "Nova(s) Correspondência(s) Recebida ";
+
+  TITAN_POST_TOOLTIP = "Caixa de Correio";
+  TITAN_POST_TOOLTIP_NEW = " nova(s) correspondência(s)\n";
+  TITAN_POST_TOOLTIP_TOTAL = " correspondência(s) no total";
+  TITAN_POST_TOOLTIP_OUTBID = "Você perdeu o lance: ";
+  TITAN_POST_TOOLTIP_WON = "Você venceu o lance: ";
+  TITAN_POST_TOOLTIP_EXPIRED = "Expirou sua Venda: ";
+  TITAN_POST_TOOLTIP_CANCELLED = "Venda Cancelada: ";
+  TITAN_POST_TOOLTIP_SOLD = "Itens foram Vendidos: ";
+
+  TITAN_POST_MENU_HIDEMM = "Esconder Icone no Mini Mapa";
+  TITAN_POST_MENU_COMPACT = "Modo Compacto";
+  TITAN_POST_MENU_CHAT = "Alerta para o Bate-Papo";
+  TITAN_POST_MENU_SOUND = "Usar Som";
+  TITAN_POST_MENU_STEXT = "Mostrar Texto";
+  TITAN_POST_MENU_SHOW_ICON = "Mostrar Icone";
+  TITAN_POST_MENU_COUNT = "Mostrar Quantidade";
+  TITAN_POST_MENU_ALTICON = "Alt. Icone da Casa de Leilao";
+  TITAN_POST_MENU_NOICONNOMAIL = "Sem icone se não tiver correspondência";
+end
+
+---  Español ---
+--- by Valeria Piñero ---
+if ( GetLocale() == "esES" or GetLocale() == "esMX") then
+  TITAN_POST_MENU_TEXT = "Buzon";
+  TITAN_POST_RIGHT_MENU_TEXT = "Correo a (Derecha)";
+  TITAN_POST_BUTTON_TEXT_NOMAIL = "No tienes correo ";
+  TITAN_POST_BUTTON_TEXT_MAIL = "Nuevo(s) Correo(s) ";
+  TITAN_POST_BUTTON_TEXT_ALERT = "Casa de Subastas! ";
+
+  TITAN_POST_CHAT_NEW = "Nuevo(s) Correo(s) Recibido(s) ";
+
+  TITAN_POST_TOOLTIP = "Buzon";
+  TITAN_POST_TOOLTIP_NEW = " nuevo(s) correo(s)\n";
+  TITAN_POST_TOOLTIP_TOTAL = " correo(s) en total";
+  TITAN_POST_TOOLTIP_OUTBID = "Ud. perdio la puja: ";
+  TITAN_POST_TOOLTIP_WON = "Ud. gano la puja: ";
+  TITAN_POST_TOOLTIP_EXPIRED = "Expiro su Venta: ";
+  TITAN_POST_TOOLTIP_CANCELLED = "Venta Cancelada: ";
+  TITAN_POST_TOOLTIP_SOLD = "Items fueron Vendidos: ";
+
+  TITAN_POST_MENU_HIDEMM = "Esconder Icono en Mini Mapa";
+  TITAN_POST_MENU_COMPACT = "Modo Compacto";
+  TITAN_POST_MENU_CHAT = "Alerta de chat";
+  TITAN_POST_MENU_SOUND = "Usar Sonido";
+  TITAN_POST_MENU_STEXT = "Mostrar Texto";
+  TITAN_POST_MENU_SHOW_ICON = "Mostrar Icono";
+  TITAN_POST_MENU_COUNT = "Mostrar Cantidade";
+  TITAN_POST_MENU_ALTICON = "Alt. Icono de Casa de Subastas";
+  TITAN_POST_MENU_NOICONNOMAIL = "Sin icono si no hay correo";
+end
diff --git a/TitanPost/TitanPost.lua b/TitanPost/TitanPost.lua
new file mode 100644
index 0000000..c55b5fd
--- /dev/null
+++ b/TitanPost/TitanPost.lua
@@ -0,0 +1,885 @@
+-- **************************************************************************
+-- * TitanPost.lua
+-- *
+-- * By: The Titan Panel Development Team
+-- **************************************************************************
+
+--[[
+Dec 2025 :
+ APIs to consider
+ CheckInbox() - when open
+GetInboxNumItems()
+GetInboxHeaderInfo(index)
+
+GetInboxInvoiceInfo(index)
+	self:RegisterEvent("MAIL_INBOX_UPDATE", UpdateAll)
+	self:RegisterEvent("MAIL_SEND_SUCCESS")
+
+	warcraft.wiki.gg/wiki/Making_scrollable_frames
+--]]
+
+-- ******************************** Constants *******************************
+local _G = getfenv(0);
+local TITAN_POST_ID = "Post";
+local TITAN_BUTTON = "TitanPanel" .. TITAN_POST_ID .. "Button"
+
+-- Constants
+local FolderPre = "Interface\\AddOns\\TitanPost\\artwork\\"
+local TITAN_POST_ICON_NEW = FolderPre .. "Mail";
+
+-- Local variables
+local L = LibStub("AceLocale-3.0"):GetLocale("Titan", true)
+local AceConfigDialog = LibStub("AceConfigDialog-3.0")
+
+local mailbox = {} -- default on load; store display info here
+mailbox.opened = false
+mailbox.when = nil
+mailbox.total = 0
+mailbox.read = 0
+mailbox.new = 0
+mailbox.expiry_active = false
+mailbox.expiry_next = 0
+mailbox.expiry_text = ""
+mailbox.expiry_num = 0
+
+local enter_or_reload = true
+
+
+local player = TitanUtils_GetPlayer()
+local debug = false;
+local SECONDS_PER_DAY = 24 * 60 * 60
+local SECONDS_PER_HOUR = 60 * 60
+local MAX_MAIL_DAYS = 30
+local MAX_COD_DAYS = 72 * SECONDS_PER_HOUR
+
+local expiry_warn_days = 7
+local expiry_err_days = 2
+
+local NOT_OPENED = "Not Opened Yet"
+local NOT_USED = "Not Used Yet"
+local NOT_SHOWN = "Not Running"
+local DAYS_REM = "Days Remaining"
+local MAIL_OPENED = "Mail Opened"
+local CHAR = "Character"
+
+local NEW_PRE = " + "
+local EXP_PRE = " !! "
+
+local MENU_SERVER = "Server_list"
+local MENU_CHAR = "Char_name"
+
+TitanPost = {}
+TitanPost.mailbox = mailbox
+--[===[ for debug
+
+	--]===]
+----------------------------------------------------------------------------------
+
+function Debug(str)
+	if (debug) then
+		DEFAULT_CHAT_FRAME:AddMessage("TitanPost " .. str);
+	end
+end
+
+local ThresholdTable = {
+	Values = { expiry_err_days, expiry_warn_days },
+	Colors = { RED_FONT_COLOR, YELLOW_FONT_COLOR, GREEN_FONT_COLOR },
+}
+local ex_header = "      " .. CHAR .. " : " .. DAYS_REM .. " : " .. MAIL_OPENED .. "\n"
+
+local date_stamp = "%Y-%m-%d"
+local time_stamp = "%H:%M"
+
+---Format time stamp
+---@param time_sec number timestamp
+---@param with_time boolean add time
+---@return string Timestamp Formatted
+local function FormatTS(time_sec, with_time)
+	local f = date_stamp
+	if with_time then
+		f = f .. " " .. time_stamp
+	else
+		-- just date w/o time
+	end
+	local str = date(f, time_sec)
+
+	return str
+end
+
+---Format an expiry text for a single toon
+---@param toon_name string
+---@param next_expiry number timestamp
+---@param last_update number timestamp
+---@return string
+local function ShowExpiry(toon_name, next_expiry, last_update)
+	local now = _G.time()
+	local res = ""
+	local use_color = true -- TitanGetVar(TITAN_POST_ID, "ShowColoredText")
+
+	local days = math.floor((next_expiry - now) / SECONDS_PER_DAY)
+	local last = FormatTS(last_update, true)
+	local estr = toon_name
+		.. " : " .. days
+		.. " : " .. last
+		.. "\n"
+	if (use_color == true)
+		or (use_color == 1) then
+		local color = TitanUtils_GetThresholdColor(ThresholdTable, days);
+		estr = TitanUtils_GetColoredText(estr, color)
+	else
+		-- leave alone
+	end
+
+	res = res .. estr
+
+	local str = "...ShowExpiry"
+		.. " " .. tostring(toon_name) .. ""
+		.. " " .. tostring(days) .. ""
+		.. " " .. tostring(last) .. ""
+		--		.." "..tostring(color)..""
+		.. " \n" .. tostring(res) .. ""
+	Debug(str)
+
+	return res
+end
+
+---Create time stamp from warning days + now
+---@return integer Timestamp
+local function ExpiryWarn()
+	local now = _G.time()
+	return (expiry_warn_days * SECONDS_PER_DAY) + now -- make timestamp
+end
+
+---Check the saved vars for expiring mail, only from last time that toon opened mail
+---@return integer Num of toons with expiring mail
+---@return string Display text with name, num, and last time mail was opened
+local function CheckExpiry()
+	local expiry_check = ExpiryWarn()
+	local res = ""
+	local exp_str = ""
+
+	local has_expiry = false
+	local expiry_toons = 0
+	local expiry_low = expiry_check + 1
+
+	local str = ""
+
+	str = "CheckExpiry"
+		.. " @ " .. FormatTS(expiry_check, true)
+		.. " " .. tostring(expiry_check) .. ""
+	Debug(str)
+
+	for toon_name, characterList in pairs(TitanPostDB) do
+		str = ".CheckExpiry"
+			.. " " .. tostring(toon_name) .. ""
+			.. " # " .. tostring(characterList.mailCount) .. ""
+		Debug(str)
+		if (characterList.mailCount > 0) then
+			str = "...CheckExpiry"
+				.. " " .. tostring(characterList.nextExpiry) .. ""
+				.. " < " .. tostring(expiry_check) .. ""
+				.. " = " .. tostring((characterList.nextExpiry < expiry_check)) .. ""
+			Debug(str)
+			if (characterList.nextExpiry < expiry_check) then -- add to list for user
+				has_expiry = true
+
+				local estr = ShowExpiry(toon_name, characterList.nextExpiry, characterList.lastUpdate)
+
+				exp_str = exp_str .. estr
+				expiry_toons = expiry_toons + 1 -- count the number of toons with expiring mail
+			else
+				-- still time
+			end
+		else
+			-- no mail
+		end
+	end
+	if has_expiry then -- add prefix for user
+		res = TITAN_POST_TOOLTIP_EXPIRED .. " " .. tostring(expiry_toons) .. "\n"
+		res = res .. ex_header
+		res = res .. exp_str
+	else
+		-- still time
+	end
+
+	str = "CheckExpiry"
+		.. " " .. tostring(expiry_toons) .. ""
+		.. " \n" .. tostring(res) .. ""
+	Debug(str)
+
+	return expiry_toons, res
+end
+
+---Create plugin text
+---@param id string
+---@return string Label
+---@return string Display text
+---@return string Label
+---@return string Display text
+local function GetButtonText(id)
+	--[[
+	local total = ""
+	local read = ""
+
+	local str = ""
+	if (mailbox.total > 0) then
+		total = tostring(mailbox.total)
+		if (mailbox.read > 0) then
+			read = tostring(mailbox.read)
+		else
+			read = ""
+		end
+		str = str .. "[" .. read .. "/" .. total .. "]"
+	else
+		str = str .. "" --NOT_OPENED
+	end
+	--]]
+
+	local new = ""
+	if (mailbox.new > 0) then
+		new = NEW_PRE .. tostring(mailbox.new)
+	else
+		new = ""
+	end
+
+	local expiry = ""
+	if (mailbox.expiry_num > 0) then
+		expiry = EXP_PRE .. tostring(mailbox.expiry_num)
+	else
+		expiry = ""
+	end
+
+	return "New : ", new,
+		"Expiry : ", expiry
+end
+
+---Create a tool tip
+---@return string
+function GetTooltipText()
+	local str = "";
+
+	--	local now = _G.time()
+	--	str = FormatTS(now, false) .. "\n" -- date only for comparisions
+
+	local playerData = TitanPostDB[player]
+	if playerData.lastUpdate == 0 then
+		str = UNKNOWN
+	else
+		str = FormatTS(playerData.lastUpdate, true)
+	end
+	str = str .. " last time Mail opened.\n"
+
+	local new = ""
+	if (mailbox.new > 0) then
+		new = NEW_PRE .. tostring(mailbox.new) .. " new mail this session.\n"
+	else
+		new = ""
+	end
+
+	local expiry = ""
+	if (mailbox.expiry_num > 0) then
+		expiry = EXP_PRE .. tostring(mailbox.expiry_num) .. " characters with mail expiring!!\n"
+	else
+		expiry = ""
+	end
+
+	--[[
+	local total = (mailbox.total > 0) and tostring(mailbox.total) or ""
+	local read = (mailbox.read > 0) and tostring(mailbox.read) or ""
+	if mailbox.opened then
+		str = str .. "[" .. read .. "/" .. total .. "]"
+	else
+		str = str .. NOT_OPENED
+	end
+--]]
+	str = str .. new .. expiry
+	str = str .. "\n"
+	str = str .. mailbox.expiry_text .. "\n"
+
+	return str;
+end
+
+local function convertSeconds(time)
+	local days = math.floor(time / 86400)
+	local hours = math.floor(math.fmod(time, 86400) / 3600)
+	local minutes = math.floor(math.fmod(time, 3600) / 60)
+	local seconds = math.floor(math.fmod(time, 60))
+
+	local s = tostring(days > 0 and days .. (days == 1 and " day, " or " days, ") or "")
+	s = s .. tostring(hours > 0 and hours .. (hours == 1 and " hour, " or " hours, ") or "")
+	s = s .. tostring(minutes > 0 and minutes .. (minutes == 1 and " minute, " or " minutes, ") or "")
+	s = s .. tostring(seconds > 0 and seconds .. (seconds == 1 and " second, " or " seconds, ") or "")
+
+	return string.gsub(s, ",[^,]*$", "")
+end
+
+---Look at any mail, setting data for action
+local function UpdateInboxData()
+	if not _G.MailFrame:IsVisible() then
+		return
+	end
+
+	local inboxCount = _G.GetInboxNumItems()
+	local playerData = TitanPostDB[player]
+	local remainingDays = MAX_MAIL_DAYS
+	local mailReadNum = 0
+
+	table.wipe(playerData.mailEntries)
+	local now = _G.time()
+
+	local str = "UpdateInboxData"
+		.. " " .. tostring(playerData) .. ""
+		.. " #" .. tostring(inboxCount) .. ""
+	Debug(str)
+
+	for index = 1, inboxCount do
+		-- https://warcraft.wiki.gg/wiki/API_GetInboxHeaderInfo
+		-- packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead,
+		--    wasReturned, textCreated, canReply, isGM = GetInboxHeaderInfo(index)
+		-- as of 2025 Dec
+		local _, _, senderName, subject, _, CODAmount, daysLeft, _, wasRead,
+		_, _, _, _ = _G.GetInboxHeaderInfo(index)
+
+		if _G.type(daysLeft) == nil then -- sanity check
+			daysLeft = MAX_MAIL_DAYS
+		end
+
+		if daysLeft < remainingDays then -- get shortest expiry
+			remainingDays = daysLeft
+		end
+
+		if wasRead then --
+			mailReadNum = mailReadNum + 1
+		end
+
+		str = "UpdateInboxData"
+			.. " #" .. tostring(index) .. ""
+			.. " '" .. tostring(senderName) .. "'"
+			.. " '" .. tostring(subject) .. "'"
+			.. " '" .. tostring(daysLeft) .. "'"
+			.. " '" .. tostring(remainingDays) .. "'"
+		Debug(str)
+
+		table.insert(playerData.mailEntries, {
+			daysLeft = daysLeft, -- fractional number
+			--			packageIcon = packageIcon,
+			senderName = senderName,
+			--			stationaryIcon = stationaryIcon,
+			subject = subject,
+			wasRead = wasRead,
+		})
+	end
+
+	playerData.lastUpdate = now
+	playerData.mailCount = inboxCount
+	playerData.mailReadNum = mailReadNum
+	playerData.nextExpiry = math.floor(remainingDays * SECONDS_PER_DAY) + now -- make timestamp
+end
+
+---Look for expiry notifications, the routine will include the current too
+local function UpdateInfo()
+	local next_exp = 0
+	mailbox.expiry_num, mailbox.expiry_text = CheckExpiry()
+
+	local str = "UpdateInfo"
+		.. " " .. tostring(player) .. ""
+	Debug(str)
+end
+
+---Ensure there is something in the saved vars
+local function InitVars()
+	local str = "InitVars"
+		.. " " .. tostring(player) .. ""
+	Debug(str)
+
+	if (not TitanPostDB) then
+		TitanPostDB = {}
+	end
+	if (not TitanPostDB[player]) then
+		TitanPostDB[player] = {}
+		local p = TitanPostDB[player]
+		p.lastUpdate = 0
+		p.mailCount = 0
+		p.mailReadNum = 0
+		p.nextExpiry = 0
+	end
+	if (not TitanPostDB[player].mailEntries) then
+		TitanPostDB[player].mailEntries = {}
+		local m = TitanPostDB[player].mailEntries
+		m.daysLeft = 0
+		m.senderName = "Init"
+		m.subject = "Init"
+		m.wasRead = false
+	end
+end
+
+---Process the MAIL_INBOX_UPDATE event while mailbox is open
+local function MailInboxUpdate()
+	local str = "MAIL_INBOX_UPDATE"
+		.. " " .. tostring(mailbox.opened) .. ""
+	Debug(str)
+
+	UpdateInboxData()
+
+	UpdateInfo()
+	Debug("Inbox: " .. GetInboxNumItems());
+	TitanPanelButton_UpdateButton(TITAN_POST_ID)
+end
+
+---Process the UPDATE_PENDING_MAIL event
+local function UpdatePending()
+	-- Fires on entering world if player has unread mail...
+	if enter_or_reload then
+		-- ignore 1st event on entering world (first or instance or reload)
+		enter_or_reload = false
+	else
+		-- Likely a brand new mail
+		mailbox.new = mailbox.new + 1
+	end
+
+	local str = "UPDATE_PENDING_MAIL"
+		.. " " .. tostring(mailbox.opened) .. ""
+		.. " " .. tostring(HasNewMail()) .. ""
+		.. " " .. tostring(GetInboxNumItems()) .. ""
+
+	Debug(str)
+
+	UpdateInfo()
+	TitanPanelButton_UpdateButton(TITAN_POST_ID)
+end
+
+---Event handler for registered events
+---@param self Button
+---@param event string
+---@param ... unknown
+local function OnEvent(self, event, ...)
+	Debug(time() .. " " .. event);
+	if (event == "VARIABLES_LOADED") then
+		InitVars()
+	end
+	if (event == "PLAYER_ENTERING_WORLD") then
+		-- ignore 1st UPDATE_PENDING_MAIL event on entering world (first or instance or reload)
+		enter_or_reload = true
+	end
+	if (event == "MAIL_INBOX_UPDATE") then
+		mailbox.opened = true -- this session only
+		--[[ Dec 2025  https://warcraft.wiki.gg/wiki/MAIL_INBOX_UPDATE
+Fires when the inbox list is loaded while the frame is open
+Fires when mail item changes from new to read
+Fires when mail item is opened for the first time in a session
+		--]]
+		MailInboxUpdate()
+	end
+	if (event == "UPDATE_PENDING_MAIL") then
+		--[[ Dec 2025  https://warcraft.wiki.gg/wiki/UPDATE_PENDING_MAIL
+Fired when the player enters the world and enters/leaves an instance, if there is mail in the player's mailbox.
+Fired when new mail is received.
+Fired when mailbox window is closed if the number of mail items in the inbox changed (I.E. you deleted mail)
+Does not appear to trigger when auction outbid mail is received... may not in other cases as well
+		--]]
+		UpdatePending()
+	end
+end
+
+---local Show list of servers / custom submenu off Profiles/Manage from the Titan (right click) menu.
+local function BuildServerProfilesMenu()
+	local info = {};
+	local servers = {};
+	local player = nil;
+	local server = nil;
+	local s, e, ident;
+	local setonce = 0;
+
+	if (TitanPanelRightClickMenu_GetDropdMenuValue() == MENU_SERVER) then
+		TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PROFILE_SERVERS"],
+			TitanPanelRightClickMenu_GetDropdownLevel());
+		-- Normal profile per toon
+		for index, id in pairs(TitanSettings.Players) do
+			player, server = TitanUtils_ParseName(index)
+
+			if TitanUtils_GetCurrentIndex(servers, server) == nil then
+				if server ~= TITAN_CUSTOM_PROFILE_POSTFIX then
+					table.insert(servers, server);
+					info = {};
+					info.notCheckable = true
+					info.text = server;
+					info.value = MENU_CHAR .. server;
+					info.hasArrow = 1;
+					TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());
+				end
+			end
+		end
+	end
+end
+
+---local Show alphabetical list of toons submenu off Profiles/Manage/<server or custom> from the Titan right click menu.
+local function BuildProfileMenu()
+	--
+	local info = {};
+	local setonce = 0;
+
+	--
+	-- Handle the profiles
+	--
+	for idx = 1, #Titan_Global.players do
+		local index = Titan_Global.players[idx]
+		local player, server = TitanUtils_ParseName(index)
+		local off = (index == TitanSettings.Player)
+			or ((index == TitanAllGetVar("GlobalProfileUse")) and (TitanAllGetVar("GlobalProfileUse")))
+		local par_val = TitanPanelRightClickMenu_GetDropdMenuValue()
+		local menu_val = string.gsub(par_val, MENU_CHAR, "")
+
+		-- handle regular profiles here
+		if server == menu_val then
+			-- Set the label once
+			if setonce and setonce == 0 then
+				TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_MENU_PROFILE_CHARS"],
+					TitanPanelRightClickMenu_GetDropdownLevel());
+				setonce = 1;
+			end
+			info = {};
+			info.disabled = off
+			info.notCheckable = true
+			info.text = player;
+			info.value = index;
+			info.hasArrow = 1;
+			TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());
+		end
+	end -- for players
+end
+
+---First level of right click menu
+---@param frame Button
+local function BuildMainMenu(frame)
+	local info;
+
+	TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_POST_ID].menuText);
+	TitanPanelRightClickMenu_AddSpacer();
+	info = {};
+	info.notCheckable = true
+	info.text = L["TITAN_PANEL_MENU_PROFILES"] .. " " .. L["TITAN_PANEL_MENU_CONFIGURATION"]
+	info.value = "ConfigProfile";
+	info.func = function()
+		TitanUpdateConfig("init")
+		AceConfigDialog:Open("Titan Panel Addon Chars")
+		--			Settings.OpenToCategory(TITAN_PANEL_CONFIG.topic.profiles)
+	end
+	TitanPanelRightClickMenu_AddButton(info);
+	TitanPanelRightClickMenu_AddSpacer();
+
+	--[[
+	TitanPanelRightClickMenu_AddSpacer();
+
+	info = {};
+	info.text = TITAN_POST_MENU_CHAT;
+	info.value = "chat";
+	info.func = TitanToggleVar(TITAN_POST_ID, "chat");
+	info.keepShownOnClick = 1;
+	info.checked = TitanGetVar(TITAN_POST_ID, "chat");
+	UIDropDownMenu_AddButton(info);
+
+	TitanPanelRightClickMenu_AddSpacer();
+
+	info = {};
+	info.notCheckable = true
+	info.text = "Servers";
+	info.value = MENU_SERVER
+	info.hasArrow = 1;
+	-- lock this menu in combat
+	if InCombatLockdown() then
+		info.disabled = 1;
+		info.hasArrow = nil;
+		info.text = info.text .. " "
+			.. _G["GREEN_FONT_COLOR_CODE"]
+			.. L["TITAN_PANEL_MENU_IN_COMBAT_LOCKDOWN"];
+	end
+	TitanPanelRightClickMenu_AddButton(info);
+
+	TitanPanelRightClickMenu_AddSpacer();
+--]]
+
+	TitanPanelRightClickMenu_AddControlVars(TITAN_POST_ID)
+end
+
+---Handle navigating within right click menu
+---@param self Button
+local function PrepareMenu(self)
+	local s, e, frame = string.find(self:GetName(), "(.*)" .. TITAN_PANEL_CLICK_MENU_SUFFIX);
+	local lev = (TitanPanelRightClickMenu_GetDropdownLevel() or 1)
+	if lev == 1 then
+		BuildMainMenu(frame)
+	end
+	--[[
+	-- Level 2
+	-- Server / Realm list
+	if (lev == 2) then
+		if (TitanPanelRightClickMenu_GetDropdMenuValue() == MENU_SERVER) then
+			BuildServerProfilesMenu()
+		end
+		return;
+	end
+
+	-- Level 3
+	-- Server / Realm list > Character on realm list
+	if (lev == 3) then
+		if string.find(TitanPanelRightClickMenu_GetDropdMenuValue(), MENU_CHAR) then
+			BuildProfileMenu()
+		end
+		return;
+	end
+--]]
+end
+
+local function sorted_index(table)
+	local index = {}
+	for key in pairs(table) do tinsert(index, key); end
+	sort(index)
+	return index
+end
+
+---Register events when active
+---@param self Button
+local function OnShow(self)
+	Debug("OnShow ");
+	-- Register for events
+	self:RegisterEvent("VARIABLES_LOADED")
+	self:RegisterEvent("MAIL_INBOX_UPDATE")
+	self:RegisterEvent("UPDATE_PENDING_MAIL")
+	self:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+	--	self:RegisterEvent("MAIL_SHOW") -- use MAIL_INBOX_UPDATE
+	--	self:RegisterEvent("MAIL_CLOSED") -- In retail, does NOT fire
+
+	UpdateInfo()
+	TitanPanelButton_UpdateButton(TITAN_POST_ID)
+end
+
+
+---Unregister events when not active
+---@param self Button
+local function OnHide(self)
+	Debug("OnHide ");
+	-- UnregisterEvent for events
+	self:UnregisterEvent("VARIABLES_LOADED");
+	self:UnregisterEvent("MAIL_INBOX_UPDATE");
+	self:UnregisterEvent("UPDATE_PENDING_MAIL");
+	self:UnregisterEvent("PLAYER_ENTERING_WORLD");
+end
+
+---Handle any mouse clicks
+---@param self Button
+---@param button string Mouse click
+local function OnClick(self, button)
+	if (button == "LeftButton") then
+		--		ToggleBags();
+	end
+end
+
+---Registry for Titan; first events
+---@param self Button
+local function OnLoad(self)
+	local notes = ""
+		.. "Adds mail expiry information to Titan Panel.\n"
+		.. "- New built-in Dec 2025.\n"
+	self.registry = {
+		id = TITAN_POST_ID,
+		menuText = TITAN_POST_ID,
+		category = "Built-ins",
+		menuTextFunction = PrepareMenu,
+		buttonTextFunction = GetButtonText,
+		tooltipTitle = TITAN_POST_ID,
+		tooltipTextFunction = GetTooltipText,
+		icon = TITAN_POST_ICON_NEW,
+		version = TITAN_VERSION,
+		iconWidth = 16,
+		notes = notes,
+		controlVariables = {
+			ShowIcon = true,
+			ShowLabelText = true,
+			--			ShowColoredText = true,
+			DisplayOnRightSide = true,
+		},
+		savedVariables = {
+			ShowIcon = 1,
+			ShowLabelText = true,
+			--			ShowColoredText = true,
+			DisplayOnRightSide = false,
+			ShowCount = 1,
+			ShowText = 1,
+			new = 0,
+			total = 0,
+			chat = 1,
+		}
+	};
+
+	-- Just these for now
+	self:RegisterEvent("VARIABLES_LOADED");
+	self:RegisterEvent("PLAYER_ENTERING_WORLD");
+end
+
+---Titan Allow Titan to lookup mail info for a toon; return a formatted string
+---@param playerName string
+---@return string
+function TitanPost.GetMailInfo(playerName)
+	local res = ""
+	local now = _G.time()
+
+	local str = "GetMailInfo"
+		.. " " .. tostring(playerName) .. ""
+	Debug(str)
+
+	if _G[TITAN_BUTTON]:IsShown() then
+		if TitanPostDB and TitanPostDB[playerName] then
+			local p = TitanPostDB[playerName]
+			local estr = ""
+			local last = ""
+
+			if p.lastUpdate == 0 then
+				-- not opened mail yet
+				res = NOT_OPENED
+			else
+				if (p.mailCount > 0) then
+					if (p.nextExpiry < ExpiryWarn()) then -- add to list for user
+						local days = math.floor((p.nextExpiry - now) / SECONDS_PER_DAY)
+						local color = TitanUtils_GetThresholdColor(ThresholdTable, days)
+						local days_str = DAYS_REM .. " : " .. tostring(days)
+						days_str = TitanUtils_GetColoredText(days_str, color)
+						estr = days_str .. "\n"
+					else
+						-- no mail to warn about
+						estr = ""
+					end
+				else
+					-- empty
+				end
+
+				last = MAIL_OPENED .. " : " .. FormatTS(p.lastUpdate, true) .. "\n"
+				res = estr .. last
+			end
+		else
+			res = NOT_USED
+		end
+	else
+		res = NOT_SHOWN
+	end
+
+	return res
+end
+
+---Titan Allow Titan to clear mail data for the given toon.
+---@param playerName string
+function TitanPost.ClearMailInfo(playerName)
+	local res = ""
+	local now = _G.time()
+
+	local str = "ClearMailInfo"
+		.. " " .. tostring(playerName) .. ""
+	Debug(str)
+
+	if _G[TITAN_BUTTON]:IsShown() then
+		if TitanPostDB and TitanPostDB[playerName] then
+			-- Set mail data to defaults for given toon
+			local p = TitanPostDB[playerName]
+			p.lastUpdate = now
+			p.mailCount = 1
+			p.mailReadNum = 0
+			p.nextExpiry = math.floor(30 * SECONDS_PER_DAY) + now -- make timestamp
+
+			table.wipe(p.mailEntries)
+		else
+			-- toon has no mail data
+		end
+	else
+		-- TitanPost not running
+	end
+end
+
+---Create needed plugin frames
+local function Create_Frames()
+	if _G[TITAN_BUTTON] then
+		return -- if already created
+	end
+
+	-- general container frame
+	local f = CreateFrame("Frame", TITAN_BUTTON .. "Frame", UIParent)
+	--	f:Hide()
+
+	-- Titan plugin button
+	local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate")
+	window:SetFrameStrata("FULLSCREEN")
+	-- Using SetScript("OnLoad",   does not work
+	OnLoad(window);
+	--	TitanPanelButton_OnLoad(window); -- Titan XML template calls this...
+
+	window:SetScript("OnShow", function(self)
+		OnShow(self);
+		TitanPanelButton_OnShow(self);
+	end)
+	window:SetScript("OnHide", function(self)
+		OnHide(self)
+	end)
+	window:SetScript("OnEvent", function(self, event, ...)
+		OnEvent(self, event, ...)
+	end)
+	window:SetScript("OnClick", function(self, button)
+		OnClick(self, button);
+		TitanPanelButton_OnClick(self, button);
+	end)
+end
+
+Create_Frames() -- do the work
+
+--==== For debug access and testing
+--[===[
+print("======")
+local TITAN_POST_ID = "Post";
+local SECONDS_PER_DAY = 24 * 60 * 60
+local now = _G.time()
+local player = "Syldil@Staghelm"
+local playerData = TitanPostDB[player]
+
+local sender = "Lascar@Staghelm"
+--[[
+local p = TitanPostDB[player]
+p.lastUpdate = now
+p.mailCount = 1
+p.mailReadNum = 0
+p.nextExpiry = math.floor(30 * SECONDS_PER_DAY) + now -- make timestamp
+
+table.wipe(playerData.mailEntries)
+TitanPostDB[player].mailEntries = {}
+TitanPostDB[player].mailEntries[1] = {}
+local m = TitanPostDB[player].mailEntries[1]
+m.daysLeft = 30
+m.senderName = sender
+m.subject = "Debug Msg"
+m.wasRead = false
+--]]
+
+--TitanPost.SimMailInboxUpdate()
+--TitanPost.SimUpdatePending()
+
+--FormatTS(1768597331, true)
+-- 1768597331 -- 2026-01-16 16:00
+--print(FormatTS(1768597331, false)) -- 2026-01-16 16:00
+--print(FormatTS(1768597331, true)) -- 2026-01-16 04:00 PM
+
+TitanDumpTable(TitanPostDB) --(playerData)
+--
+--
+
+
+-- Simulate an event manually DOES NOT WORK
+TitanPanelPostButton:OnEvent("PLAYER_REGEN_ENABLED", "player")
+
+--]===]
+
+
+
+-- ==== Simulate firing the events
+-- frame:OnEvent("MY_CUSTOM_EVENT", "arg1", "arg2") -- Does NOT appear to work...
+
+
+function TitanPost.SimUpdatePending()
+	UpdatePending()
+end
diff --git a/TitanPost/TitanPost.toc b/TitanPost/TitanPost.toc
new file mode 100644
index 0000000..d4a0937
--- /dev/null
+++ b/TitanPost/TitanPost.toc
@@ -0,0 +1,11 @@
+## Interface: 120000, 110207, 50503, 11507
+## Title: Titan Panel [|cffeda55fPost|r] |cff00aa009.0.2.0|r
+## Version: 9.0.2
+## Notes: Adds mail information to Titan Panel
+## Author: Titan Panel Development Team (http://www.titanpanel.org)
+## SavedVariables: TitanPostDB
+## Dependencies: Titan
+## OptionalDeps:
+Localization.lua
+TitanPost.lua
+
diff --git a/TitanPost/artwork/Mail.blp b/TitanPost/artwork/Mail.blp
new file mode 100644
index 0000000..44252f7
Binary files /dev/null and b/TitanPost/artwork/Mail.blp differ
diff --git a/TitanPost/artwork/mail_here.mp3 b/TitanPost/artwork/mail_here.mp3
new file mode 100644
index 0000000..9de61cb
Binary files /dev/null and b/TitanPost/artwork/mail_here.mp3 differ
diff --git a/TitanXP/TitanXP.lua b/TitanXP/TitanXP.lua
index cd5508f..685b472 100644
--- a/TitanXP/TitanXP.lua
+++ b/TitanXP/TitanXP.lua
@@ -30,9 +30,6 @@ XPTimer.last = 0
 local trace = false
 local trace_update = false

---****** overload the 'time played' text to Chat - if XP requested the API call
-local requesting
-
 -- collect the various XP variables in one place
 local txp = {
 	frame = {},
@@ -46,19 +43,36 @@ local txp = {
 	levelTime = 0,
 	sessionTime = 0,
 }
+
+--****** overload the 'time played' text to Chat - if XP requested the API call
+local requesting
+
 -- Save orignal output to Chat
-local orig_ChatFrame_DisplayTimePlayed = ChatFrame_DisplayTimePlayed
--- Override the output to Chat
-ChatFrame_DisplayTimePlayed = function(...)
+-- somewhere in 11.* (The World Within) this changed
+local orig_ChatFrame_DisplayTimePlayed = nil
+if Titan_Global.switch.chat_class then
+	orig_ChatFrame_DisplayTimePlayed = ChatFrameUtil.DisplayTimePlayed
+else
+	orig_ChatFrame_DisplayTimePlayed = ChatFrame_DisplayTimePlayed
+end
+
+local function TimePlayed(...)
 	if requesting then
 		-- XP requested time played, do not spam Chat
 		requesting = false
 	else
 		-- XP did not request time played so output
+---@diagnostic disable-next-line: need-check-nil
 		orig_ChatFrame_DisplayTimePlayed(...)
 	end
 end
---****** Override
+
+-- Override the output to Chat for the correct WoW version running
+if Titan_Global.switch.chat_class then
+	ChatFrameUtil.DisplayTimePlayed = TimePlayed(...)
+else
+	ChatFrame_DisplayTimePlayed = TimePlayed(...)
+end

 -- ******************************** Functions *******************************