Skip to content

Commit

Permalink
Merge pull request #137 from CodeDead/feature/search
Browse files Browse the repository at this point in the history
feat: added search functionality
  • Loading branch information
CodeDead authored Jan 19, 2025
2 parents a1388fd + d408baf commit 50425a9
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/main/java/com/codedead/opal/OpalApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void start(final Stage primaryStage) {
primaryStage.setTitle(translationBundle.getString("MainWindowTitle"));
primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream(SharedVariables.ICON_URL))));
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(e -> System.exit(0));
primaryStage.setOnCloseRequest(_ -> System.exit(0));

logger.info("Showing the MainWindow");
primaryStage.show();
Expand Down
173 changes: 160 additions & 13 deletions src/main/java/com/codedead/opal/controller/MainWindowController.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
Expand Down Expand Up @@ -38,7 +39,29 @@
public final class MainWindowController implements IAudioTimer, TrayIconListener {

@FXML
private GridPane grpControls;
private TitledPane pneOther;
@FXML
private TitledPane pneRadioFrequencyStatic;
@FXML
private TitledPane pneAudiences;
@FXML
private TitledPane pneOffice;
@FXML
private TitledPane pneNature;
@FXML
private Button btnClearSearch;
@FXML
private TextField txtSearch;
@FXML
private GridPane grpOther;
@FXML
private GridPane grpRadioFrequencyStatic;
@FXML
private GridPane grpAudiences;
@FXML
private GridPane grpOffice;
@FXML
private GridPane grpNature;
@FXML
private CheckMenuItem mniTimerEnabled;
@FXML
Expand Down Expand Up @@ -139,7 +162,7 @@ public void setControllers(final SettingsController settingsController, final Up
* @param visible True if the media buttons should be visible, otherwise false
*/
public void loadMediaButtonVisibility(final boolean visible) {
getAllSoundPanes(grpControls).forEach(s -> s.setMediaButton(visible));
getAllSoundPanes().forEach(s -> s.setMediaButton(visible));
}

/**
Expand Down Expand Up @@ -201,20 +224,37 @@ private void checkForUpdates(final boolean showNoUpdates, final boolean showErro
}
}

/**
* Get all {@link SoundPane} objects
*
* @return The {@link List} of {@link SoundPane} objects
*/
private List<SoundPane> getAllSoundPanes() {
final List<SoundPane> elements = new ArrayList<>();

elements.addAll(getSoundPanes(grpOther));
elements.addAll(getSoundPanes(grpRadioFrequencyStatic));
elements.addAll(getSoundPanes(grpAudiences));
elements.addAll(getSoundPanes(grpOffice));
elements.addAll(getSoundPanes(grpNature));

return elements;
}

/**
* Get all {@link SoundPane} objects from a {@link GridPane} object
*
* @param parent The {@link GridPane} object
* @return The {@link List} of {@link SoundPane} objects inside the given {@link GridPane} object
*/
private List<SoundPane> getAllSoundPanes(final GridPane parent) {
private List<SoundPane> getSoundPanes(final GridPane parent) {
if (parent == null)
throw new NullPointerException("GridPane cannot be null!");

final List<SoundPane> elements = new ArrayList<>();
parent.getChildren().forEach(e -> {
if (e instanceof GridPane p)
elements.addAll(getAllSoundPanes(p));
elements.addAll(getSoundPanes(p));
if (e instanceof SoundPane s)
elements.add(s);
});
Expand Down Expand Up @@ -271,13 +311,112 @@ private void initialize() {
cancelTimer();
}
});

txtSearch.textProperty().addListener((_, _, newValue) -> {
if (newValue == null || newValue.isBlank()) {
Platform.runLater(() -> {
getAllSoundPanes().forEach(e -> {
e.setVisible(true);
e.setManaged(true);
});
btnClearSearch.setVisible(false);
btnClearSearch.setManaged(false);

pneNature.setExpanded(true);
pneNature.setVisible(true);
pneNature.setManaged(true);

pneOffice.setExpanded(false);
pneOffice.setVisible(true);
pneOffice.setManaged(true);

pneAudiences.setExpanded(false);
pneAudiences.setVisible(true);
pneAudiences.setManaged(true);

pneRadioFrequencyStatic.setExpanded(false);
pneRadioFrequencyStatic.setVisible(true);
pneRadioFrequencyStatic.setManaged(true);

pneOther.setExpanded(false);
pneOther.setVisible(true);
pneOther.setManaged(true);
});
return;
}
Platform.runLater(() -> {
getAllSoundPanes()
.forEach(e -> {
e.setVisible(e.getName().toLowerCase().contains(newValue.trim().toLowerCase()));
e.setManaged(e.isVisible());
});

// Check if there are still active sound panes on pneNature
getSoundPanes(grpNature).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
pneNature.setExpanded(true);
pneNature.setVisible(true);
pneNature.setManaged(true);
}, () -> {
pneNature.setExpanded(false);
pneNature.setVisible(false);
pneNature.setManaged(false);
});

// Check if there are still active sound panes on pneOffice
getSoundPanes(grpOffice).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
pneOffice.setExpanded(true);
pneOffice.setVisible(true);
pneOffice.setManaged(true);
}, () -> {
pneOffice.setExpanded(false);
pneOffice.setVisible(false);
pneOffice.setManaged(false);
});

// Check if there are still active sound panes on pneAudiences
getSoundPanes(grpAudiences).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
pneAudiences.setExpanded(true);
pneAudiences.setVisible(true);
pneAudiences.setManaged(true);
}, () -> {
pneAudiences.setExpanded(false);
pneAudiences.setVisible(false);
pneAudiences.setManaged(false);
});

