From: Debayan Sutradhar Date: Fri, 11 Jun 2021 14:09:38 +0530 Subject: 1. Added sound on click --- 1. Added sound on click 2. Refactored Config 3. Lots of other work --- --- 'a/src/main/java/com/stream_pi/server/controller/Controller.java' +++ b/src/main/java/com/stream_pi/server/controller/Controller.java @@ -38,6 +38,7 @@ import javafx.concurrent.Task; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.image.Image; +import javafx.scene.media.AudioClip; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.WindowEvent; @@ -48,6 +49,7 @@ import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; +import java.io.File; import java.net.SocketAddress; import java.util.Objects; import java.util.Random; @@ -129,7 +131,7 @@ public class Controller extends Base imp { if(getConfig().isAllowDonatePopup()) { - if(new Random().nextInt(5) == 3) + if(new Random().nextInt(50) == 3) new DonatePopupContent(getHostServices(), this).show(); } @@ -157,6 +159,8 @@ public class Controller extends Base imp handleMinorException(e); } + StreamPiAlert.setIsShowPopup(getConfig().isShowAlertsPopup()); + executor.execute(new Task() { @Override protected Void call() @@ -281,7 +285,6 @@ public class Controller extends Base imp } stopServerAndAllConnections(); - executor.shutdown(); ExternalPlugins.getInstance().shutDownActions(); closeLogger(); Config.nullify(); @@ -289,6 +292,7 @@ public class Controller extends Base imp public void exit() { + executor.shutdown(); Platform.exit(); } @@ -382,10 +386,11 @@ public class Controller extends Base imp } @Override - public void handleSevereException(SevereException e) { + public void handleSevereException(SevereException e) + { getLogger().log(Level.SEVERE, e.getShortMessage(), e); e.printStackTrace(); - + Platform.runLater(()->{ StreamPiAlert alert = new StreamPiAlert(e.getTitle(), e.getShortMessage(), StreamPiAlertType.ERROR); @@ -403,6 +408,37 @@ public class Controller extends Base imp }); } + private AudioClip audioClip = null; + private String audioFilePath = null; + private void playSound() + { + if(audioClip == null) + { + updateSound(); + } + else + { + if(audioClip.isPlaying()) + { + Platform.runLater(audioClip::stop); + return; + } + } + + if(!audioFilePath.equals(getConfig().getSoundOnActionClickedFilePath())) + { + updateSound(); + } + + Platform.runLater(audioClip::play); + } + + private void updateSound() + { + audioFilePath = getConfig().getSoundOnActionClickedFilePath(); + audioClip = new AudioClip(new File(audioFilePath).toURI().toString()); + } + @Override public void onActionClicked(Client client, String profileID, String actionID, boolean toggle) { @@ -410,46 +446,47 @@ public class Controller extends Base imp { Action action = client.getProfileByID(profileID).getActionByID(actionID); - if(action.getActionType() == ActionType.NORMAL || action.getActionType() == ActionType.TOGGLE) + if(getConfig().getSoundOnActionClickedStatus()) { - if(action.isInvalid()) - { - throw new MinorException( - "The action isn't installed on the server." - ); - } - else + playSound(); + } + + if(action.isInvalid()) + { + throw new MinorException( + "The action isn't installed on the server." + ); + } + + executor.execute(new Task() { + @Override + protected Void call() { - executor.execute(new Task() { - @Override - protected Void call() - { - try { - Thread.sleep(action.getDelayBeforeExecuting()); + try + { + Thread.sleep(action.getDelayBeforeExecuting()); - getLogger().info("action "+action.getID()+" clicked!"); + getLogger().info("action "+action.getID()+" clicked!"); - if(action instanceof ToggleAction) - { - onToggleActionClicked((ToggleAction) action, toggle, profileID, - client.getRemoteSocketAddress()); - } - else if (action instanceof NormalAction) - { - onNormalActionClicked((NormalAction) action, profileID, - client.getRemoteSocketAddress()); - } - } - catch (InterruptedException e) - { - e.printStackTrace(); - getLogger().info("onActionClicked scheduled task was interrupted ..."); - } - return null; + if(action instanceof ToggleAction) + { + onToggleActionClicked((ToggleAction) action, toggle, profileID, + client.getRemoteSocketAddress()); + } + else if (action instanceof NormalAction) + { + onNormalActionClicked((NormalAction) action, profileID, + client.getRemoteSocketAddress()); } - }); + } + catch (InterruptedException e) + { + e.printStackTrace(); + getLogger().info("onActionClicked scheduled task was interrupted ..."); + } + return null; } - } + }); } catch (Exception e) { --- 'a/src/main/java/com/stream_pi/server/io/Config.java' +++ b/src/main/java/com/stream_pi/server/io/Config.java @@ -31,6 +31,7 @@ import com.stream_pi.util.iohelper.IOHel import com.stream_pi.util.xmlconfighelper.XMLConfigHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.Node; public class Config { @@ -197,20 +198,20 @@ public class Config public String getCurrentThemeFullName() { - return XMLConfigHelper.getStringProperty((Element) document, "current-theme-full-name", + return XMLConfigHelper.getStringProperty(document, "current-theme-full-name", getDefaultCurrentThemeFullName(), false, true, document, configFile); } public String getThemesPath() { - return XMLConfigHelper.getStringProperty((Element) document, "themes-path", + return XMLConfigHelper.getStringProperty(document, "themes-path", getDefaultThemesPath(), false, true, document, configFile); } public String getPluginsPath() { - return XMLConfigHelper.getStringProperty((Element) document, "plugins-path", + return XMLConfigHelper.getStringProperty(document, "plugins-path", getDefaultPluginsPath(), false, true, document, configFile); } --- 'a/src/main/java/com/stream_pi/server/window/dashboard/DonatePopupContent.java' +++ b/src/main/java/com/stream_pi/server/window/dashboard/DonatePopupContent.java @@ -19,7 +19,8 @@ public class DonatePopupContent{ Label label = new Label("We are a very small team working very hard on this project for best user experience.\n\n" + "Something like Stream-Pi takes time, effort and resources. But we will always keep this 100% opensource and free.\n\n" + "If you find this project helpful, and would want to help us, please consider donating :)\n\n"+ - "If you are unable to do so even a small shout-out and share across social media would be very helpful."); + "If you are unable to do so even a small shout-out and share across social media would be very helpful.\n\n" + + "This is also the first and the last time this dialogue will be shown :D"); label.setWrapText(true); label.getStyleClass().add("donate_request_popup_label"); --- 'a/src/main/java/com/stream_pi/server/window/dashboard/actiondetailpane/ActionDetailsPane.java' +++ b/src/main/java/com/stream_pi/server/window/dashboard/actiondetailpane/ActionDetailsPane.java @@ -331,7 +331,8 @@ public class ActionDetailsPane extends V HBox clearIconHBox = new HBox(clearIconButton); clearIconHBox.setAlignment(Pos.CENTER_RIGHT); - displayTextFieldHBox = new HBoxInputBox("Display Name", displayNameTextField, hideDisplayTextCheckBox); + HBox.setMargin(hideDisplayTextCheckBox, new Insets(0, 0, 0, 45)); + displayTextFieldHBox = new HBox(new HBoxInputBox("Display Name", displayNameTextField), hideDisplayTextCheckBox); HBox alignmentHBox = new HBox(new Label("Alignment"), SpaceFiller.horizontal(), @@ -354,6 +355,7 @@ public class ActionDetailsPane extends V new HBoxInputBoxWithFileChooser("Icon", defaultIconFileTextField, hideDefaultIconCheckBox, iconExtensions) ); + normalActionsPropsVBox.managedProperty().bind(normalActionsPropsVBox.visibleProperty()); normalActionsPropsVBox.setSpacing(10.0); --- 'a/src/main/java/com/stream_pi/server/window/settings/GeneralSettings.java' +++ b/src/main/java/com/stream_pi/server/window/settings/GeneralSettings.java @@ -1,5 +1,6 @@ package com.stream_pi.server.window.settings; +import com.stream_pi.action_api.actionproperty.property.FileExtensionFilter; import com.stream_pi.server.controller.ServerListener; import com.stream_pi.server.info.StartupFlags; import com.stream_pi.server.io.Config; @@ -15,6 +16,9 @@ import com.stream_pi.util.exception.Mino import com.stream_pi.util.exception.SevereException; import com.stream_pi.util.platform.PlatformType; import com.stream_pi.util.startatboot.StartAtBoot; +import com.stream_pi.util.uihelper.HBoxInputBox; +import com.stream_pi.util.uihelper.HBoxInputBoxWithDirectoryChooser; +import com.stream_pi.util.uihelper.HBoxInputBoxWithFileChooser; import com.stream_pi.util.uihelper.HBoxWithSpaceBetween; import javafx.application.HostServices; import javafx.application.Platform; @@ -27,8 +31,10 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.*; import javafx.stage.DirectoryChooser; +import javafx.stage.FileChooser; import org.controlsfx.control.ToggleSwitch; import org.kordamp.ikonli.javafx.FontIcon; +import org.w3c.dom.Text; import java.awt.SystemTray; import java.io.File; @@ -44,6 +50,9 @@ public class GeneralSettings extends VBo private final TextField actionGridPaneActionBoxGap; private final ToggleSwitch startOnBootToggleSwitch; private final HBoxWithSpaceBetween startOnBootHBox; + private final TextField soundOnActionClickedFilePathTextField; + private final ToggleSwitch soundOnActionClickedToggleSwitch; + private final HBoxWithSpaceBetween soundOnActionClickedToggleSwitchHBox; private final ToggleSwitch minimizeToSystemTrayOnCloseToggleSwitch; private final HBoxWithSpaceBetween minimizeToSystemTrayOnCloseHBox; private final ToggleSwitch showAlertsPopupToggleSwitch; @@ -52,7 +61,6 @@ public class GeneralSettings extends VBo private final Button checkForUpdatesButton; private final Button factoryResetButton; - private Logger logger; private ExceptionAndAlertHandler exceptionAndAlertHandler; @@ -86,6 +94,20 @@ public class GeneralSettings extends VBo startOnBootHBox = new HBoxWithSpaceBetween("Start on Boot", startOnBootToggleSwitch); startOnBootHBox.managedProperty().bind(startOnBootHBox.visibleProperty()); + soundOnActionClickedToggleSwitch = new ToggleSwitch(); + soundOnActionClickedToggleSwitchHBox = new HBoxWithSpaceBetween("Sound on Action Clicked", soundOnActionClickedToggleSwitch); + + + soundOnActionClickedFilePathTextField = new TextField(); + + HBoxInputBoxWithFileChooser soundHBoxInputBoxWithFileChooser = new HBoxInputBoxWithFileChooser("Sound File Path", soundOnActionClickedFilePathTextField, + new FileChooser.ExtensionFilter("Sounds","*.mp3","*.mp4", "*.m4a", "*.m4v","*.wav","*.aif", "*.aiff","*.fxm","*.flv","*.m3u8")); + + soundHBoxInputBoxWithFileChooser.setUseLast(false); + soundHBoxInputBoxWithFileChooser.setRememberThis(false); + + soundHBoxInputBoxWithFileChooser.getFileChooseButton().disableProperty().bind(soundOnActionClickedToggleSwitch.selectedProperty().not()); + minimizeToSystemTrayOnCloseToggleSwitch = new ToggleSwitch(); minimizeToSystemTrayOnCloseHBox = new HBoxWithSpaceBetween("Minimise To Tray On Close", minimizeToSystemTrayOnCloseToggleSwitch); @@ -105,12 +127,14 @@ public class GeneralSettings extends VBo setSpacing(5); getChildren().addAll( - getUIInputBox("Server Name", serverNameTextField), - getUIInputBox("Port", portTextField), - getUIInputBox("Grid Pane - Box Size", actionGridPaneActionBoxSize), - getUIInputBox("Grid Pane - Box Gap", actionGridPaneActionBoxGap), - getUIInputBoxWithDirectoryChooser("Plugins Path", pluginsPathTextField), - getUIInputBoxWithDirectoryChooser("Themes Path", themesPathTextField), + new HBoxInputBox("Server Name", serverNameTextField), + new HBoxInputBox("Port", portTextField), + new HBoxInputBox("Grid Pane - Box Size", actionGridPaneActionBoxSize), + new HBoxInputBox("Grid Pane - Box Gap", actionGridPaneActionBoxGap), + new HBoxInputBoxWithDirectoryChooser("Plugins Path", pluginsPathTextField), + new HBoxInputBoxWithDirectoryChooser("Themes Path", themesPathTextField), + soundHBoxInputBoxWithFileChooser, + soundOnActionClickedToggleSwitchHBox, minimizeToSystemTrayOnCloseHBox, startOnBootHBox, showAlertsPopupHBox @@ -139,55 +163,6 @@ public class GeneralSettings extends VBo }); } - private HBox getUIInputBoxWithDirectoryChooser(String labelText, TextField textField) - { - HBox hBox = getUIInputBox(labelText, textField); - hBox.setSpacing(5.0); - - TextField tf = (TextField) hBox.getChildren().get(2); - tf.setPrefWidth(300); - tf.setDisable(true); - - - Button button = new Button(); - FontIcon fontIcon = new FontIcon("far-folder"); - button.setGraphic(fontIcon); - - button.setOnAction(event -> { - DirectoryChooser directoryChooser = new DirectoryChooser(); - - - try { - File selectedDirectory = directoryChooser.showDialog(getScene().getWindow()); - - textField.setText(selectedDirectory.getAbsolutePath()); - } - catch (NullPointerException e) - { - logger.info("No folder selected"); - } - }); - - hBox.getChildren().add(button); - - - return hBox; - } - - private HBox getUIInputBox(String labelText, TextField textField) - { - textField.setPrefWidth(100); - - Label label = new Label(labelText); - Region region = new Region(); - HBox.setHgrow(region, Priority.ALWAYS); - - - return new HBox(label, region, textField); - } - - - public void loadDataFromConfig() throws SevereException { Config config = Config.getInstance(); @@ -203,6 +178,9 @@ public class GeneralSettings extends VBo minimizeToSystemTrayOnCloseToggleSwitch.setSelected(config.getMinimiseToSystemTrayOnClose()); showAlertsPopupToggleSwitch.setSelected(config.isShowAlertsPopup()); startOnBootToggleSwitch.setSelected(config.getStartOnBoot()); + + soundOnActionClickedToggleSwitch.setSelected(config.getSoundOnActionClickedStatus()); + soundOnActionClickedFilePathTextField.setText(config.getSoundOnActionClickedFilePath()); }); } @@ -232,6 +210,10 @@ public class GeneralSettings extends VBo boolean showAlertsPopup = showAlertsPopupToggleSwitch.isSelected(); boolean startOnBoot = startOnBootToggleSwitch.isSelected(); + boolean soundOnActionClicked = soundOnActionClickedToggleSwitch.isSelected(); + + String soundOnActionClickedFilePath = soundOnActionClickedFilePathTextField.getText(); + Config config = Config.getInstance(); StringBuilder errors = new StringBuilder(); @@ -362,6 +344,32 @@ public class GeneralSettings extends VBo } } + if(soundOnActionClicked) + { + if(soundOnActionClickedFilePath.isBlank()) + { + StreamPiAlert alert = new StreamPiAlert("No sound file specified", + "Sound File cannot be empty", StreamPiAlertType.ERROR); + alert.show(); + + soundOnActionClicked = false; + } + else + { + File soundFile = new File(soundOnActionClickedFilePath); + if(!soundFile.exists() || !soundFile.isFile()) + { + + StreamPiAlert alert = new StreamPiAlert("File not found", + "No sound file at \n"+soundOnActionClickedFilePath+"\n" + + "Unable to set sound on action clicked.", StreamPiAlertType.ERROR); + alert.show(); + + soundOnActionClicked = false; + } + } + } + config.setServerName(serverNameStr); config.setServerPort(serverPort); config.setActionGridGap(actionGap); @@ -374,6 +382,9 @@ public class GeneralSettings extends VBo config.setShowAlertsPopup(showAlertsPopup); config.setStartupOnBoot(startOnBoot); + config.setSoundOnActionClickedStatus(soundOnActionClicked); + config.setSoundOnActionClickedFilePath(soundOnActionClickedFilePath); + config.save();