Skip to content

Commit ba3b099

Browse files
authored
Merge pull request #138 from CodeDead/feature/add-custom-sounds
feat: added the ability to add custom sounds, refactoring
2 parents 63ceee8 + 87aa516 commit ba3b099

20 files changed

+264
-82
lines changed

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

Lines changed: 109 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import javafx.scene.input.Dragboard;
2020
import javafx.scene.input.TransferMode;
2121
import javafx.scene.layout.GridPane;
22+
import javafx.scene.layout.Priority;
23+
import javafx.scene.layout.RowConstraints;
2224
import javafx.scene.media.MediaPlayer;
2325
import javafx.stage.FileChooser;
2426
import javafx.stage.Stage;
@@ -38,6 +40,10 @@
3840

3941
public final class MainWindowController implements IAudioTimer, TrayIconListener {
4042

43+
@FXML
44+
private GridPane grpCustom;
45+
@FXML
46+
private TitledPane pneCustom;
4147
@FXML
4248
private TitledPane pneOther;
4349
@FXML
@@ -269,8 +275,8 @@ private List<SoundPane> getSoundPanes(final GridPane parent) {
269275
private void openFile(final String path) {
270276
if (path == null)
271277
throw new NullPointerException("Path cannot be null!");
272-
if (path.isEmpty())
273-
throw new IllegalArgumentException("Path cannot be empty!");
278+
if (path.isBlank())
279+
throw new IllegalArgumentException("Path cannot be blank!");
274280

275281
try {
276282
helpUtils.openFile(new RunnableFileOpener(path, new IRunnableHelper() {
@@ -319,6 +325,19 @@ private void initialize() {
319325
e.setVisible(true);
320326
e.setManaged(true);
321327
});
328+
329+
final List<SoundPane> customSoundPanes = getSoundPanes(grpCustom);
330+
if (!customSoundPanes.isEmpty()) {
331+
pneCustom.setExpanded(true);
332+
pneCustom.setVisible(true);
333+
pneCustom.setManaged(true);
334+
335+
customSoundPanes.forEach(e -> {
336+
e.setVisible(true);
337+
e.setManaged(true);
338+
});
339+
}
340+
322341
btnClearSearch.setVisible(false);
323342
btnClearSearch.setManaged(false);
324343

@@ -344,15 +363,36 @@ private void initialize() {
344363
});
345364
return;
346365
}
366+
347367
Platform.runLater(() -> {
348368
getAllSoundPanes()
349369
.forEach(e -> {
350370
e.setVisible(e.getName().toLowerCase().contains(newValue.trim().toLowerCase()));
351371
e.setManaged(e.isVisible());
352372
});
353373

374+
getSoundPanes(grpCustom)
375+
.forEach(e -> {
376+
e.setVisible(e.getName().toLowerCase().contains(newValue.trim().toLowerCase()));
377+
e.setManaged(e.isVisible());
378+
});
379+
380+
// Check if there are still active sound panes on pneCustom
381+
final List<SoundPane> customSoundPanes = getSoundPanes(grpCustom);
382+
if (!customSoundPanes.isEmpty()) {
383+
customSoundPanes.stream().filter(Node::isVisible).findFirst().ifPresentOrElse(_ -> {
384+
pneCustom.setExpanded(true);
385+
pneCustom.setVisible(true);
386+
pneCustom.setManaged(true);
387+
}, () -> {
388+
pneCustom.setExpanded(false);
389+
pneCustom.setVisible(false);
390+
pneCustom.setManaged(false);
391+
});
392+
}
393+
354394
// Check if there are still active sound panes on pneNature
355-
getSoundPanes(grpNature).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
395+
getSoundPanes(grpNature).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(_ -> {
356396
pneNature.setExpanded(true);
357397
pneNature.setVisible(true);
358398
pneNature.setManaged(true);
@@ -363,7 +403,7 @@ private void initialize() {
363403
});
364404

365405
// Check if there are still active sound panes on pneOffice
366-
getSoundPanes(grpOffice).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
406+
getSoundPanes(grpOffice).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(_ -> {
367407
pneOffice.setExpanded(true);
368408
pneOffice.setVisible(true);
369409
pneOffice.setManaged(true);
@@ -374,7 +414,7 @@ private void initialize() {
374414
});
375415

376416
// Check if there are still active sound panes on pneAudiences
377-
getSoundPanes(grpAudiences).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
417+
getSoundPanes(grpAudiences).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(_ -> {
378418
pneAudiences.setExpanded(true);
379419
pneAudiences.setVisible(true);
380420
pneAudiences.setManaged(true);
@@ -385,7 +425,7 @@ private void initialize() {
385425
});
386426

387427
// Check if there are still active sound panes on pneRadioFrequencyStatic
388-
getSoundPanes(grpRadioFrequencyStatic).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
428+
getSoundPanes(grpRadioFrequencyStatic).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(_ -> {
389429
pneRadioFrequencyStatic.setExpanded(true);
390430
pneRadioFrequencyStatic.setVisible(true);
391431
pneRadioFrequencyStatic.setManaged(true);
@@ -396,7 +436,7 @@ private void initialize() {
396436
});
397437

398438
// Check if there are still active sound panes on pneOther
399-
getSoundPanes(grpOther).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(e -> {
439+
getSoundPanes(grpOther).stream().filter(Node::isVisible).findFirst().ifPresentOrElse(_ -> {
400440
pneOther.setExpanded(true);
401441
pneOther.setVisible(true);
402442
pneOther.setManaged(true);
@@ -442,6 +482,52 @@ private void openSoundPresetAction() {
442482
}
443483
}
444484

485+
/**
486+
* Open a custom sound
487+
*/
488+
@FXML
489+
private void addCustomSound() {
490+
logger.info("Opening a custom sound");
491+
final FileChooser chooser = new FileChooser();
492+
493+
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("MP3 (*.mp3)", "*.mp3");
494+
chooser.getExtensionFilters().add(extFilter);
495+
496+
final File file = chooser.showOpenDialog(new Stage());
497+
498+
if (file != null && file.exists()) {
499+
if (file.getAbsolutePath().isBlank())
500+
throw new IllegalArgumentException("Path cannot be blank!");
501+
502+
logger.info("Loading custom sound from {}", file.getAbsolutePath());
503+
504+
try {
505+
final RowConstraints row = new RowConstraints();
506+
row.setVgrow(Priority.ALWAYS);
507+
508+
grpCustom.getRowConstraints().add(row);
509+
510+
final SoundPane customSoundPane = new SoundPane();
511+
final int count = getSoundPanes(grpCustom).size() + 1;
512+
513+
customSoundPane.setName(translationBundle.getString("CustomSound") + " #" + count);
514+
customSoundPane.setMediaKey("custom" + count);
515+
customSoundPane.setMediaPath(file.toURI().toURL().toString());
516+
customSoundPane.setImage("/images/customsound.png");
517+
customSoundPane.setResourceFile(false);
518+
519+
grpCustom.add(customSoundPane, 0, count - 1);
520+
521+
pneCustom.setExpanded(true);
522+
pneCustom.setVisible(true);
523+
pneCustom.setManaged(true);
524+
} catch (final IOException ex) {
525+
logger.error("Unable to open the custom sound from {}", file.getAbsolutePath(), ex);
526+
FxUtils.showErrorAlert(translationBundle.getString("OpenCustomSoundError"), ex.toString(), getClass().getResourceAsStream(SharedVariables.ICON_URL));
527+
}
528+
}
529+
}
530+
445531
/**
446532
* Open a sound preset
447533
*
@@ -450,17 +536,17 @@ private void openSoundPresetAction() {
450536
private void openSoundPreset(final String path) {
451537
if (path == null)
452538
throw new NullPointerException("Path cannot be null!");
453-
if (path.isEmpty())
454-
throw new IllegalArgumentException("Path cannot be empty!");
539+
if (path.isBlank())
540+
throw new IllegalArgumentException("Path cannot be blank!");
455541

456542
logger.info("Loading sound preset from {}", path);
457543

458544
try {
459545
final Path filePath = Path.of(path);
460546
final String actual = Files.readString(filePath);
461547

462-
if (actual.isEmpty())
463-
throw new IllegalArgumentException("Sound preset cannot be empty!");
548+
if (actual.isBlank())
549+
throw new IllegalArgumentException("Sound preset cannot be blank!");
464550

465551
final TypeReference<HashMap<String, Double>> typeRef = new TypeReference<>() {
466552
};
@@ -518,6 +604,10 @@ private void playPauseAction() {
518604
for (final SoundPane soundPane : getAllSoundPanes()) {
519605
soundPane.playPause();
520606
}
607+
608+
for (final SoundPane soundPane : getSoundPanes(grpCustom)) {
609+
soundPane.playPause();
610+
}
521611
} catch (final MediaPlayerException ex) {
522612
logger.error("Unable to play / pause MediaPlayer", ex);
523613
FxUtils.showErrorAlert(translationBundle.getString("PlayPauseError"), ex.toString(), getClass().getResourceAsStream(SharedVariables.ICON_URL));
@@ -531,6 +621,13 @@ private void playPauseAction() {
531621
private void resetAction() {
532622
logger.info("Resetting all audio sliders");
533623
getAllSoundPanes().forEach(e -> e.getSlider().setValue(0));
624+
625+
getSoundPanes(grpCustom).forEach(SoundPane::disposeMediaPlayer);
626+
grpCustom.getChildren().clear();
627+
628+
pneCustom.setExpanded(false);
629+
pneCustom.setVisible(false);
630+
pneCustom.setManaged(false);
534631
}
535632

536633
/**
@@ -684,6 +781,7 @@ private void clearSearchAction() {
684781
public void fired() {
685782
cancelTimer();
686783
getAllSoundPanes().forEach(SoundPane::pause);
784+
getSoundPanes(grpCustom).forEach(SoundPane::pause);
687785

688786
if (Boolean.parseBoolean(settingsController.getProperties().getProperty("timerComputerShutdown", "false"))) {
689787
final String command = switch (platformName.toLowerCase()) {

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ public String getPropertiesResourceLocation() {
8686
* @param propertiesResourceLocation The resource location of the default properties file
8787
*/
8888
public void setPropertiesResourceLocation(final String propertiesResourceLocation) {
89-
if (propertiesResourceLocation == null || propertiesResourceLocation.isEmpty())
90-
throw new IllegalArgumentException("Properties resource location cannot be null!");
89+
if (propertiesResourceLocation == null)
90+
throw new NullPointerException("Properties resource location cannot be null!");
91+
if (propertiesResourceLocation.isBlank())
92+
throw new IllegalArgumentException("Properties resource location cannot be blank!");
9193

9294
this.propertiesResourceLocation = propertiesResourceLocation;
9395
}
@@ -107,8 +109,10 @@ public String getPropertiesFileLocation() {
107109
* @param propertiesFileLocation The properties file location
108110
*/
109111
public void setPropertiesFileLocation(final String propertiesFileLocation) {
110-
if (propertiesFileLocation == null || propertiesFileLocation.isEmpty())
111-
throw new IllegalArgumentException("Properties file location cannot be null or empty!");
112+
if (propertiesFileLocation == null)
113+
throw new NullPointerException("Properties file location cannot be null!");
114+
if (propertiesFileLocation.isBlank())
115+
throw new IllegalArgumentException("Properties file location cannot be blank!");
112116

113117
this.propertiesFileLocation = propertiesFileLocation;
114118
}

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ public UpdateController(final String updateUrl, final String currentVersion) {
6060
public Optional<PlatformUpdate> checkForUpdates(final String currentPlatform, final boolean isPortable) throws InterruptedException, InvalidHttpResponseCodeException, IOException {
6161
if (currentPlatform == null)
6262
throw new NullPointerException("Current platform cannot be null!");
63-
if (currentPlatform.isEmpty())
64-
throw new IllegalArgumentException("Current platform cannot be empty!");
63+
if (currentPlatform.isBlank())
64+
throw new IllegalArgumentException("Current platform cannot be blank!");
6565

6666
logger.info("Attempting to retrieve the latest PlatformUpdate objects");
6767

@@ -151,12 +151,12 @@ public List<PlatformUpdate> getUpdates() throws IOException, InterruptedExceptio
151151
public void downloadFile(final String url, final String path) throws IOException, URISyntaxException {
152152
if (url == null)
153153
throw new NullPointerException("URL cannot be null!");
154-
if (url.isEmpty())
155-
throw new IllegalArgumentException("URL cannot be empty!");
154+
if (url.isBlank())
155+
throw new IllegalArgumentException("URL cannot be blank!");
156156
if (path == null)
157157
throw new NullPointerException("Path cannot be null!");
158-
if (path.isEmpty())
159-
throw new IllegalArgumentException("Path cannot be empty!");
158+
if (path.isBlank())
159+
throw new IllegalArgumentException("Path cannot be blank!");
160160

161161
logger.info("Attempting to download file from {} and store it at {}", url, path);
162162

@@ -187,8 +187,8 @@ public String getUpdateUrl() {
187187
public void setUpdateUrl(final String updateUrl) {
188188
if (updateUrl == null)
189189
throw new NullPointerException("Update URL cannot be null!");
190-
if (updateUrl.isEmpty())
191-
throw new IllegalArgumentException("Update URL cannot be empty!");
190+
if (updateUrl.isBlank())
191+
throw new IllegalArgumentException("Update URL cannot be blank!");
192192

193193
this.updateUrl = updateUrl;
194194
}
@@ -201,8 +201,8 @@ public void setUpdateUrl(final String updateUrl) {
201201
public void setCurrentVersion(final String currentVersion) {
202202
if (currentVersion == null)
203203
throw new NullPointerException("currentVersion cannot be null!");
204-
if (currentVersion.isEmpty())
205-
throw new IllegalArgumentException("currentVersion cannot be empty!");
204+
if (currentVersion.isBlank())
205+
throw new IllegalArgumentException("currentVersion cannot be blank!");
206206

207207
this.currentVersion = currentVersion;
208208
}

src/main/java/com/codedead/opal/domain/NumberTextField.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ public NumberTextField() {
1616
this.setOnKeyPressed(e -> {
1717
if (e.getCode() == KeyCode.UP) {
1818
int currentValue = 0;
19-
if (!this.getText().isEmpty()) {
19+
if (!this.getText().isBlank()) {
2020
currentValue = Integer.parseInt(this.getText());
2121
}
2222
currentValue++;
2323
this.setText(Integer.toString(currentValue));
2424
} else if (e.getCode() == KeyCode.DOWN) {
2525
int currentValue = 0;
26-
if (!this.getText().isEmpty()) {
26+
if (!this.getText().isBlank()) {
2727
currentValue = Integer.parseInt(this.getText());
2828
}
2929
if (currentValue - 1 >= getMin()) {

0 commit comments

Comments
 (0)