Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added search functionality #137

Merged
merged 3 commits into from
Jan 19, 2025
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
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
Loading