initial commit

This commit is contained in:
Gitea
2020-11-13 14:13:12 -05:00
commit 05df49ff60
368 changed files with 128754 additions and 0 deletions

243
Core/UI/MailingUI/Core.lua Normal file
View File

@@ -0,0 +1,243 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local MailingUI = TSM.UI:NewPackage("MailingUI")
local L = TSM.Include("Locale").GetTable()
local Delay = TSM.Include("Util.Delay")
local FSM = TSM.Include("Util.FSM")
local Event = TSM.Include("Util.Event")
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
topLevelPages = {},
frame = nil,
fsm = nil,
defaultUISwitchBtn = nil,
isVisible = false,
}
local MIN_FRAME_SIZE = { width = 575, height = 400 }
-- ============================================================================
-- Module Functions
-- ============================================================================
function MailingUI.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mailingUIContext", "showDefault")
:AddKey("global", "mailingUIContext", "frame")
private.FSMCreate()
end
function MailingUI.OnDisable()
-- hide the frame
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end
function MailingUI.RegisterTopLevelPage(name, callback)
tinsert(private.topLevelPages, { name = name, callback = callback })
end
function MailingUI.IsVisible()
return private.isVisible
end
function MailingUI.SetSelectedTab(buttonText, redraw)
private.frame:SetSelectedNavButton(buttonText, redraw)
end
-- ============================================================================
-- Main Frame
-- ============================================================================
function private.CreateMainFrame()
TSM.UI.AnalyticsRecordPathChange("mailing")
-- Always show the Inbox first
private.settings.frame.page = 1
local frame = UIElements.New("LargeApplicationFrame", "base")
:SetParent(UIParent)
:SetSettingsContext(private.settings, "frame")
:SetMinResize(MIN_FRAME_SIZE.width, MIN_FRAME_SIZE.height)
:SetStrata("HIGH")
:AddSwitchButton(private.SwitchBtnOnClick)
:SetScript("OnHide", private.BaseFrameOnHide)
for _, info in ipairs(private.topLevelPages) do
frame:AddNavButton(info.name, info.callback)
end
private.frame = frame
return frame
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.BaseFrameOnHide()
TSM.UI.AnalyticsRecordClose("mailing")
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end
function private.SwitchBtnOnClick(button)
private.settings.showDefault = button ~= private.defaultUISwitchBtn
private.fsm:ProcessEvent("EV_SWITCH_BTN_CLICKED")
end
function private.SwitchButtonOnEnter(button)
button:SetTextColor("TEXT")
:Draw()
end
function private.SwitchButtonOnLeave(button)
button:SetTextColor("TEXT_ALT")
:Draw()
end
-- ============================================================================
-- FSM
-- ============================================================================
function private.FSMCreate()
local function MailShowDelayed()
private.fsm:ProcessEvent("EV_MAIL_SHOW")
end
Event.Register("MAIL_SHOW", function()
Delay.AfterFrame("MAIL_SHOW_DELAYED", 0, MailShowDelayed)
end)
Event.Register("MAIL_CLOSED", function()
private.fsm:ProcessEvent("EV_MAIL_CLOSED")
end)
MailFrame:UnregisterEvent("MAIL_SHOW")
CancelEmote()
local fsmContext = {
frame = nil,
}
ScriptWrapper.Set(MailFrame, "OnHide", function()
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end)
private.fsm = FSM.New("MAILING_UI")
:AddState(FSM.NewState("ST_CLOSED")
:AddTransition("ST_DEFAULT_OPEN")
:AddTransition("ST_FRAME_OPEN")
:AddEvent("EV_FRAME_TOGGLE", function(context)
assert(not private.settings.showDefault)
return "ST_FRAME_OPEN"
end)
:AddEvent("EV_MAIL_SHOW", function(context)
if private.settings.showDefault then
return "ST_DEFAULT_OPEN"
else
return "ST_FRAME_OPEN"
end
end)
)
:AddState(FSM.NewState("ST_DEFAULT_OPEN")
:SetOnEnter(function(context, isIgnored)
MailFrame_OnEvent(MailFrame, "MAIL_SHOW")
if not private.defaultUISwitchBtn then
private.defaultUISwitchBtn = UIElements.New("ActionButton", "switchBtn")
:SetSize(60, TSM.IsWowClassic() and 16 or 15)
:SetFont("BODY_BODY3")
:AddAnchor("TOPRIGHT", TSM.IsWowClassic() and -26 or -27, TSM.IsWowClassic() and -3 or -4)
:DisableClickCooldown()
:SetText(L["TSM4"])
:SetScript("OnClick", private.SwitchBtnOnClick)
:SetScript("OnEnter", private.SwitchButtonOnEnter)
:SetScript("OnLeave", private.SwitchButtonOnLeave)
private.defaultUISwitchBtn:_GetBaseFrame():SetParent(MailFrame)
end
if isIgnored then
private.defaultUISwitchBtn:Hide()
else
private.defaultUISwitchBtn:Show()
private.defaultUISwitchBtn:Draw()
end
end)
:AddTransition("ST_CLOSED")
:AddTransition("ST_FRAME_OPEN")
:AddEvent("EV_FRAME_HIDE", function(context)
OpenMailFrame:Hide()
CloseMail()
return "ST_CLOSED"
end)
:AddEventTransition("EV_MAIL_CLOSED", "ST_CLOSED")
:AddEvent("EV_SWITCH_BTN_CLICKED", function()
OpenMailFrame:Hide()
return "ST_FRAME_OPEN"
end)
)
:AddState(FSM.NewState("ST_FRAME_OPEN")
:SetOnEnter(function(context)
OpenAllBags()
CheckInbox()
DoEmote("READ", nil, true)
HideUIPanel(MailFrame)
assert(not context.frame)
context.frame = private.CreateMainFrame()
context.frame:Show()
context.frame:Draw()
private.isVisible = true
end)
:SetOnExit(function(context)
if context.frame then
context.frame:Hide()
context.frame:Release()
context.frame = nil
end
private.isVisible = false
end)
:AddTransition("ST_CLOSED")
:AddTransition("ST_DEFAULT_OPEN")
:AddEvent("EV_FRAME_HIDE", function(context)
CancelEmote()
CloseAllBags()
CloseMail()
return "ST_CLOSED"
end)
:AddEvent("EV_MAIL_SHOW", function(context)
OpenAllBags()
CheckInbox()
if not context.frame then
DoEmote("READ", nil, true)
context.frame = private.CreateMainFrame()
context.frame:Draw()
private.isVisible = true
end
end)
:AddEvent("EV_MAIL_CLOSED", function(context)
CancelEmote()
CloseAllBags()
return "ST_CLOSED"
end)
:AddEvent("EV_SWITCH_BTN_CLICKED", function()
return "ST_DEFAULT_OPEN"
end)
)
:Init("ST_CLOSED", fsmContext)
end

