diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index c6d927e7e..7e62176b7 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -6,5 +6,6 @@
+
\ No newline at end of file
diff --git a/GUI/src/main/java/gui/preferences/Clear.java b/GUI/src/main/java/gui/preferences/Clear.java
index f8a5357f1..0daa6d612 100644
--- a/GUI/src/main/java/gui/preferences/Clear.java
+++ b/GUI/src/main/java/gui/preferences/Clear.java
@@ -20,6 +20,10 @@ public void mainAutoPaste() {
preferences.remove(MAIN_AUTO_PASTE.toString());
}
+ public void mainTheme() {
+ preferences.remove(MAIN_THEME.toString());
+ }
+
public void jobs() {
preferences.remove(JOBS.toString());
}
diff --git a/GUI/src/main/java/gui/preferences/Get.java b/GUI/src/main/java/gui/preferences/Get.java
index 5b3072bdb..befec1b5f 100644
--- a/GUI/src/main/java/gui/preferences/Get.java
+++ b/GUI/src/main/java/gui/preferences/Get.java
@@ -25,6 +25,7 @@ static Get getInstance() {
return INSTANCE;
}
+
public Folders folders() {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = FxGson.addFxSupport(gsonBuilder).setPrettyPrinting().create();
@@ -41,6 +42,10 @@ public boolean mainAutoPaste() {
return preferences.getBoolean(MAIN_AUTO_PASTE.toString(), false);
}
+ public String mainTheme() {
+ return preferences.get(MAIN_THEME.toString(), "Light");
+ }
+
public Jobs jobs() {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = FxGson.addFxSupport(gsonBuilder).setPrettyPrinting().create();
diff --git a/GUI/src/main/java/gui/preferences/Labels.java b/GUI/src/main/java/gui/preferences/Labels.java
index 7f15ce99a..8fc0541d7 100644
--- a/GUI/src/main/java/gui/preferences/Labels.java
+++ b/GUI/src/main/java/gui/preferences/Labels.java
@@ -1,5 +1,5 @@
package gui.preferences;
public enum Labels implements preferences.Labels {
- FOLDERS, MAIN_AUTO_PASTE, JOBS, ALWAYS_AUTO_PASTE
+ FOLDERS, MAIN_AUTO_PASTE, JOBS, ALWAYS_AUTO_PASTE, MAIN_THEME
}
diff --git a/GUI/src/main/java/gui/preferences/Set.java b/GUI/src/main/java/gui/preferences/Set.java
index 5ec37f027..862a6c4f3 100644
--- a/GUI/src/main/java/gui/preferences/Set.java
+++ b/GUI/src/main/java/gui/preferences/Set.java
@@ -14,8 +14,7 @@
import java.nio.file.Paths;
import java.util.prefs.Preferences;
-import static gui.preferences.Labels.FOLDERS;
-import static gui.preferences.Labels.MAIN_AUTO_PASTE;
+import static gui.preferences.Labels.*;
import static properties.Program.JOB_FILE;
public final class Set extends preferences.Set {
@@ -42,6 +41,11 @@ public void mainAutoPaste(boolean isMainAutoPasteEnabled) {
preferences.putBoolean(MAIN_AUTO_PASTE.toString(), isMainAutoPasteEnabled);
}
+ public void mainTheme(String theme) {
+ AppSettings.CLEAR.mainTheme();
+ preferences.put(MAIN_THEME.toString(), theme);
+ }
+
public void jobs(Jobs jobs) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = FxGson.addFxSupport(gsonBuilder).setPrettyPrinting().create();
diff --git a/GUI/src/main/java/gui/support/Constants.java b/GUI/src/main/java/gui/support/Constants.java
index 2e7590e50..00e1307fd 100644
--- a/GUI/src/main/java/gui/support/Constants.java
+++ b/GUI/src/main/java/gui/support/Constants.java
@@ -1,6 +1,8 @@
package gui.support;
import gui.init.Environment;
+import gui.preferences.AppSettings;
+import gui.utils.UIComponentBuilder;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
@@ -13,6 +15,17 @@
import java.util.Objects;
public class Constants extends support.Constants {
+ public static final UIComponentBuilder UI_COMPONENT_BUILDER_INSTANCE = UIComponentBuilder.getInstance();
+ public static final String BUTTON_RELEASED =
+ "-fx-text-fill: white;" +
+ "-fx-font-weight: Bold;" +
+ "-fx-background-color: linear-gradient(rgb(0, 53, 105) 20%, rgb(26, 21, 129) 65%, rgb(0, 0, 65) 100%);" +
+ "-fx-border-color: white;";
+ public static final String BUTTON_PRESSED =
+ "-fx-text-fill: white;" +
+ "-fx-font-weight: Bold;" +
+ " -fx-background-color: linear-gradient(rgb(11, 118, 220) 20%, rgb(33, 31, 131) 65%, rgb(2, 2, 168) 100%);\n" +
+ "-fx-border-color: white;";
public static final String GUI_APPLICATION_TERMINATED = "Drifty GUI (Graphical User Interface) Application Terminated!";
public static final String TRYING_TO_DOWNLOAD_F = "Trying to download \"%s\" ...";
public static final String WRITE_ACCESS_DENIED_F = "Write Access To \"%s\" DENIED!";
@@ -22,20 +35,25 @@ public class Constants extends support.Constants {
public static final double SCREEN_HEIGHT = SCREEN_SIZE.getHeight();
// Graphics Files
- public static final URL DRIFTY_MAIN_PNG = Constants.class.getResource("/Backgrounds/DriftyMain.png");
- public static final URL SAVE_UP_PNG = Constants.class.getResource("/Buttons/Save/SaveUp.png");
- public static final URL SAVE_DOWN_PNG = Constants.class.getResource("/Buttons/Save/SaveDown.png");
- public static final URL START_UP_PNG = Constants.class.getResource("/Buttons/Start/StartUp.png");
- public static final URL START_DOWN_PNG = Constants.class.getResource("/Buttons/Start/StartDown.png");
+ public static final URL DRIFTY_MAIN_PNG = AppSettings.GET.mainTheme().equals("Dark") ? Constants.class.getResource("/Backgrounds/DriftyMainDark.png") : Constants.class.getResource("/Backgrounds/DriftyMainLight.png");
+ public static final URL SAVE_UP_LIGHT_PNG = Constants.class.getResource("/Buttons/Save/SaveUpLight.png");
+ public static final URL SAVE_UP_DARK_PNG = Constants.class.getResource("/Buttons/Save/SaveUpDark.png");
+ public static final URL SAVE_DOWN_LIGHT_PNG = Constants.class.getResource("/Buttons/Save/SaveDownLight.png");
+ public static final URL SAVE_DOWN_DARK_PNG = Constants.class.getResource("/Buttons/Save/SaveDownDark.png");
+ public static final URL START_UP_LIGHT_PNG = Constants.class.getResource("/Buttons/Start/StartUpLight.png");
+ public static final URL START_UP_DARK_PNG = Constants.class.getResource("/Buttons/Start/StartUpDark.png");
+ public static final URL START_DOWN_LIGHT_PNG = Constants.class.getResource("/Buttons/Start/StartDownLight.png");
+ public static final URL START_DOWN_DARK_PNG = Constants.class.getResource("/Buttons/Start/StartDownDark.png");
public static final URL LINK_PNG = Constants.class.getResource("/Labels/Link.png");
public static final URL AUTO_PASTE_PNG = Constants.class.getResource("/Labels/AutoPaste.png");
public static final URL DIRECTORY_PNG = Constants.class.getResource("/Labels/Directory.png");
public static final URL FILENAME_PNG = Constants.class.getResource("/Labels/Filename.png");
public static final URL DRIFTY_ICON = Constants.class.getResource("/Icons/AppIcon.png");
- public static final URL SPLASH = Constants.class.getResource("/Splash.png");
+ public static final URL SPLASH = AppSettings.GET.mainTheme().equals("Dark") ? Constants.class.getResource("/SplashDark.png") : Constants.class.getResource("/SplashLight.png");
// Stylesheets
- public static final URL SCENE_CSS = Constants.class.getResource("/CSS/Scene.css");
+ public static final URL LIGHT_THEME_CSS = Constants.class.getResource("/CSS/LightTheme.css");
+ public static final URL DARK_THEME_CSS = Constants.class.getResource("/CSS/DarkTheme.css");
public static final URL LIST_VIEW_CSS = Constants.class.getResource("/CSS/ListView.css");
public static final URL TEXT_FIELD_CSS = Constants.class.getResource("/CSS/TextField.css");
public static final URL CONTEXT_MENU_CSS = Constants.class.getResource("/CSS/ContextMenu.css");
@@ -51,18 +69,22 @@ public class Constants extends support.Constants {
public static final URL MONACO_TTF = Constants.class.getResource("/Fonts/Monaco.ttf");
// JavaFX Image Objects
- public static final Image IMG_MAIN_GUI_BANNER = new Image(Objects.requireNonNull(DRIFTY_MAIN_PNG).toExternalForm());
- public static final Image IMG_SPLASH = new Image(Objects.requireNonNull(SPLASH).toExternalForm());
+ public static Image imgMainGuiBanner = new Image(Objects.requireNonNull(DRIFTY_MAIN_PNG).toExternalForm());
+ public static Image imgSplash = new Image(Objects.requireNonNull(SPLASH).toExternalForm());
public static final Image IMG_LINK_LABEL = new Image(Objects.requireNonNull(LINK_PNG).toExternalForm());
public static final Image IMG_DIR_LABEL = new Image(Objects.requireNonNull(DIRECTORY_PNG).toExternalForm());
public static final Image IMG_FILENAME_LABEL = new Image(Objects.requireNonNull(FILENAME_PNG).toExternalForm());
public static final Image IMG_AUTO_PASTE_LABEL = new Image(Objects.requireNonNull(AUTO_PASTE_PNG).toExternalForm());
- public static final Image IMG_START_UP = new Image(Objects.requireNonNull(START_UP_PNG).toExternalForm());
- public static final Image IMG_START_DOWN = new Image(Objects.requireNonNull(START_DOWN_PNG).toExternalForm());
- public static final Image IMG_SAVE_UP = new Image(Objects.requireNonNull(SAVE_UP_PNG).toExternalForm());
- public static final Image IMG_SAVE_DOWN = new Image(Objects.requireNonNull(SAVE_DOWN_PNG).toExternalForm());
+ public static final Image IMG_START_UP_LIGHT = new Image(Objects.requireNonNull(START_UP_LIGHT_PNG).toExternalForm());
+ public static final Image IMG_START_UP_DARK = new Image(Objects.requireNonNull(START_UP_DARK_PNG).toExternalForm());
+ public static final Image IMG_START_DOWN_LIGHT = new Image(Objects.requireNonNull(START_DOWN_LIGHT_PNG).toExternalForm());
+ public static final Image IMG_START_DOWN_DARK = new Image(Objects.requireNonNull(START_DOWN_DARK_PNG).toExternalForm());
+ public static final Image IMG_SAVE_UP_LIGHT = new Image(Objects.requireNonNull(SAVE_UP_LIGHT_PNG).toExternalForm());
+ public static final Image IMG_SAVE_UP_DARK = new Image(Objects.requireNonNull(SAVE_UP_DARK_PNG).toExternalForm());
+ public static final Image IMG_SAVE_DOWN_LIGHT = new Image(Objects.requireNonNull(SAVE_DOWN_LIGHT_PNG).toExternalForm());
+ public static final Image IMG_SAVE_DOWN_DARK = new Image(Objects.requireNonNull(SAVE_DOWN_DARK_PNG).toExternalForm());
- // Methods for obtaining consistent Stages and Scenes
+ // Methods for getting consistent Stages and Scenes
public static Stage getStage(String title, boolean isPrimaryStage) {
Stage stage = new Stage();
Image icon = new Image(Objects.requireNonNull(DRIFTY_ICON).toExternalForm());
@@ -82,7 +104,7 @@ public static Stage getStage(String title, boolean isPrimaryStage) {
public static Scene getScene(Parent root) {
Scene scene = new Scene(root);
- addCSS(scene, CHECK_BOX_CSS, CONTEXT_MENU_CSS, LABEL_CSS, LIST_VIEW_CSS, MENU_CSS, PROGRESS_BAR_CSS, SCENE_CSS, SCROLL_PANE_CSS, TEXT_FIELD_CSS, V_BOX_CSS, BUTTON_CSS);
+ addCSS(scene, CHECK_BOX_CSS, CONTEXT_MENU_CSS, LABEL_CSS, LIST_VIEW_CSS, MENU_CSS, LIGHT_THEME_CSS, PROGRESS_BAR_CSS, SCROLL_PANE_CSS, TEXT_FIELD_CSS, V_BOX_CSS, BUTTON_CSS);
return scene;
}
diff --git a/GUI/src/main/java/gui/utils/UIComponentBuilder.java b/GUI/src/main/java/gui/utils/UIComponentBuilder.java
new file mode 100644
index 000000000..66be5f215
--- /dev/null
+++ b/GUI/src/main/java/gui/utils/UIComponentBuilder.java
@@ -0,0 +1,72 @@
+package gui.utils;
+
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Hyperlink;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+import javafx.scene.paint.LinearGradient;
+import javafx.scene.paint.Paint;
+import javafx.scene.text.Font;
+import main.Drifty_GUI;
+
+import java.util.Objects;
+
+import static gui.support.Constants.MONACO_TTF;
+
+public class UIComponentBuilder {
+ private static UIComponentBuilder instance;
+
+ public static UIComponentBuilder getInstance() {
+ if (instance == null) {
+ instance = new UIComponentBuilder();
+ }
+ return instance;
+ }
+
+ public Label buildLabel() {
+ Label label = new Label("");
+ label.setFont(new Font(Objects.requireNonNull(MONACO_TTF).toExternalForm(), 20 * .75));
+ label.prefWidth(Double.MAX_VALUE);
+ label.setAlignment(Pos.CENTER);
+ return label;
+ }
+
+ public Label buildLabel(String text, Font font, Paint textFill) {
+ Label label = new Label(text);
+ label.setAlignment(Pos.TOP_CENTER);
+ label.setFont(font);
+ label.setTextFill(textFill);
+ return label;
+ }
+
+ public HBox buildHBox(Node node) {
+ HBox hbox = new HBox(node);
+ hbox.setAlignment(Pos.CENTER);
+ return hbox;
+ }
+
+ public ImageView buildImageView(Image image, double scale) {
+ ImageView imageView = new ImageView(image);
+ imageView.setPreserveRatio(true);
+ imageView.setFitWidth(image.getWidth() * scale);
+ return imageView;
+ }
+
+ public TextField buildTextField() {
+ TextField tf = new TextField("");
+ tf.setPrefWidth(Double.MAX_VALUE);
+ return tf;
+ }
+
+ public Hyperlink buildHyperlink(String text, Font font, LinearGradient fill, String url) {
+ Hyperlink link = new Hyperlink(text);
+ link.setFont(font);
+ link.setTextFill(fill);
+ link.setOnAction(e -> Drifty_GUI.INSTANCE.openWebsite(url));
+ return link;
+ }
+}
\ No newline at end of file
diff --git a/GUI/src/main/java/main/Drifty_GUI.java b/GUI/src/main/java/main/Drifty_GUI.java
index 6f6ad07d4..13402802b 100644
--- a/GUI/src/main/java/main/Drifty_GUI.java
+++ b/GUI/src/main/java/main/Drifty_GUI.java
@@ -6,18 +6,14 @@
import gui.utils.MessageBroker;
import javafx.application.Application;
import javafx.application.Preloader;
-import javafx.geometry.Insets;
-import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
-import javafx.scene.control.*;
-import javafx.scene.image.ImageView;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuBar;
+import javafx.scene.control.MenuItem;
import javafx.scene.input.Clipboard;
import javafx.scene.layout.AnchorPane;
-import javafx.scene.layout.VBox;
-import javafx.scene.paint.LinearGradient;
-import javafx.scene.text.Font;
-import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import properties.Mode;
import ui.*;
@@ -26,12 +22,14 @@
import static gui.support.Constants.GUI_APPLICATION_TERMINATED;
import static javafx.scene.layout.AnchorPane.*;
import static support.Constants.DRIFTY_WEBSITE_URL;
-import static support.Constants.VERSION_NUMBER;
public class Drifty_GUI extends Application {
+ public static final Drifty_GUI INSTANCE = new Drifty_GUI();
private static MessageBroker msgBroker;
+ private static Scene scene;
+ private final Settings settingsInstance = new Settings();
+ private About aboutInstance;
private Stage primaryStage;
- private Scene scene;
public static void main(String[] args) {
System.setProperty("javafx.preloader", Splash.class.getCanonicalName());
@@ -65,9 +63,13 @@ private void createScene() {
MenuBar menu = menuBar(getMenuItemsOfMenu(), getEditMenu(), getWindowMenu(), getHelpMenu());
ap.getChildren().add(gridPane);
ap.getChildren().add(menu);
+
placeControl(gridPane, 40, 40, 40, 40);
placeControl(menu, 0, 0, 0, -1);
scene = Constants.getScene(ap);
+ if (AppSettings.GET.mainTheme().equals("Dark")) {
+ Constants.addCSS(scene, Constants.DARK_THEME_CSS);
+ }
scene.setOnContextMenuRequested(e -> getRightClickContextMenu().show(scene.getWindow(), e.getScreenX(), e.getScreenY()));
menu.setUseSystemMenuBar(true);
UIController.initLogic(gridPane);
@@ -116,6 +118,10 @@ private MenuBar menuBar(Menu... menus) {
return new MenuBar(menus);
}
+ public static Scene getScene() {
+ return scene;
+ }
+
private Menu getWindowMenu() {
Menu menu = new Menu("Window");
MenuItem fullScreen = new MenuItem("Toggle Full Screen");
@@ -138,48 +144,10 @@ private Menu getHelpMenu() {
securityVulnerability.setOnAction(e -> openWebsite("https://github.com/SaptarshiSarkar12/Drifty/security/advisories/new"));
feature.setOnAction(e -> openWebsite("https://github.com/SaptarshiSarkar12/Drifty/issues/new?assignees=&labels=feature+%E2%9C%A8%2CApp+%F0%9F%92%BB&projects=&template=feature-request-application.yaml&title=%5BFEATURE%5D+"));
about.setOnAction(event -> {
- Stage stage = Constants.getStage("About Drifty", false);
- VBox root = new VBox(10);
- root.setPadding(new Insets(10));
- root.setAlignment(Pos.TOP_CENTER);
- ImageView appIcon = new ImageView(Constants.IMG_SPLASH);
- appIcon.setFitWidth(Constants.SCREEN_WIDTH * .2);
- appIcon.setFitHeight(Constants.SCREEN_HEIGHT * .2);
- appIcon.setPreserveRatio(true);
- Label lblDescription = new Label("An Open-Source Interactive File Downloader System");
- lblDescription.setFont(Font.font("Arial", FontWeight.BOLD, 24));
- lblDescription.setTextFill(LinearGradient.valueOf("linear-gradient(to right, #8e2de2, #4a00e0)"));
- Label lblDriftyVersion = new Label("Drifty " + VERSION_NUMBER);
- Label lblYtDlpVersion = new Label("yt-dlp version: " + AppSettings.GET.ytDlpVersion());
- lblDriftyVersion.setFont(Font.font("Arial", FontWeight.BOLD, 20));
- lblDriftyVersion.setTextFill(LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)"));
- lblYtDlpVersion.setFont(Font.font("Arial", FontWeight.BOLD, 14));
- lblYtDlpVersion.setTextFill(LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)"));
- Hyperlink websiteLink = new Hyperlink("Website");
- websiteLink.setFont(Font.font("Arial", FontWeight.BOLD, 18));
- websiteLink.setTextFill(LinearGradient.valueOf("linear-gradient(to right, #fc466b, #3f5efb)"));
- websiteLink.setOnAction(e -> openWebsite("https://saptarshisarkar12.github.io/Drifty"));
- Hyperlink discordLink = new Hyperlink("Join Discord");
- discordLink.setFont(Font.font("Arial", FontWeight.BOLD, 18));
- discordLink.setTextFill(LinearGradient.valueOf("linear-gradient(to right, #00d956, #0575e6)"));
- discordLink.setOnAction(e -> openWebsite("https://discord.gg/DeT4jXPfkG"));
- Hyperlink githubLink = new Hyperlink("Contribute to Drifty");
- githubLink.setFont(Font.font("Arial", FontWeight.BOLD, 18));
- githubLink.setTextFill(LinearGradient.valueOf("linear-gradient(to right, #009fff, #ec2f4b)"));
- githubLink.setOnAction(e -> openWebsite("https://github.com/SaptarshiSarkar12/Drifty"));
- root.getChildren().addAll(appIcon, lblDescription, lblDriftyVersion, lblYtDlpVersion);
- if (AppSettings.GET.isFfmpegWorking() && AppSettings.GET.ffmpegVersion() != null && !AppSettings.GET.ffmpegVersion().isEmpty()) {
- Label lblFfmpegVersion = new Label("FFMPEG version: " + AppSettings.GET.ffmpegVersion());
- lblFfmpegVersion.setFont(Font.font("Arial", FontWeight.BOLD, 14));
- lblFfmpegVersion.setTextFill(LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)"));
- root.getChildren().add(lblFfmpegVersion);
+ if (aboutInstance == null) {
+ aboutInstance = new About();
}
- root.getChildren().addAll(websiteLink, discordLink, githubLink);
- Scene aboutScene = Constants.getScene(root);
- stage.setMinHeight(Constants.SCREEN_HEIGHT * .55);
- stage.setMinWidth(Constants.SCREEN_WIDTH * .5);
- stage.setScene(aboutScene);
- stage.show();
+ aboutInstance.show();
});
menu.getItems().setAll(contactUs, contribute, bug, securityVulnerability, feature, about);
return menu;
@@ -188,13 +156,15 @@ private Menu getHelpMenu() {
private Menu getEditMenu() {
Menu menu = new Menu("Edit");
MenuItem wipeHistory = new MenuItem("Clear Download History");
+ MenuItem settings = new MenuItem("Settings");
wipeHistory.setOnAction(e -> {
ConfirmationDialog ask = new ConfirmationDialog("Clear Download History", "Are you sure you wish to wipe out all of your download history?\n(This will NOT delete any downloaded files)", false);
if (ask.getResponse().isYes()) {
UIController.clearJobHistory();
}
});
- menu.getItems().addAll(wipeHistory);
+ settings.setOnAction(e -> settingsInstance.show());
+ menu.getItems().addAll(wipeHistory, settings);
return menu;
}
@@ -212,7 +182,7 @@ private ContextMenu getRightClickContextMenu() {
return contextMenu;
}
- protected void openWebsite(String websiteURL) {
+ public void openWebsite(String websiteURL) {
getHostServices().showDocument(websiteURL);
}
diff --git a/GUI/src/main/java/ui/About.java b/GUI/src/main/java/ui/About.java
new file mode 100644
index 000000000..2d156d84a
--- /dev/null
+++ b/GUI/src/main/java/ui/About.java
@@ -0,0 +1,103 @@
+package ui;
+
+import gui.preferences.AppSettings;
+import gui.support.Constants;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.Hyperlink;
+import javafx.scene.control.Label;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.LinearGradient;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontWeight;
+import javafx.stage.Stage;
+
+import static gui.support.Constants.UI_COMPONENT_BUILDER_INSTANCE;
+import static support.Constants.VERSION_NUMBER;
+
+public class About {
+ private static Scene aboutScene;
+ private static final ImageView IV_SPLASH = new ImageView(Constants.imgSplash);
+ private Label lblDescription;
+ private Label lblDriftyVersion;
+ private Label lblYtDlpVersion;
+ private Hyperlink websiteLink;
+ private Hyperlink discordLink;
+ private Hyperlink githubLink;
+ private Stage stage;
+
+ private void setupLayout() {
+ VBox aboutRoot = new VBox(10);
+ aboutRoot.setPadding(new Insets(10));
+ aboutRoot.setAlignment(Pos.TOP_CENTER);
+ setupImageView();
+ createLabels();
+ createHyperlinks();
+ setupStage();
+ aboutRoot.getChildren().addAll(IV_SPLASH, lblDescription, lblDriftyVersion, lblYtDlpVersion);
+ if (AppSettings.GET.isFfmpegWorking() && AppSettings.GET.ffmpegVersion() != null && !AppSettings.GET.ffmpegVersion().isEmpty()) {
+ Label lblFfmpegVersion = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("FFMPEG version: " + AppSettings.GET.ffmpegVersion(), Font.font("Arial", FontWeight.BOLD, 14), LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)"));
+ aboutRoot.getChildren().add(lblFfmpegVersion);
+ }
+ aboutRoot.getChildren().addAll(websiteLink, discordLink, githubLink);
+ aboutScene = Constants.getScene(aboutRoot);
+ applyThemeSettings(aboutRoot);
+ }
+
+ private void setupImageView() {
+ IV_SPLASH.setFitWidth(Constants.SCREEN_WIDTH * .2);
+ IV_SPLASH.setFitHeight(Constants.SCREEN_HEIGHT * .2);
+ IV_SPLASH.setPreserveRatio(true);
+ }
+
+ private void setupStage() {
+ stage = Constants.getStage("About Drifty", false);
+ stage.setMinHeight(Constants.SCREEN_HEIGHT * .55);
+ stage.setMinWidth(Constants.SCREEN_WIDTH * .5);
+ }
+
+ private void applyThemeSettings(VBox aboutRoot) {
+ if (AppSettings.GET.mainTheme().equals("Dark")) {
+ Constants.addCSS(aboutScene, Constants.DARK_THEME_CSS);
+ for (Node node : aboutRoot.getChildren()) {
+ if (node instanceof Label) {
+ ((Label) node).setTextFill(Color.WHITE);
+ }
+ }
+ }
+ }
+
+ public void show() {
+ if (stage != null && stage.isShowing()) {
+ stage.toFront();
+ } else {
+ setupLayout();
+ stage.setScene(aboutScene);
+ stage.showAndWait();
+ }
+ }
+
+ private void createLabels() {
+ lblDescription = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("An Open-Source Interactive File Downloader System", Font.font("Arial", FontWeight.BOLD, 24), LinearGradient.valueOf("linear-gradient(to right, #8e2de2, #4a00e0)"));
+ lblDriftyVersion = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("Drifty " + VERSION_NUMBER, Font.font("Arial", FontWeight.BOLD, 20), LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)"));
+ lblYtDlpVersion = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("yt-dlp version: " + AppSettings.GET.ytDlpVersion(), Font.font("Arial", FontWeight.BOLD, 14), LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)"));
+ }
+
+ private void createHyperlinks() {
+ websiteLink = UI_COMPONENT_BUILDER_INSTANCE.buildHyperlink("Website", Font.font("Arial", FontWeight.BOLD, 18), LinearGradient.valueOf("linear-gradient(to right, #fc466b, #3f5efb)"), "https://saptarshisarkar12.github.io/Drifty");
+ discordLink = UI_COMPONENT_BUILDER_INSTANCE.buildHyperlink("Join Discord", Font.font("Arial", FontWeight.BOLD, 18), LinearGradient.valueOf("linear-gradient(to right, #00d956, #0575e6)"), "https://discord.gg/DeT4jXPfkG");
+ githubLink = UI_COMPONENT_BUILDER_INSTANCE.buildHyperlink("Contribute to Drifty", Font.font("Arial", FontWeight.BOLD, 18), LinearGradient.valueOf("linear-gradient(to right, #009fff, #ec2f4b)"), "https://github.com/SaptarshiSarkar12/Drifty");
+ }
+
+ public static Scene getScene() {
+ return aboutScene;
+ }
+
+ public static ImageView getIvSplash() {
+ return IV_SPLASH;
+ }
+}
diff --git a/GUI/src/main/java/ui/ConfirmationDialog.java b/GUI/src/main/java/ui/ConfirmationDialog.java
index a0a3c33db..52ba5589d 100644
--- a/GUI/src/main/java/ui/ConfirmationDialog.java
+++ b/GUI/src/main/java/ui/ConfirmationDialog.java
@@ -1,6 +1,8 @@
package ui;
import gui.init.Environment;
+
+import gui.preferences.AppSettings;
import gui.support.Constants;
import javafx.application.Platform;
import javafx.event.ActionEvent;
@@ -24,8 +26,11 @@ enum State {
YES_NO, OK, FILENAME
}
+ private static Scene scene;
private final State state;
private final String lf = System.lineSeparator();
+ private static Button btnNo;
+ private static Button btnYes;
private double width = 200;
private double height = 150;
private Stage stage;
@@ -78,7 +83,6 @@ private void finish() {
private Button newButton(String text, EventHandler event) {
Button button = new Button(text);
- button.setFont(Constants.getMonaco(17));
button.setMinWidth(80);
button.setMaxWidth(80);
button.setPrefWidth(80);
@@ -101,11 +105,11 @@ private void createControls() {
message.setWrapText(true);
message.setTextAlignment(TextAlignment.CENTER);
}
- Button btnYes = newButton("Yes", e -> {
+ btnYes = newButton("Yes", e -> {
answer.setAnswer(true);
stage.close();
});
- Button btnNo = newButton("No", e -> {
+ btnNo = newButton("No", e -> {
answer.setAnswer(false);
stage.close();
});
@@ -146,7 +150,14 @@ public GetConfirmationDialogResponse getResponse() {
private void showScene() {
stage = Constants.getStage(windowTitle, false);
- Scene scene = Constants.getScene(vbox);
+ scene = Constants.getScene(vbox);
+ if (AppSettings.GET.mainTheme().equals("Dark")) {
+ Theme.applyTheme("Dark", scene);
+ Theme.changeButtonStyle(true, btnYes);
+ Theme.changeButtonStyle(true, btnNo);
+ } else {
+ Theme.applyTheme("Light", scene);
+ }
stage.setWidth(width);
stage.setHeight(height);
stage.setScene(scene);
@@ -163,4 +174,16 @@ private void showScene() {
public String getFilename() {
return filename;
}
+
+ static Button getBtnNo() {
+ return btnNo;
+ }
+
+ static Scene getScene() {
+ return scene;
+ }
+
+ static Button getBtnYes() {
+ return btnYes;
+ }
}
diff --git a/GUI/src/main/java/ui/MainGridPane.java b/GUI/src/main/java/ui/MainGridPane.java
index 4e930ae8e..a2e47d566 100644
--- a/GUI/src/main/java/ui/MainGridPane.java
+++ b/GUI/src/main/java/ui/MainGridPane.java
@@ -1,10 +1,10 @@
package ui;
+import gui.preferences.AppSettings;
import gui.support.Constants;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
-import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
@@ -12,33 +12,30 @@
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
-import javafx.scene.text.Font;
import support.Job;
-import java.util.Objects;
-
-import static gui.support.Constants.MONACO_TTF;
+import static gui.support.Constants.UI_COMPONENT_BUILDER_INSTANCE;
public class MainGridPane extends GridPane {
- public final ImageView ivLogo = newImageView(Constants.IMG_MAIN_GUI_BANNER, .45);
+ public static ImageView ivLogo = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(Constants.imgMainGuiBanner, .45);
public final ProgressBar pBar = pBar();
public final ListView listView = listView();
- public final ImageView ivLink = newImageView(Constants.IMG_LINK_LABEL, .7);
- public final ImageView ivDir = newImageView(Constants.IMG_DIR_LABEL, .7);
- public final ImageView ivFilename = newImageView(Constants.IMG_FILENAME_LABEL, .7);
- public final ImageView ivAutoPaste = newImageView(Constants.IMG_AUTO_PASTE_LABEL, .7);
- public final Button btnStart = newButton(Constants.IMG_START_UP, Constants.IMG_START_DOWN);
- public final Button btnSave = newButton(Constants.IMG_SAVE_UP, Constants.IMG_SAVE_DOWN);
+ public final ImageView ivLink = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(Constants.IMG_LINK_LABEL, .7);
+ public final ImageView ivDir = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(Constants.IMG_DIR_LABEL, .7);
+ public final ImageView ivFilename = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(Constants.IMG_FILENAME_LABEL, .7);
+ public final ImageView ivAutoPaste = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(Constants.IMG_AUTO_PASTE_LABEL, .7);
+ public final Button btnStart = AppSettings.GET.mainTheme().equals("Dark") ? newButton(Constants.IMG_START_UP_DARK, Constants.IMG_START_DOWN_DARK) : newButton(Constants.IMG_START_UP_LIGHT, Constants.IMG_START_DOWN_LIGHT);
+ public final Button btnSave = AppSettings.GET.mainTheme().equals("Dark") ? newButton(Constants.IMG_SAVE_UP_DARK, Constants.IMG_SAVE_DOWN_DARK) : newButton(Constants.IMG_SAVE_UP_LIGHT, Constants.IMG_SAVE_DOWN_LIGHT);
public final CheckBox cbAutoPaste = new CheckBox();
private final HBox boxAutoPaste = boxAutoPaste();
- private final HBox boxLogo = newHBox(ivLogo);
- public final Label lblLinkOut = newLabel();
- public final Label lblDirOut = newLabel();
- public final Label lblFilenameOut = newLabel();
- public final Label lblDownloadInfo = newLabel();
- public final TextField tfLink = newTextField();
- public final TextField tfDir = newTextField();
- public final TextField tfFilename = newTextField();
+ public static HBox boxLogo = UI_COMPONENT_BUILDER_INSTANCE.buildHBox(ivLogo);
+ public final Label lblLinkOut = UI_COMPONENT_BUILDER_INSTANCE.buildLabel();
+ public final Label lblDirOut = UI_COMPONENT_BUILDER_INSTANCE.buildLabel();
+ public final Label lblFilenameOut = UI_COMPONENT_BUILDER_INSTANCE.buildLabel();
+ public final Label lblDownloadInfo = UI_COMPONENT_BUILDER_INSTANCE.buildLabel();
+ public final TextField tfLink = UI_COMPONENT_BUILDER_INSTANCE.buildTextField();
+ public final TextField tfDir = UI_COMPONENT_BUILDER_INSTANCE.buildTextField();
+ public final TextField tfFilename = UI_COMPONENT_BUILDER_INSTANCE.buildTextField();
public MainGridPane() {
super();
@@ -127,20 +124,6 @@ protected void updateItem(Job item, boolean empty) {
return listView;
}
- private Label newLabel() {
- Label label = new Label("");
- label.setFont(new Font(Objects.requireNonNull(MONACO_TTF).toExternalForm(), 20 * .75));
- label.setPrefWidth(Double.MAX_VALUE);
- label.getStyleClass().add("outline");
- return label;
- }
-
- private TextField newTextField() {
- TextField tf = new TextField("");
- tf.setPrefWidth(Double.MAX_VALUE);
- return tf;
- }
-
private ProgressBar pBar() {
ProgressBar pb = new ProgressBar(0.0);
pb.setPrefWidth(Double.MAX_VALUE);
@@ -148,35 +131,16 @@ private ProgressBar pBar() {
return pb;
}
- private HBox newHBox(Node node) {
- HBox box = new HBox(node);
- box.setAlignment(Pos.CENTER);
- return box;
- }
-
private HBox boxAutoPaste() {
HBox box = new HBox(10, ivAutoPaste, cbAutoPaste);
box.setAlignment(Pos.CENTER_RIGHT);
return box;
}
- private ImageView newImageView(Image image, double scale) {
- ImageView iv = new ImageView(image);
- double width = image.getWidth();
- iv.setPreserveRatio(true);
- iv.setFitWidth(width * scale);
- return iv;
- }
-
private Button newButton(Image imageUp, Image imageDown) {
Button button = new Button();
- ImageView imageViewUp = new ImageView(imageUp);
- ImageView imageViewDn = new ImageView(imageDown);
- double width = imageUp.getWidth();
- imageViewUp.setPreserveRatio(true);
- imageViewUp.setFitWidth(width * 0.45);
- imageViewDn.setPreserveRatio(true);
- imageViewDn.setFitWidth(width * 0.45);
+ ImageView imageViewUp = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(imageUp, 0.45);
+ ImageView imageViewDn = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(imageDown, 0.45);
button.setOnMousePressed(e -> button.setGraphic(imageViewDn));
button.setOnMouseReleased(e -> button.setGraphic(imageViewUp));
button.setGraphic(imageViewUp);
diff --git a/GUI/src/main/java/ui/Settings.java b/GUI/src/main/java/ui/Settings.java
new file mode 100644
index 000000000..1439b9a8e
--- /dev/null
+++ b/GUI/src/main/java/ui/Settings.java
@@ -0,0 +1,185 @@
+package ui;
+
+import gui.preferences.AppSettings;
+import gui.support.Constants;
+import javafx.geometry.HPos;
+import javafx.geometry.Insets;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.*;
+import javafx.scene.layout.ColumnConstraints;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Priority;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.LinearGradient;
+import javafx.scene.paint.Paint;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontWeight;
+import javafx.stage.DirectoryChooser;
+import javafx.stage.Stage;
+import main.Drifty_GUI;
+
+import java.io.File;
+
+import static gui.support.Constants.UI_COMPONENT_BUILDER_INSTANCE;
+
+public class Settings {
+ private static Button selectDirectoryButton;
+ private static Scene settingsScene;
+ private static TextField tfCurrentDirectory;
+ private CheckBox autoPasteCheckbox;
+ private Label lblDefaultDownloadDir;
+ private Label lblTheme;
+ private Label lblSettingsHeading;
+ private Label lblAutoPaste;
+ private ChoiceBox themeChoiceBox;
+ private Stage stage;
+ private GridPane root;
+
+ private void initializeComponents() {
+ initializeUIComponents();
+ configureScene();
+ }
+
+ private void initializeUIComponents() {
+ setupThemeChoice();
+ createTfDirectory();
+ createLabels();
+ createAutoPasteCheck();
+ createDirectoryButton();
+ }
+
+ private void configureScene() {
+ stage = Constants.getStage("Settings", false);
+ stage.setMinHeight(Constants.SCREEN_HEIGHT * .55);
+ stage.setMinWidth(Constants.SCREEN_WIDTH * .5);
+ stage.setMaxHeight(Constants.SCREEN_HEIGHT * .6);
+ stage.setMaxWidth(Constants.SCREEN_WIDTH * .6);
+ configureLayout();
+ settingsScene = Constants.getScene(root);
+ Constants.addCSS(settingsScene, Constants.LIGHT_THEME_CSS);
+ setInitialTheme(AppSettings.GET.mainTheme());
+ }
+
+ private void configureLayout() {
+ root = new GridPane();
+ ColumnConstraints column1 = new ColumnConstraints(); // For the first column, it will take 50% the width of the window
+ column1.setPercentWidth(50);
+ ColumnConstraints column2 = new ColumnConstraints(); // For the second column, it will take 50% the width of the window
+ column2.setPercentWidth(50);
+ root.getColumnConstraints().addAll(column1, column2);
+ root.setHgap(20);
+ root.setVgap(10);
+ root.setPadding(new Insets(10, 20, 20, 20));
+ addComponents();
+ setHAlignments();
+ setHGrowsAlways(lblSettingsHeading, lblAutoPaste, autoPasteCheckbox, lblTheme, themeChoiceBox, lblDefaultDownloadDir, tfCurrentDirectory, selectDirectoryButton);
+ }
+
+ public void show() {
+ if (stage != null && stage.isShowing()) {
+ stage.toFront();
+ } else {
+ initializeComponents();
+ stage.setScene(settingsScene);
+ stage.showAndWait();
+ }
+ }
+
+ private void setHAlignments() {
+ GridPane.setHalignment(lblSettingsHeading, HPos.CENTER);
+ GridPane.setHalignment(lblAutoPaste, HPos.RIGHT);
+ GridPane.setHalignment(lblTheme, HPos.RIGHT);
+ GridPane.setHalignment(lblDefaultDownloadDir, HPos.RIGHT);
+ GridPane.setHalignment(selectDirectoryButton, HPos.CENTER);
+ }
+
+ private void setHGrowsAlways(Node... nodes) {
+ for (Node node : nodes) {
+ GridPane.setHgrow(node, Priority.ALWAYS);
+ }
+ }
+
+ private void addComponents() {
+ root.add(lblSettingsHeading, 0, 0, 2, 1);
+ root.add(lblAutoPaste, 0, 1);
+ root.add(autoPasteCheckbox, 1, 1);
+ root.add(lblTheme, 0, 2);
+ root.add(themeChoiceBox, 1, 2);
+ root.add(lblDefaultDownloadDir, 0, 3);
+ root.add(tfCurrentDirectory, 1, 3);
+ root.add(selectDirectoryButton, 1, 4, 2, 1);
+ }
+
+ private void setInitialTheme(String theme) {
+ boolean isDark = theme.equals("Dark");
+ Constants.addCSS(settingsScene, isDark ? Constants.DARK_THEME_CSS : Constants.LIGHT_THEME_CSS);
+ applyStyleToLabels(isDark, lblTheme, lblAutoPaste, lblDefaultDownloadDir, lblSettingsHeading);
+ tfCurrentDirectory.setStyle("-fx-text-fill: " + (isDark ? "white" : "black") + " ; -fx-font-weight: Bold");
+ }
+
+ private void applyStyleToLabels(boolean isDark, Label... labels) {
+ Color darkThemeTextFill = Color.WHITE;
+ LinearGradient lightThemeTextFill = LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)");
+ for (Label label : labels) {
+ label.setTextFill(isDark ? darkThemeTextFill : lightThemeTextFill);
+ }
+ }
+
+ private void setupThemeChoice() {
+ themeChoiceBox = new ChoiceBox<>();
+ themeChoiceBox.getItems().addAll("Dark Theme", "Light Theme");
+ themeChoiceBox.setValue(AppSettings.GET.mainTheme().equals("Dark") ? "Dark Theme" : "Light Theme");
+ themeChoiceBox.setOnAction(e -> Theme.applyTheme(themeChoiceBox.getValue().equals("Dark Theme") ? "Dark" : "Light", settingsScene, Drifty_GUI.getScene(), About.getScene(), UIController.getInfoScene(), ConfirmationDialog.getScene()));
+ }
+
+ private void createAutoPasteCheck() {
+ autoPasteCheckbox = new CheckBox();
+ autoPasteCheckbox.setSelected(AppSettings.GET.mainAutoPaste());
+ autoPasteCheckbox.setMaxWidth(5.0);
+ autoPasteCheckbox.selectedProperty().addListener(((observable, oldValue, newValue) -> AppSettings.SET.mainAutoPaste(newValue)));
+ }
+
+ private void createLabels() {
+ Paint textFill = LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)");
+ lblSettingsHeading = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("Settings", Font.font("monospace", FontWeight.EXTRA_BOLD, 100), textFill);
+ lblAutoPaste = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("Auto-Paste", Font.font("Arial", FontWeight.EXTRA_BOLD, 20), textFill);
+ lblTheme = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("Theme", Font.font("Arial", FontWeight.EXTRA_BOLD, 20), textFill);
+ lblDefaultDownloadDir = UI_COMPONENT_BUILDER_INSTANCE.buildLabel("Default Download Directory", Font.font("Arial", FontWeight.BOLD, 20), textFill);
+ }
+
+ private void createTfDirectory() {
+ tfCurrentDirectory = new TextField(UIController.form.tfDir.getText());
+ tfCurrentDirectory.setMaxWidth(Double.MAX_VALUE);
+ tfCurrentDirectory.setEditable(false);
+ }
+
+ private void createDirectoryButton() {
+ selectDirectoryButton = new Button("Select Directory");
+ if (AppSettings.GET.mainTheme().equals("Dark")) {
+ selectDirectoryButton.setStyle(Constants.BUTTON_RELEASED);
+ selectDirectoryButton.setOnMousePressed(e -> selectDirectoryButton.setStyle(Constants.BUTTON_PRESSED));
+ selectDirectoryButton.setOnMouseReleased(e -> selectDirectoryButton.setStyle(Constants.BUTTON_RELEASED));
+ } else {
+ selectDirectoryButton.getStyleClass().add("button");
+ }
+ selectDirectoryButton.setOnAction(e -> handleDirectorySelection());
+ }
+
+ private void handleDirectorySelection() {
+ DirectoryChooser chooser = new DirectoryChooser();
+ chooser.setInitialDirectory(new File(System.getProperty("user.home")));
+ File selectedDirectory = chooser.showDialog(this.stage);
+ String directoryPath = (selectedDirectory != null ? selectedDirectory.getAbsolutePath() : AppSettings.GET.lastDownloadFolder());
+ UIController.form.tfDir.setText(directoryPath);
+ tfCurrentDirectory.setText(directoryPath);
+ }
+
+ public static TextField getTfCurrentDirectory() {
+ return tfCurrentDirectory;
+ }
+
+ public static Button getSelectDirectoryButton() {
+ return selectDirectoryButton;
+ }
+}
diff --git a/GUI/src/main/java/ui/Theme.java b/GUI/src/main/java/ui/Theme.java
new file mode 100644
index 000000000..7b5240f0d
--- /dev/null
+++ b/GUI/src/main/java/ui/Theme.java
@@ -0,0 +1,134 @@
+package ui;
+
+import gui.preferences.AppSettings;
+import gui.support.Constants;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.LinearGradient;
+import javafx.scene.paint.Paint;
+import javafx.scene.text.Text;
+
+import java.util.Objects;
+
+import static gui.support.Constants.UI_COMPONENT_BUILDER_INSTANCE;
+
+public class Theme {
+ public static void applyTheme(String theme, Scene... scenes) {
+ boolean isDark = theme.equals("Dark");
+ AppSettings.SET.mainTheme(theme);
+ updateCSS(isDark, scenes);
+ updateTextColors(isDark, scenes);
+ changeImages(theme);
+ updateButtonStyles(isDark, theme);
+ }
+
+ private static void setupButton(Image imageUp, Image imageDown, Button button) {
+ ImageView imageViewUp = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(imageUp, 0.45);
+ ImageView imageViewDown = UI_COMPONENT_BUILDER_INSTANCE.buildImageView(imageDown, 0.45);
+ button.setOnMousePressed(ev -> button.setGraphic(imageViewDown));
+ button.setOnMouseReleased(ev -> button.setGraphic(imageViewUp));
+ button.setGraphic(imageViewUp);
+ }
+
+ private static void setupButtonGraphics(String theme) {
+ Image imageStartUp = getImageForButton(theme, "Start", "StartUp");
+ Image imageStartDown = getImageForButton(theme, "Start", "StartDown");
+ setupButton(imageStartUp, imageStartDown, UIController.form.btnStart);
+
+ Image imageSaveUp = getImageForButton(theme, "Save", "SaveUp");
+ Image imageSaveDown = getImageForButton(theme, "Save", "SaveDown");
+ setupButton(imageSaveUp, imageSaveDown, UIController.form.btnSave);
+ }
+
+ private static Image getImageForButton(String theme, String buttonCategory, String buttonType) {
+ String imagePath = "/Buttons/" + buttonCategory + "/" + buttonType + theme + ".png";
+ return new Image(Objects.requireNonNull(Constants.class.getResource(imagePath)).toExternalForm());
+ }
+
+ private static void changeImages(String theme) {
+ String bannerPath = "/Backgrounds/DriftyMain" + theme + ".png";
+ String splashPath = "/Splash" + theme + ".png";
+ Constants.imgMainGuiBanner = new Image(Objects.requireNonNull(Constants.class.getResource(bannerPath)).toExternalForm());
+ MainGridPane.ivLogo.setImage(Constants.imgMainGuiBanner);
+ Constants.imgSplash = new Image(Objects.requireNonNull(Constants.class.getResource(splashPath)).toExternalForm());
+ About.getIvSplash().setImage(Constants.imgSplash);
+ }
+
+ private static void updateTextColors(boolean isDark, Scene... scenes) {
+ // Labels
+ Paint color = isDark ? Color.WHITE : LinearGradient.valueOf("linear-gradient(to right, #0f0c29, #302b63, #24243e)");
+ for (Scene scene : scenes) {
+ if (scene != null) {
+ for (Node node : scene.getRoot().getChildrenUnmodifiable()) {
+ if (node instanceof Label) {
+ ((Label) node).setTextFill(color);
+ } else if (node instanceof Text) {
+ ((Text) node).setFill(color);
+ }
+ }
+ }
+ }
+ changeInfoTextFlow(color);
+ // TextFields
+ String style = isDark ? "-fx-text-fill: White;" : "-fx-text-fill: Black;";
+ UIController.form.tfDir.setStyle(style);
+ UIController.form.tfFilename.setStyle(style);
+ UIController.form.tfLink.setStyle(style);
+ if (Settings.getTfCurrentDirectory() != null) {
+ Settings.getTfCurrentDirectory().setStyle(style + "-fx-font-weight: Bold");
+ }
+ }
+
+ private static void changeInfoTextFlow(Paint color) {
+ Color headingsColor = AppSettings.GET.mainTheme().equals("Dark") ? Color.LIGHTGREEN : Color.DARKBLUE;
+ for (int i = 0; i < UIController.getInfoTf().getChildren().size(); i++) {
+ if (UIController.getInfoTf().getChildren().get(i) instanceof Text) {
+ Text text = (Text) UIController.getInfoTf().getChildren().get(i);
+ if (text.getFont().getSize() == 16) {
+ ((Text) UIController.getInfoTf().getChildren().get(i)).setFill(color);
+ } else {
+ ((Text) UIController.getInfoTf().getChildren().get(i)).setFill(headingsColor);
+
+ }
+ }
+ }
+ }
+
+ private static void updateButtonStyles(boolean isDark, String theme) {
+ changeButtonStyle(isDark, Settings.getSelectDirectoryButton());
+ changeButtonStyle(isDark, ConfirmationDialog.getBtnYes());
+ changeButtonStyle(isDark, ConfirmationDialog.getBtnNo());
+ setupButtonGraphics(theme);
+ }
+
+ static void changeButtonStyle(boolean isDark, Button button) {
+ if (button != null) {
+ if (isDark) {
+ button.setStyle(Constants.BUTTON_RELEASED);
+ button.setOnMousePressed(ev -> button.setStyle(Constants.BUTTON_PRESSED));
+ button.setOnMouseReleased(ev -> button.setStyle(Constants.BUTTON_RELEASED));
+ } else {
+ String style = "-fx-text-fill: Black;";
+ String backColorReleased = "-fx-background-color: linear-gradient(rgb(54,151,225) 18%, rgb(121,218,232) 90%, rgb(126,223,255) 95%);";
+ String backColorPressed = "-fx-background-color: linear-gradient(rgb(126,223,255) 20%, rgb(121,218,232) 20%, rgb(54,151,225) 100%);";
+ button.setStyle(style + backColorReleased);
+ button.setOnMousePressed(ev -> button.setStyle(style + backColorPressed));
+ button.setOnMouseReleased(ev -> button.setStyle(style + backColorReleased));
+ }
+ }
+ }
+
+ private static void updateCSS(boolean isDark, Scene... scenes) {
+ for (Scene scene : scenes) {
+ if (scene != null) {
+ Constants.addCSS(scene, isDark ? Constants.DARK_THEME_CSS : Constants.LIGHT_THEME_CSS);
+ scene.getStylesheets().remove(isDark ? Objects.requireNonNull(Constants.LIGHT_THEME_CSS).toExternalForm() : Objects.requireNonNull(Constants.DARK_THEME_CSS).toExternalForm());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GUI/src/main/java/ui/UIController.java b/GUI/src/main/java/ui/UIController.java
index d4bf73bca..e9dccc1b8 100644
--- a/GUI/src/main/java/ui/UIController.java
+++ b/GUI/src/main/java/ui/UIController.java
@@ -42,10 +42,8 @@
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.stream.Collectors;
import static gui.support.Colors.*;
-import static gui.support.Constants.MONACO_TTF;
import static utils.Utility.*;
public final class UIController {
@@ -59,15 +57,25 @@ public final class UIController {
private final String nl = System.lineSeparator();
private int speedValueUpdateCount;
private int speedValue;
+ private static final TextFlow INFO_TF = new TextFlow();
+ private static Scene infoScene;
private String songMetadataJson;
private String filename;
private String songLink;
private Folders folders;
private Job selectedJob;
+ public static Scene getInfoScene() {
+ return infoScene;
+ }
+
+ public static TextFlow getInfoTf() {
+ return INFO_TF;
+ }
+
/*
- Single instance model only constructor
- */
+ Single instance model-only constructor
+ */
private UIController() {
folders = AppSettings.GET.folders();
}
@@ -89,15 +97,19 @@ private void setControlProperties() {
BooleanBinding disableStartButton = form.listView.itemsProperty().isNotNull().not().or(PROCESSING_BATCH).or(DIRECTORY_EXISTS.not()).or(VERIFYING_LINKS);
BooleanBinding disableInputs = PROCESSING_BATCH.or(VERIFYING_LINKS);
-
form.btnSave.visibleProperty().bind(UPDATING_BATCH);
form.btnStart.disableProperty().bind(disableStartButton);
form.tfDir.disableProperty().bind(disableInputs);
form.tfFilename.disableProperty().bind(disableInputs);
form.tfLink.disableProperty().bind(disableInputs);
-
form.listView.setContextMenu(getListMenu());
+ if (AppSettings.GET.mainTheme().equals("Dark")) {
+ form.tfDir.setStyle("-fx-text-fill: White;");
+ form.tfFilename.setStyle("-fx-text-fill: White;");
+ form.tfLink.setStyle("-fx-text-fill: White;");
+ }
+
Tooltip.install(form.cbAutoPaste, new Tooltip("When checked, will paste contents of clipboard into" + nl + "Link field when switching back to this screen."));
Tooltip.install(form.tfLink, new Tooltip("URL must be a valid URL without spaces." + nl + " Add multiple URLs by pasting them in from the clipboard and separating each URL with a space."));
Tooltip.install(form.tfFilename, new Tooltip("If the filename you enter already exists in the download folder, it will" + nl + "automatically be renamed to avoid file over-writes."));
@@ -110,7 +122,6 @@ private void setControlProperties() {
selectJob(job);
});
form.cbAutoPaste.setSelected(AppSettings.GET.mainAutoPaste());
- form.cbAutoPaste.selectedProperty().addListener(((observable, oldValue, newValue) -> AppSettings.SET.mainAutoPaste(newValue)));
form.tfDir.textProperty().addListener(((observable, oldValue, newValue) -> {
if (!newValue.equals(oldValue)) {
DIRECTORY_EXISTS.setValue(false);
@@ -280,13 +291,10 @@ private Runnable verifyLink(String link) {
String folder = fileExists(filename);
String windowTitle;
if (!folder.isEmpty()) {
- message = intro + "And the file exists in this download folder:" + nl + folder + nl.repeat(2) +
- "If you wish to download it again, it will be given the name shown below, or you can change it as you wish." + nl.repeat(2) +
- "YES will add the job to the list with new filename. NO will do nothing.";
+ message = intro + "The file already exists in the selected download folder:" + nl + folder + nl.repeat(2) + "Choose 'YES' to download and automatically rename the file to avoid overwriting the existing one. Alternatively, you can manually change the filename below to your preference." + nl.repeat(2) + "Choose 'NO' if you do not wish to download the file again.";
windowTitle = "File Already Exists";
} else {
- message = intro + "However, the file does not exist in any of your download folders." + nl.repeat(2) +
- "Do you still wish to download this file?";
+ message = intro + "The file does not exist in any of your designated download folders." + nl.repeat(2) + "This is a good opportunity to download it without concerns of duplicating existing files. Click 'YES' to proceed with the download, or 'NO' if you decide not to download.";
windowTitle = "File Already Downloaded";
}
ConfirmationDialog ask = new ConfirmationDialog(windowTitle, message, renameFile(filename, dir));
@@ -490,12 +498,8 @@ private void updateBatch() {
private void checkHistoryAddJobs(Worker> worker) {
String pastJobNoFile = "You have downloaded %s in the past, but the file does not exist in your download folder." + nl.repeat(2) + " Click Yes if you still wish to download this file. Otherwise, click No.";
- String pastJobFileExists = "You have downloaded %s in the past, and the file exists in your download folder." + nl.repeat(2) +
- "It will be renamed as shown here, or you may change the filename to your liking." + nl.repeat(2) +
- "Clicking Yes will commit the job with the shown filename, while clicking No will not add this file to the job list.";
- String fileExistsString = "This file:" + nl.repeat(2) + "%s" + nl.repeat(2) + "Exists in in the download folder." + nl.repeat(2) +
- "It will be renamed as shown here, or you may change the filename to your liking." + nl.repeat(2) +
- "Clicking Yes will commit the job with the shown filename, while clicking No will not add this file to the job list.";
+ String pastJobFileExists = "You have downloaded %s in the past, and the file exists in your download folder." + nl.repeat(2) + "It will be renamed as shown here, or you may change the filename to your liking." + nl.repeat(2) + "Clicking Yes will commit the job with the shown filename, while clicking No will not add this file to the job list.";
+ String fileExistsString = "This file:" + nl.repeat(2) + "%s" + nl.repeat(2) + "Exists in in the download folder." + nl.repeat(2) + "It will be renamed as shown here, or you may change the filename to your liking." + nl.repeat(2) + "Clicking Yes will commit the job with the shown filename, while clicking No will not add this file to the job list.";
Platform.runLater(() -> {
String message;
ConfirmationDialog ask = new ConfirmationDialog("", "");
@@ -571,6 +575,7 @@ private ContextMenu getListMenu() {
clearLink();
clearFilename();
form.listView.getItems().clear();
+ form.listView.getItems();
M.msgLinkInfo("");
M.msgFilenameInfo("");
M.msgDirInfo("");
@@ -765,18 +770,10 @@ private void commitJobListToListView() {
if (getJobs().isEmpty()) {
form.listView.getItems().clear();
} else {
- // Remove duplicate jobs if any
- Set encounteredLinks = new HashSet<>();
- ConcurrentLinkedDeque duplicates = getJobs().jobList().stream()
- .filter(job -> !encounteredLinks.add(job.getLink()))
- .collect(Collectors.toCollection(ConcurrentLinkedDeque::new));
- for (Job job : duplicates) {
- removeJobFromList(job);
- }
- // Sort the Job list
- ArrayList sortList = new ArrayList<>(getJobs().jobList());
- sortList.sort(Comparator.comparing(Job::toString));
- getJobs().setList(new ConcurrentLinkedDeque<>(sortList));
+ // Use TreeSet to remove duplicates and sort simultaneously
+ Set sortedJobs = new TreeSet<>(Comparator.comparing(Job::toString));
+ sortedJobs.addAll(getJobs().jobList());
+ getJobs().setList(new ConcurrentLinkedDeque<>(sortedJobs));
}
// Assign the jobList to the ListView
form.listView.getItems().setAll(getJobs().jobList());
@@ -785,32 +782,33 @@ private void commitJobListToListView() {
}
private void help() {
+ Color textColor = AppSettings.GET.mainTheme().equals("Dark") ? Color.WHITE : Color.BLACK;
+ Color headingsColor = AppSettings.GET.mainTheme().equals("Dark") ? Color.LIGHTGREEN : Color.DARKBLUE;
double h = 20;
double n = 16;
- TextFlow tf = new TextFlow();
- tf.getChildren().add(text("Link:\n", true, BLUE, h));
- tf.getChildren().add(text("The Drifty GUI lets you easily create batches for downloading, or download a single file. You start by pasting your web links into the Link field. Once a link has been put into Link field, Drifty will start to process it where it will attempt to determine the name of the file being downloaded. Once it has done that, you will see the filename show up in the batch list on the left.\n\n", false, BLACK, n));
- tf.getChildren().add(text("The URLs you paste into the link field must be valid URLs or Drifty wont process them.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Checking the ", false, BLACK, n));
- tf.getChildren().add(text("Auto Paste ", true, BLACK, n));
- tf.getChildren().add(text("option will let you go to another window and put a link in the clipboard then when you come back to Drifty, the link will be pasted into the Link field automatically and processed then added to the batch list.\n\n", false, BLACK, n));
- tf.getChildren().add(text("If you paste in a link that happens to extract multiple files for downloading, such as a Youtube play list, Drifty will first attempt to get the number of files in the list, then it will ask you if you would like it to obtain all of the filenames in the list. The progress bar will indicate how many filenames have been obtained and the batch list will populate with download jobs with each new filename discovered.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Directory:\n", true, BLUE, h));
- tf.getChildren().add(text("Right clicking anywhere on the form brings up a menu where you can add directories to use as download folders. As you add more directories, they accumulate and persist between reloads. The last directory that you add last will be considered the current download directory. When you click start which begins the download process for all jobs in the batch list, Drifty will look through all of the added folders for a matching filenames and it will let you know when it finds duplicates and give you the option to not download them again.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Right clicking on the form and choosing to edit the directory list pulls up a form with all of the directories you have added. Click on one to remove it if necessary.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Filename:\n", true, BLUE, h));
- tf.getChildren().add(text("Drifty tries to get the name of the file from the link. This process can take a little time but not usually more than 10 to 20 seconds. By default, Drifty adds the extension of 'mp4' to video file downloads because these have the highest chance of success. If Drifty cannot determine the name of the file, you can type in whatever filename you'd like, then click on Save to commit that to the job in the list. You can also determine the download format of the file by setting the filename extension to one of these options: 3gp, aac, flv, m4a, mp3, mp4, ogg, wav, webm.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Job list:\n", true, BLUE, h));
- tf.getChildren().add(text("Once the list box on the left has the jobs in it that you want, you can click on each one in turn and the link, download directory and filename will be placed into the related fields so you can edit them if you need to. Just click on Save when you're done editing.\n\n", false, BLACK, n));
- tf.getChildren().add(text("You can right click on any item in the list to remove it or clear out the job list completely.\n\n", false, BLACK, n));
- tf.getChildren().add(text("The Job list and the directory list will persist between program reloads. The job list will empty out one at a time as each file in the list is downloaded. You start the batch by clicking on the Start button. Any files that fail to download will get recycled back into the list on this form. I found that they will download usually after a second attempt.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Auto Paste:\n", true, BLUE, h));
- tf.getChildren().add(text("The whole point of Auto Paste is to help speed things up. When you check the box, then go out to your browser and find links that you want to download, just copy them into your clip board then ALT+TAB back to Drifty or just click on it to make it the active window. Drifty will sense that it has been made the active screen and the contents of your clipboard will be analyzed to make sure it is a valid URL, then it will process it if so.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Multi-link pasting:\n", true, BLUE, h));
- tf.getChildren().add(text("Another way to speed things up it to copy and paste links into a notepad of some kind, then just put a single space between each link so that all the links are on a single line, then paste that line into the Link field and Drifty will start processing them in turn and build up your batch for you.\n\n", false, BLACK, n));
- tf.getChildren().add(text("Youtube Playlists:\n", true, BLUE, h));
- tf.getChildren().add(text("Another thing you can do is grab a YouTube playlist and Drifty will extract all of the videos from the playlist and build a batch from the list (or add to your existing batch).\n\n", false, BLACK, n));
- tf.setStyle("-fx-background-color: transparent");
+ INFO_TF.getChildren().add(text("Link:\n", true, headingsColor, h));
+ INFO_TF.getChildren().add(text("The Drifty GUI lets you easily create batches for downloading, or download a single file. You start by pasting your web links into the Link field. Once a link has been put into Link field, Drifty will start to process it where it will attempt to determine the name of the file being downloaded. Once it has done that, you will see the filename show up in the batch list on the left.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("The URLs you paste into the link field must be valid URLs or Drifty wont process them.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Checking the ", false, textColor, n));
+ INFO_TF.getChildren().add(text("Auto Paste ", true, textColor, n));
+ INFO_TF.getChildren().add(text("option will let you go to another window and put a link in the clipboard then when you come back to Drifty, the link will be pasted into the Link field automatically and processed then added to the batch list.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("If you paste in a link that happens to extract multiple files for downloading, such as a Youtube play list, Drifty will first attempt to get the number of files in the list, then it will ask you if you would like it to obtain all of the filenames in the list. The progress bar will indicate how many filenames have been obtained and the batch list will populate with download jobs with each new filename discovered.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Directory:\n", true, headingsColor, h));
+ INFO_TF.getChildren().add(text("Right clicking anywhere on the form brings up a menu where you can add directories to use as download folders. As you add more directories, they accumulate and persist between reloads. The last directory that you add last will be considered the current download directory. When you click start which begins the download process for all jobs in the batch list, Drifty will look through all of the added folders for a matching filenames and it will let you know when it finds duplicates and give you the option to not download them again.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Right clicking on the form and choosing to edit the directory list pulls up a form with all of the directories you have added. Click on one to remove it if necessary.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Filename:\n", true, headingsColor, h));
+ INFO_TF.getChildren().add(text("Drifty tries to get the name of the file from the link. This process can take a little time but not usually more than 10 to 20 seconds. By default, Drifty adds the extension of 'mp4' to video file downloads because these have the highest chance of success. If Drifty cannot determine the name of the file, you can type in whatever filename you'd like, then click on Save to commit that to the job in the list. You can also determine the download format of the file by setting the filename extension to one of these options: 3gp, aac, flv, m4a, mp3, mp4, ogg, wav, webm.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Job list:\n", true, headingsColor, h));
+ INFO_TF.getChildren().add(text("Once the list box on the left has the jobs in it that you want, you can click on each one in turn and the link, download directory and filename will be placed into the related fields so you can edit them if you need to. Just click on Save when you're done editing.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("You can right click on any item in the list to remove it or clear out the job list completely.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("The Job list and the directory list will persist between program reloads. The job list will empty out one at a time as each file in the list is downloaded. You start the batch by clicking on the Start button. Any files that fail to download will get recycled back into the list on this form. I found that they will download usually after a second attempt.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Auto Paste:\n", true, headingsColor, h));
+ INFO_TF.getChildren().add(text("The whole point of Auto Paste is to help speed things up. When you check the box, then go out to your browser and find links that you want to download, just copy them into your clip board then ALT+TAB back to Drifty or just click on it to make it the active window. Drifty will sense that it has been made the active screen and the contents of your clipboard will be analyzed to make sure it is a valid URL, then it will process it if so.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Multi-link pasting:\n", true, headingsColor, h));
+ INFO_TF.getChildren().add(text("Another way to speed things up it to copy and paste links into a notepad of some kind, then just put a single space between each link so that all the links are on a single line, then paste that line into the Link field and Drifty will start processing them in turn and build up your batch for you.\n\n", false, textColor, n));
+ INFO_TF.getChildren().add(text("Youtube Playlists:\n", true, headingsColor, h));
+ INFO_TF.getChildren().add(text("Another thing you can do is grab a YouTube playlist and Drifty will extract all of the videos from the playlist and build a batch from the list (or add to your existing batch).\n\n", false, textColor, n));
+ INFO_TF.setStyle("-fx-background-color: transparent");
double width = 500;
double height = 700;
@@ -818,7 +816,7 @@ private void help() {
Stage stage = Constants.getStage("Help", false);
stage.setWidth(width);
stage.setHeight(height + 100);
- VBox vox = new VBox(20, tf);
+ VBox vox = new VBox(20, INFO_TF);
vox.setPrefWidth(width - 35);
vox.setPrefHeight(height - 75);
vox.setPadding(new Insets(30));
@@ -830,14 +828,18 @@ private void help() {
scrollPane.setPrefWidth(width);
scrollPane.setPrefHeight(height);
scrollPane.setFitToWidth(true);
- Scene scene = Constants.getScene(scrollPane);
- scene.setFill(Color.TRANSPARENT);
- stage.setScene(scene);
+ infoScene = Constants.getScene(scrollPane);
+ if (AppSettings.GET.mainTheme().equals("Dark")) {
+ Theme.applyTheme("Dark", infoScene);
+ }
+
+ infoScene.setFill(Color.TRANSPARENT);
+ stage.setScene(infoScene);
stage.setAlwaysOnTop(true);
stage.setTitle("Help");
stage.setOnCloseRequest(e -> stage.close());
VBox.setVgrow(vox, Priority.ALWAYS);
- VBox.setVgrow(tf, Priority.ALWAYS);
+ VBox.setVgrow(INFO_TF, Priority.ALWAYS);
btnOK.setOnAction(e -> stage.close());
scrollPane.setVvalue(0.0);
stage.showAndWait();
@@ -846,7 +848,7 @@ private void help() {
private Text text(String string, boolean bold, Color color, double size) {
// This is used by the help() method for custom text formatting
Text text = new Text(string);
- text.setFont(new Font(Objects.requireNonNull(MONACO_TTF).toExternalForm(), size));
+ text.setFont(new Font("monospace", size));
text.setFill(color);
if (bold) {
text.setStyle("-fx-font-weight: bold;");
diff --git a/GUI/src/main/resources/Backgrounds/DriftyMainDark.png b/GUI/src/main/resources/Backgrounds/DriftyMainDark.png
new file mode 100644
index 000000000..dc124f59d
Binary files /dev/null and b/GUI/src/main/resources/Backgrounds/DriftyMainDark.png differ
diff --git a/GUI/src/main/resources/Backgrounds/DriftyMain.png b/GUI/src/main/resources/Backgrounds/DriftyMainLight.png
similarity index 100%
rename from GUI/src/main/resources/Backgrounds/DriftyMain.png
rename to GUI/src/main/resources/Backgrounds/DriftyMainLight.png
diff --git a/GUI/src/main/resources/Buttons/Save/SaveDownDark.png b/GUI/src/main/resources/Buttons/Save/SaveDownDark.png
new file mode 100644
index 000000000..bd175531b
Binary files /dev/null and b/GUI/src/main/resources/Buttons/Save/SaveDownDark.png differ
diff --git a/GUI/src/main/resources/Buttons/Save/SaveDown.png b/GUI/src/main/resources/Buttons/Save/SaveDownLight.png
similarity index 100%
rename from GUI/src/main/resources/Buttons/Save/SaveDown.png
rename to GUI/src/main/resources/Buttons/Save/SaveDownLight.png
diff --git a/GUI/src/main/resources/Buttons/Save/SaveUpDark.png b/GUI/src/main/resources/Buttons/Save/SaveUpDark.png
new file mode 100644
index 000000000..2571866d0
Binary files /dev/null and b/GUI/src/main/resources/Buttons/Save/SaveUpDark.png differ
diff --git a/GUI/src/main/resources/Buttons/Save/SaveUp.png b/GUI/src/main/resources/Buttons/Save/SaveUpLight.png
similarity index 100%
rename from GUI/src/main/resources/Buttons/Save/SaveUp.png
rename to GUI/src/main/resources/Buttons/Save/SaveUpLight.png
diff --git a/GUI/src/main/resources/Buttons/Start/StartDownDark.png b/GUI/src/main/resources/Buttons/Start/StartDownDark.png
new file mode 100644
index 000000000..b3d67f19d
Binary files /dev/null and b/GUI/src/main/resources/Buttons/Start/StartDownDark.png differ
diff --git a/GUI/src/main/resources/Buttons/Start/StartDown.png b/GUI/src/main/resources/Buttons/Start/StartDownLight.png
similarity index 100%
rename from GUI/src/main/resources/Buttons/Start/StartDown.png
rename to GUI/src/main/resources/Buttons/Start/StartDownLight.png
diff --git a/GUI/src/main/resources/Buttons/Start/StartUpDark.png b/GUI/src/main/resources/Buttons/Start/StartUpDark.png
new file mode 100644
index 000000000..5da2aa212
Binary files /dev/null and b/GUI/src/main/resources/Buttons/Start/StartUpDark.png differ
diff --git a/GUI/src/main/resources/Buttons/Start/StartUp.png b/GUI/src/main/resources/Buttons/Start/StartUpLight.png
similarity index 100%
rename from GUI/src/main/resources/Buttons/Start/StartUp.png
rename to GUI/src/main/resources/Buttons/Start/StartUpLight.png
diff --git a/GUI/src/main/resources/CSS/Button.css b/GUI/src/main/resources/CSS/Button.css
index ccd49f6f3..77c05bb45 100644
--- a/GUI/src/main/resources/CSS/Button.css
+++ b/GUI/src/main/resources/CSS/Button.css
@@ -1,11 +1,12 @@
.button {
-fx-background-color: linear-gradient(rgb(54,151,225) 18%, rgb(121,218,232) 90%, rgb(126,223,255) 95%);
-fx-border-color: black;
+ -fx-font-weight: Bold;
}
.button:pressed {
-fx-background-color: linear-gradient(rgb(126,223,255) 20%, rgb(121,218,232) 20%, rgb(54,151,225) 100%);
-
+ -fx-font-weight: Bold;
}
.glassButton {
diff --git a/GUI/src/main/resources/CSS/DarkTheme.css b/GUI/src/main/resources/CSS/DarkTheme.css
new file mode 100644
index 000000000..0d2fe025a
--- /dev/null
+++ b/GUI/src/main/resources/CSS/DarkTheme.css
@@ -0,0 +1,33 @@
+.root {
+ -fx-background-color: linear-gradient(rgb(0, 53, 105) 20%, rgb(26, 21, 129) 65%, rgb(0, 0, 65) 100%);
+ /*-fx-background-color: linear-gradient(rgba(54,151,225,1) 18%, rgba(121,218,232,1) 90%, rgba(126,223,255,1) 95%);*/
+}
+.list-cell {
+ -fx-background-color: transparent;
+ -fx-text-fill: rgb(255, 255, 255);
+}
+.progress-bar .bar {
+ -fx-background-color: #17e500;
+ -fx-border-color: black;
+ -fx-border-width: 1.5px;
+}
+.normalLabel {
+ -fx-font-family: Arial;
+ -fx-font-weight: bold;
+ -fx-font-size: 20;
+ -fx-text-fill: ghostwhite
+}
+.check-box {
+ -fx-background-color: #22ff00;
+ -fx-border-width:2px;
+ -fx-padding: 0px;
+ -fx-font-size: 20;
+}
+.check-box:selected .box{
+ -fx-background-color: #22ff00;
+}
+.check-box:selected .box .mark{
+ -fx-background-color: white;
+ -fx-border-color: black;
+ -fx-border-width: 1px;
+}
diff --git a/GUI/src/main/resources/CSS/Scene.css b/GUI/src/main/resources/CSS/LightTheme.css
similarity index 51%
rename from GUI/src/main/resources/CSS/Scene.css
rename to GUI/src/main/resources/CSS/LightTheme.css
index fea1d934b..497a8a70e 100644
--- a/GUI/src/main/resources/CSS/Scene.css
+++ b/GUI/src/main/resources/CSS/LightTheme.css
@@ -1,4 +1,4 @@
.root {
- /*-fx-background-color: linear-gradient(rgb(179, 182, 182) 20%, rgb(125, 130, 130) 65%, rgb(102, 106, 106) 100%);*/
+ /*-fx-background-color: linear-gradient(rgb(0, 53, 105) 20%, rgb(26, 21, 129) 65%, rgb(0, 0, 65) 100%);*/
-fx-background-color: linear-gradient(rgba(54,151,225,1) 18%, rgba(121,218,232,1) 90%, rgba(126,223,255,1) 95%);
}
diff --git a/GUI/src/main/resources/META-INF/native-image/jni-config.json b/GUI/src/main/resources/META-INF/native-image/jni-config.json
index 354fa6135..ebcad8ace 100644
--- a/GUI/src/main/resources/META-INF/native-image/jni-config.json
+++ b/GUI/src/main/resources/META-INF/native-image/jni-config.json
@@ -64,10 +64,18 @@
"name":"com.sun.javafx.geom.Path2D",
"methods":[{"name":"","parameterTypes":["int","byte[]","int","float[]","int"] }]
},
+{
+ "name":"java.lang.Boolean",
+ "fields":[{"name":"FALSE"}, {"name":"TRUE"}]
+},
{
"name":"java.lang.Iterable",
"methods":[{"name":"iterator","parameterTypes":[] }]
},
+{
+ "name":"java.lang.Object",
+ "methods":[{"name":"equals","parameterTypes":["java.lang.Object"] }]
+},
{
"name":"java.lang.Runnable",
"methods":[{"name":"run","parameterTypes":[] }]
@@ -84,9 +92,13 @@
"name":"java.util.ArrayList",
"methods":[{"name":"","parameterTypes":[] }, {"name":"","parameterTypes":["int"] }, {"name":"add","parameterTypes":["java.lang.Object"] }, {"name":"get","parameterTypes":["int"] }]
},
+{
+ "name":"java.util.Collections",
+ "methods":[{"name":"unmodifiableMap","parameterTypes":["java.util.Map"] }]
+},
{
"name":"java.util.HashMap",
- "methods":[{"name":"containsKey","parameterTypes":["java.lang.Object"] }, {"name":"get","parameterTypes":["java.lang.Object"] }, {"name":"put","parameterTypes":["java.lang.Object","java.lang.Object"] }]
+ "methods":[{"name":"","parameterTypes":[] }, {"name":"containsKey","parameterTypes":["java.lang.Object"] }, {"name":"get","parameterTypes":["java.lang.Object"] }, {"name":"put","parameterTypes":["java.lang.Object","java.lang.Object"] }]
},
{
"name":"java.util.HashSet",
@@ -98,10 +110,14 @@
},
{
"name":"java.util.Map",
- "methods":[{"name":"containsKey","parameterTypes":["java.lang.Object"] }, {"name":"get","parameterTypes":["java.lang.Object"] }, {"name":"keySet","parameterTypes":[] }]
+ "methods":[{"name":"containsKey","parameterTypes":["java.lang.Object"] }, {"name":"get","parameterTypes":["java.lang.Object"] }, {"name":"keySet","parameterTypes":[] }, {"name":"put","parameterTypes":["java.lang.Object","java.lang.Object"] }]
},
{
"name":"java.util.Set",
"methods":[{"name":"add","parameterTypes":["java.lang.Object"] }, {"name":"size","parameterTypes":[] }, {"name":"toArray","parameterTypes":["java.lang.Object[]"] }]
+},
+{
+ "name":"javafx.scene.paint.Color",
+ "methods":[{"name":"rgb","parameterTypes":["int","int","int","double"] }]
}
]
diff --git a/GUI/src/main/resources/META-INF/native-image/reflect-config.json b/GUI/src/main/resources/META-INF/native-image/reflect-config.json
index 603c2a609..c5bae7363 100644
--- a/GUI/src/main/resources/META-INF/native-image/reflect-config.json
+++ b/GUI/src/main/resources/META-INF/native-image/reflect-config.json
@@ -107,6 +107,10 @@
"name":"com.sun.prism.shader.Mask_TextureSuper_Loader",
"methods":[{"name":"loadShader","parameterTypes":["com.sun.prism.ps.ShaderFactory","java.io.InputStream"] }]
},
+{
+ "name":"com.sun.prism.shader.Solid_Color_Loader",
+ "methods":[{"name":"loadShader","parameterTypes":["com.sun.prism.ps.ShaderFactory","java.io.InputStream"] }]
+},
{
"name":"com.sun.prism.shader.Solid_TextureFirstPassLCD_Loader",
"methods":[{"name":"loadShader","parameterTypes":["com.sun.prism.ps.ShaderFactory","java.io.InputStream"] }]
@@ -131,6 +135,10 @@
"name":"com.sun.scenario.effect.impl.prism.PrRenderer",
"methods":[{"name":"createRenderer","parameterTypes":["com.sun.scenario.effect.FilterContext"] }]
},
+{
+ "name":"com.sun.scenario.effect.impl.prism.ps.PPSBlend_SRC_INPeer",
+ "methods":[{"name":"","parameterTypes":["com.sun.scenario.effect.FilterContext","com.sun.scenario.effect.impl.Renderer","java.lang.String"] }]
+},
{
"name":"com.sun.scenario.effect.impl.prism.ps.PPSLinearConvolveShadowPeer",
"methods":[{"name":"","parameterTypes":["com.sun.scenario.effect.FilterContext","com.sun.scenario.effect.impl.Renderer","java.lang.String"] }]
@@ -264,6 +272,9 @@
{
"name":"javafx.scene.control.Control"
},
+{
+ "name":"javafx.scene.control.Labeled"
+},
{
"name":"javafx.scene.effect.Effect"
},
@@ -418,10 +429,6 @@
"name":"sun.security.rsa.RSASignature$SHA256withRSA",
"methods":[{"name":"","parameterTypes":[] }]
},
-{
- "name":"sun.security.rsa.RSASignature$SHA384withRSA",
- "methods":[{"name":"","parameterTypes":[] }]
-},
{
"name":"sun.security.ssl.KeyManagerFactoryImpl$SunX509",
"methods":[{"name":"","parameterTypes":[] }]
diff --git a/GUI/src/main/resources/META-INF/native-image/resource-config.json b/GUI/src/main/resources/META-INF/native-image/resource-config.json
index a4f938af8..0f645362a 100644
--- a/GUI/src/main/resources/META-INF/native-image/resource-config.json
+++ b/GUI/src/main/resources/META-INF/native-image/resource-config.json
@@ -1,31 +1,43 @@
{
"resources":{
"includes":[{
- "pattern":"GUI:\\QBackgrounds/DriftyMain.png\\E"
+ "pattern":"GUI:\\QBackgrounds/DriftyMainDark.png\\E"
}, {
- "pattern":"GUI:\\QButtons/Save/SaveDown.png\\E"
+ "pattern":"GUI:\\QBackgrounds/DriftyMainLight.png\\E"
}, {
- "pattern":"GUI:\\QButtons/Save/SaveUp.png\\E"
+ "pattern":"GUI:\\QButtons/Save/SaveDownDark.png\\E"
}, {
- "pattern":"GUI:\\QButtons/Start/StartDown.png\\E"
+ "pattern":"GUI:\\QButtons/Save/SaveDownLight.png\\E"
}, {
- "pattern":"GUI:\\QButtons/Start/StartUp.png\\E"
+ "pattern":"GUI:\\QButtons/Save/SaveUpDark.png\\E"
+ }, {
+ "pattern":"GUI:\\QButtons/Save/SaveUpLight.png\\E"
+ }, {
+ "pattern":"GUI:\\QButtons/Start/StartDownDark.png\\E"
+ }, {
+ "pattern":"GUI:\\QButtons/Start/StartDownLight.png\\E"
+ }, {
+ "pattern":"GUI:\\QButtons/Start/StartUpDark.png\\E"
+ }, {
+ "pattern":"GUI:\\QButtons/Start/StartUpLight.png\\E"
}, {
"pattern":"GUI:\\QCSS/Button.css\\E"
}, {
"pattern":"GUI:\\QCSS/CheckBox.css\\E"
}, {
"pattern":"GUI:\\QCSS/ContextMenu.css\\E"
+ }, {
+ "pattern":"GUI:\\QCSS/DarkTheme.css\\E"
}, {
"pattern":"GUI:\\QCSS/Label.css\\E"
+ }, {
+ "pattern":"GUI:\\QCSS/LightTheme.css\\E"
}, {
"pattern":"GUI:\\QCSS/ListView.css\\E"
}, {
"pattern":"GUI:\\QCSS/Menu.css\\E"
}, {
"pattern":"GUI:\\QCSS/ProgressBar.css\\E"
- }, {
- "pattern":"GUI:\\QCSS/Scene.css\\E"
}, {
"pattern":"GUI:\\QCSS/ScrollPane.css\\E"
}, {
@@ -45,7 +57,9 @@
}, {
"pattern":"GUI:\\QLabels/Link.png\\E"
}, {
- "pattern":"GUI:\\QSplash.png\\E"
+ "pattern":"GUI:\\QSplashDark.png\\E"
+ }, {
+ "pattern":"GUI:\\QSplashLight.png\\E"
}, {
"pattern":"\\QMETA-INF/fonts.mf\\E"
}, {
@@ -58,8 +72,6 @@
"pattern":"\\QMETA-INF/services/java.nio.channels.spi.SelectorProvider\\E"
}, {
"pattern":"\\QMETA-INF/services/java.nio.charset.spi.CharsetProvider\\E"
- }, {
- "pattern":"\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E"
}, {
"pattern":"\\QMETA-INF/services/java.util.prefs.PreferencesFactory\\E"
}, {
@@ -67,21 +79,47 @@
}, {
"pattern":"\\QMETA-INF/services/javax.xml.transform.TransformerFactory\\E"
}, {
- "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt72b/nfkc.nrm\\E"
+ "pattern":"\\Qcom/sun/javafx/scene/control/skin/resources/controls_en.properties\\E"
}, {
- "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt72b/ubidi.icu\\E"
+ "pattern":"\\Qcom/sun/javafx/scene/control/skin/resources/controls_en_US.properties\\E"
}, {
- "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt72b/uprops.icu\\E"
+ "pattern":"\\Qcom/sun/javafx/tk/quantum/QuantumMessagesBundle_en.properties\\E"
}, {
- "pattern":"java.base:\\Qsun/net/idn/uidna.spp\\E"
+ "pattern":"\\Qcom/sun/javafx/tk/quantum/QuantumMessagesBundle_en_US.properties\\E"
+ }, {
+ "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt74b/nfkc.nrm\\E"
}, {
- "pattern":"java.base:\\Qsun/text/resources/WordBreakIteratorData\\E"
+ "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt74b/ubidi.icu\\E"
+ }, {
+ "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt74b/uprops.icu\\E"
+ }, {
+ "pattern":"java.base:\\Qsun/net/idn/uidna.spp\\E"
}, {
"pattern":"java.xml:\\Qcom/sun/org/apache/xml/internal/serializer/Encodings.properties\\E"
+ }, {
+ "pattern":"java.xml:\\Qcom/sun/org/apache/xml/internal/serializer/XMLEntities.properties\\E"
+ }, {
+ "pattern":"java.xml:\\Qcom/sun/org/apache/xml/internal/serializer/XMLEntities_en.properties\\E"
+ }, {
+ "pattern":"java.xml:\\Qcom/sun/org/apache/xml/internal/serializer/XMLEntities_en_US.properties\\E"
+ }, {
+ "pattern":"java.xml:\\Qjdk/xml/internal/jdkcatalog/JDKCatalog.xml\\E"
}, {
"pattern":"javafx.controls:\\Qcom/sun/javafx/scene/control/skin/modena/modena.bss\\E"
+ }, {
+ "pattern":"javafx.controls:\\Qcom/sun/javafx/scene/control/skin/resources/controls.properties\\E"
+ }, {
+ "pattern":"javafx.controls:\\Qcom/sun/javafx/scene/control/skin/resources/controls_en.properties\\E"
+ }, {
+ "pattern":"javafx.controls:\\Qcom/sun/javafx/scene/control/skin/resources/controls_en_US.properties\\E"
}, {
"pattern":"javafx.graphics:\\Qcom/sun/glass/utils/NativeLibLoader.class\\E"
+ }, {
+ "pattern":"javafx.graphics:\\Qcom/sun/javafx/tk/quantum/QuantumMessagesBundle.properties\\E"
+ }, {
+ "pattern":"javafx.graphics:\\Qcom/sun/javafx/tk/quantum/QuantumMessagesBundle_en.properties\\E"
+ }, {
+ "pattern":"javafx.graphics:\\Qcom/sun/javafx/tk/quantum/QuantumMessagesBundle_en_US.properties\\E"
}, {
"pattern":"javafx.graphics:\\Qcom/sun/prism/es2/glsl/DrawPgram_Color.frag\\E"
}, {
@@ -92,6 +130,8 @@
"pattern":"javafx.graphics:\\Qcom/sun/prism/es2/glsl/FillRoundRect_Color.frag\\E"
}, {
"pattern":"javafx.graphics:\\Qcom/sun/prism/es2/glsl/Mask_TextureSuper.frag\\E"
+ }, {
+ "pattern":"javafx.graphics:\\Qcom/sun/prism/es2/glsl/Solid_Color.frag\\E"
}, {
"pattern":"javafx.graphics:\\Qcom/sun/prism/es2/glsl/Solid_TextureFirstPassLCD.frag\\E"
}, {
@@ -102,6 +142,8 @@
"pattern":"javafx.graphics:\\Qcom/sun/prism/es2/glsl/Texture_Color.frag\\E"
}, {
"pattern":"javafx.graphics:\\Qcom/sun/prism/es2/glsl/Texture_LinearGradient_PAD.frag\\E"
+ }, {
+ "pattern":"javafx.graphics:\\Qcom/sun/scenario/effect/impl/es2/glsl/Blend_SRC_IN.frag\\E"
}, {
"pattern":"javafx.graphics:\\Qcom/sun/scenario/effect/impl/es2/glsl/LinearConvolveShadow_20.frag\\E"
}, {
@@ -123,12 +165,18 @@
}]},
"bundles":[{
"name":"com.sun.javafx.tk.quantum.QuantumMessagesBundle",
- "locales":[""]
+ "locales":["en-US"]
}, {
"name":"com.sun.org.apache.xml.internal.serializer.XMLEntities",
- "locales":[""]
+ "locales":["en-US"]
}, {
"name":"com/sun/javafx/scene/control/skin/resources/controls",
- "locales":[""]
+ "locales":["en-US"]
+ }, {
+ "name":"sun.text.resources.cldr.FormatData",
+ "locales":["en", "en-US", "und"]
+ }, {
+ "name":"sun.util.resources.cldr.CalendarData",
+ "locales":["und"]
}]
}
diff --git a/GUI/src/main/resources/SplashDark.png b/GUI/src/main/resources/SplashDark.png
new file mode 100644
index 000000000..401c39937
Binary files /dev/null and b/GUI/src/main/resources/SplashDark.png differ
diff --git a/GUI/src/main/resources/Splash.png b/GUI/src/main/resources/SplashLight.png
similarity index 100%
rename from GUI/src/main/resources/Splash.png
rename to GUI/src/main/resources/SplashLight.png