Skip to content

Commit 012d299

Browse files
JJ173Sheikah45
andauthored
Coop Tab UI Updates (#3445)
* Added coop category to FAF Client * Added support for scenarios * Corrected API call to include maps. * Final changes for the coop tab updates. * Reverted changes to .idea xml files modified for local development * Applied changes suggested by coderabbitai. * Added a tooltip to the FAF Campaign Discord button * Removed invalid GridPane positioning attributes * Updated changes with requested changes * Applied code changes as per coderabbit suggestions * Added coop category to FAF Client * Added support for scenarios * Corrected API call to include maps. * Final changes for the coop tab updates. * Reverted changes to .idea xml files modified for local development * Applied changes suggested by coderabbitai. * Added a tooltip to the FAF Campaign Discord button * Removed invalid GridPane positioning attributes * Updated changes with requested changes * Applied code changes as per coderabbit suggestions * Small clean up * Fixed broken coop tests --------- Co-authored-by: Sheikah45 <Sheikah450@gmail.com>
1 parent 95c16ce commit 012d299

File tree

17 files changed

+211
-113
lines changed

17 files changed

+211
-113
lines changed

src/main/java/com/faforever/client/api/FafApiAccessor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.faforever.commons.api.dto.ApiException;
88
import com.faforever.commons.api.dto.Clan;
99
import com.faforever.commons.api.dto.CoopResult;
10+
import com.faforever.commons.api.dto.CoopScenario;
1011
import com.faforever.commons.api.dto.CoturnServer;
1112
import com.faforever.commons.api.dto.Game;
1213
import com.faforever.commons.api.dto.GameReviewsSummary;
@@ -108,7 +109,8 @@ public class FafApiAccessor implements InitializingBean {
108109
java.util.Map.entry(ModerationReport.class, List.of("reporter", "lastModerator", "reportedUsers", "game", "game.playerStats", "game.playerStats.player")),
109110
java.util.Map.entry(MatchmakerQueue.class, List.of("leaderboard")),
110111
java.util.Map.entry(TutorialCategory.class, List.of("tutorials", "tutorials.mapVersion.map", "tutorials.mapVersion.map.latestVersion",
111-
"tutorials.mapVersion.map.author"))
112+
"tutorials.mapVersion.map.author")),
113+
java.util.Map.entry(CoopScenario.class, List.of("maps"))
112114
);
113115

114116
@VisibleForTesting

src/main/java/com/faforever/client/config/CacheConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static com.faforever.client.config.CacheNames.CLAN;
2323
import static com.faforever.client.config.CacheNames.COOP_LEADERBOARD;
2424
import static com.faforever.client.config.CacheNames.COOP_MAPS;
25+
import static com.faforever.client.config.CacheNames.COOP_SCENARIOS;
2526
import static com.faforever.client.config.CacheNames.COTURN;
2627
import static com.faforever.client.config.CacheNames.COUNTRY_FLAGS;
2728
import static com.faforever.client.config.CacheNames.COUNTRY_NAMES;
@@ -91,6 +92,7 @@ public CacheManager cacheManager() {
9192
newBuilder().maximumSize(1).expireAfterAccess(5, MINUTES).buildAsync(), true),
9293
new CaffeineCache(AVAILABLE_AVATARS, newBuilder().expireAfterAccess(10, MINUTES).buildAsync(), true),
9394
new CaffeineCache(COOP_MAPS, newBuilder().expireAfterAccess(10, MINUTES).buildAsync(), true),
95+
new CaffeineCache(COOP_SCENARIOS, newBuilder().expireAfterAccess(10, MINUTES).buildAsync(), true),
9496
new CaffeineCache(NEWS, newBuilder().expireAfterWrite(5, MINUTES).buildAsync(), true),
9597
new CaffeineCache(RATING_HISTORY, newBuilder().expireAfterWrite(1, MINUTES).buildAsync(), true),
9698
new CaffeineCache(COOP_LEADERBOARD, newBuilder().expireAfterWrite(1, MINUTES).buildAsync(), true),

