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
29 changes: 14 additions & 15 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,6 @@
import static org.jackhuang.hmcl.util.logging.Logger.LOG;

public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage {
public static final org.jackhuang.hmcl.ui.versions.DownloadPage.DownloadCallback FOR_MOD =
(downloadProvider, repository, version, mod, file) -> download(downloadProvider, repository, version, file, "mods");
public static final org.jackhuang.hmcl.ui.versions.DownloadPage.DownloadCallback FOR_RESOURCE_PACK =
(downloadProvider, repository, version, pack, file) -> download(downloadProvider, repository, version, file, "resourcepacks");
public static final org.jackhuang.hmcl.ui.versions.DownloadPage.DownloadCallback FOR_SHADER =
(downloadProvider, repository, version, shader, file) -> download(downloadProvider, repository, version, file, "shaderpacks");

private final ReadOnlyObjectWrapper<DecoratorPage.State> state = new ReadOnlyObjectWrapper<>(DecoratorPage.State.fromTitle(i18n("download"), -1));
private final TabHeader tab;
Expand All @@ -92,12 +86,12 @@ public DownloadPage() {
this(null);
}

public DownloadPage(String uploadVersion) {
public DownloadPage(String updateVersion) {
newGameTab.setNodeSupplier(loadVersionFor(() -> new VersionsPage(versionPageNavigator, i18n("install.installer.choose", i18n("install.installer.game")), "", DownloadProviders.getDownloadProvider(),
"game", versionPageNavigator::onGameSelected)));
modpackTab.setNodeSupplier(loadVersionFor(() -> {
DownloadListPage page = HMCLLocalizedDownloadListPage.ofModPack((downloadProvider, repository, __, modpack, file) -> {
Versions.downloadModpackImpl(downloadProvider, repository, uploadVersion, modpack, file);
Versions.downloadModpackImpl(downloadProvider, repository, updateVersion, modpack, file);
}, false);

JFXButton installLocalModpackButton = FXUtils.newRaisedButton(i18n("install.modpack"));
Expand All @@ -106,9 +100,9 @@ public DownloadPage(String uploadVersion) {
page.getActions().add(installLocalModpackButton);
return page;
}));
modTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofMod(FOR_MOD, true)));
resourcePackTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofResourcePack(FOR_RESOURCE_PACK, true)));
shaderTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofShaderPack(FOR_SHADER, true)));
modTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofMod(true)));
resourcePackTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofResourcePack(true)));
shaderTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofShaderPack(true)));
worldTab.setNodeSupplier(loadVersionFor(() -> new DownloadListPage(CurseForgeRemoteAddonRepository.WORLDS)));
tab = new TabHeader(transitionPane, newGameTab, modpackTab, modTab, resourcePackTab, shaderTab, worldTab);

