Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.CommandBuilder;
import org.jackhuang.hmcl.util.platform.NativeUtils;
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.SystemInfo;

Expand Down Expand Up @@ -309,4 +310,52 @@ public static void stopWithoutPlatform() {
}

public static final CrashReporter CRASH_REPORTER = new CrashReporter(true);

private static Runnable onApplicationReloadedCallback;

public static void setOnApplicationReloaded(Runnable callback) {
onApplicationReloadedCallback = callback;
}

/**
* Reload the application
*/
public static void reloadApplication() {
LOG.info("Reloading application...\n");

try {
// Reload configuration
try {
ConfigHolder.reload();
LOG.info("Configuration reloaded successfully\n");
} catch (SambaException e) {
showAlert(AlertType.WARNING, i18n("fatal.samba"));
}

// Update UI in FX thread
Platform.runLater(() -> {
try {
// Re-initialize controllers
Controllers.reload();

// Update animation settings based on new configuration
AnimationUtils.updateAnimationSettings();

// 执行重新加载后的回调函数
if (onApplicationReloadedCallback != null) {
onApplicationReloadedCallback.run();
}

LOG.info("Application reloaded successfully\n");
} catch (Exception e) {
LOG.error("Failed to reload UI", e);
showAlert(AlertType.ERROR, i18n("launcher.reload.failed"));
}
});
} catch (Exception e) {
LOG.error("Error during application reload\n", e);
showAlert(AlertType.ERROR, i18n("launcher.reload.failed"));
}
}

}
32 changes: 32 additions & 0 deletions HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,36 @@ private static GlobalConfig loadGlobalConfig() throws IOException {
return new GlobalConfig();
}

public static void reload() {
try {
// Save current configuration state
boolean wasNewlyCreated = newlyCreated;
boolean wasOwnerChanged = ownerChanged;
boolean wasUnsupportedVersion = unsupportedVersion;

// Reload configuration
configInstance = loadConfig();
if (!unsupportedVersion)
configInstance.addListener(source -> FileSaver.save(configLocation, configInstance.toJson()));

globalConfigInstance = loadGlobalConfig();
globalConfigInstance.addListener(source -> FileSaver.save(GLOBAL_CONFIG_PATH, globalConfigInstance.toJson()));

// Force update language settings
Locale.setDefault(config().getLocalization().getLocale());
I18n.setLocale(configInstance.getLocalization());

// Update log retention policy (do not reinitialize Settings to avoid duplicate initialization)
LOG.setLogRetention(globalConfig().getLogRetention());

// Restore state flags
newlyCreated = wasNewlyCreated;
ownerChanged = wasOwnerChanged;
unsupportedVersion = wasUnsupportedVersion;

LOG.info("Configuration reloaded and UI refreshed");
} catch (IOException e) {
LOG.warning("Failed to reload configuration", e);
}
}
}
81 changes: 70 additions & 11 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ public final class Controllers {
private Controllers() {
}

private static void setupFontAntialiasing() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

重载该选项没有意义,该选项只有在 JavaFX 界面显示前生效。

if (System.getProperty("prism.lcdtext") == null) {
String fontAntiAliasing = globalConfig().getFontAntiAliasing();
if ("lcd".equalsIgnoreCase(fontAntiAliasing)) {
LOG.info("Enable sub-pixel antialiasing");
System.getProperties().put("prism.lcdtext", "true");
} else if ("gray".equalsIgnoreCase(fontAntiAliasing)
|| OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && SCREEN.getOutputScaleX() > 1) {
LOG.info("Disable sub-pixel antialiasing");
System.getProperties().put("prism.lcdtext", "false");
}
}
}

