ContentDB GUI: Load package list asynchronously (#13551)

This commit is contained in:
Gregor Parzefall 2023-08-13 14:28:24 +02:00 committed by GitHub
parent e4bedc7ea8
commit 526c5f2348
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -23,9 +23,18 @@ if not core.get_http_api then
return
end
local store = {
loading = false,
load_ok = false,
load_error = false,
-- Unordered preserves the original order of the ContentDB API,
-- before the package list is ordered based on installed state.
local store = { packages = {}, packages_full = {}, packages_full_unordered = {}, aliases = {} }
packages = {},
packages_full = {},
packages_full_unordered = {},
aliases = {},
}
local http = core.get_http_api()
@ -65,7 +74,7 @@ local REASON_DEPENDENCY = "dependency"
-- encodes for use as URL parameter or path component
local function urlencode(str)
return str:gsub("[^%a%d()._~-]", function(char)
return string.format("%%%02X", string.byte(char))
return ("%%%02X"):format(char:byte())
end)
end
assert(urlencode("sample text?") == "sample%20text%3F")
@ -432,7 +441,7 @@ function install_dialog.get_formspec()
"container_end[]",
}
return table.concat(formspec, "")
return table.concat(formspec)
end
function install_dialog.handle_submit(this, fields)
@ -577,29 +586,33 @@ local function get_screenshot(package)
return defaulttexturedir .. "loading_screenshot.png"
end
function store.load()
local function fetch_pkgs(param)
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local url = base_url ..
"/api/packages/?type=mod&type=game&type=txp&protocol_version=" ..
core.get_max_supp_proto() .. "&engine_version=" .. urlencode(version.string)
core.get_max_supp_proto() .. "&engine_version=" .. param.urlencode(version.string)
for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do
item = item:trim()
if item ~= "" then
url = url .. "&hide=" .. urlencode(item)
url = url .. "&hide=" .. param.urlencode(item)
end
end
local http = core.get_http_api()
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
store.packages_full = core.parse_json(response.data) or {}
store.aliases = {}
local packages = core.parse_json(response.data)
if not packages or #packages == 0 then
return
end
local aliases = {}
for _, package in pairs(store.packages_full) do
for _, package in pairs(packages) do
local name_len = #package.name
-- This must match what store.update_paths() does!
package.id = package.author:lower() .. "/"
@ -609,22 +622,58 @@ function store.load()
package.id = package.id .. package.name
end
package.url_part = urlencode(package.author) .. "/" .. urlencode(package.name)
package.url_part = param.urlencode(package.author) .. "/" .. param.urlencode(package.name)
if package.aliases then
for _, alias in ipairs(package.aliases) do
-- We currently don't support name changing
local suffix = "/" .. package.name
if alias:sub(-#suffix) == suffix then
store.aliases[alias:lower()] = package.id
aliases[alias:lower()] = package.id
end
end
end
end
store.packages_full_unordered = store.packages_full
store.packages = store.packages_full
store.loaded = true
return { packages = packages, aliases = aliases }
end
local function sort_and_filter_pkgs()
store.update_paths()
store.sort_packages()
store.filter_packages(search_string)
end
function store.load()
if store.load_ok then
sort_and_filter_pkgs()
return
end
if store.loading then
return
end
store.loading = true
core.handle_async(
fetch_pkgs,
{ urlencode = urlencode },
function(result)
if result then
store.packages = result.packages
store.packages_full = result.packages
store.packages_full_unordered = result.packages
store.aliases = result.aliases
sort_and_filter_pkgs()
store.load_ok = true
store.load_error = false
else
store.load_error = true
end
store.loading = false
core.event_handler("Refresh")
end
)
end
function store.update_paths()
@ -735,7 +784,29 @@ function store.filter_packages(query)
end
end
local function get_info_formspec(text)
local H = 9.5
return table.concat({
"formspec_version[6]",
"size[15.75,9.5]",
not TOUCHSCREEN_GUI and "position[0.5,0.55]" or "",
"label[4,4.35;", text, "]",
"container[0,", H - 0.8 - 0.375, "]",
"button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]",
"container_end[]",
})
end
function store.get_formspec(dlgdata)
if store.loading then
return get_info_formspec(fgettext("Loading..."))
end
if store.load_error then
return get_info_formspec(fgettext("No packages could be retrieved"))
end
assert(store.load_ok)
store.update_paths()
dlgdata.pagemax = math.max(math.ceil(#store.packages / num_per_page), 1)
@ -745,12 +816,10 @@ function store.get_formspec(dlgdata)
local W = 15.75
local H = 9.5
local formspec
if #store.packages_full > 0 then
formspec = {
"formspec_version[3]",
local formspec = {
"formspec_version[6]",
"size[15.75,9.5]",
"position[0.5,0.55]",
not TOUCHSCREEN_GUI and "position[0.5,0.55]" or "",
"style[status,downloading,queued;border=false]",
@ -759,12 +828,12 @@ function store.get_formspec(dlgdata)
"field_close_on_enter[search_string;false]",
"image_button[7.3,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
"image_button[8.125,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]",
"dropdown[9.6,0;2.4,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]",
"dropdown[9.175,0;2.7875,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]",
"container_end[]",
-- Page nav buttons
"container[0,", H - 0.8 - 0.375, "]",
"button[0.375,0;4,0.8;back;", fgettext("Back to Main Menu"), "]",
"button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]",
"container[", W - 0.375 - 0.8*4 - 2, ",0]",
"image_button[0,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "start_icon.png;pstart;]",
@ -779,7 +848,7 @@ function store.get_formspec(dlgdata)
}
if number_downloading > 0 then
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;downloading;"
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;downloading;"
if #download_queue > 0 then
formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue)
else
@ -797,31 +866,21 @@ function store.get_formspec(dlgdata)
end
if num_avail_updates == 0 then
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;status;"
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;status;"
formspec[#formspec + 1] = fgettext("No updates")
formspec[#formspec + 1] = "]"
else
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;update_all;"
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;update_all;"
formspec[#formspec + 1] = fgettext("Update All [$1]", num_avail_updates)
formspec[#formspec + 1] = "]"
end
end
if #store.packages == 0 then
formspec[#formspec + 1] = "label[4,3;"
formspec[#formspec + 1] = "label[4,4.75;"
formspec[#formspec + 1] = fgettext("No results")
formspec[#formspec + 1] = "]"
end
else
formspec = {
"size[12,7]",
"position[0.5,0.55]",
"label[4,3;", fgettext("No packages could be retrieved"), "]",
"container[0,", H - 0.8 - 0.375, "]",
"button[0,0;4,0.8;back;", fgettext("Back to Main Menu"), "]",
"container_end[]",
}
end
-- download/queued tooltips always have the same message
local tooltip_colors = ";#dff6f5;#302c2e]"
@ -891,7 +950,7 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "container_end[]"
-- description
local description_width = W - 0.375*5 - 0.85 - 2*0.7
local description_width = W - 0.375*5 - 0.85 - 2*0.7 - 0.15
formspec[#formspec + 1] = "textarea[1.855,0.3;"
formspec[#formspec + 1] = tostring(description_width)
formspec[#formspec + 1] = ",0.8;;;"
@ -901,7 +960,7 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "container_end[]"
end
return table.concat(formspec, "")
return table.concat(formspec)
end
function store.handle_submit(this, fields)
@ -1042,16 +1101,8 @@ function store.handle_submit(this, fields)
end
function create_store_dlg(type)
if not store.loaded or #store.packages_full == 0 then
store.load()
end
store.update_paths()
store.sort_packages()
search_string = ""
cur_page = 1
if type then
-- table.indexof does not work on tables that contain `nil`
for i, v in pairs(filter_types_type) do
@ -1060,9 +1111,11 @@ function create_store_dlg(type)
break
end
end
else
filter_type = 1
end
store.filter_packages(search_string)
store.load()
return dialog_create("store",
store.get_formspec,