dlg_package.lua 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. --Luanti
  2. --Copyright (C) 2018-24 rubenwardy
  3. --
  4. --This program is free software; you can redistribute it and/or modify
  5. --it under the terms of the GNU Lesser General Public License as published by
  6. --the Free Software Foundation; either version 2.1 of the License, or
  7. --(at your option) any later version.
  8. --
  9. --This program is distributed in the hope that it will be useful,
  10. --but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. --GNU Lesser General Public License for more details.
  13. --
  14. --You should have received a copy of the GNU Lesser General Public License along
  15. --with this program; if not, write to the Free Software Foundation, Inc.,
  16. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. local function get_info_formspec(size, padding, text)
  18. return table.concat({
  19. "formspec_version[6]",
  20. "size[", size.x, ",", size.y, "]",
  21. "padding[0,0]",
  22. "bgcolor[;true]",
  23. "label[4,4.35;", text, "]",
  24. "container[", padding.x, ",", size.y - 0.8 - padding.y, "]",
  25. "button[0,0;2,0.8;back;", fgettext("Back"), "]",
  26. "container_end[]",
  27. })
  28. end
  29. local function get_formspec(data)
  30. local window_padding = contentdb.get_formspec_padding()
  31. local size = contentdb.get_formspec_size()
  32. size.x = math.min(size.x, 20)
  33. local W = size.x - window_padding.x * 2
  34. local H = size.y - window_padding.y * 2
  35. if not data.info then
  36. if not data.loading and not data.loading_error then
  37. data.loading = true
  38. contentdb.get_full_package_info(data.package, function(info)
  39. data.loading = false
  40. if info == nil then
  41. data.loading_error = true
  42. ui.update()
  43. return
  44. end
  45. assert(data.package.name == info.name)
  46. data.info = info
  47. ui.update()
  48. end)
  49. end
  50. -- get_full_package_info can return cached info immediately, so
  51. -- check to see if that happened
  52. if not data.info then
  53. if data.loading_error then
  54. return get_info_formspec(size, window_padding, fgettext("No packages could be retrieved"))
  55. end
  56. return get_info_formspec(size, window_padding, fgettext("Loading..."))
  57. end
  58. end
  59. -- Check installation status
  60. contentdb.update_paths()
  61. local info = data.info
  62. local info_line =
  63. fgettext("by $1 — $2 downloads — +$3 / $4 / -$5",
  64. info.author, info.downloads,
  65. info.reviews.positive, info.reviews.neutral, info.reviews.negative)
  66. local bottom_buttons_y = H - 0.8
  67. local formspec = {
  68. "formspec_version[7]",
  69. "size[", size.x, ",", size.y, "]",
  70. "padding[0,0]",
  71. "bgcolor[;true]",
  72. "container[", window_padding.x, ",", window_padding.y, "]",
  73. "button[0,", bottom_buttons_y, ";2,0.8;back;", fgettext("Back"), "]",
  74. "button[", W - 3, ",", bottom_buttons_y, ";3,0.8;open_contentdb;", fgettext("ContentDB page"), "]",
  75. "style_type[label;font_size=+24;font=bold]",
  76. "label[0,0.4;", core.formspec_escape(info.title), "]",
  77. "style_type[label;font_size=;font=]",
  78. "label[0,1.2;", core.formspec_escape(info_line), "]",
  79. }
  80. table.insert_all(formspec, {
  81. "container[", W - 6, ",0]"
  82. })
  83. local left_button_rect = "0,0;2.875,1"
  84. local right_button_rect = "3.125,0;2.875,1"
  85. if data.package.downloading then
  86. formspec[#formspec + 1] = "animated_image[5,0;1,1;downloading;"
  87. formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
  88. formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
  89. elseif data.package.queued then
  90. formspec[#formspec + 1] = "style[queued;border=false]"
  91. formspec[#formspec + 1] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir)
  92. formspec[#formspec + 1] = "cdb_queued.png;queued;]"
  93. elseif not data.package.path then
  94. formspec[#formspec + 1] = "style[install;bgcolor=green]"
  95. formspec[#formspec + 1] = "button["
  96. formspec[#formspec + 1] = right_button_rect
  97. formspec[#formspec + 1] =";install;"
  98. formspec[#formspec + 1] = fgettext("Install [$1]", info.download_size)
  99. formspec[#formspec + 1] = "]"
  100. else
  101. if data.package.installed_release < data.package.release then
  102. -- The install_ action also handles updating
  103. formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]"
  104. formspec[#formspec + 1] = "button["
  105. formspec[#formspec + 1] = left_button_rect
  106. formspec[#formspec + 1] = ";install;"
  107. formspec[#formspec + 1] = fgettext("Update")
  108. formspec[#formspec + 1] = "]"
  109. end
  110. formspec[#formspec + 1] = "style[uninstall;bgcolor=#a93b3b]"
  111. formspec[#formspec + 1] = "button["
  112. formspec[#formspec + 1] = right_button_rect
  113. formspec[#formspec + 1] = ";uninstall;"
  114. formspec[#formspec + 1] = fgettext("Uninstall")
  115. formspec[#formspec + 1] = "]"
  116. end
  117. local current_tab = data.current_tab or 1
  118. local tab_titles = {
  119. fgettext("Description"),
  120. fgettext("Information"),
  121. }
  122. local tab_body_height = bottom_buttons_y - 2.8
  123. table.insert_all(formspec, {
  124. "container_end[]",
  125. "box[0,2.55;", W, ",", tab_body_height, ";#ffffff11]",
  126. "tabheader[0,2.55;", W, ",0.8;tabs;",
  127. table.concat(tab_titles, ","), ";", current_tab, ";true;true]",
  128. "container[0,2.8]",
  129. })
  130. if current_tab == 1 then
  131. -- Screenshots and description
  132. local hypertext = "<big><b>" .. core.hypertext_escape(info.short_description) .. "</b></big>\n"
  133. local winfo = core.get_window_info()
  134. local fs_to_px = winfo.size.x / winfo.max_formspec_size.x
  135. for i, ss in ipairs(info.screenshots) do
  136. local path = get_screenshot(data.package, ss.url, 2)
  137. hypertext = hypertext .. "<action name=\"ss_" .. i .. "\"><img name=\"" ..
  138. core.hypertext_escape(path) .. "\" width=" .. (3 * fs_to_px) ..
  139. " height=" .. (2 * fs_to_px) .. "></action>"
  140. if i ~= #info.screenshots then
  141. hypertext = hypertext .. "<img name=\"blank.png\" width=" .. (0.25 * fs_to_px) ..
  142. " height=" .. (2.25 * fs_to_px).. ">"
  143. end
  144. end
  145. hypertext = hypertext .. "\n" .. info.long_description.head
  146. local first = true
  147. local function add_link_button(label, name)
  148. if info[name] then
  149. if not first then
  150. hypertext = hypertext .. " | "
  151. end
  152. hypertext = hypertext .. "<action name=link_" .. name .. ">" .. core.hypertext_escape(label) .. "</action>"
  153. info.long_description.links["link_" .. name] = info[name]
  154. first = false
  155. end
  156. end
  157. add_link_button(fgettext("Donate"), "donate_url")
  158. add_link_button(fgettext("Website"), "website")
  159. add_link_button(fgettext("Source"), "repo")
  160. add_link_button(fgettext("Issue Tracker"), "issue_tracker")
  161. add_link_button(fgettext("Translate"), "translation_url")
  162. add_link_button(fgettext("Forum Topic"), "forum_url")
  163. hypertext = hypertext .. "\n\n" .. info.long_description.body
  164. hypertext = hypertext:gsub("<img name=\"?blank.png\"? ",
  165. "<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "blank.png\" ")
  166. table.insert_all(formspec, {
  167. "hypertext[0,0;", W, ",", tab_body_height - 0.375,
  168. ";desc;", core.formspec_escape(hypertext), "]",
  169. })
  170. elseif current_tab == 2 then
  171. local hypertext = info.info_hypertext.head .. info.info_hypertext.body
  172. table.insert_all(formspec, {
  173. "hypertext[0,0;", W, ",", tab_body_height - 0.375,
  174. ";info;", core.formspec_escape(hypertext), "]",
  175. })
  176. else
  177. error("Unknown tab " .. current_tab)
  178. end
  179. formspec[#formspec + 1] = "container_end[]"
  180. formspec[#formspec + 1] = "container_end[]"
  181. return table.concat(formspec)
  182. end
  183. local function handle_hypertext_event(this, event, hypertext_object)
  184. if not (event and event:sub(1, 7) == "action:") then
  185. return
  186. end
  187. for i, ss in ipairs(this.data.info.screenshots) do
  188. if event == "action:ss_" .. i then
  189. core.open_url(ss.url)
  190. return true
  191. end
  192. end
  193. local base_url = core.settings:get("contentdb_url"):gsub("(%W)", "%%%1")
  194. for key, url in pairs(hypertext_object.links) do
  195. if event == "action:" .. key then
  196. local author, name = url:match("^" .. base_url .. "/?packages/([A-Za-z0-9 _-]+)/([a-z0-9_]+)/?$")
  197. if author and name then
  198. local package2 = contentdb.get_package_by_info(author, name)
  199. if package2 then
  200. local dlg = create_package_dialog(package2)
  201. dlg:set_parent(this)
  202. this:hide()
  203. dlg:show()
  204. return true
  205. end
  206. end
  207. core.open_url_dialog(url)
  208. return true
  209. end
  210. end
  211. end
  212. local function handle_submit(this, fields)
  213. local info = this.data.info
  214. local package = this.data.package
  215. if fields.back then
  216. this:delete()
  217. return true
  218. end
  219. if not info then
  220. return false
  221. end
  222. if fields.open_contentdb then
  223. local url = ("%s/packages/%s/?protocol_version=%d"):format(
  224. core.settings:get("contentdb_url"), package.url_part,
  225. core.get_max_supp_proto())
  226. core.open_url(url)
  227. return true
  228. end
  229. if fields.install then
  230. install_or_update_package(this, package)
  231. return true
  232. end
  233. if fields.uninstall then
  234. local dlg = create_delete_content_dlg(package)
  235. dlg:set_parent(this)
  236. this:hide()
  237. dlg:show()
  238. return true
  239. end
  240. if fields.tabs then
  241. this.data.current_tab = tonumber(fields.tabs)
  242. return true
  243. end
  244. if handle_hypertext_event(this, fields.desc, info.long_description) or
  245. handle_hypertext_event(this, fields.info, info.info_hypertext) then
  246. return true
  247. end
  248. end
  249. local function handle_events(event)
  250. if event == "WindowInfoChange" then
  251. ui.update()
  252. return true
  253. end
  254. return false
  255. end
  256. function create_package_dialog(package)
  257. assert(package)
  258. local dlg = dialog_create("package_dialog_" .. package.id,
  259. get_formspec,
  260. handle_submit,
  261. handle_events)
  262. local data = dlg.data
  263. data.package = package
  264. data.info = nil
  265. data.loading = false
  266. data.loading_error = nil
  267. data.current_tab = 1
  268. return dlg
  269. end