From 75862e33b6bfe6b3805310152c66af1430ac3666 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 13 Apr 2025 16:07:01 +0100 Subject: [PATCH] ContentDB: Add reviews tab (#15254) --- LICENSE.txt | 5 ++ builtin/async/mainmenu.lua | 13 +++ builtin/mainmenu/content/contentdb.lua | 93 +++++++++----------- builtin/mainmenu/content/dlg_package.lua | 65 +++++++++++--- textures/base/pack/contentdb_neutral.png | Bin 0 -> 169 bytes textures/base/pack/contentdb_thumb_down.png | Bin 0 -> 348 bytes textures/base/pack/contentdb_thumb_up.png | Bin 0 -> 411 bytes 7 files changed, 110 insertions(+), 66 deletions(-) create mode 100644 textures/base/pack/contentdb_neutral.png create mode 100644 textures/base/pack/contentdb_thumb_down.png create mode 100644 textures/base/pack/contentdb_thumb_up.png diff --git a/LICENSE.txt b/LICENSE.txt index 772f86728..5c01e2c3b 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -106,6 +106,11 @@ grorp: textures/base/pack/place_btn.png 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 ------------------------------- diff --git a/builtin/async/mainmenu.lua b/builtin/async/mainmenu.lua index 0e9c222d1..c1d8618b4 100644 --- a/builtin/async/mainmenu.lua +++ b/builtin/async/mainmenu.lua @@ -1,5 +1,6 @@ core.log("info", "Initializing asynchronous environment") + function core.job_processor(func, 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) 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 diff --git a/builtin/mainmenu/content/contentdb.lua b/builtin/mainmenu/content/contentdb.lua index 963400a12..856924bd4 100644 --- a/builtin/mainmenu/content/contentdb.lua +++ b/builtin/mainmenu/content/contentdb.lua @@ -41,6 +41,7 @@ contentdb = { REASON_DEPENDENCY = "dependency", } +-- API documentation: https://content.luanti.org/help/api/ local function get_download_url(package, reason) local base_url = core.settings:get("contentdb_url") @@ -398,7 +399,6 @@ local function fetch_pkgs() local url = base_url .. "/api/packages/?type=mod&type=game&type=txp&protocol_version=" .. core.get_max_supp_proto() .. "&engine_version=" .. core.urlencode(version.string) - for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do item = item:trim() if item ~= "" then @@ -406,19 +406,11 @@ local function fetch_pkgs() 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 response = http.fetch_sync({ url = url, extra_headers = { - "Accept-Language: " .. table.concat(languages, ", ") + core.get_http_accept_languages() }, }) if not response.succeeded then @@ -596,57 +588,54 @@ function contentdb.filter_packages(query, by_type) end -function contentdb.get_full_package_info(package, callback) - assert(package) - if package.full_info then - callback(package.full_info) - return - end - - 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" } +local function get_package_info(key, path) + return function(package, callback) + assert(package) + if package[key] then + callback(package[key]) + return end - local url = base_url .. - "/api/packages/" .. params.package.url_part .. "/for-client/?" .. - "protocol_version=" .. core.urlencode(core.get_max_supp_proto()) .. - "&engine_version=" .. core.urlencode(version.string) .. - "&formspec_version=" .. core.urlencode(core.get_formspec_version()) .. - "&include_images=false" - local http = core.get_http_api() - local response = http.fetch_sync({ - url = url, - extra_headers = { - "Accept-Language: " .. table.concat(languages, ", ") - }, - }) - if not response.succeeded then - return nil + local function fetch(params) + local version = core.get_version() + local base_url = core.settings:get("contentdb_url") + local url = base_url .. + "/api/packages/" .. params.package.url_part .. params.path .. "?" .. + "protocol_version=" .. core.urlencode(core.get_max_supp_proto()) .. + "&engine_version=" .. core.urlencode(version.string) .. + "&formspec_version=" .. core.urlencode(core.get_formspec_version()) .. + "&include_images=false" + local http = core.get_http_api() + local response = http.fetch_sync({ + url = url, + extra_headers = { + core.get_http_accept_languages() + }, + }) + if not response.succeeded then + return nil + end + + return core.parse_json(response.data) end - return core.parse_json(response.data) - end + local function my_callback(value) + package[key] = value + callback(value) + end - local function my_callback(value) - package.full_info = value - callback(value) - end - - if not core.handle_async(fetch, { package = package }, my_callback) then - core.log("error", "ERROR: async event failed") - callback(nil) + if not core.handle_async(fetch, { package = package, path = path }, my_callback) then + core.log("error", "ERROR: async event failed") + callback(nil) + 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() -- Padding is increased on Android to account for notches -- TODO: use Android API to determine size of cut outs diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua index 7edbf678f..d8fc057c1 100644 --- a/builtin/mainmenu/content/dlg_package.lua +++ b/builtin/mainmenu/content/dlg_package.lua @@ -32,6 +32,7 @@ end local function get_formspec(data) + local package = data.package local window_padding = contentdb.get_formspec_padding() local size = contentdb.get_formspec_size() 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 data.loading = true - contentdb.get_full_package_info(data.package, function(info) + contentdb.get_full_package_info(package, function(info) data.loading = false if info == nil then @@ -61,7 +62,7 @@ local function get_formspec(data) -- check to see if that happened if not data.info 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 return get_info_formspec(size, window_padding, fgettext("Loading...")) end @@ -103,15 +104,15 @@ local function get_formspec(data) local left_button_rect = "0,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] = core.formspec_escape(defaulttexturedir) 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] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir) 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] = "button[" 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] = "]" else - if data.package.installed_release < data.package.release then + if package.installed_release < package.release then -- The install_ action also handles updating formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]" formspec[#formspec + 1] = "button[" @@ -137,10 +138,12 @@ local function get_formspec(data) formspec[#formspec + 1] = "]" end + local review_count = info.reviews.positive + info.reviews.neutral + info.reviews.negative local current_tab = data.current_tab or 1 local tab_titles = { fgettext("Description"), fgettext("Information"), + fgettext("Reviews") .. core.formspec_escape(" [" .. review_count .. "]"), } 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 fs_to_px = winfo.size.x / winfo.max_formspec_size.x for i, ss in ipairs(info.screenshots) do - local path = get_screenshot(data.package, ss.url, 2) - hypertext = hypertext .. "" if i ~= #info.screenshots then @@ -194,22 +197,54 @@ local function get_formspec(data) hypertext = hypertext .. "\n\n" .. info.long_description.body + -- Fix the path to blank.png. This is needed for bullet indentation. hypertext = hypertext:gsub("", + "") + hypertext = hypertext:gsub("", + "") + hypertext = hypertext:gsub("", + "") + 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 error("Unknown tab " .. current_tab) end @@ -269,9 +304,10 @@ local function handle_submit(this, fields) end if fields.open_contentdb then - local url = ("%s/packages/%s/?protocol_version=%d"):format( - core.settings:get("contentdb_url"), package.url_part, - core.get_max_supp_proto()) + local version = core.get_version() + local url = core.settings:get("contentdb_url") .. "/packages/" .. package.url_part .. + "/?protocol_version=" .. core.urlencode(core.get_max_supp_proto()) .. + "&engine_version=" .. core.urlencode(version.string) core.open_url(url) return true end @@ -295,7 +331,8 @@ local function handle_submit(this, fields) end 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 end end diff --git a/textures/base/pack/contentdb_neutral.png b/textures/base/pack/contentdb_neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..a73e30bcd34066231558709f701435395026b2ee GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(a8A!&?{Fw`+_yc@GT!HlSS8rdwe*668>ld%y zuKD}b4=BV^666=m5L(|b=XcHxAm7!~#W5tK@$DH$-UA8(3`nEQl-ild6t3eGAn zDy}QIskrMntl+5Pq~fgNvVyCMn~M7q4l0f+PAfR8xTv_QxUJy+103G`XIK{SWHl>u zVb08n`JCpC`MUKj6F!)CW`A>j<&D`fTjr1A<&|Z^2lLMCneXCtV8?8k4YN%6D&Azs z&g_}DIrotrvt>5SGU02UF!IjqnKx#~d=-x)8)ljC!Mrnj_zrRxCw9!1*)Yq54=i{V uNA}DcJ?zD#Vqw|Nn2Ic!IWa$&e`B7Vr4%?A@oSO*0000ufGF(HyNCAsbdCI3ApSuR7c}S=?#GzF|Yv;iLd!DIRE5GeTnc)K+Adg4BXk_?`%elF{r5}E+JOt9Pl literal 0 HcmV?d00001