enUS Localization Update Announcement / localization-update-announcement (push) Canceled after 0s
266 lines
9.4 KiB
Lua
266 lines
9.4 KiB
Lua
-- Bagshui Character Data Management UI
|
|
-- Exposes: BsCharacterData (and Bagshui.components.CharacterData)
|
|
-- Raises: BAGSHUI_CHARACTERDATA_UPDATE
|
|
-- Consumes: BAGSHUI_CHARACTERDATA_UPDATE
|
|
|
|
Bagshui:AddComponent(function()
|
|
-- CharacterData class is built on the ObjectList prototype, even though it
|
|
-- only exists to provide a UI for deleting old alts.
|
|
local CharacterData = Bagshui.prototypes.ObjectList:New({
|
|
|
|
dataStorageKey = "characters",
|
|
objectName = "CharacterData",
|
|
objectNamePlural = "CharacterData",
|
|
wikiPage = BS_WIKI_PAGES.CharacterData,
|
|
|
|
-- Disable all table content filters.
|
|
objectSkeleton = BS_OBJECT_LIST_TEMPLATE_TABLE_WILDCARD,
|
|
objectTemplate = BS_OBJECT_LIST_TEMPLATE_TABLE_WILDCARD,
|
|
|
|
managerMultiSelect = false,
|
|
|
|
disableObjectCreation = true,
|
|
disableObjectEditing = true,
|
|
disableObjectSharing = true,
|
|
|
|
disableObjectDeletionFunc = function(characterId)
|
|
-- Loop for scrollable list entries.
|
|
if type(characterId) == "table" then
|
|
for charId, _ in pairs(characterId) do
|
|
if charId == Bagshui.currentCharacterId or Bagshui.sharedCharacters[charId] then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
-- Single object ID.
|
|
-- Characters from other accounts have to be deleted from the account they belong to.
|
|
return characterId == Bagshui.currentCharacterId or Bagshui.sharedCharacters[characterId] ~= nil
|
|
end,
|
|
|
|
-- This metatable will be assigned to each character in SavedVariables BagshuiData.characters.
|
|
-- It's basically a hack that quickly makes the character data structures compatible
|
|
-- with ObjectList's expectations, since ObjectList wasn't originally designed
|
|
-- to handle an object that stores its primary data in a sub-table. (Adding this metatable
|
|
-- is safe because there is no arbitrary access to keys in the character table.)
|
|
objectMetatable = {
|
|
__index = function(tbl, key)
|
|
if rawget(tbl, key) then
|
|
return rawget(tbl, key)
|
|
end
|
|
if rawget(tbl, "info") then
|
|
return rawget(tbl, "info")[key]
|
|
end
|
|
return rawget(tbl, key)
|
|
end,
|
|
},
|
|
|
|
---@type string[]
|
|
-- List of cached characters that will be used for the Character menu.
|
|
-- Managed by `CharacterData:Update()`.
|
|
characterIdList = {},
|
|
|
|
---@type string[]
|
|
-- Same as `characterIdList`, but formatted names.
|
|
characterNameList = {},
|
|
})
|
|
|
|
Bagshui.environment.BsCharacterData = CharacterData
|
|
Bagshui.components.CharacterData = CharacterData
|
|
|
|
--- Initialize the CharacterData class.
|
|
function CharacterData:Init()
|
|
-- Add sorting functions.
|
|
self.sortedIdLists.realm = {}
|
|
self.idListSortFunctions.realm = function(idA, idB)
|
|
return (self._idListSortFunctions_objectList[idA].realm or "")
|
|
< (self._idListSortFunctions_objectList[idB].realm or "")
|
|
end
|
|
self.sortedIdLists.lastLogout = {}
|
|
self.idListSortFunctions.lastLogout = function(idA, idB)
|
|
return (self._idListSortFunctions_objectList[idA].lastLogout or 0)
|
|
< (self._idListSortFunctions_objectList[idB].lastLogout or 0)
|
|
end
|
|
|
|
-- Calls ObjectList:Init().
|
|
self._super.Init(self)
|
|
|
|
-- ObjectList points `self.list` at the saved characters table (`Bagshui.characters`).
|
|
-- Replace it with a merged view that also contains characters shared by other accounts,
|
|
-- which are not saved. See `CharacterData:RefreshList()` and `CharacterData:Delete()`.
|
|
self.list = {}
|
|
self:RefreshList()
|
|
|
|
-- Generate the Character auto-split menu's initial list.
|
|
CharacterData:Update()
|
|
|
|
-- Add auto-split menu that lists all characters.
|
|
Bagshui.prototypes.Menus:AddAutoSplitMenu(BS_AUTO_SPLIT_MENU_TYPE.CHARACTERS, {
|
|
defaultIdList = self.characterIdList,
|
|
nameFunc = function(id)
|
|
return BsCharacter:FormatCharacterName(id, true) or id
|
|
end,
|
|
-- Manage...
|
|
extraItems = {
|
|
{
|
|
text = string.format(L.Symbol_Ellipsis, L.Manage),
|
|
tooltipTitle = L.Manage,
|
|
tooltipText = string.format(L.Prefix_Manage, L.CharacterData),
|
|
checked = false,
|
|
value = {
|
|
func = function()
|
|
Bagshui:CloseMenus()
|
|
self:Open()
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
end
|
|
|
|
--- Event handling.
|
|
---@param event string Event name.
|
|
---@param arg1 any Event argument.
|
|
function CharacterData:OnEvent(event, arg1)
|
|
-- Check to see if the ObjectList prototype is handling this event
|
|
if self._super.OnEvent(self, event, arg1) then
|
|
return
|
|
end
|
|
|
|
-- Refresh the Character auto-split menu.
|
|
if event == "BAGSHUI_CHARACTERDATA_UPDATE" then
|
|
self:Update()
|
|
return
|
|
end
|
|
end
|
|
|
|
--- Subclass override for InitUI() to handle class-specific details.
|
|
function CharacterData:InitUi()
|
|
-- Calls ObjectList:InitUi().
|
|
self._super.InitUi(
|
|
self,
|
|
nil, -- No custom Object Manager needed.
|
|
nil, -- No custom Object Editor needed.
|
|
-- Not much to configure since there's no editing.
|
|
{
|
|
managerHeight = 400,
|
|
managerWidth = 450,
|
|
managerColumns = {
|
|
{
|
|
field = "name",
|
|
title = L.ObjectManager_Column_Name,
|
|
widthPercent = "45",
|
|
currentSortOrder = "ASC",
|
|
lastSortOrder = "ASC",
|
|
},
|
|
{
|
|
field = "realm",
|
|
title = L.ObjectManager_Column_Realm,
|
|
widthPercent = "25",
|
|
lastSortOrder = "ASC",
|
|
},
|
|
{
|
|
field = "lastLogout",
|
|
title = L.ObjectManager_Column_LastInventoryUpdate,
|
|
widthPercent = "25",
|
|
lastSortOrder = "ASC",
|
|
},
|
|
},
|
|
|
|
-- Show correctly formatted data.
|
|
managerColumnTextFunc = function(fieldName, id, obj, preliminaryDisplayValue)
|
|
if fieldName == "name" then
|
|
local formattedName = BsCharacter:FormatCharacterName(id) or preliminaryDisplayValue
|
|
if Bagshui.sharedCharacters[id] and type(formattedName) == "string" then
|
|
formattedName = formattedName .. " " .. GRAY_FONT_COLOR_CODE .. "(other account)" .. FONT_COLOR_CODE_CLOSE
|
|
end
|
|
return formattedName
|
|
elseif fieldName == "lastLogout" then
|
|
return _G.date(
|
|
"%Y-%b-%d",
|
|
type(preliminaryDisplayValue) == "number" and preliminaryDisplayValue or _G.time()
|
|
)
|
|
end
|
|
return preliminaryDisplayValue
|
|
end,
|
|
|
|
deletePrompt = L.ObjectManager_DeleteForPrompt,
|
|
deletePromptExtraInfo = L.CharacterDataManager_DeleteInfo,
|
|
}
|
|
)
|
|
end
|
|
|
|
--- Rebuild the list shown in the manager: this account's saved characters plus
|
|
--- characters shared by other accounts (which are never saved here).
|
|
function CharacterData:RefreshList()
|
|
BsUtil.TableClear(self.list)
|
|
for id, character in pairs(Bagshui.characters) do
|
|
self.list[id] = character
|
|
end
|
|
for id, character in pairs(Bagshui.sharedCharacters) do
|
|
if not self.list[id] then
|
|
self.list[id] = character
|
|
end
|
|
end
|
|
self:UpdateTrackingLists()
|
|
end
|
|
|
|
--- Delete a character from this account's saved data. (Subclass override.)
|
|
--- Because `self.list` is a merged view, the base implementation can't be used.
|
|
--- The character's shared file is also cleared so other accounts stop seeing it.
|
|
---@param characterId string
|
|
---@return boolean success
|
|
function CharacterData:Delete(characterId)
|
|
if
|
|
characterId == Bagshui.currentCharacterId
|
|
or Bagshui.sharedCharacters[characterId]
|
|
or not Bagshui.characters[characterId]
|
|
then
|
|
Bagshui:PrintWarning(string.format(L.ObjectList_ActionNotAllowed, L.Deletion, L.CharacterData))
|
|
return false
|
|
end
|
|
|
|
Bagshui.characters[characterId] = nil
|
|
if BsCatalog and BsCatalog.ForgetSharedCharacter then
|
|
BsCatalog:ForgetSharedCharacter(characterId)
|
|
end
|
|
self:RefreshList()
|
|
Bagshui:RaiseEvent(self.objectChangeEvent, false, characterId)
|
|
return true
|
|
end
|
|
|
|
-- Keep the Character auto-split menu current when old alts are deleted.
|
|
function CharacterData:Update()
|
|
BsUtil.TableClear(self.characterIdList)
|
|
|
|
-- Sort the list of characters alphabetically but sort by realm first.
|
|
for character, _ in pairs(Bagshui.characters) do
|
|
if character ~= Bagshui.currentCharacterId then
|
|
table.insert(self.characterIdList, character)
|
|
end
|
|
end
|
|
-- Characters shared by other accounts can be viewed too.
|
|
for character, _ in pairs(Bagshui.sharedCharacters) do
|
|
table.insert(self.characterIdList, character)
|
|
end
|
|
local function sortKey(characterId)
|
|
local characterData = Bagshui.characters[characterId] or Bagshui.sharedCharacters[characterId]
|
|
return tostring(characterData.info.realm or "") .. " " .. tostring(characterData.info.name or "")
|
|
end
|
|
table.sort(self.characterIdList, function(a, b)
|
|
return sortKey(a) < sortKey(b)
|
|
end)
|
|
-- Place the current character at the top.
|
|
table.insert(self.characterIdList, 1, Bagshui.currentCharacterId)
|
|
|
|
-- Refresh formatted name list.
|
|
BsUtil.TableClear(self.characterNameList)
|
|
for _, id in ipairs(self.characterIdList) do
|
|
table.insert(self.characterNameList, BsCharacter:FormatCharacterName(id, true) or id)
|
|
end
|
|
end
|
|
|
|
-- Class event registration.
|
|
-- This is done at the end because RegisterEvent expects the class to have an OnEvent function.
|
|
Bagshui:RegisterEvent("BAGSHUI_CHARACTERDATA_UPDATE", CharacterData)
|
|
end)
|