diff --git a/assets/UI/Homepage.fxml b/assets/UI/Homepage.fxml index c2e787fc..81f93c67 100644 --- a/assets/UI/Homepage.fxml +++ b/assets/UI/Homepage.fxml @@ -14,95 +14,76 @@ - + - + - - - + + + - + - - - + + + - + - + - + - + - + - + - + - + - + - + - - + + - - diff --git a/core/src/cn/harryh/arkpets/assets/AssetItemGroup.java b/core/src/cn/harryh/arkpets/assets/AssetItemGroup.java index 5bb469ee..8d414a15 100644 --- a/core/src/cn/harryh/arkpets/assets/AssetItemGroup.java +++ b/core/src/cn/harryh/arkpets/assets/AssetItemGroup.java @@ -103,23 +103,6 @@ public void sort() { assetItemList.sort(Comparator.comparing(asset -> asset.assetDir, Comparator.naturalOrder())); } - @Deprecated - public void removeDuplicated() { - ArrayList newList = new ArrayList<>(); - for (AssetItem i : assetItemList) { - boolean flag = true; - for (AssetItem j : newList) { - if (j.equals(i)) { - flag = false; - break; - } - } - if (flag) - newList.add(i); - } - assetItemList.clear(); - assetItemList.addAll(newList); - } public static class FilterMode { public static final int MATCH_ANY = 0b1; @@ -133,12 +116,14 @@ public Iterator iterator() { @Override public boolean add(AssetItem assetItem) { - return assetItemList.add(assetItem); + return !assetItemList.contains(assetItem) && assetItemList.add(assetItem); } @Override public boolean addAll(Collection c) { - return assetItemList.addAll(c); + int size = size(); + c.forEach(this::add); + return size != size(); } @Override diff --git a/core/src/cn/harryh/arkpets/assets/ModelsDataset.java b/core/src/cn/harryh/arkpets/assets/ModelsDataset.java index d3d25424..b1e415b6 100644 --- a/core/src/cn/harryh/arkpets/assets/ModelsDataset.java +++ b/core/src/cn/harryh/arkpets/assets/ModelsDataset.java @@ -58,7 +58,6 @@ protected ModelsDataset(ModelsDatasetBean bean) { } data.add(assetItem); } - data.removeDuplicated(); data.sort(); arkPetsCompatibility = new Version(bean.arkPetsCompatibility); diff --git a/desktop/src/cn/harryh/arkpets/controllers/Homepage.java b/desktop/src/cn/harryh/arkpets/controllers/Homepage.java index 3293212a..97b3fac6 100644 --- a/desktop/src/cn/harryh/arkpets/controllers/Homepage.java +++ b/desktop/src/cn/harryh/arkpets/controllers/Homepage.java @@ -11,6 +11,7 @@ import cn.harryh.arkpets.utils.*; import com.alibaba.fastjson.JSONObject; import com.jfoenix.controls.*; +import javafx.stage.FileChooser; import org.apache.log4j.Level; import javafx.animation.FadeTransition; @@ -41,7 +42,6 @@ public final class Homepage { - private boolean isNoFilter = true; public PopupUtils.Handbook trayExitHandbook = new TrayExitHandBook(); public JavaProcess.UnexpectedExitCodeException lastLaunchFailed = null; @@ -151,6 +151,8 @@ public final class Homepage { @FXML private JFXButton manageModelVerify; @FXML + private JFXButton manageModelImport; + @FXML private JFXComboBox configLoggingLevel; @FXML private Label exploreLogDir; @@ -203,7 +205,6 @@ public void initialize() { config.saveConfig(); menuBtn1.getStyleClass().add("menu-btn-active"); new CheckAppUpdateTask(root, GuiTask.GuiTaskStyle.HIDDEN, "auto").start(); - }); } @@ -236,7 +237,6 @@ private void initWrapper(int activeIdx) { private final ChangeListener filterListener = (observable, oldValue, newValue) -> { if (searchModelFilter.getValue() != null) { popLoading(e -> { - isNoFilter = searchModelFilter.getSelectionModel().getSelectedIndex() == 0; Logger.info("ModelManager", "Filter \"" + searchModelFilter.getValue() + "\""); dealModelSearch(searchModelInput.getText()); searchModelFilter.getSelectionModel().clearAndSelect(searchModelFilter.getSelectionModel().getSelectedIndex()); @@ -304,9 +304,17 @@ private boolean initModelDataset(boolean doPopNotice) { // If any exception occurred during the progress above: } catch (FileNotFoundException e) { Logger.warn("ModelManager", "Failed to initialize model dataset due to file not found. (" + e.getMessage() + ")"); - if (doPopNotice) - DialogUtil.createCommonDialog(root, IconUtil.getIcon(IconUtil.ICON_WARNING_ALT, COLOR_WARNING), "模型载入失败", "模型未成功载入:未找到数据集。", - "模型数据集文件 " + PathConfig.fileModelsDataPath + " 可能不在工作目录下。\n请先前往 [选项] 进行模型下载。", null).show(); + if (doPopNotice) { + JFXDialog dialog = DialogUtil.createCommonDialog(root, IconUtil.getIcon(IconUtil.ICON_WARNING_ALT, COLOR_WARNING), "模型载入失败", "模型未成功载入:未找到数据集。", + "模型数据集文件 " + PathConfig.fileModelsDataPath + " 可能不在工作目录下。\n请先前往 [选项] 进行模型下载。", null); + JFXButton go2 = DialogUtil.getGotoButton(dialog, root); + go2.setOnAction(ev -> { + initWrapper(3); + DialogUtil.disposeDialog(dialog, root); + }); + DialogUtil.attachAction(dialog, go2, 0); + dialog.show(); + } } catch (ModelsDataset.DatasetKeyException e) { Logger.warn("ModelManager", "Failed to initialize model dataset due to dataset parsing error. (" + e.getMessage() + ")"); if (doPopNotice) @@ -321,9 +329,9 @@ private boolean initModelDataset(boolean doPopNotice) { return false; } - private boolean initModelAssets(boolean doPopNotice) { + private void initModelAssets(boolean doPopNotice) { if (!initModelDataset(doPopNotice)) - return false; + return; try { // Find every model assets. assetItemList = modelsDataset.data.filter(AssetItem::isExisted); @@ -340,7 +348,6 @@ private boolean initModelAssets(boolean doPopNotice) { modelCellList = new ArrayList<>(); assetItemList.forEach(assetItem -> modelCellList.add(getMenuItem(assetItem, searchModelView))); Logger.debug("ModelManager", "Initialized model assets successfully."); - return true; } catch (IOException e) { // Explicitly set all lists to empty. assetItemList = new AssetItemGroup(); @@ -350,7 +357,6 @@ private boolean initModelAssets(boolean doPopNotice) { DialogUtil.createCommonDialog(root, IconUtil.getIcon(IconUtil.ICON_WARNING_ALT, COLOR_WARNING), "模型载入失败", "模型未成功载入:读取模型列表失败。", "失败原因概要:" + e.getLocalizedMessage(), null).show(); } - return false; } private void initConfigBehavior() { @@ -502,14 +508,20 @@ private void initModelManage() { @Override protected void onSucceeded(boolean result){ // Go to [Step 2/3]: - new UnzipModelsTask(root, GuiTaskStyle.STRICT) { + new UnzipModelsTask(root, GuiTaskStyle.STRICT, PathConfig.tempModelsZipCachePath) { @Override protected void onSucceeded(boolean result) { // Go to [Step 3/3]: new PostUnzipModelTask(root, GuiTaskStyle.STRICT) { @Override protected void onSucceeded(boolean result) { + try { + IOUtils.FileUtil.delete(new File(PathConfig.tempModelsZipCachePath).toPath(), false); + } catch (IOException ex) { + Logger.warn("Task", "The zip file cannot be deleted, because " + ex.getMessage()); + } dealModelReload(true); + initWrapper(1); } }.start(); } @@ -523,6 +535,34 @@ protected void onSucceeded(boolean result) { return; new VerifyModelsTask(root, GuiTask.GuiTaskStyle.COMMON, modelsDataset).start(); }); + manageModelImport.setOnAction(e -> { + // Initialize the file chooser + Logger.info("ModelManager", "Opening file chooser to import zip file"); + FileChooser fileChooser = new FileChooser(); + FileChooser.ExtensionFilter extensionFilter1 = new FileChooser.ExtensionFilter("All Files", "*.*"); + FileChooser.ExtensionFilter extensionFilter2 = new FileChooser.ExtensionFilter("Archives", "*.zip"); + fileChooser.getExtensionFilters().addAll(extensionFilter1, extensionFilter2); + fileChooser.setSelectedExtensionFilter(extensionFilter2); + // Handle the chosen file + File zipFile = fileChooser.showOpenDialog(root.getScene().getWindow()); + if (zipFile != null && zipFile.isFile()) { + Logger.info("ModelManager", "Importing zip file: " + zipFile); + // Go to [Step 1/2]: + new UnzipModelsTask(root, GuiTask.GuiTaskStyle.STRICT, zipFile.getPath()) { + @Override + protected void onSucceeded(boolean result) { + // Go to [Step 2/2]: + new PostUnzipModelTask(root, GuiTaskStyle.STRICT) { + @Override + protected void onSucceeded(boolean result) { + dealModelReload(true); + initWrapper(1); + } + }.start(); + } + }.start(); + } + }); } private void initConfigAdvanced() { diff --git a/desktop/src/cn/harryh/arkpets/guitasks/PostUnzipModelTask.java b/desktop/src/cn/harryh/arkpets/guitasks/PostUnzipModelTask.java index 334c59ba..8bc285ca 100644 --- a/desktop/src/cn/harryh/arkpets/guitasks/PostUnzipModelTask.java +++ b/desktop/src/cn/harryh/arkpets/guitasks/PostUnzipModelTask.java @@ -74,9 +74,8 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th throw new FileNotFoundException("The file " + modelsDataPath + " not found."); try { IOUtils.FileUtil.delete(new File(PathConfig.tempModelsUnzipDirPath).toPath(), false); - IOUtils.FileUtil.delete(new File(PathConfig.tempModelsZipCachePath).toPath(), false); } catch (IOException e) { - Logger.warn("Task", "The cache file or directory cannot be deleted, because " + e.getMessage()); + Logger.warn("Task", "The unzipped cache cannot be deleted, because " + e.getMessage()); } Logger.info("Task", "Moved required files from unzipped files, finished"); return true; diff --git a/desktop/src/cn/harryh/arkpets/guitasks/UnzipModelsTask.java b/desktop/src/cn/harryh/arkpets/guitasks/UnzipModelsTask.java index fe44499b..9ce9285b 100644 --- a/desktop/src/cn/harryh/arkpets/guitasks/UnzipModelsTask.java +++ b/desktop/src/cn/harryh/arkpets/guitasks/UnzipModelsTask.java @@ -9,8 +9,8 @@ public class UnzipModelsTask extends UnzipTask { - public UnzipModelsTask(StackPane root, GuiTaskStyle style) { - super(root, style, PathConfig.tempModelsZipCachePath, PathConfig.tempModelsUnzipDirPath); + public UnzipModelsTask(StackPane root, GuiTaskStyle style, String zipPath) { + super(root, style, zipPath, PathConfig.tempModelsUnzipDirPath); } @Override diff --git a/desktop/src/cn/harryh/arkpets/utils/PopupUtils.java b/desktop/src/cn/harryh/arkpets/utils/PopupUtils.java index b1bbf533..38207ffe 100644 --- a/desktop/src/cn/harryh/arkpets/utils/PopupUtils.java +++ b/desktop/src/cn/harryh/arkpets/utils/PopupUtils.java @@ -8,6 +8,7 @@ import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialogLayout; import com.jfoenix.controls.JFXTextArea; +import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.control.Label; import javafx.scene.control.Separator; @@ -180,13 +181,21 @@ public static JFXDialog createErrorDialog(StackPane root, Throwable e) { Const.isHttpsTrustAll = true; DialogUtil.disposeDialog(dialog, root); }); - layout.setActions(DialogUtil.getOkayButton(dialog, root), apply); + DialogUtil.attachAction(dialog, apply, 0); } else if (e instanceof ZipException) { - h3.setText("压缩文件相关错误。推测可能是下载源问题,请再次重试。"); + h3.setText("压缩文件相关错误。可能是文件不完整或已损坏,请稍后重试。"); } return dialog; } + public static void attachAction(JFXDialog dialog, Node action, int index) { + ObservableList actionList = ((JFXDialogLayout)dialog.getContent()).getActions(); + if (index < 0) + actionList.add(action); + else + actionList.add(index, action); + } + public static Node getHeading(Node graphic, String text, String color) { Label label = new Label(text); label.setGraphic(graphic); @@ -227,6 +236,14 @@ public static JFXButton getOkayButton(JFXDialog dialog, StackPane root) { return button; } + public static JFXButton getGotoButton(JFXDialog dialog, StackPane root) { + JFXButton button = new JFXButton(); + button.setText("前 往"); + button.setStyle("-fx-font-size:13px;-fx-text-fill:" + COLOR_WHITE + ";-fx-background-color:" + COLOR_SUCCESS); + button.setOnAction(e -> disposeDialog(dialog, root)); + return button; + } + public static JFXButton getTrustButton(JFXDialog dialog, StackPane root) { JFXButton button = new JFXButton(); button.setText("信 任");