Repository: HMCL-dev/HMCL (language: java)

Issue:
[Bug] 游戏内容和整合包下载的翻至最后一页有问题
### 平台 | Platform

Windows 11

### 问题描述 | Bug Description

![Image](https://github.com/user-attachments/assets/0f318d5a-0314-4151-a63b-fa34063d6c8e)

点击资源下载中的最后一页，并没有翻到这里的 200 页，需要重新尝试才可以

### 启动器崩溃报告 / 启动器日志文件 | Launcher Crash Report / Launcher Log File

[hmcl-exported-logs-2025-02-23T08-27-46.log](https://github.com/user-attachments/files/18926657/hmcl-exported-logs-2025-02-23T08-27-46.log)


Discussion / hints:
确实有这个问题，打开启动器后第一次尝试几乎必现。

在 CurseForge 触发这个问题后，右上角切换为 Modrinth 还会再出现一次。

EDIT: 我用的 `main` 分支代码测试。
补充下：点击「下一页」也有这个问题。
@burningtnt cc?
似乎是所有按钮在第一次点击时都不会正常工作 ……

Fix patch:
diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java
index 53a972c749..f353da485e 100644
--- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java
+++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java
@@ -60,10 +60,7 @@
 import org.jackhuang.hmcl.util.javafx.BindingMapping;
 import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Optional;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent;
@@ -156,7 +153,7 @@ public void selectVersion(String versionID) {
         FXUtils.runInFX(() -> selectedVersion.set(versionID));
     }
 
-    public void search(String userGameVersion, RemoteModRepository.Category category, int pageOffset, String searchFilter, RemoteModRepository.SortType sort) {
+    private void search(String userGameVersion, RemoteModRepository.Category category, int pageOffset, String searchFilter, RemoteModRepository.SortType sort) {
         retrySearch = null;
         setLoading(true);
         setFailed(false);
@@ -171,7 +168,9 @@ public void search(String userGameVersion, RemoteModRepository.Category category
                         ? version.getProfile().getRepository().getGameVersion(version.getVersion()).orElse("")
                         : "";
             }
-        }).thenApplyAsync(gameVersion -> repository.search(gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC)).whenComplete(Schedulers.javafx(), (result, exception) -> {
+        }).thenApplyAsync(
+                gameVersion -> repository.search(gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC)
+        ).whenComplete(Schedulers.javafx(), (result, exception) -> {
             if (searchID != currentSearchID) {
                 return;
             }
@@ -312,7 +311,7 @@ protected ModDownloadListPageSkin(DownloadListPage control) {
 
                 StackPane categoryStackPane = new StackPane();
                 JFXComboBox<CategoryIndented> categoryComboBox = new JFXComboBox<>();
-                categoryComboBox.getItems().setAll(new CategoryIndented(0, null));
+                categoryComboBox.getItems().setAll(CategoryIndented.ALL);
                 categoryStackPane.getChildren().setAll(categoryComboBox);
                 categoryComboBox.prefWidthProperty().bind(categoryStackPane.widthProperty());
                 categoryComboBox.getStyleClass().add("fit-width");
@@ -320,14 +319,22 @@ protected ModDownloadListPageSkin(DownloadListPage control) {
                 categoryComboBox.getSelectionModel().select(0);
                 categoryComboBox.setConverter(stringConverter(getSkinnable()::getLocalizedCategoryIndent));
                 FXUtils.onChangeAndOperate(getSkinnable().downloadSource, downloadSource -> {
+                    categoryComboBox.getItems().setAll(CategoryIndented.ALL);
+                    categoryComboBox.getSelectionModel().select(0);
+
                     Task.supplyAsync(() -> getSkinnable().repository.getCategories())
                             .thenAcceptAsync(Schedulers.javafx(), categories -> {
+                                if (!Objects.equals(getSkinnable().downloadSource.get(), downloadSource)) {
+                                    return;
+                                }
+
                                 List<CategoryIndented> result = new ArrayList<>();
-                                result.add(new CategoryIndented(0, null));
+                                result.add(CategoryIndented.ALL);
                                 for (RemoteModRepository.Category category : Lang.toIterable(categories)) {
                                     resolveCategory(category, 0, result);
                                 }
                                 categoryComboBox.getItems().setAll(result);
+                                categoryComboBox.getSelectionModel().select(0);
                             }).start();
                 });
 
@@ -344,7 +351,7 @@ protected ModDownloadListPageSkin(DownloadListPage control) {
                 IntegerProperty filterID = new SimpleIntegerProperty(this, "Filter ID", 0);
                 IntegerProperty currentFilterID = new SimpleIntegerProperty(this, "Current Filter ID", -1);
                 EventHandler<ActionEvent> searchAction = e -> {
-                    if (currentFilterID.get() != filterID.get()) {
+                    if (currentFilterID.get() != -1 && currentFilterID.get() != filterID.get()) {
                         control.pageOffset.set(0);
                     }
                     currentFilterID.set(filterID.get());
@@ -379,8 +386,8 @@ protected ModDownloadListPageSkin(DownloadListPage control) {
                     JFXButton firstPageButton = FXUtils.newBorderButton(i18n("search.first_page"));
                     firstPageButton.setOnAction(event -> {
                         control.pageOffset.set(0);
-                        changeButton.value.run();
                         searchAction.handle(event);
+                        changeButton.value.run();
                     });
 
                     JFXButton previousPageButton = FXUtils.newBorderButton(i18n("search.previous_page"));
@@ -388,8 +395,8 @@ protected ModDownloadListPageSkin(DownloadListPage control) {
                         int pageOffset = control.pageOffset.get();
                         if (pageOffset > 0) {
                             control.pageOffset.set(pageOffset - 1);
-                            changeButton.value.run();
                             searchAction.handle(event);
+                            changeButton.value.run();
                         }
                     });
 
@@ -404,16 +411,16 @@ protected ModDownloadListPageSkin(DownloadListPage control) {
                         int nv = control.pageOffset.get() + 1;
                         if (nv < control.pageCount.get()) {
                             control.pageOffset.set(nv);
-                            changeButton.value.run();
                             searchAction.handle(event);
+                            changeButton.value.run();
                         }
                     });
 
                     JFXButton lastPageButton = FXUtils.newBorderButton(i18n("search.last_page"));
                     lastPageButton.setOnAction(event -> {
                         control.pageOffset.set(control.pageCount.get() - 1);
-                        changeButton.value.run();
                         searchAction.handle(event);
+                        changeButton.value.run();
                     });
 
                     firstPageButton.setDisable(true);
@@ -529,6 +536,8 @@ protected void updateControl(RemoteMod dataItem, boolean empty) {
         }
 
         private static class CategoryIndented {
+            private static final CategoryIndented ALL = new CategoryIndented(0, null);
+
             private final int indent;
             private final RemoteModRepository.Category category;
 
diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/HMCLLocalizedDownloadListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/HMCLLocalizedDownloadListPage.java
index e00db972b9..ab92b07e0c 100644
--- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/HMCLLocalizedDownloadListPage.java
+++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/HMCLLocalizedDownloadListPage.java
@@ -110,7 +110,7 @@ protected String getLocalizedCategory(String category) {
         try {
             return I18n.getResourceBundle().getString(key);
         } catch (MissingResourceException e) {
-            LOG.warning("Cannot find key " + key + " in resource bundle", e);
+            LOG.warning("Cannot find key " + key + " in resource bundle");
             return category;
         }
     }
diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseForgeRemoteModRepository.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseForgeRemoteModRepository.java
index 3913ef7f0e..087f8a0c11 100644
--- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseForgeRemoteModRepository.java
+++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseForgeRemoteModRepository.java
@@ -102,7 +102,9 @@ private int calculateTotalPages(Response<List<CurseAddon>> response, int pageSiz
     @Override
     public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder) throws IOException {
         int categoryId = 0;
-        if (category != null) categoryId = ((CurseAddon.Category) category.getSelf()).getId();
+        if (category != null && category.getSelf() instanceof CurseAddon.Category) {
+            categoryId = ((CurseAddon.Category) category.getSelf()).getId();
+        }
         Response<List<CurseAddon>> response = HttpRequest.GET(PREFIX + "/v1/mods/search",
                         pair("gameId", "432"),
                         pair("classId", Integer.toString(section)),


Test patch: