Skip to content

74 featureadd description logo keyvalues etc to charity page #76

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
import javafx.stage.Stage;
import ntnu.systemutvikling.team6.database.DatabaseConnection;
import ntnu.systemutvikling.team6.database.DatabaseSetup;
import ntnu.systemutvikling.team6.models.Charity;
import ntnu.systemutvikling.team6.models.registry.CharityRegistry;
import ntnu.systemutvikling.team6.scraper.scraperComponents.APICharityScraper;
import ntnu.systemutvikling.team6.scraper.FullCharityScrape;
import ntnu.systemutvikling.team6.service.APIToDatabaseService;

public class HmHApplication extends Application {
Expand Down Expand Up @@ -49,16 +48,24 @@ public void init() {
/* Test and get data from Innsamlingkontrollen API */
try {
HttpClient https = HttpClient.newHttpClient();
APICharityScraper scraper = new APICharityScraper(https);
// APICharityScraper scraper = new APICharityScraper(https);
FullCharityScrape scraper = new FullCharityScrape();

DatabaseConnection conn = new DatabaseConnection();
APIToDatabaseService db = new APIToDatabaseService(conn);

if (scraper.checkConnection()) {
if (scraper.getAPIScraper().checkConnection()) {
/*
if (scraper.checkConnection()) {
CharityRegistry charityRegistry = scraper.parseJSON(scraper.getJSONData());
for (Charity charity : charityRegistry.getAllCharities()) {
System.out.println(charity.getName());
}
*/

// Comment out the two below to use already generated database.
CharityRegistry charityRegistry = scraper.getAPIAndURLCharityData();

db.addAPIDataToTable(charityRegistry.getAllCharities());
}
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
package ntnu.systemutvikling.team6.controller;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Arc;
import javafx.scene.shape.Rectangle;
import ntnu.systemutvikling.team6.controller.components.LoaderScene;
import ntnu.systemutvikling.team6.models.Charity;

Expand All @@ -18,6 +29,24 @@ public class CharityPageController {

@FXML private Label CharityName;

@FXML private ImageView CharityLogo;

@FXML private Hyperlink CharityURL;

@FXML private Arc keyValueInnsamlingArc;

@FXML private Label keyValueInnsamlingLabel;

@FXML private Arc keyValueAdminArc;

@FXML private Label keyValueAdminLabel;

@FXML private Arc keyValueFormaalArc;

@FXML private Label keyValueFormaalLabel;

@FXML private VBox categoriesContainer;

@FXML
public void initialize() {}

Expand All @@ -31,14 +60,48 @@ public void initialize() {}
* front page when the user clicks on a charity, to set the charity that is being displayed on the
* page.
*
* @param charity
* @param charity the charity to be displayed
*/
@FXML
public void setCharity(Charity charity) {
this.charity = charity;

CharityDescription.setText(charity.getDescription());
CharityName.setText(charity.getName());

if (this.charity.getLogoBlob() != null) {
ByteArrayInputStream logoByteStream = new ByteArrayInputStream(this.charity.getLogoBlob());
Image CharityLogoImage = new Image(logoByteStream);
this.CharityLogo.setImage(CharityLogoImage);
} else {
String placeholderImagePath =
Objects.requireNonNull(getClass().getResource("/images/leggTilBilde.jpg"))
.toExternalForm();
Image placeholderImage = new Image(placeholderImagePath);
this.CharityLogo.setImage(placeholderImage);
}

// Sets key values to a List<Double>
String input = charity.getKeyValues();

String[] parts = input.split(":");
List<Double> numbers = new ArrayList<>();

for (String part : parts) {
part = part.replace(",", ".");
numbers.add(Double.parseDouble(part));
}

// Sets the value of each arc and label
setArc(keyValueInnsamlingArc, numbers.getFirst());
keyValueInnsamlingLabel.setText(String.format("%.1f%%", numbers.getFirst()));
setArc(keyValueAdminArc, numbers.get(1));
keyValueAdminLabel.setText(String.format("%.1f%%", numbers.get(1)));
setArc(keyValueFormaalArc, numbers.getLast());
keyValueFormaalLabel.setText(String.format("%.1f%%", numbers.getLast()));

// Sets the categories
setCategories(charity.getCategory());
}

/**
Expand Down Expand Up @@ -73,4 +136,73 @@ public void handleSearch(ActionEvent event) {

LoaderScene.LoadScene("availableOrganization", event, null, query);
}

/**
* Opens OS default webbrowser and loads the url of the charity on click.
*
* @param event the onclick event
*/
@FXML
public void handleHomepageClick(ActionEvent event) {
try {
String url = this.charity.getURL();
java.awt.Desktop.getDesktop().browse(java.net.URI.create(url));
} catch (Exception e) {
System.out.println("Something went wrong when opening URL.");
e.printStackTrace();
}
}

/**
* Creates the labels (and the rectangle surrounding it) for the categories
*
* @param category the String for the category
* @return a fxml object used to populate the category scroll pane
*/
private StackPane createCategoryChip(String category) {

Rectangle rect = new Rectangle();
rect.setArcWidth(30);
rect.setArcHeight(30);
rect.setHeight(40);
rect.setWidth(200);
rect.setFill(javafx.scene.paint.Color.web("#F5F5F5"));
rect.setStroke(javafx.scene.paint.Color.web("#4F4F4F"));

Label label = new Label(category);
label.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;");

StackPane stack = new StackPane(rect, label);
stack.setPadding(new javafx.geometry.Insets(5));

return stack;
}

/**
* Takes a list of categories for the charities and populates a scroll pane with labels containing
* the charities.
*
* @param categories the list of categories for the charity
*/
public void setCategories(List<String> categories) {
categoriesContainer.getChildren().clear();

for (String category : categories) {
if (category == null || category.isEmpty()) continue;

StackPane chip = createCategoryChip(category);
categoriesContainer.getChildren().add(chip);
}
}

/**
* Sets the fill of the arc for the different key values.
*
* @param arc the arc for one of the 3 key values
* @param percent the percentage of the key value
*/
private void setArc(Arc arc, double percent) {
double angle = -360 * (percent / 100.0);
arc.setLength(angle);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
Expand All @@ -17,6 +18,7 @@
import ntnu.systemutvikling.team6.controller.components.NavbarFooterController;
import ntnu.systemutvikling.team6.controller.components.OrganizationCardController;
import ntnu.systemutvikling.team6.database.DatabaseConnection;
import ntnu.systemutvikling.team6.database.Readers.CategorySelect;
import ntnu.systemutvikling.team6.database.Readers.CharitySelect;
import ntnu.systemutvikling.team6.database.Readers.DonationSelect;
import ntnu.systemutvikling.team6.models.Charity;
Expand All @@ -41,9 +43,8 @@ public class FrontpageController extends BaseController implements NavbarFooterC
@FXML private Label PreApproved_Percentage;
@FXML private TextField frontSearchField;
@FXML private CheckBox verifiedFilter;
@FXML private CheckBox childrenFilter;
@FXML private CheckBox healthFilter;
@FXML private CheckBox emergencyAidFilter;
@FXML private javafx.scene.layout.VBox categoryList;
private final List<String> selectedCategories = new ArrayList<>();

private List<Charity> allCharities = new ArrayList<>();

Expand All @@ -64,8 +65,27 @@ public void initialize() {
DatabaseConnection conn = new DatabaseConnection();
CharitySelect cdb = new CharitySelect(conn);
DonationSelect ddb = new DonationSelect(conn);
CategorySelect categoryselect = new CategorySelect(conn);
CharityRegistry charities = cdb.getCharitiesFromDB();
DonationRegistry donations = ddb.getDonationFromDB();
List<String> categories = categoryselect.getCategoriesFromDB();
categories.sort(String::compareToIgnoreCase);

for (String category : categories) {
CheckBox cb = new CheckBox(category);

cb.setOnAction(
e -> {
if (cb.isSelected()) {
selectedCategories.add(category);
} else {
selectedCategories.remove(category);
}
displayCharities(getFilteredCharities());
});

categoryList.getChildren().add(cb);
}

allCharities = new ArrayList<>(charities.getAllCharities());
displayCharities(allCharities);
Expand Down Expand Up @@ -142,69 +162,42 @@ public void handleFrontSearch(ActionEvent event) {
/**
* This method is used to filter the charities based on the selected filters.
*
* <p>The filters are whether the charity was pre-verified, or if it falls under one (or more) of
* the given categories.</p>
*
* <p>The check checks whether the given charity has ALL filters. If one does not apply,
* the charity is rejected.</p>
*
* @return a list of filtered charities.
*/
private List<Charity> getFilteredCharities() {
if (!verifiedFilter.isSelected()
&& !childrenFilter.isSelected()
&& !healthFilter.isSelected()
&& !emergencyAidFilter.isSelected()) {
return allCharities;
}

List<Charity> filteredCharities = new ArrayList<>();
List<Charity> filtered = new ArrayList<>();

for (Charity charity : allCharities) {
if (matchesSelectedFilters(charity)) {
filteredCharities.add(charity);

if (verifiedFilter.isSelected() && !charity.getPreApproved()) {
continue;
}
}
return filteredCharities;
}

/**
* This method is used to check if a charity matches the selected filters.
*
* @param charity is the charity to be checked.
* @return true if the charity matches the selected filters, false otherwise.
*/
private boolean matchesSelectedFilters(Charity charity) {
return (verifiedFilter.isSelected() && charity.getPreApproved())
|| (childrenFilter.isSelected() && matchesKeywordCategory(charity, "children"))
|| (healthFilter.isSelected() && matchesKeywordCategory(charity, "health"))
|| (emergencyAidFilter.isSelected() && matchesKeywordCategory(charity, "emergency"));
}
if (!selectedCategories.isEmpty()) {

/**
* This method is used to check if a charity matches a specific category.
*
* @param charity is the charity to be checked.
* @param category is the category to check against.
* @return true if the charity matches the category, false otherwise.
*/
private boolean matchesKeywordCategory(Charity charity, String category) {
String text = (charity.getName() + " " + charity.getDescription()).toLowerCase();

return switch (category) {
case "children" ->
text.contains("child")
|| text.contains("children")
|| text.contains("barn")
|| text.contains("youth")
|| text.contains("young");
case "health" ->
text.contains("health")
|| text.contains("medical")
|| text.contains("helse")
|| text.contains("hospital")
|| text.contains("care");
case "emergency" ->
text.contains("emergency")
|| text.contains("relief")
|| text.contains("crisis")
|| text.contains("aid")
|| text.contains("disaster");
default -> false;
};
boolean hasAll =
charity.getCategory().stream()
.filter(Objects::nonNull)
.map(c -> c.toLowerCase().trim())
.collect(java.util.stream.Collectors.toSet())
.containsAll(selectedCategories);

if (!hasAll) {
continue;
}
}

filtered.add(charity);
}

return filtered;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ FOREIGN KEY (`user_id`)
CREATE TABLE IF NOT EXISTS `apbaluna`.`Categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category` VARCHAR(255) NOT NULL,
PRIMARY KEY (`category_id`))
PRIMARY KEY (`category_id`),
UNIQUE (`category`)
)
ENGINE = InnoDB;
""";

Expand All @@ -221,8 +223,8 @@ FOREIGN KEY (`Categories_category_id`)
CONSTRAINT `fk_Categories_has_Charities_Charities1`
FOREIGN KEY (`Charities_UUID_charities`)
REFERENCES `apbaluna`.`Charities` (`UUID_charities`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
""";

Expand Down Expand Up @@ -259,6 +261,7 @@ FOREIGN KEY (`User_UUID_User`)
`logoURL` TEXT NULL,
`key_values` TEXT NULL,
`logoBLOB` MEDIUMBLOB NULL,
CONSTRAINT `unique_UUID_charity` UNIQUE (`UUID_charity`),
INDEX `fk_CharityVanity_Charities1_idx` (`UUID_charity` ASC) VISIBLE,
CONSTRAINT `fk_CharityVanity_Charities1`
FOREIGN KEY (`UUID_charity`)
Expand Down
Loading
Loading