Expand All @@ -123,7 +117,7 @@ public DownloadPage(String uploadVersion) {
.startCategory(i18n("download.content").toUpperCase(Locale.ROOT))
.addNavigationDrawerTab(tab, modTab, i18n("mods"), SVG.EXTENSION, SVG.EXTENSION_FILL)
.addNavigationDrawerTab(tab, resourcePackTab, i18n("resourcepack"), SVG.TEXTURE)
.addNavigationDrawerTab(tab, shaderTab, i18n("download.shader"), SVG.WB_SUNNY, SVG.WB_SUNNY_FILL)
.addNavigationDrawerTab(tab, shaderTab, i18n("shaderpack"), SVG.WB_SUNNY, SVG.WB_SUNNY_FILL)
.addNavigationDrawerTab(tab, worldTab, i18n("world"), SVG.PUBLIC);
FXUtils.setLimitWidth(sideBar, 200);
setLeft(sideBar);
Expand Down Expand Up @@ -220,14 +214,19 @@ public void showModpackDownloads() {
tab.select(modpackTab, false);
}

public DownloadListPage showModDownloads() {
tab.select(modTab, false);
return modTab.getNode();
}

public DownloadListPage showResourcePackDownloads() {
tab.select(resourcePackTab, false);
return resourcePackTab.getNode();
}

public DownloadListPage showModDownloads() {
tab.select(modTab, false);
return modTab.getNode();
public DownloadListPage showShaderDownloads() {
tab.select(shaderTab, false);
return shaderTab.getNode();
}

public void showWorldDownloads() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@

import static org.jackhuang.hmcl.util.logging.Logger.LOG;

public class AddonCheckUpdatesTask<T extends LocalAddonFile> extends Task<List<LocalAddonFile.AddonUpdate>> {
public class AddonCheckUpdatesTask extends Task<List<LocalAddonFile.AddonUpdate>> {
private final DownloadProvider downloadProvider;
private final List<Task<LocalAddonFile.AddonUpdate>> dependents;

public AddonCheckUpdatesTask(DownloadProvider downloadProvider, String gameVersion, Collection<T> addons) {
public AddonCheckUpdatesTask(DownloadProvider downloadProvider, String gameVersion, Collection<? extends LocalAddonFile> addons) {
this.downloadProvider = downloadProvider;
dependents = addons.stream().map(addon ->
Task.supplyAsync(Schedulers.io(), () -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;

public class AddonUpdatesPage<F extends LocalAddonFile> extends BorderPane implements DecoratorPage {
public class AddonUpdatesPage extends BorderPane implements DecoratorPage {
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(DecoratorPage.State.fromTitle(i18n("addon.check_update")));

private final LocalAddonManager<F> localAddonManager;
private final Path addonsDirectory;
private final ObservableList<AddonUpdateObject> objects;

@SuppressWarnings("unchecked")
public AddonUpdatesPage(LocalAddonManager<F> localAddonManager, List<LocalAddonFile.AddonUpdate> updates) {
this.localAddonManager = localAddonManager;
public AddonUpdatesPage(Path addonsDirectory, List<LocalAddonFile.AddonUpdate> updates) {
this.addonsDirectory = addonsDirectory;

getStyleClass().add("gray-background");

Expand Down Expand Up @@ -132,7 +132,7 @@ private <T> void setupCellValueFactory(TableColumn<AddonUpdateObject, T> column,

private void updateFiles() {
AddonUpdateTask task = new AddonUpdateTask(
localAddonManager.getDirectory(),
addonsDirectory,
objects.stream()
.filter(AddonUpdateObject::isEnabled)
.map(AddonUpdateObject::getData)
Expand Down Expand Up @@ -294,19 +294,18 @@ public static class AddonUpdateTask extends Task<Void> {
RemoteAddon.Version remote = addon.targetVersion();
boolean isDisabled = local.isDisabled();
String originalFileName = local.getFile().getFileName().toString();
String fileName = addon.useRemoteFileName() ? remote.file().filename() : originalFileName;
if (isDisabled)
fileName = StringUtils.addSuffix(fileName, LocalAddonManager.DISABLED_EXTENSION);
String newFileName = fileName;

dependents.add(Task
.runAsync(Schedulers.javafx(), () -> local.setOld(true))
.thenComposeAsync(() -> {
String fileName = addon.useRemoteFileName() ? remote.file().filename() : originalFileName;
if (isDisabled)
fileName = StringUtils.addSuffix(fileName, LocalAddonManager.DISABLED_EXTENSION);

var task = new FileDownloadTask(
remote.file().url(),
addonDirectory.resolve(fileName)
addonDirectory.resolve(newFileName)
);

task.setName(remote.name());
return task;
})
Expand All @@ -317,11 +316,14 @@ public static class AddonUpdateTask extends Task<Void> {
if (isDisabled)
local.markDisabled();
failedAddons.add(local);
} else if (!local.keepOldFiles()) {
try {
local.delete();
} catch (IOException e) {
LOG.warning("Failed to delete outdated addon: " + local.getFile(), e);
} else {
local.onUpdated(newFileName);
if (!local.keepOldFiles()) {
try {
local.delete();
} catch (IOException e) {
LOG.warning("Failed to delete outdated addon: " + local.getFile(), e);
}
}
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import javafx.scene.control.Skin;
import javafx.stage.FileChooser;
import org.jackhuang.hmcl.game.World;
import org.jackhuang.hmcl.addon.datapack.DataPack;
import org.jackhuang.hmcl.addon.pack.datapack.DataPack;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;
import org.jackhuang.hmcl.addon.datapack.DataPack;
import org.jackhuang.hmcl.addon.pack.datapack.DataPack;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
private final ListProperty<RemoteAddon> items = new SimpleListProperty<>(this, "items", FXCollections.observableArrayList());
private final ObservableList<String> versions = FXCollections.observableArrayList();
private final StringProperty selectedVersion = new SimpleStringProperty();
private final DownloadPage.DownloadCallback callback;
private final DownloadPage.DownloadCallback callback; // ONLY FOR MODPACKS
private boolean searchInitialized = false;
protected final BooleanProperty supportChinese = new SimpleBooleanProperty();
private final ObservableList<Node> actions = FXCollections.observableArrayList();
Expand Down
52 changes: 35 additions & 17 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,25 @@
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;

public class DownloadPage extends Control implements DecoratorPage {
public static final DownloadCallback FOR_MOD =
(downloadProvider, repository, version, mod, file) ->
org.jackhuang.hmcl.ui.download.DownloadPage.download(downloadProvider, repository, version, file, "mods");
public static final DownloadCallback FOR_RESOURCE_PACK =
(downloadProvider, repository, version, pack, file) ->
org.jackhuang.hmcl.ui.download.DownloadPage.download(downloadProvider, repository, version, file, "resourcepacks");
public static final DownloadCallback FOR_SHADER =
(downloadProvider, repository, version, shader, file) ->
org.jackhuang.hmcl.ui.download.DownloadPage.download(downloadProvider, repository, version, file, "shaderpacks");

public static @Nullable DownloadCallback getDownloadCallbackFor(RemoteAddonRepository.Type repoType) {
return switch (repoType) {
case MOD -> FOR_MOD;
case RESOURCE_PACK -> FOR_RESOURCE_PACK;
case SHADER_PACK -> FOR_SHADER;
default -> null;
};
}

private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();
private final BooleanProperty loaded = new SimpleBooleanProperty(false);
private final BooleanProperty loading = new SimpleBooleanProperty(false);
Expand All @@ -68,7 +87,7 @@ public class DownloadPage extends Control implements DecoratorPage {
private final RemoteAddon addon;
private final ModTranslations.Mod mod;
private final HMCLGameRepository.InstanceReference instanceReference;
private final DownloadCallback callback;
private final DownloadCallback callback; // ONLY FOR MODPACKS
private final DownloadListPage page;
private final RemoteAddonRepository.Type type;

Expand Down Expand Up @@ -156,11 +175,17 @@ public void setFailed(boolean failed) {
this.failed.set(failed);
}

public @Nullable DownloadCallback getCallbackFor(RemoteAddon addon) {
if (addon.repoType() == RemoteAddonRepository.Type.MODPACK) return this.callback;
return getDownloadCallbackFor(addon.repoType());
}

public void download(RemoteAddon addon, RemoteAddon.Version file) {
if (this.callback == null) {
var callback = getCallbackFor(addon);
if (callback == null) {
saveAs(file);
} else {
this.callback.download(page.getDownloadProvider(), instanceReference.repository(), instanceReference.instanceId(), addon, file);
callback.download(page.getDownloadProvider(), instanceReference.repository(), instanceReference.instanceId(), addon, file);
}
}

Expand Down Expand Up @@ -386,21 +411,14 @@ private static final class DependencyAddonItem extends LineButton {
pane.getChildren().setAll(imageView, content);
FXUtils.setLimitHeight(this, 60);

RemoteAddonRepository.Type type = addon.repoType();
DownloadCallback callback = switch (type) {
case MOD -> org.jackhuang.hmcl.ui.download.DownloadPage.FOR_MOD;
case RESOURCE_PACK -> org.jackhuang.hmcl.ui.download.DownloadPage.FOR_RESOURCE_PACK;
case SHADER_PACK -> org.jackhuang.hmcl.ui.download.DownloadPage.FOR_SHADER;
default -> null; // Dependencies should not be modpacks, worlds or customized stuff
};
setOnAction((e) -> {
fireEvent(new DialogCloseEvent());
Controllers.navigate(new DownloadPage(page, addon, instanceReference, callback));
Controllers.navigate(new DownloadPage(page, addon, instanceReference, null));
});
setNode(IDX_LEADING, pane);

if (addon != RemoteAddon.BROKEN) {
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(type).getModByCurseForgeId(addon.slug());
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(addon.repoType()).getModByCurseForgeId(addon.slug());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : addon.title());
content.setSubtitle(addon.description());
for (String category : addon.categories()) {
Expand Down Expand Up @@ -491,7 +509,7 @@ private static final class AddonItem extends StackPane {
}

private static final class AddonVersion extends JFXDialogLayout {
public AddonVersion(RemoteAddon mod, RemoteAddon.Version version, DownloadPage selfPage) {
public AddonVersion(RemoteAddon addon, RemoteAddon.Version version, DownloadPage selfPage) {
RemoteAddonRepository.Type type = selfPage.type;

String title = switch (type) {
Expand All @@ -505,7 +523,7 @@ public AddonVersion(RemoteAddon mod, RemoteAddon.Version version, DownloadPage s

VBox box = new VBox(8);
box.setPadding(new Insets(8));
AddonItem addonItem = new AddonItem(mod, version, selfPage);
AddonItem addonItem = new AddonItem(addon, version, selfPage);
addonItem.setMouseTransparent(true); // Item is displayed for info, clicking shouldn't open the dialog again
box.getChildren().setAll(addonItem);
SpinnerPane spinnerPane = new SpinnerPane();
Expand All @@ -527,14 +545,14 @@ public AddonVersion(RemoteAddon mod, RemoteAddon.Version version, DownloadPage s
this.setBody(box);

JFXButton downloadButton = null;
if (selfPage.callback != null) {
downloadButton = new JFXButton(type == RemoteAddonRepository.Type.MODPACK ? i18n("install.modpack") : i18n("mods.install"));
if (selfPage.getCallbackFor(addon) != null) {
downloadButton = new JFXButton(type == RemoteAddonRepository.Type.MODPACK ? i18n("install.modpack") : i18n("addon.install"));
downloadButton.getStyleClass().add("dialog-accept");
downloadButton.setOnAction(e -> {
if (type == RemoteAddonRepository.Type.MODPACK || !spinnerPane.isLoading() && spinnerPane.getFailedReason() == null) {
fireEvent(new DialogCloseEvent());
}
selfPage.download(mod, version);
selfPage.download(addon, version);
});
}

Expand Down
Loading