diff --git a/client/src/main/java/client/exception/UpdateException.java b/client/src/main/java/client/exception/UpdateException.java new file mode 100644 index 0000000..5439018 --- /dev/null +++ b/client/src/main/java/client/exception/UpdateException.java @@ -0,0 +1,7 @@ +package client.exception; + +public class UpdateException extends RuntimeException { + public UpdateException(String message) { + super(message); + } +} diff --git a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java index 93a2507..bc39741 100644 --- a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java +++ b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java @@ -4,20 +4,30 @@ package client.scenes; import java.io.IOException; import java.util.List; +import client.exception.UpdateException; +import client.utils.DefaultRecipeFactory; import client.utils.ServerUtils; import commons.Recipe; import jakarta.inject.Inject; import javafx.fxml.FXML; +import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.input.KeyCode; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; public class FoodpalApplicationCtrl { private final MainCtrl mainCtrl; private final ServerUtils server; + public VBox detailsScreen; + public HBox editableTitleArea; + // all of these aren't used with only my part of the code // everything in the top bar === @@ -103,10 +113,13 @@ public class FoodpalApplicationCtrl { refresh(); } - + private void showName(String name) { + editableTitleArea.getChildren().clear(); + editableTitleArea.getChildren().add(new Label(name)); + } // till the all the code from everyone is implemented for now to not have errors private void showRecipeDetails(Recipe newRecipe) { - recipeNameLabel.setText(newRecipe.getName()); + showName(newRecipe.getName()); ingredientsListView.getItems().setAll(newRecipe.getIngredients()); preparationListView.getItems().setAll(newRecipe.getPreparationSteps()); @@ -123,17 +136,40 @@ public class FoodpalApplicationCtrl { // Select first recipe in the list by default if (!recipes.isEmpty()) { recipeList.getSelectionModel().selectFirst(); + detailsScreen.visibleProperty().set(true); } } - + private void printError(String msg) { + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setContentText(msg); + alert.showAndWait(); + } /** - * Adds a recipe, by going to a different scene, there you insert the title and bam recipe created + * Adds a recipe, by providing a default name "Untitled recipe (n)" + * The UX flow is now: + *
    + *
  1. User creates an untitled recipe
  2. + *
  3. The application autofocuses on the edit box (not exactly automagically yet)
  4. + *
  5. User edits the name to whatever they want
  6. + *
  7. Profit??
  8. + *
*/ @FXML private void addRecipe() { - // Navigate to "create recipe" screen (should be like a pop-up or new screen or just another place in the app) - mainCtrl.showAddName(); + // a default factory provides the value + Recipe newRecipe = DefaultRecipeFactory.getDefaultRecipe(); + try { + server.addRecipe(newRecipe); + refresh(); + // the list focuses on the new recipe + // otherwise strange issues occur when the autofocus on edit box is called + recipeList.getFocusModel().focus(recipeList.getItems().indexOf(newRecipe)); + } catch (IOException | InterruptedException e) { + printError("Error occurred when adding recipe!"); + } + // Calls edit after the recipe has been created, seamless name editing + editRecipeTitle(); } @FXML @@ -145,7 +181,10 @@ public class FoodpalApplicationCtrl { server.deleteRecipe(selected.getId()); - recipeList.getItems().remove(selected); + // prefer a global refresh (or WS-based update upon its impl) + // rather than recipeList.getItems().remove(selected); + // to maintain single source of truth from the server. + refresh(); } @FXML @@ -154,15 +193,38 @@ public class FoodpalApplicationCtrl { if (selected == null) { return; } - // Let MainCtrl open the full detail screen - mainCtrl.showAddName(); //I had showrecipedetail but intelij says showoverview + detailsScreen.visibleProperty().set(true); } + /** + * 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() { - // TODO: someone else todo - // For now reuse openSelectedRecipe() - openSelectedRecipe(); + editableTitleArea.getChildren().clear(); + TextField edit = new TextField(); + edit.setOnKeyPressed(event -> { + if (event.getCode() != KeyCode.ENTER) { + return; + } + String newName = edit.getText(); + Recipe selected = recipeList.getSelectionModel().getSelectedItem(); + if (selected == null) { + // edge case, prob won't happen but best to handle it later + throw new NullPointerException("No recipe selected while name was changed!"); + } + selected.setName(newName); + try { + server.updateRecipe(selected); + refresh(); + } catch (IOException | InterruptedException e) { + // throw a nice blanket UpdateException + throw new UpdateException("Error occurred when updating recipe name!"); + } + showName(edit.getText()); + }); + editableTitleArea.getChildren().add(edit); } /** diff --git a/client/src/main/java/client/utils/DefaultRecipeFactory.java b/client/src/main/java/client/utils/DefaultRecipeFactory.java new file mode 100644 index 0000000..0a94786 --- /dev/null +++ b/client/src/main/java/client/utils/DefaultRecipeFactory.java @@ -0,0 +1,15 @@ +package client.utils; + +import commons.Recipe; + +import java.util.List; + +public class DefaultRecipeFactory { + public static Recipe getDefaultRecipe() { + return new Recipe( + null, + "Untitled recipe", + List.of(), + List.of()); + } +}