diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java index 61cc8c9a1cb..675f7439965 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/address/commons/util/StringUtil.java @@ -65,4 +65,25 @@ public static boolean isNonZeroUnsignedInteger(String s) { return false; } } + + /** + * Formats the given values with the format string, but return null if any of the given values are null or empty. + * + * @param format The format string to use. + * @param values The values to insert into the format string. + * @return The formatted string, or null if any of the values are null. + */ + public static String formatWithNullFallback(String format, Object... values) { + if (format == null) { + return null; + } + + for (Object v : values) { + if (v == null || v.toString().isBlank()) { + return null; + } + } + + return String.format(format, values); + } } diff --git a/src/main/java/seedu/address/ui/ContactCard.java b/src/main/java/seedu/address/ui/ContactCard.java index 57c1a85b811..7148574e103 100644 --- a/src/main/java/seedu/address/ui/ContactCard.java +++ b/src/main/java/seedu/address/ui/ContactCard.java @@ -1,13 +1,19 @@ package seedu.address.ui; import java.util.Comparator; +import java.util.function.Supplier; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import seedu.address.commons.util.StringUtil; import seedu.address.model.person.Contact; +import seedu.address.model.person.Id; +import seedu.address.model.person.Organization; +import seedu.address.model.person.Recruiter; /** * An UI component that displays information of a {@code Contact}. @@ -29,16 +35,28 @@ public class ContactCard extends UiPart { @FXML private HBox cardPane; @FXML + private VBox cardPaneInnerVbox; + @FXML private Label name; @FXML + private Label index; + @FXML private Label id; @FXML + private Label linkedParentOrganization; + @FXML private Label phone; @FXML private Label address; @FXML private Label email; @FXML + private Label status; + @FXML + private Label position; + @FXML + private Label url; + @FXML private FlowPane tags; /** @@ -47,13 +65,78 @@ public class ContactCard extends UiPart { public ContactCard(Contact contact, int displayedIndex) { super(FXML); this.contact = contact; - id.setText(displayedIndex + ". "); + + index.setText(String.format("%d. ", displayedIndex)); + id.setText(contact.getId().value); name.setText(contact.getName().fullName); - phone.setText(contact.getPhone().value); - address.setText(contact.getAddress().value); - email.setText(contact.getEmail().value); + + final Label typeLabel = new Label(contact.getType().toString()); + typeLabel.setId("type"); + tags.getChildren().add(typeLabel); // add it to the front of tags + + setVboxInnerLabelText(phone, () -> contact.getPhone().value); + setVboxInnerLabelText(address, () -> contact.getAddress().value); + setVboxInnerLabelText(email, () -> contact.getEmail().value); + setVboxInnerLabelText(url, () -> contact.getUrl().value); + + switch (contact.getType()) { + case ORGANIZATION: { + Organization organization = (Organization) contact; + final String statusString = organization.getStatus().applicationStatus; + final String positionString = organization.getPosition().jobPosition; + + setVboxInnerLabelText( + status, () -> StringUtil.formatWithNullFallback("Application Status: %s", statusString) + ); + setVboxInnerLabelText( + position, () -> StringUtil.formatWithNullFallback("Application Position: %s", positionString) + ); + cardPaneInnerVbox.getChildren().remove(linkedParentOrganization); + break; + } + case RECRUITER: { + Recruiter recruiter = (Recruiter) contact; + + final Id linkedOrgId = recruiter.getOrganizationId(); + + setVboxInnerLabelText( + linkedParentOrganization, () -> linkedOrgId == null + ? null + : String.format( + "from %s (%s)", "organization" /* TODO: Use org name instead */, linkedOrgId.value + ) + ); + cardPaneInnerVbox.getChildren().removeAll(status, position); + break; + } + default: + cardPaneInnerVbox.getChildren().removeAll(status, position, linkedParentOrganization); + break; + } + contact.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); } + + /** + * Configures the inner label contained within the vbox container to show the given string, + * or remove the label entirely if the string is empty or null. + * + * @param label The label to set the text to. + * @param valueSupplier The string value supplier. This may be expressed as a lambda function. + */ + private void setVboxInnerLabelText(Label label, Supplier valueSupplier) { + if (label == null) { + return; + } + + String value = valueSupplier.get(); + if (value == null || value.isBlank()) { + label.setText(null); + cardPaneInnerVbox.getChildren().remove(label); + } else { + label.setText(value); + } + } } diff --git a/src/main/resources/view/ContactListCard.fxml b/src/main/resources/view/ContactListCard.fxml index f5e812e25e6..8411c22cd18 100644 --- a/src/main/resources/view/ContactListCard.fxml +++ b/src/main/resources/view/ContactListCard.fxml @@ -14,12 +14,12 @@ - + - + diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 36e6b001cd8..51cb32b4bdb 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -337,6 +337,12 @@ -fx-background-radius: 0; } +.label#id { + -fx-text-fill: #d0d0d088; + -fx-font-size: 10px; + -fx-font-style: italic; +} + #tags { -fx-hgap: 7; -fx-vgap: 3; @@ -350,3 +356,7 @@ -fx-background-radius: 2; -fx-font-size: 11; } + +#tags .label#type { + -fx-background-color: #3f917e; +}