fix desktop pet and product dialogs

This commit is contained in:
2026-03-29 16:54:01 -06:00
parent 8a278cd6e2
commit b3a30e10d1
7 changed files with 99 additions and 28 deletions

View File

@@ -44,6 +44,33 @@ public class Validator {
return msg;
}
/**
* Checks if the input is a positive double
* @param value input of string
* @param name name of input
* @return error msg if input is not a number or not positive, otherwise empty
*/
public static String isPositiveDouble(String value, String name){
String msg ="";
if (value == null) {
msg += name + " must be a number.\n";
return msg;
}
double result;
try {
result = Double.parseDouble(value);
if (result <= 0){
msg += name + " must be greater than 0. \n";
}
}
catch (NumberFormatException e){
msg += name + " must be a number.\n";
}
return msg;
}
/**
* Checks if the input is a double in 2 different range
* @param value input of string
@@ -95,6 +122,28 @@ public class Validator {
return msg;
}
/**
* Checks if the input is a positive integer
* @param value input of string
* @param name name of input
* @return error msg if input is not a number or not positive, otherwise empty
*/
public static String isPositiveInteger(String value, String name){
String msg ="";
int result;
try {
result = Integer.parseInt(value);
if (result <= 0){
msg += name + " must be greater than 0. \n";
}
}
catch (NumberFormatException e){
msg += name + " must be a whole number.\n";
}
return msg;
}
/**
* check if the string is a given amount of characters or fewer
* @param value input of string
@@ -154,4 +203,4 @@ public class Validator {
return msg;
}
}
}

View File

@@ -224,15 +224,21 @@ public class ApiClient {
try {
if (response.body() != null && !response.body().isEmpty()) {
var errorNode = objectMapper.readTree(response.body());
if (errorNode.has("message")) {
return errorNode.get("message").asText();
}
if (errorNode.has("errors")) {
StringBuilder sb = new StringBuilder();
errorNode.get("errors").fields().forEachRemaining(entry -> {
sb.append(entry.getValue().asText()).append("\n");
String errorText = entry.getValue().asText();
if (errorText != null && !errorText.isBlank()) {
sb.append(errorText).append("\n");
}
});
return sb.toString().trim();
if (sb.length() > 0) {
String message = errorNode.has("message") ? errorNode.get("message").asText() : null;
return (message != null && !message.isBlank() ? message + "\n" : "") + sb.toString().trim();
}
}
if (errorNode.has("message")) {
return errorNode.get("message").asText();
}
}
} catch (Exception e) {

View File

@@ -20,6 +20,7 @@ import org.example.petshopdesktop.util.FilePickerSupport;
import java.io.File;
import java.math.BigDecimal;
public class PetDialogController {
@FXML
@@ -120,7 +121,7 @@ public class PetDialogController {
//Check validation (format)
errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price");
errorMsg += Validator.isNonNegativeInteger(txtPetAge.getText(), "Age");
errorMsg += Validator.isPositiveInteger(txtPetAge.getText(), "Age");
if(errorMsg.isEmpty()){
PetRequest request = buildPetRequest();
@@ -252,6 +253,7 @@ public class PetDialogController {
}
private void applyImageChanges(Long petId) throws Exception {
String previousImageUrl = currentImageUrl;
if (removeImageRequested) {
try {
PetApi.getInstance().deletePetImage(petId);
@@ -260,7 +262,15 @@ public class PetDialogController {
}
if (selectedImageFile != null) {
PetApi.getInstance().uploadPetImage(petId, selectedImageFile.toPath());
currentImageUrl = "/api/v1/pets/" + petId + "/image";
} else if (removeImageRequested) {
currentImageUrl = null;
}
DesktopImageSupport.evict(previousImageUrl);
DesktopImageSupport.evict(currentImageUrl);
selectedImageFile = null;
removeImageRequested = false;
refreshImagePreview();
}
private void refreshImagePreview() {

View File

@@ -130,7 +130,7 @@ public class ProductDialogController {
errorMsg += Validator.isLessThanVarChars(txtProdPrice.getText(), "Product Price", 12);
//Check Validation (format)
errorMsg += Validator.isNonNegativeDouble(txtProdPrice.getText(), "Product Price");
errorMsg += Validator.isPositiveDouble(txtProdPrice.getText(), "Product Price");
if (errorMsg.isEmpty()) {
try {
@@ -258,6 +258,7 @@ public class ProductDialogController {
}
private void applyImageChanges(Long productId) throws Exception {
String previousImageUrl = currentImageUrl;
if (removeImageRequested) {
try {
ProductApi.getInstance().deleteProductImage(productId);
@@ -266,7 +267,15 @@ public class ProductDialogController {
}
if (selectedImageFile != null) {
ProductApi.getInstance().uploadProductImage(productId, selectedImageFile.toPath());
currentImageUrl = "/api/v1/products/" + productId + "/image";
} else if (removeImageRequested) {
currentImageUrl = null;
}
DesktopImageSupport.evict(previousImageUrl);
DesktopImageSupport.evict(currentImageUrl);
selectedImageFile = null;
removeImageRequested = false;
refreshImagePreview();
}
private void refreshImagePreview() {

View File

@@ -20,12 +20,21 @@ public final class DesktopImageSupport {
imageView.setFitWidth(width);
imageView.setFitHeight(height);
imageView.setPreserveRatio(true);
imageView.setSmooth(true);
imageView.setImage(null);
if (imageUrl == null || imageUrl.isBlank()) {
return;
}
if (imageUrl.startsWith("file:")) {
Image image = new Image(imageUrl, 0, 0, true, true);
if (!image.isError()) {
imageView.setImage(image);
}
return;
}
Image cached = IMAGE_CACHE.get(imageUrl);
if (cached != null) {
imageView.setImage(cached);
@@ -35,7 +44,7 @@ public final class DesktopImageSupport {
new Thread(() -> {
try {
byte[] bytes = ApiClient.getInstance().getBytes(imageUrl);
Image image = new Image(new ByteArrayInputStream(bytes), width, height, true, true);
Image image = new Image(new ByteArrayInputStream(bytes));
if (!image.isError()) {
IMAGE_CACHE.put(imageUrl, image);
Platform.runLater(() -> imageView.setImage(image));

View File

@@ -10,11 +10,10 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox minHeight="-Infinity" minWidth="-Infinity" prefHeight="523.0" prefWidth="790.0" spacing="20.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.PetDialogController">
<VBox minHeight="-Infinity" minWidth="-Infinity" prefHeight="560.0" prefWidth="790.0" spacing="20.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.PetDialogController">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="79.0" prefWidth="727.0" spacing="20.0" style="-fx-background-color: #2C3E50; -fx-background-radius: 14;">
<children>
@@ -63,18 +62,13 @@
<Insets left="15.0" right="15.0" />
</padding>
</HBox>
<VBox prefHeight="370.0" prefWidth="750.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-color: #5580b5; -fx-border-radius: 14;">
<VBox prefHeight="405.0" prefWidth="750.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-color: #5580b5; -fx-border-radius: 14;">
<children>
<GridPane hgap="25.0" VBox.vgrow="ALWAYS">
<GridPane hgap="25.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0">
<children>

View File

@@ -10,11 +10,10 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox minHeight="-Infinity" minWidth="-Infinity" prefHeight="523.0" prefWidth="790.0" spacing="20.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController">
<VBox minHeight="-Infinity" minWidth="-Infinity" prefHeight="560.0" prefWidth="790.0" spacing="20.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="79.0" prefWidth="727.0" spacing="20.0" style="-fx-background-color: #2C3E50; -fx-background-radius: 14;">
<children>
@@ -63,19 +62,14 @@
<Insets left="15.0" right="15.0" />
</padding>
</HBox>
<VBox prefHeight="370.0" prefWidth="750.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-color: #5580b5; -fx-border-radius: 14;">
<VBox prefHeight="405.0" prefWidth="750.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-color: #5580b5; -fx-border-radius: 14;">
<children>
<GridPane hgap="25.0" VBox.vgrow="ALWAYS">
<GridPane hgap="25.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0">
<children>
<Label text="Product Name:" textFill="#2c3e50">