Skip to content

Commit

Permalink
Add package update detection on Content tab
Browse files Browse the repository at this point in the history
Fixes #7327
  • Loading branch information
rubenwardy committed Sep 18, 2023
1 parent 5bfc5d4 commit f0a78ac
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 24 deletions.
1 change: 1 addition & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Zughy:
textures/base/pack/cdb_downloading.png
textures/base/pack/cdb_queued.png
textures/base/pack/cdb_update.png
textures/base/pack/cdb_update_cropped.png
textures/base/pack/cdb_viewonline.png
textures/base/pack/settings_btn.png
textures/base/pack/settings_info.png
Expand Down
10 changes: 7 additions & 3 deletions builtin/fstk/tabview.lua
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,17 @@ end
local function tab_header(self, size)
local toadd = ""

for i=1,#self.tablist,1 do

for i = 1, #self.tablist do
if toadd ~= "" then
toadd = toadd .. ","
end

toadd = toadd .. self.tablist[i].caption
local caption = self.tablist[i].caption
if type(caption) == "function" then
caption = caption(self)
end

toadd = toadd .. caption
end
return string.format("tabheader[%f,%f;%f,%f;%s;%s;%i;true;false]",
self.header_x, self.header_y, size.width, size.height, self.name, toadd, self.last_tab_index)
Expand Down
File renamed without changes.
22 changes: 22 additions & 0 deletions builtin/mainmenu/content/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--Minetest
--Copyright (C) 2023 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

local path = core.get_mainmenu_path() .. DIR_DELIM .. "content"

dofile(path .. DIR_DELIM .. "pkgmgr.lua")
dofile(path .. DIR_DELIM .. "update_detector.lua")
dofile(path .. DIR_DELIM .. "dlg_contentstore.lua")
51 changes: 38 additions & 13 deletions builtin/mainmenu/pkgmgr.lua → builtin/mainmenu/content/pkgmgr.lua
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ function pkgmgr.get_mods(path, virtual_path, listing, modpack)
end
end

--------------------------------------------------------------------------------
function pkgmgr.get_texture_packs()
local txtpath = core.get_texturepath()
local txtpath_system = core.get_texturepath_share()
Expand All @@ -195,6 +196,23 @@ function pkgmgr.get_texture_packs()
return retval
end

--------------------------------------------------------------------------------
function pkgmgr.get_all()
local result = {}

