Skip to content
Draft
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
22 changes: 14 additions & 8 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public final class Controllers {
return gameListPage;
});
private static Lazy<RootPage> rootPage = new Lazy<>(RootPage::new);
private static Lazy<org.jackhuang.hmcl.ui.versions.DownloadPage> downloadVersionListPage = new Lazy<>(org.jackhuang.hmcl.ui.versions.DownloadPage::new);
private static DecoratorController decorator;
Comment on lines +115 to 116
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

The identifier downloadVersionListPage is a bit misleading because it holds a ui.versions.DownloadPage (mod version details), not a list page. Consider renaming it (and the accessor) to something like downloadVersionPage/downloadModVersionPage to avoid confusion with DownloadListPage and ui.download.DownloadPage.

Copilot uses AI. Check for mistakes.
private static DownloadPage downloadPage;
private static Lazy<AccountListPage> accountListPage = new Lazy<>(() -> {
Expand All @@ -135,7 +136,7 @@ public static Stage getStage() {
return stage;
}

// FXThread
@FXThread
public static VersionPage getVersionPage() {
if (versionPage == null) {
versionPage = new VersionPage();
Expand All @@ -151,17 +152,17 @@ public static void prepareVersionPage() {
}
}

// FXThread
@FXThread
public static GameListPage getGameListPage() {
return gameListPage.get();
}

// FXThread
@FXThread
public static RootPage getRootPage() {
return rootPage.get();
}

// FXThread
@FXThread
public static LauncherSettingsPage getSettingsPage() {
if (settingsPage == null) {
settingsPage = new LauncherSettingsPage();
Expand All @@ -177,12 +178,17 @@ public static void prepareSettingsPage() {
}
}

// FXThread
@FXThread
public static AccountListPage getAccountListPage() {
return accountListPage.get();
}

// FXThread
@FXThread
public static org.jackhuang.hmcl.ui.versions.DownloadPage getDownloadVersionListPage() {
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Method name getDownloadVersionListPage() suggests returning a list page, but it returns a ui.versions.DownloadPage instance. Renaming the method to match the actual UI concept (e.g., getDownloadVersionPage) would make call sites clearer.

Suggested change
public static org.jackhuang.hmcl.ui.versions.DownloadPage getDownloadVersionListPage() {
public static org.jackhuang.hmcl.ui.versions.DownloadPage getDownloadVersionPage() {

Copilot uses AI. Check for mistakes.
return downloadVersionListPage.get();
}

@FXThread
public static DownloadPage getDownloadPage() {
if (downloadPage == null) {
downloadPage = new DownloadPage();
Expand All @@ -198,12 +204,12 @@ public static void prepareDownloadPage() {
}
}

// FXThread
@FXThread
public static Node getTerracottaPage() {
return terracottaPage.get();
}

// FXThread
@FXThread
public static DecoratorController getDecorator() {
return decorator;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,11 @@ protected ModDownloadListPageSkin(DownloadListPage control) {

FXUtils.onClicked(wrapper, () -> {
RemoteMod item = getItem();
if (item != null)
Controllers.navigate(new DownloadPage(getSkinnable(), item, getSkinnable().getProfileVersion(), getSkinnable().callback));
if (item != null) {
var page = Controllers.getDownloadVersionListPage();
page.loadMod(getSkinnable(), item, getSkinnable().getProfileVersion(), getSkinnable().callback);
Controllers.navigate(page);
}
});

setPrefWidth(0);
Expand Down
37 changes: 24 additions & 13 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,17 @@ public class DownloadPage extends Control implements DecoratorPage {
private final BooleanProperty loaded = new SimpleBooleanProperty(false);
private final BooleanProperty loading = new SimpleBooleanProperty(false);
private final BooleanProperty failed = new SimpleBooleanProperty(false);
private final RemoteModRepository repository;
private final ModTranslations translations;
private final RemoteMod addon;
private final ModTranslations.Mod mod;
private final Profile.ProfileVersion version;
private final DownloadCallback callback;
private final DownloadListPage page;
private RemoteModRepository repository;
private ModTranslations translations;
private RemoteMod addon;
private ModTranslations.Mod mod;
private Profile.ProfileVersion version;
private DownloadCallback callback;
private DownloadListPage page;

private SimpleMultimap<String, RemoteMod.Version, List<RemoteMod.Version>> versions;

public DownloadPage(DownloadListPage page, RemoteMod addon, Profile.ProfileVersion version, @Nullable DownloadCallback callback) {
public void loadMod(DownloadListPage page, RemoteMod addon, Profile.ProfileVersion version, @Nullable DownloadCallback callback) {
this.page = page;
this.repository = page.repository;
this.addon = addon;
Expand All @@ -91,8 +91,11 @@ public DownloadPage(DownloadListPage page, RemoteMod addon, Profile.ProfileVersi

private void loadModVersions() {
setLoading(true);
loaded.set(false);
setFailed(false);

versions = null;

Task.supplyAsync(() -> {
Stream<RemoteMod.Version> versions = addon.getData().loadVersions(repository, page.getDownloadProvider());
return sortVersions(versions);
Expand Down Expand Up @@ -211,7 +214,10 @@ protected ModDownloadPageSkin(DownloadPage control) {
descriptionPane.setAlignment(Pos.CENTER);
pane.getChildren().add(descriptionPane);
descriptionPane.getStyleClass().add("card-non-transparent");
{

Runnable updateDescriptionPane = () -> {
descriptionPane.getChildren().clear();

var imageContainer = new ImageContainer(40);
if (StringUtils.isNotBlank(getSkinnable().addon.getIconUrl())) {
imageContainer.imageProperty().bind(FXUtils.newRemoteImage(getSkinnable().addon.getIconUrl(), 80, 80, true, true));
Expand Down Expand Up @@ -240,7 +246,10 @@ protected ModDownloadPageSkin(DownloadPage control) {
openUrlButton.setExternalLink(getSkinnable().addon.getPageUrl());
descriptionPane.getChildren().add(openUrlButton);
openUrlButton.setMinWidth(Region.USE_PREF_SIZE);
}
};

FXUtils.onChangeAndOperate(control.loadingProperty(), loading -> updateDescriptionPane.run());


SpinnerPane spinnerPane = new SpinnerPane();
VBox.setVgrow(spinnerPane, Priority.ALWAYS);
Expand All @@ -266,8 +275,8 @@ protected ModDownloadPageSkin(DownloadPage control) {
spinnerPane.setContent(scrollPane);

FXUtils.onChangeAndOperate(control.loaded, loaded -> {
if (control.versions == null) return;

if (control.versions == null || !loaded) return;
list.getContent().clear();
if (control.version.getProfile() != null && control.version.getVersion() != null) {
HMCLGameRepository repository = control.version.getProfile().getRepository();
Version game = repository.getResolvedPreservingPatchesVersion(control.version.getVersion());
Expand Down Expand Up @@ -374,7 +383,9 @@ private static final class DependencyModItem extends StackPane {
RipplerContainer container = new RipplerContainer(pane);
FXUtils.onClicked(container, () -> {
fireEvent(new DialogCloseEvent());
Controllers.navigate(new DownloadPage(page, addon, version, callback));
var downloadPage = new DownloadPage();
downloadPage.loadMod(page, addon, version, callback);
Controllers.navigate(downloadPage);
});
getChildren().setAll(container);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.util.*;
import org.jackhuang.hmcl.util.FXThread;
import org.jackhuang.hmcl.util.Lazy;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.io.CompressingUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
Expand Down Expand Up @@ -490,12 +493,12 @@ final class ModInfoDialog extends JFXDialogLayout {

button.setOnAction(e -> {
fireEvent(new DialogCloseEvent());
Controllers.navigate(new DownloadPage(
repository instanceof CurseForgeRemoteModRepository ? HMCLLocalizedDownloadListPage.ofCurseForgeMod(null, false) : HMCLLocalizedDownloadListPage.ofModrinthMod(null, false),
var page = Controllers.getDownloadVersionListPage();
page.loadMod(repository instanceof CurseForgeRemoteModRepository ? HMCLLocalizedDownloadListPage.ofCurseForgeMod(null, false) : HMCLLocalizedDownloadListPage.ofModrinthMod(null, false),
remoteMod,
new Profile.ProfileVersion(ModListPageSkin.this.getSkinnable().getProfile(), ModListPageSkin.this.getSkinnable().getInstanceId()),
(downloadProvider, profile, version, mod, file) -> org.jackhuang.hmcl.ui.download.DownloadPage.download(downloadProvider, profile, version, file, "mods")
));
(downloadProvider, profile, version, mod, file) -> org.jackhuang.hmcl.ui.download.DownloadPage.download(downloadProvider, profile, version, file, "mods"));
Controllers.navigate(page);
});
button.setDisable(false);
});
Expand Down
Loading