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:
parent
78293404c7
commit
75862e33b6
7 changed files with 110 additions and 66 deletions
|
@ -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
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
BIN
textures/base/pack/contentdb_neutral.png
Normal file
BIN
textures/base/pack/contentdb_neutral.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 169 B |
BIN
textures/base/pack/contentdb_thumb_down.png
Normal file
BIN
textures/base/pack/contentdb_thumb_down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 348 B |
BIN
textures/base/pack/contentdb_thumb_up.png
Normal file
BIN
textures/base/pack/contentdb_thumb_up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 411 B |
Loading…
Add table
Add a link
Reference in a new issue