From b2227e9f4f9b9bd692af2e0c3e0025e04b67abeb Mon Sep 17 00:00:00 2001 From: Luis Uguina Date: Tue, 14 Apr 2020 23:24:28 +1000 Subject: [PATCH] feature: light/dark mode theme support (#208) * feature: light/dark mode theme support New feature providing a more modern flat design with support for light and dark modes, including: - New SheepIt logo (old one removed) - New configuration option (-theme) that changes the existing client theme. - Minimal UI cosmetic changes (some separation lines under the logo and above the buttons) --- build.gradle | 2 + resources/sheepit-logo.png | Bin 0 -> 13716 bytes resources/title.png | Bin 24556 -> 0 bytes src/com/sheepit/client/Configuration.java | 2 + src/com/sheepit/client/SettingsLoader.java | 26 ++++- .../sheepit/client/standalone/GuiSwing.java | 26 +++-- src/com/sheepit/client/standalone/Worker.java | 13 +++ .../standalone/swing/activity/Settings.java | 99 +++++++++++++++++- .../standalone/swing/activity/Working.java | 34 +++++- 9 files changed, 188 insertions(+), 14 deletions(-) create mode 100644 resources/sheepit-logo.png delete mode 100644 resources/title.png diff --git a/build.gradle b/build.gradle index 8b5a59f..eee0cb0 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,8 @@ dependencies { compile 'net.java.dev.jna:jna:4.0.0' compile 'javax.xml.bind:jaxb-api:2.3.1' compile 'com.squareup.retrofit2:converter-simplexml:2.3.0' + + implementation 'com.formdev:flatlaf:0.30' } jar { diff --git a/resources/sheepit-logo.png b/resources/sheepit-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bbaeff6e08e7ea2f2261330c3de2c6e5970b2ecc GIT binary patch literal 13716 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 literal 0 HcmV?d00001 diff --git a/resources/title.png b/resources/title.png deleted file mode 100644 index e52fffdeb78a412fe824ccd9a62ba078bb0a094f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24556 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 0) { cores = String.valueOf(cores_); } @@ -166,6 +169,10 @@ public class SettingsLoader { if (ui != null) { prop.setProperty("ui", ui); } + + if (theme != null) { + prop.setProperty("theme", theme); + } prop.store(output, null); } @@ -212,6 +219,7 @@ public class SettingsLoader { this.priority = 19; // must be the same default as Configuration this.ram = null; this.renderTime = null; + this.theme = null; if (new File(path).exists() == false) { return; @@ -275,6 +283,10 @@ public class SettingsLoader { this.ui = prop.getProperty("ui"); } + if (prop.containsKey("theme")) { + this.theme = prop.getProperty("theme"); + } + if (prop.containsKey("priority")) { this.priority = Integer.parseInt(prop.getProperty("priority")); } @@ -357,12 +369,20 @@ public class SettingsLoader { if (config.getUIType() == null && ui != null) { config.setUIType(ui); } - + + if (config.getTheme() == null) { + if (this.theme != null) { + config.setTheme(this.theme); + } else { + config.setTheme("light"); + } + } + config.setAutoSignIn(Boolean.valueOf(autoSignIn)); } @Override public String toString() { - return "SettingsLoader [path=" + path + ", login=" + login + ", password=" + password + ", computeMethod=" + computeMethod + ", gpu=" + gpu + ", cacheDir=" + cacheDir + "priority="+priority+"]"; + return "SettingsLoader [path=" + path + ", login=" + login + ", password=" + password + ", computeMethod=" + computeMethod + ", gpu=" + gpu + ", cacheDir=" + cacheDir + ", theme=" + theme + ", priority="+priority+"]"; } } diff --git a/src/com/sheepit/client/standalone/GuiSwing.java b/src/com/sheepit/client/standalone/GuiSwing.java index 355185f..f689795 100644 --- a/src/com/sheepit/client/standalone/GuiSwing.java +++ b/src/com/sheepit/client/standalone/GuiSwing.java @@ -25,7 +25,6 @@ import java.awt.Image; import java.awt.MenuItem; import java.awt.PopupMenu; import java.awt.SystemTray; -import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -57,6 +56,10 @@ import com.sheepit.client.standalone.swing.activity.Working; import lombok.Getter; import lombok.Setter; +import com.formdev.flatlaf.FlatLightLaf; // Required for dark & light mode +import com.formdev.flatlaf.FlatDarkLaf; +import com.formdev.flatlaf.FlatLaf; + public class GuiSwing extends JFrame implements Gui { public static final String type = "swing"; @@ -104,13 +107,6 @@ public class GuiSwing extends JFrame implements Gui { @Override public void start() { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } - catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e1) { - e1.printStackTrace(); - } - if (useSysTray) { try { sysTray = SystemTray.getSystemTray(); @@ -158,6 +154,20 @@ public class GuiSwing extends JFrame implements Gui { this.showActivity(ActivityType.SETTINGS); + try { + if (client.getConfiguration().getTheme().equals("light")) { + UIManager.setLookAndFeel(new FlatLightLaf()); + } else if (client.getConfiguration().getTheme().equals("dark")) { + UIManager.setLookAndFeel(new FlatDarkLaf()); + } + + // Apply the selected theme to swing components + FlatLaf.updateUI(); + } + catch (UnsupportedLookAndFeelException e1) { + e1.printStackTrace(); + } + while (waitingForAuthentication) { try { synchronized (this) { diff --git a/src/com/sheepit/client/standalone/Worker.java b/src/com/sheepit/client/standalone/Worker.java index 6f6420d..91ff585 100644 --- a/src/com/sheepit/client/standalone/Worker.java +++ b/src/com/sheepit/client/standalone/Worker.java @@ -112,6 +112,9 @@ public class Worker { @Option(name = "-title", usage = "Custom title for the GUI Client", required = false) private String title = "SheepIt Render Farm"; + @Option(name = "-theme", usage = "Specify the theme to use for the graphical client, default 'light', available 'light', 'dark'", required = false) + private String theme = null; + public static void main(String[] args) { new Worker().doMain(args); } @@ -283,6 +286,16 @@ public class Worker { config.setUIType(ui_type); } + if (theme != null) { + if (!theme.equals("light") && !theme.equals("dark")) { + System.err.println(String.format("The theme specified (%s) doesn't exist. Please choose 'light' or 'dark'.", theme)); + System.err.println("Aborting"); + System.exit(2); + } + + config.setTheme(this.theme); + } + if (config_file != null) { if (new File(config_file).exists() == false) { System.err.println("Configuration file not found."); diff --git a/src/com/sheepit/client/standalone/swing/activity/Settings.java b/src/com/sheepit/client/standalone/swing/activity/Settings.java index 55fc4de..42bdf00 100644 --- a/src/com/sheepit/client/standalone/swing/activity/Settings.java +++ b/src/com/sheepit/client/standalone/swing/activity/Settings.java @@ -35,6 +35,7 @@ import java.util.List; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -43,11 +44,18 @@ import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; +import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; import javax.swing.SpinnerNumberModel; +import com.formdev.flatlaf.FlatLaf; +import com.formdev.flatlaf.FlatLightLaf; +import com.formdev.flatlaf.FlatDarkLaf; + import com.sheepit.client.Configuration; import com.sheepit.client.Configuration.ComputeType; import com.sheepit.client.SettingsLoader; @@ -78,6 +86,10 @@ public class Settings implements Activity { private JTextField proxy; private JTextField hostname; + private ButtonGroup themeOptionsGroup; + private JRadioButton lightMode; + private JRadioButton darkMode; + private JCheckBox saveFile; private JCheckBox autoSignIn; JButton saveButton; @@ -96,11 +108,13 @@ public class Settings implements Activity { Configuration config = parent.getConfiguration(); new SettingsLoader(config.getConfigFilePath()).merge(config); + applyTheme(config.getTheme()); // apply the proper theme (light/dark) + List gpus = GPU.listDevices(config); GridBagConstraints constraints = new GridBagConstraints(); int currentRow = 0; - ImageIcon image = new ImageIcon(getClass().getResource("/title.png")); + ImageIcon image = new ImageIcon(getClass().getResource("/sheepit-logo.png")); constraints.fill = GridBagConstraints.CENTER; JLabel labelImage = new JLabel(image); @@ -111,6 +125,11 @@ public class Settings implements Activity { ++currentRow; + constraints.gridy = currentRow; + parent.getContentPane().add(new JLabel(" "), constraints); // Add a separator between logo and first panel + + currentRow++; + // authentication CollapsibleJPanel authentication_panel = new CollapsibleJPanel(new GridLayout(2, 2)); authentication_panel.setBorder(BorderFactory.createTitledBorder("Authentication")); @@ -137,6 +156,36 @@ public class Settings implements Activity { constraints.fill = GridBagConstraints.HORIZONTAL; parent.getContentPane().add(authentication_panel, constraints); + // Theme selection panel + CollapsibleJPanel themePanel = new CollapsibleJPanel(new GridLayout(1, 3)); + themePanel.setBorder(BorderFactory.createTitledBorder("Theme")); + + themeOptionsGroup = new ButtonGroup(); + + lightMode = new JRadioButton("Light"); + lightMode.setActionCommand("light"); + lightMode.setSelected(config.getTheme().equals("light")); + lightMode.addActionListener(new ApplyThemeAction()); + + darkMode = new JRadioButton("Dark"); + darkMode.setActionCommand("dark"); + darkMode.setSelected(config.getTheme().equals("dark")); + darkMode.addActionListener(new ApplyThemeAction()); + + themePanel.add(lightMode); + themePanel.add(darkMode); + + // Group both radio buttons to allow only one selected + themeOptionsGroup.add(lightMode); + themeOptionsGroup.add(darkMode); + + currentRow++; + constraints.gridx = 0; + constraints.gridy = currentRow; + constraints.gridwidth = 2; + + parent.getContentPane().add(themePanel, constraints); + // directory CollapsibleJPanel directory_panel = new CollapsibleJPanel(new GridLayout(1, 3)); directory_panel.setBorder(BorderFactory.createTitledBorder("Cache")); @@ -370,6 +419,11 @@ public class Settings implements Activity { constraints.gridwidth = 2; parent.getContentPane().add(general_panel, constraints); + currentRow++; + constraints.gridy = currentRow; + parent.getContentPane().add(new JLabel(" "), constraints); // Add a separator between last checkboxes and button + + currentRow++; String buttonText = "Start"; if (parent.getClient() != null) { if (parent.getClient().isRunning()) { @@ -406,6 +460,22 @@ public class Settings implements Activity { saveButton.setEnabled(selected); return selected; } + + private void applyTheme(String theme_) { + try { + if (theme_.equals("light")) { + UIManager.setLookAndFeel(new FlatLightLaf()); + } else if (theme_.equals("dark")) { + UIManager.setLookAndFeel(new FlatDarkLaf()); + } + + // Apply the new theme + FlatLaf.updateUI(); + } + catch (UnsupportedLookAndFeelException e1) { + e1.printStackTrace(); + } + } class ChooseFileAction implements ActionListener { @@ -452,6 +522,13 @@ public class Settings implements Activity { } } + class ApplyThemeAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + applyTheme(themeOptionsGroup.getSelection().getActionCommand()); + } + } + class SaveAction implements ActionListener { @Override @@ -464,6 +541,9 @@ public class Settings implements Activity { if (config == null) { return; } + + if (themeOptionsGroup.getSelection().getActionCommand() != null) + config.setTheme(themeOptionsGroup.getSelection().getActionCommand()); if (cacheDir != null) { File fromConfig = config.getStorageDir(); @@ -550,7 +630,22 @@ public class Settings implements Activity { } if (saveFile.isSelected()) { - parent.setSettingsLoader(new SettingsLoader(config.getConfigFilePath(), login.getText(), new String(password.getPassword()), proxyText, hostnameText, method, selected_gpu, cpu_cores, max_ram, max_rendertime, cachePath, autoSignIn.isSelected(), GuiSwing.type, priority.getValue())); + parent.setSettingsLoader(new SettingsLoader( + config.getConfigFilePath(), + login.getText(), + new String(password.getPassword()), + proxyText, + hostnameText, + method, + selected_gpu, + cpu_cores, + max_ram, + max_rendertime, + cachePath, + autoSignIn.isSelected(), + GuiSwing.type, + themeOptionsGroup.getSelection().getActionCommand(), // selected theme + priority.getValue())); // wait for successful authentication (to store the public key) // or do we already have one? diff --git a/src/com/sheepit/client/standalone/swing/activity/Working.java b/src/com/sheepit/client/standalone/swing/activity/Working.java index 5599cd3..2c0b116 100644 --- a/src/com/sheepit/client/standalone/swing/activity/Working.java +++ b/src/com/sheepit/client/standalone/swing/activity/Working.java @@ -40,6 +40,7 @@ import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.UIManager; import javax.swing.Spring; import javax.swing.SpringLayout; @@ -73,6 +74,7 @@ public class Working implements Activity { private JLabel waiting_projects_value; private JLabel connected_machines_value; private JLabel user_info_total_rendertime_this_session_value; + private String currentTheme; public Working(GuiSwing parent_) { parent = parent_; @@ -92,10 +94,38 @@ public class Working implements Activity { user_info_total_rendertime_this_session_value = new JLabel(""); lastRenderTime = new JLabel(""); lastRender = new JLabel(""); + currentTheme = UIManager.getLookAndFeel().getName(); // Capture the theme on component instantiation } @Override public void show() { + // If the stored theme and the UIManager's theme doesn't match is bc the user has changed it + if (!currentTheme.equals(UIManager.getLookAndFeel().getName())) { + // And, as the user has changed the theme, then we must recreate all the UI elements with session data + // Reason being they are defined as class variables and therefore created once when the object + // is created the first time. + // As the Java swing engine applies the "look & feel" at creation time, we need to "re-create" the + // objects to ensure they have the right theme colors. + statusContent = new JLabel(statusContent.getText()); + renderedFrameContent = new JLabel(renderedFrameContent.getText()); + remainingFrameContent = new JLabel(remainingFrameContent.getText()); + creditEarned = new JLabel(creditEarned.getText()); + current_project_name_value = new JLabel(current_project_name_value.getText()); + current_project_duration_value = new JLabel(current_project_duration_value.getText()); + currrent_project_progression_value = new JLabel(currrent_project_progression_value.getText()); + current_project_compute_method_value = new JLabel(current_project_compute_method_value.getText()); + user_info_points_total_value = new JLabel(user_info_points_total_value.getText()); + renderable_projects_value = new JLabel(renderable_projects_value.getText()); + waiting_projects_value = new JLabel(waiting_projects_value.getText()); + connected_machines_value = new JLabel(connected_machines_value.getText()); + user_info_total_rendertime_this_session_value = new JLabel(user_info_total_rendertime_this_session_value.getText()); + lastRenderTime = new JLabel(lastRenderTime.getText()); + lastRender = new JLabel(lastRender.getText()); + + // set the new theme as the current one + currentTheme = UIManager.getLookAndFeel().getName(); + } + // current project JPanel current_project_panel = new JPanel(new SpringLayout()); current_project_panel.setBorder(BorderFactory.createTitledBorder("Project")); @@ -173,7 +203,7 @@ public class Working implements Activity { last_frame_panel.add(lastRenderTime); last_frame_panel.add(lastRender); - ImageIcon image = new ImageIcon(getClass().getResource("/title.png")); + ImageIcon image = new ImageIcon(getClass().getResource("/sheepit-logo.png")); JLabel labelImage = new JLabel(image); labelImage.setAlignmentX(Component.CENTER_ALIGNMENT); parent.getContentPane().add(labelImage); @@ -208,10 +238,12 @@ public class Working implements Activity { global_constraints.weightx = 1; global_constraints.gridx = 0; + parent.getContentPane().add(new JLabel(" "), global_constraints); // Add a separator between logo and first panel parent.getContentPane().add(current_project_panel, global_constraints); parent.getContentPane().add(global_stats_panel, global_constraints); parent.getContentPane().add(session_info_panel, global_constraints); parent.getContentPane().add(last_frame_panel, global_constraints); + parent.getContentPane().add(new JLabel(" "), global_constraints); // Add a separator between last panel and buttons parent.getContentPane().add(buttonsPanel, global_constraints); Spring widthLeftColumn = getBestWidth(current_project_panel, 4, 2);