Skip to content

Commit 50425a9

Browse files
authored
Merge pull request #137 from CodeDead/feature/search
feat: added search functionality
2 parents a1388fd + d408baf commit 50425a9

14 files changed

+216
-28
lines changed

src/main/java/com/codedead/opal/OpalApplication.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void start(final Stage primaryStage) {
109109
primaryStage.setTitle(translationBundle.getString("MainWindowTitle"));
110110
primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream(SharedVariables.ICON_URL))));
111111
primaryStage.setScene(scene);
112-
primaryStage.setOnCloseRequest(e -> System.exit(0));
112+
primaryStage.setOnCloseRequest(_ -> System.exit(0));
113113

114114
logger.info("Showing the MainWindow");
115115
primaryStage.show();

src/main/java/com/codedead/opal/controller/MainWindowController.java

+160-13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import javafx.application.Platform;
1111
import javafx.fxml.FXML;
1212
import javafx.fxml.FXMLLoader;
13+
import javafx.scene.Node;
1314
import javafx.scene.Parent;
1415
import javafx.scene.Scene;
1516
import javafx.scene.control.*;
@@ -38,7 +39,29 @@
3839
public final class MainWindowController implements IAudioTimer, TrayIconListener {
3940

4041
@FXML
41-
private GridPane grpControls;
42+
private TitledPane pneOther;
43+
@FXML
44+
private TitledPane pneRadioFrequencyStatic;
45+
@FXML
46+
private TitledPane pneAudiences;
47+
@FXML
48+
private TitledPane pneOffice;
49+
@FXML
50+
private TitledPane pneNature;
51+
@FXML
52+
private Button btnClearSearch;
53+
@FXML
54+
private TextField txtSearch;
55+
@FXML
56+
private GridPane grpOther;
57+
@FXML
58+
private GridPane grpRadioFrequencyStatic;
59+
@FXML
60+
private GridPane grpAudiences;
61+
@FXML
62+
private GridPane grpOffice;
63+
@FXML
64+
private GridPane grpNature;
4265
@FXML
4366
private CheckMenuItem mniTimerEnabled;
4467
@FXML
@@ -139,7 +162,7 @@ public void setControllers(final SettingsController settingsController, final Up
139162
* @param visible True if the media buttons should be visible, otherwise false
140163
*/
141164
public void loadMediaButtonVisibility(final boolean visible) {
142-
getAllSoundPanes(grpControls).forEach(s -> s.setMediaButton(visible));
165+
getAllSoundPanes().forEach(s -> s.setMediaButton(visible));
143166
}
144167

145168
/**
@@ -201,20 +224,37 @@ private void checkForUpdates(final boolean showNoUpdates, final boolean showErro
201224
}
202225
}
203226

227+
/**
228+
* Get all {@link SoundPane} objects
229+
*
230+
* @return The {@link List} of {@link SoundPane} objects
231+
*/
232+
private List<SoundPane> getAllSoundPanes() {
233+
final List<SoundPane> elements = new ArrayList<>();
234+
235+
elements.addAll(getSoundPanes(grpOther));
236+
elements.addAll(getSoundPanes(grpRadioFrequencyStatic));
237+
elements.addAll(getSoundPanes(grpAudiences));
238+
elements.addAll(getSoundPanes(grpOffice));
239+
elements.addAll(getSoundPanes(grpNature));
240+
241+
return elements;
242+
}
243+
204244
/**
205245
* Get all {@link SoundPane} objects from a {@link GridPane} object
206246
*
207247
* @param parent The {@link GridPane} object
208248
* @return The {@link List} of {@link SoundPane} objects inside the given {@link GridPane} object
209249
*/
210-
private List<SoundPane> getAllSoundPanes(final GridPane parent) {
250+
private List<SoundPane> getSoundPanes(final GridPane parent) {
211251
if (parent == null)
212252
throw new NullPointerException("GridPane cannot be null!");
213253

214254
final List<SoundPane> elements = new ArrayList<>();
215255
parent.getChildren().forEach(e -> {
216256
if (e instanceof GridPane p)
217-
elements.addAll(getAllSoundPanes(p));
257+
elements.addAll(getSoundPanes(p));
218258
if (e instanceof SoundPane s)
219259
elements.add(s);
220260
});
@@ -271,13 +311,112 @@ private void initialize() {
271311
cancelTimer();
272312
}
273313
});
314+
315+
txtSearch.textProperty().addListener((_, _, newValue) -> {
316+
if (newValue == null || newValue.isBlank()) {
317+
Platform.runLater(() -> {
318+
getAllSoundPanes().forEach(e -> {
319+
e.setVisible(true);
320+
e.setManaged(true);
321+
});
322+
btnClearSearch.setVisible(false);
323+
btnClearSearch.setManaged(false);
324+
325+
pneNature.setExpanded(true);
326+
pneNature.setVisible(true);
327+
pneNature.setManaged(true);
328+
329+
pneOffice.setExpanded(false);
330+
pneOffice.setVisible(true);
331+
pneOffice.setManaged(true);
332+
333+
pneAudiences.setExpanded(false);
334+
pneAudiences.setVisible(true);
335+
pneAudiences.setManaged(true);
336+
337+
pneRadioFrequencyStatic.setExpanded(false);
338+
pneRadioFrequencyStatic.setVisible(true);
339+
pneRadioFrequencyStatic.setManaged(true);
340+
341+
pneOther.setExpanded(false);
342+
pneOther.setVisible(true);
343+
pneOther.setManaged(true);
344+
});
345+
return;
346+
}
347+
Platform.runLater(() -> {
348+
getAllSoundPanes()
349+
.forEach(e -> {
350+
e.setVisible(e.getName().toLowerCase().contains(newValue.trim().toLowerCase()));
351+
e.setManaged(e.isVisible());
352+
});
353+
354+
// Check if there are still active sound panes on pneNature
355+
getSoundPanes(grpNature).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
356+
pneNature.setExpanded(true);
357+
pneNature.setVisible(true);
358+
pneNature.setManaged(true);
359+
}, () -> {
360+
pneNature.setExpanded(false);
361+
pneNature.setVisible(false);
362+
pneNature.setManaged(false);
363+
});
364+
365+
// Check if there are still active sound panes on pneOffice
366+
getSoundPanes(grpOffice).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
367+
pneOffice.setExpanded(true);
368+
pneOffice.setVisible(true);
369+
pneOffice.setManaged(true);
370+
}, () -> {
371+
pneOffice.setExpanded(false);
372+
pneOffice.setVisible(false);
373+
pneOffice.setManaged(false);
374+
});
375+
376+
// Check if there are still active sound panes on pneAudiences
377+
getSoundPanes(grpAudiences).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
378+
pneAudiences.setExpanded(true);
379+
pneAudiences.setVisible(true);
380+
pneAudiences.setManaged(true);
381+
}, () -> {
382+
pneAudiences.setExpanded(false);
383+
pneAudiences.setVisible(false);
384+
pneAudiences.setManaged(false);
385+
});
386+
387+
// Check if there are still active sound panes on pneRadioFrequencyStatic
388+
getSoundPanes(grpRadioFrequencyStatic).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
389+
pneRadioFrequencyStatic.setExpanded(true);
390+
pneRadioFrequencyStatic.setVisible(true);
391+
pneRadioFrequencyStatic.setManaged(true);
392+
}, () -> {
393+
pneRadioFrequencyStatic.setExpanded(false);
394+
pneRadioFrequencyStatic.setVisible(false);
395+
pneRadioFrequencyStatic.setManaged(false);
396+
});
397+
398+
// Check if there are still active sound panes on pneOther
399+
getSoundPanes(grpOther).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
400+
pneOther.setExpanded(true);
401+
pneOther.setVisible(true);
402+
pneOther.setManaged(true);
403+
}, () -> {
404+
pneOther.setExpanded(false);
405+
pneOther.setVisible(false);
406+
pneOther.setManaged(false);
407+
});
408+
409+
btnClearSearch.setVisible(true);
410+
btnClearSearch.setManaged(true);
411+
});
412+
});
274413
}
275414

