-
Notifications
You must be signed in to change notification settings - Fork 912
[Bugfix] 修复导出整合包文件选择界面UI线程阻塞 #6363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
50c8042
e126452
61077fa
7c096a2
6e7402b
6f05c5d
0a17258
5991000
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,24 +27,29 @@ | |
| import javafx.scene.control.TreeItem; | ||
| import javafx.scene.layout.BorderPane; | ||
| import javafx.scene.layout.HBox; | ||
| import javafx.scene.layout.StackPane; | ||
| import org.jackhuang.hmcl.game.GameInstanceID; | ||
| import org.jackhuang.hmcl.game.HMCLGameRepository; | ||
| import org.jackhuang.hmcl.modpack.ModAdviser; | ||
| import org.jackhuang.hmcl.task.Schedulers; | ||
| import org.jackhuang.hmcl.ui.FXUtils; | ||
| import org.jackhuang.hmcl.ui.construct.NoneMultipleSelectionModel; | ||
| import org.jackhuang.hmcl.ui.construct.SpinnerPane; | ||
| import org.jackhuang.hmcl.ui.wizard.WizardController; | ||
| import org.jackhuang.hmcl.ui.wizard.WizardPage; | ||
| import org.jackhuang.hmcl.util.Pair; | ||
| import org.jackhuang.hmcl.util.SettingsMap; | ||
| import org.jackhuang.hmcl.util.StringUtils; | ||
| import org.jackhuang.hmcl.util.io.FileUtils; | ||
| import org.jetbrains.annotations.Nullable; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; | ||
| import static org.jackhuang.hmcl.util.Lang.mapOf; | ||
|
|
@@ -59,43 +64,75 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard | |
| private final WizardController controller; | ||
| private final GameInstanceID instanceId; | ||
| private final ModAdviser adviser; | ||
| private final ModpackFileTreeItem rootNode; | ||
| private @Nullable ModpackFileTreeItem rootNode; | ||
|
|
||
| public ModpackFileSelectionPage(WizardController controller, HMCLGameRepository repository, GameInstanceID instanceId, ModAdviser adviser) { | ||
| this.controller = controller; | ||
| this.instanceId = instanceId; | ||
| this.adviser = adviser; | ||
|
|
||
| JFXTreeView<String> treeView = new JFXTreeView<>(); | ||
| rootNode = getTreeItem(repository.getRunDirectory(instanceId), "minecraft", 0); | ||
| treeView.setRoot(rootNode); | ||
| treeView.setSelectionModel(new NoneMultipleSelectionModel<>()); | ||
| onEscPressed(treeView, () -> controller.onPrev(true)); | ||
| setMargin(treeView, new Insets(10, 10, 5, 10)); | ||
| this.setCenter(treeView); | ||
|
|
||
| Label placeholder = new Label(i18n("modpack.files.empty")); | ||
| StackPane placeholderPane = new StackPane(placeholder); | ||
| placeholderPane.getStyleClass().add("notice-pane"); | ||
| placeholderPane.setVisible(false); | ||
|
|
||
| SpinnerPane spinnerPane = new SpinnerPane(); | ||
| StackPane center = new StackPane(treeView, placeholderPane); | ||
| spinnerPane.setContent(center); | ||
|
|
||
| setMargin(spinnerPane, new Insets(10, 10, 5, 10)); | ||
| this.setCenter(spinnerPane); | ||
|
|
||
|
|
||
| HBox nextPane = new HBox(); | ||
| nextPane.setPadding(new Insets(16, 16, 16, 0)); | ||
| nextPane.setAlignment(Pos.CENTER_RIGHT); | ||
| { | ||
| JFXButton btnNext = FXUtils.newRaisedButton(i18n("wizard.next")); | ||
| btnNext.setPrefSize(100, 40); | ||
| btnNext.setOnAction(e -> onNext()); | ||
|
|
||
| nextPane.getChildren().setAll(btnNext); | ||
| } | ||
| JFXButton btnNext = FXUtils.newRaisedButton(i18n("wizard.next")); | ||
| btnNext.setPrefSize(100, 40); | ||
| btnNext.setOnAction(e -> onNext()); | ||
| nextPane.getChildren().setAll(btnNext); | ||
|
|
||
| loadRoot(repository, treeView, placeholderPane, spinnerPane, btnNext); | ||
| spinnerPane.setOnFailedAction((__) -> loadRoot(repository, treeView, placeholderPane, spinnerPane, btnNext)); | ||
|
|
||
| this.setBottom(nextPane); | ||
| } | ||
|
|
||
| private void loadRoot(HMCLGameRepository repository, JFXTreeView<String> treeView, StackPane placeholderPane, SpinnerPane spinnerPane, JFXButton btnNext) { | ||
| spinnerPane.setLoading(true); | ||
| btnNext.setDisable(true); | ||
| CompletableFuture | ||
| .supplyAsync(() -> getTreeItem(repository.getRunDirectory(instanceId), "minecraft", 0), Schedulers.io()) | ||
| .whenCompleteAsync((root, throwable) -> { | ||
| if (throwable == null) { | ||
| if (root != null) { | ||
| treeView.setRoot(rootNode = root); | ||
| } else { | ||
| placeholderPane.setVisible(true); | ||
|
Comment on lines
+115
to
+116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| } | ||
| spinnerPane.setFailedReason(null); | ||
| btnNext.setDisable(false); | ||
| } else { | ||
| LOG.warning("Failed to load modpack file tree", throwable); | ||
| spinnerPane.setFailedReason(i18n("modpack.files.load_failed")); | ||
| } | ||
| spinnerPane.setLoading(false); | ||
| }, Schedulers.javafx()); | ||
| } | ||
|
|
||
| private ModpackFileTreeItem getTreeItem(Path file, String basePath, int level) { | ||
| if (Files.notExists(file)) | ||
| return null; | ||
|
|
||
| boolean isDirectory = Files.isDirectory(file); | ||
|
|
||
| ModAdviser.ModSuggestion state = ModAdviser.ModSuggestion.SUGGESTED; | ||
| if (basePath.length() > "minecraft/".length()) { | ||
| if (level > 0) { | ||
| state = adviser.advise(StringUtils.substringAfter(basePath, "minecraft/") + (isDirectory ? "/" : ""), isDirectory); | ||
|
|
||
| String fileName = FileUtils.getName(file); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The newly introduced
rootandthrowablelambda parameters are both nullable—this branch explicitly tests each fornull—but neither is annotated, and the nullable return contract ofgetTreeItemremains implicit. Explicitly type and annotate these parameters and the method return so nullability analysis accurately models the asynchronous result.AGENTS.md reference: AGENTS.md:L8-L9
Useful? React with 👍 / 👎.