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
17 changes: 12 additions & 5 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.upgrade.RemoteVersion;
import org.jackhuang.hmcl.upgrade.UpdateChannel;
import org.jackhuang.hmcl.upgrade.UpdateChecker;
import org.jackhuang.hmcl.upgrade.UpdateHandler;
import org.jackhuang.hmcl.upgrade.*;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.i18n.I18n;
Expand Down Expand Up @@ -113,7 +110,7 @@ protected int getTrailingTextIndex() {

final StringProperty lblUpdateSubProperty = updatePane.subtitleProperty();

{
if (IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK || IntegrityChecker.isSelfVerified()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid verifying the launcher on the FX thread

IntegrityChecker.isSelfVerified() is explicitly blocking and, on its first call, reads and hashes the entire launcher JAR. This condition runs while SettingsPage is being constructed on the JavaFX thread; therefore opening or preloading Settings before the background update check has completed can freeze the UI until verification finishes. Keep this verification in the existing background update-check path and publish its result back to the UI instead.

Useful? React with 👍 / 👎.

updateListener = any -> {
boolean outdated = UpdateChecker.isOutdated();

Expand All @@ -125,14 +122,24 @@ protected int getTrailingTextIndex() {
lblUpdateSubProperty.set(i18n("update.newest_version", UpdateChecker.getLatestVersion().version()));
} else if (UpdateChecker.isCheckingUpdate()) {
lblUpdateSubProperty.set(i18n("update.checking"));
} else if (UpdateChecker.errorProperty().get() != null) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Surface failures before stale update results

When an earlier successful check found an update and a later check fails (for example, after toggling Preview), latestVersion is deliberately retained, so isOutdated() remains true. The preceding outdated branch then wins and this new error branch is never reached, leaving the stale update button and “newest version” text visible even though the most recent request failed. Check the error state before the stale result, or explicitly define how stale results should be presented.

Useful? React with 👍 / 👎.

Throwable t = UpdateChecker.errorProperty().get();
String msg = t.getClass().getSimpleName() + ": " + t.getLocalizedMessage();
lblUpdateSubProperty.set(i18n("update.check_failed", msg));
} else {
lblUpdateSubProperty.set(i18n("update.latest"));
}
};
UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener));
UpdateChecker.outdatedProperty().addListener(new WeakInvalidationListener(updateListener));
UpdateChecker.checkingUpdateProperty().addListener(new WeakInvalidationListener(updateListener));
UpdateChecker.errorProperty().addListener(new WeakInvalidationListener(updateListener));
updateListener.invalidated(null);
} else {
updateButton.setVisible(false);
updateButton.setManaged(false);
lblUpdateSubProperty.set(i18n("update.unverified"));
updateListener = null;
}

updatePaneList.getContent().add(updatePane);
Expand Down
13 changes: 12 additions & 1 deletion HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ private UpdateChecker() {
},
latestVersion);
private static final ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false);
private static final ReadOnlyObjectWrapper<Throwable> error = new ReadOnlyObjectWrapper<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Declare the nullable error state explicitly

The new wrapper is assigned null on successful checks and the UI tests its value for null, but it is declared as ReadOnlyObjectWrapper<Throwable> and exposed as ReadOnlyObjectProperty<Throwable>. This violates the repository AGENTS.md nullability rule for nullable generic arguments and makes the new API appear non-null to callers; annotate the wrapper/property type argument and nullable locals with @Nullable under a @NotNullByDefault class.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Document the new error-state API

The added error field and errorProperty() method have no /// Markdown-style Javadoc. The repository AGENTS.md requires documentation for every field and method, including newly added internal state and public accessors; add concise documentation describing when this property is set and cleared.

Useful? React with 👍 / 👎.


