From 7fc8fc40b4de2a3130b68dbe6b66666a87905ae0 Mon Sep 17 00:00:00 2001 From: obydog002 <> Date: Sat, 11 May 2024 14:04:17 +0800 Subject: [PATCH] #3118 add persistent properties to replay search page --- .../client/map/MapVaultController.java | 23 +- .../client/mod/ModVaultController.java | 17 +- .../client/preferences/VaultPrefs.java | 221 +++++++++++++++++- .../query/CategoryFilterController.java | 14 ++ .../query/DateRangeFilterController.java | 6 + .../client/query/RangeFilterController.java | 11 +- .../client/query/TextFilterController.java | 3 + .../client/query/ToggleFilterController.java | 5 + .../replay/OnlineReplayVaultController.java | 26 ++- .../client/vault/search/SearchController.java | 31 ++- .../client/game/CreateGameControllerTest.java | 4 +- .../query/CategoryFilterControllerTest.java | 29 +++ .../query/DateRangeFilterControllerTest.java | 28 +++ .../query/RangeFilterControllerTest.java | 34 ++- .../query/TextFilterControllerTest.java | 26 +++ .../query/ToggleFilterControllerTest.java | 24 ++ .../OnlineReplayVaultControllerTest.java | 4 +- 17 files changed, 465 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/faforever/client/map/MapVaultController.java b/src/main/java/com/faforever/client/map/MapVaultController.java index 1d7e9dbe2d..430b44bb45 100644 --- a/src/main/java/com/faforever/client/map/MapVaultController.java +++ b/src/main/java/com/faforever/client/map/MapVaultController.java @@ -20,11 +20,17 @@ import com.faforever.client.vault.VaultEntityCardController; import com.faforever.client.vault.VaultEntityController; import com.faforever.client.vault.search.SearchController.SearchConfig; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; import javafx.scene.Node; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import javafx.collections.ObservableList; +import java.time.LocalDate; import java.nio.file.Path; import java.util.LinkedHashMap; @@ -76,9 +82,9 @@ protected void initSearchController() { searchController.setVaultRoot(vaultRoot); searchController.setSavedQueries(vaultPrefs.getSavedMapQueries()); - searchController.addTextFilter("displayName", i18n.get("map.name"), false); - searchController.addTextFilter("author.login", i18n.get("map.author"), false); - searchController.addDateRangeFilter("latestVersion.updateTime", i18n.get("map.uploadedDateTime"), 0); + searchController.addTextFilter("displayName", i18n.get("map.name"), false, new SimpleStringProperty()); + searchController.addTextFilter("author.login", i18n.get("map.author"), false, new SimpleStringProperty()); + searchController.addDateRangeFilter("latestVersion.updateTime", i18n.get("map.uploadedDateTime"), 0, new SimpleObjectProperty(), new SimpleObjectProperty()); LinkedHashMap mapSizeMap = new LinkedHashMap<>(); mapSizeMap.put("1km", "64"); @@ -89,11 +95,12 @@ protected void initSearchController() { mapSizeMap.put("40km", "2048"); mapSizeMap.put("80km", "4096"); - searchController.addCategoryFilter("latestVersion.width", i18n.get("map.width"), mapSizeMap); - searchController.addCategoryFilter("latestVersion.height", i18n.get("map.height"), mapSizeMap); - searchController.addRangeFilter("latestVersion.maxPlayers", i18n.get("map.maxPlayers"), 0, 16, 16, 0, 0, Double::intValue); - searchController.addRangeFilter("reviewsSummary.averageScore", i18n.get("reviews.averageScore"), 0, 5, 10, 4, 1); - searchController.addToggleFilter("latestVersion.ranked", i18n.get("map.onlyRanked"), "true"); + // TODO add persistence + searchController.addCategoryFilter("latestVersion.width", i18n.get("map.width"), mapSizeMap, new SimpleObjectProperty>()); + searchController.addCategoryFilter("latestVersion.height", i18n.get("map.height"), mapSizeMap, new SimpleObjectProperty>()); + searchController.addRangeFilter("latestVersion.maxPlayers", i18n.get("map.maxPlayers"), 0, 16, 16, 0, 0, Double::intValue, new SimpleDoubleProperty(), new SimpleDoubleProperty()); + searchController.addRangeFilter("reviewsSummary.averageScore", i18n.get("reviews.averageScore"), 0, 5, 10, 4, 1, new SimpleDoubleProperty(), new SimpleDoubleProperty()); + searchController.addToggleFilter("latestVersion.ranked", i18n.get("map.onlyRanked"), "true", new SimpleBooleanProperty()); } @Override diff --git a/src/main/java/com/faforever/client/mod/ModVaultController.java b/src/main/java/com/faforever/client/mod/ModVaultController.java index 5d1d504f08..891562c97b 100644 --- a/src/main/java/com/faforever/client/mod/ModVaultController.java +++ b/src/main/java/com/faforever/client/mod/ModVaultController.java @@ -18,12 +18,17 @@ import com.faforever.client.vault.VaultEntityCardController; import com.faforever.client.vault.VaultEntityController; import com.faforever.client.vault.search.SearchController.SearchConfig; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; import javafx.scene.Node; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import java.time.LocalDate; import java.nio.file.Path; import java.util.List; import java.util.Random; @@ -147,15 +152,15 @@ protected void initSearchController() { searchController.setVaultRoot(vaultRoot); searchController.setSavedQueries(vaultPrefs.getSavedModQueries()); - searchController.addTextFilter("displayName", i18n.get("mod.displayName"), false); - searchController.addTextFilter("author", i18n.get("mod.author"), false); - searchController.addDateRangeFilter("latestVersion.updateTime", i18n.get("mod.uploadedDateTime"), 0); - - searchController.addRangeFilter("reviewsSummary.averageScore", i18n.get("reviews.averageScore"), 0, 5, 10, 4, 1); + searchController.addTextFilter("displayName", i18n.get("mod.displayName"), false, new SimpleStringProperty()); + searchController.addTextFilter("author", i18n.get("mod.author"), false, new SimpleStringProperty()); + searchController.addDateRangeFilter("latestVersion.updateTime", i18n.get("mod.uploadedDateTime"), 0, new SimpleObjectProperty(), new SimpleObjectProperty()); + // TODO add persistence + searchController.addRangeFilter("reviewsSummary.averageScore", i18n.get("reviews.averageScore"), 0, 5, 10, 4, 1, new SimpleDoubleProperty(), new SimpleDoubleProperty()); searchController.addBinaryFilter("latestVersion.type", i18n.get("mod.type"), ModType.UI.toString(), ModType.SIM.toString(), i18n.get("modType.ui"), i18n.get("modType.sim")); - searchController.addToggleFilter("latestVersion.ranked", i18n.get("mod.onlyRanked"), "true"); + searchController.addToggleFilter("latestVersion.ranked", i18n.get("mod.onlyRanked"), "true", new SimpleBooleanProperty()); } @Override diff --git a/src/main/java/com/faforever/client/preferences/VaultPrefs.java b/src/main/java/com/faforever/client/preferences/VaultPrefs.java index b4059b13ef..944a4996d8 100644 --- a/src/main/java/com/faforever/client/preferences/VaultPrefs.java +++ b/src/main/java/com/faforever/client/preferences/VaultPrefs.java @@ -2,14 +2,23 @@ import com.faforever.client.vault.search.SearchController.SortConfig; import com.faforever.client.vault.search.SearchController.SortOrder; +import java.time.LocalDate; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ListProperty; import javafx.beans.property.MapProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.StringProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleMapProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.SimpleDoubleProperty; import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.collections.ObservableMap; - public class VaultPrefs { private final ObjectProperty onlineReplaySortConfig = new SimpleObjectProperty<>( new SortConfig("startTime", SortOrder.DESC)); @@ -23,6 +32,24 @@ public class VaultPrefs { FXCollections.observableHashMap()); private final MapProperty savedModQueries = new SimpleMapProperty<>( FXCollections.observableHashMap()); + private final StringProperty playerNameField = new SimpleStringProperty(); + private final StringProperty mapNameField = new SimpleStringProperty(); + private final StringProperty mapAuthorField = new SimpleStringProperty(); + private final StringProperty titleField = new SimpleStringProperty(); + private final StringProperty replayIDField = new SimpleStringProperty(); + private final ObjectProperty> featuredModFilter = new SimpleObjectProperty>( + FXCollections.emptyObservableList()); + private final ObjectProperty> leaderboardFilter = new SimpleObjectProperty>( + FXCollections.emptyObservableList()); + private final DoubleProperty ratingMin = new SimpleDoubleProperty(); + private final DoubleProperty ratingMax = new SimpleDoubleProperty(); + private final DoubleProperty averageReviewScoresMin = new SimpleDoubleProperty(); + private final DoubleProperty averageReviewScoresMax = new SimpleDoubleProperty(); + private final ObjectProperty gameBeforeDate = new SimpleObjectProperty(); + private final ObjectProperty gameAfterDate = new SimpleObjectProperty(); + private final DoubleProperty gameDurationMin = new SimpleDoubleProperty(); + private final DoubleProperty gameDurationMax = new SimpleDoubleProperty(); + private final BooleanProperty onlyRanked = new SimpleBooleanProperty(); public SortConfig getOnlineReplaySortConfig() { return onlineReplaySortConfig.get(); @@ -95,4 +122,196 @@ public void setSavedModQueries(ObservableMap savedModQueries) { public MapProperty savedModQueriesProperty() { return savedModQueries; } + + public String getPlayerNameField() { + return playerNameField.get(); + } + + public void setPlayerNameField(String playerName) { + this.playerNameField.set(playerName); + } + + public StringProperty playerNameFieldProperty() { + return playerNameField; + } + + public String getMapNameField() { + return mapNameField.get(); + } + + public void setMapNameField(String mapName) { + this.mapNameField.set(mapName); + } + + public StringProperty mapNameFieldProperty() { + return mapNameField; + } + + public String getMapAuthorField() { + return mapAuthorField.get(); + } + + public void setMapAuthorField(String mapAuthor) { + this.mapAuthorField.set(mapAuthor); + } + + public StringProperty mapAuthorFieldProperty() { + return mapAuthorField; + } + + public String getTitleField() { + return titleField.get(); + } + + public void setTitleField(String titleField) { + this.titleField.set(titleField); + } + + public StringProperty titleFieldProperty() { + return titleField; + } + + public String getReplayIDField() { + return replayIDField.get(); + } + + public void setReplayIDField(String replayIDField) { + this.replayIDField.set(replayIDField); + } + + public StringProperty replayIDFieldProperty() { + return replayIDField; + } + + public ObservableList getFeaturedModFilter() { + return featuredModFilter.get(); + } + + public void setFeaturedModFilter(ObservableList featuredModFilter) { + this.featuredModFilter.set(featuredModFilter); + } + + public ObjectProperty> featuredModFilterProperty() { + return featuredModFilter; + } + + public ObservableList getLeaderboardFilter() { + return leaderboardFilter.get(); + } + + public void setLeaderboardFilter(ObservableList leaderboardFilter) { + this.leaderboardFilter.set(leaderboardFilter); + } + + public ObjectProperty> leaderboardFilterProperty() { + return leaderboardFilter; + } + + public Double getRatingMin() { + return ratingMin.get(); + } + + public void setRatingMin(Double ratingMin) { + this.ratingMin.set(ratingMin); + } + + public DoubleProperty ratingMinProperty() { + return ratingMin; + } + + public Double getRatingMax() { + return ratingMax.get(); + } + + public void setRatingMax(Double ratingMax) { + this.ratingMax.set(ratingMax); + } + + public DoubleProperty ratingMaxProperty() { + return ratingMax; + } + + public Double getAverageReviewScoresMin() { + return averageReviewScoresMin.get(); + } + + public void setAverageReviewScoresMin(Double averageReviewScoresMin) { + this.averageReviewScoresMin.set(averageReviewScoresMin); + } + + public DoubleProperty averageReviewScoresMinProperty() { + return averageReviewScoresMin; + } + + public Double getAverageReviewScoresMax() { + return averageReviewScoresMax.get(); + } + + public void setAverageReviewScoresMax(Double averageReviewScoresMax) { + this.averageReviewScoresMax.set(averageReviewScoresMax); + } + + public DoubleProperty averageReviewScoresMaxProperty() { + return averageReviewScoresMax; + } + + public LocalDate getGameBeforeDate() { + return gameBeforeDate.get(); + } + + public void setGameBeforeDate(LocalDate gameBeforeDate) { + this.gameBeforeDate.set(gameBeforeDate); + } + + public ObjectProperty gameBeforeDateProperty() { + return gameBeforeDate; + } + + public LocalDate getGameAfterDate() { + return gameAfterDate.get(); + } + + public void setGameAfterDate(LocalDate gameAfterDate) { + this.gameAfterDate.set(gameAfterDate); + } + + public ObjectProperty gameAfterDateProperty() { + return gameAfterDate; + } + + public Double getGameDurationMin() { + return gameDurationMin.get(); + } + + public void setGameDurationMin(Double gameDurationMin) { + this.gameDurationMin.set(gameDurationMin); + } + + public DoubleProperty gameDurationMinProperty() { + return gameDurationMin; + } + + public Double getGameDurationMax() { + return gameDurationMax.get(); + } + + public void setGameDurationMax(Double gameDurationMax) { + this.gameDurationMax.set(gameDurationMax); + } + + public DoubleProperty gameDurationMaxProperty() { + return gameDurationMax; + } + + public Boolean getOnlyRanked() { + return onlyRanked.get(); + } + + public void setOnlyRanked(Boolean onlyRanked) { + this.onlyRanked.set(onlyRanked); + } + + public BooleanProperty onlyRankedProperty() { + return onlyRanked; + } } diff --git a/src/main/java/com/faforever/client/query/CategoryFilterController.java b/src/main/java/com/faforever/client/query/CategoryFilterController.java index 510068cecb..54051d26e2 100644 --- a/src/main/java/com/faforever/client/query/CategoryFilterController.java +++ b/src/main/java/com/faforever/client/query/CategoryFilterController.java @@ -5,7 +5,9 @@ import com.github.rutledgepaulv.qbuilders.conditions.Condition; import com.github.rutledgepaulv.qbuilders.properties.concrete.StringProperty; import javafx.beans.InvalidationListener; +import javafx.beans.property.ObjectProperty; import javafx.beans.binding.Bindings; +import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.control.MenuButton; import lombok.Getter; @@ -39,15 +41,24 @@ public class CategoryFilterController extends FilterNodeController { public MenuButton menu; private String propertyName; private Map itemMap; + private ObjectProperty> persistenceProperty; public void setItems(List items) { itemMap = null; checkListView.getItems().setAll(items); + if (persistenceProperty != null) { + persistenceProperty.get().stream().forEach((item) -> checkListView.getCheckModel().check(item)); + persistenceProperty.bind(Bindings.createObjectBinding(() -> checkListView.getCheckModel().getCheckedItems())); + } } public void setItems(Map items) { itemMap = items; checkListView.getItems().setAll(items.keySet()); + if (persistenceProperty != null) { + persistenceProperty.get().stream().forEach((item) -> checkListView.getCheckModel().check(item)); + persistenceProperty.bind(Bindings.createObjectBinding(() -> checkListView.getCheckModel().getCheckedItems())); + } } @@ -91,4 +102,7 @@ public Node getRoot() { return menu; } + public void setPersistenceProperty(ObjectProperty> property) { + this.persistenceProperty = property; + } } diff --git a/src/main/java/com/faforever/client/query/DateRangeFilterController.java b/src/main/java/com/faforever/client/query/DateRangeFilterController.java index 981fff9baf..4b8a757e3a 100644 --- a/src/main/java/com/faforever/client/query/DateRangeFilterController.java +++ b/src/main/java/com/faforever/client/query/DateRangeFilterController.java @@ -8,6 +8,7 @@ import com.github.rutledgepaulv.qbuilders.properties.concrete.InstantProperty; import javafx.beans.InvalidationListener; import javafx.beans.binding.Bindings; +import javafx.beans.property.ObjectProperty; import javafx.scene.Node; import javafx.scene.control.DatePicker; import javafx.scene.control.MenuButton; @@ -106,6 +107,11 @@ public void setInitialYearsBefore(int initialYearsBefore) { afterDate.setValue(LocalDate.now().minusYears(initialYearsBefore)); } + public void setPersistentBindings(ObjectProperty beforeDate, ObjectProperty afterDate) { + this.beforeDate.valueProperty().bindBidirectional(beforeDate); + this.afterDate.valueProperty().bindBidirectional(afterDate); + } + @Override public Node getRoot() { return menu; diff --git a/src/main/java/com/faforever/client/query/RangeFilterController.java b/src/main/java/com/faforever/client/query/RangeFilterController.java index dc78e306e1..006fa54619 100644 --- a/src/main/java/com/faforever/client/query/RangeFilterController.java +++ b/src/main/java/com/faforever/client/query/RangeFilterController.java @@ -38,7 +38,9 @@ public class RangeFilterController extends FilterNodeController { public MenuButton menu; public TextField lowValue; public TextField highValue; - + + private javafx.beans.property.DoubleProperty minProperty; + private javafx.beans.property.DoubleProperty maxProperty; private String propertyName; private Function valueTransform; private int numberOfFractionDigits; @@ -139,6 +141,13 @@ public void bind() { numberFormat.setMinimumFractionDigits(0); numberFormat.setMaximumFractionDigits(numberOfFractionDigits); JavaFxUtil.bindTextFieldAndRangeSlider(lowValue, highValue, rangeSlider, numberFormat); + this.minProperty.bindBidirectional(rangeSlider.lowValueProperty()); + this.maxProperty.bindBidirectional(rangeSlider.highValueProperty()); + } + + public void setPersistentRangeBindings(javafx.beans.property.DoubleProperty minProperty, javafx.beans.property.DoubleProperty maxProperty) { + this.minProperty = minProperty; + this.maxProperty = maxProperty; } @Override diff --git a/src/main/java/com/faforever/client/query/TextFilterController.java b/src/main/java/com/faforever/client/query/TextFilterController.java index 91aad70a43..9c6f41e8f8 100644 --- a/src/main/java/com/faforever/client/query/TextFilterController.java +++ b/src/main/java/com/faforever/client/query/TextFilterController.java @@ -81,4 +81,7 @@ public Node getRoot() { return textBox; } + public void setPersistenceProperty(javafx.beans.property.StringProperty property) { + this.textField.textProperty().bindBidirectional(property); + } } diff --git a/src/main/java/com/faforever/client/query/ToggleFilterController.java b/src/main/java/com/faforever/client/query/ToggleFilterController.java index ed349333d5..faf4f4ccfb 100644 --- a/src/main/java/com/faforever/client/query/ToggleFilterController.java +++ b/src/main/java/com/faforever/client/query/ToggleFilterController.java @@ -3,6 +3,7 @@ import com.github.rutledgepaulv.qbuilders.builders.QBuilder; import com.github.rutledgepaulv.qbuilders.conditions.Condition; import com.github.rutledgepaulv.qbuilders.properties.concrete.StringProperty; +import javafx.beans.property.BooleanProperty; import javafx.beans.InvalidationListener; import javafx.scene.Node; import javafx.scene.control.CheckBox; @@ -56,6 +57,10 @@ public void setTitle(String title) { this.title.setText(title + ":"); } + public void setPersistentProperty(BooleanProperty property) { + this.checkBox.selectedProperty().bindBidirectional(property); + } + @Override public Node getRoot() { return toggleFilter; diff --git a/src/main/java/com/faforever/client/replay/OnlineReplayVaultController.java b/src/main/java/com/faforever/client/replay/OnlineReplayVaultController.java index 8832e47f24..205b1a68a5 100644 --- a/src/main/java/com/faforever/client/replay/OnlineReplayVaultController.java +++ b/src/main/java/com/faforever/client/replay/OnlineReplayVaultController.java @@ -15,11 +15,13 @@ import com.faforever.client.preferences.VaultPrefs; import com.faforever.client.query.CategoryFilterController; import com.faforever.client.query.SearchablePropertyMappings; +import com.faforever.client.query.TextFilterController; import com.faforever.client.reporting.ReportingService; import com.faforever.client.theme.UiService; import com.faforever.client.vault.VaultEntityController; import com.faforever.client.vault.search.SearchController.SearchConfig; import com.faforever.commons.api.dto.Game; +import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.Node; @@ -131,14 +133,14 @@ protected void initSearchController() { searchController.setVaultRoot(vaultRoot); searchController.setSavedQueries(vaultPrefs.getSavedReplayQueries()); - searchController.addTextFilter("playerStats.player.login", i18n.get("game.player.username"), true); - searchController.addTextFilter("mapVersion.map.displayName", i18n.get("game.map.displayName"), false); - searchController.addTextFilter("mapVersion.map.author.login", i18n.get("game.map.author"), false); - searchController.addTextFilter("name", i18n.get("game.title"), false); - searchController.addTextFilter("id", i18n.get("game.id"), true); + searchController.addTextFilter("playerStats.player.login", i18n.get("game.player.username"), true, vaultPrefs.playerNameFieldProperty()); + searchController.addTextFilter("mapVersion.map.displayName", i18n.get("game.map.displayName"), false, vaultPrefs.mapNameFieldProperty()); + searchController.addTextFilter("mapVersion.map.author.login", i18n.get("game.map.author"), false, vaultPrefs.mapAuthorFieldProperty()); + searchController.addTextFilter("name", i18n.get("game.title"), false, vaultPrefs.titleFieldProperty()); + searchController.addTextFilter("id", i18n.get("game.id"), true, vaultPrefs.replayIDFieldProperty()); CategoryFilterController featuredModFilterController = searchController.addCategoryFilter("featuredMod.displayName", - i18n.get("featuredMod.displayName"), List.of()); + i18n.get("featuredMod.displayName"), List.of(), vaultPrefs.featuredModFilterProperty()); featuredModService.getFeaturedMods().map(FeaturedMod::displayName) .collectList() @@ -147,7 +149,7 @@ protected void initSearchController() { CategoryFilterController leaderboardFilterController = searchController.addCategoryFilter( "playerStats.ratingChanges.leaderboard.id", - i18n.get("leaderboard.displayName"), Map.of()); + i18n.get("leaderboard.displayName"), Map.of(), vaultPrefs.leaderboardFilterProperty()); leaderboardService.getLeaderboards() .collect(Collectors.toMap( @@ -158,13 +160,13 @@ protected void initSearchController() { //TODO: Use rating rather than estimated mean with an assumed deviation of 300 when that is available searchController.addRangeFilter("playerStats.ratingChanges.meanBefore", i18n.get("game.rating"), - MIN_RATING, MAX_RATING, 10, 4, 0, value -> value + 300); + MIN_RATING, MAX_RATING, 10, 4, 0, value -> value + 300, vaultPrefs.ratingMinProperty(), vaultPrefs.ratingMaxProperty()); - searchController.addRangeFilter("reviewsSummary.averageScore", i18n.get("reviews.averageScore"),0, 5, 10, 4, 1); + searchController.addRangeFilter("reviewsSummary.averageScore", i18n.get("reviews.averageScore"),0, 5, 10, 4, 1, vaultPrefs.averageReviewScoresMinProperty(), vaultPrefs.averageReviewScoresMaxProperty()); - searchController.addDateRangeFilter("endTime", i18n.get("game.date"), 1); - searchController.addRangeFilter("replayTicks", i18n.get("game.duration"), 0, 60, 12, 4, 0, value -> (int) (value * 60 * 10)); - searchController.addToggleFilter("validity", i18n.get("game.onlyRanked"), "VALID"); + searchController.addDateRangeFilter("endTime", i18n.get("game.date"), 1, vaultPrefs.gameBeforeDateProperty(), vaultPrefs.gameAfterDateProperty()); + searchController.addRangeFilter("replayTicks", i18n.get("game.duration"), 0, 60, 12, 4, 0, value -> (int) (value * 60 * 10), vaultPrefs.gameDurationMinProperty(), vaultPrefs.gameDurationMaxProperty()); + searchController.addToggleFilter("validity", i18n.get("game.onlyRanked"), "VALID", vaultPrefs.onlyRankedProperty()); } diff --git a/src/main/java/com/faforever/client/vault/search/SearchController.java b/src/main/java/com/faforever/client/vault/search/SearchController.java index c37012093e..f55da08d84 100644 --- a/src/main/java/com/faforever/client/vault/search/SearchController.java +++ b/src/main/java/com/faforever/client/vault/search/SearchController.java @@ -20,9 +20,13 @@ import com.github.rutledgepaulv.qbuilders.builders.QBuilder; import com.github.rutledgepaulv.qbuilders.conditions.Condition; import com.github.rutledgepaulv.qbuilders.visitors.RSQLVisitor; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableMap; +import javafx.collections.ObservableList; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; @@ -35,10 +39,12 @@ import javafx.util.StringConverter; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.controlsfx.control.IndexedCheckModel; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import java.time.LocalDate; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; @@ -274,42 +280,48 @@ public void addFilterNode(FilterNodeController filterNodeController) { queryInvalidationListener.invalidated(null); } - public TextFilterController addTextFilter(String propertyName, String title, boolean exact) { + public TextFilterController addTextFilter(String propertyName, String title, boolean exact, StringProperty persistentProperty) { TextFilterController textFilterController = uiService.loadFxml("theme/vault/search/textFilter.fxml"); textFilterController.setExact(exact); textFilterController.setPropertyName(propertyName); textFilterController.setTitle(title); textFilterController.setOnAction(this::onSearchButtonClicked); + textFilterController.setPersistenceProperty(persistentProperty); addFilterNode(textFilterController); return textFilterController; } - public CategoryFilterController addCategoryFilter(String propertyName, String title, List items) { + public CategoryFilterController addCategoryFilter(String propertyName, String title, List items, ObjectProperty> persistentProperty) { CategoryFilterController categoryFilterController = uiService.loadFxml("theme/vault/search/categoryFilter.fxml"); categoryFilterController.setPropertyName(propertyName); categoryFilterController.setTitle(title); categoryFilterController.setItems(items); + categoryFilterController.setPersistenceProperty(persistentProperty); addFilterNode(categoryFilterController); return categoryFilterController; } - public CategoryFilterController addCategoryFilter(String propertyName, String title, Map items) { + public CategoryFilterController addCategoryFilter(String propertyName, String title, Map items, ObjectProperty> persistentProperty) { CategoryFilterController categoryFilterController = uiService.loadFxml("theme/vault/search/categoryFilter.fxml"); categoryFilterController.setPropertyName(propertyName); categoryFilterController.setTitle(title); categoryFilterController.setItems(items); + categoryFilterController.setPersistenceProperty(persistentProperty); addFilterNode(categoryFilterController); return categoryFilterController; } public void addRangeFilter(String propertyName, String title, double min, double max, - int majorTickCount, int interMajorTickCount, int numberOfFractionDigits) { - addRangeFilter(propertyName, title, min, max, majorTickCount, interMajorTickCount, numberOfFractionDigits, Function.identity()); + int majorTickCount, int interMajorTickCount, int numberOfFractionDigits, + DoubleProperty minProperty, DoubleProperty maxProperty) { + addRangeFilter(propertyName, title, min, max, majorTickCount, interMajorTickCount, + numberOfFractionDigits, Function.identity(), minProperty, maxProperty); } public void addRangeFilter(String propertyName, String title, double min, double max, int majorTickCount, int interMajorTickCount, int numberOfFractionDigits, - Function valueTransform) { + Function valueTransform, + DoubleProperty minProperty, DoubleProperty maxProperty) { RangeFilterController rangeFilterController = uiService.loadFxml("theme/vault/search/rangeFilter.fxml"); rangeFilterController.setTitle(title); rangeFilterController.setPropertyName(propertyName); @@ -317,26 +329,29 @@ public void addRangeFilter(String propertyName, String title, double min, double rangeFilterController.setSnapToTicks(true); rangeFilterController.setNumberOfFractionDigits(numberOfFractionDigits); rangeFilterController.setValueTransform(valueTransform); + rangeFilterController.setPersistentRangeBindings(minProperty, maxProperty); rangeFilterController.bind(); addFilterNode(rangeFilterController); } - public DateRangeFilterController addDateRangeFilter(String propertyName, String title, int initialYearsBefore) { + public DateRangeFilterController addDateRangeFilter(String propertyName, String title, int initialYearsBefore, ObjectProperty beforeDate, ObjectProperty afterDate) { DateRangeFilterController dateRangeFilterController = uiService.loadFxml("theme/vault/search/dateRangeFilter.fxml"); dateRangeFilterController.setTitle(title); dateRangeFilterController.setPropertyName(propertyName); if (initialYearsBefore != 0) { dateRangeFilterController.setInitialYearsBefore(initialYearsBefore); } + dateRangeFilterController.setPersistentBindings(beforeDate, afterDate); addFilterNode(dateRangeFilterController); return dateRangeFilterController; } - public ToggleFilterController addToggleFilter(String propertyName, String title, String value) { + public ToggleFilterController addToggleFilter(String propertyName, String title, String value, BooleanProperty persistenceProperty) { ToggleFilterController toggleFilterController = uiService.loadFxml("theme/vault/search/toggleFilter.fxml"); toggleFilterController.setTitle(title); toggleFilterController.setPropertyName(propertyName); toggleFilterController.setValue(value); + toggleFilterController.setPersistentProperty(persistenceProperty); addFilterNode(toggleFilterController); return toggleFilterController; } diff --git a/src/test/java/com/faforever/client/game/CreateGameControllerTest.java b/src/test/java/com/faforever/client/game/CreateGameControllerTest.java index a3f14f3050..a7c3391aa5 100644 --- a/src/test/java/com/faforever/client/game/CreateGameControllerTest.java +++ b/src/test/java/com/faforever/client/game/CreateGameControllerTest.java @@ -494,9 +494,9 @@ public void testMapNameSearchClearsSelected() { ObjectProperty> predicate = mapFilterController.predicateProperty(); mapList.add(Instancio.of(MapVersion.class).set(field(Map::displayName).within(scope(Map.class)), "Test1") .create()); - - predicate.setValue((item) -> filter.apply("Not in Filtered Maps", item)); + runOnFxThreadAndWait(() -> { + predicate.setValue((item) -> filter.apply("Not in Filtered Maps", item)); instance.mapSearchTextField.setText("Not in Filtered Maps"); }); diff --git a/src/test/java/com/faforever/client/query/CategoryFilterControllerTest.java b/src/test/java/com/faforever/client/query/CategoryFilterControllerTest.java index 58b8101707..39f88e33a8 100644 --- a/src/test/java/com/faforever/client/query/CategoryFilterControllerTest.java +++ b/src/test/java/com/faforever/client/query/CategoryFilterControllerTest.java @@ -6,7 +6,11 @@ import com.github.rutledgepaulv.qbuilders.conditions.Condition; import com.github.rutledgepaulv.qbuilders.properties.concrete.StringProperty; import com.github.rutledgepaulv.qbuilders.visitors.RSQLVisitor; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.InvalidationListener; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.scene.control.MenuButton; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -133,4 +137,29 @@ public void testGetConditionCheckedWithMap() throws Exception { property.in(instance.checkListView.getCheckModel().getCheckedItems().stream().map(itemMap::get).toArray()).query(new RSQLVisitor())); assertTrue(instance.menu.getStyleClass().contains("query-filter-selected")); } + + @Test + public void testPersistentPropertiesSetCheckedItems() { + ObservableList checkedItems = FXCollections.observableArrayList(); + checkedItems.add("2"); + ObjectProperty> property = new SimpleObjectProperty>(checkedItems); + instance.setPersistenceProperty(property); + instance.setItems(itemMap); + + assertFalse(instance.checkListView.getCheckModel().isChecked("1")); + assertTrue(instance.checkListView.getCheckModel().isChecked("2")); + } + + @Test + public void testPersistentPropertyBindsToCheckedItems() { + ObjectProperty> property = new SimpleObjectProperty>(FXCollections.emptyObservableList()); + instance.setPersistenceProperty(property); + instance.setItems(itemMap); + + instance.checkListView.getCheckModel().check("1"); + + ObservableList expected = FXCollections.observableArrayList(); + expected.add("1"); + assertEquals(property.get(), expected); + } } diff --git a/src/test/java/com/faforever/client/query/DateRangeFilterControllerTest.java b/src/test/java/com/faforever/client/query/DateRangeFilterControllerTest.java index 6ba34ab0b8..e8dfd31235 100644 --- a/src/test/java/com/faforever/client/query/DateRangeFilterControllerTest.java +++ b/src/test/java/com/faforever/client/query/DateRangeFilterControllerTest.java @@ -8,6 +8,8 @@ import com.github.rutledgepaulv.qbuilders.properties.concrete.InstantProperty; import com.github.rutledgepaulv.qbuilders.visitors.RSQLVisitor; import javafx.beans.InvalidationListener; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.MenuButton; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -149,4 +151,30 @@ public void testGetConditionRange() throws Exception { .query(new RSQLVisitor())); assertTrue(instance.menu.getStyleClass().contains("query-filter-selected")); } + + @Test + public void testPersistentPropertiesGetsDates() { + ObjectProperty persistentBeforeDate = new SimpleObjectProperty(); + ObjectProperty persistentAfterDate = new SimpleObjectProperty(); + instance.setPersistentBindings(persistentBeforeDate, persistentAfterDate); + instance.setAfterDate(after); + instance.setBeforeDate(before); + + assertEquals(persistentBeforeDate.get(), before); + assertEquals(persistentAfterDate.get(), after); + } + + @Test + public void testPersistentPropertiesSetsDates() { + ObjectProperty persistentBeforeDate = new SimpleObjectProperty(); + ObjectProperty persistentAfterDate = new SimpleObjectProperty(); + instance.setPersistentBindings(persistentBeforeDate, persistentAfterDate); + instance.setAfterDate(after); + instance.setBeforeDate(before); + + persistentBeforeDate.setValue(LocalDate.now()); + persistentAfterDate.setValue(LocalDate.now()); + assertEquals(instance.beforeDate.getValue(), persistentBeforeDate.get()); + assertEquals(instance.afterDate.getValue(), persistentAfterDate.get()); + } } diff --git a/src/test/java/com/faforever/client/query/RangeFilterControllerTest.java b/src/test/java/com/faforever/client/query/RangeFilterControllerTest.java index bc077f21cb..894c4318ae 100644 --- a/src/test/java/com/faforever/client/query/RangeFilterControllerTest.java +++ b/src/test/java/com/faforever/client/query/RangeFilterControllerTest.java @@ -6,6 +6,7 @@ import com.github.rutledgepaulv.qbuilders.conditions.Condition; import com.github.rutledgepaulv.qbuilders.properties.concrete.DoubleProperty; import com.github.rutledgepaulv.qbuilders.visitors.RSQLVisitor; +import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.InvalidationListener; import javafx.scene.control.MenuButton; import org.junit.jupiter.api.BeforeEach; @@ -38,17 +39,22 @@ public class RangeFilterControllerTest extends PlatformTest { private I18n i18n; @Mock private InvalidationListener queryListener; + private javafx.beans.property.DoubleProperty lowerValue; + private javafx.beans.property.DoubleProperty higherValue; @BeforeEach public void setUp() throws Exception { loadFxml("theme/vault/search/rangeFilter.fxml", clazz -> instance); + lowerValue = new SimpleDoubleProperty(); + higherValue = new SimpleDoubleProperty(); instance.setPropertyName(propertyName); instance.setRange(min, max, 10, 0); instance.setIncrement(increment); instance.setSnapToTicks(true); instance.setTickUnit(increment); instance.setValueTransform((value) -> value); + instance.setPersistentRangeBindings(lowerValue, higherValue); instance.bind(); } @@ -161,11 +167,37 @@ public void testGetConditionRange() throws Exception { } @Test - void testTicks() { + public void testTicks() { instance.setRange(-10.0, 90.0, 5, 1); assertEquals(20.0, instance.rangeSlider.getMajorTickUnit()); assertEquals(1, instance.rangeSlider.getMinorTickCount()); assertEquals(10.0, instance.rangeSlider.getBlockIncrement()); } + + @Test + public void testPersistentPropertiesGetsValuesFromRangeFilter() { + instance.lowValue.setText("20"); + instance.highValue.setText("80"); + + assertEquals(lowerValue.get(), 20, 0); + assertEquals(higherValue.get(), 80, 0); + + instance.lowValue.setText("a"); + instance.highValue.setText("a"); + + assertEquals(min, lowerValue.get(), 0); + assertEquals(max, higherValue.get(), 0); + } + + @Test + public void testPersistentPropertiesSetsRangeFilter() { + instance.lowValue.setText("20"); + instance.highValue.setText("80"); + lowerValue.setValue(30); + higherValue.setValue(70); + + assertEquals(instance.lowValue.getText(), "30"); + assertEquals(instance.highValue.getText(), "70"); + } } diff --git a/src/test/java/com/faforever/client/query/TextFilterControllerTest.java b/src/test/java/com/faforever/client/query/TextFilterControllerTest.java index 01b85bc939..d84246c594 100644 --- a/src/test/java/com/faforever/client/query/TextFilterControllerTest.java +++ b/src/test/java/com/faforever/client/query/TextFilterControllerTest.java @@ -6,6 +6,7 @@ import com.github.rutledgepaulv.qbuilders.properties.concrete.StringProperty; import com.github.rutledgepaulv.qbuilders.visitors.RSQLVisitor; import javafx.beans.InvalidationListener; +import javafx.beans.property.SimpleStringProperty; import javafx.scene.layout.VBox; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -82,4 +83,29 @@ public void testGetConditionChecked() throws Exception { assertTrue(result.isPresent()); assertEquals(result.get().getFirst().query(new RSQLVisitor()), property.eq("*test*").query(new RSQLVisitor())); } + + @Test + public void testPersistentPropertyGetsText() { + javafx.beans.property.StringProperty property = new SimpleStringProperty(); + instance.setPersistenceProperty(property); + + instance.textField.setText("test"); + assertEquals(property.get(), "test"); + + instance.clear(); + assertTrue(property.get().isEmpty()); + } + + @Test + public void testPersistentPropertySetsText() { + javafx.beans.property.StringProperty property = new SimpleStringProperty(); + instance.setPersistenceProperty(property); + instance.textField.setText("test"); + + property.setValue("test2"); + assertEquals(instance.textField.getText(), "test2"); + + property.setValue(""); + assertEquals(instance.textField.getText(), ""); + } } diff --git a/src/test/java/com/faforever/client/query/ToggleFilterControllerTest.java b/src/test/java/com/faforever/client/query/ToggleFilterControllerTest.java index df689d918e..1b9fa414a2 100644 --- a/src/test/java/com/faforever/client/query/ToggleFilterControllerTest.java +++ b/src/test/java/com/faforever/client/query/ToggleFilterControllerTest.java @@ -5,6 +5,8 @@ import com.github.rutledgepaulv.qbuilders.conditions.Condition; import com.github.rutledgepaulv.qbuilders.properties.concrete.StringProperty; import com.github.rutledgepaulv.qbuilders.visitors.RSQLVisitor; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.InvalidationListener; import javafx.scene.layout.GridPane; import org.junit.jupiter.api.BeforeEach; @@ -82,4 +84,26 @@ public void testGetConditionChecked() throws Exception { assertTrue(result.isPresent()); assertEquals(result.get().getFirst().query(new RSQLVisitor()), property.eq(value).query(new RSQLVisitor())); } + + @Test + public void testPersistentPropertiesGetsValue() { + BooleanProperty property = new SimpleBooleanProperty(); + instance.setPersistentProperty(property); + + instance.checkBox.setSelected(true); + assertTrue(property.get()); + + instance.checkBox.setSelected(false); + assertFalse(property.get()); + } + + @Test + public void testPersistentPropertySetValues() { + BooleanProperty property = new SimpleBooleanProperty(); + instance.setPersistentProperty(property); + instance.checkBox.setSelected(false); + + property.setValue(true); + assertTrue(instance.checkBox.isSelected()); + } } diff --git a/src/test/java/com/faforever/client/replay/OnlineReplayVaultControllerTest.java b/src/test/java/com/faforever/client/replay/OnlineReplayVaultControllerTest.java index 47216edd8d..b7bb44ecc1 100644 --- a/src/test/java/com/faforever/client/replay/OnlineReplayVaultControllerTest.java +++ b/src/test/java/com/faforever/client/replay/OnlineReplayVaultControllerTest.java @@ -104,8 +104,8 @@ public void setUp() throws Exception { lenient().when(uiService.loadFxml("theme/vault/vault_entity_show_room.fxml")) .thenReturn(vaultEntityShowRoomController); lenient().when(i18n.get(anyString())).thenReturn("test"); - lenient().when(searchController.addCategoryFilter(any(), any(), anyMap())).thenReturn(categoryFilterController); - lenient().when(searchController.addCategoryFilter(any(), any(), anyList())).thenReturn(categoryFilterController); + lenient().when(searchController.addCategoryFilter(any(), any(), anyMap(), any())).thenReturn(categoryFilterController); + lenient().when(searchController.addCategoryFilter(any(), any(), anyList(), any())).thenReturn(categoryFilterController); sortOrder = new VaultPrefs().getOnlineReplaySortConfig(); standardSearchConfig = new SearchConfig(sortOrder, "query");