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