diff --git a/src/main/java/com/faforever/client/map/MapVaultController.java b/src/main/java/com/faforever/client/map/MapVaultController.java index 1af0403e8b..03adf4c9bb 100644 --- a/src/main/java/com/faforever/client/map/MapVaultController.java +++ b/src/main/java/com/faforever/client/map/MapVaultController.java @@ -11,14 +11,21 @@ import com.faforever.client.map.management.MapsManagementController; import com.faforever.client.notification.NotificationService; import com.faforever.client.preferences.ForgedAlliancePrefs; +import com.faforever.client.preferences.MapSearchPrefs; import com.faforever.client.preferences.VaultPrefs; +import com.faforever.client.query.CategoryFilterController; +import com.faforever.client.query.DateRangeFilterController; +import com.faforever.client.query.RangeFilterController; import com.faforever.client.query.SearchablePropertyMappings; +import com.faforever.client.query.TextFilterController; +import com.faforever.client.query.ToggleFilterController; import com.faforever.client.reporting.ReportingService; import com.faforever.client.theme.UiService; import com.faforever.client.ui.dialog.Dialog; import com.faforever.client.vault.VaultEntityCardController; import com.faforever.client.vault.VaultEntityController; import com.faforever.client.vault.search.SearchController.SearchConfig; +import javafx.beans.binding.Bindings; import javafx.scene.Node; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -43,6 +50,8 @@ public class MapVaultController extends VaultEntityController { private MapDetailController mapDetailController; private Integer recommendedShowRoomPageCount; private MatchmakerQueueInfo matchmakerQueue; + private CategoryFilterController widthCategoryFilterController; + private CategoryFilterController heightCategoryFilterController; public MapVaultController(MapService mapService, I18n i18n, UiService uiService, NotificationService notificationService, @@ -75,9 +84,19 @@ 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); + MapSearchPrefs mapSearchPrefs = vaultPrefs.getMapSearch(); + TextFilterController textFilterController = searchController.addTextFilter("displayName", i18n.get("map.name"), false); + textFilterController.setText(mapSearchPrefs.getMapNameField()); + mapSearchPrefs.mapNameFieldProperty().bind(textFilterController.textFieldProperty().when(showing)); + textFilterController = searchController.addTextFilter("author.login", i18n.get("map.author"), false); + textFilterController.setText(mapSearchPrefs.getMapAuthorField()); + mapSearchPrefs.mapAuthorFieldProperty().bind(textFilterController.textFieldProperty().when(showing)); + + DateRangeFilterController dateRangeFilterController = searchController.addDateRangeFilter("latestVersion.updateTime", i18n.get("map.uploadedDateTime"), 0); + dateRangeFilterController.setBeforeDate(mapSearchPrefs.getUploadedBeforeDate()); + dateRangeFilterController.setAfterDate(mapSearchPrefs.getUploadedAfterDate()); + mapSearchPrefs.uploadedBeforeDateProperty().bind(dateRangeFilterController.beforeDateProperty().when(showing)); + mapSearchPrefs.uploadedAfterDateProperty().bind(dateRangeFilterController.afterDateProperty().when(showing)); LinkedHashMap mapSizeMap = new LinkedHashMap<>(); mapSizeMap.put("1km", "64"); @@ -88,11 +107,25 @@ 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"); + widthCategoryFilterController = searchController.addCategoryFilter("latestVersion.width", i18n.get("map.width"), mapSizeMap); + mapSearchPrefs.getMapWidthFilter().forEach((item) -> widthCategoryFilterController.checkItem(item)); + heightCategoryFilterController = searchController.addCategoryFilter("latestVersion.height", i18n.get("map.height"), mapSizeMap); + mapSearchPrefs.getMapHeightFilter().forEach((item) -> heightCategoryFilterController.checkItem(item)); + + RangeFilterController rangeFilterController = searchController.addRangeFilter("latestVersion.maxPlayers", i18n.get("map.maxPlayers"), 0, 16, 16, 0, 0, Double::intValue); + rangeFilterController.setLowValue(mapSearchPrefs.getMaxPlayersMin()); + rangeFilterController.setHighValue(mapSearchPrefs.getMaxPlayersMax()); + mapSearchPrefs.maxPlayersMinProperty().bind(rangeFilterController.lowValueProperty().asObject().when(showing)); + mapSearchPrefs.maxPlayersMaxProperty().bind(rangeFilterController.highValueProperty().asObject().when(showing)); + rangeFilterController = searchController.addRangeFilter("reviewsSummary.averageScore", i18n.get("reviews.averageScore"), 0, 5, 10, 4, 1); + rangeFilterController.setLowValue(mapSearchPrefs.getAverageReviewScoresMin()); + rangeFilterController.setHighValue(mapSearchPrefs.getAverageReviewScoresMax()); + mapSearchPrefs.averageReviewScoresMinProperty().bind(rangeFilterController.lowValueProperty().asObject().when(showing)); + mapSearchPrefs.averageReviewScoresMaxProperty().bind(rangeFilterController.highValueProperty().asObject().when(showing)); + + ToggleFilterController toggleFilterController = searchController.addToggleFilter("latestVersion.ranked", i18n.get("map.onlyRanked"), "true"); + toggleFilterController.setSelected(mapSearchPrefs.getOnlyRanked()); + mapSearchPrefs.onlyRankedProperty().bind(toggleFilterController.selectedProperty().when(showing)); } @Override @@ -184,4 +217,14 @@ private void openUploadWindow(Path path) { mapUploadController.setOnCancelButtonClickedListener(dialog::close); mapUploadController.setUploadListener(this::onRefreshButtonClicked); } + + @Override + public void onShow() { + super.onShow(); + MapSearchPrefs mapSearchPrefs = vaultPrefs.getMapSearch(); + Bindings.bindContent(mapSearchPrefs.mapWidthFilterProperty(), widthCategoryFilterController.getCheckedItems()); + addShownSubscription(() -> Bindings.unbindContent(mapSearchPrefs.mapWidthFilterProperty(), widthCategoryFilterController.getCheckedItems())); + Bindings.bindContent(mapSearchPrefs.mapHeightFilterProperty(), heightCategoryFilterController.getCheckedItems()); + addShownSubscription(() -> Bindings.unbindContent(mapSearchPrefs.mapHeightFilterProperty(), heightCategoryFilterController.getCheckedItems())); + } } diff --git a/src/main/java/com/faforever/client/preferences/MapSearchPrefs.java b/src/main/java/com/faforever/client/preferences/MapSearchPrefs.java new file mode 100644 index 0000000000..bc95d0a9bc --- /dev/null +++ b/src/main/java/com/faforever/client/preferences/MapSearchPrefs.java @@ -0,0 +1,134 @@ +package com.faforever.client.preferences; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ListProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import java.time.LocalDate; + +public class MapSearchPrefs { + private final StringProperty mapNameField = new SimpleStringProperty(""); + private final StringProperty mapAuthorField = new SimpleStringProperty(""); + private final ObjectProperty uploadedBeforeDate = new SimpleObjectProperty(); + private final ObjectProperty uploadedAfterDate = new SimpleObjectProperty(); + private final ListProperty mapWidthFilter = new SimpleListProperty<>( + FXCollections.observableArrayList() + ); + private final ListProperty mapHeightFilter = new SimpleListProperty<>( + FXCollections.observableArrayList() + ); + private final ObjectProperty maxPlayersMin = new SimpleObjectProperty(); + private final ObjectProperty maxPlayersMax = new SimpleObjectProperty(); + private final ObjectProperty averageReviewScoresMin = new SimpleObjectProperty(); + private final ObjectProperty averageReviewScoresMax = new SimpleObjectProperty(); + private final BooleanProperty onlyRanked = new SimpleBooleanProperty(); + + public String getMapNameField() { + return mapNameField.get(); + } + + public void setMapNameField(String mapNameField) { + this.mapNameField.set(mapNameField); + } + + public StringProperty mapNameFieldProperty() { + return mapNameField; + } + public String getMapAuthorField() { + return mapAuthorField.get(); + } + public void setMapAuthorField(String mapAuthorField) { + this.mapAuthorField.set(mapAuthorField); + } + public StringProperty mapAuthorFieldProperty() { + return mapAuthorField; + } + public LocalDate getUploadedBeforeDate() { + return uploadedBeforeDate.get(); + } + public void setUploadedBeforeDate(LocalDate uploadedBeforeDate) { + this.uploadedBeforeDate.set(uploadedBeforeDate); + } + public ObjectProperty uploadedBeforeDateProperty() { + return uploadedBeforeDate; + } + public LocalDate getUploadedAfterDate() { + return uploadedAfterDate.get(); + } + public void setUploadedAfterDate(LocalDate uploadedAfterDate) { + this.uploadedAfterDate.set(uploadedAfterDate); + } + public ObjectProperty uploadedAfterDateProperty() { + return uploadedAfterDate; + } + public ObservableList getMapWidthFilter() { + return mapWidthFilter.get(); + } + public void setMapWidthFilter(ObservableList mapWidthFilter) { + this.mapWidthFilter.set(mapWidthFilter); + } + public ListProperty mapWidthFilterProperty() { + return mapWidthFilter; + } + public ObservableList getMapHeightFilter() { + return mapHeightFilter.get(); + } + public void setMapHeightFilter(ObservableList mapHeightFilter) { + this.mapHeightFilter.set(mapHeightFilter); + } + public ListProperty mapHeightFilterProperty() { + return mapHeightFilter; + } + public Double getMaxPlayersMin() { + return maxPlayersMin.get(); + } + public void setMaxPlayersMin(Double maxPlayersMin) { + this.maxPlayersMin.set(maxPlayersMin); + } + public ObjectProperty maxPlayersMinProperty() { + return maxPlayersMin; + } + public Double getMaxPlayersMax() { + return maxPlayersMax.get(); + } + public void setMaxPlayersMax(Double maxPlayersMax) { + this.maxPlayersMax.set(maxPlayersMax); + } + public ObjectProperty maxPlayersMaxProperty() { + return maxPlayersMax; + } + public Double getAverageReviewScoresMin() { + return averageReviewScoresMin.get(); + } + public void setAverageReviewScoresMin(Double averageReviewScoresMin) { + this.averageReviewScoresMin.set(averageReviewScoresMin); + } + public ObjectProperty averageReviewScoresMinProperty() { + return averageReviewScoresMin; + } + public Double getAverageReviewScoresMax() { + return averageReviewScoresMax.get(); + } + public void setAverageReviewScoresMax(Double averageReviewScoresMax) { + this.averageReviewScoresMax.set(averageReviewScoresMax); + } + public ObjectProperty averageReviewScoresMaxProperty() { + return averageReviewScoresMax; + } + 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/preferences/VaultPrefs.java b/src/main/java/com/faforever/client/preferences/VaultPrefs.java index 1f33c4b287..0be0b74fb8 100644 --- a/src/main/java/com/faforever/client/preferences/VaultPrefs.java +++ b/src/main/java/com/faforever/client/preferences/VaultPrefs.java @@ -27,7 +27,10 @@ public class VaultPrefs { @JsonMerge @Getter private final ReplaySearchPrefs replaySearch = new ReplaySearchPrefs(); - + @JsonMerge + @Getter + private final MapSearchPrefs mapSearch = new MapSearchPrefs(); + public SortConfig getOnlineReplaySortConfig() { return onlineReplaySortConfig.get(); } diff --git a/src/main/java/com/faforever/client/query/DateRangeFilterController.java b/src/main/java/com/faforever/client/query/DateRangeFilterController.java index 981fff9baf..5a07128395 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,14 @@ public void setInitialYearsBefore(int initialYearsBefore) { afterDate.setValue(LocalDate.now().minusYears(initialYearsBefore)); } + public ObjectProperty beforeDateProperty() { + return this.beforeDate.valueProperty(); + } + + public ObjectProperty afterDateProperty() { + return this.afterDate.valueProperty(); + } + @Override public Node getRoot() { return menu; diff --git a/src/test/java/com/faforever/client/map/MapVaultControllerTest.java b/src/test/java/com/faforever/client/map/MapVaultControllerTest.java index 26636e6533..47fd53689d 100644 --- a/src/test/java/com/faforever/client/map/MapVaultControllerTest.java +++ b/src/test/java/com/faforever/client/map/MapVaultControllerTest.java @@ -6,8 +6,13 @@ import com.faforever.client.notification.NotificationService; import com.faforever.client.preferences.Preferences; import com.faforever.client.preferences.VaultPrefs; +import com.faforever.client.query.CategoryFilterController; +import com.faforever.client.query.DateRangeFilterController; import com.faforever.client.query.LogicalNodeController; +import com.faforever.client.query.RangeFilterController; import com.faforever.client.query.SpecificationController; +import com.faforever.client.query.TextFilterController; +import com.faforever.client.query.ToggleFilterController; import com.faforever.client.reporting.ReportingService; import com.faforever.client.test.PlatformTest; import com.faforever.client.theme.UiService; @@ -17,6 +22,11 @@ import com.faforever.client.vault.search.SearchController; import com.faforever.client.vault.search.SearchController.SearchConfig; import com.faforever.client.vault.search.SearchController.SortConfig; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; import javafx.scene.layout.Pane; import org.instancio.Instancio; import org.junit.jupiter.api.BeforeEach; @@ -27,10 +37,15 @@ import reactor.core.publisher.Mono; import java.net.MalformedURLException; +import java.time.LocalDate; import java.util.List; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyDouble; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -58,6 +73,16 @@ public class MapVaultControllerTest extends PlatformTest { private ReportingService reportingService; @Mock private PlatformService platformService; + @Mock + private CategoryFilterController categoryFilterController; + @Mock + private DateRangeFilterController dateRangeFilterController; + @Mock + private TextFilterController textFilterController; + @Mock + private RangeFilterController rangeFilterController; + @Mock + private ToggleFilterController toggleFilterController; @Spy private VaultPrefs vaultPrefs; @@ -77,7 +102,19 @@ public void setUp() throws Exception { }).when(uiService).loadFxml("theme/vault/map/map_detail.fxml"); when(mapService.getRecommendedMapPageCount(VaultEntityController.TOP_ELEMENT_COUNT)).thenReturn(Mono.just(0)); - + when(searchController.addCategoryFilter(any(), any(), anyMap())).thenReturn(categoryFilterController); + when(categoryFilterController.getCheckedItems()).thenReturn(new SimpleListProperty()); + when(searchController.addTextFilter(anyString(), anyString(), anyBoolean())).thenReturn(textFilterController); + when(textFilterController.textFieldProperty()).thenReturn(new SimpleStringProperty()); + when(searchController.addRangeFilter(anyString(), anyString(), anyDouble(), anyDouble(), anyInt(), anyInt(), anyInt())).thenReturn(rangeFilterController); + when(searchController.addRangeFilter(anyString(), anyString(), anyDouble(), anyDouble(), anyInt(), anyInt(), anyInt(), any())).thenReturn(rangeFilterController); + when(rangeFilterController.lowValueProperty()).thenReturn(new SimpleDoubleProperty()); + when(rangeFilterController.highValueProperty()).thenReturn(new SimpleDoubleProperty()); + when(searchController.addToggleFilter(anyString(), anyString(), anyString())).thenReturn(toggleFilterController); + when(toggleFilterController.selectedProperty()).thenReturn(new SimpleBooleanProperty()); + when(searchController.addDateRangeFilter(anyString(), anyString(), anyInt())).thenReturn(dateRangeFilterController); + when(dateRangeFilterController.beforeDateProperty()).thenReturn(new SimpleObjectProperty()); + when(dateRangeFilterController.afterDateProperty()).thenReturn(new SimpleObjectProperty()); SortConfig sortOrder = new Preferences().getVault().getMapSortConfig(); standardSearchConfig = new SearchConfig(sortOrder, "query"); diff --git a/src/test/java/com/faforever/client/query/DateRangeFilterControllerTest.java b/src/test/java/com/faforever/client/query/DateRangeFilterControllerTest.java index 6ba34ab0b8..e6d8a44968 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,17 @@ 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(); + persistentBeforeDate.bind(instance.beforeDateProperty()); + persistentAfterDate.bind(instance.afterDateProperty()); + instance.setAfterDate(after); + instance.setBeforeDate(before); + + assertEquals(persistentBeforeDate.get(), before); + assertEquals(persistentAfterDate.get(), after); + } }