mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-22 10:43:57 -04:00
Merge 6cca22740fe2288cfc230fa79dfd1573fd1b206b into bd9ae189f83e33a6977bbe056774c851e96fe0a7
This commit is contained in:
commit
c97b7c0f89
@ -309,4 +309,37 @@ public final class Launcher extends Application {
|
||||
}
|
||||
|
||||
public static final CrashReporter CRASH_REPORTER = new CrashReporter(true);
|
||||
/**
|
||||
* 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();
|
||||
|
||||
LOG.info("Application reloaded successfully\n");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to reload UI", e);
|
||||
showAlert(AlertType.ERROR, i18n("error.reload_failed"));
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error during application reload\n", e);
|
||||
showAlert(AlertType.ERROR, i18n("error.reload_failed"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -209,4 +209,36 @@ public final class ConfigHolder {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -480,6 +480,58 @@ public final class Controllers {
|
||||
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);
|
||||
|
||||
// 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;
|
||||
|
@ -188,6 +188,10 @@ public class DecoratorController {
|
||||
return decorator;
|
||||
}
|
||||
|
||||
public Navigator getNavigator() {
|
||||
return navigator;
|
||||
}
|
||||
|
||||
// ==== Background ====
|
||||
|
||||
//FXThread
|
||||
|
@ -30,6 +30,7 @@ import javafx.scene.Cursor;
|
||||
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;
|
||||
@ -39,16 +40,22 @@ import javafx.scene.paint.Color;
|
||||
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;
|
||||
@ -229,6 +236,27 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
||||
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.setOnAction(e -> Launcher.reloadApplication());
|
||||
btnReload.setVisible(false);
|
||||
btnReload.managedProperty().bind(btnReload.visibleProperty());
|
||||
|
||||
// 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);
|
||||
|
||||
JFXButton btnHelp = new JFXButton();
|
||||
btnHelp.setFocusTraversable(false);
|
||||
btnHelp.setGraphic(SVG.HELP.createIcon(Theme.foregroundFillBinding(), -1));
|
||||
@ -247,7 +275,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
||||
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);
|
||||
|
@ -195,6 +195,9 @@ button.save_as=Save As
|
||||
button.select_all=Select All
|
||||
button.view=View
|
||||
button.yes=Yes
|
||||
button.reload=Reload
|
||||
reload.failed=Failed to reload HMCL
|
||||
reload.failed.title=Reload Failed
|
||||
|
||||
chat=Join Group Chat
|
||||
|
||||
|
@ -195,6 +195,9 @@ button.save_as=Guardar como
|
||||
button.select_all=Seleccionar todo
|
||||
button.view=Vista
|
||||
button.yes=Sí
|
||||
button.reload=Recargar
|
||||
reload.failed=Error al recargar HMCL
|
||||
reload.failed.title=Error de recarga
|
||||
|
||||
chat=Chat de grupo
|
||||
|
||||
|
@ -156,6 +156,9 @@ button.save_as=名前を付けて保存
|
||||
button.select_all=すべて選択
|
||||
button.view=読む
|
||||
button.yes=はい
|
||||
button.reload=再読み込み
|
||||
reload.failed=HMCLの再読み込みに失敗しました
|
||||
reload.failed.title=再読み込み失敗
|
||||
|
||||
chat=グループチャット
|
||||
|
||||
|
@ -205,6 +205,9 @@ button.save_as=另存
|
||||
button.select_all=悉擇之
|
||||
button.view=覽
|
||||
button.yes=然
|
||||
button.reload=重載
|
||||
reload.failed=重載 HMCL 失敗
|
||||
reload.failed.title=重載失敗
|
||||
|
||||
chat=會集
|
||||
|
||||
|
@ -196,6 +196,9 @@ button.save_as=Сохранить как
|
||||
button.select_all=Выбрать все
|
||||
button.view=Просмотреть
|
||||
button.yes=Да
|
||||
button.reload=Перезагрузить
|
||||
reload.failed=Не удалось перезагрузить HMCL
|
||||
reload.failed.title=Ошибка перезагрузки
|
||||
|
||||
chat=Групповой чат
|
||||
|
||||
|
@ -193,6 +193,9 @@ button.save_as=Зберегти як
|
||||
button.select_all=Вибрати все
|
||||
button.view=Переглянути
|
||||
button.yes=Так
|
||||
button.reload=Перезавантажити
|
||||
reload.failed=Не вдалося перезавантажити HMCL
|
||||
reload.failed.title=Помилка перезавантаження
|
||||
|
||||
chat=Приєднатися до групового чату
|
||||
|
||||
|
@ -198,6 +198,9 @@ button.save_as=另存新檔
|
||||
button.select_all=全選
|
||||
button.view=查看
|
||||
button.yes=是
|
||||
button.reload=重新加載
|
||||
reload.failed=HMCL 重新加載失敗
|
||||
reload.failed.title=重新加載失敗
|
||||
|
||||
chat=官方群組
|
||||
|
||||
@ -1168,7 +1171,7 @@ settings.launcher.proxy.socks=SOCKS
|
||||
settings.launcher.proxy.username=帳戶
|
||||
settings.launcher.theme=主題
|
||||
settings.launcher.title_transparent=標題欄透明
|
||||
settings.launcher.turn_off_animations=關閉動畫 (重啟後生效)
|
||||
settings.launcher.st=關閉動畫 (重啟後生效)
|
||||
settings.launcher.version_list_source=版本清單來源
|
||||
settings.launcher.background.settings.opacity=不透明度
|
||||
|
||||
|
@ -206,6 +206,9 @@ button.save_as=另存为
|
||||
button.select_all=全选
|
||||
button.view=查看
|
||||
button.yes=是
|
||||
button.reload=重新加载
|
||||
reload.failed=HMCL 重新加载失败
|
||||
reload.failed.title=重新加载失败
|
||||
|
||||
chat=官方群组
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user