View File

@@ -0,0 +1,266 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Groups = TSM.UI.MailingUI:NewPackage("Groups")
local L = TSM.Include("Locale").GetTable()
local FSM = TSM.Include("Util.FSM")
local Log = TSM.Include("Util.Log")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
filterText = "",
fsm = nil
}
local SECONDS_PER_MINUTE = 60
-- ============================================================================
-- Module Functions
-- ============================================================================
function Groups.OnInitialize()
private.settings = Settings.NewView()
:AddKey("char", "mailingUIContext", "groupTree")
:AddKey("global", "mailingOptions", "resendDelay")
private.FSMCreate()
TSM.UI.MailingUI.RegisterTopLevelPage(L["Groups"], private.GetGroupsFrame)
end
-- ============================================================================
-- Groups UI
-- ============================================================================
function private.GetGroupsFrame()
TSM.UI.AnalyticsRecordPathChange("mailing", "groups")
return UIElements.New("Frame", "groups")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "container")
:SetLayout("VERTICAL")
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "search")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert(true)
:SetHintText(L["Search Groups"])
:SetValue(private.filterText)
:SetScript("OnValueChanged", private.GroupSearchOnValueChanged)
)
:AddChild(UIElements.New("Button", "expandAllBtn")
:SetSize(24, 24)
:SetMargin(8, 4, 0, 0)
:SetBackground("iconPack.18x18/Expand All")
:SetScript("OnClick", private.ExpandAllGroupsOnClick)
:SetTooltip(L["Expand / Collapse All Groups"])
)
:AddChild(UIElements.New("Button", "selectAllBtn")
:SetSize(24, 24)
:SetBackground("iconPack.18x18/Select All")
:SetScript("OnClick", private.SelectAllGroupsOnClick)
:SetTooltip(L["Select / Deselect All Groups"])
)
)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("ApplicationGroupTree", "groupTree")
:SetMargin(0, 0, 0, 1)
:SetSettingsContext(private.settings, "groupTree")
:SetQuery(TSM.Groups.CreateQuery(), "Mailing")
:SetSearchString(private.filterText)
:SetScript("OnGroupSelectionChanged", private.GroupTreeOnGroupSelectionChanged)
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(26)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "groupsText")
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("RIGHT")
:SetText(format(L["%d Groups Selected"], 0))
)
:AddChild(UIElements.New("Texture", "vline")
:SetWidth(1)
:SetMargin(8, 8, 2, 2)
:SetTexture("ACTIVE_BG_ALT")
)
:AddChild(UIElements.New("Text", "itemsText")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("RIGHT")
:SetText(L["Total Items"]..": ".."0")
)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "bottom")
:SetLayout("VERTICAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("ActionButton", "mailGroupBtn")
:SetHeight(24)
:SetText(L["Mail Selected Groups"])
:SetScript("OnClick", private.MailBtnOnClick)
:SetModifierText(L["Mail Selected Groups (Dry Run)"], "CTRL")
:SetModifierText(L["Mail Selected Groups (Auto Resend)"], "SHIFT")
:SetModifierText(L["Mail Selected Groups (Dry Run + Auto Resend)"], "SHIFT", "CTRL")
:SetTooltip(format(L["Hold SHIFT to automatically resend items after '%s', and CTRL to perform a dry-run where no items are actually mailed, but chat messages will still display the result."], SecondsToTime(private.settings.resendDelay * SECONDS_PER_MINUTE)))
)
)
:SetScript("OnUpdate", private.FrameOnUpdate)
:SetScript("OnHide", private.FrameOnHide)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.FrameOnUpdate(frame)
frame:SetScript("OnUpdate", nil)
private.GroupTreeOnGroupSelectionChanged(frame:GetElement("groupTree"))
private.fsm:ProcessEvent("EV_FRAME_SHOW", frame)
end
function private.FrameOnHide(frame)
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end
function private.GroupSearchOnValueChanged(input)
local text = strlower(input:GetValue())
if text == private.filterText then
return
end
private.filterText = text
input:GetElement("__parent.__parent.__parent.groupTree")
:SetSearchString(private.filterText)
:Draw()
end
function private.ExpandAllGroupsOnClick(button)
button:GetElement("__parent.__parent.__parent.groupTree")
:ToggleExpandAll()
end
function private.SelectAllGroupsOnClick(button)
button:GetElement("__parent.__parent.__parent.groupTree")
:ToggleSelectAll()
end
function private.GroupTreeOnGroupSelectionChanged(groupTree)
groupTree:GetElement("__parent.bottom.mailGroupBtn")
:SetDisabled(groupTree:IsSelectionCleared())
:Draw()
local numGroups, numItems = 0, 0
for _, groupPath in groupTree:SelectedGroupsIterator() do
numGroups = numGroups + 1
if groupPath == TSM.CONST.ROOT_GROUP_PATH then
-- TODO
else
for _ in TSM.Groups.ItemIterator(groupPath) do
numItems = numItems + 1
end
end
end
groupTree:GetElement("__parent.footer.groupsText")
:SetText(format(L["%d Groups Selected"], numGroups))
groupTree:GetElement("__parent.footer.itemsText")
:SetText(L["Total Items"]..": "..numItems)
groupTree:GetElement("__parent.footer")
:Draw()
end
function private.MailBtnOnClick(button)
private.fsm:ProcessEvent("EV_BUTTON_CLICKED", IsShiftKeyDown(), IsControlKeyDown())
end
-- ============================================================================
-- FSM
-- ============================================================================
function private.FSMCreate()
local fsmContext = {
frame = nil,
sending = false
}
local function UpdateButton(context)
context.frame:GetElement("bottom.mailGroupBtn")
:SetText(context.sending and L["Sending..."] or L["Mail Selected Groups"])
:SetPressed(context.sending)
:Draw()
end
private.fsm = FSM.New("MAILING_GROUPS")
:AddState(FSM.NewState("ST_HIDDEN")
:SetOnEnter(function(context)
TSM.Mailing.Send.KillThread()
TSM.Mailing.Groups.KillThread()
context.frame = nil
end)
:AddTransition("ST_SHOWN")
:AddTransition("ST_HIDDEN")
:AddEventTransition("EV_FRAME_SHOW", "ST_SHOWN")
)
:AddState(FSM.NewState("ST_SHOWN")
:SetOnEnter(function(context, frame)
if not context.frame then
context.frame = frame
end
UpdateButton(context)
end)
:AddTransition("ST_HIDDEN")
:AddTransition("ST_SENDING_START")
:AddEventTransition("EV_BUTTON_CLICKED", "ST_SENDING_START")
)
:AddState(FSM.NewState("ST_SENDING_START")
:SetOnEnter(function(context, sendRepeat, isDryRun)
context.sending = true
local groups = {}
for _, groupPath in context.frame:GetElement("groupTree"):SelectedGroupsIterator() do
tinsert(groups, groupPath)
end
if isDryRun then
Log.PrintUser(L["Performing a dry-run of your Mailing operations for the selected groups."])
end
TSM.Mailing.Groups.StartSending(private.FSMGroupsCallback, groups, sendRepeat, isDryRun)
UpdateButton(context)
end)
:SetOnExit(function(context)
context.sending = false
end)
:AddTransition("ST_SHOWN")
:AddTransition("ST_HIDDEN")
:AddEventTransition("EV_SENDING_DONE", "ST_SHOWN")
)
:AddDefaultEventTransition("EV_FRAME_HIDE", "ST_HIDDEN")
:Init("ST_HIDDEN", fsmContext)
end
function private.FSMGroupsCallback()
private.fsm:ProcessEvent("EV_SENDING_DONE")
end

