Skip to content

Commit da4f8a5

Browse files
committed
Fix native download modal game version default
1 parent 858ff94 commit da4f8a5

3 files changed

Lines changed: 148 additions & 16 deletions

File tree

launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionDropdown.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public final class GameVersionDropdown extends VBox {
3535
private List<String> selectedVersions = List.of();
3636
private String emptyText = "No versions found";
3737
private String anyLabel = "Any";
38+
private boolean allowEmptySelection = true;
3839
private double maxListHeight = 224;
3940
private Consumer<List<String>> selectionListener = ignored -> {
4041
};
@@ -105,6 +106,12 @@ public void setAnyLabel(String anyLabel) {
105106
refresh();
106107
}
107108

109+
public void setAllowEmptySelection(boolean allowEmptySelection) {
110+
this.allowEmptySelection = allowEmptySelection;
111+
this.selectedVersions = selectedVersions(this.selectedVersions);
112+
refresh();
113+
}
114+
108115
public void setEmptyText(String emptyText) {
109116
this.emptyText = emptyText == null || emptyText.isBlank() ? "No versions found" : emptyText;
110117
refresh();
@@ -153,13 +160,20 @@ private HBox toggleContent() {
153160
}
154161

155162
private void refresh() {
156-
toggleLabel.setText(GameVersionGroups.displayLabel(selectedVersions, versions, anyLabel));
163+
String fallbackLabel = allowEmptySelection ? anyLabel : requiredSelectionFallbackLabel();
164+
toggleLabel.setText(GameVersionGroups.displayLabel(selectedVersions, versions, fallbackLabel));
157165
options.getChildren().setAll(optionNodes());
158166
}
159167

168+
private String requiredSelectionFallbackLabel() {
169+
return versions.isEmpty() ? emptyText : versions.getFirst();
170+
}
171+
160172
private List<Node> optionNodes() {
161173
List<Node> nodes = new ArrayList<>();
162-
nodes.add(optionRow(anyLabel, selectedVersions.isEmpty(), () -> commitSelection(List.of())));
174+
if (allowEmptySelection) {
175+
nodes.add(optionRow(anyLabel, selectedVersions.isEmpty(), () -> commitSelection(List.of())));
176+
}
163177
List<GameVersionGroups.Group> groups = GameVersionGroups.build(versions);
164178
if (groups.isEmpty()) {
165179
Label empty = new Label(emptyText);
@@ -308,11 +322,14 @@ private void commitSelection(List<String> nextSelection) {
308322

309323
private List<String> selectedVersions(List<String> selectedVersions) {
310324
if (selectedVersions == null || selectedVersions.isEmpty()) {
311-
return List.of();
325+
return allowEmptySelection || versions.isEmpty() ? List.of() : List.of(versions.getFirst());
312326
}
313327
Set<String> selected = new LinkedHashSet<>(selectedVersions);
314-
return versions.stream()
328+
List<String> ordered = versions.stream()
315329
.filter(selected::contains)
316330
.toList();
331+
return ordered.isEmpty() && !allowEmptySelection && !versions.isEmpty()
332+
? List.of(versions.getFirst())
333+
: ordered;
317334
}
318335
}

launcher/src/main/java/net/modtale/launcher/ui/project/NativeDownloadModal.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,13 @@ void refresh(ProjectDetail project, GameVersionCatalog catalog) {
106106
this.project = project;
107107
this.catalog = catalog == null ? GameVersionCatalog.fromVersions(List.of()) : catalog;
108108
this.loading = false;
109-
if (!selectedGameVersions.isEmpty() && !gameVersions().containsAll(selectedGameVersions)) {
109+
List<String> availableGameVersions = gameVersions();
110+
if (selectedGameVersions.isEmpty() && !availableGameVersions.isEmpty()) {
111+
selectedGameVersions = preferredVisibleGameVersions();
112+
listExpanded = false;
113+
} else if (!selectedGameVersions.isEmpty() && !availableGameVersions.containsAll(selectedGameVersions)) {
110114
List<String> validSelections = selectedGameVersions.stream()
111-
.filter(gameVersions()::contains)
115+
.filter(availableGameVersions::contains)
112116
.toList();
113117
selectedGameVersions = validSelections.isEmpty() ? preferredVisibleGameVersions() : validSelections;
114118
listExpanded = false;
@@ -267,14 +271,14 @@ private VBox body() {
267271
versionLabel.getStyleClass().add("download-modal-field-label");
268272
GameVersionDropdown versions = GameVersionDropdown.multiSelect();
269273
versions.getStyleClass().add("download-game-version-dropdown");
270-
versions.setAnyLabel("Any");
274+
versions.setAllowEmptySelection(false);
271275
versions.setEmptyText("No compatible game versions");
272276
versions.setMaxListHeight(224);
273277
versions.setVersions(gameVersions());
274-
versions.setSelectedVersions(selectedGameVersions);
278+
versions.setSelectedVersions(activeSelectedGameVersions());
275279
versions.setOnOpenChange(open -> gameVersionDropdownOpen = open);
276280
versions.setOnSelectionChange(next -> {
277-
selectedGameVersions = List.copyOf(next);
281+
selectedGameVersions = next.isEmpty() ? preferredVisibleGameVersions() : List.copyOf(next);
278282
listExpanded = false;
279283
rebuildOverlay();
280284
});
@@ -603,7 +607,14 @@ private List<String> gameVersions() {
603607
}
604608

605609
private List<String> activeSelectedGameVersions() {
606-
return selectedGameVersions.isEmpty() ? gameVersions() : selectedGameVersions;
610+
if (selectedGameVersions.isEmpty()) {
611+
return preferredVisibleGameVersions();
612+
}
613+
List<String> versions = gameVersions();
614+
List<String> validSelections = selectedGameVersions.stream()
615+
.filter(versions::contains)
616+
.toList();
617+
return validSelections.isEmpty() ? preferredVisibleGameVersions() : validSelections;
607618
}
608619

609620
private List<VersionEntry> selectedVersionEntries() {
@@ -633,9 +644,8 @@ private List<VersionEntry> sortedVisibleVersions() {
633644

634645
private List<String> preferredVisibleGameVersions() {
635646
List<String> versions = gameVersions();
636-
String preferred = preferredGameVersion.get();
637-
if (preferred != null && versions.contains(preferred)) {
638-
return List.of(preferred);
647+
if (versions.isEmpty()) {
648+
return List.of();
639649
}
640650
if (!selectedGameVersions.isEmpty()) {
641651
List<String> validSelections = selectedGameVersions.stream()
@@ -645,8 +655,7 @@ private List<String> preferredVisibleGameVersions() {
645655
return validSelections;
646656
}
647657
}
648-
List<GameVersionGroups.Group> groups = GameVersionGroups.build(versions);
649-
return groups.isEmpty() ? List.of() : groups.getFirst().versions();
658+
return List.of(versions.getFirst());
650659
}
651660

652661
private Map<String, List<ProjectVersion>> versionsByGame() {
@@ -728,7 +737,7 @@ private boolean shouldShowEntryGameVersion() {
728737
}
729738

730739
private String selectedGameVersionLabel() {
731-
return GameVersionGroups.displayLabel(selectedGameVersions, gameVersions(), "any version");
740+
return GameVersionGroups.displayLabel(activeSelectedGameVersions(), gameVersions(), "selected version");
732741
}
733742

734743
private List<String> otherCompatibleVersions(ProjectVersion version, String selectedGameVersion) {
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package net.modtale.launcher.ui.project;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.lang.reflect.Field;
6+
import java.util.List;
7+
import javafx.scene.layout.StackPane;
8+
import net.modtale.launcher.model.project.GameVersionCatalog;
9+
import net.modtale.launcher.model.project.ProjectDetail;
10+
import net.modtale.launcher.model.project.ProjectVersion;
11+
import org.junit.jupiter.api.Test;
12+
13+
class NativeDownloadModalTest {
14+
15+
@Test
16+
void defaultsToLatestCatalogGameVersionInsteadOfPreferredOrGroupedFamily() throws Exception {
17+
NativeDownloadModal modal = new NativeDownloadModal(
18+
() -> null,
19+
() -> "0.5.3",
20+
ignored -> {
21+
},
22+
ignored -> {
23+
}
24+
);
25+
26+
modal.show(project(List.of(
27+
version("v53", "1.0.0", "0.5.3"),
28+
version("v54", "1.1.0", "0.5.4"),
29+
version("v49", "0.9.0", "0.4.9")
30+
)), catalog("0.5.4", "0.5.3", "0.4.9"));
31+
32+
assertEquals(List.of("0.5.4"), selectedGameVersions(modal));
33+
}
34+
35+
@Test
36+
void refreshPromotesEmptySelectionToLatestCatalogGameVersion() throws Exception {
37+
NativeDownloadModal modal = new NativeDownloadModal(
38+
() -> null,
39+
() -> "",
40+
ignored -> {
41+
},
42+
ignored -> {
43+
}
44+
);
45+
ProjectDetail emptyProject = project(List.of());
46+
ProjectDetail hydratedProject = project(List.of(
47+
version("v53", "1.0.0", "0.5.3"),
48+
version("v54", "1.1.0", "0.5.4")
49+
));
50+
51+
modal.showLoading(emptyProject, catalog("0.5.4", "0.5.3"));
52+
assertEquals(List.of(), selectedGameVersions(modal));
53+
markShowing(modal);
54+
55+
modal.refresh(hydratedProject, catalog("0.5.4", "0.5.3"));
56+
57+
assertEquals(List.of("0.5.4"), selectedGameVersions(modal));
58+
}
59+
60+
private static ProjectDetail project(List<ProjectVersion> versions) {
61+
return new ProjectDetail(
62+
"project-id",
63+
"skyforge",
64+
"Skyforge",
65+
"A test project",
66+
"Modtale",
67+
"PLUGIN",
68+
"2026-01-01T00:00:00Z",
69+
"MIT",
70+
null,
71+
List.of("Magic"),
72+
versions
73+
);
74+
}
75+
76+
private static ProjectVersion version(String id, String versionNumber, String gameVersion) {
77+
return new ProjectVersion(
78+
id,
79+
versionNumber,
80+
List.of(gameVersion),
81+
"/files/" + id + ".jar",
82+
0,
83+
"2026-01-01T00:00:00Z",
84+
"",
85+
List.of(),
86+
"RELEASE"
87+
);
88+
}
89+
90+
private static GameVersionCatalog catalog(String... versions) {
91+
return GameVersionCatalog.fromVersions(List.of(versions));
92+
}
93+
94+
@SuppressWarnings("unchecked")
95+
private static List<String> selectedGameVersions(NativeDownloadModal modal) throws Exception {
96+
Field field = NativeDownloadModal.class.getDeclaredField("selectedGameVersions");
97+
field.setAccessible(true);
98+
return (List<String>) field.get(modal);
99+
}
100+
101+
private static void markShowing(NativeDownloadModal modal) throws Exception {
102+
Field field = NativeDownloadModal.class.getDeclaredField("overlay");
103+
field.setAccessible(true);
104+
field.set(modal, new StackPane());
105+
}
106+
}

0 commit comments

Comments
 (0)