diff --git a/PlayWall/src/main/java/de/tobias/playpad/PlayPadImpl.java b/PlayWall/src/main/java/de/tobias/playpad/PlayPadImpl.java index f3f434f50447c73577d67fdb21460933fcb5ea93..a8590e8ec2ffe39a877e882a444c9b82085d98f3 100644 --- a/PlayWall/src/main/java/de/tobias/playpad/PlayPadImpl.java +++ b/PlayWall/src/main/java/de/tobias/playpad/PlayPadImpl.java @@ -26,6 +26,8 @@ import de.tobias.playpad.viewcontroller.dialog.project.ProjectLoadDialog; import de.tobias.playpad.viewcontroller.dialog.project.ProjectReaderDelegateImpl; import de.tobias.playpad.viewcontroller.main.IMainViewController; import de.tobias.playpad.viewcontroller.main.MainViewController; +import de.tobias.playpad.viewcontroller.option.GlobalSettingsTabViewController; +import de.tobias.playpad.viewcontroller.option.ProfileSettingsTabViewController; import javafx.application.Application; import javafx.application.Platform; import javafx.scene.image.Image; @@ -37,21 +39,24 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; public class PlayPadImpl implements PlayPad { - private Application.Parameters parameters; + private final Application.Parameters parameters; - private List<MainWindowListener> mainViewListeners = new ArrayList<>(); - private List<SettingsListener> settingsListeners = new ArrayList<>(); - private List<PadListener> padListeners = new ArrayList<>(); - private List<GlobalListener> globalListeners = new ArrayList<>(); + private final List<MainWindowListener> mainViewListeners = new ArrayList<>(); + private final List<SettingsListener> settingsListeners = new ArrayList<>(); + private final List<PadListener> padListeners = new ArrayList<>(); + private final List<GlobalListener> globalListeners = new ArrayList<>(); + private final List<Supplier<ProfileSettingsTabViewController>> additionalProfileSettingsTabs = new ArrayList<>(); + private final List<Supplier<GlobalSettingsTabViewController>> additionalGlobalSettingsTabs = new ArrayList<>(); private MainViewController mainViewController; private Image stageIcon; private Project currentProject; - private Module module; + private final Module module; private UpdateService updateService; protected GlobalSettings globalSettings; @@ -242,6 +247,26 @@ public class PlayPadImpl implements PlayPad { return updateService; } + @Override + public void addAdditionalProfileSettingsTab(Supplier<ProfileSettingsTabViewController> tab) { + additionalProfileSettingsTabs.add(tab); + } + + @Override + public List<Supplier<ProfileSettingsTabViewController>> getAdditionalProfileSettingsTabs() { + return additionalProfileSettingsTabs; + } + + @Override + public void addGlobalSettingsTab(Supplier<GlobalSettingsTabViewController> tab) { + additionalGlobalSettingsTabs.add(tab); + } + + @Override + public List<Supplier<GlobalSettingsTabViewController>> getGlobalSettingsTabs() { + return additionalGlobalSettingsTabs; + } + /* Getter / Setter */ diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/global/GlobalSettingsViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/global/GlobalSettingsViewController.java index 068ecda32cf6bd2f68391253facbedee24e5f5d1..e29db503f32fbff22d8f33dcf471b8423c9238af 100644 --- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/global/GlobalSettingsViewController.java +++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/global/GlobalSettingsViewController.java @@ -36,9 +36,8 @@ public class GlobalSettingsViewController extends NVC implements IGlobalSettings @FXML private Button finishButton; - private List<GlobalSettingsTabViewController> tabs = new ArrayList<>(); - - private Runnable onFinish; + private final List<GlobalSettingsTabViewController> tabs = new ArrayList<>(); + private final Runnable onFinish; public GlobalSettingsViewController(Window owner, Runnable onFinish) { load("view/option/global", "GlobalSettingsView", Localization.getBundle()); @@ -53,6 +52,13 @@ public class GlobalSettingsViewController extends NVC implements IGlobalSettings addTab(new KeysTabViewController()); addTab(new UpdateTabViewController()); + PlayPadPlugin.getInstance().getGlobalSettingsTabs().forEach(supplier -> { + final GlobalSettingsTabViewController globalSettingsTabViewController = supplier.get(); + if (globalSettingsTabViewController != null) { + addTab(globalSettingsTabViewController); + } + }); + // Show Current Settings loadTabs(); } diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/profile/ProfileSettingsViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/profile/ProfileSettingsViewController.java index 1c4b3641862810f6d72a8366aad2936365556fc1..4f0ab95348e67855818b1aaf81a63b5a9010a4e7 100644 --- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/profile/ProfileSettingsViewController.java +++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/profile/ProfileSettingsViewController.java @@ -40,15 +40,15 @@ public class ProfileSettingsViewController extends NVC implements IProfileSettin @FXML private Button finishButton; - private List<ProfileSettingsTabViewController> tabs = new ArrayList<>(); + private final List<ProfileSettingsTabViewController> tabs = new ArrayList<>(); - private Runnable onFinish; + private final Runnable onFinish; public ProfileSettingsViewController(Window owner, Project project, Runnable onFinish) { load("view/option/profile", "SettingsView", Localization.getBundle()); this.onFinish = onFinish; - boolean activePlayer = project.hasActivePlayers(); + boolean hasActivePlayers = project.hasActivePlayers(); addTab(new MappingTabViewController()); addTab(new DesignTabViewController()); @@ -58,12 +58,19 @@ public class ProfileSettingsViewController extends NVC implements IProfileSettin PadContentRegistry padContents = PlayPadPlugin.getRegistries().getPadContents(); for (String type : padContents.getTypes()) { PadContentFactory component = padContents.getFactory(type); - ProfileSettingsTabViewController controller = component.getSettingsTabViewController(activePlayer); + ProfileSettingsTabViewController controller = component.getSettingsTabViewController(hasActivePlayers); if (controller != null) { addTab(controller); } } + PlayPadPlugin.getInstance().getAdditionalProfileSettingsTabs().forEach(supplier -> { + ProfileSettingsTabViewController controller = supplier.get(); + if (controller != null) { + addTab(controller); + } + }); + NVCStage nvcStage = applyViewControllerToStage(); nvcStage.initOwner(owner); nvcStage.addCloseHook(this::onFinish); diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/PlayPad.java b/PlayWallCore/src/main/java/de/tobias/playpad/PlayPad.java index 14d50ffae9ec046ee3cdb1b70fa00542ec112b81..c480828c5d48c0712eab670dbd4a3d2ed05ede89 100644 --- a/PlayWallCore/src/main/java/de/tobias/playpad/PlayPad.java +++ b/PlayWallCore/src/main/java/de/tobias/playpad/PlayPad.java @@ -14,12 +14,15 @@ import de.tobias.playpad.project.ProjectReader.ProjectReaderDelegate.ProfileAbor import de.tobias.playpad.project.ref.ProjectReference; import de.tobias.playpad.settings.GlobalSettings; import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.playpad.viewcontroller.option.GlobalSettingsTabViewController; +import de.tobias.playpad.viewcontroller.option.ProfileSettingsTabViewController; import javafx.scene.image.Image; import org.dom4j.DocumentException; import java.io.IOException; import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; /** * Hauptfunktionen für Listener und zur Programmsteuerung für Plugins. @@ -138,4 +141,15 @@ public interface PlayPad { UpdateService getUpdateService(); + /* + Settings Views + */ + + void addAdditionalProfileSettingsTab(Supplier<ProfileSettingsTabViewController> tab); + + List<Supplier<ProfileSettingsTabViewController>> getAdditionalProfileSettingsTabs(); + + void addGlobalSettingsTab(Supplier<GlobalSettingsTabViewController> tab); + + List<Supplier<GlobalSettingsTabViewController>> getGlobalSettingsTabs(); } diff --git a/PlayWallPlugins/PlayWallPluginWebAPI/src/main/java/de/tobias/playpad/plugin/api/websocket/settings/WebApiSettings.java b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/java/de/tobias/playpad/plugin/api/websocket/settings/WebApiSettings.java new file mode 100644 index 0000000000000000000000000000000000000000..c5b35f5f180fa76bf0c1f9681e96c9b03f30f4c5 --- /dev/null +++ b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/java/de/tobias/playpad/plugin/api/websocket/settings/WebApiSettings.java @@ -0,0 +1,28 @@ +package de.tobias.playpad.plugin.api.websocket.settings; + +import de.thecodelabs.storage.settings.annotation.FilePath; +import de.thecodelabs.storage.settings.annotation.Key; + +@FilePath("webapi.json") +public class WebApiSettings { + @Key + private boolean enabled = false; + @Key + private int port = 9876; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } +} diff --git a/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/lang/base.properties b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/lang/base.properties new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/lang/base_de.properties b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/lang/base_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..e38784c885abf44da7f1bab609096701f6b09e09 --- /dev/null +++ b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/lang/base_de.properties @@ -0,0 +1,5 @@ +webapi.settings=WebAPI +webapi.settings.enable=WebAPI aktiv +webapi.settings.enabled=Aktiv +webapi.settings.port=Port +webapi.settings.restart=\u00C4nderungen an den Einstellungen werden erst mit einem Neustart von PlayWall wirksam. \ No newline at end of file diff --git a/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/view/WebApiSettings.fxml b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/view/WebApiSettings.fxml new file mode 100644 index 0000000000000000000000000000000000000000..473dba8d1a6441e62fed11fa04b87a6be18397b3 --- /dev/null +++ b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/resources/plugin/webapi/view/WebApiSettings.fxml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import de.thecodelabs.utils.ui.scene.input.NumberTextField?> +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.CheckBox?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.VBox?> +<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="14.0" + xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%webapi.settings.enable"/> + <CheckBox fx:id="activeCheckbox" mnemonicParsing="false" text="%webapi.settings.enabled"/> + </children> + </HBox> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%webapi.settings.port"/> + <NumberTextField fx:id="portTextField"/> + </children> + </HBox> + <Label text="%webapi.settings.restart"> + <padding> + <Insets left="164.0"/> + </padding> + </Label> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0"/> + </padding> +</VBox> diff --git a/PlayWallPlugins/PlayWallPluginWebAPI/src/main/scala/de/tobias/playpad/plugin/api/WebApiPlugin.scala b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/scala/de/tobias/playpad/plugin/api/WebApiPlugin.scala index b48693f977353202c063d4d00dc9b3ae5d21d915..0d4d7321ee3a880471919572daaea62d1da8517d 100644 --- a/PlayWallPlugins/PlayWallPluginWebAPI/src/main/scala/de/tobias/playpad/plugin/api/WebApiPlugin.scala +++ b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/scala/de/tobias/playpad/plugin/api/WebApiPlugin.scala @@ -1,18 +1,27 @@ package de.tobias.playpad.plugin.api +import java.nio.file.{Files, Path} + import de.thecodelabs.logger.Logger import de.thecodelabs.plugins.PluginDescriptor import de.thecodelabs.plugins.versionizer.PluginArtifact +import de.thecodelabs.storage.settings.{Storage, StorageTypes} +import de.thecodelabs.utils.application.ApplicationUtils +import de.thecodelabs.utils.application.container.PathType +import de.thecodelabs.utils.util.Localization import de.tobias.playpad.PlayPadPlugin import de.tobias.playpad.plugin.api.websocket.WebSocketHandler import de.tobias.playpad.plugin.api.websocket.listener.{PadStatusListener, ProjectListener} +import de.tobias.playpad.plugin.api.websocket.settings.{WebApiSettings, WebApiSettingsViewController} import de.tobias.playpad.plugin.{Module, PlayPadPluginStub} -import spark.Spark +import spark.{Request, Response, Spark} class WebApiPlugin extends PlayPadPluginStub with PluginArtifact { private var module: Module = _ + private var webApiSettings: WebApiSettings = _ + override def startup(descriptor: PluginDescriptor): Unit = { module = new Module(descriptor.getName, descriptor.getArtifactId) @@ -21,16 +30,34 @@ class WebApiPlugin extends PlayPadPluginStub with PluginArtifact { Logger.debug("Enable Web API Plugin") - Spark.port(9876) - Spark.webSocket("/api", WebSocketHandler.instance) - Spark.get("/", (_, _) => "PlayWall API") + val settingsPath = WebApiPlugin.getWebApiSettingsPath + if (Files.exists(settingsPath)) { + webApiSettings = Storage.load(StorageTypes.JSON, classOf[WebApiSettings]) + } + if (webApiSettings == null) { + webApiSettings = new WebApiSettings + } + + if (webApiSettings.isEnabled) { + Spark.port(webApiSettings.getPort) + Spark.webSocket("/api", WebSocketHandler.instance) + Spark.get("/", (_: Request, _: Response) => "PlayWall API") + Logger.info(f"Start WebAPI on port ${webApiSettings.getPort}") + } + + PlayPadPlugin.getInstance().addGlobalSettingsTab(() => new WebApiSettingsViewController(webApiSettings)) + Localization.addResourceBundle("plugin/webapi/lang/base", getClass.getClassLoader) } override def shutdown(): Unit = { - Logger.debug("Disable Web API Plugin") - Spark.stop() + Logger.debug("Disable Web API Plugin") } override def getModule: Module = module + } + +object WebApiPlugin { + def getWebApiSettingsPath: Path = ApplicationUtils.getApplication.getPath(PathType.CONFIGURATION, "webapi.json") +} \ No newline at end of file diff --git a/PlayWallPlugins/PlayWallPluginWebAPI/src/main/scala/de/tobias/playpad/plugin/api/websocket/settings/WebApiSettingsViewController.scala b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/scala/de/tobias/playpad/plugin/api/websocket/settings/WebApiSettingsViewController.scala new file mode 100644 index 0000000000000000000000000000000000000000..4f86d86df6e85433d7bd38a2dfb21fcb99361fdd --- /dev/null +++ b/PlayWallPlugins/PlayWallPluginWebAPI/src/main/scala/de/tobias/playpad/plugin/api/websocket/settings/WebApiSettingsViewController.scala @@ -0,0 +1,81 @@ +package de.tobias.playpad.plugin.api.websocket.settings + +import java.nio.file.Files + +import de.thecodelabs.logger.Logger +import de.thecodelabs.storage.settings.{Storage, StorageTypes} +import de.thecodelabs.utils.ui.scene.input.NumberTextField +import de.thecodelabs.utils.util.Localization +import de.tobias.playpad.plugin.api.WebApiPlugin +import de.tobias.playpad.settings.GlobalSettings +import de.tobias.playpad.viewcontroller.option.GlobalSettingsTabViewController +import javafx.fxml.FXML +import javafx.scene.control.CheckBox + +class WebApiSettingsViewController(val webApiSettings: WebApiSettings) extends GlobalSettingsTabViewController { + + load("plugin/webapi/view", "WebApiSettings", Localization.getBundle) + + @FXML + var activeCheckbox: CheckBox = _ + + @FXML + var portTextField: NumberTextField = _ + + /** + * Lädt alle Einstellungen vom Model in die GUI. + * + * @param settings Aktuelles GlobalSettings + */ + override def loadSettings(settings: GlobalSettings): Unit = { + activeCheckbox.setSelected(webApiSettings.isEnabled) + portTextField.setText(webApiSettings.getPort.toString) + } + + /** + * Speichert alle Änderungen in das Model. + * + * @param settings Aktuelles GlobalSettings + */ + override def saveSettings(settings: GlobalSettings): Unit = { + webApiSettings.setEnabled(activeCheckbox.isSelected) + webApiSettings.setPort(portTextField.getText.toInt) + + saveToFile() + } + + /** + * Gibt <code>true</code> zurück, wenn im Hauptprogramm etwas neu geladen werden muss. + * + * @return <code>true</code> Benötigt Reload + */ + override def needReload(): Boolean = { + false + } + + /** + * Prüft ob die eingetragen Einstellungen erlaubt sind. Bei falschen Eingaben können die Einstellungen nicht + * geschlossen werden. + * + * @return <code>true</code> Einstellungen erlaubt. <code>false</code> Einstellungen fehlerhaft. + */ + override def validSettings(): Boolean = { + true + } + + /** + * Gibt den Namen für den Tab zurück. + * + * @return Display Name des Tabs. + */ + override def name(): String = Localization.getString("webapi.settings") + + private def saveToFile(): Unit = { + val settingsPath = WebApiPlugin.getWebApiSettingsPath + if (Files.notExists(settingsPath)) { + Files.createDirectories(settingsPath.getParent) + } + Storage.save(StorageTypes.JSON, webApiSettings) + Logger.info(f"Save WebAPI settings to $settingsPath") + } +}