From ee66b643ec48f414ccd3543826a8ee0cbf727f5c Mon Sep 17 00:00:00 2001 From: Natalia Cholewa Date: Mon, 5 Jan 2026 16:05:27 +0100 Subject: [PATCH] refactor: make callbacks clean --- .../scenes/recipe/RecipeDetailCtrl.java | 108 +++++++++--------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java index 3d6441f..423404f 100644 --- a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java +++ b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java @@ -9,6 +9,10 @@ import client.utils.LocaleManager; import client.utils.ServerUtils; import com.google.inject.Inject; import commons.Recipe; +import java.io.IOException; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -19,12 +23,10 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; -import java.io.IOException; -import java.util.Optional; - /** * Controller for the recipe detail view. - * Manages displaying and editing recipe details such as name, ingredients, and steps. + * Manages displaying and editing recipe details such as name, ingredients, and + * steps. */ public class RecipeDetailCtrl implements LocaleAware { private final LocaleManager localeManager; @@ -41,10 +43,9 @@ public class RecipeDetailCtrl implements LocaleAware { private Recipe recipe; @Inject - public RecipeDetailCtrl(LocaleManager localeManager, - ServerUtils server, - FoodpalApplicationCtrl appCtrl, - ConfigService configService) { + public RecipeDetailCtrl(LocaleManager localeManager, ServerUtils server, + FoodpalApplicationCtrl appCtrl, + ConfigService configService) { this.localeManager = localeManager; this.server = server; this.appCtrl = appCtrl; @@ -74,15 +75,14 @@ public class RecipeDetailCtrl implements LocaleAware { } /** - * Convenience method for a frequently needed operation to retrieve the currently - * selected recipe. + * Convenience method for a frequently needed operation to retrieve the + * currently selected recipe. * * @return The currently selected recipe in the parent recipe list. */ private Optional getSelectedRecipe() { return Optional.ofNullable( - this.getParentRecipeList().getSelectionModel().getSelectedItem() - ); + this.getParentRecipeList().getSelectionModel().getSelectedItem()); } /** @@ -98,7 +98,7 @@ public class RecipeDetailCtrl implements LocaleAware { /** * Refreshes the recipe list from the server. * - * @throws IOException Upon invalid recipe response. + * @throws IOException Upon invalid recipe response. * @throws InterruptedException Upon request interruption. * * @see FoodpalApplicationCtrl#refresh() @@ -135,45 +135,50 @@ public class RecipeDetailCtrl implements LocaleAware { } /** - * Initializes the ingredient and step list controllers with update callbacks. + * Create a callback that takes in the selected recipe and a helper type + * and updates the recipe based on that. + * Also, posts the update to the server. + * + * @param recipeConsumer The helper function to use when updating the recipe - + * how to update it + * @return The created callback to use in a setUpdateCallback or related + * function */ - private void initStepsIngredientsList() { - // Initialize callback for ingredient list updates - this.ingredientListController.setUpdateCallback(newList -> { - var maybeSelected = this.getSelectedRecipe(); - if (maybeSelected.isEmpty()) { // Safely handle edge case - throw new NullPointerException("Null recipe whereas ingredients are edited"); - } + private Consumer createUpdateRecipeCallback(BiConsumer recipeConsumer) { + return recipes -> { + Recipe selectedRecipe = this.getSelectedRecipe().orElseThrow( + () -> new NullPointerException( + "Null recipe whereas ingredients are edited")); - Recipe selectedRecipe = maybeSelected.get(); - selectedRecipe.setIngredients(newList); - try { // propagate changes to server + recipeConsumer.accept(selectedRecipe, recipes); + + try { // propagate changes to server server.updateRecipe(selectedRecipe); } catch (IOException | InterruptedException e) { - throw new UpdateException("Unable to update recipe to server for " + selectedRecipe); + throw new UpdateException("Unable to update recipe to server for " + + selectedRecipe); } - }); - - // Ditto, for step list updates - this.stepListController.setUpdateCallback(newList -> { - var maybeSelected = this.getSelectedRecipe(); - if (maybeSelected.isEmpty()) { // Safely handle edge case - throw new NullPointerException("Null recipe whereas ingredients are edited"); - } - - Recipe selectedRecipe = maybeSelected.get(); - selectedRecipe.setPreparationSteps(newList); - try { // propagate changes to server - server.updateRecipe(selectedRecipe); - } catch (IOException | InterruptedException e) { - throw new UpdateException("Unable to update recipe to server for " + selectedRecipe); - } - }); + }; } /** - * Revised edit recipe control flow, deprecates the use of a separate AddNameCtrl. - * This is automagically called when a new recipe is created, making for a more seamless UX. + * Initializes the ingredient and step list controllers with update callbacks. + */ + private void initStepsIngredientsList() { + // code does NOT get nicer than this :pray: + + // Initialize callback for ingredient list updates + this.ingredientListController.setUpdateCallback( + this.createUpdateRecipeCallback(Recipe::setIngredients)); + // Ditto, for step list updates + this.stepListController.setUpdateCallback( + this.createUpdateRecipeCallback(Recipe::setPreparationSteps)); + } + + /** + * Revised edit recipe control flow, deprecates the use of a separate + * AddNameCtrl. This is automagically called when a new recipe is created, + * making for a more seamless UX. */ @FXML private void editRecipeTitle() { @@ -222,8 +227,8 @@ public class RecipeDetailCtrl implements LocaleAware { } /** - * Refreshes the favourite button state based on whether the currently viewed recipe - * is marked as a favourite in the application configuration. + * Refreshes the favourite button state based on whether the currently viewed + * recipe is marked as a favourite in the application configuration. */ public void refreshFavouriteButton() { if (recipe == null) { @@ -233,14 +238,13 @@ public class RecipeDetailCtrl implements LocaleAware { } favouriteButton.setDisable(false); - favouriteButton.setText( - this.getConfig().isFavourite(recipe.getId()) ? "★" : "☆" - ); + favouriteButton.setText(this.getConfig().isFavourite(recipe.getId()) ? "★" + : "☆"); } /** - * Toggles the favourite status of the currently viewed recipe in the application configuration - * and writes the changes to disk. + * Toggles the favourite status of the currently viewed recipe in the + * application configuration and writes the changes to disk. */ @FXML private void toggleFavourite() { @@ -255,7 +259,7 @@ public class RecipeDetailCtrl implements LocaleAware { configService.save(); - //instant ui update + // instant ui update appCtrl.applyRecipeFilterAndKeepSelection(); this.getParentRecipeList().refresh(); refreshFavouriteButton();