src/main/java/com/faforever/client/config/CacheNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public final class CacheNames {
3131
public static final String IMAGES = "images";
3232
public static final String MOD_THUMBNAIL = "modThumbnail";
3333
public static final String COOP_MAPS = "coopMaps";
34+
public static final String COOP_SCENARIOS = "coopScenarios";
3435
public static final String AVAILABLE_AVATARS = "availableAvatars";
3536
public static final String NEWS = "news";
3637
public static final String RATING_HISTORY = "ratingHistory";

src/main/java/com/faforever/client/coop/CoopCategory.java

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/main/java/com/faforever/client/coop/CoopController.java

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import com.faforever.client.domain.api.CoopMission;
44
import com.faforever.client.domain.api.CoopResult;
5+
import com.faforever.client.domain.api.CoopScenario;
56
import com.faforever.client.domain.server.GameInfo;
67
import com.faforever.client.fx.ControllerTableCell;
78
import com.faforever.client.fx.FxApplicationThreadExecutor;
89
import com.faforever.client.fx.ImageViewHelper;
910
import com.faforever.client.fx.NodeController;
1011
import com.faforever.client.fx.ObservableConstant;
12+
import com.faforever.client.fx.PlatformService;
1113
import com.faforever.client.fx.StringCell;
1214
import com.faforever.client.fx.StringListCell;
1315
import com.faforever.client.fx.WebViewConfigurer;
@@ -57,6 +59,7 @@
5759
import java.time.OffsetDateTime;
5860
import java.util.Collection;
5961
import java.util.List;
62+
import java.util.Objects;
6063
import java.util.Optional;
6164
import java.util.Set;
6265
import java.util.function.Function;
@@ -77,6 +80,7 @@ public class CoopController extends NodeController<Node> {
7780
private final ReplayService replayService;
7881
private final GameService gameService;
7982
private final CoopService coopService;
83+
private final PlatformService platformService;
8084
private final ImageViewHelper imageViewHelper;
8185
private final NotificationService notificationService;
8286
private final I18n i18n;
@@ -89,6 +93,7 @@ public class CoopController extends NodeController<Node> {
8993
private final FilteredList<CoopResult> leaderboardFilteredList = new FilteredList<>(leaderboardUnFilteredList);
9094

9195
public GridPane coopRoot;
96+
public ComboBox<CoopScenario> scenarioComboBox;
9297
public ComboBox<CoopMission> missionComboBox;
9398
public WebView descriptionWebView;
9499
public Pane gameViewContainer;
@@ -111,9 +116,13 @@ public class CoopController extends NodeController<Node> {
111116

112117
@Override
113118
protected void onInitialize() {
114-
missionComboBox.setCellFactory(param -> missionListCell());
115-
missionComboBox.setButtonCell(missionListCell());
119+
scenarioComboBox.setCellFactory(param -> scenarioListCell());
120+
scenarioComboBox.setButtonCell(scenarioListCell());
121+
scenarioComboBox.getSelectionModel().selectedItemProperty().when(showing).subscribe(this::populateMissionList);
122+
116123
missionComboBox.getSelectionModel().selectedItemProperty().when(showing).subscribe(this::setSelectedMission);
124+
missionComboBox.setButtonCell(missionListCell());
125+
missionComboBox.setCellFactory(param -> missionListCell());
117126

118127
mapPreviewImageView.imageProperty()
119128
.bind(missionComboBox.getSelectionModel().selectedItemProperty().map(CoopMission::mapFolderName)
@@ -148,10 +157,10 @@ protected void onInitialize() {
148157
playerCountColumn.setCellFactory(param -> new StringCell<>(String::valueOf));
149158

150159
playerNamesColumn.setCellValueFactory(param -> ObservableConstant.valueOf(param.getValue().replay().teams().values()
151-
.stream()
152-
.flatMap(Collection::stream)
153-
.collect(Collectors.joining(
154-
i18n.get("textSeparator")))));
160+
.stream()
161+
.flatMap(Collection::stream)
162+
.collect(Collectors.joining(
163+
i18n.get("textSeparator")))));
155164

156165
playerNamesColumn.setCellFactory(param -> new StringCell<>(Function.identity()));
157166

@@ -185,25 +194,32 @@ protected void onInitialize() {
185194
FilteredList<GameInfo> filteredItems = new FilteredList<>(gameService.getGames());
186195
filteredItems.setPredicate(OPEN_COOP_GAMES_PREDICATE);
187196

188-
coopService.getMissions()
197+
coopService.getScenarios()
189198
.collectList()
190199
.map(FXCollections::observableList)
191200
.publishOn(fxApplicationThreadExecutor.asScheduler())
192-
.subscribe(coopMaps -> {
193-
missionComboBox.setItems(coopMaps);
201+
.subscribe(coopScenarios -> {
202+
scenarioComboBox.getItems().addAll(coopScenarios);
203+
204+
List<CoopMission> coopMissions = coopScenarios.stream()
205+
.map(CoopScenario::maps)
206+
.filter(Objects::nonNull)
207+
.flatMap(Collection::stream)
208+
.toList();
194209

195210
gamesTableController.initializeGameTable(filteredItems,
196-
mapFolderName -> coopMissionFromFolderName(coopMaps,
211+
mapFolderName -> coopMissionFromFolderName(coopMissions,
197212
mapFolderName),
198213
false);
199214
gamesTableController.getMapPreviewColumn().setVisible(false);
200215
gamesTableController.getRatingRangeColumn().setVisible(false);
201216

217+
SingleSelectionModel<CoopScenario> selectionModel = scenarioComboBox.getSelectionModel();
202218

203-
SingleSelectionModel<CoopMission> selectionModel = missionComboBox.getSelectionModel();
204219
if (selectionModel.isEmpty()) {
205220
selectionModel.selectFirst();
206221
}
222+
207223
}, throwable -> notificationService.addPersistentErrorNotification("coop.couldNotLoad",
208224
throwable.getLocalizedMessage()));
209225
}
@@ -232,22 +248,28 @@ private ListCell<Integer> numberOfPlayersCell() {
232248
}, fxApplicationThreadExecutor);
233249
}
234250

235-
private ListCell<CoopMission> missionListCell() {
236-
return new StringListCell<>(fxApplicationThreadExecutor, CoopMission::name, mission -> {
251+
private ListCell<CoopScenario> scenarioListCell() {
252+
return new StringListCell<>(fxApplicationThreadExecutor, CoopScenario::name, category -> {
237253
Label label = new Label();
238254
Region iconRegion = new Region();
239255
label.setGraphic(iconRegion);
240256
iconRegion.getStyleClass().add(ThemeService.CSS_CLASS_ICON);
241-
switch (mission.category()) {
257+
switch (category.faction()) {
242258
case AEON -> iconRegion.getStyleClass().add(ThemeService.AEON_STYLE_CLASS);
243259
case CYBRAN -> iconRegion.getStyleClass().add(ThemeService.CYBRAN_STYLE_CLASS);
244260
case UEF -> iconRegion.getStyleClass().add(ThemeService.UEF_STYLE_CLASS);
261+
case SERAPHIM -> iconRegion.getStyleClass().add(ThemeService.SERAPHIM_STYLE_CLASS);
262+
case CUSTOM -> iconRegion.getStyleClass().add(ThemeService.WRENCH_STYLE_CLASS);
245263
default -> {
246264
return null;
247265
}
248266
}
249267
return label;
250-
}, Pos.CENTER_LEFT, "coop-mission");
268+
}, Pos.CENTER_LEFT, "coop-category");
269+
}
270+
271+
private ListCell<CoopMission> missionListCell() {
272+
return new StringListCell<>(fxApplicationThreadExecutor, this::getMissionConcatDisplayName, null, Pos.CENTER_LEFT, "coop-mission");
251273
}
252274

253275
private void loadLeaderboard() {
@@ -274,11 +296,25 @@ private Set<String> getAllPlayerNamesFromTeams(CoopResult coopResult) {
274296
.collect(Collectors.toUnmodifiableSet());
275297
}
276298

277-
278299
private CoopMission getSelectedMission() {
279300
return missionComboBox.getSelectionModel().getSelectedItem();
280301
}
281302

303+
private void populateMissionList(CoopScenario scenario) {
304+
if (scenario == null) {
305+
return;
306+
}
307+
308+
List<CoopMission> missions = scenario.maps();
309+
if (missions == null || missions.isEmpty()) {
310+
missionComboBox.getItems().clear();
311+
return;
312+
}
313+
314+
missionComboBox.getItems().setAll(missions);
315+
missionComboBox.getSelectionModel().select(0);
316+
}
317+
282318
private void setSelectedMission(CoopMission mission) {
283319
if (mission == null) {
284320
return;
@@ -297,10 +333,22 @@ public void onPlayButtonClicked() {
297333
COOP.getTechnicalName(), getSelectedMission().mapFolderName(), Set.of()));
298334
}
299335

336+
public void onWikiButtonClicked() {
337+
platformService.showDocument("https://wiki.faforever.com/en/Development/Missions/Mission-Scripting");
338+
}
339+
340+
public void onDiscordHyperLinkClicked() {
341+
platformService.showDocument("https://discord.gg/ayzAVr9JUV");
342+
}
343+
300344
public void onMapPreviewImageClicked() {
301345
Optional.ofNullable(mapPreviewImageView.getImage()).ifPresent(PopupUtil::showImagePopup);
302346
}
303347

348+
public String getMissionConcatDisplayName(CoopMission mission) {
349+
return mission.name() + " - V" + mission.version();
350+
}
351+
304352
@Override
305353
public Node getRoot() {
306354
return coopRoot;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.faforever.client.coop;
2+
3+
public enum CoopFaction {
4+
UEF, CYBRAN, AEON, SERAPHIM, CUSTOM
5+
}

src/main/java/com/faforever/client/coop/CoopService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.faforever.client.config.CacheNames;
55
import com.faforever.client.domain.api.CoopMission;
66
import com.faforever.client.domain.api.CoopResult;
7+
import com.faforever.client.domain.api.CoopScenario;
78
import com.faforever.client.mapstruct.CoopMapper;
89
import com.faforever.commons.api.dto.Game;
910
import com.faforever.commons.api.dto.GamePlayerStats;
@@ -39,6 +40,14 @@ public Flux<CoopMission> getMissions() {
3940
return fafApiAccessor.getMany(navigator).map(coopMapper::map).cache();
4041
}
4142

43+
@Cacheable(value = CacheNames.COOP_SCENARIOS, sync = true)
44+
public Flux<CoopScenario> getScenarios() {
45+
ElideNavigatorOnCollection<com.faforever.commons.api.dto.CoopScenario> navigator = ElideNavigator.of(
46+
com.faforever.commons.api.dto.CoopScenario.class).collection();
47+
return fafApiAccessor.getMany(navigator).map(coopMapper::map).cache();
48+
}
49+
50+
4251
@Cacheable(value = CacheNames.COOP_LEADERBOARD, sync = true)
4352
public Flux<CoopResult> getLeaderboard(CoopMission mission, int numberOfPlayers) {
4453
Condition<?> filterCondition = qBuilder().intNum("mission").eq(mission.id());
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.faforever.client.coop;
2+
3+
public enum CoopType {
4+
SC, SCFA, CUSTOM
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.faforever.client.domain.api;
2+
3+
import com.faforever.client.coop.CoopFaction;
4+
5+
public record CoopCategory(
6+
String categoryName,
7+
CoopFaction coopCategory
8+
) {}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
package com.faforever.client.domain.api;
22

3-
import com.faforever.client.coop.CoopCategory;
4-
53
import java.net.URL;
64

75
public record CoopMission(
86
Integer id,
97
String name,
108
String description,
119
int version,
12-
CoopCategory category,
1310
URL downloadUrl,
1411
URL thumbnailUrlSmall,
1512
URL thumbnailUrlLarge,
1613
String mapFolderName
17-
) {}
14+
) {}

0 commit comments

Comments
 (0)