diff --git a/src/main/java/com/codedead/opal/OpalApplication.java b/src/main/java/com/codedead/opal/OpalApplication.java index 4fa3be3..6e5591d 100644 --- a/src/main/java/com/codedead/opal/OpalApplication.java +++ b/src/main/java/com/codedead/opal/OpalApplication.java @@ -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(); diff --git a/src/main/java/com/codedead/opal/controller/MainWindowController.java b/src/main/java/com/codedead/opal/controller/MainWindowController.java index 314b289..a2cfaf4 100644 --- a/src/main/java/com/codedead/opal/controller/MainWindowController.java +++ b/src/main/java/com/codedead/opal/controller/MainWindowController.java @@ -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.*; @@ -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 @@ -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)); } /** @@ -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 getAllSoundPanes() { + final List 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 getAllSoundPanes(final GridPane parent) { + private List getSoundPanes(final GridPane parent) { if (parent == null) throw new NullPointerException("GridPane cannot be null!"); final List 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); }); @@ -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 { @@ -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> typeRef = new TypeReference<>() { }; final Map mediaVolumes = objectMapper.readValue(actual, typeRef); - final List soundPanes = getAllSoundPanes(grpControls); + final List soundPanes = getAllSoundPanes(); mediaVolumes.forEach((key, value) -> soundPanes.stream().filter(e -> e.getMediaKey().equals(key)).forEach(e -> e.getSlider().setValue(value))); } catch (final IOException ex) { @@ -356,7 +495,7 @@ private void saveSoundPresetAction() { } final Map 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); @@ -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) { @@ -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)); } /** @@ -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()) { @@ -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)); } /** diff --git a/src/main/resources/translations/OpalApplication.properties b/src/main/resources/translations/OpalApplication.properties index 27a977a..0946c7a 100644 --- a/src/main/resources/translations/OpalApplication.properties +++ b/src/main/resources/translations/OpalApplication.properties @@ -101,3 +101,4 @@ PlayPauseError=Unable to play / pause! Dolphins=Dolphins RollerCoaster=Roller coaster LargeCrowd=Large crowd +Search=Search diff --git a/src/main/resources/translations/OpalApplication_de_DE.properties b/src/main/resources/translations/OpalApplication_de_DE.properties index 5d1c915..f1951ef 100644 --- a/src/main/resources/translations/OpalApplication_de_DE.properties +++ b/src/main/resources/translations/OpalApplication_de_DE.properties @@ -101,3 +101,4 @@ PlayPauseError=Abspielen / Pause konnte nicht ausgeführt werden! Dolphins=Delfine RollerCoaster=Achterbahn LargeCrowd=Große Menschenmenge +Search=Suche diff --git a/src/main/resources/translations/OpalApplication_es_ES.properties b/src/main/resources/translations/OpalApplication_es_ES.properties index 343eff1..1f78414 100644 --- a/src/main/resources/translations/OpalApplication_es_ES.properties +++ b/src/main/resources/translations/OpalApplication_es_ES.properties @@ -101,3 +101,4 @@ PlayPauseError=¡No se puede reproducir / pausar el sonido! Dolphins=Delfines RollerCoaster=Montaña rusa LargeCrowd=Multitud grande +Search=Buscar diff --git a/src/main/resources/translations/OpalApplication_fr_FR.properties b/src/main/resources/translations/OpalApplication_fr_FR.properties index 9309d95..2c3cd86 100644 --- a/src/main/resources/translations/OpalApplication_fr_FR.properties +++ b/src/main/resources/translations/OpalApplication_fr_FR.properties @@ -101,3 +101,4 @@ PlayPauseError=Impossible de lire / mettre en pause! Dolphins=Dauphins RollerCoaster=Montagnes russes LargeCrowd=Grande foule +Search=Chercher diff --git a/src/main/resources/translations/OpalApplication_hi_IN.properties b/src/main/resources/translations/OpalApplication_hi_IN.properties index 99eeb05..4f1a7f2 100644 --- a/src/main/resources/translations/OpalApplication_hi_IN.properties +++ b/src/main/resources/translations/OpalApplication_hi_IN.properties @@ -101,3 +101,4 @@ PlayPauseError=चलाने/रोकने में असमर्थ! Dolphins=डाल्फिन RollerCoaster=रोलर कोस्टर LargeCrowd=बड़ी भीड़ +Search=खोज diff --git a/src/main/resources/translations/OpalApplication_jp_JP.properties b/src/main/resources/translations/OpalApplication_jp_JP.properties index 0759b1e..f91b284 100644 --- a/src/main/resources/translations/OpalApplication_jp_JP.properties +++ b/src/main/resources/translations/OpalApplication_jp_JP.properties @@ -101,3 +101,4 @@ PlayPauseError=再生/一時停止できません! Dolphins=イルカ RollerCoaster=ローラーコースター LargeCrowd=大観衆 +Search=検索 diff --git a/src/main/resources/translations/OpalApplication_nl_NL.properties b/src/main/resources/translations/OpalApplication_nl_NL.properties index 3de44e4..2e256ad 100644 --- a/src/main/resources/translations/OpalApplication_nl_NL.properties +++ b/src/main/resources/translations/OpalApplication_nl_NL.properties @@ -101,3 +101,4 @@ PlayPauseError=Kan niet afspelen / pauzeren! Dolphins=Dolfijnen RollerCoaster=Achtbaan LargeCrowd=Grote menigte +Search=Zoeken diff --git a/src/main/resources/translations/OpalApplication_ru_RU.properties b/src/main/resources/translations/OpalApplication_ru_RU.properties index 8489b71..85a02a7 100644 --- a/src/main/resources/translations/OpalApplication_ru_RU.properties +++ b/src/main/resources/translations/OpalApplication_ru_RU.properties @@ -101,3 +101,4 @@ PlayPauseError=Невозможно воспроизвести / приоста Dolphins=Дельфины RollerCoaster=Американские горки LargeCrowd=Большая толпа +Search=Поиск diff --git a/src/main/resources/translations/OpalApplication_tr_TR.properties b/src/main/resources/translations/OpalApplication_tr_TR.properties index 0b79755..fdc75ce 100644 --- a/src/main/resources/translations/OpalApplication_tr_TR.properties +++ b/src/main/resources/translations/OpalApplication_tr_TR.properties @@ -101,3 +101,4 @@ PlayPauseError=Oynatma / Duraklatma düğmesi oluşturulamıyor! Dolphins=Yunuslar RollerCoaster=Lunapark treni LargeCrowd=Kalabalık +Search=Ara diff --git a/src/main/resources/translations/OpalApplication_uk_UA.properties b/src/main/resources/translations/OpalApplication_uk_UA.properties index d0b1885..6ad6126 100644 --- a/src/main/resources/translations/OpalApplication_uk_UA.properties +++ b/src/main/resources/translations/OpalApplication_uk_UA.properties @@ -101,3 +101,4 @@ PlayPauseError=Неможливо відтворити/призупинити! Dolphins=Дельфіни RollerCoaster=Американські гірки LargeCrowd=Великий натовп +Search=Пошук diff --git a/src/main/resources/translations/OpalApplication_zh_CN.properties b/src/main/resources/translations/OpalApplication_zh_CN.properties index eb488e7..742cda2 100644 --- a/src/main/resources/translations/OpalApplication_zh_CN.properties +++ b/src/main/resources/translations/OpalApplication_zh_CN.properties @@ -101,3 +101,4 @@ PlayPauseError=无法播放 / 暂停! Dolphins=海豚 RollerCoaster=过山车 LargeCrowd=大群众 +Search=搜索 diff --git a/src/main/resources/windows/MainWindow.fxml b/src/main/resources/windows/MainWindow.fxml index 57495a1..f71cffd 100644 --- a/src/main/resources/windows/MainWindow.fxml +++ b/src/main/resources/windows/MainWindow.fxml @@ -21,14 +21,15 @@ + + + onDragDropped="#onDragDropped"> @@ -147,9 +148,10 @@ - + + @@ -158,12 +160,40 @@ - + + + + + + + + + + + + + + + + + + - - + + @@ -221,8 +251,8 @@ image="/images/ocean.png"/> - - + + @@ -260,8 +290,8 @@ image="/images/coffee.png"/> - - + + @@ -295,8 +325,8 @@ image="/images/rugbyfootball.png"/> - - + + @@ -325,8 +355,8 @@ image="/images/radio.png"/> - - + +