public static Scene getScene() {
return scene;
}
Expand Down Expand Up @@ -187,17 +201,7 @@ public static void onApplicationStop() {
public static void initialize(Stage stage) {
LOG.info("Start initializing application");

if (System.getProperty("prism.lcdtext") == null) {
String fontAntiAliasing = globalConfig().getFontAntiAliasing();
if ("lcd".equalsIgnoreCase(fontAntiAliasing)) {
LOG.info("Enable sub-pixel antialiasing");
System.getProperties().put("prism.lcdtext", "true");
} else if ("gray".equalsIgnoreCase(fontAntiAliasing)
|| OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && SCREEN.getOutputScaleX() > 1) {
LOG.info("Disable sub-pixel antialiasing");
System.getProperties().put("prism.lcdtext", "false");
}
}
setupFontAntialiasing();

Controllers.stage = stage;

Expand Down Expand Up @@ -517,6 +521,61 @@ public static boolean isStopped() {
return decorator == null;
}

/**
* Reload UI controllers
*/
public static void reload() {
if (isStopped()) {
throw new IllegalStateException("Application has been stopped");
}

// Reinitialize all pages
rootPage = new Lazy<>(RootPage::new);
versionPage = new Lazy<>(VersionPage::new);
gameListPage = new Lazy<>(() -> {
GameListPage gameListPage = new GameListPage();
gameListPage.selectedProfileProperty().bindBidirectional(Profiles.selectedProfileProperty());
gameListPage.profilesProperty().bindContent(Profiles.profilesProperty());
FXUtils.applyDragListener(gameListPage, ModpackHelper::isFileModpackByExtension, modpacks -> {
Path modpack = modpacks.get(0);
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack"));
});
return gameListPage;
});
downloadPage = new Lazy<>(DownloadPage::new);
accountListPage = new Lazy<>(() -> {
AccountListPage accountListPage = new AccountListPage();
accountListPage.selectedAccountProperty().bindBidirectional(Accounts.selectedAccountProperty());
accountListPage.accountsProperty().bindContent(Accounts.getAccounts());
accountListPage.authServersProperty().bindContentBidirectional(config().getAuthlibInjectorServers());
return accountListPage;
});
settingsPage = new Lazy<>(LauncherSettingsPage::new);

// Apply antialiasing settings when reloading
setupFontAntialiasing();

// Update window title
if (stage != null) {
stage.setTitle(Metadata.FULL_TITLE);
}

// Reset scene and navigate back to home page
if (scene != null && decorator != null) {
scene.setRoot(decorator.getDecorator());
decorator.getDecorator().prefWidthProperty().bind(scene.widthProperty());
decorator.getDecorator().prefHeightProperty().bind(scene.heightProperty());

// Clear navigation history and navigate back to home page
if (decorator.getNavigator() != null) {
decorator.getNavigator().clear();
decorator.navigate(getRootPage());
}
}

LOG.info("UI controllers have been successfully reloaded");
}

public static void shutdown() {
rootPage = null;
versionPage = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,23 @@ private AnimationUtils() {
public static void init() {
}

private static final boolean ENABLED = !ConfigHolder.config().isAnimationDisabled();
private static final boolean PLAY_WINDOW_ANIMATION = ENABLED && !OperatingSystem.CURRENT_OS.isLinuxOrBSD();
private static boolean enabled;
private static boolean playWindowAnimation;

static {
updateAnimationSettings();
}

public static void updateAnimationSettings() {
enabled = !ConfigHolder.config().isAnimationDisabled();
playWindowAnimation = enabled && !OperatingSystem.CURRENT_OS.isLinuxOrBSD();
}

public static boolean isAnimationEnabled() {
return ENABLED;
return enabled;
}

public static boolean playWindowAnimation() {
return PLAY_WINDOW_ANIMATION;
return playWindowAnimation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ public Decorator getDecorator() {
return decorator;
}

public Navigator getNavigator() {
return navigator;
}

// ==== Background ====

//FXThread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.jackhuang.hmcl.ui.decorator;

import com.jfoenix.controls.JFXButton;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.binding.Bindings;
Expand All @@ -30,6 +31,7 @@
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.SkinBase;
import javafx.scene.control.Tooltip;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.input.MouseButton;
Expand All @@ -39,16 +41,22 @@
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

import org.jackhuang.hmcl.Launcher;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import java.util.Objects;
import org.jackhuang.hmcl.ui.animation.AnimationProducer;
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.platform.OperatingSystem;

import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;

public class DecoratorSkin extends SkinBase<Decorator> {
private final StackPane root, parent;
private final StackPane titleContainer;
Expand Down Expand Up @@ -229,6 +237,41 @@ public DecoratorSkin(Decorator control) {
buttonsContainer.setAlignment(Pos.TOP_RIGHT);
buttonsContainer.setMaxHeight(40);
{

JFXButton btnReload = new JFXButton();
btnReload.setGraphic(SVG.REFRESH.createIcon(Theme.foregroundFillBinding(), 20));
btnReload.getStyleClass().add("jfx-decorator-button");
btnReload.setTooltip(new Tooltip(i18n("button.reload")));
btnReload.setVisible(false);
btnReload.setOnMouseClicked(e -> {
Launcher.reloadApplication();
btnReload.setVisible(false);
});

// Create a generic listener to show reload button when property value changes
javafx.beans.value.ChangeListener<Object> restartButtonListener = (observable, oldValue, newValue) -> {
if (!Objects.equals(oldValue, newValue)) {
btnReload.setVisible(true);
}
};

// Listen to settings that require reload to take effect
config().localizationProperty().addListener(restartButtonListener);
globalConfig().fontAntiAliasingProperty().addListener(restartButtonListener);
config().animationDisabledProperty().addListener(restartButtonListener);

Launcher.setOnApplicationReloaded(() -> {
Platform.runLater(() -> {
config().localizationProperty().removeListener(restartButtonListener);
globalConfig().fontAntiAliasingProperty().removeListener(restartButtonListener);
config().animationDisabledProperty().removeListener(restartButtonListener);

config().localizationProperty().addListener(restartButtonListener);
globalConfig().fontAntiAliasingProperty().addListener(restartButtonListener);
config().animationDisabledProperty().addListener(restartButtonListener);
});
});

JFXButton btnHelp = new JFXButton();
btnHelp.setFocusTraversable(false);
btnHelp.setGraphic(SVG.HELP.createIcon(Theme.foregroundFillBinding(), -1));
Expand All @@ -247,7 +290,7 @@ public DecoratorSkin(Decorator control) {
btnClose.getStyleClass().add("jfx-decorator-button");
btnClose.setOnAction(e -> skinnable.close());

buttonsContainer.getChildren().setAll(btnHelp, btnMin, btnClose);
buttonsContainer.getChildren().setAll(btnReload, btnHelp, btnMin, btnClose);
}
AnchorPane layer = new AnchorPane();
layer.setPickOnBounds(false);
Expand Down
2 changes: 2 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N.properties
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ button.save_as=Save As
button.select_all=Select All
button.view=View
button.yes=Yes
button.reload=Reload

chat=Join Group Chat

Expand Down Expand Up @@ -840,6 +841,7 @@ launcher.contact=Contact Us
launcher.crash=Hello Minecraft! Launcher has encountered a fatal error! Please copy the following log and ask for help on our Discord, QQ group, GitHub, or other Minecraft forum.
launcher.crash.java_internal_error=Hello Minecraft! Launcher has encountered a fatal error because your Java is corrupted. Please uninstall your Java and download a suitable Java <a href="https://bell-sw.com/pages/downloads/#downloads">here</a>.
launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher has encountered a fatal error! Your launcher is outdated. Please update your launcher!
launcher.reload.failed=Reload Failed
launcher.update_java=Please update your Java version.

libraries.download=Downloading Libraries
Expand Down
2 changes: 2 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ button.save_as=Guardar como
button.select_all=Seleccionar todo
button.view=Vista
button.yes=Sí
button.reload=Recargar

chat=Chat de grupo

Expand Down Expand Up @@ -846,6 +847,7 @@ launcher.contact=Contacta con nosotros
launcher.crash=Hello Minecraft! Launcher ha encontrado un error fatal. Por favor, copie el siguiente registro y pida ayuda en nuestra comunidad en Discord, GitHub o Minecraft Forums.
launcher.crash.java_internal_error=Hello Minecraft! Launcher ha encontrado un error fatal porque su Java está dañado. Por favor, desinstala tu Java y descarga un Java adecuado <a href="https://bell-sw.com/pages/downloads/#downloads">aquí</a>.
launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher ha encontrado un error fatal. Su launcher está desactualizado. Por favor, ¡actualícelo!
launcher.reload.failed=Error de recarga
launcher.update_java=Por favor, actualice su versión de Java.

libraries.download=Descargando bibliotecas
Expand Down
3 changes: 3 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N_ja.properties
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ button.save_as=名前を付けて保存
button.select_all=すべて選択
button.view=読む
button.yes=はい
button.reload=再読み込み

chat=グループチャット

Expand Down Expand Up @@ -548,6 +549,7 @@ launcher.cache_directory.invalid=無効なディレクトリ。デフォルト
launcher.contact=お問い合わせ
launcher.crash=Hello Minecraft!ランチャーがクラッシュしました!次のコンテンツをコピーして、MCBBS、Baidu Tieba、GitHub、またはMinecraftForumを介してフィードバックを送信してください。
launcher.crash.hmcl_out_dated=Hello Minecraft!ランチャーがクラッシュしました!ランチャーが古くなっています。ランチャーを更新してください!
launcher.reload.failed=再読み込み失敗
launcher.update_java=Javaを更新してください。

login.empty_username=ユーザー名を設定していません!
Expand Down Expand Up @@ -870,6 +872,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=アカウント
settings.launcher.theme=テーマ
settings.launcher.title_transparent=タイトルの透明性
settings.launcher.turn_off_animations=アニメーションをオフにする(再起動後に有効になります)
settings.launcher.version_list_source=バージョンリストソース

settings.memory=ゲームメモリ
Expand Down
Loading