1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

ContentDB: Add reviews tab (#15254)

This commit is contained in:
rubenwardy 2025-04-13 16:07:01 +01:00 committed by GitHub
parent 78293404c7
commit 75862e33b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 110 additions and 66 deletions

View file

@ -106,6 +106,11 @@ grorp:
textures/base/pack/place_btn.png textures/base/pack/place_btn.png
derived by editing the text in aux1_btn.svg derived by editing the text in aux1_btn.svg
Material Design, Google (Apache license v2.0):
textures/base/pack/contentdb_thumb_up.png
textures/base/pack/contentdb_thumb_down.png
textures/base/pack/contentdb_neutral.png
License of Luanti source code License of Luanti source code
------------------------------- -------------------------------

View file

@ -1,5 +1,6 @@
core.log("info", "Initializing asynchronous environment") core.log("info", "Initializing asynchronous environment")
function core.job_processor(func, serialized_param) function core.job_processor(func, serialized_param)
local param = core.deserialize(serialized_param) local param = core.deserialize(serialized_param)
@ -7,3 +8,15 @@ function core.job_processor(func, serialized_param)
return retval or core.serialize(nil) return retval or core.serialize(nil)
end end
function core.get_http_accept_languages()
local languages
local current_language = core.get_language()
if current_language ~= "" then
languages = { current_language, "en;q=0.8" }
else
languages = { "en" }
end
return "Accept-Language: " .. table.concat(languages, ", ")
end

View file

@ -41,6 +41,7 @@ contentdb = {
REASON_DEPENDENCY = "dependency", REASON_DEPENDENCY = "dependency",
} }
-- API documentation: https://content.luanti.org/help/api/
local function get_download_url(package, reason) local function get_download_url(package, reason)
local base_url = core.settings:get("contentdb_url") local base_url = core.settings:get("contentdb_url")
@ -398,7 +399,6 @@ local function fetch_pkgs()
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=" .. core.urlencode(version.string) core.get_max_supp_proto() .. "&engine_version=" .. core.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
@ -406,19 +406,11 @@ local function fetch_pkgs()
end end
end end
local languages
local current_language = core.get_language()
if current_language ~= "" then
languages = { current_language, "en;q=0.8" }
else
languages = { "en" }
end
local http = core.get_http_api() local http = core.get_http_api()
local response = http.fetch_sync({ local response = http.fetch_sync({
url = url, url = url,
extra_headers = { extra_headers = {
"Accept-Language: " .. table.concat(languages, ", ") core.get_http_accept_languages()
}, },
}) })
if not response.succeeded then if not response.succeeded then
@ -596,57 +588,54 @@ function contentdb.filter_packages(query, by_type)
end end
function contentdb.get_full_package_info(package, callback) local function get_package_info(key, path)
assert(package) return function(package, callback)
if package.full_info then assert(package)
callback(package.full_info) if package[key] then
return callback(package[key])
end return
local function fetch(params)
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local languages
local current_language = core.get_language()
if current_language ~= "" then
languages = { current_language, "en;q=0.8" }
else
languages = { "en" }
end end
local url = base_url .. local function fetch(params)
"/api/packages/" .. params.package.url_part .. "/for-client/?" .. local version = core.get_version()
"protocol_version=" .. core.urlencode(core.get_max_supp_proto()) .. local base_url = core.settings:get("contentdb_url")
"&engine_version=" .. core.urlencode(version.string) .. local url = base_url ..
"&formspec_version=" .. core.urlencode(core.get_formspec_version()) .. "/api/packages/" .. params.package.url_part .. params.path .. "?" ..
"&include_images=false" "protocol_version=" .. core.urlencode(core.get_max_supp_proto()) ..
local http = core.get_http_api() "&engine_version=" .. core.urlencode(version.string) ..
local response = http.fetch_sync({ "&formspec_version=" .. core.urlencode(core.get_formspec_version()) ..
url = url, "&include_images=false"
extra_headers = { local http = core.get_http_api()
"Accept-Language: " .. table.concat(languages, ", ") local response = http.fetch_sync({
}, url = url,
}) extra_headers = {
if not response.succeeded then core.get_http_accept_languages()
return nil },
})
if not response.succeeded then
return nil
end
return core.parse_json(response.data)
end end
return core.parse_json(response.data) local function my_callback(value)
end package[key] = value
callback(value)
end
local function my_callback(value) if not core.handle_async(fetch, { package = package, path = path }, my_callback) then
package.full_info = value core.log("error", "ERROR: async event failed")
callback(value) callback(nil)
end end
if not core.handle_async(fetch, { package = package }, my_callback) then
core.log("error", "ERROR: async event failed")
callback(nil)
end end
end end
contentdb.get_full_package_info = get_package_info("full_info", "/for-client/")
contentdb.get_package_reviews = get_package_info("reviews", "/for-client/reviews/")
function contentdb.get_formspec_padding() function contentdb.get_formspec_padding()
-- Padding is increased on Android to account for notches -- Padding is increased on Android to account for notches
-- TODO: use Android API to determine size of cut outs -- TODO: use Android API to determine size of cut outs

