diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/AboutPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/AboutPage.java index 0c3e8c78f..9d84d5399 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/AboutPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/AboutPage.java @@ -17,18 +17,30 @@ */ package org.jackhuang.hmcl.ui.main; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import javafx.geometry.Insets; import javafx.scene.control.ScrollPane; +import javafx.scene.image.Image; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.ComponentList; import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem; +import org.jackhuang.hmcl.util.gson.JsonUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; -public class AboutPage extends StackPane { +public final class AboutPage extends StackPane { public AboutPage() { ComponentList about = new ComponentList(); @@ -48,131 +60,9 @@ public class AboutPage extends StackPane { about.getContent().setAll(launcher, author); } - ComponentList thanks = new ComponentList(); - { - IconedTwoLineListItem yushijinhun = new IconedTwoLineListItem(); - yushijinhun.setImage(FXUtils.newBuiltinImage("/assets/img/yushijinhun.png")); - yushijinhun.setTitle("yushijinhun"); - yushijinhun.setSubtitle(i18n("about.thanks_to.yushijinhun.statement")); - yushijinhun.setExternalLink("https://yushi.moe/"); + ComponentList thanks = loadIconedTwoLineList("/assets/about/thanks.json"); - IconedTwoLineListItem bangbang93 = new IconedTwoLineListItem(); - bangbang93.setImage(FXUtils.newBuiltinImage("/assets/img/bangbang93.png")); - bangbang93.setTitle("bangbang93"); - bangbang93.setSubtitle(i18n("about.thanks_to.bangbang93.statement")); - bangbang93.setExternalLink("https://bmclapi2.bangbang93.com/"); - - IconedTwoLineListItem glavo = new IconedTwoLineListItem(); - glavo.setImage(FXUtils.newBuiltinImage("/assets/img/glavo.png")); - glavo.setTitle("Glavo"); - glavo.setSubtitle(i18n("about.thanks_to.glavo.statement")); - glavo.setExternalLink("https://github.com/Glavo"); - - IconedTwoLineListItem zekerzhayard = new IconedTwoLineListItem(); - zekerzhayard.setImage(FXUtils.newBuiltinImage("/assets/img/zekerzhayard.png")); - zekerzhayard.setTitle("ZekerZhayard"); - zekerzhayard.setSubtitle(i18n("about.thanks_to.zekerzhayard.statement")); - zekerzhayard.setExternalLink("https://github.com/ZekerZhayard"); - - IconedTwoLineListItem zkitefly = new IconedTwoLineListItem(); - zkitefly.setImage(FXUtils.newBuiltinImage("/assets/img/zkitefly.png")); - zkitefly.setTitle("Zkitefly"); - zkitefly.setSubtitle(i18n("about.thanks_to.zkitefly.statement")); - zkitefly.setExternalLink("https://github.com/zkitefly"); - - IconedTwoLineListItem burningtnt = new IconedTwoLineListItem(); - burningtnt.setImage(FXUtils.newBuiltinImage("/assets/img/burningtnt.png")); - burningtnt.setTitle("Burning_TNT"); - burningtnt.setSubtitle(i18n("about.thanks_to.burningtnt.statement")); - burningtnt.setExternalLink("https://github.com/burningtnt"); - - IconedTwoLineListItem shulkerSakura = new IconedTwoLineListItem(); - shulkerSakura.setTitle("ShulkerSakura"); - shulkerSakura.setImage(FXUtils.newBuiltinImage("/assets/img/ShulkerSakura.png")); - shulkerSakura.setSubtitle(i18n("about.thanks_to.shulkersakura.statement")); - shulkerSakura.setExternalLink("https://github.com/ShulkerSakura"); - - IconedTwoLineListItem gamerteam = new IconedTwoLineListItem(); - gamerteam.setTitle("gamerteam"); - gamerteam.setImage(FXUtils.newBuiltinImage("/assets/img/gamerteam.png")); - gamerteam.setSubtitle(i18n("about.thanks_to.gamerteam.statement")); - gamerteam.setExternalLink("http://www.zhaisoul.com/"); - - IconedTwoLineListItem redLnn = new IconedTwoLineListItem(); - redLnn.setTitle("Red_lnn"); - redLnn.setImage(FXUtils.newBuiltinImage("/assets/img/red_lnn.png")); - redLnn.setSubtitle(i18n("about.thanks_to.red_lnn.statement")); - - IconedTwoLineListItem mcmod = new IconedTwoLineListItem(); - mcmod.setImage(FXUtils.newBuiltinImage("/assets/img/mcmod.png")); - mcmod.setTitle(i18n("about.thanks_to.mcmod")); - mcmod.setSubtitle(i18n("about.thanks_to.mcmod.statement")); - mcmod.setExternalLink("https://www.mcmod.cn/"); - - IconedTwoLineListItem mcbbs = new IconedTwoLineListItem(); - mcbbs.setImage(FXUtils.newBuiltinImage("/assets/img/chest.png")); - mcbbs.setTitle(i18n("about.thanks_to.mcbbs")); - mcbbs.setSubtitle(i18n("about.thanks_to.mcbbs.statement")); - - IconedTwoLineListItem contributors = new IconedTwoLineListItem(); - contributors.setImage(FXUtils.newBuiltinImage("/assets/img/github.png")); - contributors.setTitle(i18n("about.thanks_to.contributors")); - contributors.setSubtitle(i18n("about.thanks_to.contributors.statement")); - contributors.setExternalLink("https://github.com/HMCL-dev/HMCL/graphs/contributors"); - - IconedTwoLineListItem users = new IconedTwoLineListItem(); - users.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png")); - users.setTitle(i18n("about.thanks_to.users")); - users.setSubtitle(i18n("about.thanks_to.users.statement")); - users.setExternalLink("https://docs.hmcl.net/groups.html"); - - thanks.getContent().setAll(yushijinhun, bangbang93, glavo, zekerzhayard, zkitefly, burningtnt, mcmod, mcbbs, shulkerSakura, gamerteam, redLnn, contributors, users); - } - - ComponentList dep = new ComponentList(); - { - IconedTwoLineListItem javafx = new IconedTwoLineListItem(); - javafx.setTitle("JavaFX"); - javafx.setSubtitle("Copyright © 2013, 2024, Oracle and/or its affiliates.\nLicensed under the GPL 2 with Classpath Exception."); - javafx.setExternalLink("https://openjfx.io/"); - - IconedTwoLineListItem jfoenix = new IconedTwoLineListItem(); - jfoenix.setTitle("JFoenix"); - jfoenix.setSubtitle("Copyright © 2016 JFoenix.\nLicensed under the MIT License."); - jfoenix.setExternalLink("https://github.com/sshahine/JFoenix"); - - IconedTwoLineListItem gson = new IconedTwoLineListItem(); - gson.setTitle("Gson"); - gson.setSubtitle("Copyright © 2008 Google Inc.\nLicensed under the Apache 2.0 License."); - gson.setExternalLink("https://github.com/google/gson"); - - IconedTwoLineListItem xz = new IconedTwoLineListItem(); - xz.setTitle("XZ for Java"); - xz.setSubtitle("Lasse Collin, Igor Pavlov, and/or Brett Okken.\nPublic Domain."); - xz.setExternalLink("https://tukaani.org/xz/java.html"); - - IconedTwoLineListItem fxgson = new IconedTwoLineListItem(); - fxgson.setTitle("fx-gson"); - fxgson.setSubtitle("Copyright © 2016 Joffrey Bion.\nLicensed under the MIT License."); - fxgson.setExternalLink("https://github.com/joffrey-bion/fx-gson"); - - IconedTwoLineListItem constantPoolScanner = new IconedTwoLineListItem(); - constantPoolScanner.setTitle("Constant Pool Scanner"); - constantPoolScanner.setSubtitle("Copyright © 1997-2010 Oracle and/or its affiliates.\nLicensed under the GPL 2 or the CDDL."); - constantPoolScanner.setExternalLink("https://github.com/jenkinsci/constant-pool-scanner"); - - IconedTwoLineListItem openNBT = new IconedTwoLineListItem(); - openNBT.setTitle("OpenNBT"); - openNBT.setSubtitle("Copyright © 2013-2021 Steveice10.\nLicensed under the MIT License."); - openNBT.setExternalLink("https://github.com/GeyserMC/OpenNBT"); - - IconedTwoLineListItem minecraftJFXSkin = new IconedTwoLineListItem(); - minecraftJFXSkin.setTitle("minecraft-jfx-skin"); - minecraftJFXSkin.setSubtitle("Copyright © 2016 InfinityStudio.\nLicensed under the GPL 3."); - minecraftJFXSkin.setExternalLink("https://github.com/InfinityStudio/minecraft-jfx-skin"); - - dep.getContent().setAll(javafx, jfoenix, gson, xz, fxgson, constantPoolScanner, openNBT, minecraftJFXSkin); - } + ComponentList deps = loadIconedTwoLineList("/assets/about/deps.json"); ComponentList legal = new ComponentList(); { @@ -204,7 +94,7 @@ public class AboutPage extends StackPane { thanks, ComponentList.createComponentListTitle(i18n("about.dependency")), - dep, + deps, ComponentList.createComponentListTitle(i18n("about.legal")), legal @@ -216,4 +106,49 @@ public class AboutPage extends StackPane { FXUtils.smoothScrolling(scrollPane); getChildren().setAll(scrollPane); } + + private static ComponentList loadIconedTwoLineList(String path) { + ComponentList componentList = new ComponentList(); + + InputStream input = FXUtils.class.getResourceAsStream(path); + if (input == null) { + LOG.warning("Resources not found: " + path); + return componentList; + } + + try (Reader reader = new InputStreamReader(input)) { + JsonArray array = JsonUtils.GSON.fromJson(reader, JsonArray.class); + + for (JsonElement element : array) { + JsonObject obj = element.getAsJsonObject(); + IconedTwoLineListItem item = new IconedTwoLineListItem(); + + if (obj.has("image")) { + String image = obj.get("image").getAsString(); + item.setImage(image.startsWith("/") + ? FXUtils.newBuiltinImage(image) + : new Image(image)); + } + + if (obj.has("title")) + item.setTitle(obj.get("title").getAsString()); + else if (obj.has("titleLocalized")) + item.setTitle(i18n(obj.get("titleLocalized").getAsString())); + + if (obj.has("subtitle")) + item.setSubtitle(obj.get("subtitle").getAsString()); + else if (obj.has("subtitleLocalized")) + item.setSubtitle(i18n(obj.get("subtitleLocalized").getAsString())); + + if (obj.has("externalLink")) + item.setExternalLink(obj.get("externalLink").getAsString()); + + componentList.getContent().add(item); + } + } catch (IOException | JsonParseException e) { + LOG.warning("Failed to load list: " + path, e); + } + + return componentList; + } } diff --git a/HMCL/src/main/resources/assets/about/deps.json b/HMCL/src/main/resources/assets/about/deps.json new file mode 100644 index 000000000..5b0cf6847 --- /dev/null +++ b/HMCL/src/main/resources/assets/about/deps.json @@ -0,0 +1,62 @@ +[ + { + "title" : "OpenJFX", + "subtitle" : "Copyright © 2013, 2024, Oracle and/or its affiliates.\nLicensed under the GPL 2 with Classpath Exception.", + "externalLink" : "https://openjfx.io" + }, + { + "title" : "JFoenix", + "subtitle" : "Copyright © 2016 JFoenix.\nLicensed under the MIT License.", + "externalLink" : "https://github.com/sshahine/JFoenix" + }, + { + "title" : "Gson", + "subtitle" : "Copyright © 2008 Google Inc.\nLicensed under the Apache 2.0 License.", + "externalLink" : "https://github.com/google/gson" + }, + { + "title" : "Apache Commons Compress", + "subtitle" : "Licensed under the Apache 2.0 License.", + "externalLink" : "https://commons.apache.org/proper/commons-compress/" + }, + { + "title" : "XZ for Java", + "subtitle" : "Lasse Collin, Igor Pavlov, and/or Brett Okken.\nPublic Domain.", + "externalLink" : "https://tukaani.org/xz/java.html" + }, + { + "title" : "FX Gson", + "subtitle" : "Copyright © 2016 Joffrey Bion.\nLicensed under the MIT License.", + "externalLink" : "https://github.com/joffrey-bion/fx-gson" + }, + { + "title" : "jsoup", + "subtitle" : "Copyright © 2009 - 2024 Jonathan Hedley (https://jsoup.org/)\nLicensed under the MIT License.", + "externalLink" : "https://jsoup.org/" + }, + { + "title" : "NanoHTTPD", + "subtitle" : "Copyright © 2012 - 2015 nanohttpd.\nLicensed under the BSD 3-clause License.", + "externalLink" : "https://github.com/NanoHttpd/nanohttpd" + }, + { + "title" : "Constant Pool Scanner", + "subtitle" : "Copyright © 1997-2010 Oracle and/or its affiliates.\nLicensed under the GPL 2 or the CDDL.", + "externalLink" : "https://github.com/jenkinsci/constant-pool-scanner" + }, + { + "title" : "OpenNBT", + "subtitle" : "Copyright © 2013-2021 Steveice10.\nLicensed under the MIT License.", + "externalLink" : "https://github.com/GeyserMC/OpenNBT" + }, + { + "title" : "minecraft-jfx-skin", + "subtitle" : "Copyright © 2016 InfinityStudio.\nLicensed under the GPL 3.", + "externalLink" : "https://github.com/InfinityStudio/minecraft-jfx-skin" + }, + { + "title" : "SimplePNG", + "subtitle" : "Copyright © 2023 Glavo.\nLicensed under the Apache 2.0 License.", + "externalLink" : "https://github.com/Glavo/SimplePNG" + } +] \ No newline at end of file diff --git a/HMCL/src/main/resources/assets/about/thanks.json b/HMCL/src/main/resources/assets/about/thanks.json new file mode 100644 index 000000000..189ff3012 --- /dev/null +++ b/HMCL/src/main/resources/assets/about/thanks.json @@ -0,0 +1,78 @@ +[ + { + "image" : "/assets/img/yushijinhun.png", + "title" : "yushijinhun", + "subtitleLocalized" : "about.thanks_to.yushijinhun.statement", + "externalLink" : "https://github.com/yushijinhun" + }, + { + "image" : "/assets/img/bangbang93.png", + "title" : "bangbang93", + "subtitleLocalized" : "about.thanks_to.bangbang93.statement", + "externalLink" : "https://www.bangbang93.com" + }, + { + "image" : "/assets/img/glavo.png", + "title" : "Glavo", + "subtitleLocalized" : "about.thanks_to.glavo.statement", + "externalLink" : "https://github.com/Glavo" + }, + { + "image" : "/assets/img/zekerzhayard.png", + "title" : "ZekerZhayard", + "subtitleLocalized" : "about.thanks_to.zekerzhayard.statement", + "externalLink" : "https://github.com/ZekerZhayard" + }, + { + "image" : "/assets/img/zkitefly.png", + "title" : "Zkitefly", + "subtitleLocalized" : "about.thanks_to.zkitefly.statement", + "externalLink" : "https://github.com/zkitefly" + }, + { + "image" : "/assets/img/burningtnt.png", + "title" : "Burning_TNT", + "subtitleLocalized" : "about.thanks_to.burningtnt.statement", + "externalLink" : "https://github.com/burningtnt" + }, + { + "image" : "/assets/img/ShulkerSakura.png", + "title" : "ShulkerSakura", + "subtitleLocalized" : "about.thanks_to.shulkersakura.statement", + "externalLink" : "https://github.com/ShulkerSakura" + }, + { + "image" : "/assets/img/gamerteam.png", + "title" : "gamerteam", + "subtitleLocalized" : "about.thanks_to.gamerteam.statement", + "externalLink" : "https://github.com/ZhaiSoul" + }, + { + "image" : "/assets/img/red_lnn.png", + "title" : "Red_lnn", + "subtitleLocalized" : "about.thanks_to.red_lnn.statement" + }, + { + "image" : "/assets/img/mcmod.png", + "titleLocalized" : "about.thanks_to.mcmod", + "subtitleLocalized" : "about.thanks_to.mcmod.statement", + "externalLink" : "https://www.mcmod.cn" + }, + { + "image" : "/assets/img/chest.png", + "titleLocalized" : "about.thanks_to.mcbbs", + "subtitleLocalized" : "about.thanks_to.mcbbs.statement" + }, + { + "image" : "/assets/img/github.png", + "titleLocalized" : "about.thanks_to.contributors", + "subtitleLocalized" : "about.thanks_to.contributors.statement", + "externalLink" : "https://github.com/HMCL-dev/HMCL/graphs/contributors" + }, + { + "image" : "/assets/img/icon.png", + "titleLocalized" : "about.thanks_to.users", + "subtitleLocalized" : "about.thanks_to.users.statement", + "externalLink" : "https://docs.hmcl.net/groups.html" + } +] \ No newline at end of file