diff --git a/README.md b/README.md index 3d368171..ee279aa8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- +

diff --git a/doc/owlplug-logo.png b/doc/owlplug-logo.png deleted file mode 100644 index dfcf7d4b..00000000 Binary files a/doc/owlplug-logo.png and /dev/null differ diff --git a/doc/owlplug-title-bg.png b/doc/owlplug-title-bg.png new file mode 100644 index 00000000..cfa0e23d Binary files /dev/null and b/doc/owlplug-title-bg.png differ diff --git a/owlplug-client/pom.xml b/owlplug-client/pom.xml index 9b40f62d..0f560b4a 100644 --- a/owlplug-client/pom.xml +++ b/owlplug-client/pom.xml @@ -38,6 +38,11 @@ owlplug-host 1.33.1 + + com.owlplug + owlplug-theme + 1.33.1 + com.owlplug owlplug-controls @@ -124,7 +129,7 @@ io.github.mkpaz atlantafx-base - 2.1.0 + ${atlantafx.version} org.kordamp.ikonli diff --git a/owlplug-client/src/main/java/com/owlplug/OwlPlug.java b/owlplug-client/src/main/java/com/owlplug/OwlPlug.java index 0dbe55a7..fd3a8016 100644 --- a/owlplug-client/src/main/java/com/owlplug/OwlPlug.java +++ b/owlplug-client/src/main/java/com/owlplug/OwlPlug.java @@ -18,7 +18,7 @@ package com.owlplug; -import atlantafx.base.theme.PrimerDark; +import com.owlplug.theme.OwlPlugDarkTheme; import com.owlplug.controls.OwlPlugControlsResources; import com.owlplug.core.components.ApplicationDefaults; import com.owlplug.core.controllers.MainController; @@ -120,7 +120,7 @@ public void start(Stage primaryStage) throws Exception { double width = 1050; double height = 800; - Application.setUserAgentStylesheet(new PrimerDark().getUserAgentStylesheet()); + Application.setUserAgentStylesheet(new OwlPlugDarkTheme().getUserAgentStylesheet()); Scene scene = new Scene(rootNode, width, height); diff --git a/owlplug-client/src/main/java/com/owlplug/OwlPlugPreloader.java b/owlplug-client/src/main/java/com/owlplug/OwlPlugPreloader.java index 5111db2c..7db2ff12 100644 --- a/owlplug-client/src/main/java/com/owlplug/OwlPlugPreloader.java +++ b/owlplug-client/src/main/java/com/owlplug/OwlPlugPreloader.java @@ -18,7 +18,7 @@ package com.owlplug; -import atlantafx.base.theme.PrimerDark; +import com.owlplug.theme.OwlPlugDarkTheme; import com.owlplug.core.components.ApplicationDefaults; import javafx.application.Application; import javafx.application.Preloader; @@ -42,7 +42,7 @@ public void start(Stage primaryStage) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Preloader.fxml")); Parent root = loader.load(); - Application.setUserAgentStylesheet(new PrimerDark().getUserAgentStylesheet()); + Application.setUserAgentStylesheet(new OwlPlugDarkTheme().getUserAgentStylesheet()); Scene scene = new Scene(root); String owlplugCss = OwlPlugPreloader.class.getResource("/owlplug.css").toExternalForm(); diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/MainController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/MainController.java index 4a2de393..07d4dd3a 100644 --- a/owlplug-client/src/main/java/com/owlplug/core/controllers/MainController.java +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/MainController.java @@ -111,6 +111,9 @@ public class MainController extends BaseController { private Button downloadUpdateButton; public static int PLUGINS_TAB_INDEX = 1; + public static int EXPLORE_TAB_INDEX = 2; + public static int PROJECTS_TAB_INDEX = 3; + public static int OPTIONS_TAB_INDEX = 4; /** * FXML initialize method. @@ -204,7 +207,7 @@ public void dispatchPostInitialize() { } - public void selectMainTab(int index) { + public void navigateToMainTab(int index) { this.tabPaneHeader.getSelectionModel().select(index); } diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/OptionsController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/OptionsController.java index f25a963b..27578e7a 100644 --- a/owlplug-client/src/main/java/com/owlplug/core/controllers/OptionsController.java +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/OptionsController.java @@ -18,321 +18,135 @@ package com.owlplug.core.controllers; -import com.owlplug.controls.Dialog; -import com.owlplug.controls.DialogLayout; import com.owlplug.core.components.ApplicationDefaults; -import com.owlplug.core.controllers.dialogs.DonateDialogController; -import com.owlplug.core.controllers.fragments.PluginPathFragmentController; +import com.owlplug.core.controllers.options.ApplicationOptionsController; +import com.owlplug.core.controllers.options.InstallationOptionsController; +import com.owlplug.core.controllers.options.PluginScanOptionsController; +import com.owlplug.core.controllers.options.ProjectsOptionsController; import com.owlplug.core.events.PreferencesChangedEvent; -import com.owlplug.core.model.OperatingSystem; -import com.owlplug.core.services.OptionsService; import com.owlplug.core.ui.SlidingLabel; import com.owlplug.core.utils.FX; -import com.owlplug.core.utils.PlatformUtils; -import com.owlplug.host.loaders.NativePluginLoader; -import com.owlplug.core.controllers.dialogs.ListDirectoryDialogController; -import com.owlplug.plugin.services.NativeHostService; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.CheckBox; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Hyperlink; +import javafx.geometry.Pos; +import javafx.scene.Node; import javafx.scene.control.Label; -import javafx.scene.control.TextField; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.TextFlow; -import org.springframework.beans.factory.annotation.Autowired; +import org.kordamp.ikonli.javafx.FontIcon; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Controller; @Controller public class OptionsController extends BaseController { - @Autowired - private OptionsService optionsService; - @Autowired - private NativeHostService nativeHostService; - @Autowired - private ListDirectoryDialogController listDirectoryDialogController; - @Autowired - private DonateDialogController donateDialogController; @FXML - private CheckBox pluginNativeCheckbox; + private VBox navContainer; @FXML - private ComboBox pluginNativeComboBox; - @FXML - private TextField loaderTimeoutTextField; - @FXML - private CheckBox syncPluginsCheckBox; - @FXML - private CheckBox syncFileStatCheckbox; - @FXML - private Button removeDataButton; + private StackPane contentArea; @FXML private Label versionLabel; - - @FXML - private Button clearCacheButton; - @FXML - private CheckBox storeSubDirectoryCheckBox; - @FXML - private CheckBox storeByCreatorCheckBox; - @FXML - private Label storeByCreatorLabel; @FXML - private Label storeSubDirectoryLabel; - @FXML - private Label warningSubDirectory; - @FXML - private CheckBox storeDirectoryCheckBox; + private TextFlow contributorsFlow; + + // Section root nodes injected via fx:include fx:id convention @FXML - private TextField storeDirectoryTextField; + private ScrollPane pluginScanOptions; @FXML - private Label storeDirectorySeparator; + private ScrollPane installationOptions; @FXML - private Hyperlink owlplugWebsiteLink; + private ScrollPane projectsOptions; @FXML - private VBox pluginPathContainer; + private ScrollPane applicationOptions; + // Section controllers injected via {fx:id}Controller convention @FXML - private CheckBox telemetryCheckBox; - @FXML - private Hyperlink telemetryHyperlink; + private PluginScanOptionsController pluginScanOptionsController; @FXML - private Button moreFeaturesButton; + private InstallationOptionsController installationOptionsController; @FXML - private Button openLogsButton; + private ProjectsOptionsController projectsOptionsController; @FXML - private TextFlow versionTextFlow; + private ApplicationOptionsController applicationOptionsController; - private PluginPathFragmentController vst2PluginPathFragment; - private PluginPathFragmentController vst3PluginPathFragment; - private PluginPathFragmentController auPluginPathFragment; - private PluginPathFragmentController lv2PluginPathFragment; + private final ToggleGroup navToggleGroup = new ToggleGroup(); + + public static int SCAN_SECTION_INDEX = 0; + public static int INSTALLATION_SECTION_INDEX = 1; + public static int PROJECTS_SECTION_INDEX = 2; + public static int APPLICATION_SECTION_INDEX = 3; - /** - * FXML initialize method. - */ @FXML public void initialize() { - - vst2PluginPathFragment = new PluginPathFragmentController("VST2", - ApplicationDefaults.VST2_DISCOVERY_ENABLED_KEY, - ApplicationDefaults.VST_DIRECTORY_KEY, - ApplicationDefaults.VST2_EXTRA_DIRECTORY_KEY, - this.getPreferences(), - this.listDirectoryDialogController); - - vst3PluginPathFragment = new PluginPathFragmentController("VST3", - ApplicationDefaults.VST3_DISCOVERY_ENABLED_KEY, - ApplicationDefaults.VST3_DIRECTORY_KEY, - ApplicationDefaults.VST3_EXTRA_DIRECTORY_KEY, - this.getPreferences(), - this.listDirectoryDialogController); - - auPluginPathFragment = new PluginPathFragmentController("AU", - ApplicationDefaults.AU_DISCOVERY_ENABLED_KEY, - ApplicationDefaults.AU_DIRECTORY_KEY, - ApplicationDefaults.AU_EXTRA_DIRECTORY_KEY, - this.getPreferences(), - this.listDirectoryDialogController); - - lv2PluginPathFragment = new PluginPathFragmentController("LV2", - ApplicationDefaults.LV2_DISCOVERY_ENABLED_KEY, - ApplicationDefaults.LV2_DIRECTORY_KEY, - ApplicationDefaults.LV2_EXTRA_DIRECTORY_KEY, - this.getPreferences(), - this.listDirectoryDialogController); - - pluginPathContainer.getChildren().add(vst2PluginPathFragment.getNode()); - pluginPathContainer.getChildren().add(vst3PluginPathFragment.getNode()); - pluginPathContainer.getChildren().add(auPluginPathFragment.getNode()); - pluginPathContainer.getChildren().add(lv2PluginPathFragment.getNode()); - - storeByCreatorLabel.setVisible(false); - storeSubDirectoryLabel.setVisible(false); - - pluginNativeCheckbox.selectedProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().putBoolean(ApplicationDefaults.NATIVE_HOST_ENABLED_KEY, newValue); - this.pluginNativeComboBox.setDisable(!newValue); - updateScannerTimeoutFieldState(); - }); - - ObservableList pluginLoaders = FXCollections.observableArrayList( - nativeHostService.getAvailablePluginLoaders()); - pluginNativeComboBox.setItems(pluginLoaders); - - pluginNativeComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null) { - this.getPreferences().put(ApplicationDefaults.PREFERRED_NATIVE_LOADER, newValue.getId()); - nativeHostService.setCurrentPluginLoader(newValue); - updateScannerTimeoutFieldState(); + hideSection(pluginScanOptions); + hideSection(installationOptions); + hideSection(projectsOptions); + hideSection(applicationOptions); + + addNavButton("Plugin Scan", "mdi2m-magnify", pluginScanOptions); + addNavButton("Installation", "mdi2d-download-outline", installationOptions); + addNavButton("Projects", "mdi2f-folder-music-outline", projectsOptions); + addNavButton("Application", "mdi2c-cog-outline", applicationOptions); + + // Prevent deselecting all buttons + navToggleGroup.selectedToggleProperty().addListener((obs, prev, next) -> { + if (next == null && prev != null) { + prev.setSelected(true); } }); - loaderTimeoutTextField.textProperty().addListener((observable, oldValue, newValue) -> { - if (!newValue.matches("\\d*")) { - loaderTimeoutTextField.setText(newValue.replaceAll("[^\\d]", "")); - return; - } - try { - long timeout = Long.parseLong(newValue); - if (timeout >= 0 && timeout <= 3600) { - this.getPreferences().putLong(ApplicationDefaults.NATIVE_LOADER_TIMEOUT_KEY, timeout); - nativeHostService.setScannerTimeout(timeout); - } else { - loaderTimeoutTextField.setText(oldValue); - } - } catch (NumberFormatException ignored) { - // Ignore in case of invalid values (empty string) - } - }); - - syncPluginsCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().putBoolean(ApplicationDefaults.SYNC_PLUGINS_STARTUP_KEY, newValue); - }); - - syncFileStatCheckbox.selectedProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().putBoolean(ApplicationDefaults.SYNC_FILE_STAT_KEY, newValue); - }); - - storeSubDirectoryCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().putBoolean(ApplicationDefaults.STORE_SUBDIRECTORY_ENABLED, newValue); - warningSubDirectory.setVisible(!newValue); - storeSubDirectoryLabel.setVisible(newValue); - }); - - warningSubDirectory.managedProperty().bind(warningSubDirectory.visibleProperty()); - storeSubDirectoryLabel.managedProperty().bind(storeSubDirectoryLabel.visibleProperty()); - storeDirectorySeparator.managedProperty().bind(storeDirectorySeparator.visibleProperty()); - storeDirectoryTextField.managedProperty().bind(storeDirectoryTextField.visibleProperty()); + navToggleGroup.getToggles().get(0).setSelected(true); - storeDirectoryCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().putBoolean(ApplicationDefaults.STORE_DIRECTORY_ENABLED_KEY, newValue); - storeDirectorySeparator.setVisible(newValue); - storeDirectoryTextField.setVisible(newValue); - }); - - storeByCreatorCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().putBoolean(ApplicationDefaults.STORE_BY_CREATOR_ENABLED_KEY, newValue); - storeByCreatorLabel.setVisible(newValue); - }); - - storeByCreatorLabel.managedProperty().bind(storeByCreatorLabel.visibleProperty()); - - storeDirectoryTextField.textProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().put(ApplicationDefaults.STORE_DIRECTORY_KEY, newValue); - }); - - telemetryCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> { - this.getPreferences().putBoolean(ApplicationDefaults.TELEMETRY_ENABLED_KEY, newValue); - }); - - telemetryHyperlink.setOnAction(e -> { - PlatformUtils.openDefaultBrowser(this.getApplicationDefaults().getEnvProperty("owlplug.github.wiki.url") - + "/Telemetry"); - }); - - clearCacheButton.setOnAction(e -> { - optionsService.clearCache(); - }); - - removeDataButton.setOnAction(e -> { - Dialog dialog = this.getDialogManager().newDialog(); - DialogLayout layout = new DialogLayout(); - layout.setHeading(new Label("Remove user data")); - layout.setBody(new Label("Do you really want to remove all user data including accounts, " - + "stores and custom settings ? \n\nYou must restart OwlPlug for a complete reset.")); - - Button cancelButton = new Button("Cancel"); - cancelButton.setOnAction(cancelEvent -> { - dialog.close(); - }); - - Button removeButton = new Button("Remove data"); - removeButton.setOnAction(removeEvent -> { - dialog.close(); - optionsService.clearAllUserData(); - this.refreshView(); - - // User data cleared twice because the refreshView() triggers UI changes that may be replicated in data - optionsService.clearAllUserData(); - - }); - removeButton.getStyleClass().add("button-danger"); + versionLabel.setText("OwlPlug " + getApplicationDefaults().getVersion()); + contributorsFlow.getChildren().add(new SlidingLabel(ApplicationDefaults.getContributors())); - layout.setActions(removeButton, cancelButton); - dialog.setContent(layout); - dialog.show(); - }); - - versionLabel.setText(this.getApplicationDefaults().getVersion()); - - owlplugWebsiteLink.setOnAction(e -> { - PlatformUtils.openDefaultBrowser(owlplugWebsiteLink.getText()); - }); + refreshView(); + } - moreFeaturesButton.setOnAction(e -> { - donateDialogController.show(); + private void addNavButton(String label, String iconCode, Node section) { + FontIcon icon = new FontIcon(iconCode); + icon.setIconSize(15); + + ToggleButton btn = new ToggleButton(label, icon); + btn.setToggleGroup(navToggleGroup); + btn.setMaxWidth(Double.MAX_VALUE); + btn.setAlignment(Pos.CENTER_LEFT); + btn.getStyleClass().add("options-nav-button"); + btn.setGraphicTextGap(10); + + btn.selectedProperty().addListener((obs, wasSelected, isSelected) -> { + if (isSelected) { + showSection(section); + } else { + hideSection(section); + } }); - openLogsButton.setOnAction(e -> { - PlatformUtils.openFromDesktop(ApplicationDefaults.getLogDirectory()); - }); + navContainer.getChildren().add(btn); + } - versionTextFlow.getChildren().add(new SlidingLabel(ApplicationDefaults.getContributors())); + private void showSection(Node section) { + section.setVisible(true); + section.setManaged(true); + } - refreshView(); + private void hideSection(Node section) { + section.setVisible(false); + section.setManaged(false); } - private void updateScannerTimeoutFieldState() { - NativePluginLoader selected = pluginNativeComboBox.getSelectionModel().getSelectedItem(); - boolean isOwlPlugScanner = selected != null && "owlplug-scanner".equals(selected.getId()); - boolean nativeEnabled = pluginNativeCheckbox.isSelected() && !pluginNativeCheckbox.isDisable(); - loaderTimeoutTextField.setDisable(!nativeEnabled || !isOwlPlugScanner); + public void navigateToSection(int index) { + navToggleGroup.getToggles().get(index).setSelected(true); } public void refreshView() { - - vst2PluginPathFragment.refresh(); - vst3PluginPathFragment.refresh(); - auPluginPathFragment.refresh(); - lv2PluginPathFragment.refresh(); - - pluginNativeCheckbox.setDisable(!nativeHostService.isNativeHostAvailable()); - pluginNativeComboBox.setDisable(!nativeHostService.isNativeHostAvailable()); - pluginNativeCheckbox.setSelected(this.getPreferences().getBoolean(ApplicationDefaults.NATIVE_HOST_ENABLED_KEY, false)); - syncPluginsCheckBox.setSelected(this.getPreferences().getBoolean(ApplicationDefaults.SYNC_PLUGINS_STARTUP_KEY, false)); - syncFileStatCheckbox.setSelected(this.getPreferences().getBoolean(ApplicationDefaults.SYNC_FILE_STAT_KEY, true)); - storeSubDirectoryCheckBox.setSelected(this.getPreferences().getBoolean(ApplicationDefaults.STORE_SUBDIRECTORY_ENABLED, true)); - warningSubDirectory.setVisible(!this.getPreferences().getBoolean(ApplicationDefaults.STORE_SUBDIRECTORY_ENABLED, true)); - storeDirectoryCheckBox.setSelected(this.getPreferences().getBoolean(ApplicationDefaults.STORE_DIRECTORY_ENABLED_KEY, false)); - storeByCreatorCheckBox.setSelected(this.getPreferences().getBoolean(ApplicationDefaults.STORE_BY_CREATOR_ENABLED_KEY, false)); - storeDirectoryTextField.setText(this.getPreferences().get(ApplicationDefaults.STORE_DIRECTORY_KEY, "")); - telemetryCheckBox.setSelected(this.getPreferences().getBoolean(ApplicationDefaults.TELEMETRY_ENABLED_KEY, true)); - - NativePluginLoader pluginLoader = nativeHostService.getCurrentPluginLoader(); - pluginNativeComboBox.getSelectionModel().select(pluginLoader); - - long timeout = this.getPreferences().getLong(ApplicationDefaults.NATIVE_LOADER_TIMEOUT_KEY, 10L); - loaderTimeoutTextField.setText(String.valueOf(timeout)); - updateScannerTimeoutFieldState(); - - if (!storeDirectoryCheckBox.isSelected()) { - storeDirectoryTextField.setVisible(false); - } - if (!storeByCreatorCheckBox.isSelected()) { - storeByCreatorLabel.setVisible(false); - } - - // Disable AU options for non MAC users - if (!this.getApplicationDefaults().getRuntimePlatform() - .getOperatingSystem().equals(OperatingSystem.MAC)) { - auPluginPathFragment.disable(); - } - + pluginScanOptionsController.refresh(); + installationOptionsController.refresh(); + projectsOptionsController.refresh(); + applicationOptionsController.refresh(); } @EventListener @@ -340,4 +154,4 @@ private void handle(PreferencesChangedEvent event) { FX.run(this::refreshView); } -} +} \ No newline at end of file diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DonateDialogController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DonateDialogController.java index f6d3af91..01b95a94 100644 --- a/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DonateDialogController.java +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DonateDialogController.java @@ -45,7 +45,7 @@ public class DonateDialogController extends AbstractDialogController { private Button cancelButton; DonateDialogController() { - super(550, 480); + super(600, 480); this.setOverlayClose(false); } diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ListDirectoryDialogController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ListDirectoryDialogController.java index 0cc56c3e..f3a93e4b 100644 --- a/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ListDirectoryDialogController.java +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ListDirectoryDialogController.java @@ -20,87 +20,101 @@ import com.owlplug.controls.DialogLayout; import com.owlplug.core.components.LazyViewRegistry; -import com.owlplug.core.controllers.dialogs.AbstractDialogController; import com.owlplug.core.events.PreferencesChangedEvent; +import java.io.File; import java.util.ArrayList; -import java.util.List; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.Button; +import javafx.scene.control.Label; import javafx.scene.control.ListView; -import javafx.scene.control.cell.TextFieldListCell; +import javafx.stage.DirectoryChooser; +import org.kordamp.ikonli.javafx.FontIcon; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Controller; @Controller -public class ListDirectoryDialogController extends AbstractDialogController implements ListChangeListener { +public class ListDirectoryDialogController extends AbstractDialogController { @Autowired private ApplicationEventPublisher publisher; @Autowired private LazyViewRegistry lazyViewRegistry; + @FXML + private ListView directoryListView; @FXML private Button addDirectoryButton; @FXML - private ListView directoryListView; + private Button removeDirectoryButton; @FXML private Button closeButton; - private final String newDirectoryItem = "[New directory] (double-click to update)"; private String currentPreferenceKey; private ObservableList observableItems; + public ListDirectoryDialogController() { + super(700,500); + } + public void initialize() { + Label placeholder = new Label("No additional directories configured."); + placeholder.getStyleClass().add("label-disabled"); + directoryListView.setPlaceholder(placeholder); + + FontIcon addIcon = new FontIcon("mdi2p-plus"); + addIcon.setIconSize(14); + addDirectoryButton.setGraphic(addIcon); + + FontIcon removeIcon = new FontIcon("mdi2m-minus"); + removeIcon.setIconSize(14); + removeDirectoryButton.setGraphic(removeIcon); addDirectoryButton.setOnAction(e -> { - observableItems.add(newDirectoryItem); + DirectoryChooser chooser = new DirectoryChooser(); + File dir = chooser.showDialog(addDirectoryButton.getScene().getWindow()); + if (dir != null) { + String path = dir.getAbsolutePath(); + if (!observableItems.contains(path)) { + observableItems.add(path); + } + } }); - directoryListView.setCellFactory(TextFieldListCell.forListView()); - closeButton.setOnAction(e -> { - this.close(); + + removeDirectoryButton.setOnAction(e -> { + String selected = directoryListView.getSelectionModel().getSelectedItem(); + if (selected != null) { + observableItems.remove(selected); + } }); + + closeButton.setOnAction(e -> this.close()); } public void configure(String preferenceKey) { this.currentPreferenceKey = preferenceKey; - if (observableItems != null) { - observableItems.removeListener(this); - } + observableItems = FXCollections.observableArrayList( + this.getPreferences().getList(preferenceKey, new ArrayList<>())); - List items = this.getPreferences().getList(preferenceKey, new ArrayList<>()); - observableItems = FXCollections.observableArrayList(items); + observableItems.addListener((ListChangeListener) change -> { + this.getPreferences().putList(currentPreferenceKey, new ArrayList<>(observableItems)); + publisher.publishEvent(new PreferencesChangedEvent()); + }); - observableItems.addListener(this); directoryListView.setItems(observableItems); - directoryListView.refresh(); - } - - - @Override - public void onChanged(Change change) { - - ObservableList eventList = change.getList(); - // Remove blank entries in the backed list - eventList.removeIf(x -> x.isBlank()); - - // Create a new list and filter it before saving it to preferences - List prefList = new ArrayList<>(change.getList()); - prefList.removeIf(x -> x.isBlank() || x.equals(newDirectoryItem)); - this.getPreferences().putList(currentPreferenceKey, prefList); - - publisher.publishEvent(new PreferencesChangedEvent()); - } protected DialogLayout getLayout() { DialogLayout layout = new DialogLayout(); + Label title = new Label("Additional Directories"); + title.setGraphic(new FontIcon("mdi2f-folder-multiple")); + layout.setHeading(title); layout.setBody(lazyViewRegistry.get(LazyViewRegistry.LIST_DIRECTORY_VIEW)); return layout; } -} +} \ No newline at end of file diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java index 48fde37f..77746b3a 100644 --- a/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java @@ -27,6 +27,7 @@ import com.owlplug.core.model.OperatingSystem; import com.owlplug.core.utils.FX; import com.owlplug.plugin.components.PluginTaskFactory; +import com.owlplug.plugin.model.PluginFormat; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -70,28 +71,28 @@ public class WelcomeDialogController extends AbstractDialogController { */ public void initialize() { - vst2PluginPathFragment = new PluginPathFragmentController("VST2", + vst2PluginPathFragment = new PluginPathFragmentController(PluginFormat.VST2, ApplicationDefaults.VST2_DISCOVERY_ENABLED_KEY, ApplicationDefaults.VST_DIRECTORY_KEY, ApplicationDefaults.VST2_EXTRA_DIRECTORY_KEY, - this.getPreferences(), + this.getPreferences(), this.getApplicationDefaults(), this.listDirectoryDialogController); - vst3PluginPathFragment = new PluginPathFragmentController("VST3", + vst3PluginPathFragment = new PluginPathFragmentController(PluginFormat.VST3, ApplicationDefaults.VST3_DISCOVERY_ENABLED_KEY, ApplicationDefaults.VST3_DIRECTORY_KEY, ApplicationDefaults.VST3_EXTRA_DIRECTORY_KEY, - this.getPreferences(), + this.getPreferences(), this.getApplicationDefaults(), this.listDirectoryDialogController); - auPluginPathFragment = new PluginPathFragmentController("AU", + auPluginPathFragment = new PluginPathFragmentController(PluginFormat.AU, ApplicationDefaults.AU_DISCOVERY_ENABLED_KEY, ApplicationDefaults.AU_DIRECTORY_KEY, ApplicationDefaults.AU_EXTRA_DIRECTORY_KEY, - this.getPreferences(), + this.getPreferences(), this.getApplicationDefaults(), this.listDirectoryDialogController); - lv2PluginPathFragment = new PluginPathFragmentController("LV2", + lv2PluginPathFragment = new PluginPathFragmentController(PluginFormat.LV2, ApplicationDefaults.LV2_DISCOVERY_ENABLED_KEY, ApplicationDefaults.LV2_DIRECTORY_KEY, ApplicationDefaults.LV2_EXTRA_DIRECTORY_KEY, - this.getPreferences(), + this.getPreferences(), this.getApplicationDefaults(), this.listDirectoryDialogController); pluginPathContainer.getChildren().add(vst2PluginPathFragment.getNode()); diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/fragments/PluginPathFragmentController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/fragments/PluginPathFragmentController.java index db3ca0d2..8f8f5ba7 100644 --- a/owlplug-client/src/main/java/com/owlplug/core/controllers/fragments/PluginPathFragmentController.java +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/fragments/PluginPathFragmentController.java @@ -19,10 +19,13 @@ package com.owlplug.core.controllers.fragments; import atlantafx.base.controls.ToggleSwitch; +import com.owlplug.core.components.ApplicationDefaults; import com.owlplug.core.components.ApplicationPreferences; +import com.owlplug.core.controllers.dialogs.ListDirectoryDialogController; import com.owlplug.core.ui.SVGPaths; import com.owlplug.core.utils.FileUtils; -import com.owlplug.core.controllers.dialogs.ListDirectoryDialogController; +import com.owlplug.plugin.model.PluginFormat; +import com.owlplug.plugin.ui.PluginFormatBadgeView; import java.io.File; import java.io.IOException; import java.text.MessageFormat; @@ -34,6 +37,7 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.control.Tooltip; +import javafx.scene.layout.HBox; import javafx.scene.layout.Region; import javafx.scene.shape.SVGPath; import javafx.stage.DirectoryChooser; @@ -48,6 +52,8 @@ public class PluginPathFragmentController { @FXML private Node mainNode; @FXML + private HBox headerBox; + @FXML private Label headerLabel; @FXML private ToggleSwitch activationToggleButton; @@ -69,21 +75,24 @@ public class PluginPathFragmentController { private SVGPath crossPath = new SVGPath(); - private String name; + private PluginFormat pluginFormat; private String enableOptionKey; private String directoryOptionKey; private String extraDirectoryOptionKey; private ApplicationPreferences prefs; + private ApplicationDefaults applicationDefaults; private ListDirectoryDialogController listDirectoryDialogController; - public PluginPathFragmentController(String name, String enableOptionKey, String directoryOptionKey, + public PluginPathFragmentController(PluginFormat pluginFormat, String enableOptionKey, String directoryOptionKey, String extraDirectoryOptionKey, ApplicationPreferences prefs, + ApplicationDefaults applicationDefaults, ListDirectoryDialogController listDirectoryDialogController) { - this.name = name; + this.pluginFormat = pluginFormat; this.enableOptionKey = enableOptionKey; this.directoryOptionKey = directoryOptionKey; this.extraDirectoryOptionKey = extraDirectoryOptionKey; this.prefs = prefs; + this.applicationDefaults = applicationDefaults; this.listDirectoryDialogController = listDirectoryDialogController; init(); @@ -104,10 +113,14 @@ public void init() { checkPath.setContent(SVGPaths.check); crossPath.setContent(SVGPaths.cross); - headerLabel.setText(name); - directoryTextField.setPromptText(name + " plugin directory"); + PluginFormatBadgeView badge = new PluginFormatBadgeView( + pluginFormat, applicationDefaults, PluginFormatBadgeView.DisplayMode.DEFAULT); + headerBox.getChildren().add(0, badge); + + headerLabel.setText(pluginFormat.getFullName()); + directoryTextField.setPromptText(pluginFormat.getName() + " plugin directory"); - activationToggleButton.setText("Explore " + name + " plugins"); + activationToggleButton.setText("Scan " + pluginFormat.getName() + " plugins"); activationToggleButton.selectedProperty().addListener((observable, oldValue, newValue) -> { prefs.putBoolean(enableOptionKey, newValue); refresh(); diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/options/ApplicationOptionsController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/ApplicationOptionsController.java new file mode 100644 index 00000000..082ec448 --- /dev/null +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/ApplicationOptionsController.java @@ -0,0 +1,99 @@ +/* OwlPlug + * Copyright (C) 2021 Arthur + * + * This file is part of OwlPlug. + * + * OwlPlug is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 + * as published by the Free Software Foundation. + * + * OwlPlug is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OwlPlug. If not, see . + */ + +package com.owlplug.core.controllers.options; + +import com.owlplug.controls.Dialog; +import com.owlplug.controls.DialogLayout; +import com.owlplug.core.components.ApplicationDefaults; +import com.owlplug.core.controllers.BaseController; +import com.owlplug.core.controllers.dialogs.DonateDialogController; +import com.owlplug.core.services.OptionsService; +import com.owlplug.core.utils.PlatformUtils; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +@Controller +public class ApplicationOptionsController extends BaseController { + + @Autowired + private OptionsService optionsService; + @Autowired + private DonateDialogController donateDialogController; + + @FXML + private CheckBox telemetryCheckBox; + @FXML + private Hyperlink telemetryHyperlink; + @FXML + private Button clearCacheButton; + @FXML + private Button removeDataButton; + @FXML + private Hyperlink websiteLink; + @FXML + private Button contributeButton; + @FXML + private Button openLogsButton; + + @FXML + public void initialize() { + telemetryCheckBox.selectedProperty().addListener((obs, o, n) -> + getPreferences().putBoolean(ApplicationDefaults.TELEMETRY_ENABLED_KEY, n)); + + telemetryHyperlink.setOnAction(e -> PlatformUtils.openDefaultBrowser( + getApplicationDefaults().getEnvProperty("owlplug.github.wiki.url") + "/Telemetry")); + + clearCacheButton.setOnAction(e -> optionsService.clearCache()); + + removeDataButton.setOnAction(e -> { + Dialog dialog = getDialogManager().newDialog(); + DialogLayout layout = new DialogLayout(); + layout.setHeading(new Label("Remove User Data")); + layout.setBody(new Label( + "Do you really want to remove all user data including accounts, " + + "stores and custom settings?\n\nYou must restart OwlPlug for a complete reset.")); + Button cancelButton = new Button("Cancel"); + cancelButton.setOnAction(ce -> dialog.close()); + Button confirmButton = new Button("Remove Data"); + confirmButton.getStyleClass().add("button-danger"); + confirmButton.setOnAction(ce -> { + dialog.close(); + optionsService.clearAllUserData(); + }); + layout.setActions(confirmButton, cancelButton); + dialog.setContent(layout); + dialog.show(); + }); + + websiteLink.setOnAction(e -> PlatformUtils.openDefaultBrowser(websiteLink.getText())); + contributeButton.setOnAction(e -> donateDialogController.show()); + openLogsButton.setOnAction(e -> PlatformUtils.openFromDesktop(ApplicationDefaults.getLogDirectory())); + } + + public void refresh() { + telemetryCheckBox.setSelected( + getPreferences().getBoolean(ApplicationDefaults.TELEMETRY_ENABLED_KEY, true)); + } + +} \ No newline at end of file diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/options/InstallationOptionsController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/InstallationOptionsController.java new file mode 100644 index 00000000..db43b15d --- /dev/null +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/InstallationOptionsController.java @@ -0,0 +1,145 @@ +/* OwlPlug + * Copyright (C) 2021 Arthur + * + * This file is part of OwlPlug. + * + * OwlPlug is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 + * as published by the Free Software Foundation. + * + * OwlPlug is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OwlPlug. If not, see . + */ + +package com.owlplug.core.controllers.options; + +import com.owlplug.core.components.ApplicationDefaults; +import com.owlplug.core.controllers.BaseController; +import com.owlplug.plugin.ui.PluginFormatBadgeView; +import java.io.File; +import javafx.fxml.FXML; +import javafx.geometry.Pos; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import org.springframework.stereotype.Controller; + +@Controller +public class InstallationOptionsController extends BaseController { + + @FXML + private CheckBox storeDirectoryCheckBox; + @FXML + private HBox storeDirectoryRow; + @FXML + private TextField storeDirectoryTextField; + @FXML + private CheckBox storeByCreatorCheckBox; + @FXML + private CheckBox storeSubDirectoryCheckBox; + @FXML + private Label warningSubDirectory; + @FXML + private VBox pathPreviewContainer; + + private Label vst2PathLabel; + private Label vst3PathLabel; + private Label auPathLabel; + private Label lv2PathLabel; + + @FXML + public void initialize() { + storeDirectoryRow.visibleProperty().bind(storeDirectoryCheckBox.selectedProperty()); + storeDirectoryRow.managedProperty().bind(storeDirectoryCheckBox.selectedProperty()); + warningSubDirectory.managedProperty().bind(warningSubDirectory.visibleProperty()); + + storeDirectoryCheckBox.selectedProperty().addListener((obs, o, n) -> { + getPreferences().putBoolean(ApplicationDefaults.STORE_DIRECTORY_ENABLED_KEY, n); + refreshPathPreview(); + }); + storeByCreatorCheckBox.selectedProperty().addListener((obs, o, n) -> { + getPreferences().putBoolean(ApplicationDefaults.STORE_BY_CREATOR_ENABLED_KEY, n); + refreshPathPreview(); + }); + storeSubDirectoryCheckBox.selectedProperty().addListener((obs, o, n) -> { + getPreferences().putBoolean(ApplicationDefaults.STORE_SUBDIRECTORY_ENABLED, n); + warningSubDirectory.setVisible(!n); + refreshPathPreview(); + }); + storeDirectoryTextField.textProperty().addListener((obs, o, n) -> { + getPreferences().put(ApplicationDefaults.STORE_DIRECTORY_KEY, n); + refreshPathPreview(); + }); + + vst2PathLabel = previewLabel(); + vst3PathLabel = previewLabel(); + auPathLabel = previewLabel(); + lv2PathLabel = previewLabel(); + + pathPreviewContainer.getChildren().addAll( + previewRow("vst2", vst2PathLabel), + previewRow("vst3", vst3PathLabel), + previewRow("au", auPathLabel), + previewRow("lv2", lv2PathLabel)); + } + + public void refresh() { + boolean storeSubDir = getPreferences().getBoolean(ApplicationDefaults.STORE_SUBDIRECTORY_ENABLED, true); + storeSubDirectoryCheckBox.setSelected(storeSubDir); + warningSubDirectory.setVisible(!storeSubDir); + storeDirectoryCheckBox.setSelected( + getPreferences().getBoolean(ApplicationDefaults.STORE_DIRECTORY_ENABLED_KEY, false)); + storeByCreatorCheckBox.setSelected( + getPreferences().getBoolean(ApplicationDefaults.STORE_BY_CREATOR_ENABLED_KEY, false)); + storeDirectoryTextField.setText( + getPreferences().get(ApplicationDefaults.STORE_DIRECTORY_KEY, "")); + refreshPathPreview(); + } + + private void refreshPathPreview() { + vst2PathLabel.setText(simulatePath(ApplicationDefaults.VST_DIRECTORY_KEY)); + vst3PathLabel.setText(simulatePath(ApplicationDefaults.VST3_DIRECTORY_KEY)); + auPathLabel.setText(simulatePath(ApplicationDefaults.AU_DIRECTORY_KEY)); + lv2PathLabel.setText(simulatePath(ApplicationDefaults.LV2_DIRECTORY_KEY)); + } + + private String simulatePath(String formatDirKey) { + String baseDir = getPreferences().get(formatDirKey, ""); + if (baseDir == null || baseDir.isBlank()) return "Format directory not configured"; + + File path = new File(baseDir); + if (storeDirectoryCheckBox.isSelected()) { + String sub = storeDirectoryTextField.getText(); + if (sub != null && !sub.isBlank()) path = new File(path, sub); + } + if (storeByCreatorCheckBox.isSelected()) path = new File(path, "Acme Audio"); + if (storeSubDirectoryCheckBox.isSelected()) path = new File(path, "MyPlugin"); + return path.getAbsolutePath(); + } + + private Label previewLabel() { + Label l = new Label(); + l.getStyleClass().add("label-disabled"); + l.setWrapText(true); + HBox.setHgrow(l, Priority.ALWAYS); + return l; + } + + private HBox previewRow(String formatValue, Label pathLabel) { + PluginFormatBadgeView badge = new PluginFormatBadgeView( + formatValue, getApplicationDefaults(), PluginFormatBadgeView.DisplayMode.TEXT_ONLY); + badge.setMinWidth(42); + HBox row = new HBox(12, badge, pathLabel); + row.setAlignment(Pos.CENTER_LEFT); + return row; + } + +} \ No newline at end of file diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/options/PluginScanOptionsController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/PluginScanOptionsController.java new file mode 100644 index 00000000..b70b8cbe --- /dev/null +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/PluginScanOptionsController.java @@ -0,0 +1,156 @@ +/* OwlPlug + * Copyright (C) 2021 Arthur + * + * This file is part of OwlPlug. + * + * OwlPlug is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 + * as published by the Free Software Foundation. + * + * OwlPlug is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OwlPlug. If not, see . + */ + +package com.owlplug.core.controllers.options; + +import com.owlplug.core.components.ApplicationDefaults; +import com.owlplug.core.controllers.BaseController; +import com.owlplug.core.controllers.dialogs.ListDirectoryDialogController; +import com.owlplug.core.controllers.fragments.PluginPathFragmentController; +import com.owlplug.core.model.OperatingSystem; +import com.owlplug.host.loaders.NativePluginLoader; +import com.owlplug.plugin.model.PluginFormat; +import com.owlplug.plugin.services.NativeHostService; +import javafx.collections.FXCollections; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Spinner; +import javafx.scene.control.SpinnerValueFactory; +import javafx.scene.layout.VBox; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +@Controller +public class PluginScanOptionsController extends BaseController { + + @Autowired + private NativeHostService nativeHostService; + @Autowired + private ListDirectoryDialogController listDirectoryDialogController; + + @FXML + private VBox formatsContainer; + @FXML + private CheckBox pluginNativeCheckbox; + @FXML + private ComboBox pluginNativeComboBox; + @FXML + private Spinner loaderTimeoutSpinner; + @FXML + private CheckBox syncPluginsCheckBox; + @FXML + private CheckBox syncFileStatCheckbox; + + private PluginPathFragmentController vst2Fragment; + private PluginPathFragmentController vst3Fragment; + private PluginPathFragmentController auFragment; + private PluginPathFragmentController lv2Fragment; + + @FXML + public void initialize() { + vst2Fragment = new PluginPathFragmentController(PluginFormat.VST2, + ApplicationDefaults.VST2_DISCOVERY_ENABLED_KEY, ApplicationDefaults.VST_DIRECTORY_KEY, + ApplicationDefaults.VST2_EXTRA_DIRECTORY_KEY, getPreferences(), + getApplicationDefaults(), listDirectoryDialogController); + vst3Fragment = new PluginPathFragmentController(PluginFormat.VST3, + ApplicationDefaults.VST3_DISCOVERY_ENABLED_KEY, ApplicationDefaults.VST3_DIRECTORY_KEY, + ApplicationDefaults.VST3_EXTRA_DIRECTORY_KEY, getPreferences(), + getApplicationDefaults(), listDirectoryDialogController); + auFragment = new PluginPathFragmentController(PluginFormat.AU, + ApplicationDefaults.AU_DISCOVERY_ENABLED_KEY, ApplicationDefaults.AU_DIRECTORY_KEY, + ApplicationDefaults.AU_EXTRA_DIRECTORY_KEY, getPreferences(), + getApplicationDefaults(), listDirectoryDialogController); + lv2Fragment = new PluginPathFragmentController(PluginFormat.LV2, + ApplicationDefaults.LV2_DISCOVERY_ENABLED_KEY, ApplicationDefaults.LV2_DIRECTORY_KEY, + ApplicationDefaults.LV2_EXTRA_DIRECTORY_KEY, getPreferences(), + getApplicationDefaults(), listDirectoryDialogController); + + formatsContainer.getChildren().addAll( + vst2Fragment.getNode(), + vst3Fragment.getNode(), + auFragment.getNode(), + lv2Fragment.getNode()); + + pluginNativeCheckbox.selectedProperty().addListener((obs, o, n) -> { + getPreferences().putBoolean(ApplicationDefaults.NATIVE_HOST_ENABLED_KEY, n); + pluginNativeComboBox.setDisable(!n); + updateScannerTimeoutFieldState(); + }); + + pluginNativeComboBox.setItems( + FXCollections.observableArrayList(nativeHostService.getAvailablePluginLoaders())); + pluginNativeComboBox.getSelectionModel().selectedItemProperty().addListener((obs, o, n) -> { + if (n != null) { + getPreferences().put(ApplicationDefaults.PREFERRED_NATIVE_LOADER, n.getId()); + nativeHostService.setCurrentPluginLoader(n); + updateScannerTimeoutFieldState(); + } + }); + + loaderTimeoutSpinner.setValueFactory( + new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 3600, 10)); + loaderTimeoutSpinner.valueProperty().addListener((obs, o, n) -> { + getPreferences().putLong(ApplicationDefaults.NATIVE_LOADER_TIMEOUT_KEY, n.longValue()); + nativeHostService.setScannerTimeout(n.longValue()); + }); + + syncPluginsCheckBox.selectedProperty().addListener((obs, o, n) -> + getPreferences().putBoolean(ApplicationDefaults.SYNC_PLUGINS_STARTUP_KEY, n)); + syncFileStatCheckbox.selectedProperty().addListener((obs, o, n) -> + getPreferences().putBoolean(ApplicationDefaults.SYNC_FILE_STAT_KEY, n)); + } + + public void refresh() { + vst2Fragment.refresh(); + vst3Fragment.refresh(); + auFragment.refresh(); + lv2Fragment.refresh(); + + boolean nativeAvailable = nativeHostService.isNativeHostAvailable(); + pluginNativeCheckbox.setDisable(!nativeAvailable); + pluginNativeComboBox.setDisable(!nativeAvailable); + pluginNativeCheckbox.setSelected( + getPreferences().getBoolean(ApplicationDefaults.NATIVE_HOST_ENABLED_KEY, false)); + + NativePluginLoader loader = nativeHostService.getCurrentPluginLoader(); + pluginNativeComboBox.getSelectionModel().select(loader); + + int timeout = (int) getPreferences().getLong(ApplicationDefaults.NATIVE_LOADER_TIMEOUT_KEY, 10L); + loaderTimeoutSpinner.getValueFactory().setValue(timeout); + updateScannerTimeoutFieldState(); + + syncPluginsCheckBox.setSelected( + getPreferences().getBoolean(ApplicationDefaults.SYNC_PLUGINS_STARTUP_KEY, false)); + syncFileStatCheckbox.setSelected( + getPreferences().getBoolean(ApplicationDefaults.SYNC_FILE_STAT_KEY, true)); + + if (!getApplicationDefaults().getRuntimePlatform() + .getOperatingSystem().equals(OperatingSystem.MAC)) { + auFragment.disable(); + } + } + + private void updateScannerTimeoutFieldState() { + NativePluginLoader selected = pluginNativeComboBox.getSelectionModel().getSelectedItem(); + boolean isOwlPlugScanner = selected != null && "owlplug-scanner".equals(selected.getId()); + boolean nativeEnabled = pluginNativeCheckbox.isSelected() && !pluginNativeCheckbox.isDisable(); + loaderTimeoutSpinner.setDisable(!nativeEnabled || !isOwlPlugScanner); + } + +} \ No newline at end of file diff --git a/owlplug-client/src/main/java/com/owlplug/core/controllers/options/ProjectsOptionsController.java b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/ProjectsOptionsController.java new file mode 100644 index 00000000..f70c9fe1 --- /dev/null +++ b/owlplug-client/src/main/java/com/owlplug/core/controllers/options/ProjectsOptionsController.java @@ -0,0 +1,92 @@ +/* OwlPlug + * Copyright (C) 2021 Arthur + * + * This file is part of OwlPlug. + * + * OwlPlug is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 + * as published by the Free Software Foundation. + * + * OwlPlug is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OwlPlug. If not, see . + */ + +package com.owlplug.core.controllers.options; + +import com.owlplug.core.components.ApplicationDefaults; +import com.owlplug.core.controllers.BaseController; +import java.io.File; +import java.util.ArrayList; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.stage.DirectoryChooser; +import javafx.stage.Window; +import org.kordamp.ikonli.javafx.FontIcon; +import org.springframework.stereotype.Controller; + +@Controller +public class ProjectsOptionsController extends BaseController { + + @FXML + private ListView projectListView; + @FXML + private Button addDirButton; + @FXML + private Button removeDirButton; + + private ObservableList projectDirectories; + + @FXML + public void initialize() { + Label placeholder = new Label("No project directories configured."); + placeholder.getStyleClass().add("label-disabled"); + projectListView.setPlaceholder(placeholder); + + FontIcon addIcon = new FontIcon("mdi2p-plus"); + addIcon.setIconSize(14); + addDirButton.setGraphic(addIcon); + + FontIcon removeIcon = new FontIcon("mdi2m-minus"); + removeIcon.setIconSize(14); + removeDirButton.setGraphic(removeIcon); + + projectDirectories = FXCollections.observableArrayList( + getPreferences().getList(ApplicationDefaults.PROJECT_DIRECTORY_KEY, new ArrayList<>())); + projectListView.setItems(projectDirectories); + + projectDirectories.addListener((ListChangeListener) change -> + getPreferences().putList( + ApplicationDefaults.PROJECT_DIRECTORY_KEY, new ArrayList<>(projectDirectories))); + + addDirButton.setOnAction(e -> { + DirectoryChooser chooser = new DirectoryChooser(); + Window window = addDirButton.getScene().getWindow(); + File dir = chooser.showDialog(window); + if (dir != null) { + String path = dir.getAbsolutePath(); + if (!projectDirectories.contains(path)) projectDirectories.add(path); + } + }); + + removeDirButton.setOnAction(e -> { + String selected = projectListView.getSelectionModel().getSelectedItem(); + if (selected != null) projectDirectories.remove(selected); + }); + } + + public void refresh() { + projectDirectories.setAll( + getPreferences().getList(ApplicationDefaults.PROJECT_DIRECTORY_KEY, new ArrayList<>())); + } + +} \ No newline at end of file diff --git a/owlplug-client/src/main/java/com/owlplug/explore/ui/ExploreChipView.java b/owlplug-client/src/main/java/com/owlplug/explore/ui/ExploreChipView.java index 2ec150ed..3d27822b 100644 --- a/owlplug-client/src/main/java/com/owlplug/explore/ui/ExploreChipView.java +++ b/owlplug-client/src/main/java/com/owlplug/explore/ui/ExploreChipView.java @@ -139,10 +139,10 @@ public ExploreFilterCriteria fromString(String string) { root.getStyleClass().add("chip-brown"); } if (getItem().getFilterType() == ExploreFilterCriteriaType.TAG) { - root.getStyleClass().add("chip-blue"); + root.getStyleClass().add("chip-red"); } if (getItem().getFilterType() == ExploreFilterCriteriaType.CREATOR) { - root.getStyleClass().add("chip-red"); + root.getStyleClass().add("chip-blue"); } } }); diff --git a/owlplug-client/src/main/java/com/owlplug/explore/ui/PackageListRowView.java b/owlplug-client/src/main/java/com/owlplug/explore/ui/PackageListRowView.java index 4903bcc7..0c7caeb7 100644 --- a/owlplug-client/src/main/java/com/owlplug/explore/ui/PackageListRowView.java +++ b/owlplug-client/src/main/java/com/owlplug/explore/ui/PackageListRowView.java @@ -102,7 +102,7 @@ private StackPane buildThumbnail(Image image, RemotePackage remotePackage) { } else if (remotePackage.getStage() == PluginStage.DEMO) { stageBadge.getStyleClass().add("package-stage-demo"); } - StackPane.setAlignment(stageBadge, Pos.BOTTOM_LEFT); + StackPane.setAlignment(stageBadge, Pos.TOP_LEFT); thumb.getChildren().add(stageBadge); } diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/model/PluginFormat.java b/owlplug-client/src/main/java/com/owlplug/plugin/model/PluginFormat.java index 5958d131..60963614 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/model/PluginFormat.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/model/PluginFormat.java @@ -19,16 +19,30 @@ package com.owlplug.plugin.model; public enum PluginFormat { - VST2("VST2"), VST3("VST3"), AU("AU"), LV2("LV2"); + VST2("VST2", "Virtual Instrument (v2)"), + VST3("VST3", "Virtual Instrument (v3)"), + AU("AU", "Audio Unit"), + LV2("LV2", "LADSPA (v2)"); - private final String text; + private final String name; + private final String fullName; - PluginFormat(String text) { - this.text = text; + PluginFormat(String name, String fullName) { + this.name = name; + this.fullName = fullName; } + @Deprecated public String getText() { - return text; + return name; + } + + public String getName() { + return name; + } + + public String getFullName() { + return fullName; } /** @@ -43,7 +57,7 @@ public static PluginFormat fromBundleString(String text) { return PluginFormat.VST2; } for (PluginFormat f : PluginFormat.values()) { - if (f.text.equalsIgnoreCase(text)) { + if (f.name.equalsIgnoreCase(text)) { return f; } } diff --git a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java index 2396522f..afc02099 100644 --- a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java @@ -170,7 +170,7 @@ public void updateItem(Plugin item, boolean empty) { link.setGraphic(new ImageView(getApplicationDefaults().linkIconImage)); link.setOnAction(e -> { pluginsController.selectPluginById(item.getId()); - mainController.selectMainTab(MainController.PLUGINS_TAB_INDEX); + mainController.navigateToMainTab(MainController.PLUGINS_TAB_INDEX); }); setGraphic(link); } diff --git a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java index c27ea2b9..d8802ca5 100644 --- a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java +++ b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java @@ -18,9 +18,9 @@ package com.owlplug.project.controllers; -import com.owlplug.core.components.ApplicationDefaults; import com.owlplug.core.controllers.BaseController; -import com.owlplug.core.controllers.dialogs.ListDirectoryDialogController; +import com.owlplug.core.controllers.MainController; +import com.owlplug.core.controllers.OptionsController; import com.owlplug.core.ui.FilterableTreeItem; import com.owlplug.core.utils.FX; import com.owlplug.project.events.ProjectSyncEvent; @@ -46,7 +46,9 @@ public class ProjectsController extends BaseController { @Autowired private ProjectService projectService; @Autowired - private ListDirectoryDialogController listDirectoryDialogController; + private MainController mainController; + @Autowired + private OptionsController optionsController; @Autowired private ProjectInfoController projectInfoController; @@ -81,8 +83,8 @@ public void initialize() { }); projectDirectoryButton.setOnAction(e -> { - listDirectoryDialogController.configure(ApplicationDefaults.PROJECT_DIRECTORY_KEY); - listDirectoryDialogController.show(); + optionsController.navigateToSection(OptionsController.PROJECTS_SECTION_INDEX); + mainController.navigateToMainTab(MainController.OPTIONS_TAB_INDEX); }); projectTreeNode = new FilterableTreeItem<>("(all)"); diff --git a/owlplug-client/src/main/resources/fxml/MainView.fxml b/owlplug-client/src/main/resources/fxml/MainView.fxml index 3b027854..49db49c0 100644 --- a/owlplug-client/src/main/resources/fxml/MainView.fxml +++ b/owlplug-client/src/main/resources/fxml/MainView.fxml @@ -5,8 +5,6 @@ - - diff --git a/owlplug-client/src/main/resources/fxml/OptionsView.fxml b/owlplug-client/src/main/resources/fxml/OptionsView.fxml index cccce37e..e0bd9a5d 100644 --- a/owlplug-client/src/main/resources/fxml/OptionsView.fxml +++ b/owlplug-client/src/main/resources/fxml/OptionsView.fxml @@ -1,141 +1,45 @@ - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - + + + +

+ + + + + + +
+ + \ No newline at end of file diff --git a/owlplug-client/src/main/resources/fxml/Preloader.fxml b/owlplug-client/src/main/resources/fxml/Preloader.fxml index 2970ee6f..f234b868 100644 --- a/owlplug-client/src/main/resources/fxml/Preloader.fxml +++ b/owlplug-client/src/main/resources/fxml/Preloader.fxml @@ -5,7 +5,7 @@ diff --git a/owlplug-client/src/main/resources/fxml/dialogs/ListDirectoryView.fxml b/owlplug-client/src/main/resources/fxml/dialogs/ListDirectoryView.fxml index 749897b2..a4224593 100644 --- a/owlplug-client/src/main/resources/fxml/dialogs/ListDirectoryView.fxml +++ b/owlplug-client/src/main/resources/fxml/dialogs/ListDirectoryView.fxml @@ -3,13 +3,12 @@ - - + \ No newline at end of file diff --git a/owlplug-client/src/main/resources/fxml/options/InstallationOptionsView.fxml b/owlplug-client/src/main/resources/fxml/options/InstallationOptionsView.fxml new file mode 100644 index 00000000..f8803514 --- /dev/null +++ b/owlplug-client/src/main/resources/fxml/options/InstallationOptionsView.fxml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/owlplug-client/src/main/resources/fxml/options/PluginScanOptionsView.fxml b/owlplug-client/src/main/resources/fxml/options/PluginScanOptionsView.fxml new file mode 100644 index 00000000..4dd98c14 --- /dev/null +++ b/owlplug-client/src/main/resources/fxml/options/PluginScanOptionsView.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/owlplug-client/src/main/resources/fxml/options/ProjectsOptionsView.fxml b/owlplug-client/src/main/resources/fxml/options/ProjectsOptionsView.fxml new file mode 100644 index 00000000..4e68372b --- /dev/null +++ b/owlplug-client/src/main/resources/fxml/options/ProjectsOptionsView.fxml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + - + diff --git a/owlplug-client/src/main/resources/fxml/projects/ProjectsView.fxml b/owlplug-client/src/main/resources/fxml/projects/ProjectsView.fxml index e48f5e8e..3dbaf744 100644 --- a/owlplug-client/src/main/resources/fxml/projects/ProjectsView.fxml +++ b/owlplug-client/src/main/resources/fxml/projects/ProjectsView.fxml @@ -6,8 +6,6 @@ - - @@ -36,9 +34,7 @@ -