276415
/**
277416
* Hide the current stage
278417
*/
279418
private void hideShowStage() {
280-
final Stage stage = (Stage) grpControls.getScene().getWindow();
419+
final Stage stage = (Stage) grpNature.getScene().getWindow();
281420
if (stage.isShowing()) {
282421
stage.hide();
283422
} else {
@@ -320,14 +459,14 @@ private void openSoundPreset(final String path) {
320459
final Path filePath = Path.of(path);
321460
final String actual = Files.readString(filePath);
322461

323-
if (actual == null || actual.isEmpty())
324-
throw new IllegalArgumentException("Sound preset cannot be null or empty!");
462+
if (actual.isEmpty())
463+
throw new IllegalArgumentException("Sound preset cannot be empty!");
325464

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

329468
final Map<String, Double> mediaVolumes = objectMapper.readValue(actual, typeRef);
330-
final List<SoundPane> soundPanes = getAllSoundPanes(grpControls);
469+
final List<SoundPane> soundPanes = getAllSoundPanes();
331470

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

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

361500
try {
362501
objectMapper.writeValue(new File(filePath), mediaVolumes);
@@ -376,7 +515,7 @@ private void saveSoundPresetAction() {
376515
private void playPauseAction() {
377516
logger.info("Play / pause all media");
378517
try {
379-
for (final SoundPane soundPane : getAllSoundPanes(grpControls)) {
518+
for (final SoundPane soundPane : getAllSoundPanes()) {
380519
soundPane.playPause();
381520
}
382521
} catch (final MediaPlayerException ex) {
@@ -391,7 +530,7 @@ private void playPauseAction() {
391530
@FXML
392531
private void resetAction() {
393532
logger.info("Resetting all audio sliders");
394-
getAllSoundPanes(grpControls).forEach(e -> e.getSlider().setValue(0));
533+
getAllSoundPanes().forEach(e -> e.getSlider().setValue(0));
395534
}
396535

397536
/**
@@ -530,13 +669,21 @@ private void updateAction() {
530669
checkForUpdates(true, true);
531670
}
532671

672+
/**
673+
* Method that is called when the search field should be cleared
674+
*/
675+
@FXML
676+
private void clearSearchAction() {
677+
txtSearch.clear();
678+
}
679+
533680
/**
534681
* Method that is called when the {@link Timer} object has fired
535682
*/
536683
@Override
537684
public void fired() {
538685
cancelTimer();
539-
getAllSoundPanes(grpControls).forEach(SoundPane::pause);
686+
getAllSoundPanes().forEach(SoundPane::pause);
540687

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

709856
logger.info("Setting the audio balance to {}", audioBalance);
710-
getAllSoundPanes(grpControls).forEach(s -> s.setBalance(audioBalance));
857+
getAllSoundPanes().forEach(s -> s.setBalance(audioBalance));
711858
}
712859

713860
/**

src/main/resources/translations/OpalApplication.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=Unable to play / pause!
101101
Dolphins=Dolphins
102102
RollerCoaster=Roller coaster
103103
LargeCrowd=Large crowd
104+
Search=Search

src/main/resources/translations/OpalApplication_de_DE.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=Abspielen / Pause konnte nicht ausgeführt werden!
101101
Dolphins=Delfine
102102
RollerCoaster=Achterbahn
103103
LargeCrowd=Große Menschenmenge
104+
Search=Suche

src/main/resources/translations/OpalApplication_es_ES.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=¡No se puede reproducir / pausar el sonido!
101101
Dolphins=Delfines
102102
RollerCoaster=Montaña rusa
103103
LargeCrowd=Multitud grande
104+
Search=Buscar

src/main/resources/translations/OpalApplication_fr_FR.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=Impossible de lire / mettre en pause!
101101
Dolphins=Dauphins
102102
RollerCoaster=Montagnes russes
103103
LargeCrowd=Grande foule
104+
Search=Chercher

src/main/resources/translations/OpalApplication_hi_IN.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=चलाने/रोकने में असमर्थ!
101101
Dolphins=डाल्फिन
102102
RollerCoaster=रोलर कोस्टर
103103
LargeCrowd=बड़ी भीड़
104+
Search=खोज

src/main/resources/translations/OpalApplication_jp_JP.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=再生/一時停止できません!
101101
Dolphins=イルカ
102102
RollerCoaster=ローラーコースター
103103
LargeCrowd=大観衆
104+
Search=検索

src/main/resources/translations/OpalApplication_nl_NL.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=Kan niet afspelen / pauzeren!
101101
Dolphins=Dolfijnen
102102
RollerCoaster=Achtbaan
103103
LargeCrowd=Grote menigte
104+
Search=Zoeken

src/main/resources/translations/OpalApplication_ru_RU.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=Невозможно воспроизвести / приоста
101101
Dolphins=Дельфины
102102
RollerCoaster=Американские горки
103103
LargeCrowd=Большая толпа
104+
Search=Поиск

src/main/resources/translations/OpalApplication_tr_TR.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=Oynatma / Duraklatma düğmesi oluşturulamıyor!
101101
Dolphins=Yunuslar
102102
RollerCoaster=Lunapark treni
103103
LargeCrowd=Kalabalık
104+
Search=Ara

src/main/resources/translations/OpalApplication_uk_UA.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=Неможливо відтворити/призупинити!
101101
Dolphins=Дельфіни
102102
RollerCoaster=Американські гірки
103103
LargeCrowd=Великий натовп
104+
Search=Пошук

src/main/resources/translations/OpalApplication_zh_CN.properties

+1
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ PlayPauseError=无法播放 / 暂停!
101101
Dolphins=海豚
102102
RollerCoaster=过山车
103103
LargeCrowd=大群众
104+
Search=搜索

0 commit comments

Comments
 (0)