feat: auto-fetch Mojang Java 25; strip April Fools, task list, unused locales
On first-capable startup, download java-runtime-epsilon via the existing BMCLAPI-mirrored Mojang path when missing (progress dialog only; no prompt). Remove launcher April Fools prompts/settings/UI tags, the top-right task center page/button, dead NBT/April Fools images, and unused locale packs (ar/de/es/ja/ru/uk) to shrink the distributable.
No files matched your search
@@ -455,9 +455,9 @@ public class HMCLGameInstance extends DefaultGameInstance {
|
||||
return GameInstanceIconType.OPTIFINE.getIcon();
|
||||
|
||||
GameVersionNumber version = getVersion();
|
||||
if (version.isAprilFools())
|
||||
return GameInstanceIconType.APRIL_FOOLS.getIcon();
|
||||
else if (version instanceof GameVersionNumber.LegacySnapshot || version instanceof GameVersionNumber.Release release && release.getEaType() != GameVersionNumber.Release.ReleaseType.GA)
|
||||
if (version instanceof GameVersionNumber.LegacySnapshot
|
||||
|| version.isAprilFools()
|
||||
|| version instanceof GameVersionNumber.Release release && release.getEaType() != GameVersionNumber.Release.ReleaseType.GA)
|
||||
return GameInstanceIconType.COMMAND.getIcon();
|
||||
else if (version instanceof GameVersionNumber.Old)
|
||||
return GameInstanceIconType.CRAFT_TABLE.getIcon();
|
||||
|
||||
@@ -22,7 +22,8 @@ public enum GameInstanceIconType {
|
||||
NEO_FORGE("/assets/img/neoforge.png"),
|
||||
FURNACE("/assets/img/furnace.png"),
|
||||
QUILT("/assets/img/quilt.png"),
|
||||
APRIL_FOOLS("/assets/img/april_fools.png"),
|
||||
/// Retained for settings migration; UI no longer offers this icon.
|
||||
APRIL_FOOLS("/assets/img/command.png"),
|
||||
CLEANROOM("/assets/img/cleanroom.png"),
|
||||
LEGACY_FABRIC("/assets/img/legacyfabric.png")
|
||||
;
|
||||
|
||||
@@ -179,15 +179,6 @@ public final class LauncherSettings extends ObservableSetting implements JsonSch
|
||||
|
||||
|
||||
|
||||
/// Whether April Fools features are disabled.
|
||||
@SerializedName("disableAprilFools")
|
||||
private final BooleanProperty disableAprilFools = new SimpleBooleanProperty(false);
|
||||
|
||||
/// Returns the April Fools disable property.
|
||||
public BooleanProperty disableAprilFoolsProperty() {
|
||||
return disableAprilFools;
|
||||
}
|
||||
|
||||
/// The common Minecraft directory selection mode.
|
||||
@SerializedName("commonDirectoryType")
|
||||
private final ObjectProperty<EnumCommonDirectory> commonDirectoryType = new RawPreservingObjectProperty<>(EnumCommonDirectory.DEFAULT);
|
||||
|
||||
@@ -8,7 +8,6 @@ import com.jfoenix.validation.base.ValidatorBase;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ReadOnlyStringProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
@@ -22,6 +21,7 @@ import javafx.util.Duration;
|
||||
import org.jackhuang.hmcl.Launcher;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.game.GameInstanceID;
|
||||
import org.jackhuang.hmcl.game.GameJavaVersion;
|
||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||
import org.jackhuang.hmcl.game.LauncherHelper;
|
||||
import org.jackhuang.hmcl.game.ModpackHelper;
|
||||
@@ -45,8 +45,6 @@ import org.jackhuang.hmcl.ui.instances.Instances;
|
||||
import org.jackhuang.hmcl.upgrade.IntegrityChecker;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||
import org.jackhuang.hmcl.util.i18n.SupportedLocale;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.platform.Architecture;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
@@ -57,7 +55,6 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -78,8 +75,6 @@ public final class Controllers {
|
||||
public static final String JAVA_INTERPRETED_MODE_TIP = "javaInterpretedMode";
|
||||
/// The shown-tip key for the software-rendering warning.
|
||||
public static final String SOFTWARE_RENDERING = "softwareRendering";
|
||||
/// The shown-tip key storing the year of the April Fools prompt.
|
||||
public static final String APRIL_FOOLS = "aprilFools";
|
||||
|
||||
/// The coordinator for the main window's scene graph and navigation stack.
|
||||
private static @Nullable Decorator decorator;
|
||||
@@ -259,8 +254,6 @@ public final class Controllers {
|
||||
public static void initialize(Stage stage) {
|
||||
LOG.info("Start initializing application");
|
||||
|
||||
LOG.info("April Fools: " + AprilFools.isEnabled());
|
||||
|
||||
if (System.getProperty("prism.lcdtext") == null) {
|
||||
@Nullable String fontAntiAliasing = SettingsManager.userSettings().fontAntiAliasingProperty().get();
|
||||
if ("lcd".equalsIgnoreCase(fontAntiAliasing)) {
|
||||
@@ -280,7 +273,10 @@ public final class Controllers {
|
||||
// Dedicated server client: always use the fixed default cache directory.
|
||||
settings().commonDirectoryTypeProperty().set(EnumCommonDirectory.DEFAULT);
|
||||
|
||||
Lang.thread(JavaManager::initialize, "Search Java", true);
|
||||
Lang.thread(() -> {
|
||||
JavaManager.initialize();
|
||||
FXUtils.runInFX(Controllers::tryEnsureRecommendedMojangJava);
|
||||
}, "Search Java", true);
|
||||
|
||||
StyleSheets.init(mainScene);
|
||||
|
||||
@@ -363,54 +359,42 @@ public final class Controllers {
|
||||
Controllers.dialog(agreementPane);
|
||||
}
|
||||
|
||||
aprilFools:
|
||||
if (AprilFools.isEnabled()) {
|
||||
int currentYear = LocalDate.now().getYear();
|
||||
if (state().getShownTips().get(APRIL_FOOLS) instanceof Number year && year.intValue() >= currentYear)
|
||||
break aprilFools;
|
||||
tryInstallBundledModpack(GameDirectoryManager.getSelectedRepository());
|
||||
}
|
||||
|
||||
if (!I18n.getLocale().getLocale().getLanguage().equals("zh"))
|
||||
break aprilFools;
|
||||
/// Downloads Mojang Runtime Java 25 when missing on supported platforms.
|
||||
///
|
||||
/// No confirm dialog: if already installed, returns quietly; otherwise shows a progress dialog.
|
||||
private static void tryEnsureRecommendedMojangJava() {
|
||||
org.jackhuang.hmcl.util.platform.Platform platform =
|
||||
org.jackhuang.hmcl.util.platform.Platform.SYSTEM_PLATFORM;
|
||||
GameJavaVersion target = GameJavaVersion.JAVA_25;
|
||||
|
||||
@Nullable SupportedLocale lzh = SupportedLocale.getSupportedLocales().stream()
|
||||
.filter(locale -> "lzh".equals(locale.getName()))
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (lzh == null) {
|
||||
LOG.warning("No supported locale found for lzh");
|
||||
break aprilFools;
|
||||
}
|
||||
|
||||
Runnable updateShowTips = () -> state().getShownTips().put(APRIL_FOOLS, currentYear);
|
||||
|
||||
Controllers.confirmWithCountdown(i18n("launcher.april_fools.switch_lzh"), null, 10,
|
||||
MessageType.QUESTION, () -> {
|
||||
Controllers.confirm(i18n("launcher.april_fools.switch_lzh.confirm"), null, MessageType.QUESTION, () -> {
|
||||
LOG.info("Switching locale to " + lzh);
|
||||
|
||||
updateShowTips.run();
|
||||
settings().languageProperty().set(lzh);
|
||||
|
||||
Controllers.onApplicationStop();
|
||||
|
||||
try {
|
||||
FileSaver.waitForAllSaves();
|
||||
} catch (InterruptedException ignored) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
try {
|
||||
Restarter.restartSelf();
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to restart self", e);
|
||||
}
|
||||
|
||||
Platform.exit();
|
||||
}, updateShowTips);
|
||||
}, updateShowTips);
|
||||
if (!GameJavaVersion.getSupportedVersions(platform).contains(target)) {
|
||||
return;
|
||||
}
|
||||
if (JavaManager.getMojangJavaPlatform(platform) == null) {
|
||||
return;
|
||||
}
|
||||
if (JavaManager.REPOSITORY.isInstalled(platform, target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tryInstallBundledModpack(GameDirectoryManager.getSelectedRepository());
|
||||
LOG.info("Recommended Mojang Java " + target.majorVersion()
|
||||
+ " (" + target.component() + ") missing; starting automatic download");
|
||||
|
||||
Controllers.taskDialog(
|
||||
JavaManager.getDownloadJavaTask(DownloadProviders.getDownloadProvider(), platform, target)
|
||||
.whenComplete(Schedulers.javafx(), (result, exception) -> {
|
||||
if (exception != null) {
|
||||
LOG.warning("Failed to download recommended Mojang Java " + target.majorVersion(), exception);
|
||||
} else {
|
||||
LOG.info("Installed Mojang Java " + target.majorVersion() + " at " + result.getBinary());
|
||||
}
|
||||
}),
|
||||
i18n("java.download"),
|
||||
TaskCancellationAction.NO_CANCEL
|
||||
);
|
||||
}
|
||||
|
||||
/// Installs the package found by [Metadata#findBundledModpackFile()] asynchronously, if present.
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
|
||||
package org.jackhuang.hmcl.ui;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXListView;
|
||||
import com.jfoenix.controls.JFXSpinner;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.control.Control;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.SkinBase;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
||||
import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
|
||||
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||
import org.jackhuang.hmcl.util.TaskManager;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
/// Displays active tasks and pending completion actions.
|
||||
@NotNullByDefault
|
||||
public final class TaskManagerPage extends Control implements DecoratorPage {
|
||||
|
||||
/// Navigation metadata for the task list.
|
||||
private final ReadOnlyObjectWrapper<State> state =
|
||||
new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("task.list")));
|
||||
|
||||
/// Creates a page backed by the application-wide task manager.
|
||||
public TaskManagerPage() {
|
||||
getStyleClass().add("content-background");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyObjectProperty<State> stateProperty() {
|
||||
return state.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SkinBase<TaskManagerPage> createDefaultSkin() {
|
||||
return new Skin(this);
|
||||
}
|
||||
|
||||
/// Binds a list view to active dialogs and pending completion actions.
|
||||
@NotNullByDefault
|
||||
private static final class Skin extends SkinBase<TaskManagerPage> {
|
||||
|
||||
/// Creates the task list and its empty-state message.
|
||||
private Skin(TaskManagerPage control) {
|
||||
super(control);
|
||||
StackPane container = new StackPane();
|
||||
container.setPadding(new Insets(10));
|
||||
container.getStyleClass().add("notice-pane");
|
||||
|
||||
ComponentList root = new ComponentList();
|
||||
root.getStyleClass().add("no-padding");
|
||||
|
||||
JFXListView<TaskExecutorDialogPane> list = new JFXListView<>();
|
||||
list.setItems(TaskManager.getInstance().getTasks());
|
||||
list.setCellFactory(view -> new TaskCell());
|
||||
list.setPadding(Insets.EMPTY);
|
||||
list.getStyleClass().add("no-horizontal-scrollbar");
|
||||
FXUtils.ignoreEvent(list, KeyEvent.KEY_PRESSED, event -> event.getCode() == KeyCode.ESCAPE);
|
||||
|
||||
StackPane placeholder = new StackPane(new Label(i18n("task.list.empty")));
|
||||
placeholder.getStyleClass().add("notice-pane");
|
||||
list.setPlaceholder(placeholder);
|
||||
|
||||
ComponentList.setVgrow(list, Priority.ALWAYS);
|
||||
root.getContent().setAll(list);
|
||||
container.getChildren().setAll(root);
|
||||
getChildren().setAll(container);
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays a live task title and an action to restore progress or continue a completed task.
|
||||
@NotNullByDefault
|
||||
private static final class TaskCell extends ListCell<@Nullable TaskExecutorDialogPane> {
|
||||
|
||||
/// The list item whose title is bound to the current dialog.
|
||||
private final TwoLineListItem content = new TwoLineListItem();
|
||||
|
||||
/// The row's shared hover and ripple feedback.
|
||||
private final RipplerContainer graphic;
|
||||
|
||||
/// Centers running and pending indicators in a fixed-size slot to keep row titles aligned.
|
||||
private final StackPane statusIcon = new StackPane();
|
||||
|
||||
/// Restores progress or invokes the pending completion action.
|
||||
private final JFXButton actionButton = FXUtils.newToggleButton4(SVG.ARROW_FORWARD);
|
||||
|
||||
/// Describes the current row action.
|
||||
private final Tooltip actionTooltip = new Tooltip();
|
||||
|
||||
/// Creates a row that activates the current task through its body or trailing action.
|
||||
private TaskCell() {
|
||||
content.getStyleClass().add("md-list-cell");
|
||||
content.setPadding(new Insets(8));
|
||||
|
||||
statusIcon.setMinSize(32, 32);
|
||||
statusIcon.setPrefSize(32, 32);
|
||||
statusIcon.setMaxSize(32, 32);
|
||||
statusIcon.setMouseTransparent(true);
|
||||
content.setMinWidth(0);
|
||||
TwoLineListItem.setMargin(statusIcon, new Insets(0, 8, 0, 0));
|
||||
content.setLeading(statusIcon);
|
||||
|
||||
FXUtils.installFastTooltip(actionButton, actionTooltip);
|
||||
actionButton.setOnAction(event -> activateTask());
|
||||
TwoLineListItem.setMargin(actionButton, new Insets(0, 0, 0, 8));
|
||||
content.setTrailing(actionButton);
|
||||
|
||||
graphic = new RipplerContainer(content);
|
||||
graphic.setCursor(Cursor.HAND);
|
||||
graphic.setOnAction(event -> activateTask());
|
||||
}
|
||||
|
||||
/// Invokes a pending action or restores the current task's progress dialog.
|
||||
private void activateTask() {
|
||||
@Nullable TaskExecutorDialogPane pane = getItem();
|
||||
if (pane != null) {
|
||||
if (pane.pendingActionProperty().get() != null)
|
||||
pane.runPendingAction();
|
||||
else
|
||||
pane.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/// Rebinds a reused cell and updates its progress or pending-action presentation.
|
||||
@Override
|
||||
protected void updateItem(@Nullable TaskExecutorDialogPane pane, boolean empty) {
|
||||
super.updateItem(pane, empty);
|
||||
graphic.resetFeedback();
|
||||
content.titleProperty().unbind();
|
||||
content.setSubtitle(null);
|
||||
if (empty || pane == null) {
|
||||
content.setTitle("");
|
||||
statusIcon.getChildren().clear();
|
||||
setGraphic(null);
|
||||
} else {
|
||||
content.titleProperty().bind(pane.titleProperty());
|
||||
@Nullable TaskExecutorDialogPane.PendingAction action = pane.pendingActionProperty().get();
|
||||
actionButton.getStyleClass().removeAll("toggle-icon4", "jfx-button-border");
|
||||
if (action != null) {
|
||||
actionButton.getStyleClass().add("jfx-button-border");
|
||||
statusIcon.getChildren().setAll(SVG.PENDING.createIcon(24));
|
||||
content.setSubtitle(action.description());
|
||||
actionButton.setGraphic(null);
|
||||
actionButton.setText(action.text());
|
||||
actionButton.setAccessibleText(action.text());
|
||||
actionTooltip.setText(action.text());
|
||||
} else {
|
||||
actionButton.getStyleClass().add("toggle-icon4");
|
||||
if (pane.queuedProperty().get()) {
|
||||
statusIcon.getChildren().setAll(SVG.PENDING.createIcon(24));
|
||||
content.setSubtitle(i18n("task.queued"));
|
||||
} else if (statusIcon.getChildren().isEmpty() || !(statusIcon.getChildren().get(0) instanceof JFXSpinner)) {
|
||||
JFXSpinner spinner = new JFXSpinner();
|
||||
spinner.setRadius(12);
|
||||
statusIcon.getChildren().setAll(spinner);
|
||||
}
|
||||
actionButton.setGraphic(SVG.ARROW_FORWARD.createIcon());
|
||||
actionButton.setText(null);
|
||||
actionButton.setAccessibleText(i18n("task.show"));
|
||||
actionTooltip.setText(i18n("task.show"));
|
||||
}
|
||||
setGraphic(graphic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
package org.jackhuang.hmcl.ui.decorator;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXSpinner;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
@@ -24,7 +23,6 @@ import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.scene.shape.SVGPath;
|
||||
import javafx.util.Duration;
|
||||
import org.glavo.monetfx.ColorRole;
|
||||
import org.glavo.monetfx.ColorScheme;
|
||||
@@ -33,13 +31,11 @@ import org.jackhuang.hmcl.ui.*;
|
||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||
import org.jackhuang.hmcl.ui.wizard.Navigation;
|
||||
import org.jackhuang.hmcl.util.TaskManager;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.animation.TransitionPane.DEFAULT_DURATION;
|
||||
import static org.jackhuang.hmcl.ui.animation.TransitionPane.DEFAULT_INTERPOLATOR;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
/// Renders the clipped background, title bar, and navigation content owned by a [Decorator].
|
||||
@NotNullByDefault
|
||||
@@ -170,7 +166,7 @@ final class MainWindowPane extends StackPane {
|
||||
return backgroundNode;
|
||||
}
|
||||
|
||||
/// Creates the task, minimize, and application-close buttons.
|
||||
/// Creates the minimize and application-close buttons.
|
||||
///
|
||||
/// @return a size-limited top-right button row
|
||||
private HBox createWindowButtons() {
|
||||
@@ -179,34 +175,6 @@ final class MainWindowPane extends StackPane {
|
||||
decorator.capableDraggingWindow(buttons);
|
||||
buttons.setMaxSize(Region.USE_PREF_SIZE, 40);
|
||||
|
||||
JFXButton tasksButton = new JFXButton();
|
||||
tasksButton.setFocusTraversable(false);
|
||||
tasksButton.setAccessibleText(i18n("task.list"));
|
||||
tasksButton.getStyleClass().add("jfx-decorator-button");
|
||||
tasksButton.setOnAction(event -> {
|
||||
if (!(decorator.getNavigator().getCurrentPage() instanceof TaskManagerPage))
|
||||
Controllers.navigate(new TaskManagerPage());
|
||||
});
|
||||
decorator.forbidDraggingWindow(tasksButton);
|
||||
|
||||
SVGPath tasksEmptyIcon = SVG.LIST_ALT.createIcon(Themes.titleFillProperty());
|
||||
|
||||
holder.onWeakChangeAndOperate(TaskManager.getInstance().statusProperty(), status -> {
|
||||
switch (status) {
|
||||
case IDLE -> tasksButton.setGraphic(tasksEmptyIcon);
|
||||
case PENDING -> tasksButton.setGraphic(SVG.PENDING.createIcon(Themes.titleFillProperty()));
|
||||
case RUNNING -> {
|
||||
JFXSpinner tasksSpinner = new JFXSpinner();
|
||||
tasksSpinner.getStyleClass().add("small-spinner");
|
||||
tasksSpinner.setRadius(9);
|
||||
tasksSpinner.setMouseTransparent(true);
|
||||
FXUtils.setLimitWidth(tasksSpinner, 20);
|
||||
FXUtils.setLimitHeight(tasksSpinner, 20);
|
||||
tasksButton.setGraphic(tasksSpinner);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JFXButton minimizeButton = new JFXButton();
|
||||
minimizeButton.setFocusTraversable(false);
|
||||
minimizeButton.setGraphic(SVG.MINIMIZE_CENTER.createIcon(Themes.titleFillProperty()));
|
||||
@@ -221,7 +189,7 @@ final class MainWindowPane extends StackPane {
|
||||
closeButton.setOnAction(event -> decorator.closeWindow());
|
||||
decorator.forbidDraggingWindow(closeButton);
|
||||
|
||||
buttons.getChildren().setAll(tasksButton, minimizeButton, closeButton);
|
||||
buttons.getChildren().setAll(minimizeButton, closeButton);
|
||||
return buttons;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,6 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
|
||||
ALL,
|
||||
RELEASE,
|
||||
SNAPSHOTS,
|
||||
APRIL_FOOLS,
|
||||
OLD
|
||||
}
|
||||
|
||||
@@ -234,13 +233,8 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
|
||||
imageView.setImage(GameInstanceIconType.GRASS.getIcon());
|
||||
}
|
||||
case SNAPSHOT, PENDING, UNOBFUSCATED -> {
|
||||
if (versionType == ComponentRemoteVersion.Type.SNAPSHOT && gameVersion.isAprilFools()) {
|
||||
tags.add(new Tag(i18n("instance.game.april_fools")));
|
||||
imageView.setImage(GameInstanceIconType.APRIL_FOOLS.getIcon());
|
||||
} else {
|
||||
tags.add(new Tag(i18n("instance.game.snapshot")));
|
||||
imageView.setImage(GameInstanceIconType.COMMAND.getIcon());
|
||||
}
|
||||
tags.add(new Tag(i18n("instance.game.snapshot")));
|
||||
imageView.setImage(GameInstanceIconType.COMMAND.getIcon());
|
||||
}
|
||||
default -> {
|
||||
tags.add(new Tag(i18n("instance.game.old")));
|
||||
@@ -334,7 +328,6 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
|
||||
VersionTypeFilter.ALL,
|
||||
VersionTypeFilter.RELEASE,
|
||||
VersionTypeFilter.SNAPSHOTS,
|
||||
VersionTypeFilter.APRIL_FOOLS,
|
||||
VersionTypeFilter.OLD
|
||||
);
|
||||
categoryField.getSelectionModel().select(VersionTypeFilter.RELEASE);
|
||||
@@ -461,8 +454,6 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
|
||||
case SNAPSHOTS -> versionType == ComponentRemoteVersion.Type.SNAPSHOT
|
||||
|| versionType == ComponentRemoteVersion.Type.PENDING
|
||||
|| versionType == ComponentRemoteVersion.Type.UNOBFUSCATED;
|
||||
case APRIL_FOOLS -> versionType == ComponentRemoteVersion.Type.SNAPSHOT
|
||||
&& it.getGameVersion().isAprilFools();
|
||||
case OLD -> versionType == ComponentRemoteVersion.Type.OLD;
|
||||
// case ALL,
|
||||
default -> true;
|
||||
|
||||
@@ -45,7 +45,6 @@ public class GameInstanceIconDialog extends JFXDialogLayout {
|
||||
createIcon(GameInstanceIconType.CHEST),
|
||||
createIcon(GameInstanceIconType.CHICKEN),
|
||||
createIcon(GameInstanceIconType.COMMAND),
|
||||
createIcon(GameInstanceIconType.APRIL_FOOLS),
|
||||
createIcon(GameInstanceIconType.OPTIFINE),
|
||||
createIcon(GameInstanceIconType.CRAFT_TABLE),
|
||||
createIcon(GameInstanceIconType.FABRIC),
|
||||
|
||||
@@ -82,14 +82,6 @@ public final class SettingsPage extends ScrollPane {
|
||||
{
|
||||
ComponentList miscPaneList = new ComponentList();
|
||||
|
||||
{
|
||||
LineSwitch disableAprilFools = new LineSwitch();
|
||||
disableAprilFools.setTitle(i18n("settings.launcher.disable_april_fools"));
|
||||
disableAprilFools.setSubtitle(i18n("settings.take_effect_after_restart"));
|
||||
disableAprilFools.selectedProperty().bindBidirectional(settings().disableAprilFoolsProperty());
|
||||
miscPaneList.getContent().add(disableAprilFools);
|
||||
}
|
||||
|
||||
{
|
||||
BorderPane debugPane = new BorderPane();
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import org.jackhuang.hmcl.util.i18n.LocaleUtils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.SettingsManager.settings;
|
||||
|
||||
/// April Fools' Day utilities.
|
||||
///
|
||||
/// This class provides methods to check if it is April Fools' Day or near April Fools' Day.
|
||||
/// It also provides a method to check if April Fools is enabled.
|
||||
///
|
||||
/// @author Glavo
|
||||
public final class AprilFools {
|
||||
|
||||
private static final boolean ENABLED;
|
||||
|
||||
static {
|
||||
var date = LocalDate.now();
|
||||
|
||||
// Some countries/regions may oppose April Fools' Day for various reasons.
|
||||
// Therefore, we use a regional whitelist to avoid risks.
|
||||
// Currently, we have only listed a limited set of countries/regions for testing.
|
||||
// We will investigate more countries/regions in the future to expand this list.
|
||||
boolean supportedRegion = List.of(
|
||||
"CN", "TW", "HK", "MO", "JP", "KR", "VN", "SG", "MY",
|
||||
"ES", "DE", "FR", "GB", "RU", "UA", "US"
|
||||
).contains(LocaleUtils.SYSTEM_DEFAULT.getCountry());
|
||||
|
||||
boolean aprilFoolsMode;
|
||||
String value = System.getProperty("hmcl.april_fools", System.getenv("HMCL_APRIL_FOOLS"));
|
||||
if ("true".equalsIgnoreCase(value))
|
||||
aprilFoolsMode = true;
|
||||
else if ("false".equalsIgnoreCase(value) || !supportedRegion)
|
||||
aprilFoolsMode = false;
|
||||
else
|
||||
aprilFoolsMode = date.getMonth() == Month.APRIL && date.getDayOfMonth() == 1;
|
||||
|
||||
ENABLED = aprilFoolsMode && !settings().disableAprilFoolsProperty().get();
|
||||
}
|
||||
|
||||
/// Whether April Fools is enabled.
|
||||
///
|
||||
/// This method returns true if April Fools is enabled.
|
||||
public static boolean isEnabled() {
|
||||
return ENABLED;
|
||||
}
|
||||
|
||||
private AprilFools() {
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 768 B |
|
Before Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 677 B |
|
Before Width: | Height: | Size: 656 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 468 B |
|
Before Width: | Height: | Size: 689 B |
|
Before Width: | Height: | Size: 276 B |
|
Before Width: | Height: | Size: 300 B |
|
Before Width: | Height: | Size: 236 B |
|
Before Width: | Height: | Size: 279 B |
|
Before Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 306 B |
|
Before Width: | Height: | Size: 185 B |
|
Before Width: | Height: | Size: 193 B |
|
Before Width: | Height: | Size: 222 B |
|
Before Width: | Height: | Size: 248 B |
|
Before Width: | Height: | Size: 253 B |
|
Before Width: | Height: | Size: 274 B |
|
Before Width: | Height: | Size: 602 B |
|
Before Width: | Height: | Size: 1003 B |
|
Before Width: | Height: | Size: 374 B |
|
Before Width: | Height: | Size: 627 B |
@@ -782,7 +782,6 @@ instance.empty.launch=No available instances.\nInstall the bundled server modpac
|
||||
instance.empty.launch.goto_download=Install Modpack
|
||||
instance.empty.hint=There are no Minecraft instances here.\nYou can try switching to another game directory or clicking here to install the server modpack.
|
||||
instance.game.all=All
|
||||
instance.game.april_fools=April Fools
|
||||
instance.game.old=Historical
|
||||
instance.game.release=Release
|
||||
instance.game.releases=Releases
|
||||
@@ -911,8 +910,6 @@ launcher.agreement=ToS and EULA
|
||||
launcher.agreement.accept=Accept
|
||||
launcher.agreement.decline=Decline
|
||||
launcher.agreement.hint=You must agree to the EULA to use this software.
|
||||
launcher.april_fools.switch_lzh=HMCL Launcher now supports Classical Chinese, do you want to switch to Classical Chinese mode?\nYou can switch back to English in "置設 → 貫用 → 文".
|
||||
launcher.april_fools.switch_lzh.confirm=Confirm switching to Classical Chinese mode?\nClick "OK" to exit HMCL and restart it in Classical Chinese mode; click "Cancel" to keep the current language and enter HMCL homepage.
|
||||
launcher.background=Background Image
|
||||
launcher.background.choose=Choose background image
|
||||
launcher.background.builtin=Built-in
|
||||
@@ -1538,7 +1535,6 @@ settings.launcher.brightness.auto=Follow System Settings
|
||||
settings.launcher.brightness.dark=Dark Mode
|
||||
settings.launcher.brightness.light=Light Mode
|
||||
settings.launcher.debug=Debug
|
||||
settings.launcher.disable_april_fools=Do not enable April Fools features
|
||||
settings.launcher.disable_auto_game_options=Do not switch game language
|
||||
settings.launcher.download=Download
|
||||
settings.launcher.download.threads=Download Threads
|
||||
@@ -1643,8 +1639,6 @@ system.architecture=Architecture
|
||||
system.operating_system=Operating System
|
||||
|
||||
task.background=Run in Background
|
||||
task.list=Tasks
|
||||
task.list.empty=No tasks
|
||||
task.queued=Waiting for other tasks to finish
|
||||
task.show=Show Progress
|
||||
|
||||
|
||||
@@ -602,7 +602,6 @@ instance.empty.add=裝伺服器整合包
|
||||
# instance.empty.launch.goto_download=
|
||||
instance.empty.hint=無畢裝者。\n君且更他戲夾,抑擊斯以裝伺服器整合包。
|
||||
instance.game.all=全覽
|
||||
instance.game.april_fools=愚人節
|
||||
instance.game.old=古典版
|
||||
instance.game.release=當版
|
||||
instance.game.releases=當版
|
||||
@@ -731,8 +730,6 @@ launcher.agreement=客契與免責告示
|
||||
launcher.agreement.accept=許
|
||||
launcher.agreement.decline=拒
|
||||
launcher.agreement.hint=將用而須許其客契與免責告示。
|
||||
# launcher.april_fools.switch_lzh=
|
||||
# launcher.april_fools.switch_lzh.confirm=
|
||||
launcher.background=繪圖
|
||||
launcher.background.choose=擇繪圖
|
||||
# launcher.background.builtin=
|
||||
@@ -1351,7 +1348,6 @@ settings.launcher.appearance=外觀
|
||||
# settings.launcher.brightness.dark=
|
||||
# settings.launcher.brightness.light=
|
||||
settings.launcher.debug=勘誤
|
||||
# settings.launcher.disable_april_fools=
|
||||
settings.launcher.disable_auto_game_options=弗自改戲文
|
||||
settings.launcher.download=引
|
||||
settings.launcher.download.threads=綫程數
|
||||
@@ -1455,8 +1451,6 @@ system.architecture=大構
|
||||
system.operating_system=械網
|
||||
|
||||
# task.background=
|
||||
# task.list=
|
||||
# task.list.empty=
|
||||
# task.queued=
|
||||
# task.show=
|
||||
|
||||
|
||||
@@ -605,7 +605,6 @@ instance.empty.launch=没有可启动的游戏。\n请安装自带的服务器
|
||||
instance.empty.launch.goto_download=安装整合包
|
||||
instance.empty.hint=没有已安装的游戏。\n你可以切换其他游戏文件夹,或者点击此处安装服务器整合包。
|
||||
instance.game.all=全部
|
||||
instance.game.april_fools=愚人节
|
||||
instance.game.old=远古版
|
||||
instance.game.release=正式版
|
||||
instance.game.releases=正式版
|
||||
@@ -734,8 +733,6 @@ launcher.agreement=用户协议与免责声明
|
||||
launcher.agreement.accept=同意
|
||||
launcher.agreement.decline=拒绝
|
||||
launcher.agreement.hint=同意本软件的用户协议与免责声明以使用本软件。
|
||||
launcher.april_fools.switch_lzh=HMCL 启动器现已支持文言文,我们诚邀你参与体验。是否要将界面语言切换至中文 (文言)?\n在切换语言后,你可以在“置設 → 貫用 → 文”中将语言切换回中文 (简体)。
|
||||
launcher.april_fools.switch_lzh.confirm=确认切换语言?\n点击“确定”后 HMCL 将自动重启并将界面语言切换至中文 (文言);点击“取消”将继续使用中文 (简体) 进入 HMCL 主页。
|
||||
launcher.background=背景图片
|
||||
launcher.background.choose=选择背景图片
|
||||
launcher.background.builtin=内置
|
||||
@@ -1355,7 +1352,6 @@ settings.launcher.brightness.auto=跟随系统设置
|
||||
settings.launcher.brightness.dark=深色模式
|
||||
settings.launcher.brightness.light=浅色模式
|
||||
settings.launcher.debug=调试
|
||||
settings.launcher.disable_april_fools=不启用愚人节功能
|
||||
settings.launcher.disable_auto_game_options=不自动切换游戏语言
|
||||
settings.launcher.download=下载
|
||||
settings.launcher.download.threads=下载线程数
|
||||
@@ -1460,8 +1456,6 @@ system.architecture=架构
|
||||
system.operating_system=操作系统
|
||||
|
||||
task.background=在后台运行
|
||||
task.list=任务列表
|
||||
task.list.empty=当前没有任务。
|
||||
task.queued=等待其他任务完成
|
||||
task.show=显示进度
|
||||
|
||||
|
||||
@@ -599,7 +599,6 @@ instance.empty.launch=沒有可啟動的遊戲。\n請安裝內建的伺服器
|
||||
instance.empty.launch.goto_download=安裝整合包
|
||||
instance.empty.hint=沒有已安裝的遊戲。\n你可以切換其他遊戲目錄,或者點擊此處安裝伺服器整合包。
|
||||
instance.game.all=全部
|
||||
instance.game.april_fools=愚人節
|
||||
instance.game.old=遠古版
|
||||
instance.game.release=正式版
|
||||
instance.game.releases=正式版
|
||||
@@ -728,8 +727,6 @@ launcher.agreement=使用者協議與免責宣告
|
||||
launcher.agreement.accept=同意
|
||||
launcher.agreement.decline=拒絕
|
||||
launcher.agreement.hint=同意本軟體的使用者協議與免責宣告以使用本軟體。
|
||||
launcher.april_fools.switch_lzh=HMCL 啟動器現已支援文言文,我們誠邀你參與體驗。是否要將介面語言切換至中文 (文言)?\n在切換語言後,你可以在「置設 → 貫用 → 文」中將語言切換回中文 (繁體)。
|
||||
launcher.april_fools.switch_lzh.confirm=確認切換語言?\n點擊「確定」後 HMCL 將自動重新啟動並將介面語言切換至中文 (文言);點擊「取消」將繼續使用中文 (繁體) 進入 HMCL 主頁。
|
||||
launcher.background=背景圖片
|
||||
launcher.background.choose=選取背景圖片
|
||||
launcher.background.builtin=內建
|
||||
@@ -1349,7 +1346,6 @@ settings.launcher.brightness.auto=跟隨系統設定
|
||||
settings.launcher.brightness.dark=深色模式
|
||||
settings.launcher.brightness.light=淺色模式
|
||||
settings.launcher.debug=除錯
|
||||
settings.launcher.disable_april_fools=不啟用愚人節功能
|
||||
settings.launcher.disable_auto_game_options=不自動切換遊戲語言
|
||||
settings.launcher.download=下載
|
||||
settings.launcher.download.threads=下載執行緒數
|
||||
@@ -1454,8 +1450,6 @@ system.architecture=架構
|
||||
system.operating_system=作業系統
|
||||
|
||||
task.background=在背景執行
|
||||
task.list=任務列表
|
||||
task.list.empty=目前沒有任務。
|
||||
task.queued=等待其他任務完成
|
||||
task.show=顯示進度
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
|
||||
package org.jackhuang.hmcl.ui.construct;
|
||||
|
||||
import com.jfoenix.controls.JFXSpinner;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.ButtonBase;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.shape.SVGPath;
|
||||
import org.jackhuang.hmcl.setting.LauncherSettings;
|
||||
import org.jackhuang.hmcl.setting.SettingsManager;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
@@ -17,8 +15,6 @@ import org.jackhuang.hmcl.task.TaskExecutor;
|
||||
import org.jackhuang.hmcl.task.TaskListener;
|
||||
import org.jackhuang.hmcl.ui.Controllers;
|
||||
import org.jackhuang.hmcl.ui.DialogUtils;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.ui.TaskManagerPage;
|
||||
import org.jackhuang.hmcl.ui.decorator.Decorator;
|
||||
import org.jackhuang.hmcl.util.TaskCancellationAction;
|
||||
import org.jackhuang.hmcl.util.TaskManager;
|
||||
@@ -34,7 +30,6 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -73,7 +68,7 @@ final class TaskExecutorDialogPaneTest {
|
||||
field.set(null, previousSettings);
|
||||
}
|
||||
|
||||
/// Verifies dialog reuse and the task button's idle, running, and pending presentations.
|
||||
/// Verifies dialog reuse and TaskManager status transitions without a task-list chrome button.
|
||||
@Test
|
||||
void restoresThroughMainWindow() throws Exception {
|
||||
onFxThread(() -> {
|
||||
@@ -86,25 +81,17 @@ final class TaskExecutorDialogPaneTest {
|
||||
TaskExecutorDialogPane pane = new TaskExecutorDialogPane(TaskCancellationAction.NORMAL);
|
||||
TaskExecutorDialogPane second = new TaskExecutorDialogPane(TaskCancellationAction.NORMAL);
|
||||
try {
|
||||
ButtonBase tasksButton = decorator.getRoot().lookupAll(".jfx-decorator-button").stream()
|
||||
.filter(node -> i18n("task.list").equals(node.getAccessibleText()))
|
||||
.map(ButtonBase.class::cast).findFirst().orElseThrow();
|
||||
Node icon = Objects.requireNonNull(tasksButton.getGraphic());
|
||||
ControlledExecutor executor = new ControlledExecutor();
|
||||
pane.setExecutor(executor, false);
|
||||
executor.start();
|
||||
Controllers.dialog(pane);
|
||||
assertEquals(TaskManager.Status.IDLE, TaskManager.getInstance().statusProperty().get());
|
||||
assertSame(icon, tasksButton.getGraphic());
|
||||
Node progress = pane.getCenter();
|
||||
pane.runInBackground();
|
||||
assertEquals(TaskManager.Status.RUNNING, TaskManager.getInstance().statusProperty().get());
|
||||
Node spinner = Objects.requireNonNull(tasksButton.getGraphic());
|
||||
assertInstanceOf(JFXSpinner.class, spinner);
|
||||
pane.restore();
|
||||
pane.restore();
|
||||
assertEquals(TaskManager.Status.IDLE, TaskManager.getInstance().statusProperty().get());
|
||||
assertSame(icon, tasksButton.getGraphic());
|
||||
assertTrue(DialogUtils.isShowing(pane));
|
||||
assertSame(progress, pane.getCenter());
|
||||
@Nullable JFXDialogPane stack = (JFXDialogPane) pane.getProperties()
|
||||
@@ -119,38 +106,26 @@ final class TaskExecutorDialogPaneTest {
|
||||
secondExecutor.start();
|
||||
Controllers.dialog(second);
|
||||
second.runInBackground();
|
||||
Node nextSpinner = Objects.requireNonNull(tasksButton.getGraphic());
|
||||
assertInstanceOf(JFXSpinner.class, nextSpinner);
|
||||
assertNotSame(spinner, nextSpinner);
|
||||
pane.runInBackground();
|
||||
pane.restore();
|
||||
assertEquals(TaskManager.Status.RUNNING, TaskManager.getInstance().statusProperty().get());
|
||||
assertSame(nextSpinner, tasksButton.getGraphic());
|
||||
|
||||
AtomicInteger actions = new AtomicInteger();
|
||||
pane.runInBackground();
|
||||
assertFalse(pane.runOrDeferCompletionAction("Install", "Ready to install", actions::incrementAndGet));
|
||||
assertEquals(TaskManager.Status.RUNNING, TaskManager.getInstance().statusProperty().get());
|
||||
assertSame(nextSpinner, tasksButton.getGraphic());
|
||||
second.restore();
|
||||
assertEquals(TaskManager.Status.PENDING, TaskManager.getInstance().statusProperty().get());
|
||||
SVGPath pendingIcon = assertInstanceOf(SVGPath.class, tasksButton.getGraphic());
|
||||
assertEquals(SVG.PENDING.getPath(), pendingIcon.getContent());
|
||||
second.runInBackground();
|
||||
assertEquals(TaskManager.Status.RUNNING, TaskManager.getInstance().statusProperty().get());
|
||||
Node resumedSpinner = assertInstanceOf(JFXSpinner.class, tasksButton.getGraphic());
|
||||
assertNotSame(nextSpinner, resumedSpinner);
|
||||
pane.runPendingAction();
|
||||
assertEquals(1, actions.get());
|
||||
assertEquals(TaskManager.Status.RUNNING, TaskManager.getInstance().statusProperty().get());
|
||||
assertSame(resumedSpinner, tasksButton.getGraphic());
|
||||
|
||||
assertFalse(second.runOrDeferCompletionAction("Install", "Ready to install", actions::incrementAndGet));
|
||||
assertEquals(TaskManager.Status.PENDING, TaskManager.getInstance().statusProperty().get());
|
||||
assertEquals(SVG.PENDING.getPath(), assertInstanceOf(SVGPath.class, tasksButton.getGraphic()).getContent());
|
||||
second.setExecutor(null);
|
||||
assertEquals(TaskManager.Status.IDLE, TaskManager.getInstance().statusProperty().get());
|
||||
assertSame(icon, tasksButton.getGraphic());
|
||||
} finally {
|
||||
DialogUtils.close(pane);
|
||||
pane.setExecutor(null);
|
||||
@@ -351,15 +326,10 @@ final class TaskExecutorDialogPaneTest {
|
||||
});
|
||||
}
|
||||
|
||||
/// Verifies a visible task list switches from progress to a retained, single-use install action.
|
||||
/// Verifies a background task retains a single-use install action until runPendingAction.
|
||||
@Test
|
||||
void backgroundCompletionWaitsForInstallAction() throws Exception {
|
||||
AtomicInteger installations = new AtomicInteger();
|
||||
TaskManagerPage page = onFxThread(() -> {
|
||||
TaskManagerPage result = new TaskManagerPage();
|
||||
new Scene(result, 600, 400);
|
||||
return result;
|
||||
});
|
||||
TaskExecutorDialogPane pane = onFxThread(() -> {
|
||||
TaskExecutorDialogPane dialog = new TaskExecutorDialogPane(TaskCancellationAction.NORMAL);
|
||||
dialog.setTitle("Example modpack");
|
||||
@@ -370,9 +340,6 @@ final class TaskExecutorDialogPaneTest {
|
||||
DialogUtils.show(container, dialog);
|
||||
executor.start();
|
||||
dialog.runInBackground();
|
||||
page.applyCss();
|
||||
page.layout();
|
||||
assertFalse(page.lookupAll(".jfx-spinner").isEmpty());
|
||||
assertFalse(dialog.runOrDeferCompletionAction(i18n("button.install"), i18n("modpack.install.ready"),
|
||||
installations::incrementAndGet));
|
||||
executor.stop(true);
|
||||
@@ -384,17 +351,7 @@ final class TaskExecutorDialogPaneTest {
|
||||
assertFalse(DialogUtils.isShowing(pane));
|
||||
assertTrue(TaskManager.getInstance().getTasks().contains(pane));
|
||||
assertEquals(TaskManager.Status.PENDING, TaskManager.getInstance().statusProperty().get());
|
||||
page.applyCss();
|
||||
page.layout();
|
||||
ButtonBase install = page.lookupAll(".jfx-button").stream()
|
||||
.filter(ButtonBase.class::isInstance)
|
||||
.map(ButtonBase.class::cast)
|
||||
.filter(button -> i18n("button.install").equals(button.getText()))
|
||||
.findFirst().orElseThrow();
|
||||
assertTrue(page.lookupAll(".label").stream().anyMatch(node -> node instanceof Label label
|
||||
&& i18n("modpack.install.ready").equals(label.getText())));
|
||||
assertTrue(page.lookupAll(".jfx-spinner").isEmpty());
|
||||
install.fire();
|
||||
assertNotNull(pane.pendingActionProperty().get());
|
||||
pane.runPendingAction();
|
||||
assertEquals(1, installations.get());
|
||||
assertNull(pane.pendingActionProperty().get());
|
||||
|
||||
@@ -18,9 +18,6 @@
|
||||
"language": {
|
||||
"type": "string"
|
||||
},
|
||||
"disableAprilFools": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"commonDirectoryType": {
|
||||
"enum": [
|
||||
"DEFAULT",
|
||||
|
||||