public static void init() {
requestCheckUpdate(UpdateChannel.getChannel(), settings().acceptPreviewUpdateProperty().get());
Expand Down Expand Up @@ -83,6 +84,10 @@ public static ReadOnlyBooleanProperty checkingUpdateProperty() {
return checkingUpdate.getReadOnlyProperty();
}

public static ReadOnlyObjectProperty<Throwable> errorProperty() {
return error.getReadOnlyProperty();
}

private static RemoteVersion checkUpdate(UpdateChannel channel, boolean preview) throws IOException {
if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK && !IntegrityChecker.isSelfVerified()) {
throw new IOException("Self verification failed");
Expand All @@ -109,16 +114,22 @@ public static void requestCheckUpdate(UpdateChannel channel, boolean preview) {

thread(() -> {
RemoteVersion result = null;
Throwable t = null;
try {
result = checkUpdate(channel, preview);
LOG.info("Latest version (" + channel + ", preview=" + preview + ") is " + result);
} catch (Throwable e) {
t = e;
LOG.warning("Failed to check for update", e);
}
Throwable throwable = t;

RemoteVersion finalResult = result;
Platform.runLater(() -> {
if (finalResult != null) {
if (throwable != null) {
error.set(throwable);
} else {
error.set(null);
latestVersion.set(finalResult);
}
Comment thread
ToobLac marked this conversation as resolved.
checkingUpdate.set(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 @@ -1787,6 +1787,7 @@ update.channel.nightly.hint=You are currently using a Nightly channel build of t
update.channel.nightly.title=Nightly Channel Notice
update.channel.stable=Stable
update.checking=Checking for updates
update.check_failed=Failed to check for update. %s
update.disable_auto_show_update_dialog=Do not show update dialog automatically
update.disable_auto_show_update_dialog.subtitle=Enable this option to prevent HMCL from automatically showing the update dialog.
update.failed=Failed to update
Expand All @@ -1801,6 +1802,7 @@ update.no_browser=Cannot open in system browser. But we copied the link to your
update.tooltip=Update
update.preview=Preview HMCL releases early
update.preview.subtitle=Enable this option to receive new versions of HMCL early for testing before their official release.
update.unverified=Update unavailable due to this launcher instance not verified

version=Games
version.name=Instance Name
Expand Down
2 changes: 2 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,7 @@ update.channel.nightly.hint=你正在使用 HMCL 預覽版。預覽版更新較
update.channel.nightly.title=預覽版提示
update.channel.stable=穩定版
update.checking=正在檢查更新
update.check_failed=檢查更新失敗 %s
update.disable_auto_show_update_dialog=不自動顯示更新彈窗
update.disable_auto_show_update_dialog.subtitle=啟用此選項,HMCL 將不會自動彈出更新彈窗。
update.failed=更新失敗
Expand All @@ -1588,6 +1589,7 @@ update.no_browser=無法開啟瀏覽器。網址已經複製到剪貼簿了,
update.tooltip=更新
update.preview=提前測試 HMCL 預覽版本
update.preview.subtitle=啟用此選項,你將可以提前取得 HMCL 的新版本,以便在正式發布前進行測試。
update.unverified=更新不可用,因為無法驗證此啟動器例項完整性

version=遊戲
version.name=遊戲實例名稱
Expand Down
2 changes: 2 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,7 @@ update.channel.nightly.hint=你正在使用 HMCL 预览版。预览版更新较
update.channel.nightly.title=预览版提示
update.channel.stable=稳定版
update.checking=正在检查更新
update.check_failed=检查更新失败 %s
update.disable_auto_show_update_dialog=不自动显示更新弹窗
update.disable_auto_show_update_dialog.subtitle=启用此选项,HMCL 将不会自动弹出更新弹窗。
update.failed=更新失败
Expand All @@ -1593,6 +1594,7 @@ update.no_browser=无法打开浏览器。网址已经复制到剪贴板,你
update.tooltip=更新
update.preview=提前预览 HMCL 版本
update.preview.subtitle=启用此选项,你将可以提前获取 HMCL 的新版本,以便在正式发布前进行测试。
update.unverified=更新不可用,因为无法验证此启动器实例完整性

version=游戏
version.name=游戏实例名称
Expand Down