优化游戏下载界面 (#4405)

This commit is contained in:
Glavo
2025-09-07 16:33:49 +08:00
committed by GitHub
parent 55a7169e21
commit c3352d2b73
2 changed files with 82 additions and 42 deletions

View File

@@ -52,6 +52,7 @@ import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.Duration;
import javafx.util.StringConverter;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.task.CacheFileTask;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
@@ -1159,6 +1160,13 @@ public final class FXUtils {
return button;
}
public static JFXButton newToggleButton4(SVG icon) {
JFXButton button = new JFXButton();
button.getStyleClass().add("toggle-icon4");
button.setGraphic(icon.createIcon(Theme.blackFill(), -1));
return button;
}
public static Label truncatedLabel(String text, int limit) {
Label label = new Label();
if (text.length() <= limit) {

View File

@@ -19,12 +19,13 @@ package org.jackhuang.hmcl.ui.download;
import com.jfoenix.controls.*;
import javafx.beans.InvalidationListener;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.*;
@@ -41,7 +42,6 @@ import org.jackhuang.hmcl.download.neoforge.NeoForgeRemoteVersion;
import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion;
import org.jackhuang.hmcl.download.quilt.QuiltAPIRemoteVersion;
import org.jackhuang.hmcl.download.quilt.QuiltRemoteVersion;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.setting.VersionIconType;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
@@ -73,17 +73,23 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
private final String libraryId;
private final String title;
private final Navigation navigation;
private final DownloadProvider downloadProvider;
private final VersionList<?> versionList;
private final Runnable callback;
private final ObservableList<RemoteVersion> versions = FXCollections.observableArrayList();
private final ObjectProperty<Status> status = new SimpleObjectProperty<>(Status.LOADING);
public VersionsPage(Navigation navigation, String title, String gameVersion, DownloadProvider downloadProvider, String libraryId, Runnable callback) {
public VersionsPage(Navigation navigation,
String title, String gameVersion,
DownloadProvider downloadProvider,
String libraryId,
Runnable callback) {
this.title = title;
this.gameVersion = gameVersion;
this.libraryId = libraryId;
this.navigation = navigation;
this.downloadProvider = downloadProvider;
this.versionList = downloadProvider.getVersionListById(libraryId);
this.callback = callback;
@@ -130,10 +136,6 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
navigation.onPrev(true);
}
private void onSponsor() {
FXUtils.openLink("https://bmclapidoc.bangbang93.com");
}
private enum Status {
LOADING,
FAILED,
@@ -149,22 +151,61 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
}
private static class RemoteVersionListCell extends ListCell<RemoteVersion> {
private final IconedTwoLineListItem content = new IconedTwoLineListItem();
private final RipplerContainer ripplerContainer = new RipplerContainer(content);
private final VersionsPage control;
private final TwoLineListItem twoLineListItem = new TwoLineListItem();
private final ImageView imageView = new ImageView();
private final StackPane pane = new StackPane();
private final Holder<RemoteVersionListCell> lastCell;
RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell, String libraryId) {
RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell, VersionsPage control) {
this.lastCell = lastCell;
if ("game".equals(libraryId)) {
content.getExternalLinkButton().setGraphic(SVG.GLOBE_BOOK.createIcon(Theme.blackFill(), -1));
FXUtils.installFastTooltip(content.getExternalLinkButton(), i18n("wiki.tooltip"));
this.control = control;
HBox hbox = new HBox(16);
HBox.setHgrow(twoLineListItem, Priority.ALWAYS);
hbox.setAlignment(Pos.CENTER);
HBox actions = new HBox(8);
actions.setAlignment(Pos.CENTER);
{
if ("game".equals(control.libraryId)) {
JFXButton wikiButton = newToggleButton4(SVG.GLOBE_BOOK);
wikiButton.setOnAction(event -> onOpenWiki());
FXUtils.installFastTooltip(wikiButton, i18n("wiki.tooltip"));
actions.getChildren().add(wikiButton);
}
JFXButton actionButton = newToggleButton4(SVG.ARROW_FORWARD);
actionButton.setOnAction(e -> onAction());
actions.getChildren().add(actionButton);
}
hbox.getChildren().setAll(imageView, twoLineListItem, actions);
pane.getStyleClass().add("md-list-cell");
StackPane.setMargin(content, new Insets(10, 16, 10, 16));
pane.getChildren().setAll(ripplerContainer);
StackPane.setMargin(hbox, new Insets(10, 16, 10, 16));
pane.getChildren().setAll(new RipplerContainer(hbox));
FXUtils.onClicked(this, this::onAction);
}
private void onAction() {
RemoteVersion item = getItem();
if (item == null)
return;
control.navigation.getSettings().put(control.libraryId, item);
control.callback.run();
}
private void onOpenWiki() {
RemoteVersion item = getItem();
if (!(item instanceof GameRemoteVersion))
return;
FXUtils.openLink(I18n.getWikiLink((GameRemoteVersion) item));
}
@Override
@@ -182,37 +223,36 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
}
setGraphic(pane);
content.setTitle(I18n.getDisplaySelfVersion(remoteVersion));
twoLineListItem.setTitle(I18n.getDisplaySelfVersion(remoteVersion));
if (remoteVersion.getReleaseDate() != null) {
content.setSubtitle(I18n.formatDateTime(remoteVersion.getReleaseDate()));
twoLineListItem.setSubtitle(I18n.formatDateTime(remoteVersion.getReleaseDate()));
} else {
content.setSubtitle(null);
twoLineListItem.setSubtitle(null);
}
if (remoteVersion instanceof GameRemoteVersion) {
RemoteVersion.Type versionType = remoteVersion.getVersionType();
switch (versionType) {
case RELEASE:
content.getTags().setAll(i18n("version.game.release"));
content.setImage(VersionIconType.GRASS.getIcon());
twoLineListItem.getTags().setAll(i18n("version.game.release"));
imageView.setImage(VersionIconType.GRASS.getIcon());
break;
case PENDING:
case SNAPSHOT:
if (versionType == RemoteVersion.Type.SNAPSHOT
&& GameVersionNumber.asGameVersion(remoteVersion.getGameVersion()).isAprilFools()) {
content.getTags().setAll(i18n("version.game.april_fools"));
content.setImage(VersionIconType.APRIL_FOOLS.getIcon());
twoLineListItem.getTags().setAll(i18n("version.game.april_fools"));
imageView.setImage(VersionIconType.APRIL_FOOLS.getIcon());
} else {
content.getTags().setAll(i18n("version.game.snapshot"));
content.setImage(VersionIconType.COMMAND.getIcon());
twoLineListItem.getTags().setAll(i18n("version.game.snapshot"));
imageView.setImage(VersionIconType.COMMAND.getIcon());
}
break;
default:
content.getTags().setAll(i18n("version.game.old"));
content.setImage(VersionIconType.CRAFT_TABLE.getIcon());
twoLineListItem.getTags().setAll(i18n("version.game.old"));
imageView.setImage(VersionIconType.CRAFT_TABLE.getIcon());
break;
}
content.setExternalLink(I18n.getWikiLink((GameRemoteVersion) remoteVersion));
} else {
VersionIconType iconType;
if (remoteVersion instanceof LiteLoaderRemoteVersion)
@@ -230,14 +270,13 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
else if (remoteVersion instanceof QuiltRemoteVersion || remoteVersion instanceof QuiltAPIRemoteVersion)
iconType = VersionIconType.QUILT;
else
iconType = null;
iconType = VersionIconType.COMMAND;
content.setImage(iconType != null ? iconType.getIcon() : null);
if (content.getSubtitle() == null)
content.setSubtitle(remoteVersion.getGameVersion());
imageView.setImage(iconType.getIcon());
if (twoLineListItem.getSubtitle() == null)
twoLineListItem.setSubtitle(remoteVersion.getGameVersion());
else
content.getTags().setAll(remoteVersion.getGameVersion());
content.setExternalLink(null);
twoLineListItem.getTags().setAll(remoteVersion.getGameVersion());
}
}
}
@@ -355,14 +394,7 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab
control.versions.addListener((InvalidationListener) o -> updateList());
Holder<RemoteVersionListCell> lastCell = new Holder<>();
list.setCellFactory(listView -> new RemoteVersionListCell(lastCell, control.libraryId));
FXUtils.onClicked(list, () -> {
if (list.getSelectionModel().getSelectedIndex() < 0)
return;
control.navigation.getSettings().put(control.libraryId, list.getSelectionModel().getSelectedItem());
control.callback.run();
});
list.setCellFactory(listView -> new RemoteVersionListCell(lastCell, control));
ComponentList.setVgrow(list, Priority.ALWAYS);