1124
Core/UI/MailingUI/Inbox.lua Normal file

File diff suppressed because it is too large Load Diff

362
Core/UI/MailingUI/Other.lua Normal file
View File

@@ -0,0 +1,362 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Groups = TSM.UI.MailingUI:NewPackage("Other")
local L = TSM.Include("Locale").GetTable()
local FSM = TSM.Include("Util.FSM")
local Event = TSM.Include("Util.Event")
local Money = TSM.Include("Util.Money")
local String = TSM.Include("Util.String")
local ItemInfo = TSM.Include("Service.ItemInfo")
local BagTracking = TSM.Include("Service.BagTracking")
local PlayerInfo = TSM.Include("Service.PlayerInfo")
local UIElements = TSM.Include("UI.UIElements")
local private = {
frame = nil,
fsm = nil,
}
local PLAYER_NAME = UnitName("player")
local PLAYER_NAME_REALM = string.gsub(PLAYER_NAME.."-"..GetRealmName(), "%s+", "")
-- ============================================================================
-- Module Functions
-- ============================================================================
function Groups.OnInitialize()
private.FSMCreate()
TSM.UI.MailingUI.RegisterTopLevelPage(OTHER, private.GetOtherFrame)
end
-- ============================================================================
-- Other UI
-- ============================================================================
function private.GetOtherFrame()
TSM.UI.AnalyticsRecordPathChange("mailing", "other")
local frame = UIElements.New("Frame", "other")
:SetLayout("VERTICAL")
:SetPadding(10)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Text", "enchant")
:SetHeight(24)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Mail Disenchantables"])
)
:AddChild(UIElements.New("Text", "enchantDesc")
:SetHeight(20)
:SetMargin(0, 0, 4, 0)
:SetFont("BODY_BODY2")
:SetText(L["Quickly mail all excess disenchantable items to a character"])
)
:AddChild(UIElements.New("Text", "enchantRecipient")
:SetHeight(15)
:SetMargin(0, 0, 12, 0)
:SetFont("BODY_BODY2")
:SetText(L["Recipient"])
)
:AddChild(UIElements.New("Frame", "enchantHeader")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Input", "recipient")
:SetMargin(0, 8, 0, 0)
:SetAutoComplete(PlayerInfo.GetConnectedAlts())
:SetClearButtonEnabled(true)
:SetValue(TSM.db.factionrealm.internalData.mailDisenchantablesChar)
:SetScript("OnValueChanged", private.EchantRecipientOnValueChanged)
)
:AddChild(UIElements.New("ActionButton", "send")
:SetSize(186, 24)
:SetDisabled(true)
:SetText(L["Send Disenchantables"])
:SetScript("OnClick", private.EnchantSendBtnOnClick)
)
)
:AddChild(UIElements.New("Text", "gold")
:SetHeight(24)
:SetMargin(0, 0, 24, 0)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Send Excess Gold to Banker"])
)
:AddChild(UIElements.New("Text", "goldDesc")
:SetHeight(18)
:SetMargin(0, 0, 4, 0)
:SetFont("BODY_BODY2")
:SetText(L["Quickly mail all excess gold (limited to a certain amount) to a character"])
)
:AddChild(UIElements.New("Frame", "goldTextHeader")
:SetLayout("HORIZONTAL")
:SetHeight(13)
:SetMargin(0, 0, 12, 0)
:AddChild(UIElements.New("Text", "recipient")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2")
:SetText(L["Recipient"])
)
:AddChild(UIElements.New("Text", "limit")
:SetWidth(128)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2")
:SetText(L["Limit"])
)
:AddChild(UIElements.New("Spacer", "spacer")
:SetWidth(106)
)
)
:AddChild(UIElements.New("Frame", "goldHeader")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 4, 0)
:AddChild(UIElements.New("Input", "recipient")
:SetMargin(0, 8, 0, 0)
:SetAutoComplete(PlayerInfo.GetConnectedAlts())
:SetClearButtonEnabled(true)
:SetValue(TSM.db.factionrealm.internalData.mailExcessGoldChar)
:SetScript("OnValueChanged", private.GoldRecipientOnValueChanged)
)
:AddChild(UIElements.New("Input", "limit")
:SetSize(128, 24)
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetJustifyH("RIGHT")
:SetValidateFunc(private.LimitValidateFunc)
:SetValue(Money.ToString(TSM.db.factionrealm.internalData.mailExcessGoldLimit, nil, "OPT_TRIM"))
:SetScript("OnValueChanged", private.LimitOnValueChanged)
)
:AddChild(UIElements.New("ActionButton", "send")
:SetSize(106, 24)
:SetDisabled(true)
:SetText(L["Send Gold"])
:SetScript("OnClick", private.GoldSendBtnOnClick)
)
)
:AddChild(UIElements.New("Spacer", "spacer")
)
:SetScript("OnUpdate", private.FrameOnUpdate)
:SetScript("OnHide", private.FrameOnHide)
private.frame = frame
return frame
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.FrameOnUpdate(frame)
frame:SetScript("OnUpdate", nil)
private.UpdateEnchantButton()
private.UpdateGoldButton()
private.fsm:ProcessEvent("EV_FRAME_SHOW", frame)
end
function private.FrameOnHide(frame)
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end
function private.EchantRecipientOnValueChanged(input)
local value = input:GetValue()
if value == TSM.db.factionrealm.internalData.mailDisenchantablesChar then
return
end
TSM.db.factionrealm.internalData.mailDisenchantablesChar = value
private.UpdateEnchantButton()
end
function private.EnchantSendBtnOnClick(button)
local items = {}
local query = BagTracking.CreateQueryBags()
:OrderBy("slotId", true)
:Select("itemString", "quantity")
:Equal("isBoP", false)
:Equal("isBoA", false)
for _, itemString, quantity in query:Iterator() do
if ItemInfo.IsDisenchantable(itemString) and not ItemInfo.IsSoulbound(itemString) then
local quality = ItemInfo.GetQuality(itemString)
if quality <= TSM.db.global.mailingOptions.deMaxQuality then
items[itemString] = (items[itemString] or 0) + quantity
end
end
end
query:Release()
private.fsm:ProcessEvent("EV_BUTTON_CLICKED", TSM.db.factionrealm.internalData.mailDisenchantablesChar, 0, items)
end
function private.GoldRecipientOnValueChanged(input)
local value = input:GetValue()
if value == TSM.db.factionrealm.internalData.mailExcessGoldChar then
return
end
TSM.db.factionrealm.internalData.mailExcessGoldChar = value
private.UpdateGoldButton()
end
function private.GoldSendBtnOnClick(button)
local money = private.GetSendMoney()
private.fsm:ProcessEvent("EV_BUTTON_CLICKED", TSM.db.factionrealm.internalData.mailExcessGoldChar, money)
end
function private.ConvertLimitValue(value)
value = gsub(value, String.Escape(LARGE_NUMBER_SEPERATOR), "")
value = tonumber(value) or Money.FromString(value)
if not value then
return nil
end
return value > 0 and value <= MAXIMUM_BID_PRICE and value or nil
end
function private.LimitValidateFunc(_, value)
return private.ConvertLimitValue(value) and true or false
end
function private.LimitOnValueChanged(input)
local value = private.ConvertLimitValue(input:GetValue())
assert(value)
if value == TSM.db.factionrealm.internalData.mailExcessGoldLimit then
return
end
TSM.db.factionrealm.internalData.mailExcessGoldLimit = value
private.UpdateGoldButton()
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.GetSendMoney()
local money = GetMoney() - 30 - TSM.db.factionrealm.internalData.mailExcessGoldLimit
if money < 0 then
money = 0
end
return money
end
function private.UpdateEnchantButton()
local recipient = TSM.db.factionrealm.internalData.mailDisenchantablesChar
local enchantButton = private.frame:GetElement("enchantHeader.send")
if recipient == "" or recipient == PLAYER_NAME or recipient == PLAYER_NAME_REALM then
enchantButton:SetDisabled(true)
:Draw()
return
else
enchantButton:SetDisabled(false)
:Draw()
end
end
function private.UpdateGoldButton()
local recipient = TSM.db.factionrealm.internalData.mailExcessGoldChar
local goldButton = private.frame:GetElement("goldHeader.send")
if recipient == "" or recipient == PLAYER_NAME or recipient == PLAYER_NAME_REALM then
goldButton:SetDisabled(true)
:Draw()
return
end
if private.GetSendMoney() > 0 then
goldButton:SetDisabled(false)
else
goldButton:SetDisabled(true)
end
goldButton:Draw()
end
-- ============================================================================
-- FSM
-- ============================================================================
function private.FSMCreate()
Event.Register("PLAYER_MONEY", function()
private.fsm:ProcessEvent("EV_PLAYER_MONEY_UPDATE")
end)
local fsmContext = {
frame = nil,
sending = false
}
local function UpdateEnchant(context)
context.frame:GetElement("enchantHeader.send"):SetText(context.sending and L["Sending..."] or L["Send Disenchantables"])
:SetPressed(context.sending)
:Draw()
end
local function UpdateGold(context)
private.UpdateGoldButton()
context.frame:GetElement("goldHeader.send"):SetText(context.sending and L["Sending..."] or L["Send Gold"])
:SetPressed(context.sending)
:Draw()
end
private.fsm = FSM.New("MAILING_GROUPS")
:AddState(FSM.NewState("ST_HIDDEN")
:SetOnEnter(function(context)
context.frame = nil
end)
:AddTransition("ST_SHOWN")
:AddTransition("ST_HIDDEN")
:AddEventTransition("EV_FRAME_SHOW", "ST_SHOWN")
)
:AddState(FSM.NewState("ST_SHOWN")
:SetOnEnter(function(context, frame)
if not context.frame then
context.frame = frame
end
end)
:AddTransition("ST_HIDDEN")
:AddTransition("ST_SENDING_START")
:AddEvent("EV_PLAYER_MONEY_UPDATE", function(context)
UpdateGold(context)
end)
:AddEventTransition("EV_BUTTON_CLICKED", "ST_SENDING_START")
)
:AddState(FSM.NewState("ST_SENDING_START")
:SetOnEnter(function(context, recipient, money, items)
context.sending = true
if money > 0 then
TSM.Mailing.Send.StartSending(private.FSMOthersCallback, recipient, "TSM Mailing: Excess Gold", "", money)
UpdateGold(context)
elseif items then
TSM.Mailing.Send.StartSending(private.FSMOthersCallback, recipient, "TSM Mailing: Disenchantables", "", money, items)
UpdateEnchant(context)
end
end)
:SetOnExit(function(context)
context.sending = false
UpdateEnchant(context)
UpdateGold(context)
end)
:AddTransition("ST_SHOWN")
:AddTransition("ST_HIDDEN")
:AddEventTransition("EV_SENDING_DONE", "ST_SHOWN")
)
:AddDefaultEventTransition("EV_FRAME_HIDE", "ST_HIDDEN")
:Init("ST_HIDDEN", fsmContext)
end
function private.FSMOthersCallback()
private.fsm:ProcessEvent("EV_SENDING_DONE")
end