// Check if there are still active sound panes on pneRadioFrequencyStatic
getSoundPanes(grpRadioFrequencyStatic).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
pneRadioFrequencyStatic.setExpanded(true);
pneRadioFrequencyStatic.setVisible(true);
pneRadioFrequencyStatic.setManaged(true);
}, () -> {
pneRadioFrequencyStatic.setExpanded(false);
pneRadioFrequencyStatic.setVisible(false);
pneRadioFrequencyStatic.setManaged(false);
});

// Check if there are still active sound panes on pneOther
getSoundPanes(grpOther).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
pneOther.setExpanded(true);
pneOther.setVisible(true);
pneOther.setManaged(true);
}, () -> {
pneOther.setExpanded(false);
pneOther.setVisible(false);
pneOther.setManaged(false);
});

btnClearSearch.setVisible(true);
btnClearSearch.setManaged(true);
});
});
}

/**
* Hide the current stage
*/
private void hideShowStage() {
final Stage stage = (Stage) grpControls.getScene().getWindow();
final Stage stage = (Stage) grpNature.getScene().getWindow();
if (stage.isShowing()) {
stage.hide();
} else {
Expand Down Expand Up @@ -320,14 +459,14 @@ private void openSoundPreset(final String path) {
final Path filePath = Path.of(path);
final String actual = Files.readString(filePath);

if (actual == null || actual.isEmpty())
throw new IllegalArgumentException("Sound preset cannot be null or empty!");
if (actual.isEmpty())
throw new IllegalArgumentException("Sound preset cannot be empty!");

final TypeReference<HashMap<String, Double>> typeRef = new TypeReference<>() {
};

final Map<String, Double> mediaVolumes = objectMapper.readValue(actual, typeRef);
final List<SoundPane> soundPanes = getAllSoundPanes(grpControls);
final List<SoundPane> soundPanes = getAllSoundPanes();

mediaVolumes.forEach((key, value) -> soundPanes.stream().filter(e -> e.getMediaKey().equals(key)).forEach(e -> e.getSlider().setValue(value)));
} catch (final IOException ex) {
Expand Down Expand Up @@ -356,7 +495,7 @@ private void saveSoundPresetAction() {
}

final Map<String, Double> mediaVolumes = new HashMap<>();
getAllSoundPanes(grpControls).forEach(e -> mediaVolumes.put(e.getMediaKey(), e.getSlider().getValue()));
getAllSoundPanes().forEach(e -> mediaVolumes.put(e.getMediaKey(), e.getSlider().getValue()));

try {
objectMapper.writeValue(new File(filePath), mediaVolumes);
Expand All @@ -376,7 +515,7 @@ private void saveSoundPresetAction() {
private void playPauseAction() {
logger.info("Play / pause all media");
try {
for (final SoundPane soundPane : getAllSoundPanes(grpControls)) {
for (final SoundPane soundPane : getAllSoundPanes()) {
soundPane.playPause();
}
} catch (final MediaPlayerException ex) {
Expand All @@ -391,7 +530,7 @@ private void playPauseAction() {
@FXML
private void resetAction() {
logger.info("Resetting all audio sliders");
getAllSoundPanes(grpControls).forEach(e -> e.getSlider().setValue(0));
getAllSoundPanes().forEach(e -> e.getSlider().setValue(0));
}

/**
Expand Down Expand Up @@ -530,13 +669,21 @@ private void updateAction() {
checkForUpdates(true, true);
}

/**
* Method that is called when the search field should be cleared
*/
@FXML
private void clearSearchAction() {
txtSearch.clear();
}

/**
* Method that is called when the {@link Timer} object has fired
*/
@Override
public void fired() {
cancelTimer();
getAllSoundPanes(grpControls).forEach(SoundPane::pause);
getAllSoundPanes().forEach(SoundPane::pause);

if (Boolean.parseBoolean(settingsController.getProperties().getProperty("timerComputerShutdown", "false"))) {
final String command = switch (platformName.toLowerCase()) {
Expand Down Expand Up @@ -707,7 +854,7 @@ public void setAudioBalance(final double audioBalance) {
throw new IllegalArgumentException("Balance must be between -1.0 and 1.0!");

logger.info("Setting the audio balance to {}", audioBalance);
getAllSoundPanes(grpControls).forEach(s -> s.setBalance(audioBalance));
getAllSoundPanes().forEach(s -> s.setBalance(audioBalance));
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/translations/OpalApplication.properties
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=Unable to play / pause!
Dolphins=Dolphins
RollerCoaster=Roller coaster
LargeCrowd=Large crowd
Search=Search
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=Abspielen / Pause konnte nicht ausgeführt werden!
Dolphins=Delfine
RollerCoaster=Achterbahn
LargeCrowd=Große Menschenmenge
Search=Suche
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=¡No se puede reproducir / pausar el sonido!
Dolphins=Delfines
RollerCoaster=Montaña rusa
LargeCrowd=Multitud grande
Search=Buscar
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=Impossible de lire / mettre en pause!
Dolphins=Dauphins
RollerCoaster=Montagnes russes
LargeCrowd=Grande foule
Search=Chercher
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=चलाने/रोकने में असमर्थ!
Dolphins=डाल्फिन
RollerCoaster=रोलर कोस्टर
LargeCrowd=बड़ी भीड़
Search=खोज
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=再生/一時停止できません!
Dolphins=イルカ
RollerCoaster=ローラーコースター
LargeCrowd=大観衆
Search=検索
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=Kan niet afspelen / pauzeren!
Dolphins=Dolfijnen
RollerCoaster=Achtbaan
LargeCrowd=Grote menigte
Search=Zoeken
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=Невозможно воспроизвести / приоста
Dolphins=Дельфины
RollerCoaster=Американские горки
LargeCrowd=Большая толпа
Search=Поиск
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=Oynatma / Duraklatma düğmesi oluşturulamıyor!
Dolphins=Yunuslar
RollerCoaster=Lunapark treni
LargeCrowd=Kalabalık
Search=Ara
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=Неможливо відтворити/призупинити!
Dolphins=Дельфіни
RollerCoaster=Американські гірки
LargeCrowd=Великий натовп
Search=Пошук
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ PlayPauseError=无法播放 / 暂停!
Dolphins=海豚
RollerCoaster=过山车
LargeCrowd=大群众
Search=搜索
Loading

0 comments on commit 50425a9

Please sign in to comment.