View file

@ -32,6 +32,7 @@ end
local function get_formspec(data) local function get_formspec(data)
local package = data.package
local window_padding = contentdb.get_formspec_padding() local window_padding = contentdb.get_formspec_padding()
local size = contentdb.get_formspec_size() local size = contentdb.get_formspec_size()
size.x = math.min(size.x, 20) size.x = math.min(size.x, 20)
@ -42,7 +43,7 @@ local function get_formspec(data)
if not data.loading and not data.loading_error then if not data.loading and not data.loading_error then
data.loading = true data.loading = true
contentdb.get_full_package_info(data.package, function(info) contentdb.get_full_package_info(package, function(info)
data.loading = false data.loading = false
if info == nil then if info == nil then
@ -61,7 +62,7 @@ local function get_formspec(data)
-- check to see if that happened -- check to see if that happened
if not data.info then if not data.info then
if data.loading_error then if data.loading_error then
return get_info_formspec(size, window_padding, fgettext("No packages could be retrieved")) return get_info_formspec(size, window_padding, fgettext("Error loading package information"))
end end
return get_info_formspec(size, window_padding, fgettext("Loading...")) return get_info_formspec(size, window_padding, fgettext("Loading..."))
end end
@ -103,15 +104,15 @@ local function get_formspec(data)
local left_button_rect = "0,0;2.875,1" local left_button_rect = "0,0;2.875,1"
local right_button_rect = "3.125,0;2.875,1" local right_button_rect = "3.125,0;2.875,1"
if data.package.downloading then if package.downloading then
formspec[#formspec + 1] = "animated_image[5,0;1,1;downloading;" formspec[#formspec + 1] = "animated_image[5,0;1,1;downloading;"
formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir) formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "cdb_downloading.png;3;400;]" formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
elseif data.package.queued then elseif package.queued then
formspec[#formspec + 1] = "style[queued;border=false]" formspec[#formspec + 1] = "style[queued;border=false]"
formspec[#formspec + 1] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir) formspec[#formspec + 1] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "cdb_queued.png;queued;]" formspec[#formspec + 1] = "cdb_queued.png;queued;]"
elseif not data.package.path then elseif not package.path then
formspec[#formspec + 1] = "style[install;bgcolor=green]" formspec[#formspec + 1] = "style[install;bgcolor=green]"
formspec[#formspec + 1] = "button[" formspec[#formspec + 1] = "button["
formspec[#formspec + 1] = right_button_rect formspec[#formspec + 1] = right_button_rect
@ -119,7 +120,7 @@ local function get_formspec(data)
formspec[#formspec + 1] = fgettext("Install [$1]", info.download_size) formspec[#formspec + 1] = fgettext("Install [$1]", info.download_size)
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "]"
else else
if data.package.installed_release < data.package.release then if package.installed_release < package.release then
-- The install_ action also handles updating -- The install_ action also handles updating
formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]" formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]"
formspec[#formspec + 1] = "button[" formspec[#formspec + 1] = "button["
@ -137,10 +138,12 @@ local function get_formspec(data)
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "]"
end end
local review_count = info.reviews.positive + info.reviews.neutral + info.reviews.negative
local current_tab = data.current_tab or 1 local current_tab = data.current_tab or 1
local tab_titles = { local tab_titles = {
fgettext("Description"), fgettext("Description"),
fgettext("Information"), fgettext("Information"),
fgettext("Reviews") .. core.formspec_escape(" [" .. review_count .. "]"),
} }
local tab_body_height = bottom_buttons_y - 2.8 local tab_body_height = bottom_buttons_y - 2.8
@ -162,8 +165,8 @@ local function get_formspec(data)
local winfo = core.get_window_info() local winfo = core.get_window_info()
local fs_to_px = winfo.size.x / winfo.max_formspec_size.x local fs_to_px = winfo.size.x / winfo.max_formspec_size.x
for i, ss in ipairs(info.screenshots) do for i, ss in ipairs(info.screenshots) do
local path = get_screenshot(data.package, ss.url, 2) local path = get_screenshot(package, ss.url, 2)
hypertext = hypertext .. "<action name=\"ss_" .. i .. "\"><img name=\"" .. hypertext = hypertext .. "<action name=\"ss_".. i .. "\"><img name=\"" ..
core.hypertext_escape(path) .. "\" width=" .. (3 * fs_to_px) .. core.hypertext_escape(path) .. "\" width=" .. (3 * fs_to_px) ..
" height=" .. (2 * fs_to_px) .. "></action>" " height=" .. (2 * fs_to_px) .. "></action>"
if i ~= #info.screenshots then if i ~= #info.screenshots then
@ -194,22 +197,54 @@ local function get_formspec(data)
hypertext = hypertext .. "\n\n" .. info.long_description.body hypertext = hypertext .. "\n\n" .. info.long_description.body
-- Fix the path to blank.png. This is needed for bullet indentation.
hypertext = hypertext:gsub("<img name=\"?blank.png\"? ", hypertext = hypertext:gsub("<img name=\"?blank.png\"? ",
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "blank.png\" ") "<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "blank.png\" ")
table.insert_all(formspec, { table.insert_all(formspec, {
"hypertext[0,0;", W, ",", tab_body_height - 0.375, "hypertext[0,0;", W, ",", tab_body_height - 0.375,
";desc;", core.formspec_escape(hypertext), "]", ";desc;", core.formspec_escape(hypertext), "]",
}) })
elseif current_tab == 2 then elseif current_tab == 2 then
local hypertext = info.info_hypertext.head .. info.info_hypertext.body local hypertext = info.info_hypertext.head .. info.info_hypertext.body
table.insert_all(formspec, { table.insert_all(formspec, {
"hypertext[0,0;", W, ",", tab_body_height - 0.375, "hypertext[0,0;", W, ",", tab_body_height - 0.375,
";info;", core.formspec_escape(hypertext), "]", ";info;", core.formspec_escape(hypertext), "]",
}) })
elseif current_tab == 3 then
if not package.reviews and not data.reviews_error and not data.reviews_loading then
data.reviews_loading = true
contentdb.get_package_reviews(package, function(reviews)
if not reviews then
data.reviews_error = true
end
ui.update()
end)
end
if package.reviews then
local hypertext = package.reviews.head .. package.reviews.body
-- Provide correct path to blank.png image. This is needed for bullet indentation.
hypertext = hypertext:gsub("<img name=\"?blank.png\"? ",
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "blank.png\" ")
-- Placeholders in reviews hypertext for icons
hypertext = hypertext:gsub("<thumbsup>",
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "contentdb_thumb_up.png\" width=24>")
hypertext = hypertext:gsub("<thumbsdown>",
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "contentdb_thumb_down.png\" width=24>")
hypertext = hypertext:gsub("<neutral>",
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "contentdb_neutral.png\" width=24>")
table.insert_all(formspec, {
"hypertext[0,0;", W, ",", tab_body_height - 0.375,
";reviews;", core.formspec_escape(hypertext), "]",
})
elseif data.reviews_error then
table.insert_all(formspec, {"label[2,2;", fgettext("Error loading reviews"), "]"} )
else
table.insert_all(formspec, {"label[2,2;", fgettext("Loading..."), "]"} )
end
else else
error("Unknown tab " .. current_tab) error("Unknown tab " .. current_tab)
end end
@ -269,9 +304,10 @@ local function handle_submit(this, fields)
end end
if fields.open_contentdb then if fields.open_contentdb then
local url = ("%s/packages/%s/?protocol_version=%d"):format( local version = core.get_version()
core.settings:get("contentdb_url"), package.url_part, local url = core.settings:get("contentdb_url") .. "/packages/" .. package.url_part ..
core.get_max_supp_proto()) "/?protocol_version=" .. core.urlencode(core.get_max_supp_proto()) ..
"&engine_version=" .. core.urlencode(version.string)
core.open_url(url) core.open_url(url)
return true return true
end end
@ -295,7 +331,8 @@ local function handle_submit(this, fields)
end end
if handle_hypertext_event(this, fields.desc, info.long_description) or if handle_hypertext_event(this, fields.desc, info.long_description) or
handle_hypertext_event(this, fields.info, info.info_hypertext) then handle_hypertext_event(this, fields.info, info.info_hypertext) or
(package.reviews and handle_hypertext_event(this, fields.reviews, package.reviews)) then
return true return true
end end
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B