feat: clientside language filter and recipe language selector

This commit is contained in:
Natalia Cholewa 2026-01-09 23:35:30 +01:00
commit b130381154
11 changed files with 168 additions and 2 deletions

View file

@ -0,0 +1,87 @@
package client.scenes;
import client.utils.ConfigService;
import client.utils.LocaleAware;
import client.utils.LocaleManager;
import com.google.inject.Inject;
import javafx.fxml.FXML;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.MenuButton;
import java.util.ArrayList;
import java.util.List;
public class LanguageFilterCtrl implements LocaleAware {
private final LocaleManager manager;
private final ConfigService configService;
private final FoodpalApplicationCtrl appCtrl;
@Inject
public LanguageFilterCtrl(LocaleManager manager, ConfigService configService, FoodpalApplicationCtrl appCtrl) {
this.manager = manager;
this.configService = configService;
this.appCtrl = appCtrl;
}
@FXML
MenuButton langFilterMenu;
List<String> selectedLanguages = new ArrayList<>();
private String getSelectedLanguagesDisplay() {
String joined = String.join(", ", selectedLanguages);
if (joined.isEmpty()) {
return "none";
} else {
return joined;
}
}
private void updateMenuButtonDisplay() {
langFilterMenu.setText(getLocaleString("menu.label.selected-langs") + ": " + this.getSelectedLanguagesDisplay());
}
@Override
public void updateText() {
this.updateMenuButtonDisplay();
}
@Override
public LocaleManager getLocaleManager() {
return this.manager;
}
public void initializeComponents() {
var items = this.langFilterMenu.getItems();
final List<String> languages = List.of("en", "nl", "pl");
this.selectedLanguages = this.configService.getConfig().getRecipeLanguages();
this.updateMenuButtonDisplay();
items.clear();
languages.forEach(lang -> {
CheckMenuItem it = new CheckMenuItem(lang);
if (selectedLanguages.contains(it.getText())) {
it.setSelected(true);
}
it.selectedProperty().addListener((observable, _, value) -> {
if (value) {
selectedLanguages.add(it.getText());
} else {
selectedLanguages.remove(it.getText());
}
configService.save();
selectedLanguages.sort(String::compareTo);
appCtrl.refresh();
this.updateMenuButtonDisplay();
});
items.add(it);
});
}
}

View file

@ -19,6 +19,7 @@ import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
@ -77,6 +78,9 @@ public class RecipeDetailCtrl implements LocaleAware {
@FXML
private Button favouriteButton;
@FXML
private ComboBox<String> langSelector;
private ListView<Recipe> getParentRecipeList() {
return this.appCtrl.recipeList;
}
@ -138,6 +142,7 @@ public class RecipeDetailCtrl implements LocaleAware {
this.showName(recipe.getName());
this.ingredientListController.refetchFromRecipe(recipe);
this.stepListController.refetchFromRecipe(recipe);
this.langSelector.setValue(recipe.getLocale());
this.refreshFavouriteButton();
}
@ -294,6 +299,20 @@ public class RecipeDetailCtrl implements LocaleAware {
editableTitleArea.getChildren().add(nameLabel);
}
/**
* Switch the recipe's language.
*/
@FXML
void changeLanguage() {
recipe.setLocale(this.langSelector.getValue());
try {
server.updateRecipe(this.recipe);
} catch (IOException | InterruptedException e) {
throw new UpdateException("Error occurred when updating recipe locale!");
}
}
@Override
public void updateText() {
editRecipeTitleButton.setText(getLocaleString("menu.button.edit"));
@ -309,5 +328,7 @@ public class RecipeDetailCtrl implements LocaleAware {
@Override
public void initializeComponents() {
initStepsIngredientsList();
langSelector.getItems().addAll("en", "nl", "pl");
}
}

View file

@ -7,6 +7,7 @@ public class Config {
private String language = "en";
private List<String> recipeLanguages = new ArrayList<>();
private String serverUrl = "http://localhost:8080";
private List<Long> favourites = new ArrayList<>();
@ -66,5 +67,28 @@ public class Config {
public void removeFavourite(long recipeId) {
getFavourites().remove(recipeId);
}
/**
* Get a list of languages that should filter the displayed recipes.
*
* @return The desired languages the user would like to see.
*/
public List<String> getRecipeLanguages() {
return this.recipeLanguages;
}
/**
* Add a language to the list of filtering languages.
*/
public void addRecipeLanguage(String lang) {
this.recipeLanguages.add(lang);
}
/**
* Remove a language from the list of filtering languages.
*/
public void removeRecipeLanguage(String lang) {
this.recipeLanguages.remove(lang);
}
}

View file

@ -29,9 +29,11 @@ public class ServerUtils {
private final HttpClient client;
private final ObjectMapper objectMapper = new ObjectMapper();
private final int statusOK = 200;
private final ConfigService configService;
@Inject
public ServerUtils() {
public ServerUtils(ConfigService configService) {
this.configService = configService;
client = HttpClient.newHttpClient();
}
@ -40,8 +42,15 @@ public class ServerUtils {
* @return a JSON string with all the recipes
*/
public List<Recipe> getRecipes() throws IOException, InterruptedException {
String uri =
SERVER +
"/recipes" +
"?locales=" +
String.join(",", this.configService.getConfig().getRecipeLanguages());
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(SERVER + "/recipes"))
.uri(URI.create(uri))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

View file

@ -47,6 +47,7 @@
</font></Label>
<fx:include source="SearchBar.fxml" fx:id="searchBar" />
<fx:include source="LanguageFilter.fxml" fx:id="langFilter" />
<ListView fx:id="recipeList" />

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.MenuButton?>
<MenuButton
mnemonicParsing="false"
text="Languages"
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/25"
fx:controller="client.scenes.LanguageFilterCtrl"
fx:id="langFilterMenu"
/>

View file

@ -27,6 +27,8 @@
<Button fx:id="favouriteButton" onAction="#toggleFavourite" text="☆" />
</HBox>
<ComboBox fx:id="langSelector" onAction="#changeLanguage" />
<!-- Ingredients -->
<fx:include source="IngredientList.fxml" fx:id="ingredientList" />

View file

@ -25,6 +25,8 @@ menu.button.edit=Edit
menu.button.clone=Clone
menu.button.print=Print recipe
menu.label.selected-langs=Languages
lang.en.display=English
lang.nl.display=Dutch
lang.pl.display=Polish

View file

@ -26,6 +26,9 @@ menu.button.clone=Clone
menu.button.print=Print recipe
menu.search=Search...
menu.label.selected-langs=Languages
lang.en.display=English
lang.nl.display=Nederlands
lang.pl.display=Polski

View file

@ -25,6 +25,8 @@ menu.button.edit=Bewerken
menu.button.clone=Dupliceren
menu.button.print=Recept afdrukken
menu.label.selected-langs=Talen
menu.search=Zoeken...
lang.en.display=English
lang.nl.display=Nederlands

View file

@ -26,6 +26,9 @@ menu.button.clone=Duplikuj
menu.button.print=Drukuj przepis
menu.search=Szukaj...
menu.label.selected-langs=J?zyki
lang.en.display=English
lang.nl.display=Nederlands
lang.pl.display=Polski