Conversation
CiiLu
commented
Mar 20, 2026
There was a problem hiding this comment.
Pull request overview
该 PR 为启动器新增“清理游戏文件”能力:在版本列表页提供入口,统计可清理文件占用空间并提示用户确认后执行清理,同时补充了文件大小格式化与相关本地化文案。
Changes:
- 新增游戏文件清理入口与实现(扫描冗余 assets/libraries、日志/缓存、natives 目录等并删除)。
- 增加文件大小的本地化格式化能力(
I18n.formatSize/Translator.formatSize+ 对应多语言 key)。 - UI 支持动态更新 MessageDialog 文本,并新增清理图标与多语言文案。
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 添加 size 格式化 key 与“清理游戏文件”文案(简中) |
| HMCL/src/main/resources/assets/lang/I18N_zh.properties | 添加 size 格式化 key 与“清理游戏文件”文案(繁中) |
| HMCL/src/main/resources/assets/lang/I18N.properties | 添加 size 格式化 key 与“清理游戏文件”文案(英文) |
| HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java | 新增 formatSize(long),使用 i18n key 格式化大小 |
| HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java | 暴露 I18n.formatSize(long) 静态入口 |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java | 实现清理逻辑与统计/确认对话框交互 |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java | 在版本列表页工具栏新增“清理游戏文件”按钮入口 |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java | 支持 setText 动态更新对话框文本 |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java | 新增 CLEAN 图标枚举值 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| JFXButton okButton = new JFXButton(i18n("button.yes")); | ||
| okButton.getStyleClass().add("dialog-accept"); | ||
|
|
||
| dialogBuilder.addAction(buttonPane); |
There was a problem hiding this comment.
MessageDialogPane.Builder#addAction(Node) registers an ActionEvent handler on the provided node to close the dialog. Passing a container (buttonPane) means the ActionEvent from okButton will bubble up and close the dialog immediately on click, preventing the intended “show spinner while deleting, then close” flow. Prefer adding the actual button as the action node (and suppress auto-close), or expose/update the dialog action area via an API instead of wrapping with a pane.
| dialogBuilder.addAction(buttonPane); | |
| dialogBuilder.addAction(okButton); |
| .collect(Collectors.toSet()); | ||
|
|
||
| Set<String> activeLibraries = versions.parallelStream() | ||
| .flatMap(version -> version.getLibraries().stream()) |
There was a problem hiding this comment.
activeLibraries is derived from version.getLibraries() only, but HMCL stores extra libraries in version.getPatches() (e.g., modpack/loader patches). Those patched libraries live under libraries/ too, so this cleanup can misclassify them as unused and delete required files. Build activeLibraries from the resolved version (e.g., resolvePreservingPatches(...)) or explicitly include libraries from patches when collecting paths.
| .flatMap(version -> version.getLibraries().stream()) | |
| .flatMap(version -> { | |
| Stream<Library> baseLibraries = version.getLibraries().stream(); | |
| Stream<Library> patchedLibraries = version.getPatches().stream() | |
| .flatMap(patch -> patch.getLibraries().stream()); | |
| return Stream.concat(baseLibraries, patchedLibraries); | |
| }) |
| try (var walker = Files.walk(repository.getVersionRoot(v.getId()), 1)) { | ||
| unusedFolders.addAll(walker | ||
| .filter(it -> { | ||
| var name = it.getFileName().toString(); | ||
| return Files.isDirectory(it) && (name.startsWith("natives-") || name.endsWith("-natives")); | ||
| }).toList()); |
There was a problem hiding this comment.
Files.walk(versionRoot, 1) includes versionRoot itself. If a user’s version id happens to start with natives- or end with -natives, this filter will treat the entire version directory as a “natives” folder and enqueue all its files for deletion. Use Files.list(versionRoot) (children only) or add an explicit !it.equals(versionRoot) guard before applying the name predicate.
| } else if (bytes < 1024 * 1024 * 1024) { | ||
| return supportedLocale.i18n("download.size.megabyte", (double) bytes / (1024 * 1024)); | ||
| } else { | ||
| return supportedLocale.i18n("download.size.gibabyte", (double) bytes / (1024 * 1024 * 1024)); |
There was a problem hiding this comment.
The i18n key name download.size.gibabyte appears to be a typo (GiB is “gibibyte”, matching the existing kibibyte/megabyte naming). Since this is newly introduced, consider renaming the key (and all translations/usages) to download.size.gibibyte to avoid confusion and keep key naming consistent.
| return supportedLocale.i18n("download.size.gibabyte", (double) bytes / (1024 * 1024 * 1024)); | |
| return supportedLocale.i18n("download.size.gibibyte", (double) bytes / (1024 * 1024 * 1024)); |
| download.size.byte=%d B | ||
| download.size.kibibyte=%.1f KiB | ||
| download.size.megabyte=%.1f MiB | ||
| download.size.gibabyte=%.1f GiB |
There was a problem hiding this comment.
The i18n key name download.size.gibabyte appears to be a typo (GiB is “gibibyte”, matching the existing kibibyte/megabyte naming). Since this is newly introduced, consider renaming the key to download.size.gibibyte (and update all locales/usages) for consistency.
| download.size.gibabyte=%.1f GiB | |
| download.size.gibibyte=%.1f GiB |
| download.size.byte=%d B | ||
| download.size.kibibyte=%.1f KiB | ||
| download.size.megabyte=%.1f MiB | ||
| download.size.gibabyte=%.1f GiB |
There was a problem hiding this comment.
The i18n key name download.size.gibabyte appears to be a typo (GiB is “gibibyte”, matching the kibibyte/megabyte naming). Since this is newly introduced, consider renaming the key to download.size.gibibyte (and update all locales/usages) for consistency.
| download.size.gibabyte=%.1f GiB | |
| download.size.gibibyte=%.1f GiB |
| download.size.byte=%d B | ||
| download.size.kibibyte=%.1f KiB | ||
| download.size.megabyte=%.1f MiB | ||
| download.size.gibabyte=%.1f GiB |
There was a problem hiding this comment.
The i18n key name download.size.gibabyte appears to be a typo (GiB is “gibibyte”, matching the kibibyte/megabyte naming). Since this is newly introduced, consider renaming the key to download.size.gibibyte (and update all locales/usages) for consistency.
| download.size.gibabyte=%.1f GiB | |
| download.size.gibibyte=%.1f GiB |
|
|
||
| game=遊戲 | ||
| game.clean=清理遊戲文件 | ||
| game.clean.loading=统计中... |
There was a problem hiding this comment.
This is the Traditional Chinese locale file, but the new string uses the Simplified character “统计”. Consider changing it to Traditional (“統計”) to keep the locale consistent.
| game.clean.loading=统计中... | |
| game.clean.loading=統計中... |