839
Core/UI/MailingUI/Send.lua Normal file
View File

@@ -0,0 +1,839 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Send = TSM.UI.MailingUI:NewPackage("Send")
local L = TSM.Include("Locale").GetTable()
local Delay = TSM.Include("Util.Delay")
local Money = TSM.Include("Util.Money")
local FSM = TSM.Include("Util.FSM")
local Database = TSM.Include("Util.Database")
local String = TSM.Include("Util.String")
local Event = TSM.Include("Util.Event")
local ItemString = TSM.Include("Util.ItemString")
local Theme = TSM.Include("Util.Theme")
local ItemInfo = TSM.Include("Service.ItemInfo")
local InventoryInfo = TSM.Include("Service.InventoryInfo")
local BagTracking = TSM.Include("Service.BagTracking")
local PlayerInfo = TSM.Include("Service.PlayerInfo")
local UIElements = TSM.Include("UI.UIElements")
local private = {
fsm = nil,
frame = nil,
db = nil,
query = nil,
recipient = "",
subject = "",
body = "",
money = 0,
isMoney = true,
isCOD = false,
}
local PLAYER_NAME = UnitName("player")
local PLAYER_NAME_REALM = gsub(PLAYER_NAME.."-"..GetRealmName(), "%s+", "")
local MAX_COD_AMOUNT = 10000 * COPPER_PER_GOLD
-- ============================================================================
-- Module Functions
-- ============================================================================
function Send.OnInitialize()
private.FSMCreate()
TSM.UI.MailingUI.RegisterTopLevelPage(L["Send"], private.GetSendFrame)
private.db = Database.NewSchema("MAILTRACKING_SEND_INFO")
:AddStringField("itemString")
:AddNumberField("quantity")
:Commit()
private.query = private.db:NewQuery()
end
function Send.SetSendRecipient(recipient)
private.recipient = recipient
end
-- ============================================================================
-- Send UI
-- ============================================================================
function private.GetSendFrame()
TSM.UI.AnalyticsRecordPathChange("mailing", "send")
local frame = UIElements.New("Frame", "send")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "container")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Text", "recipient")
:SetMargin(8, 8, 8, 8)
:SetHeight(24)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Recipient"])
)
:AddChild(UIElements.New("Frame", "name")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 8)
:AddChild(UIElements.New("Input", "input")
:SetHintText(L["Enter recipient name"])
:SetAutoComplete(PlayerInfo.GetConnectedAlts())
:SetClearButtonEnabled(true)
:SetValue(private.recipient)
:SetScript("OnValueChanged", private.RecipientOnValueChanged)
)
:AddChild(UIElements.New("ActionButton", "contacts")
:SetWidth(152)
:SetMargin(8, 0, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Contacts"])
:SetScript("OnClick", private.ContactsBtnOnClick)
)
)
:AddChild(UIElements.New("Frame", "subject")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 16)
:AddChild(UIElements.New("Button", "icon")
:SetMargin(4, 4, 0, 0)
:SetBackgroundAndSize("iconPack.12x12/Add/Circle")
:SetScript("OnClick", private.SubjectBtnOnClick)
)
:AddChild(UIElements.New("Button", "text")
:SetWidth("AUTO")
:SetText(L["Add subject & description (optional)"])
:SetFont("BODY_BODY2")
:SetScript("OnClick", private.SubjectBtnOnClick)
)
:AddChild(UIElements.New("Button", "button")
:SetWidth("AUTO")
:SetMargin(8, 0, 0, 0)
:SetFont("BODY_BODY2")
:SetTextColor("INDICATOR")
:SetText(L["Edit"])
:SetScript("OnClick", private.SubjectBtnOnClick)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 4)
:AddChild(UIElements.New("Text", "items")
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Select Items to Attach"])
)
)
:AddChild(UIElements.New("Frame", "dragBox")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:RegisterForDrag("LeftButton")
:SetScript("OnReceiveDrag", private.DragBoxOnItemRecieve)
:SetScript("OnMouseUp", private.DragBoxOnItemRecieve)
:AddChild(UIElements.New("QueryScrollingTable", "items")
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Items"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetIconSize(12)
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetIconInfo("itemString", ItemInfo.GetTexture)
:SetTooltipInfo("itemString")
:SetTooltipLinkingDisabled(true)
:DisableHiding()
:Commit()
:NewColumn("quantity")
:SetTitle(L["Amount"])
:SetWidth(60)
:SetFont("TABLE_TABLE1")
:SetJustifyH("LEFT")
:SetTextInfo("quantity")
:DisableHiding()
:Commit()
:Commit()
:SetQuery(private.query)
:SetScript("OnRowClick", private.QueryOnRowClick)
:SetScript("OnDataUpdated", private.SendOnDataUpdated)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(26)
:SetPadding(8, 8, 3, 3)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "items")
:SetWidth(144)
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("RIGHT")
:Hide()
)
:AddChild(UIElements.New("Texture", "vline")
:SetWidth(1)
:SetMargin(8, 8, 3, 3)
:SetTexture("ACTIVE_BG_ALT")
:Hide()
)
:AddChild(UIElements.New("Text", "postage")
:SetWidth(150)
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("RIGHT")
:SetText(L["Total Postage"]..": "..Money.ToString(30))
)
)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "check")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(8, 0, 8, 6)
:AddChild(UIElements.New("Checkbox", "sendCheck")
:SetWidth("AUTO")
:SetMargin(0, 0, 1, 0)
:SetFont("BODY_BODY2")
:SetCheckboxPosition("LEFT")
:SetChecked(private.isMoney)
:SetText(L["Send Money"])
:SetScript("OnValueChanged", private.SendOnValueChanged)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "checkbox")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 8)
:AddChild(UIElements.New("Checkbox", "cod")
:SetSize("AUTO", 20)
:SetFont("BODY_BODY2")
:SetCheckboxPosition("LEFT")
:SetChecked(private.isCOD)
:SetText(L["Make Cash On Delivery?"])
:SetDisabled(true)
:SetScript("OnValueChanged", private.CODOnValueChanged)
)
:AddChild(UIElements.New("Text", "amountText")
:SetHeight(20)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("RIGHT")
:SetText(L["Amount"]..":")
)
:AddChild(UIElements.New("Input", "moneyInput")
:SetWidth(160)
:SetBackgroundColor("ACTIVE_BG")
:SetFont("BODY_BODY2_MEDIUM")
:SetValidateFunc(private.MoneyValidateFunc)
:SetJustifyH("RIGHT")
:SetValue(Money.ToString(private.money))
:SetScript("OnValueChanged", private.MoneyOnValueChanged)
)
)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("ActionButton", "sendMail")
:SetHeight(24)
:SetText(L["Send Mail"])
:SetScript("OnClick", private.SendMail)
:SetDisabled(private.recipient == "")
)
:AddChild(UIElements.New("Button", "clear")
:SetWidth("AUTO")
:SetHeight(24)
:SetMargin(16, 10, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetJustifyH("LEFT")
:SetText(L["Clear All"])
:SetScript("OnClick", private.ClearOnClick)
)
)
:SetScript("OnUpdate", private.SendFrameOnUpdate)
:SetScript("OnHide", private.SendFrameOnHide)
private.frame = frame
return frame
end
function private.SubjectBtnOnClick(button)
button:GetBaseElement():ShowDialogFrame(UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(478, 314)
:SetPadding(12)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG", true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, -4, 14)
:AddChild(UIElements.New("Spacer", "spacer")
:SetWidth(20)
)
:AddChild(UIElements.New("Text", "title")
:SetFont("BODY_BODY1_BOLD")
:SetJustifyH("CENTER")
:SetText(L["Add Subject / Description"])
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetMargin(0, -4, 0, 0)
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.CloseDialog)
)
)
:AddChild(UIElements.New("Text", "subjectText")
:SetMargin(0, 0, 0, 4)
:SetHeight(20)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Subject"])
)
:AddChild(UIElements.New("Input", "subjectInput")
:SetHeight(24)
:SetMargin(0, 0, 0, 8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetMaxLetters(64)
:SetClearButtonEnabled(true)
:SetValue(private.subject)
:SetTabPaths("__parent.descriptionInput", "__parent.descriptionInput")
:SetScript("OnValueChanged", private.SubjectOnValueChanged)
)
:AddChild(UIElements.New("Text", "descriptionText")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(DESCRIPTION)
)
:AddChild(UIElements.New("MultiLineInput", "descriptionInput")
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetIgnoreEnter()
:SetMaxLetters(500)
:SetValue(private.body)
:SetTabPaths("__parent.subjectInput", "__parent.subjectInput")
:SetScript("OnValueChanged", private.DesciptionOnValueChanged)
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetMargin(0, 0, 4, 12)
:AddChild(UIElements.New("Text", "title")
:SetHeight(20)
:SetMargin(0, 4, 0, 0)
:SetFont("BODY_BODY3")
:SetJustifyH("RIGHT")
:SetText(format(L["(%d/500 Characters)"], #private.body))
)
:AddChild(UIElements.New("Button", "clearAll")
:SetSize("AUTO", 20)
:SetFont("BODY_BODY3_MEDIUM")
:SetJustifyH("LEFT")
:SetText(L["Clear All"])
:SetDisabled(private.subject == "" and private.body == "")
:SetScript("OnClick", private.SubjectClearAllBtnOnClick)
)
)
:AddChild(UIElements.New("ActionButton", "addMailBtn")
:SetHeight(24)
:SetText(L["Add to Mail"])
:SetScript("OnClick", private.CloseDialog)
:SetDisabled(private.subject == "" and private.body == "")
)
:SetScript("OnHide", private.DialogOnHide)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.SendFrameOnUpdate(frame)
frame:SetScript("OnUpdate", nil)
private.fsm:ProcessEvent("EV_FRAME_SHOW", frame)
end
function private.SendFrameOnHide(frame)
assert(frame == private.frame)
private.frame = nil
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end
function private.ClearOnClick(button)
private.fsm:ProcessEvent("EV_MAIL_CLEAR", true)
end
function private.CloseDialog(button)
button:GetBaseElement():HideDialog()
private.fsm:ProcessEvent("EV_DIALOG_HIDDEN")
end
function private.DialogOnHide(button)
private.fsm:ProcessEvent("EV_DIALOG_HIDDEN")
end
function private.ContactsBtnOnClick(button)
TSM.UI.Util.Contacts.ShowDialog(button, button:GetElement("__parent.input"), private.RecipientOnValueChanged)
end
function private.DragBoxOnItemRecieve(frame, button)
if not CursorHasItem() then
ClearCursor()
return
end
if private.query:Count() >= 12 then
ClearCursor()
UIErrorsFrame:AddMessage(ERR_MAIL_INVALID_ATTACHMENT_SLOT, 1.0, 0.1, 0.1, 1.0)
return
end
local _, _, subType = GetCursorInfo()
local itemString = ItemString.Get(subType)
local stackSize = nil
local query = BagTracking.CreateQueryBags()
:OrderBy("slotId", true)
:Select("bag", "slot", "quantity")
:Equal("isBoP", false)
:Equal("itemString", itemString)
for _, bag, slot, quantity in query:Iterator() do
if InventoryInfo.IsBagSlotLocked(bag, slot) then
stackSize = quantity
end
end
query:Release()
ClearCursor()
if not stackSize then
return
end
private.DatabaseNewRow(itemString, stackSize)
end
function private.QueryOnRowClick(scrollingTable, row, button)
if button == "RightButton" then
private.db:DeleteRow(row)
end
end
function private.SendOnDataUpdated()
private.fsm:ProcessEvent("EV_MAIL_DATA_UPDATED")
end
function private.SubjectClearAllBtnOnClick(button)
private.subject = ""
private.body = ""
button:GetElement("__parent.__parent.subjectInput")
:SetFocused(false)
:SetValue(private.subject)
:Draw()
button:GetElement("__parent.__parent.descriptionInput")
:SetFocused(false)
:SetValue(private.body)
:Draw()
button:GetElement("__parent.title")
:SetText(format(L["(%d/500 Characters)"], 0))
:Draw()
button:SetDisabled(true)
:Draw()
button:GetElement("__parent.__parent.addMailBtn")
:SetDisabled(true)
:Draw()
end
function private.RecipientOnValueChanged(input)
local value = input:GetValue()
if value == private.recipient then
return
end
private.recipient = value
private.UpdateSendFrame()
end
function private.SubjectOnValueChanged(input)
local value = input:GetValue()
if value == private.subject then
return
end
private.subject = value
input:GetElement("__parent.footer.clearAll")
:SetDisabled(private.subject == "" and private.body == "")
:Draw()
input:GetElement("__parent.addMailBtn")
:SetDisabled(private.subject == "" and private.body == "")
:Draw()
end
function private.DesciptionOnValueChanged(input)
local text = input:GetValue()
if text == private.body then
return
end
private.body = text
input:GetElement("__parent.footer.title")
:SetText(format(L["(%d/500 Characters)"], #private.body))
:Draw()
input:GetElement("__parent.footer.clearAll")
:SetDisabled(private.subject == "" and private.body == "")
:Draw()
input:GetElement("__parent.addMailBtn")
:SetDisabled(private.subject == "" and private.body == "")
:Draw()
end
function private.SendOnValueChanged(checkbox)
if checkbox:IsChecked() then
checkbox:GetElement("__parent.__parent.checkbox.cod"):SetChecked(false)
:Draw()
private.isMoney = true
private.isCOD = false
else
private.isMoney = false
end
end
function private.CODOnValueChanged(checkbox)
if checkbox:IsChecked() then
checkbox:GetElement("__parent.__parent.check.sendCheck"):SetChecked(false)
:Draw()
local input = checkbox:GetElement("__parent.moneyInput")
local value = private.ConvertMoneyValue(input:GetValue())
private.money = private.isCOD and min(value, MAX_COD_AMOUNT) or value
input:SetValue(Money.ToString(private.money))
:Draw()
private.isMoney = false
private.isCOD = true
else
private.isCOD = false
end
end
function private.ConvertMoneyValue(value)
value = gsub(value, String.Escape(LARGE_NUMBER_SEPERATOR), "")
value = tonumber(value) or Money.FromString(value)
if not value then
return nil
end
local maxVal = private.isCOD and MAX_COD_AMOUNT or MAXIMUM_BID_PRICE
return value >= 0 and value <= maxVal and value or nil
end
function private.MoneyValidateFunc(_, value)
return private.ConvertMoneyValue(value) and true or false
end
function private.MoneyOnValueChanged(input)
local value = private.ConvertMoneyValue(input:GetValue())
assert(value)
if value == private.money then
return
end
private.money = value
input:SetValue(Money.ToString(value))
:Draw()
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.SendMail(button)
local money = 0
if private.money > 0 and private.isMoney then
money = private.money
elseif private.money > 0 and private.isCOD then
money = private.money * -1
end
button:GetElement("__parent.__parent.container.name.input"):SetFocused(false)
private.UpdateRecentlyMailed(private.recipient)
if private.query:Count() > 0 then
local items = {}
for _, row in private.query:Iterator() do
local itemString = row:GetField("itemString")
local quantity = row:GetField("quantity")
if items[itemString] then
items[itemString] = items[itemString] + quantity
else
items[itemString] = quantity
end
end
private.fsm:ProcessEvent("EV_BUTTON_CLICKED", IsShiftKeyDown(), private.recipient, private.subject, private.body, money, items)
else
private.fsm:ProcessEvent("EV_BUTTON_CLICKED", IsShiftKeyDown(), private.recipient, private.subject, private.body, money)
end
end
function private.UpdateRecentlyMailed(recipient)
if recipient == UnitName("player") or recipient == PLAYER_NAME_REALM then
return
end
local size = 0
local oldestName = nil
local oldestTime = nil
for k, v in pairs(TSM.db.global.mailingOptions.recentlyMailedList) do
size = size + 1
if not oldestName or not oldestTime or oldestTime > v then
oldestName = k
oldestTime = v
end
end
if size >= 20 then
TSM.db.global.mailingOptions.recentlyMailedList[oldestName] = nil
end
TSM.db.global.mailingOptions.recentlyMailedList[recipient] = time()
end
function private.UpdateSendFrame()
if not private.frame then
return
end
local sendMail = private.frame:GetElement("footer.sendMail")
if private.recipient ~= "" then
sendMail:SetDisabled(false)
else
sendMail:SetDisabled(true)
end
sendMail:Draw()
end
function private.DatabaseNewRow(itemString, stackSize)
private.db:NewRow()
:SetField("itemString", itemString)
:SetField("quantity", stackSize)
:Create()
end
-- ============================================================================
-- FSM
-- ============================================================================
function private.FSMCreate()
Event.Register("MAIL_CLOSED", function()
private.fsm:ProcessEvent("EV_MAIL_CLEAR")
end)
Event.Register("MAIL_SEND_INFO_UPDATE", function()
private.fsm:ProcessEvent("EV_MAIL_INFO_UPDATE")
end)
Event.Register("MAIL_FAILED", function()
private.fsm:ProcessEvent("EV_SENDING_DONE")
end)
local fsmContext = {
frame = nil,
sending = false,
keepInfo = false
}
local function UpdateFrame(context)
if not context.frame then
return
end
local subject = context.frame:GetElement("container.subject")
if private.subject == "" and private.body == "" then
subject:GetElement("icon")
:SetBackgroundAndSize("iconPack.12x12/Add/Circle")
:Draw()
subject:GetElement("text")
:SetText(L["Add subject & description (optional)"])
:Draw()
subject:GetElement("button")
:Hide()
else
subject:GetElement("icon")
:SetBackgroundAndSize("iconPack.12x12/Checkmark/Default")
:Draw()
subject:GetElement("text")
:SetText(L["Subject & Description added"])
:Draw()
subject:GetElement("button")
:Show()
end
subject:Draw()
local items = context.frame:GetElement("container.dragBox.footer.items")
local line = context.frame:GetElement("container.dragBox.footer.vline")
local postage = context.frame:GetElement("container.dragBox.footer.postage")
local send = context.frame:GetElement("container.check.sendCheck")
local cod = context.frame:GetElement("container.checkbox.cod")
local size = private.query:Count()
if size > 0 then
postage:SetText(L["Total Postage"]..": "..Money.ToString(30 * size))
:Draw()
items:SetText(format(L["%s Items Selected"], Theme.GetFeedbackColor("GREEN"):ColorText(size.."/"..ATTACHMENTS_MAX_SEND)))
:Show()
:Draw()
line:Show()
cod:SetDisabled(false)
:Draw()
else
postage:SetText(L["Total Postage"]..": "..Money.ToString(30))
:Draw()
items:Hide()
line:Hide()
cod:SetDisabled(true)
:Draw()
send:SetChecked(true)
:SetDisabled(false)
:Draw()
end
end
local function UpdateButton(context)
context.frame:GetElement("footer.sendMail")
:SetText(context.sending and L["Sending..."] or L["Send Mail"])
:SetPressed(context.sending)
:Draw()
end
local function UpdateSendMailInfo(context)
if private.query:Count() >= 12 then
UIErrorsFrame:AddMessage(ERR_MAIL_INVALID_ATTACHMENT_SLOT, 1.0, 0.1, 0.1, 1.0)
else
for i = 1, ATTACHMENTS_MAX_SEND do
local itemName, _, _, stackCount = GetSendMailItem(i)
if itemName and stackCount then
local itemLink = GetSendMailItemLink(i)
local itemString = ItemString.Get(itemLink)
private.DatabaseNewRow(itemString, stackCount)
break
end
end
end
ClearSendMail()
end
local function ClearMail(context, keepInfo, redraw)
if not keepInfo then
private.recipient = ""
end
private.subject = ""
private.body = ""
private.money = 0
private.isMoney = true
private.isCOD = false
private.db:Truncate()
if redraw and context.frame then
context.frame:GetElement("container.name.input")
:SetValue(private.recipient)
:Draw()
context.frame:GetElement("container.checkbox.moneyInput")
:SetValue(Money.ToString(private.money))
:Draw()
if not keepInfo then
context.frame:GetElement("footer.sendMail")
:SetDisabled(true)
:Draw()
end
end
UpdateFrame(context)
end
local function SendMailShowing()
SetSendMailShowing(true)
end
private.fsm = FSM.New("MAILING_SEND")
:AddState(FSM.NewState("ST_HIDDEN")
:SetOnEnter(function(context)
TSM.Mailing.Send.KillThread()
SetSendMailShowing(false)
context.frame = nil
end)
:AddTransition("ST_SHOWN")
:AddTransition("ST_HIDDEN")
:AddEventTransition("EV_FRAME_SHOW", "ST_SHOWN")
)
:AddState(FSM.NewState("ST_SHOWN")
:SetOnEnter(function(context, frame)
if not context.frame then
context.frame = frame
UpdateFrame(context)
Delay.AfterFrame("setMailShowing", 2, SendMailShowing)
end
UpdateButton(context)
end)
:AddTransition("ST_HIDDEN")
:AddTransition("ST_SENDING_START")
:AddEvent("EV_DIALOG_HIDDEN", function(context)
UpdateFrame(context)
end)
:AddEvent("EV_MAIL_INFO_UPDATE", function(context)
UpdateSendMailInfo(context)
UpdateFrame(context)
end)
:AddEvent("EV_MAIL_DATA_UPDATED", function(context)
UpdateFrame(context)
end)
:AddEvent("EV_MAIL_CLEAR", function(context, redraw)
ClearMail(context, IsShiftKeyDown(), redraw)
end)
:AddEventTransition("EV_BUTTON_CLICKED", "ST_SENDING_START")
)
:AddState(FSM.NewState("ST_SENDING_START")
:SetOnEnter(function(context, keepInfo, recipient, subject, body, money, items)
context.sending = true
context.keepInfo = keepInfo
private.db:SetQueryUpdatesPaused(true)
TSM.Mailing.Send.StartSending(private.FSMSendCallback, recipient, subject, body, money, items)
UpdateButton(context)
end)
:SetOnExit(function(context)
context.sending = false
private.db:SetQueryUpdatesPaused(false)
ClearMail(context, context.keepInfo, true)
UpdateFrame(context)
end)
:AddTransition("ST_SHOWN")
:AddTransition("ST_HIDDEN")
:AddEventTransition("EV_SENDING_DONE", "ST_SHOWN")
)
:AddDefaultEvent("EV_FRAME_HIDE", function(context)
context.frame = nil
return "ST_HIDDEN"
end)
:Init("ST_HIDDEN", fsmContext)
end
function private.FSMSendCallback()
private.fsm:ProcessEvent("EV_SENDING_DONE")
end