for _, mod in pairs(pkgmgr.global_mods:get_list()) do
result[#result + 1] = mod
end
for _, game in pairs(pkgmgr.games) do
result[#result + 1] = game
end
for _, txp in pairs(pkgmgr.get_texture_packs()) do
result[#result + 1] = txp
end

return result
end

--------------------------------------------------------------------------------
function pkgmgr.get_folder_type(path)
local testfile = io.open(path .. DIR_DELIM .. "init.lua","r")
Expand Down Expand Up @@ -260,7 +278,10 @@ function pkgmgr.is_valid_modname(modpath)
end

--------------------------------------------------------------------------------
function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
--- @param render_list filterlist
--- @param use_technical_names boolean to show technical names instead of human-readable titles
--- @param with_icon table or nil, from virtual path to icon object
function pkgmgr.render_packagelist(render_list, use_technical_names, with_icon)
if not render_list then
if not pkgmgr.global_mods then
pkgmgr.refresh_globals()
Expand All @@ -273,10 +294,10 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
for i, v in ipairs(list) do
local color = ""
local icon = 0
local error = with_error and with_error[v.virtual_path]
local function update_error(val)
if val and (not error or (error.type == "warning" and val.type == "error")) then
error = val
local icon_info = with_icon and with_icon[v.virtual_path or v.path]
local function update_icon_info(val)
if val and (not icon_info or (icon_info.type == "warning" and val.type == "error")) then
icon_info = val
end
end

Expand All @@ -286,8 +307,8 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)

for j = 1, #rawlist do
if rawlist[j].modpack == list[i].name then
if with_error then
update_error(with_error[rawlist[j].virtual_path])
if with_icon then
update_icon_info(with_icon[rawlist[j].virtual_path])
end

if rawlist[j].enabled then
Expand All @@ -303,10 +324,10 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
color = mt_color_blue

local rawlist = render_list:get_raw_list()
if v.type == "game" and with_error then
if v.type == "game" and with_icon then
for j = 1, #rawlist do
if rawlist[j].is_game_content then
update_error(with_error[rawlist[j].virtual_path])
update_icon_info(with_icon[rawlist[j].virtual_path])
end
end
end
Expand All @@ -315,13 +336,17 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
color = mt_color_green
end

if error then
if error.type == "warning" then
if icon_info then
if icon_info.type == "warning" then
color = mt_color_orange
icon = 2
else
elseif icon_info.type == "error" then
color = mt_color_red
icon = 3
elseif icon_info.type == "update" then
icon = 4
else
icon_info("Unknown error type " .. icon_info.type)
end
end

Expand All @@ -332,7 +357,7 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
retval[#retval + 1] = "0"
end

if with_error then
if with_icon then
retval[#retval + 1] = icon
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ local function reset()
end

setfenv(loadfile("builtin/common/misc_helpers.lua"), env)()
setfenv(loadfile("builtin/mainmenu/pkgmgr.lua"), env)()
setfenv(loadfile("builtin/mainmenu/content/pkgmgr.lua"), env)()

function env.pkgmgr.update_gamelist()
table.insert(calls, { "update_gamelist" })
Expand Down
153 changes: 153 additions & 0 deletions builtin/mainmenu/content/update_detector.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
--Minetest
--Copyright (C) 2023 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


update_detector = {}


if not core.get_http_api then
update_detector.get_all = function() return {} end
update_detector.get_count = function() return 0 end
return
end


local has_fetched = false
local latest_releases


-- encodes for use as URL parameter or path component
local function urlencode(str)
return str:gsub("[^%a%d()._~-]", function(char)
return ("%%%02X"):format(char:byte())
end)
end
assert(urlencode("sample text?") == "sample%20text%3F")


local function fetch_latest_releases(param)
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local url = base_url ..
"/api/updates/?type=mod&type=game&type=txp&protocol_version=" ..
core.get_max_supp_proto() .. "&engine_version=" .. param.urlencode(version.string)
local http = core.get_http_api()
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end

return core.parse_json(response.data)
end


--- Get a table from package key (author/name) to latest release id
---
--- @param callback function that takes a single argument, table or nil
local function get_latest_releases(callback)
core.handle_async(
fetch_latest_releases,
{ urlencode = urlencode },
callback)
end


local function has_packages_from_cdb()
pkgmgr.refresh_globals()
pkgmgr.update_gamelist()

for _, content in pairs(pkgmgr.get_all()) do
if content.author and content.release > 0 then
return true
end
end
return false
end


--- @returns a new table with all keys lowercase
local function lowercase_keys(tab)
local ret = {}
for key, value in pairs(tab) do
ret[key:lower()] = value
end
return ret
end


local function fetch()
if has_fetched or not has_packages_from_cdb() then
return
end

has_fetched = true

get_latest_releases(function(releases)
if not releases then
has_fetched = false
return
end

latest_releases = lowercase_keys(releases)
if update_detector.get_count() > 0 then
local maintab = ui.find_by_name("maintab")
if not maintab.hidden then
ui.update()
end
end
end)
end


--- @returns a list of content with an update available
function update_detector.get_all()
if latest_releases == nil then
fetch()
return {}
end

pkgmgr.refresh_globals()
pkgmgr.update_gamelist()

local ret = {}
local all_content = pkgmgr.get_all()
for i = 1, #all_content do
local content = all_content[i]
if content.author and content.release > 0 then
-- The backend will account for aliases in `latest_releases`
local id = content.author:lower() .. "/"
if content.type == "game" then
id = id .. content.id
else
id = id .. content.name
end

local latest_release = latest_releases[id]
if latest_release and latest_release > content.release then
ret[#ret + 1] = content
end
end
end

return ret
end


--- @return number of packages with updates available
function update_detector.get_count()
return #update_detector.get_all()
end
3 changes: 1 addition & 2 deletions builtin/mainmenu/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ dofile(basepath .. "fstk" .. DIR_DELIM .. "tabview.lua")
dofile(basepath .. "fstk" .. DIR_DELIM .. "ui.lua")
dofile(menupath .. DIR_DELIM .. "async_event.lua")
dofile(menupath .. DIR_DELIM .. "common.lua")
dofile(menupath .. DIR_DELIM .. "pkgmgr.lua")
dofile(menupath .. DIR_DELIM .. "serverlistmgr.lua")
dofile(menupath .. DIR_DELIM .. "game_theme.lua")
dofile(menupath .. DIR_DELIM .. "content" .. DIR_DELIM .. "init.lua")

dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
dofile(menupath .. DIR_DELIM .. "settings" .. DIR_DELIM .. "init.lua")
dofile(menupath .. DIR_DELIM .. "dlg_contentstore.lua")
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
Expand Down

0 comments on commit f0a78ac

Please sign in to comment.