1818
1919package com .owlplug .core .controllers .settings ;
2020
21+ import atlantafx .base .controls .ToggleSwitch ;
22+ import atlantafx .base .theme .Styles ;
23+ import com .owlplug .controls .Dialog ;
24+ import com .owlplug .controls .DialogLayout ;
2125import com .owlplug .core .components .ApplicationDefaults .Prefs ;
2226import com .owlplug .core .controllers .BaseController ;
27+ import com .owlplug .core .utils .FX ;
28+ import com .owlplug .explore .controllers .NewSourceDialogController ;
29+ import com .owlplug .explore .events .RemoteSourceUpdatedEvent ;
30+ import com .owlplug .explore .model .RemoteSource ;
31+ import com .owlplug .explore .services .ExploreService ;
2332import com .owlplug .plugin .ui .PluginFormatBadgeView ;
2433import java .io .File ;
34+ import java .util .ArrayList ;
35+ import java .util .List ;
36+ import javafx .collections .FXCollections ;
37+ import javafx .collections .ObservableList ;
2538import javafx .fxml .FXML ;
39+ import javafx .geometry .Insets ;
2640import javafx .geometry .Pos ;
41+ import javafx .scene .control .Button ;
2742import javafx .scene .control .CheckBox ;
2843import javafx .scene .control .Label ;
44+ import javafx .scene .control .ListCell ;
45+ import javafx .scene .control .ListView ;
2946import javafx .scene .control .TextField ;
47+ import javafx .scene .control .Tooltip ;
3048import javafx .scene .layout .HBox ;
3149import javafx .scene .layout .Priority ;
3250import javafx .scene .layout .VBox ;
51+ import org .kordamp .ikonli .javafx .FontIcon ;
52+ import org .springframework .beans .factory .annotation .Autowired ;
53+ import org .springframework .context .event .EventListener ;
3354import org .springframework .stereotype .Controller ;
3455
3556@ Controller
3657public class InstallationSettingsController extends BaseController {
3758
59+ @ Autowired
60+ private ExploreService exploreService ;
61+ @ Autowired
62+ private NewSourceDialogController newSourceDialogController ;
63+
64+ @ FXML
65+ private ListView <RemoteSource > sourceListView ;
66+ @ FXML
67+ private Button addSourceButton ;
3868 @ FXML
3969 private CheckBox storeDirectoryCheckBox ;
4070 @ FXML
@@ -50,13 +80,38 @@ public class InstallationSettingsController extends BaseController {
5080 @ FXML
5181 private VBox pathPreviewContainer ;
5282
83+ private final ObservableList <RemoteSource > sourceItems = FXCollections .observableArrayList ();
84+
5385 private Label vst2PathLabel ;
5486 private Label vst3PathLabel ;
5587 private Label auPathLabel ;
5688 private Label lv2PathLabel ;
5789
5890 @ FXML
5991 public void initialize () {
92+ Label sourcePlaceholder = new Label ("No remote sources configured." );
93+ sourcePlaceholder .getStyleClass ().add ("label-disabled" );
94+ sourceListView .setPlaceholder (sourcePlaceholder );
95+ sourceListView .setItems (sourceItems );
96+ sourceListView .setCellFactory (lv -> new ListCell <>() {
97+ @ Override
98+ protected void updateItem (RemoteSource remoteSource , boolean empty ) {
99+ super .updateItem (remoteSource , empty );
100+ setText (null );
101+ setGraphic (empty || remoteSource == null ? null : buildSourceRow (remoteSource ));
102+ }
103+ });
104+
105+ FontIcon addSourceIcon = new FontIcon ("mdi2p-plus" );
106+ addSourceIcon .setIconSize (14 );
107+ addSourceButton .setGraphic (addSourceIcon );
108+ addSourceButton .setOnAction (e -> {
109+ newSourceDialogController .show ();
110+ newSourceDialogController .startCreateSequence ();
111+ });
112+
113+ refreshSources ();
114+
60115 storeDirectoryRow .visibleProperty ().bind (storeDirectoryCheckBox .selectedProperty ());
61116 storeDirectoryRow .managedProperty ().bind (storeDirectoryCheckBox .selectedProperty ());
62117 warningSubDirectory .managedProperty ().bind (warningSubDirectory .visibleProperty ());
@@ -102,6 +157,74 @@ public void refresh() {
102157 storeDirectoryTextField .setText (
103158 getPreferences ().get (Prefs .Explore .STORE_DIRECTORY , "" ));
104159 refreshPathPreview ();
160+ refreshSources ();
161+ }
162+
163+ private void refreshSources () {
164+ List <RemoteSource > sources = new ArrayList <>();
165+ exploreService .getRemoteSources ().forEach (sources ::add );
166+ sourceItems .setAll (sources );
167+ }
168+
169+ private HBox buildSourceRow (RemoteSource remoteSource ) {
170+ VBox infoBox = new VBox (2 );
171+ Label nameLabel = new Label (remoteSource .getName ());
172+ Label urlLabel = new Label (formatUrl (remoteSource .getDisplayUrl ()));
173+ urlLabel .getStyleClass ().add ("label-disabled" );
174+ infoBox .getChildren ().addAll (nameLabel , urlLabel );
175+ HBox .setHgrow (infoBox , Priority .ALWAYS );
176+
177+ ToggleSwitch enabledToggle = new ToggleSwitch ();
178+ enabledToggle .setSelected (remoteSource .isEnabled ());
179+ Tooltip .install (enabledToggle , new Tooltip ("Enable or disable this source" ));
180+ enabledToggle .selectedProperty ().addListener ((obs , old , selected ) ->
181+ exploreService .enableSource (remoteSource , selected ));
182+
183+ Button deleteButton = new Button ();
184+ deleteButton .getStyleClass ().addAll (Styles .BUTTON_ICON , Styles .FLAT );
185+ deleteButton .setGraphic (new FontIcon ("mdi2d-delete-outline" ));
186+ Tooltip .install (deleteButton , new Tooltip ("Remove source" ));
187+ deleteButton .setOnAction (e -> confirmAndDeleteSource (remoteSource ));
188+
189+ HBox row = new HBox (12 , infoBox , enabledToggle , deleteButton );
190+ row .setAlignment (Pos .CENTER_LEFT );
191+ row .setPadding (new Insets (4 ));
192+ return row ;
193+ }
194+
195+ private void confirmAndDeleteSource (RemoteSource remoteSource ) {
196+ Dialog dialog = this .getDialogManager ().newDialog ();
197+ DialogLayout layout = new DialogLayout ();
198+ layout .setHeading (new Label ("Remove source" ));
199+ layout .setBody (new Label ("Do you really want to remove \" " + remoteSource .getName ()
200+ + "\" ? Packages from this source will no longer be available in Explore." ));
201+
202+ Button cancelButton = new Button ("Cancel" );
203+ cancelButton .setOnAction (e -> dialog .close ());
204+
205+ Button removeButton = new Button ("Remove" );
206+ removeButton .getStyleClass ().add ("button-danger" );
207+ removeButton .setOnAction (e -> {
208+ dialog .close ();
209+ exploreService .delete (remoteSource );
210+ refreshSources ();
211+ });
212+
213+ layout .setActions (removeButton , cancelButton );
214+ dialog .setContent (layout );
215+ dialog .show ();
216+ }
217+
218+ private String formatUrl (String url ) {
219+ if (url == null ) {
220+ return null ;
221+ }
222+ return url .replace ("http://" , "" ).replace ("https://" , "" );
223+ }
224+
225+ @ EventListener
226+ private void handle (RemoteSourceUpdatedEvent event ) {
227+ FX .run (this ::refreshSources );
105228 }
106229
107230 private void refreshPathPreview () {
0 commit comments