From 48489179e916f12b45deb0d4130583477d3e8f98 Mon Sep 17 00:00:00 2001 From: RememBerBer Date: Thu, 11 Nov 2021 09:09:20 +0800 Subject: [PATCH] init seed --- assets/logo/MooInfo.svg | 2 +- pom.xml | 13 + .../java/com/luoboduner/moo/info/App.java | 52 ++ .../moo/info/bean/VersionSummary.java | 53 ++ .../java/com/luoboduner/moo/info/ui/Init.java | 222 ++++++++ .../com/luoboduner/moo/info/ui/UiConsts.java | 78 +++ .../moo/info/ui/component/TopMenuBar.java | 375 ++++++++++++++ .../moo/info/ui/dialog/AboutDialog.form | 344 ++++++++++++ .../moo/info/ui/dialog/AboutDialog.java | 488 ++++++++++++++++++ .../moo/info/ui/dialog/SettingDialog.form | 97 ++++ .../moo/info/ui/dialog/SettingDialog.java | 150 ++++++ .../info/ui/dialog/SystemEnvResultDialog.form | 69 +++ .../info/ui/dialog/SystemEnvResultDialog.java | 103 ++++ .../moo/info/ui/dialog/UpdateDialog.form | 96 ++++ .../moo/info/ui/dialog/UpdateDialog.java | 190 +++++++ .../moo/info/ui/dialog/UpdateInfoDialog.form | 86 +++ .../moo/info/ui/dialog/UpdateInfoDialog.java | 157 ++++++ .../moo/info/ui/form/LoadingForm.form | 24 + .../moo/info/ui/form/LoadingForm.java | 78 +++ .../moo/info/ui/form/MainWindow.form | 35 ++ .../moo/info/ui/form/MainWindow.java | 73 +++ .../moo/info/ui/frame/MainFrame.java | 36 ++ .../moo/info/ui/listener/FrameListener.java | 68 +++ .../moo/info/util/ComponentUtil.java | 40 ++ .../moo/info/util/ConfigBaseUtil.java | 41 ++ .../luoboduner/moo/info/util/ConfigUtil.java | 99 ++++ .../luoboduner/moo/info/util/FrameUtil.java | 33 ++ .../luoboduner/moo/info/util/SystemUtil.java | 42 ++ .../com/luoboduner/moo/info/util/UIUtil.java | 64 +++ .../luoboduner/moo/info/util/UpgradeUtil.java | 136 +++++ src/main/resources/icons/MooTool-logo-64.png | Bin 0 -> 3412 bytes src/main/resources/icons/WePush-logo-64.png | Bin 0 -> 3235 bytes src/main/resources/icons/loading_dark.gif | Bin 0 -> 3213 bytes src/main/resources/icons/logo-1024.png | Bin 0 -> 32542 bytes src/main/resources/icons/logo-128.png | Bin 0 -> 2772 bytes src/main/resources/icons/logo-16.png | Bin 0 -> 423 bytes src/main/resources/icons/logo-24.png | Bin 0 -> 604 bytes src/main/resources/icons/logo-256.png | Bin 0 -> 6136 bytes src/main/resources/icons/logo-32.png | Bin 0 -> 736 bytes src/main/resources/icons/logo-48.png | Bin 0 -> 1043 bytes src/main/resources/icons/logo-512.png | Bin 0 -> 13507 bytes src/main/resources/icons/logo-64.png | Bin 0 -> 1302 bytes src/main/resources/icons/wx-zanshang.jpg | Bin 0 -> 33010 bytes src/main/resources/theme/Cyan.theme.json | 293 +++++++++++ .../resources/theme/DarkPurple.theme.json | 421 +++++++++++++++ src/main/resources/theme/Light.theme.json | 145 ++++++ src/main/resources/version_summary.json | 19 + 47 files changed, 4221 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/luoboduner/moo/info/bean/VersionSummary.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/Init.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/UiConsts.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/component/TopMenuBar.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.form create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.form create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.form create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.form create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.form create mode 100644 src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.form create mode 100644 src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form create mode 100644 src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/frame/MainFrame.java create mode 100644 src/main/java/com/luoboduner/moo/info/ui/listener/FrameListener.java create mode 100644 src/main/java/com/luoboduner/moo/info/util/ComponentUtil.java create mode 100644 src/main/java/com/luoboduner/moo/info/util/ConfigBaseUtil.java create mode 100644 src/main/java/com/luoboduner/moo/info/util/ConfigUtil.java create mode 100644 src/main/java/com/luoboduner/moo/info/util/FrameUtil.java create mode 100644 src/main/java/com/luoboduner/moo/info/util/SystemUtil.java create mode 100644 src/main/java/com/luoboduner/moo/info/util/UIUtil.java create mode 100644 src/main/java/com/luoboduner/moo/info/util/UpgradeUtil.java create mode 100644 src/main/resources/icons/MooTool-logo-64.png create mode 100644 src/main/resources/icons/WePush-logo-64.png create mode 100644 src/main/resources/icons/loading_dark.gif create mode 100644 src/main/resources/icons/logo-1024.png create mode 100644 src/main/resources/icons/logo-128.png create mode 100644 src/main/resources/icons/logo-16.png create mode 100644 src/main/resources/icons/logo-24.png create mode 100644 src/main/resources/icons/logo-256.png create mode 100644 src/main/resources/icons/logo-32.png create mode 100644 src/main/resources/icons/logo-48.png create mode 100644 src/main/resources/icons/logo-512.png create mode 100644 src/main/resources/icons/logo-64.png create mode 100644 src/main/resources/icons/wx-zanshang.jpg create mode 100644 src/main/resources/theme/Cyan.theme.json create mode 100644 src/main/resources/theme/DarkPurple.theme.json create mode 100644 src/main/resources/theme/Light.theme.json create mode 100644 src/main/resources/version_summary.json diff --git a/assets/logo/MooInfo.svg b/assets/logo/MooInfo.svg index 86f188f..64500f0 100644 --- a/assets/logo/MooInfo.svg +++ b/assets/logo/MooInfo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/pom.xml b/pom.xml index c9e5e29..057898c 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,8 @@ 4.9.0 1.6.1 1.6.1 + 5.6.3 + 1.2.74 @@ -95,6 +97,17 @@ ${flatlaf-extras.version} + + cn.hutool + hutool-all + ${hutool-all.version} + + + + com.alibaba + fastjson + ${fastjson.version} + diff --git a/src/main/java/com/luoboduner/moo/info/App.java b/src/main/java/com/luoboduner/moo/info/App.java index f5f10e7..7818b64 100644 --- a/src/main/java/com/luoboduner/moo/info/App.java +++ b/src/main/java/com/luoboduner/moo/info/App.java @@ -1,5 +1,16 @@ package com.luoboduner.moo.info; +import com.formdev.flatlaf.util.SystemInfo; +import com.luoboduner.moo.info.ui.Init; +import com.luoboduner.moo.info.ui.form.LoadingForm; +import com.luoboduner.moo.info.ui.form.MainWindow; +import com.luoboduner.moo.info.ui.frame.MainFrame; +import com.luoboduner.moo.info.util.ConfigUtil; +import com.luoboduner.moo.info.util.UpgradeUtil; + +import javax.swing.*; +import java.awt.*; + /** * Main Enter! * @@ -7,4 +18,45 @@ package com.luoboduner.moo.info; * @since 2021/11/07. */ public class App { + + public static ConfigUtil config = ConfigUtil.getInstance(); + + public static MainFrame mainFrame; + + + public static void main(String[] args) { + + if (SystemInfo.isMacOS) { +// java -Xdock:name="MooInfo" -Xdock:icon=MooInfo.jpg ... (whatever else you normally specify here) +// java -Xms64m -Xmx256m -Dapple.awt.application.name="MooInfo" -Dcom.apple.mrj.application.apple.menu.about.name="MooInfo" -cp "./lib/*" com.luoboduner.moo.info.App + System.setProperty("apple.laf.useScreenMenuBar", "true"); + System.setProperty("apple.awt.application.name", "MooInfo"); + System.setProperty("com.apple.mrj.application.apple.menu.about.name", "MooInfo"); + } + + Init.initTheme(); + mainFrame = new MainFrame(); + mainFrame.init(); + JPanel loadingPanel = new LoadingForm().getLoadingPanel(); + mainFrame.add(loadingPanel); + mainFrame.pack(); + mainFrame.setVisible(true); + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + if (config.isDefaultMaxWindow() || screenSize.getWidth() <= 1366) { + // The window is automatically maximized at low resolution + mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); + } + + UpgradeUtil.smoothUpgrade(); + + mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + Init.initGlobalFont(); + mainFrame.setContentPane(MainWindow.getInstance().getMainPanel()); + MainWindow.getInstance().init(); + Init.initAllTab(); + Init.initOthers(); + mainFrame.addListeners(); + mainFrame.remove(loadingPanel); + } } diff --git a/src/main/java/com/luoboduner/moo/info/bean/VersionSummary.java b/src/main/java/com/luoboduner/moo/info/bean/VersionSummary.java new file mode 100644 index 0000000..0e71529 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/bean/VersionSummary.java @@ -0,0 +1,53 @@ +package com.luoboduner.moo.info.bean; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * Version summary + * + * @author RememBerBer + * @since 2021/11/08. + */ +@Data +public class VersionSummary implements Serializable { + + private static final long serialVersionUID = 4637273116136790267L; + + /** + * current version + */ + private String currentVersion; + + /** + * version index + */ + private String versionIndex; + + /** + * list of history versions + */ + private List versionDetailList; + + /** + * Version Class + * + * @author RememBerBer + * @since 2021/11/08. + */ + @Data + public static class Version implements Serializable { + + private static final long serialVersionUID = 4637273116136790268L; + + private String version; + + private String title; + + private String log; + + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/Init.java b/src/main/java/com/luoboduner/moo/info/ui/Init.java new file mode 100644 index 0000000..e848236 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/Init.java @@ -0,0 +1,222 @@ +package com.luoboduner.moo.info.ui; + +import cn.hutool.log.Log; +import cn.hutool.log.LogFactory; +import com.formdev.flatlaf.FlatLightLaf; +import com.formdev.flatlaf.IntelliJTheme; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.ui.component.TopMenuBar; +import com.luoboduner.moo.info.util.SystemUtil; +import com.luoboduner.moo.info.util.UIUtil; +import com.luoboduner.moo.info.util.UpgradeUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javax.swing.*; +import javax.swing.plaf.FontUIResource; +import java.awt.*; +import java.util.Enumeration; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * The init Class + * + * @author RememBerBer + * @since 2021/11/09. + */ +public class Init { + + private static final Log logger = LogFactory.get(); + + /** + * font size inti KEY + */ + private static final String FONT_SIZE_INIT_PROP = "fontSizeInit"; + + /** + * set font for global + */ + public static void initGlobalFont() { + if (StringUtils.isEmpty(App.config.getProps(FONT_SIZE_INIT_PROP))) { + // Adjust the font size according to the DPI + // Gets the resolution of the screen dpi + // dell 1920*1080/24 inch =96 + // Xiaomi air 1920*1080/13.3 inch =144 + // Xiaomi air 1366*768/13.3inch =96 + int fontSize = 12; + + // Initialize high-resolution screen font sizes such as Macs + if (SystemUtil.isMacOs()) { + fontSize = 15; + } else { + fontSize = (int) (UIUtil.getScreenScale() * fontSize); + } + App.config.setFontSize(fontSize); + + App.config.setProps(FONT_SIZE_INIT_PROP, "true"); + App.config.save(); + + TopMenuBar.getInstance().initFontSizeMenu(); + } + + Font font = new Font(App.config.getFont(), Font.PLAIN, App.config.getFontSize()); + FontUIResource fontRes = new FontUIResource(font); + for (Enumeration keys = UIManager.getDefaults().keys(); keys.hasMoreElements(); ) { + Object key = keys.nextElement(); + Object value = UIManager.get(key); + if (value instanceof FontUIResource) { + UIManager.put(key, fontRes); + } + } + + } + + /** + * Other initialization + */ + public static void initOthers() { + + } + + /** + * init look and feel + */ + public static void initTheme() { + if (SystemUtil.isMacM1() || SystemUtil.isLinuxOs()) { + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarculaLaf"); + logger.warn("FlatDarculaLaf theme set."); + } catch (Exception e) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e2) { + logger.error(ExceptionUtils.getStackTrace(e2)); + } + logger.error(ExceptionUtils.getStackTrace(e)); + } + return; + } + + if (App.config.isUnifiedBackground()) { + UIManager.put("TitlePane.unifiedBackground", true); + } + + try { + switch (App.config.getTheme()) { + case "System Default": + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + break; + case "Flat Light": + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + FlatLightLaf.install(); + break; + case "Flat IntelliJ": + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatIntelliJLaf"); + break; + case "Flat Dark": + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarkLaf"); + break; + case "Darcula": + case "Darcula(Recommended)": + case "Flat Darcula(Recommended)": + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarculaLaf"); + + UIManager.put("PopupMenu.background", UIManager.getColor("Panel.background")); + +/** + If you don't like/want it, you can disable it with: + UIManager.put( "TitlePane.useWindowDecorations", false ); + + It is also possible to disable only the embedded menu bar (and keep the dark title pane) with: + UIManager.put( "TitlePane.menuBarEmbedded", false ); + + It is also possible to disable this on command line with following VM options: + -Dflatlaf.useWindowDecorations=false + -Dflatlaf.menuBarEmbedded=false + + If you have following code in your app, you can remove it (no longer necessary): + // enable window decorations + JFrame.setDefaultLookAndFeelDecorated( true ); + JDialog.setDefaultLookAndFeelDecorated( true ); + **/ + break; + case "Dark purple": + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + IntelliJTheme.setup(App.class.getResourceAsStream( + "/theme/DarkPurple.theme.json")); + break; + case "IntelliJ Cyan": + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + IntelliJTheme.setup(App.class.getResourceAsStream( + "/theme/Cyan.theme.json")); + break; + case "IntelliJ Light": + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + IntelliJTheme.setup(App.class.getResourceAsStream( + "/theme/Light.theme.json")); + break; + + default: + if (SystemUtil.isJBR()) { + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + } + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarculaLaf"); + } + } catch (Exception e) { + logger.error(e); + } + } + + /** + * init all tab + */ + public static void initAllTab() { + + // Check the new version + if (App.config.isAutoCheckUpdate()) { + ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(1); + threadPoolExecutor.scheduleAtFixedRate(() -> UpgradeUtil.checkUpdate(true), 0, 24, TimeUnit.HOURS); + } + } + + public static void showMainFrame() { + App.mainFrame.setVisible(true); + if (App.mainFrame.getExtendedState() == Frame.ICONIFIED) { + App.mainFrame.setExtendedState(Frame.NORMAL); + } else if (App.mainFrame.getExtendedState() == 7) { + App.mainFrame.setExtendedState(Frame.MAXIMIZED_BOTH); + } + App.mainFrame.requestFocus(); + } + + public static void shutdown() { + App.mainFrame.dispose(); + System.exit(0); + } +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/UiConsts.java b/src/main/java/com/luoboduner/moo/info/ui/UiConsts.java new file mode 100644 index 0000000..e4e33d0 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/UiConsts.java @@ -0,0 +1,78 @@ +package com.luoboduner.moo.info.ui; + +import java.awt.*; + +/** + * constants about UI + * + * @author RememBerBer + * @since 2021/11/08. + */ +public class UiConsts { + + public static final String APP_NAME = "MooInfo"; + public static final String APP_VERSION = "1.0.0"; + + public static final int TABLE_ROW_HEIGHT = 36; + + /** + * Logo-1024*1024 + */ + public static final Image IMAGE_LOGO_1024 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-1024.png")); + + /** + * Logo-512*512 + */ + public static final Image IMAGE_LOGO_512 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-512.png")); + + /** + * Logo-256*256 + */ + public static final Image IMAGE_LOGO_256 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-256.png")); + + /** + * Logo-128*128 + */ + public static final Image IMAGE_LOGO_128 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-128.png")); + + /** + * Logo-64*64 + */ + public static final Image IMAGE_LOGO_64 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-64.png")); + + /** + * Logo-48*48 + */ + public static final Image IMAGE_LOGO_48 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-48.png")); + + /** + * Logo-32*32 + */ + public static final Image IMAGE_LOGO_32 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-32.png")); + + /** + * Logo-24*24 + */ + public static final Image IMAGE_LOGO_24 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-24.png")); + + /** + * Logo-16*16 + */ + public static final Image IMAGE_LOGO_16 = Toolkit.getDefaultToolkit() + .getImage(UiConsts.class.getResource("/icons/logo-16.png")); + + /** + * update checking url + */ + public static final String CHECK_VERSION_URL = "https://gitee.com/zhoubochina/MooInfo/raw/master/src/main/resources/version_summary.json"; + + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/component/TopMenuBar.java b/src/main/java/com/luoboduner/moo/info/ui/component/TopMenuBar.java new file mode 100644 index 0000000..eba7a4f --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/component/TopMenuBar.java @@ -0,0 +1,375 @@ +package com.luoboduner.moo.info.ui.component; + +import com.formdev.flatlaf.FlatLaf; +import com.formdev.flatlaf.extras.FlatAnimatedLafChange; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.ui.Init; +import com.luoboduner.moo.info.ui.dialog.AboutDialog; +import com.luoboduner.moo.info.ui.dialog.SettingDialog; +import com.luoboduner.moo.info.ui.dialog.SystemEnvResultDialog; +import com.luoboduner.moo.info.ui.form.MainWindow; +import com.luoboduner.moo.info.util.SystemUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.Map; +import java.util.Properties; + +/** + * The top menu bar + * + * @author RememBerBer + * @since 2021/11/10. + */ +@Slf4j +public class TopMenuBar extends JMenuBar { + + private static TopMenuBar menuBar; + + private static JMenu themeMenu; + + private static JMenu fontFamilyMenu; + + private static JMenu fontSizeMenu; + + private static int initialThemeItemCount = -1; + + private static int initialFontFamilyItemCount = -1; + + private static int initialFontSizeItemCount = -1; + + private static String[] themeNames = { + "System Default", + "Flat Light", + "Flat IntelliJ", + "Flat Dark", + "Flat Darcula(Recommended)", + "Dark purple", + "IntelliJ Cyan", + "IntelliJ Light"}; + + private static String[] fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); + + private static String[] fontSizes = { + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26"}; + + private TopMenuBar() { + } + + public static TopMenuBar getInstance() { + if (menuBar == null) { + menuBar = new TopMenuBar(); + } + return menuBar; + } + + public void init() { + TopMenuBar topMenuBar = getInstance(); + // ---------App + JMenu appMenu = new JMenu(); + appMenu.setText("App"); + // Setting + JMenuItem settingMenuItem = new JMenuItem(); + settingMenuItem.setText("Settings"); + settingMenuItem.addActionListener(e -> settingActionPerformed()); + appMenu.add(settingMenuItem); + // Exit + JMenuItem exitMenuItem = new JMenuItem(); + exitMenuItem.setText("Exit"); + exitMenuItem.addActionListener(e -> exitActionPerformed()); + appMenu.add(exitMenuItem); + topMenuBar.add(appMenu); + + // ---------Appearance + JMenu appearanceMenu = new JMenu(); + appearanceMenu.setText("Appearance"); + + JCheckBoxMenuItem defaultMaxWindowitem = new JCheckBoxMenuItem("Maximize window by Default"); + defaultMaxWindowitem.setSelected(App.config.isDefaultMaxWindow()); + defaultMaxWindowitem.addActionListener(e -> { + boolean selected = defaultMaxWindowitem.isSelected(); + if (selected) { + App.mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); + } else { + App.mainFrame.setExtendedState(JFrame.NORMAL); + } + App.config.setDefaultMaxWindow(selected); + App.config.save(); + }); + appearanceMenu.add(defaultMaxWindowitem); + + JCheckBoxMenuItem unifiedBackgrounditem = new JCheckBoxMenuItem("Window color immersive"); + unifiedBackgrounditem.setSelected(App.config.isUnifiedBackground()); + unifiedBackgrounditem.addActionListener(e -> { + boolean selected = unifiedBackgrounditem.isSelected(); + App.config.setUnifiedBackground(selected); + App.config.save(); + UIManager.put("TitlePane.unifiedBackground", selected); + FlatLaf.updateUI(); + }); + appearanceMenu.add(unifiedBackgrounditem); + + themeMenu = new JMenu(); + themeMenu.setText("Theme"); + + initThemesMenu(); + + appearanceMenu.add(themeMenu); + + fontFamilyMenu = new JMenu(); + fontFamilyMenu.setText("Font Family"); + initFontFamilyMenu(); + + appearanceMenu.add(fontFamilyMenu); + + fontSizeMenu = new JMenu(); + fontSizeMenu.setText("Font Size"); + initFontSizeMenu(); + + appearanceMenu.add(fontSizeMenu); + + topMenuBar.add(appearanceMenu); + // ---------Debug + JMenu debugMenu = new JMenu(); + debugMenu.setText("Debug"); + // Show logs + JMenuItem logMenuItem = new JMenuItem(); + logMenuItem.setText("Show logs"); + logMenuItem.addActionListener(e -> logActionPerformed()); + + debugMenu.add(logMenuItem); + // System environment variables + JMenuItem sysEnvMenuItem = new JMenuItem(); + sysEnvMenuItem.setText("System environment variables"); + sysEnvMenuItem.addActionListener(e -> sysEnvActionPerformed()); + + debugMenu.add(sysEnvMenuItem); + + topMenuBar.add(debugMenu); + // ---------About + JMenu aboutMenu = new JMenu(); + aboutMenu.setText("About"); + + // About + JMenuItem aboutMenuItem = new JMenuItem(); + aboutMenuItem.setText("About"); + aboutMenuItem.addActionListener(e -> aboutActionPerformed()); + aboutMenu.add(aboutMenuItem); + + topMenuBar.add(aboutMenu); + } + + public void initFontSizeMenu() { + + if (initialFontSizeItemCount < 0) + initialFontSizeItemCount = fontSizeMenu.getItemCount(); + else { + // remove old items + for (int i = fontSizeMenu.getItemCount() - 1; i >= initialFontSizeItemCount; i--) + fontSizeMenu.remove(i); + } + for (String fontSize : fontSizes) { + JCheckBoxMenuItem item = new JCheckBoxMenuItem(fontSize); + item.setSelected(fontSize.equals(String.valueOf(App.config.getFontSize()))); + item.addActionListener(this::fontSizeChanged); + fontSizeMenu.add(item); + } + } + + + private void initFontFamilyMenu() { + + if (initialFontFamilyItemCount < 0) + initialFontFamilyItemCount = fontFamilyMenu.getItemCount(); + else { + // remove old items + for (int i = fontFamilyMenu.getItemCount() - 1; i >= initialFontFamilyItemCount; i--) + fontFamilyMenu.remove(i); + } + for (String font : fontNames) { + JCheckBoxMenuItem item = new JCheckBoxMenuItem(font); + item.setSelected(font.equals(App.config.getFont())); + item.addActionListener(this::fontFamilyChanged); + fontFamilyMenu.add(item); + } + } + + private void initThemesMenu() { + + if (initialThemeItemCount < 0) + initialThemeItemCount = themeMenu.getItemCount(); + else { + // remove old items + for (int i = themeMenu.getItemCount() - 1; i >= initialThemeItemCount; i--) + themeMenu.remove(i); + } + for (String themeName : themeNames) { + JCheckBoxMenuItem item = new JCheckBoxMenuItem(themeName); + item.setSelected(themeName.equals(App.config.getTheme())); + item.addActionListener(this::themeChanged); + themeMenu.add(item); + } + } + + private void fontSizeChanged(ActionEvent actionEvent) { + try { + String selectedFontSize = actionEvent.getActionCommand(); + + FlatAnimatedLafChange.showSnapshot(); + + App.config.setFontSize(Integer.parseInt(selectedFontSize)); + App.config.save(); + + Init.initGlobalFont(); + SwingUtilities.updateComponentTreeUI(App.mainFrame); + SwingUtilities.updateComponentTreeUI(MainWindow.getInstance().getTabbedPane()); + +// FlatLaf.updateUI(); + + FlatAnimatedLafChange.hideSnapshotWithAnimation(); + + initFontSizeMenu(); + + } catch (Exception e1) { + JOptionPane.showMessageDialog(MainWindow.getInstance().getMainPanel(), "Save failed!\n\n" + e1.getMessage(), "Failed", + JOptionPane.ERROR_MESSAGE); + log.error(ExceptionUtils.getStackTrace(e1)); + } + } + + + private void fontFamilyChanged(ActionEvent actionEvent) { + try { + String selectedFamily = actionEvent.getActionCommand(); + + FlatAnimatedLafChange.showSnapshot(); + + App.config.setFont(selectedFamily); + App.config.save(); + + Init.initGlobalFont(); + SwingUtilities.updateComponentTreeUI(App.mainFrame); + SwingUtilities.updateComponentTreeUI(MainWindow.getInstance().getTabbedPane()); + +// FlatLaf.updateUI(); + + FlatAnimatedLafChange.hideSnapshotWithAnimation(); + + initFontFamilyMenu(); + + } catch (Exception e1) { + JOptionPane.showMessageDialog(MainWindow.getInstance().getMainPanel(), "Save failed!\n\n" + e1.getMessage(), "Failed", + JOptionPane.ERROR_MESSAGE); + log.error(ExceptionUtils.getStackTrace(e1)); + } + } + + private void themeChanged(ActionEvent actionEvent) { + try { + String selectedThemeName = actionEvent.getActionCommand(); + + FlatAnimatedLafChange.showSnapshot(); + + App.config.setTheme(selectedThemeName); + App.config.save(); + + Init.initTheme(); + SwingUtilities.updateComponentTreeUI(App.mainFrame); + SwingUtilities.updateComponentTreeUI(MainWindow.getInstance().getTabbedPane()); + +// FlatLaf.updateUI(); + + FlatAnimatedLafChange.hideSnapshotWithAnimation(); + + initThemesMenu(); + + } catch (Exception e1) { + JOptionPane.showMessageDialog(MainWindow.getInstance().getMainPanel(), "Save failed!\n\n" + e1.getMessage(), "Failed", + JOptionPane.ERROR_MESSAGE); + log.error(ExceptionUtils.getStackTrace(e1)); + } + } + + private void aboutActionPerformed() { + try { + AboutDialog dialog = new AboutDialog(); + + dialog.pack(); + dialog.setVisible(true); + } catch (Exception e2) { + log.error(ExceptionUtils.getStackTrace(e2)); + } + } + + private void sysEnvActionPerformed() { + try { + SystemEnvResultDialog dialog = new SystemEnvResultDialog(); + + dialog.appendTextArea("------------System.getenv---------------"); + Map map = System.getenv(); + for (Map.Entry envEntry : map.entrySet()) { + dialog.appendTextArea(envEntry.getKey() + "=" + envEntry.getValue()); + } + + dialog.appendTextArea("------------System.getProperties---------------"); + Properties properties = System.getProperties(); + for (Map.Entry objectObjectEntry : properties.entrySet()) { + dialog.appendTextArea(objectObjectEntry.getKey() + "=" + objectObjectEntry.getValue()); + } + + dialog.pack(); + dialog.setVisible(true); + } catch (Exception e2) { + log.error("Show system environment variables failed", e2); + } + } + + private void logActionPerformed() { + try { + Desktop desktop = Desktop.getDesktop(); + desktop.open(new File(SystemUtil.LOG_DIR)); + } catch (Exception e2) { + log.error("Show log failed", e2); + } + } + + private void exitActionPerformed() { + Init.shutdown(); + } + + private void settingActionPerformed() { + try { + SettingDialog dialog = new SettingDialog(); + + dialog.pack(); + dialog.setVisible(true); + } catch (Exception e2) { + log.error(ExceptionUtils.getStackTrace(e2)); + } + } +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.form b/src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.form new file mode 100644 index 0000000..4281be4 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.form @@ -0,0 +1,344 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.java b/src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.java new file mode 100644 index 0000000..eac4080 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/AboutDialog.java @@ -0,0 +1,488 @@ +package com.luoboduner.moo.info.ui.dialog; + +import cn.hutool.core.thread.ThreadUtil; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.ui.UiConsts; +import com.luoboduner.moo.info.util.ComponentUtil; +import com.luoboduner.moo.info.util.UpgradeUtil; + +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.plaf.FontUIResource; +import javax.swing.text.StyleContext; +import java.awt.*; +import java.awt.event.*; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Locale; + +public class AboutDialog extends JDialog { + private JPanel contentPane; + private JScrollPane scrollPane; + private JLabel versionLabel; + private JLabel codeGitHubLabel; + private JLabel codeGiteeLabel; + private JLabel issueLabel; + private JLabel hutoolLabel; + private JLabel vsCodeIconsLabel; + private JLabel wePushLinkLabel; + private JPanel wePushPanel; + private JLabel authorLabel; + private JLabel logoLabel; + private JLabel flatLafLabel; + private JPanel mooToolPanel; + private JLabel httpsGithubComRememberberLabel; + + public AboutDialog() { + + super(App.mainFrame, "About"); + ComponentUtil.setPreferSizeAndLocateToCenter(this, 0.4, 0.64); + setContentPane(contentPane); + setModal(true); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + onOK(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(e -> onOK(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + versionLabel.setText(UiConsts.APP_VERSION); + + scrollPane.getVerticalScrollBar().setUnitIncrement(16); + scrollPane.getVerticalScrollBar().setDoubleBuffered(true); + contentPane.updateUI(); + + logoLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://rememberber.github.io/MooInfo/")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + authorLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("http://www.luoboduner.com/")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + codeGitHubLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/rememberber/MooInfo")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + codeGiteeLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://gitee.com/zhoubochina/MooInfo")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + issueLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/rememberber/MooInfo/issues")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + flatLafLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/JFormDesigner/FlatLaf")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + hutoolLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://hutool.cn/")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + wePushPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/rememberber/WePush")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + mooToolPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/rememberber/MooTool")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + vsCodeIconsLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/microsoft/vscode-icons")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + // Check for updates + versionLabel.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + ThreadUtil.execute(() -> UpgradeUtil.checkUpdate(false)); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + e.getComponent().setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }); + } + + private void onOK() { + // add your code here + dispose(); + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + contentPane = new JPanel(); + contentPane.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + scrollPane = new JScrollPane(); + contentPane.add(scrollPane, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + scrollPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(9, 2, new Insets(40, 40, 40, 0), -1, -1)); + scrollPane.setViewportView(panel1); + panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + logoLabel = new JLabel(); + logoLabel.setIcon(new ImageIcon(getClass().getResource("/icons/logo-128.png"))); + logoLabel.setText(""); + panel1.add(logoLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + panel1.add(spacer1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final Spacer spacer2 = new Spacer(); + panel1.add(spacer2, new GridConstraints(8, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(3, 1, new Insets(5, 3, 20, 0), -1, -1)); + panel1.add(panel2, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "MooInfo", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, 20, panel2.getFont()), new Color(-4425028))); + final JLabel label1 = new JLabel(); + label1.setText("A visual implementation of OSHI, to view information about the system and hardware"); + panel2.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + authorLabel = new JLabel(); + authorLabel.setText("Proudly by RememBerBer 周波"); + panel2.add(authorLabel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + versionLabel = new JLabel(); + Font versionLabelFont = this.$$$getFont$$$(null, Font.BOLD, -1, versionLabel.getFont()); + if (versionLabelFont != null) versionLabel.setFont(versionLabelFont); + versionLabel.setText("v0.0.0"); + versionLabel.setToolTipText("Check for updates"); + panel2.add(versionLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridLayoutManager(5, 1, new Insets(5, 3, 20, 0), -1, -1)); + panel1.add(panel3, new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "About", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel3.getFont()), null)); + final JLabel label2 = new JLabel(); + label2.setText("Hi. Thanks to use MooInfo. \"Moo\" named from my daughter."); + panel3.add(label2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label3 = new JLabel(); + label3.setText("Less Java developer use Swing building projects, but I still love to develop by it."); + panel3.add(label3, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label4 = new JLabel(); + label4.setText("So every little free time, I had went towards the development."); + panel3.add(label4, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label5 = new JLabel(); + label5.setText("I did some works finaly, although there are so many same on web page."); + panel3.add(label5, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label6 = new JLabel(); + label6.setText("Hope you enjoy using it as much as I did building it."); + panel3.add(label6, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel4 = new JPanel(); + panel4.setLayout(new GridLayoutManager(2, 1, new Insets(5, 3, 20, 0), -1, -1)); + panel1.add(panel4, new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel4.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "CODE", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel4.getFont()), null)); + codeGitHubLabel = new JLabel(); + codeGitHubLabel.setText("GitHub:https://github.com/rememberber/MooInfo"); + panel4.add(codeGitHubLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + codeGiteeLabel = new JLabel(); + codeGiteeLabel.setText("Gitee:https://gitee.com/zhoubochina/MooInfo"); + panel4.add(codeGiteeLabel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel5 = new JPanel(); + panel5.setLayout(new GridLayoutManager(1, 1, new Insets(5, 3, 20, 0), -1, -1)); + panel1.add(panel5, new GridConstraints(4, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel5.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "HELP TO DO BETTER", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel5.getFont()), null)); + issueLabel = new JLabel(); + issueLabel.setText("https://github.com/rememberber/MooInfo/issues"); + panel5.add(issueLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel6 = new JPanel(); + panel6.setLayout(new GridLayoutManager(3, 1, new Insets(5, 3, 20, 0), -1, -1)); + panel1.add(panel6, new GridConstraints(5, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel6.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "THANKS TO", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel6.getFont()), null)); + flatLafLabel = new JLabel(); + flatLafLabel.setText("FlatLaf"); + panel6.add(flatLafLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + hutoolLabel = new JLabel(); + hutoolLabel.setText("Hutool"); + panel6.add(hutoolLabel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + vsCodeIconsLabel = new JLabel(); + vsCodeIconsLabel.setText("vscode-icons"); + panel6.add(vsCodeIconsLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel7 = new JPanel(); + panel7.setLayout(new GridLayoutManager(1, 1, new Insets(5, 3, 20, 0), -1, -1)); + panel1.add(panel7, new GridConstraints(6, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel7.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "SPONSOR", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel7.getFont()), null)); + final JLabel label7 = new JLabel(); + label7.setIcon(new ImageIcon(getClass().getResource("/icons/wx-zanshang.jpg"))); + label7.setText(""); + label7.setToolTipText("感谢您的鼓励和支持"); + panel7.add(label7, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel8 = new JPanel(); + panel8.setLayout(new GridLayoutManager(2, 1, new Insets(5, 3, 20, 0), -1, -1)); + panel1.add(panel8, new GridConstraints(7, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel8.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "OTHER WORKS", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel8.getFont()), null)); + wePushPanel = new JPanel(); + wePushPanel.setLayout(new GridLayoutManager(4, 1, new Insets(0, 0, 0, 0), -1, -1)); + panel8.add(wePushPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + wePushLinkLabel = new JLabel(); + wePushLinkLabel.setText("https://github.com/rememberber/WePush"); + wePushPanel.add(wePushLinkLabel, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label8 = new JLabel(); + label8.setIcon(new ImageIcon(getClass().getResource("/icons/WePush-logo-64.png"))); + label8.setText(""); + wePushPanel.add(label8, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label9 = new JLabel(); + label9.setText("WePush"); + wePushPanel.add(label9, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label10 = new JLabel(); + label10.setText("专注批量推送的小而美的工具"); + wePushPanel.add(label10, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + mooToolPanel = new JPanel(); + mooToolPanel.setLayout(new GridLayoutManager(4, 1, new Insets(0, 0, 0, 0), -1, -1)); + panel8.add(mooToolPanel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + httpsGithubComRememberberLabel = new JLabel(); + httpsGithubComRememberberLabel.setText("https://github.com/rememberber/MooTool"); + mooToolPanel.add(httpsGithubComRememberberLabel, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label11 = new JLabel(); + label11.setIcon(new ImageIcon(getClass().getResource("/icons/MooTool-logo-64.png"))); + label11.setText(""); + mooToolPanel.add(label11, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label12 = new JLabel(); + label12.setText("MooTool"); + mooToolPanel.add(label12, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label13 = new JLabel(); + label13.setText("A handy tool set for developers."); + mooToolPanel.add(label13, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + } + + /** + * @noinspection ALL + */ + private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) { + if (currentFont == null) return null; + String resultName; + if (fontName == null) { + resultName = currentFont.getName(); + } else { + Font testFont = new Font(fontName, Font.PLAIN, 10); + if (testFont.canDisplay('a') && testFont.canDisplay('1')) { + resultName = fontName; + } else { + resultName = currentFont.getName(); + } + } + Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize()); + boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac"); + Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize()); + return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return contentPane; + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.form b/src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.form new file mode 100644 index 0000000..5e47749 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.form @@ -0,0 +1,97 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.java b/src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.java new file mode 100644 index 0000000..1eb30b3 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/SettingDialog.java @@ -0,0 +1,150 @@ +package com.luoboduner.moo.info.ui.dialog; + +import cn.hutool.log.Log; +import cn.hutool.log.LogFactory; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.util.ComponentUtil; + +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.plaf.FontUIResource; +import javax.swing.text.StyleContext; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Locale; + +public class SettingDialog extends JDialog { + + private static final Log logger = LogFactory.get(); + + private JPanel contentPane; + private JScrollPane settingScrollPane; + private JCheckBox autoCheckUpdateCheckBox; + private JComboBox comboBox1; + + public SettingDialog() { + + super(App.mainFrame, "Settings"); + ComponentUtil.setPreferSizeAndLocateToCenter(this, 0.5, 0.6); + setContentPane(contentPane); + setModal(true); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + onOK(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(e -> onOK(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + // Set the scroll bar speed + settingScrollPane.getVerticalScrollBar().setUnitIncrement(16); + settingScrollPane.getVerticalScrollBar().setDoubleBuffered(true); + + // routine + autoCheckUpdateCheckBox.setSelected(App.config.isAutoCheckUpdate()); + + contentPane.updateUI(); + + // Settings-routine-Updates are checked automatically at startup + autoCheckUpdateCheckBox.addActionListener(e -> { + App.config.setAutoCheckUpdate(autoCheckUpdateCheckBox.isSelected()); + App.config.save(); + }); + + } + + private void onOK() { + // add your code here + dispose(); + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + contentPane = new JPanel(); + contentPane.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + settingScrollPane = new JScrollPane(); + contentPane.add(settingScrollPane, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + settingScrollPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(2, 2, new Insets(20, 20, 10, 10), -1, -1)); + settingScrollPane.setViewportView(panel1); + final Spacer spacer1 = new Spacer(); + panel1.add(spacer1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + panel1.add(panel2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(600, -1), null, 0, false)); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridLayoutManager(2, 3, new Insets(15, 15, 25, 0), -1, -1)); + panel2.add(panel3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "Routine", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel3.getFont()), null)); + autoCheckUpdateCheckBox = new JCheckBox(); + autoCheckUpdateCheckBox.setText("Automatically check for updates"); + panel3.add(autoCheckUpdateCheckBox, new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label1 = new JLabel(); + label1.setText("Language"); + panel3.add(label1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + comboBox1 = new JComboBox(); + comboBox1.setEnabled(false); + final DefaultComboBoxModel defaultComboBoxModel1 = new DefaultComboBoxModel(); + defaultComboBoxModel1.addElement("English"); + defaultComboBoxModel1.addElement("简体中文"); + comboBox1.setModel(defaultComboBoxModel1); + panel3.add(comboBox1, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer2 = new Spacer(); + panel3.add(spacer2, new GridConstraints(1, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final Spacer spacer3 = new Spacer(); + panel1.add(spacer3, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + } + + /** + * @noinspection ALL + */ + private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) { + if (currentFont == null) return null; + String resultName; + if (fontName == null) { + resultName = currentFont.getName(); + } else { + Font testFont = new Font(fontName, Font.PLAIN, 10); + if (testFont.canDisplay('a') && testFont.canDisplay('1')) { + resultName = fontName; + } else { + resultName = currentFont.getName(); + } + } + Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize()); + boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac"); + Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize()); + return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return contentPane; + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.form b/src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.form new file mode 100644 index 0000000..bba7a4c --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.form @@ -0,0 +1,69 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.java b/src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.java new file mode 100644 index 0000000..1c8fcd4 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/SystemEnvResultDialog.java @@ -0,0 +1,103 @@ +package com.luoboduner.moo.info.ui.dialog; + +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.util.ComponentUtil; + +import javax.swing.*; +import javax.swing.border.TitledBorder; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class SystemEnvResultDialog extends JDialog { + private JPanel contentPane; + private JButton buttonOK; + private JTextArea textArea1; + + public SystemEnvResultDialog() { + + super(App.mainFrame, "System environment variables"); + ComponentUtil.setPreferSizeAndLocateToCenter(this, 0.4, 0.64); + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(e -> onOK()); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + onOK(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(e -> onOK(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + } + + private void onOK() { + // add your code here + dispose(); + } + + public void setTextArea(String str) { + textArea1.setText(str); + } + + public void appendTextArea(String str) { + textArea1.append(str); + textArea1.append("\n"); + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + contentPane = new JPanel(); + contentPane.setLayout(new GridLayoutManager(2, 1, new Insets(10, 10, 10, 10), -1, -1)); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(panel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + panel1.add(spacer1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + panel1.add(panel2, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + buttonOK = new JButton(); + buttonOK.setText("OK"); + panel2.add(buttonOK, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(panel3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JScrollPane scrollPane1 = new JScrollPane(); + panel3.add(scrollPane1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + scrollPane1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + textArea1 = new JTextArea(); + scrollPane1.setViewportView(textArea1); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return contentPane; + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.form b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.form new file mode 100644 index 0000000..084f7c4 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.form @@ -0,0 +1,96 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.java b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.java new file mode 100644 index 0000000..46e6b11 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateDialog.java @@ -0,0 +1,190 @@ +package com.luoboduner.moo.info.ui.dialog; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.StreamProgress; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.http.HttpUtil; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.util.ComponentUtil; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * Update download dialog + * + * @author RememBerBer + * @since 2021/11/08. + */ +public class UpdateDialog extends JDialog { + private static final long serialVersionUID = -5858063892133811698L; + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JProgressBar progressBarDownload; + private JButton buttonDownloadFromWeb; + private JLabel statusLabel; + private File downLoadFile; + + public UpdateDialog() { + super(App.mainFrame, "Download the new version"); + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + + ComponentUtil.setPreferSizeAndLocateToCenter(this, 600, 200); + + buttonOK.addActionListener(e -> onOK()); + + buttonCancel.addActionListener(e -> onCancel()); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + buttonDownloadFromWeb.addActionListener(e -> { + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/rememberber/MooInfo/releases")); + } catch (IOException | URISyntaxException ex) { + ex.printStackTrace(); + } + }); + } + + public void downLoad(String newVersion) { + buttonOK.setEnabled(false); + ThreadUtil.execute( + () -> { + String fileUrl = "http://download.zhoubochina.com/moo/exe/MooInfo-" + newVersion + "-x64-Setup.exe"; + String fileName = FileUtil.getName(fileUrl); + URL url; + try { + url = new URL(fileUrl); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + // Get the appropriate file length + int fileLength = urlConnection.getContentLength(); + progressBarDownload.setMaximum(fileLength); + } catch (IOException e) { + e.printStackTrace(); + } + + File tempDir = new File(FileUtil.getTmpDirPath() + "MooInfo"); + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + FileUtil.clean(tempDir); + downLoadFile = FileUtil.file(tempDir + File.separator + fileName); + HttpUtil.downloadFile(fileUrl, FileUtil.touch(downLoadFile), new StreamProgress() { + + @Override + public void start() { + statusLabel.setText("Start downloading..."); + } + + @Override + public void progress(long progressSize) { + progressBarDownload.setValue((int) progressSize); + statusLabel.setText("Already download:" + FileUtil.readableFileSize(progressSize)); + } + + @Override + public void finish() { + statusLabel.setText("Download finished!"); + buttonOK.setEnabled(true); + } + }); + } + ); + } + + private void onOK() { + try { + Desktop.getDesktop().open(downLoadFile); + dispose(); + System.exit(0); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void onCancel() { + // add your code here if necessary + dispose(); + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + contentPane = new JPanel(); + contentPane.setLayout(new GridLayoutManager(2, 1, new Insets(10, 10, 10, 10), -1, -1)); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(panel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + panel1.add(spacer1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1)); + panel1.add(panel2, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + buttonOK = new JButton(); + buttonOK.setText("立即安装"); + panel2.add(buttonOK, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + buttonCancel = new JButton(); + buttonCancel.setText("取消"); + panel2.add(buttonCancel, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + buttonDownloadFromWeb = new JButton(); + buttonDownloadFromWeb.setText("打开下载页面"); + panel2.add(buttonDownloadFromWeb, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridLayoutManager(4, 1, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(panel3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + progressBarDownload = new JProgressBar(); + panel3.add(progressBarDownload, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + statusLabel = new JLabel(); + statusLabel.setText("就绪"); + panel3.add(statusLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer2 = new Spacer(); + panel3.add(spacer2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + final Spacer spacer3 = new Spacer(); + panel3.add(spacer3, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return contentPane; + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.form b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.form new file mode 100644 index 0000000..479456c --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.form @@ -0,0 +1,86 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.java b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.java new file mode 100644 index 0000000..948743e --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/dialog/UpdateInfoDialog.java @@ -0,0 +1,157 @@ +package com.luoboduner.moo.info.ui.dialog; + +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.util.ComponentUtil; +import com.luoboduner.moo.info.util.SystemUtil; +import lombok.Getter; + +import javax.swing.*; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.StyleSheet; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Dialog of update info + * + * @author RememBerBer + * @since 2021/11/08. + */ +@Getter +public class UpdateInfoDialog extends JDialog { + private static final long serialVersionUID = -9114988145315865608L; + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JTextPane textPane1; + private String newVersion; + + public void setNewVersion(String newVersion) { + this.newVersion = newVersion; + } + + public UpdateInfoDialog() { + super(App.mainFrame, "Surprise the new version"); + + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + + ComponentUtil.setPreferSizeAndLocateToCenter(this, 0.4, 0.64); + + buttonOK.addActionListener(e -> onOK()); + + buttonCancel.addActionListener(e -> onCancel()); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + } + + private void onOK() { + if (SystemUtil.isMacOs()) { + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("https://github.com/rememberber/MooInfo/releases")); + } catch (IOException | URISyntaxException ex) { + ex.printStackTrace(); + } + } else { + UpdateDialog dialog = new UpdateDialog(); + dialog.pack(); + dialog.downLoad(newVersion); + dialog.setVisible(true); + } + dispose(); + } + + private void onCancel() { + dispose(); + } + + public void setPlaneText(String planeText) { + textPane1.setContentType("text/plain; charset=utf-8"); + textPane1.setText(planeText); + textPane1.setCaretPosition(0); + } + + public void setHtmlText(String htmlText) { + textPane1.setContentType("text/html; charset=utf-8"); + HTMLEditorKit kit = new HTMLEditorKit(); + textPane1.setEditorKit(kit); + StyleSheet styleSheet = kit.getStyleSheet(); + styleSheet.addRule("h2{color:#FBC87A;}"); + styleSheet.addRule("body{font-family:" + buttonOK.getFont().getName() + ";font-size:" + buttonOK.getFont().getSize() + ";}"); + textPane1.setText(htmlText); + textPane1.setCaretPosition(0); + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + contentPane = new JPanel(); + contentPane.setLayout(new GridLayoutManager(2, 1, new Insets(0, 0, 10, 0), -1, -1)); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(panel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + panel1.add(spacer1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1)); + panel1.add(panel2, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + buttonOK = new JButton(); + buttonOK.setText("立即下载"); + panel2.add(buttonOK, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + buttonCancel = new JButton(); + buttonCancel.setText("取消"); + panel2.add(buttonCancel, new GridConstraints(0, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer2 = new Spacer(); + panel1.add(spacer2, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(panel3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JScrollPane scrollPane1 = new JScrollPane(); + panel3.add(scrollPane1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + textPane1 = new JTextPane(); + textPane1.setEditable(false); + textPane1.setMargin(new Insets(80, 28, 3, 28)); + textPane1.setText(""); + scrollPane1.setViewportView(textPane1); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return contentPane; + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.form b/src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.form new file mode 100644 index 0000000..811d6cf --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.form @@ -0,0 +1,24 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.java b/src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.java new file mode 100644 index 0000000..f430e43 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/form/LoadingForm.java @@ -0,0 +1,78 @@ +package com.luoboduner.moo.info.ui.form; + +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import lombok.Getter; + +import javax.swing.*; +import javax.swing.plaf.FontUIResource; +import javax.swing.text.StyleContext; +import java.awt.*; +import java.util.Locale; + +/** + * the loading form + * + * @author RememBerBer + * @since 2021/11/10. + */ +@Getter +public class LoadingForm { + private JPanel loadingPanel; + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + loadingPanel = new JPanel(); + loadingPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + final JLabel label1 = new JLabel(); + Font label1Font = this.$$$getFont$$$(null, -1, 26, label1.getFont()); + if (label1Font != null) label1.setFont(label1Font); + label1.setHorizontalAlignment(10); + label1.setIcon(new ImageIcon(getClass().getResource("/icons/loading_dark.gif"))); + label1.setText("Loading……"); + loadingPanel.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + } + + /** + * @noinspection ALL + */ + private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) { + if (currentFont == null) return null; + String resultName; + if (fontName == null) { + resultName = currentFont.getName(); + } else { + Font testFont = new Font(fontName, Font.PLAIN, 10); + if (testFont.canDisplay('a') && testFont.canDisplay('1')) { + resultName = fontName; + } else { + resultName = currentFont.getName(); + } + } + Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize()); + boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac"); + Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize()); + return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return loadingPanel; + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form new file mode 100644 index 0000000..3000706 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form @@ -0,0 +1,35 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java new file mode 100644 index 0000000..742e5be --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java @@ -0,0 +1,73 @@ +package com.luoboduner.moo.info.ui.form; + +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import lombok.Getter; + +import javax.swing.*; +import java.awt.*; + +/** + * The main interface + * + * @author RememBerBer + * @since 2021/11/10. + */ +@Getter +public class MainWindow { + private JTabbedPane tabbedPane; + private JPanel mainPanel; + private JPanel overViewPanel; + + private static MainWindow mainWindow; + + private MainWindow() { + } + + public static MainWindow getInstance() { + if (mainWindow == null) { + mainWindow = new MainWindow(); + } + return mainWindow; + } + + private static GridConstraints gridConstraints = new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(200, 200), null, 0, false); + + public void init() { + mainWindow = getInstance(); + mainWindow.getMainPanel().updateUI(); + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + mainPanel = new JPanel(); + mainPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + tabbedPane = new JTabbedPane(); + tabbedPane.setTabLayoutPolicy(1); + mainPanel.add(tabbedPane, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(200, 200), null, 0, false)); + overViewPanel = new JPanel(); + overViewPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + tabbedPane.addTab("Overview", overViewPanel); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return mainPanel; + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/frame/MainFrame.java b/src/main/java/com/luoboduner/moo/info/ui/frame/MainFrame.java new file mode 100644 index 0000000..dd7e6e4 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/frame/MainFrame.java @@ -0,0 +1,36 @@ +package com.luoboduner.moo.info.ui.frame; + +import cn.hutool.core.thread.ThreadUtil; +import com.luoboduner.moo.info.ui.UiConsts; +import com.luoboduner.moo.info.ui.component.TopMenuBar; +import com.luoboduner.moo.info.ui.listener.FrameListener; +import com.luoboduner.moo.info.util.ComponentUtil; +import com.luoboduner.moo.info.util.FrameUtil; + +import javax.swing.*; + +/** + * Main Frame + * + * @author RememBerBer + * @since 2021/11/08. + */ +public class MainFrame extends JFrame { + + public void init() { + this.setName(UiConsts.APP_NAME); + this.setTitle(UiConsts.APP_NAME); + FrameUtil.setFrameIcon(this); + TopMenuBar topMenuBar = TopMenuBar.getInstance(); + topMenuBar.init(); + setJMenuBar(topMenuBar); + ComponentUtil.setPreferSizeAndLocateToCenter(this, 0.8, 0.88); + } + + /** + * add event listeners + */ + public void addListeners() { + ThreadUtil.execute(FrameListener::addListeners); + } +} diff --git a/src/main/java/com/luoboduner/moo/info/ui/listener/FrameListener.java b/src/main/java/com/luoboduner/moo/info/ui/listener/FrameListener.java new file mode 100644 index 0000000..0f3851f --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/listener/FrameListener.java @@ -0,0 +1,68 @@ +package com.luoboduner.moo.info.ui.listener; + + +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.ui.Init; +import com.luoboduner.moo.info.util.SystemUtil; + +import javax.swing.*; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +/** + * Form event monitoring + * + * @author RememBerBer + * @since 2021/11/10. + */ +public class FrameListener { + + + public static void addListeners() { + App.mainFrame.addWindowListener(new WindowListener() { + + @Override + public void windowOpened(WindowEvent e) { + + } + + @Override + public void windowIconified(WindowEvent e) { + + } + + @Override + public void windowDeiconified(WindowEvent e) { + + } + + @Override + public void windowDeactivated(WindowEvent e) { + + } + + @Override + public void windowClosing(WindowEvent e) { + if (SystemUtil.isWindowsOs()) { + App.mainFrame.setVisible(false); + } else { + App.mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + + Init.shutdown(); + } + + @Override + public void windowClosed(WindowEvent e) { + + } + + @Override + public void windowActivated(WindowEvent e) { + + } + }); + + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/util/ComponentUtil.java b/src/main/java/com/luoboduner/moo/info/util/ComponentUtil.java new file mode 100644 index 0000000..62a2a27 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/util/ComponentUtil.java @@ -0,0 +1,40 @@ +package com.luoboduner.moo.info.util; + +import com.luoboduner.moo.info.App; + +import java.awt.*; + +/** + * util for swing component + * + * @author RememBerBer + * @since 2021/11/08. + */ +public class ComponentUtil { + private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + private static Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(App.mainFrame.getGraphicsConfiguration()); + + private static int screenWidth = screenSize.width - screenInsets.left - screenInsets.right; + + private static int screenHeight = screenSize.height - screenInsets.top - screenInsets.bottom; + + /** + * Set up the component preferSize and position it in the center of the screen + */ + public static void setPreferSizeAndLocateToCenter(Component component, int preferWidth, int preferHeight) { + component.setBounds((screenWidth - preferWidth) / 2, (screenHeight - preferHeight) / 2, + preferWidth, preferHeight); + Dimension preferSize = new Dimension(preferWidth, preferHeight); + component.setPreferredSize(preferSize); + } + + /** + * Set the component preferSize and position it in the center of the screen (based on the percentage of screen width) + */ + public static void setPreferSizeAndLocateToCenter(Component component, double preferWidthPercent, double preferHeightPercent) { + int preferWidth = (int) (screenWidth * preferWidthPercent); + int preferHeight = (int) (screenHeight * preferHeightPercent); + setPreferSizeAndLocateToCenter(component, preferWidth, preferHeight); + } +} diff --git a/src/main/java/com/luoboduner/moo/info/util/ConfigBaseUtil.java b/src/main/java/com/luoboduner/moo/info/util/ConfigBaseUtil.java new file mode 100644 index 0000000..58f0429 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/util/ConfigBaseUtil.java @@ -0,0 +1,41 @@ +package com.luoboduner.moo.info.util; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.setting.Setting; + +import java.io.File; + +/** + * Base class of configuration management + * + * @author RememBerBer + * @since 2021/11/08. + */ +public class ConfigBaseUtil { + /** + * path of the setting file + */ + private String settingFilePath = SystemUtil.CONFIG_HOME + File.separator + "config" + File.separator + "config.setting"; + + Setting setting; + + ConfigBaseUtil() { + setting = new Setting(FileUtil.touch(settingFilePath), CharsetUtil.CHARSET_UTF_8, false); + } + + public void setProps(String key, String value) { + setting.put(key, value); + } + + public String getProps(String key) { + return setting.get(key); + } + + /** + * save to disk + */ + public void save() { + setting.store(settingFilePath); + } +} diff --git a/src/main/java/com/luoboduner/moo/info/util/ConfigUtil.java b/src/main/java/com/luoboduner/moo/info/util/ConfigUtil.java new file mode 100644 index 0000000..283533d --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/util/ConfigUtil.java @@ -0,0 +1,99 @@ +package com.luoboduner.moo.info.util; + +/** + * Configuration management + * + * @author RememBerBer + * @since 2021/11/08. + */ +public class ConfigUtil extends ConfigBaseUtil { + + private static final ConfigUtil configUtil = new ConfigUtil(); + + public static ConfigUtil getInstance() { + return configUtil; + } + + private ConfigUtil() { + super(); + } + + private boolean autoCheckUpdate; + + private boolean defaultMaxWindow; + + private boolean unifiedBackground; + + private String beforeVersion; + + private String theme; + + private String font; + + private int fontSize; + + public boolean isAutoCheckUpdate() { + return setting.getBool("autoCheckUpdate", "setting.common", true); + } + + public void setAutoCheckUpdate(boolean autoCheckUpdate) { + setting.putByGroup("autoCheckUpdate", "setting.common", String.valueOf(autoCheckUpdate)); + } + + public boolean isDefaultMaxWindow() { + return setting.getBool("defaultMaxWindow", "setting.normal", false); + } + + public void setDefaultMaxWindow(boolean defaultMaxWindow) { + setting.putByGroup("defaultMaxWindow", "setting.normal", String.valueOf(defaultMaxWindow)); + } + + public boolean isUnifiedBackground() { + return setting.getBool("unifiedBackground", "setting.normal", true); + } + + public void setUnifiedBackground(boolean unifiedBackground) { + setting.putByGroup("unifiedBackground", "setting.normal", String.valueOf(unifiedBackground)); + } + + public String getBeforeVersion() { + return setting.getStr("beforeVersion", "setting.common", "0.0.0"); + } + + public void setBeforeVersion(String beforeVersion) { + setting.putByGroup("beforeVersion", "setting.common", beforeVersion); + } + + public String getTheme() { + if (SystemUtil.isLinuxOs()) { + return setting.getStr("theme", "setting.appearance", "System Default"); + } else { + return setting.getStr("theme", "setting.appearance", "Dark purple"); + } + } + + public void setTheme(String theme) { + setting.putByGroup("theme", "setting.appearance", theme); + } + + public String getFont() { + if (SystemUtil.isLinuxOs()) { + return setting.getStr("font", "setting.appearance", "Noto Sans CJK HK"); + } else { + return setting.getStr("font", "setting.appearance", "Microsoft YaHei"); + } + } + + public void setFont(String font) { + setting.putByGroup("font", "setting.appearance", font); + } + + public int getFontSize() { + return setting.getInt("fontSize", "setting.appearance", 13); + } + + public void setFontSize(int fontSize) { + setting.putByGroup("fontSize", "setting.appearance", String.valueOf(fontSize)); + } + +} diff --git a/src/main/java/com/luoboduner/moo/info/util/FrameUtil.java b/src/main/java/com/luoboduner/moo/info/util/FrameUtil.java new file mode 100644 index 0000000..0da3a53 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/util/FrameUtil.java @@ -0,0 +1,33 @@ +package com.luoboduner.moo.info.util; + +import com.google.common.collect.Lists; +import com.luoboduner.moo.info.ui.UiConsts; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + *
+ * FrameUtil
+ * 
+ * + * @author RememBerBer + * @since 2021/11/08. + */ +public class FrameUtil { + + public static void setFrameIcon(JFrame jFrame) { + List images = Lists.newArrayList(); + images.add(UiConsts.IMAGE_LOGO_1024); + images.add(UiConsts.IMAGE_LOGO_512); + images.add(UiConsts.IMAGE_LOGO_256); + images.add(UiConsts.IMAGE_LOGO_128); + images.add(UiConsts.IMAGE_LOGO_64); + images.add(UiConsts.IMAGE_LOGO_48); + images.add(UiConsts.IMAGE_LOGO_32); + images.add(UiConsts.IMAGE_LOGO_24); + images.add(UiConsts.IMAGE_LOGO_16); + jFrame.setIconImages(images); + } +} diff --git a/src/main/java/com/luoboduner/moo/info/util/SystemUtil.java b/src/main/java/com/luoboduner/moo/info/util/SystemUtil.java new file mode 100644 index 0000000..1fb5838 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/util/SystemUtil.java @@ -0,0 +1,42 @@ +package com.luoboduner.moo.info.util; + +import java.io.File; + +/** + * System util + * + * @author RememBerBer + * @since 2021/11/08. + */ +public class SystemUtil { + private static final String OS_NAME = System.getProperty("os.name"); + private static final String OS_ARCH = System.getProperty("os.arch"); + private static final String VM_VENDOR = System.getProperty("java.vm.vendor"); + private static final String USER_HOME = System.getProperty("user.home"); + public static final String CONFIG_HOME = USER_HOME + File.separator + ".MooInfo"; + + /** + * log file dir + */ + public final static String LOG_DIR = USER_HOME + File.separator + ".MooInfo" + File.separator + "logs" + File.separator; + + public static boolean isMacOs() { + return OS_NAME.contains("Mac"); + } + + public static boolean isMacM1() { + return OS_NAME.contains("Mac") && "aarch64".equals(OS_ARCH); + } + + public static boolean isWindowsOs() { + return OS_NAME.contains("Windows"); + } + + public static boolean isLinuxOs() { + return OS_NAME.contains("Linux"); + } + + public static boolean isJBR() { + return VM_VENDOR.contains("JetBrains"); + } +} \ No newline at end of file diff --git a/src/main/java/com/luoboduner/moo/info/util/UIUtil.java b/src/main/java/com/luoboduner/moo/info/util/UIUtil.java new file mode 100644 index 0000000..6f09989 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/util/UIUtil.java @@ -0,0 +1,64 @@ +package com.luoboduner.moo.info.util; + +import com.luoboduner.moo.info.App; +import lombok.extern.slf4j.Slf4j; + +import java.awt.*; + +/** + * UI custom tools + * + * @author RememBerBer + * @since 2021/11/10. + */ +@Slf4j +public class UIUtil { + + /** + * Get screen specifications + *

+ * author by darcula@com.bulenkov + * see https://github.com/bulenkov/Darcula + * + * @return + */ + public static float getScreenScale() { + int dpi = 96; + + try { + dpi = Toolkit.getDefaultToolkit().getScreenResolution(); + } catch (HeadlessException var2) { + } + + float scale = 1.0F; + if (dpi < 120) { + scale = 1.0F; + } else if (dpi < 144) { + scale = 1.25F; + } else if (dpi < 168) { + scale = 1.5F; + } else if (dpi < 192) { + scale = 1.75F; + } else { + scale = 2.0F; + } + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + log.info("screen dpi:{},width:{},height:{}", dpi, screenSize.getWidth(), screenSize.getHeight()); + + return scale; + } + + /** + * the theme is dark or not + * + * @return + */ + public static boolean isDarkLaf() { + return "Darcula".equals(App.config.getTheme()) + || "Darcula(Recommended)".equals(App.config.getTheme()) + || "Flat Dark".equals(App.config.getTheme()) + || "Flat Darcula".equals(App.config.getTheme()) + || "Flat Darcula(Recommended)".equals(App.config.getTheme()); + } +} diff --git a/src/main/java/com/luoboduner/moo/info/util/UpgradeUtil.java b/src/main/java/com/luoboduner/moo/info/util/UpgradeUtil.java new file mode 100644 index 0000000..e736a3f --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/util/UpgradeUtil.java @@ -0,0 +1,136 @@ +package com.luoboduner.moo.info.util; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.bean.VersionSummary; +import com.luoboduner.moo.info.ui.UiConsts; +import com.luoboduner.moo.info.ui.dialog.UpdateInfoDialog; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import javax.swing.*; +import java.util.List; +import java.util.Map; + +/** + * Upgrade tool class + * + * @author RememBerBer + * @since 2021/11/08. + */ +@Slf4j +public class UpgradeUtil { + + public static void checkUpdate(boolean initCheck) { + // current version + String currentVersion = UiConsts.APP_VERSION; + + // Get information about the latest version from github + String versionSummaryJsonContent = HttpUtil.get(UiConsts.CHECK_VERSION_URL); + if (StringUtils.isEmpty(versionSummaryJsonContent) && !initCheck) { + JOptionPane.showMessageDialog(App.mainFrame, + "Check for timeouts, follow GitHub Release!", "Network error", + JOptionPane.INFORMATION_MESSAGE); + return; + } else if (StringUtils.isEmpty(versionSummaryJsonContent) || versionSummaryJsonContent.contains("404: Not Found")) { + return; + } + versionSummaryJsonContent = versionSummaryJsonContent.replace("\n", ""); + + VersionSummary versionSummary = JSON.parseObject(versionSummaryJsonContent, VersionSummary.class); + // The latest version + String newVersion = versionSummary.getCurrentVersion(); + String versionIndexJsonContent = versionSummary.getVersionIndex(); + // Version index + Map versionIndexMap = JSON.parseObject(versionIndexJsonContent, Map.class); + // list of version details + List versionDetailList = versionSummary.getVersionDetailList(); + + if (newVersion.compareTo(currentVersion) > 0) { + // The current version index + int currentVersionIndex = Integer.parseInt(versionIndexMap.get(currentVersion)); + // Version update log: + StringBuilder versionLogBuilder = new StringBuilder("

Surprise the new version! Download it now?

"); + VersionSummary.Version version; + for (int i = currentVersionIndex + 1; i < versionDetailList.size(); i++) { + version = versionDetailList.get(i); + versionLogBuilder.append("

").append(version.getVersion()).append("

"); + versionLogBuilder.append("").append(version.getTitle()).append("
"); + versionLogBuilder.append("

").append(version.getLog().replaceAll("\\n", "

")).append("

"); + } + String versionLog = versionLogBuilder.toString(); + + UpdateInfoDialog updateInfoDialog = new UpdateInfoDialog(); + updateInfoDialog.setHtmlText(versionLog); + updateInfoDialog.setNewVersion(newVersion); + updateInfoDialog.pack(); + updateInfoDialog.setVisible(true); + } else { + if (!initCheck) { + JOptionPane.showMessageDialog(App.mainFrame, + "It's the latest version!", "Congratulations", + JOptionPane.INFORMATION_MESSAGE); + } + } + } + + /** + * Smooth upgrade + * The version update scripts and sql methods involved are as idempotent as possible to avoid repeated upgrade operations due to unusual interruptions such as power failures and deaths during the upgrade process + */ + public static void smoothUpgrade() { + // Get the current version + String currentVersion = UiConsts.APP_VERSION; + // Get the before upgrade version + String beforeVersion = App.config.getBeforeVersion(); + + if (currentVersion.compareTo(beforeVersion) <= 0) { + // If both are consistent, no upgrade action is performed + return; + } else { + log.info("Smooth upgrade begins"); + + // Then take the index for both versions + String versionSummaryJsonContent = FileUtil.readString(UiConsts.class.getResource("/version_summary.json"), CharsetUtil.UTF_8); + versionSummaryJsonContent = versionSummaryJsonContent.replace("\n", ""); + VersionSummary versionSummary = JSON.parseObject(versionSummaryJsonContent, VersionSummary.class); + String versionIndex = versionSummary.getVersionIndex(); + Map versionIndexMap = JSON.parseObject(versionIndex, Map.class); + int currentVersionIndex = Integer.parseInt(versionIndexMap.get(currentVersion)); + int beforeVersionIndex = Integer.parseInt(versionIndexMap.get(beforeVersion)); + log.info("Older version{}", beforeVersion); + log.info("Current version{}", currentVersion); + // Traverses the index range + beforeVersionIndex++; + for (int i = beforeVersionIndex; i <= currentVersionIndex; i++) { + log.info("Update the version index {} begin", i); + // Perform updates to each version index, from far to nearby time + upgrade(i); + log.info("Update the version index {} finished", i); + } + + // If the upgrade is complete and successful, the version number prior to the upgrade is assigned to the current version + App.config.setBeforeVersion(currentVersion); + App.config.save(); + log.info("Smooth upgrade ends"); + } + } + + /** + * Execute the upgrade script + * + * @param versionIndex Version index + */ + private static void upgrade(int versionIndex) { + log.info("Start with the upgrade script, version index:{}", versionIndex); + switch (versionIndex) { + case 21: + break; + default: + } + log.info("The upgrade script ends, the version index:{}", versionIndex); + } +} diff --git a/src/main/resources/icons/MooTool-logo-64.png b/src/main/resources/icons/MooTool-logo-64.png new file mode 100644 index 0000000000000000000000000000000000000000..7ab8bef141287f697178b579fd00db4e9da44a23 GIT binary patch literal 3412 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 V()tP1z8nAm002ovPDHLkV1nzI3QPb1 literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/loading_dark.gif b/src/main/resources/icons/loading_dark.gif new file mode 100644 index 0000000000000000000000000000000000000000..5d4800a0f98becce75008af34c02b44bb052f908 GIT binary patch literal 3213 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 b6GNtZ1?~Ow_!uo5>d#V@tqPsJA7A_z9{74+ literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/logo-1024.png b/src/main/resources/icons/logo-1024.png new file mode 100644 index 0000000000000000000000000000000000000000..ceffd98501d276467130096ef498ae7f78e4e96e GIT binary patch literal 32542 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 Iza2jJKUed1t^fc4 literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/logo-128.png b/src/main/resources/icons/logo-128.png new file mode 100644 index 0000000000000000000000000000000000000000..e47bb8463472c2f4520aed25bf5e1b0a933fe520 GIT binary patch literal 2772 zcmaJ@c|4Tu8h(X_!Ptf(AsJ?@`KTx|m7OrwMwSmB+Gvtpm@FS-vPDI<8I(2CLSq}* zMZ#EP>`P6Slo&A$XLQc_opb&pA!L007Q5H8^h<;<}paa#Lzp;%{5RQ{tZLl3RC*l3I6Q*(q0A>99%72CS_MCCy6^Z6aLLMf{9&0jP)KZnZ zj<=H+DZTy%l_sk+m3K>Td8P4AZ%@`3I^6pgW#CR)$ke>%^w!svkRV3Svr8)C_;!!y zB=Nt+E3-fJO`qALY^%@r6Ae3%pTY7 z&5PY?AM>lgj9Z4ymFALapAAvJgvbImzK*L-C`^#~9?jR&CBrl6eSQQNS#ZFaI)-53 zeLY#7y)@e)gNain{`zEeD3e>K7kZ44qK^qZ5XiQN7IBtaPu@HC zaH0ImXZogW3K!kBOX7CpvC2l9hwqLzYiyL-O`<5M0O?8HcfhaX7TTJ}wuVXJ_Em>I zr_k-Yl*XeBNzr@(MM!nCQ=>K^X4sg7 zecr;~5`E7r#?y_vYFQEyO7#9@*9`Ye`s!DJjm-Kf%ti)N@&1CZ>9!t8PUJ!v7&)9T z;(AVaKYsnJ`WFHmQgC{34gjP8RVl1WA}4?WsxZJSI0R_o=x^b8SD+05AS5417S9Hu z1(2m{GoNhy{C#Sp)~WuL{#8ScXj#UFRj%ap?#C=yhM@Gh$#pt>%ih%>KY6mY+njE^ zu;y%#pZN0Lm&a86%2C}7r5!t6trIM;uhq!{C)9_Mpv!$jSD$_t1uY~G!2}dUHoXM~ z#kq85RTn1~(CrWn;j1GyBhcj>liK)SunFF0Hy+vCmd6M(wL=xe6&|qCzDHc~@q>R4 zk5n(UO?vqihr;zbQ_{WXVBZun0@HQTp#~c63PvRzm$%wVwu2iz1}yGc|HhR@%|R_Q zaS~|Hif|A4J{z|m7MZv#+~|w1dZH0GIuU1RhOYcsFU~sZtmd8&RkZW0sE3qWv&1)r zn3C{1pJ~>B(M$w$RkwlF?}llyXxOjH;Y@TLX}rROGSCRK`&z1qgWy=s{%|=iLi+XqrA#q)Y_d|aG0@HyI zx^mxD9!?NpE8qyWiB$bQY04lSK>;^4-jeZ?+KH^by|C+IEB2cA3iIZgU2`G_+B-P8zJiLyy~xmNz9-qR1?@)th{X?5X1KSA1a+R@OwwD1@|JJpmIyXL?B zm3M|)E31X0KRp$2=GPT2>MVobH^KlL@^V0^k3Rb_!h({R0m^Ft2Rm313|!FD!k-FA z;W~6%R$m(k8_@vLWU@!0uC5y~>fFmXWx!pHTeLBX(f(W{>TnUP637_YX(gN}=tBJ7 zxVjWptA&Gy1JrZ~f|Q&EVzHbv>~>AU02i7#zIpi`_*3lpt;A?eMKD7rtf7{dd9b+m zpPB!nEIG`C(zd%}_M{_rcCdyvYu+3-2S&!4H@E$<31wD5^+a4Wu=~_3OJNlhQtFFg z9^%xiU^W9H2V~K0k--TL=}=(^OO?HN5fQA{wAjV%yr!wNRN&{d=w+IHy@ULpL=y-$ zPmL3U3%eh&mI@yq1Q+gC#PMKPR2j6wag){8{_{ViUvvCEfu>M)Yg|D%T^i`6bwXo) zvdMg%$3bvCSSeKYpt`j#Yd0u^^H)=>9_yk0Y-}N0s4kxDs9PpXp#)!&^lWkZeElMh zfZ2^rG!jZ(fQmu{{zJ}V+z%L&V#eN-w*;k^x**#viYMurrHu)fJb3PmP*e zI?8JqbYjdiUF{RqMVT1+pZA2XvlS#*za)Ohe1$}ssE=L>G1W+@QR61h7XFSmB|V$)j}xaU(I%vdSTu>jRndoMM6{1>IWJux{@^ zEfVyIsVL*?sz@(a5enZawoJMewPGQ}1PSK*g$86WmDCHYI=?zE!Zwbt2dfoWwSR2d zcuzNEK%~ROB9x>hGb7{P6icF>mw1=@-A%1%(2O3fIN5-AwF@-fG>Wsrb%Esk>&gAa z9kn0|y#A{G>?Q)97(@S1_1}Z<|4hdwBR;Il3#Oi-^&JjM$ry1g1>9=iyST;z@1P2{ ziv&oc_!>S6e5+I$tUmV(Ov!pwuSMx1r&KE-k)<7OIp59?WV+uwV+hn*@KXQM`7`q3 z+bvaoRp)pb$TYdye5dbC(x#h4_cYa1(eH@7&(N3>OA)qrMZ&ycRQJ4;Fq!SB9DcO^ zI4z-mOYU6viXIfuN&0`V0xi#33e9hYX^i;H;CPD5yn2Y%M4lOiEKRvB^!9po5bj6|Fvq zyR&P#-Y>?Gwn9Taa7c2`_xp10KaNX9I3EuBTChqvIzTj{)Rp>#r+6ct8Z4qtRI(h- zghOejEdcl$q28P~%AQR!OOBY~lCSxnsI##zW}s^CQ*-q2SISTyMefX_25CObi+vNlBP4MQ1q$?y@&_> z7WxJJ1cGt?u_H-rl}7W22YH?Meviz&ys03RP%fBj(?qQn&-tl*b#^@4&ey0+8}p%j zJ@<7f*KG=B1^0iIF<~?lnZ6T+9>FIvi7?+JA=1N&Rb^%R%KRs+WhG-8Ypm#;lk$TY zXwXVh=#}Lwl)z`OP--$&XBCs_3)UET>C-2h4oE4j_9fePMRh$L$~?r!PRa5>d^R?6 zrorD6kGIx_lJj_0gW3(&B7t-S{^96J6uEAmLrcBU_T~Qg8#B|Ry@BE83c8}V5Q&Jp z!|Fznq_PYQu)wt7=$68snyFys-kngcfx&rT3ur|m8!>jES~PH`*@H9lm*(B(-H(PC zdkz?2fyvwaODp}cMIN|1kT7qH0NsWd#PU2a98i2jtkw42Z?HC)_y#Lwh;_dKm|&xi zJBpow*8=u40NZ*CHU>Iz@?lZk{%Zj+zyi~;RgnD*ycYO&1{cALrowFb*DV4QYyne| z{qV^4>scK;zy50hFu(%SK5;Gi(x#Z>RH8FPGIkCF=_C(?dHK-501Hg(j$l38Rjf_D znxjn_TL_24l|&&6sCp1Mjky!bH88*e6KuzJ`8KZY^7X>u^7YDue82P|Hcwg;@^uZK qF%_-Lqab{t`iS1ZeRNByzbzly|No?%A}jv@0000x$p3O_jkYbt-J2JYu)>se`elu_Bm(2XZEw7XYU9-9W^>?c4`0s=rq)C z-Ua{?@FxjCMFD=9x#!pd0BgO*O+|yp7R%{~=VrqJU%O=)G*elHZ!!kMo=`weoqk|f zR6AQF>%&5+Zmc36!ILOQO>v)ORXh~#ugu}QxGfZ68gO1c%ilj%aU+K z$G3R`4u`;HGZcK7giLBL*thXPwznrNrYTT|{R?ExVV;qy(_(pM1GOoN_(HUeH zGTYLP$NifA>b(kEY&KKgb#)f4bKgJT?YPKmCKBjuRv#A^*Nm+vjpF1&H_+6*cWg{p z4|XW_$l1hL=ndmOzf9K25D1cV8ba(Tl9an>isMENHkerNc-w$+*0$xhE*&pzU? z8q_CuCGX9+;?Z*0t=0bfGrhKS@@V#SZ1bkH#h_gIkC|Fdz1YzVt3M~|zx+&HUs%@xDzbq5)Ln9xYJOAI12 zYzFaouR-#s!bY{6?CoOsCYsoOg48#t<&qtyS_`mAD!Z` zRW+Rxtn$7+U+ihH!i2$TR6V>se>8gIjt0bIME-2ehmNwBN{cH)OUzpJEEAVU$zLcb zdxtv%%0Y><1xR+i5B(^F1mR24l`6`aJ&o5|N0eAD+dPdb?=$wbLT?f0c1<^mX9?K7 zhO6_pSE(FP7<={x^}rUB6>I7nH0@h(tPi*@yUYBZ&(^&MtSh=38L6MV#S!Q74mHsX zoFN%D$*K$r5sqe{eF5IzGvK}@e3AKKpsa35UC~+8Xq&wDtIvsA*hq&FoJkd>8?B#h z%@se~>^fn}oq=iRj#5jI*MTsdW8;`RHk200Q4Y%XABTPniO(DfeM(S{Wne~1iyK+eR?aSsKm%W<|Rx%A-@5}~!tAplq|v&r7~%6g<#JMfAJAA6okEEeGu ziHJt%Y+r0kneLdskhMwQt*H2_Y63A4QY@m_I)oTWzmpkI9>YoflqKzFMnVAfHLFUy z%>_T*U(DSXVfMNU8Y}RzPZw0~7^xcFDq^@9$zXj|u0dXq!1BJKODrhsYQg2}PgUI6 zjUbmx7J^%US1yHT#rY*7?rdKbec+X~_DenPBD8R#q&VgY$-ZP1^vY8kM%UBXu=B3? z#`Wu$2y9=FH(U(AempF!;cDQgU=qczS(q45Y4PFvcxsb?Fxi$e z1_Z~?7soOt-CD63!&s3l$VYn-A8#)lKZXe{N~uzxvOa~iNIIZnK~hUyp*dx(aXy*& z5S4uy+-9g2ILF2&BbOiAnZRoCF>l(%LAKcc*8xgN$@qFzvQ5wjp595MX-A2`oR}Cy zM7jqbESvBlkoV}d5-M=+?dmUC;5C!GNavx>*pIUm6&ubSzVJjhQM0(Msop36iGHOF zbP1wh8reL+YavrA;M)GBUUb^rw>~Ay7gsWBi92~ikombH9lkH< z%=cEGLDNErgCh{6tx=B$beweAXHbdoj>b*|0#v`P1*o>eL#98^nEB8h;CxXk9;ZnF z^Zt8)=RWG_k<6(1FQaCZnWzZSkpc>!yD)7Lz4ozy1{>@f0ltpC7_jrM$sPTnzBFnu zQUx8S1~SZLdW&v>MB_d!2fYjASGnbvOp96DeUE1F2`t@K6D6%GH@lB6%MXexV+QJ2 z{ndIrocTo3<>FWnhF3DmvQ8lkd2aarzsq8F{>(fT%D(q)xc}FvPVHsNerA)x|=nN;vpvi!YwqXe2ZR!KN zep2MB#-l1%ONEfP^$M{FpfA6JO{Z%~ggkex&6dq%2AHxtPaE`TrbJ*p5r!twqmj&7 z*MhmKPLUh+tJX(4rxl0N0oAKtY=YKi#4ay5L1f4q>es-)=zdD1s<+*8AdwBW%I+?Q zmDW17%zm)B7z3JE*gyToXAXe;?@gx##K)y~{<(G!`ffP6B!9%)3N zfo9TW#>rJc<|iv4c66+8ef5v)h`!?ARz)*n@pE^8)4-$Yw+_?}!!A+^XB?!Bp}Ws# zs+eJ9FtbW~l#=O7jAMK^MU(>xhUF&kB@~3gdx=qoT=jR2_d4t@_4XE1AuHYb#Y0Q^ zj&4UfiyLe2=FjY!u#hmaUO{EYjyPL*1ikOKx{57{pR+UhYg3QTGKQP%bS(M`LcW1X zDu3;h9o^X9r9X^2jC>a^u5Gs z0DGEb3NRCgUo40K1Y)QF$|>S2!pUI1HvwsYcnMBCKnE}6g4zy^GJoF75AT;P4O&(g2Zh?>%#j^%y3_7QQh_+wgp+ov+ z{xV72NPXsQNifFdW;#iBYLfxtUU8Jbkqa_&_ux<#%gOPsrjTvykNY5WhE%u#u`syI zSJfPnt*fSP*Q*uFL7eAOA=y5pPR^)d<-Uep;ZLw#>mnX~8t@oc0%6{=gdwFp6e@P3 zKe06l5ZURy8FaOcd$TtoYW5NYKt%%50z^!r*W{0Qs;n$d3_~b}r|y9mXL_tye}ZuX zvIfNiN9hZ5)lR{tZsq?POdTFkBj$*p{8$!W!z-w8@C5}SQ*@T_{eG+J@SQid(|`I@ zvQG4g4x`)_y1_^Sz*T@Q6aC~4Ur8n3>6dXWVl2mFh0`zHUqq)6;0@;e@M5OpvA%rz z9HtpgexCf$xgIFz4=B^|m2d%a`*Ur(aPqn{RE~}MD7Zc=Xl`CZ0;^bXxUsP~#X!|v zD;qm@_v!Ja(*PNbl(!L$BJ^UGrzPhzhe3J#2DYPwnyg+z+xW&DK7uN38w~~74 zmFvOF4tw2oYhQ_I2Jyrq3{--Y#_#1lYrkzz;md;cw{2a@q%~s5oA-H{C0NJAh%zk& z+ID0~<_sA4_VlNIz;ZV(jXPUu*zONwg z2+hezmiFn+H2FR|UOI{6ch9(g^-;?g?wqvMgSnIVca`oIgMzWTqs!pH(yanQieO7y6FlmE*~!L6*}JNVemYf(s*%ib(79 zctP#s(ovy*x>GZ)L!_pRYKs!L*%RdW4sU_(h%Lzb(F$+h^IUU2@kgw#4fK4BsyYT| z-*|w6Upooxt_cFd{RLATUM-jy(Jfp+u0NTvnjW2k8pl!`hwViWq1Dewtr&W9(!Lv< zqHNYr{J>|}>dHVoEJ_r}_T}@H#Man`VOF_y@oYg0h{l}trUK24S{scoJ`g4SC>FrP zpZ`KHXYXVe?Eti67b@@NFC;2nYEPo)vv&7MN!b4~ZT?R|IN`ob8mAi4lF+M}k!kZ6 z!*tI|;MM+_^`(LWwf>p)Jq}_c#o3|R{&&{*p;5pyn&YI6uC>4aPg}3=(J?nsbSzp5 zyuJ^~8UN&-J3nwKq62P)#_MeD9zw{!cxnNa^)6j)M2^ehx-spp^UmMc4i5?h^-_yXD87mZZ^alD>hvck!Ez&Qw#{iwR7)hup1=4W;fFaya;zS z->wx#DX}!ACOw>Y{=7D=&ZH!}Zh}i`^ALlnrlIX4n!vQmLn5j}=^S#kPamP*6jDlO;4=m^|O6i{9#@32dpIJ38+{ z3vAnD7=pNawUj9r!4jxZVq%-b2h5szOn>V_^i>MC>7a#2UpWacT0Q_p<@O~a8e0W) z<=>6{q2I{@gm>WIN58R}O}>p9bzYwE`9azTL!Tdwbu!r`>{kpZ0iKU-LArWFF=XYr zwj}HUz#iv-TJ!x_;sz%NhK4KhPpMfBLD~_eW~+Wk3{igC0yx^vsugz3hDbaOk-)0o4g;@`F45( zPQ+1R@&<8m*pAm<~M65b{P{GJyAbe#b66bX$*L4_5OUsZ0INX?e$jp1gr81AZ(E25a(n55cC2 z4##1Fr>h0l-c2*KX8H02LD zc=3^Tum;i01rv4%`8l-s%Coa)n$Db5K>+hIg^4;so|JMc-G=+Hs z(pvweWKzep#TnGd7r$am>XIkMts<-5TDCZOXrZ=FdmV*&arHo@ioV`|7H7nIGbHjc zjD@)={xK3^ye;ue@q7hIVa?C=8<(3C`xW8V7ojy1pNlh}ka%*3TG9q*#h(<0!{pI} zi}KM%55VH^{m@5Zd8h~pL#Ter{;8uDNoQS@Hfxc1Ky%y5%f{32{3>y1*P?)KWo=8j4c~l+}oa>tf>n-*?c#E9IP%S@I}^j zf(;^!jrlW^sGkiYv$Za}t>JZL z_x#mNC#&vlh=rqF7vQz`-++a;ln94YXMpy;DkhsBJFZa^u$#?4!^JmQ?Ad$=Z0(G0 zN)9>q>aFTAbZ?&7I*U(QlG0N$fENt6F*TQ67j%IPqW0p)l$Q(AF!n(nP1X zIpSV{eGhDCW^{gfUm;5%Y=x8)Lc+*R2Dnj>!TcG41~x`uO%VX>V89nj5+IG_-#H12 zD@>cR?!75;5n>An%pn@+bOS%<1F+5W*b2Oa_hOZnE7rm5L(J~W?=x z;sg6OvS8old8Sn0*#e0I6U;XRr73q3;T5d66yH|%lI=yiyfzhO(+1e^agUiGl@4P! zVD4_@*KUT2%^ejO^o| zI-8|7cb5ac$0RJKUb~epcd5Xx6fDaxj_L+$y7nFFpwr2yUn+KU@zurKiavoT_u8+% zCq43kGkqDrn+kz1f2(ZjyL)Eko&_$}OzN^Y=Um_T5kEfiw}qi0cf1pSDB3$?WQn;K z#U8f^2~PP*%y-NwEVsktNyXxi-LTJFDt0~XT>Ha!P3QCAn1zI zj z;~okuZ+1;o4ms}Pz8a*09gqWz&Hf9LpvUTm92}(zV|&WfA(OMP$EWJcHFC*>0wr=-RRC2ajYw=6&B|<}v#=llh-P{j{BI@tNbj zu*Ftz4Qo2f&)+!a!gaQHil2Y*?{&rT`f=vI^Y0PGB?j4ah(&w^3+(|XO5%p%oV>Fs zSSRM%Yu>KpiZ7D0L_=|j!O4e}8Sh38T*DSO6<0f0+YF8@@x0B=t6cv7RdOXkic5s^ zxv^~{`zOviHoZaI-d8_yF*}m49B_seH?+4>09P+g&EWZg<-Wi(!m-@f;A%yu3N2l~ zCkA)j9Uk00+T!pHMGKm`Pb@C)yw@iaR*S4PTF}=0BxJW+bd1mZc%?XbAtu>KKpP(L zf~Pe1GyVo{mQSj&+JrRPSD{3%jJ!HCX2m#z*GTR6E4C#*n#$4zRm@N zFS8EB^?<1Yy7oX6sT4pZI>}qo0`?-os45#GuQ7|#T(>_jlfT3q<9nW~Dnfr<2Le8f9wAPQ)^}sKfamI0^ S_wxq;0000DcJ7@K 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

dt}Fi7f}~s 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�fVpj7^H}jdAw&sNaH)sG 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/theme/Cyan.theme.json b/src/main/resources/theme/Cyan.theme.json new file mode 100644 index 0000000..021630a --- /dev/null +++ b/src/main/resources/theme/Cyan.theme.json @@ -0,0 +1,293 @@ +{ + "name": "Cyan light", + "dark": false, + "author": "Olga Berdnikova", + + "editorScheme": "/themes/cyanScheme.xml", + + "ui": { + "*": { + "background": "#e4e6eb", + "foreground": "#1d1d1d", + + "selectionBackground": "#3eb2c2", + "selectionBackgroundInactive": "#d0d5db", + "selectionInactiveBackground": "#d0d5db", + "lightSelectionBackground": "#d3e4eb", + + "disabledForeground": "#b1b1b1", + "disabledText": "#b1b1b1", + "inactiveForeground": "#b1b1b1", + + "infoForeground": "#787878", + "modifiedItemForeground": "#00a9bf", + + "separatorColor": "#bec5cd", + "borderColor": "#bec5cd", + + "underlineColor": "#0ab0d1" + }, + + "ActionButton": { + "hoverBackground": "#d0d3d9", + "hoverBorderColor": "#d0d3d9", + "pressedBackground": "#c3c7cf", + "pressedBorderColor": "#c3c7cf" + }, + + "Borders": { + "color": "#bec5cd", + "ContrastBorderColor": "#bec5cd" + }, + + "Button": { + "startBorderColor": "#b0b9c3", + "endBorderColor": "#b0b9c3", + "default": { + "foreground": "#FFFFFF", + "startBackground": "#28a4c3", + "endBackground": "#28a4c3", + "startBorderColor": "#258aa4", + "endBorderColor": "#258aa4", + "focusedBorderColor": "#82d3dd" + } + }, + + "ComboBox": { + "background": "#eef0f4", + "nonEditableBackground": "#FFFFFF", + "ArrowButton.background": "#FFFFFF" + }, + "ComboBoxButton.background": "#FFFFFF", + "ComboPopup.border": "1,1,1,1,b0b9c3", + + "CompletionPopup": { + "foreground": "#404040", + "infoForeground": "#8c8c8c", + "selectionBackground": "#bce2e6", + "selectionInactiveBackground": "#d7dbe0", + "matchForeground": "#00a0d1", + "selectionForeground": "#404040", + "selectionInfoForeground": "#8c8c8c", + "matchSelectionForeground": "#00a0d1" + }, + + "Component": { + "borderColor": "#b0b9c3", + "focusedBorderColor": "#31b1d0", + "focusColor": "#5fc5de" + }, + + "Counter": { + "background": "#9AA7B0", + "foreground": "#FFFFFF" + }, + + "DefaultTabs": { + "inactiveUnderlineColor": "#8699a6", + "hoverBackground": "#ced2d9" + }, + + "DragAndDrop": { + "areaBackground": "#4cb2c733" + }, + + "Editor": { + "background": "#d0d3d9", + "foreground": "#808080", + "shortcutForeground": "#1b9bb6" + }, + + "EditorPane.inactiveBackground": "#e4e6eb", + + "EditorTabs": { + "selectedBackground": "#f3f3f3", + "inactiveMaskColor": "#4752661A", + + "underlineColor": "#29abcb", + + "underlinedTabBackground": "#f2f4f5", + "inactiveColoredFileBackground": "#a6a9b350", + "hoverBackground": "#b9bdc999" + }, + + "DebuggerTabs.selectedBackground": "#e4e6eb", + + "FileColor.Yellow": "#f2efda", + "FileColor.Green": "#d8f0e2", + "FileColor.Blue": "#d3f0f4", + + "Label.errorForeground": "#C7222D", + + "Link": { + "activeForeground": "#009eb3", + "hoverForeground": "#009eb3", + "pressedForeground": "#009eb3", + "visitedForeground": "#009eb3", + "secondaryForeground": "#7ac2cc" + }, + + "List.background": "#eef0f4", + + "Notification": { + "MoreButton.innerBorderColor": "#bec5cd", + "errorBackground": "#f5e1e4", + "errorBorderColor": "#e695a3", + "ToolWindow": { + "informativeBackground": "#ccedcf", + "informativeBorderColor": "#8ebd91", + "warningBackground": "#f0e4c0", + "warningBorderColor": "#d9b857", + "errorBackground": "#fad7dd", + "errorBorderColor": "#e68a99" + } + }, + + "PasswordField.background": "#FFFFFF", + + "Plugins": { + "background": "#f5f7fa", + "SearchField.background": "#FFFFFF", + "SectionHeader.foreground": "#808080", + "SectionHeader.background": "#edeef2", + "Tab.selectedBackground": "#cacccf", + "Tab.hoverBackground": "#cacccf" + }, + + "Popup": { + "Header": { + "activeBackground": "#d6dae5", + "inactiveBackground": "#d6dae5" + }, + + "separatorColor": "#bec5cd", + "separatorForeground": "#919699", + + "Advertiser": { + "foreground": "#787878", + "background": "#e4e6eb", + "borderColor": "#e4e6eb" + } + }, + + "ProgressBar": { + "trackColor": "#c4c9d5", + "progressColor": "#2b9cb8", + "indeterminateStartColor": "#b8dde6", + "indeterminateEndColor": "#2b9cb8", + "passedEndColor": "#bcebd5", + "passedColor": "#1eb070", + "failedEndColor": "#e6b8bf", + "failedColor": "#dc445d" + }, + + "SearchEverywhere": { + "SearchField.background": "#FFFFFF", + "Tab.selectedBackground": "#d1d4d4", + "Advertiser.foreground": "#787878" + }, + + "SearchMatch": { + "startBackground": "#ffc466", + "endBackground": "#FFC466" + }, + + "SidePanel.background": "#e4e6eb", + + "SpeedSearch": { + "background": "#FFFFFF", + "errorForeground": "#C7222D" + }, + + "TabbedPane": { + "hoverColor": "#ced2d9", + "focusColor": "#dbebed", + "contentAreaColor": "#bec5cd" + }, + + "Table": { + "background": "#eef0f4", + "hoverBackground": "#C3D2E366" + }, + + "TableHeader": { + "cellBorder": "3,0,3,0", + "background": "#e9ecf0", + "bottomSeparatorColor": "#dfe2e6" + }, + + "TextArea.background": "#FFFFFF", + + "TextField.background": "#FFFFFF", + + "ToggleButton": { + "onBackground": "#28a4c3", + "offForeground": "#787878", + "buttonColor": "#b0b9c3", + "borderColor": "#b0b9c3" + }, + + "ToolTip": { + "background": "#f3f6fb", + "Actions.background": "#e4e6eb" + }, + + "ToolWindow": { + "Header": { + "background": "#d8dee8", + "inactiveBackground": "#e4e6eb" + }, + "HeaderTab": { + "selectedBackground": "#b9bec7", + "hoverBackground": "#b9bdc999", + "selectedInactiveBackground": "#CED1D6", + "hoverInactiveBackground": "#b9bdc999" + }, + "Button": { + "selectedBackground": "#C3C6C9", + "hoverBackground": "#C3C6C9" + } + }, + + "Tree.background": "#eef0f4", + + "WelcomeScreen": { + "Details.background": "#eef0f4", + "Projects.actions.background": "#E1E4EB" + } + }, + + "icons": { + "ColorPalette": { + "Actions.Grey": "#696d78", + "Actions.Red": "#e0516b", + "Actions.Blue": "#348def", + "Actions.Green": "#29a66c", + "Actions.Yellow": "#e3b610", + + "Objects.Grey": "#858994", + "Objects.RedStatus": "#dc445d", + "Objects.Red": "#de4765", + "Objects.Pink": "#f070a5", + "Objects.Yellow": "#e6ba29", + "Objects.Green": "#1eb070", + "Objects.Blue": "#499df2", + "Objects.Purple": "#bc8af2", + "Objects.YellowDark": "#b79108", + "Objects.BlackText": "#26282b", + + "Checkbox.Background.Default": "#f3f3f3", + "Checkbox.Border.Default": "#8a9199", + "Checkbox.Background.Selected": "#28a4c3", + "Checkbox.Border.Selected": "#2896b2", + "Checkbox.Foreground.Selected": "#FFFFFF", + "Checkbox.Focus.Wide": "#5fc5de", + "Checkbox.Focus.Thin.Default": "#98a0aa4c", + "Checkbox.Focus.Thin.Selected": "#82d3dd", + "Checkbox.Background.Disabled": "#e4e6eb", + "Checkbox.Border.Disabled": "#babfc4", + "Checkbox.Foreground.Disabled": "#babfc4" + } + } + +} \ No newline at end of file diff --git a/src/main/resources/theme/DarkPurple.theme.json b/src/main/resources/theme/DarkPurple.theme.json new file mode 100644 index 0000000..2cfc2ba --- /dev/null +++ b/src/main/resources/theme/DarkPurple.theme.json @@ -0,0 +1,421 @@ +{ + "name": "Dark purple", + "dark": true, + "author": "JetBrains", + + "editorScheme": "/themes/darkPurpleScheme.xml", + + "ui": { + "*": { + "background": "#2C2C3B", + "foreground": "#D0D0D9", + + "infoForeground": "#6d6a80", + + "selectionBackground": "#713a91", + "selectionForeground": "#D0D0D9", + "selectionInactiveBackground": "#3d3952", + "selectionBackgroundInactive": "#3d3952", + + "lightSelectionBackground": "#3a324a", + "lightSelectionForeground": "#D0D0D9", + "lightSelectionInactiveBackground": "#3d3952", + "lightSelectionInactiveForeground":"#D0D0D9", + + "disabledBackground": "#2C2C3B", + "inactiveBackground": "#2C2C3B", + + "disabledForeground": "#646078", + "disabledText": "#646078", + "inactiveForeground": "#646078", + + "acceleratorForeground": "#D0D0D9", + "acceleratorSelectionForeground": "#D0D0D9", + + "errorForeground": "#dd3962", + + "borderColor": "#4E4C63", + "disabledBorderColor": "#45405C", + + "focusColor": "#693687", + "focusedBorderColor": "#814F9E", + + "separatorForeground": "#6d6a80", + "separatorColor": "#4e4b61", + "lineSeparatorColor": "#55506b", + + "modifiedItemForeground": "#b279f2" + }, + + "ActionButton": { + "hoverBackground": "#453e57", + "hoverBorderColor": "#453E57", + "pressedBackground": "#49415c", + "pressedBorderColor": "#49415C", + "focusedBorderColor": "#476fcc" + }, + + "Button": { + "startBackground": "#45405C", + "endBackground": "#45405C", + "startBorderColor": "#544F70", + "endBorderColor": "#544F70", + "shadowColor": "#27282B", + + "default": { + "foreground": "#D0D0D9", + "startBackground": "#6B388F", + "endBackground": "#6B388F", + "startBorderColor": "#7C519C", + "endBorderColor": "#7C519C", + "focusedBorderColor": "#8465a6", + "focusColor": "#784299", + "shadowColor": "#27282B" + } + }, + + "Borders": { + "color": "#1a1721", + "ContrastBorderColor": "#1a1721" + }, + + "ComboBox": { + "nonEditableBackground": "#3A384D", + "background": "#343445", + "ArrowButton": { + "iconColor": "#9A97A8", + "disabledIconColor": "#454554", + "nonEditableBackground": "#3A384D" + } + }, + + "ComboPopup.border": "1,1,1,1,64647A", + + "CompletionPopup": { + "matchForeground": "#ED94FF", + "matchSelectionForeground": "#ED94FF", + "selectionInactiveBackground": "#44405c", + "nonFocusedMask": "#00000033", + "selectionBackground": "#623380" + }, + + "Component": { + "errorFocusColor": "#993750", + "inactiveErrorFocusColor": "#522530", + "warningFocusColor": "#8c812b", + "inactiveWarningFocusColor": "#47441f", + "iconColor": "#77728fCC", + "hoverIconColor": "#8b85a6" + }, + + "Counter": { + "background": "#FFFFFF80", + "foreground": "#000000" + }, + + "DebuggerPopup.borderColor": "#524e66", + + "DebuggerTabs.selectedBackground": "#332C40", + + "DefaultTabs": { + "underlineColor": "#9649cc", + "inactiveUnderlineColor": "#877399", + "hoverBackground": "#dfb3ff1a" + }, + + "DragAndDrop": { + "areaForeground": "#D0D0D9", + "areaBackground": "#5d476680", + "areaBorderColor": "#343142" + }, + + "Editor": { + "background": "#1D1D26", + "foreground": "#6d6a80", + "shortcutForeground": "#6E86FF" + }, + + "EditorPane.inactiveBackground": "#2C2C3B", + + "EditorTabs": { + "selectedForeground": "#D0D0D9", + "selectedBackground": "#343445", + "inactiveMaskColor": "#0d0d0d33", + + "underlineColor": "#904ac2", + + "underlinedTabBackground": "#363647", + "inactiveColoredFileBackground": "#2C2C3B80", + + "borderColor": "#1a1721" + }, + + "FileColor": { + "Yellow": "#45243b", + "Green": "#213d37", + "Blue": "#1f3557", + "Violet": "#2a2754", + "Orange": "#402e23", + "Rose": "#4a2d59" + }, + + "InplaceRefactoringPopup.borderColor": "#474359", + + "Link": { + "activeForeground": "#7094ff", + "hoverForeground": "#7094FF", + "pressedForeground": "#7094FF", + "visitedForeground": "#7094FF" + }, + + "MenuBar.borderColor": "#1a1721", + + "NavBar.borderColor": "#1a1721", + + "Notification": { + "background": "#3d394d", + "borderColor": "#57506e", + + "errorForeground": "#D0D0D9", + "errorBackground": "#4d232e", + "errorBorderColor": "#802e44", + + "MoreButton.innerBorderColor": "#1a1721", + + "ToolWindow": { + "informativeForeground": "#D0D0D9", + "informativeBackground": "#2e4280", + "informativeBorderColor": "#17254d", + + "warningForeground": "#D0D0D9", + "warningBackground": "#735822", + "warningBorderColor": "#403013", + + "errorForeground": "#D0D0D9", + "errorBackground": "#802d43", + "errorBorderColor": "#4d1c2b" + } + }, + + "MemoryIndicator": { + "allocatedBackground": "#352140", + "usedBackground": "#533473" + }, + + "ParameterInfo": { + "background": "#463f57", + "foreground": "#ababb3", + "infoForeground": "ababb3", + "currentOverloadBackground": "#6A6173", + "currentParameterForeground": "#D0D0D9" + }, + + "Plugins": { + "Tab": { + "selectedForeground": "#D0D0D9", + "selectedBackground": "#593f73", + "hoverBackground": "#593F73" + }, + + "SearchField.borderColor": "#1a1721", + "SearchField.background": "#252533", + "SectionHeader.background": "#3d3952", + "tagBackground": "#4c4766", + "tagForeground": "#D0D0D9", + + "Button": { + "installForeground": "#8862b3", + "installBorderColor":"#8862b3", + "installFillForeground": "#D0D0D9", + "installFillBackground": "#713a91", + "updateForeground":"#D0D0D9", + "updateBackground": "#713a91", + "updateBorderColor": "#713a91" + } + }, + + "Popup": { + "paintBorder": true, + "borderColor": "#4e4b61", + "inactiveBorderColor": "#343142", + "Toolbar.borderColor": "#1a1721", + "Header.activeBackground": "#453A5C", + "Header.inactiveBackground": "#453A5C", + "Advertiser": { + "foreground": "#8785a6", + "borderColor": "#4e4b61", + "borderInsets": "4,8,3,0" + } + }, + + "PopupMenu": { + "borderWidth": 1, + "borderInsets": "4,1,4,1" + }, + + "ProgressBar": { + "trackColor": "#1D1D26", + "progressColor": "#a85ed6", + "indeterminateStartColor": "#a85ed6", + "indeterminateEndColor": "#402e4d", + "failedColor": "#bd3c5f", + "failedEndColor": "#472c33", + "passedColor": "#239E62", + "passedEndColor": "#2b4242" + }, + + "SearchEverywhere": { + "Header.background": "#3a394d", + "Tab": { + "selectedForeground": "#D0D0D9", + "selectedBackground": "#5c3d7a" + }, + "SearchField":{ + "background": "#252533", + "borderColor": "#1a1721" + }, + "Advertiser.foreground": "#8785a6" + }, + + "SearchMatch": { + "startBackground": "#cca929", + "endBackground": "#cca929" + }, + + "SearchOption.selectedBackground": "#424885", + + "SpeedSearch": { + "foreground": "#D0D0D9", + "borderColor": "#69418c", + "background": "#5c3a7a", + "errorForeground": "#ff80a1" + }, + + "StatusBar.borderColor": "#1a1721", + + "TabbedPane": { + "underlineColor": "#9649cc", + "disabledUnderlineColor": "#5e5b6b", + "contentAreaColor": "#1a1721", + "hoverColor": "#dfb3ff1a", + "focusColor": "#523366" + }, + + "TableHeader": { + "cellBorder": "3,0,3,0", + "background": "#363445", + "separatorColor": "#1a1721", + "bottomSeparatorColor": "#282430" + }, + + "Table": { + "stripeColor": "#323242", + "hoverBackground": "#00000028" + }, + + "TextArea": { + "background": "#3A384D", + "selectionBackground": "#69418c" + }, + + "TextField": { + "background": "#3A384D", + "selectionBackground": "#69418c" + }, + + "ToggleButton": { + "onForeground": "#D0D0D9", + "onBackground": "#543073", + "offForeground": "#9f9fa6", + "offBackground": "#2C2C3B", + "buttonColor": "#666380", + "borderColor": "#666380" + }, + + "ToolTip": { + "background": "#463f57", + "Actions.background": "#323245", + "infoForeground": "#8985a1", + "shortcutForeground": "#8985A1" + }, + + "ToolWindow": { + "Header": { + "background": "#453A5C", + "inactiveBackground": "#2C2C3B", + "borderColor": "#1a1721" + }, + + "HeaderTab": { + "selectedBackground": "#0a0a0a66", + "selectedInactiveBackground": "#0a0a0a4D", + "hoverBackground": "#dfb3ff1a", + "hoverInactiveBackground": "#dfb3ff1a" + }, + + "Button": { + "hoverBackground": "#1e1e24", + "selectedBackground": "#1e1e24", + "selectedForeground": "#D0D0D9" + } + }, + + "Tree.rowHeight": 20, + + "ValidationTooltip": { + "errorBackground": "#802d43", + "errorBorderColor": "#4d1c2b", + "warningBackground": "#735822", + "warningBorderColor": "#403013" + }, + + "VersionControl": { + "Log.Commit": { + "currentBranchBackground": "#202340", + "unmatchedForeground": "#6d6a80", + "hoveredBackground": "#000000B9" + }, + "FileHistory.Commit.selectedBranchBackground": "#202340" + }, + + "WelcomeScreen": { + "Projects.selectionInactiveBackground": "#713a91", + "separatorColor": "#1a1721", + "Details.background": "#26262E", + "Projects.actions.background": "#343445" + } + }, + + "icons": { + "ColorPalette": { + "Actions.Grey": "#a4a1b3", + "Actions.Red": "#c63a5d", + "Actions.Yellow": "#caba2d", + "Actions.Green": "#25ad6b", + "Actions.Blue": "#4d85ff", + "Actions.GreyInline.Dark": "#9f99bfb3", + + "Objects.Grey": "#9790ad", + "Objects.RedStatus": "#dd3962", + "Objects.Red": "#c63a5d", + "Objects.Pink": "#f98b9e", + "Objects.Yellow": "#caba2d", + "Objects.Green": "#239e62", + "Objects.Blue": "#598bff", + "Objects.Purple": "#af71e0", + "Objects.BlackText": "#000000ff", + "Objects.YellowDark": "#988c26", + "Objects.GreenAndroid": "#78c257", + + "Checkbox.Background.Default.Dark": "#343445", + "Checkbox.Border.Default.Dark": "#756b8c", + "Checkbox.Foreground.Selected.Dark": "#a4a1b3", + "Checkbox.Focus.Wide.Dark": "#723b94", + "Checkbox.Focus.Thin.Default.Dark": "#8a64b3", + "Checkbox.Focus.Thin.Selected.Dark": "#8a64b3", + "Checkbox.Background.Disabled.Dark": "#2C2C3B", + "Checkbox.Border.Disabled.Dark": "#4c4766", + "Checkbox.Foreground.Disabled.Dark": "#565073" + } + } +} diff --git a/src/main/resources/theme/Light.theme.json b/src/main/resources/theme/Light.theme.json new file mode 100644 index 0000000..531ad96 --- /dev/null +++ b/src/main/resources/theme/Light.theme.json @@ -0,0 +1,145 @@ +{ + "name": "IntelliJ Light", + "dark": false, + "author": "JetBrains", + "editorScheme": "/themes/Light.xml", + + "colors": { + "foreground": "#000000", + "infoPanelForeground": "#808080", + "infoInputForeground": "#999999", + "disabledForeground": "#8C8C8C", + "selectionForeground": "#FFFFFF", + "linkForeground": "#2470B3", + + "border": "#D1D1D1", + "componentBorder": "#C4C4C4", + "lightBorder": "#d9d9d9", + "windowsPopupBorder": "#adadad", + + "panel": "#F2F2F2" + }, + + "ui": { + "*": { + "foreground": "foreground", + "acceleratorForeground": "foreground", + "caretForeground": "foreground", + "selectedForeground": "foreground", + "selectionInactiveForeground": "foreground", + + "selectionBackground": "#2675BF", + "selectionBackgroundInactive": "#D5D5D5", + "selectionInactiveBackground": "#D5D5D5", + + "disabledForeground": "disabledForeground", + "disabledText": "disabledForeground", + "inactiveForeground": "disabledForeground", + + "modifiedItemForeground": "#005ad9", + + "acceleratorSelectionForeground": "selectionForeground", + + "separatorColor": "border", + "separatorForeground": "infoInputForeground" + }, + + "Borders": { + "color": "border", + "ContrastBorderColor": "border" + }, + + "Button": { + "shadowColor": "#A6A6A600", + "startBorderColor": "componentBorder", + "endBorderColor": "componentBorder", + "default": { + "foreground": "selectionForeground", + "startBackground": "#528CC7", + "endBackground": "#4989CC", + "startBorderColor": "#487EB8", + "endBorderColor": "#346DAD", + "shadowColor": "#A6A6A600", + "focusedBorderColor": "#A9C9F5" + } + }, + + "ComboBox": { + "background": "#FFFFFF", + "nonEditableBackground": "#FFFFFF", + "ArrowButton.background": "#fafafa" + }, + + "ComboBoxButton.background": "#FFFFFF", + + "CompletionPopup": { + "selectionBackground": "#c5dffc", + "selectionInactiveBackground": "#e0e0e0" + }, + + "Component": { + "borderColor": "componentBorder", + "infoForeground": "infoInputForeground" + }, + + "DefaultTabs.background": "panel", + + "EditorTabs.underlinedTabBackground": "#ffffff", + + "Editor": { + "background": "#cccccc", + "foreground": "#737373", + "shortcutForeground": "#4274A6" + }, + + "Label": { + "errorForeground": "#C7222D", + "infoForeground": "infoPanelForeground" + }, + + "Link": { + "activeForeground": "linkForeground", + "hoverForeground": "linkForeground", + "pressedForeground": "linkForeground", + "visitedForeground": "linkForeground", + "secondaryForeground": "#77a8d9" + }, + + "Notification": { + "borderColor": "border" + }, + + "Menu.borderColor": "lightBorder", + + "Panel.background": "panel", + + "PasswordField.background": "#FFFFFF", + + "Popup": { + "separatorColor": "lightBorder", + "Advertiser.borderColor": "border", + "borderColor": "windowsPopupBorder" + }, + + "ProgressBar": { + "trackColor": "#D1D1D1", + "progressColor": "#1E82E6", + "indeterminateStartColor": "#91C5F2", + "indeterminateEndColor": "#1E82E6" + }, + + "StatusBar.borderColor": "border", + + "ToolWindow.Header.inactiveBackground": "panel", + + "Tree.rowHeight": 20 + }, + + "icons": { + "ColorPalette": { + "Checkbox.Border.Default": "#b0b0b0", + "Checkbox.Background.Selected": "#4F9EE3", + "Checkbox.Border.Selected": "#4B97D9" + } + } +} \ No newline at end of file diff --git a/src/main/resources/version_summary.json b/src/main/resources/version_summary.json new file mode 100644 index 0000000..8acae24 --- /dev/null +++ b/src/main/resources/version_summary.json @@ -0,0 +1,19 @@ +{ + "currentVersion": "1.0.0", + "versionIndex": { + "0.0.0": "0", + "1.0.0": "1" + }, + "versionDetailList": [ + { + "version": "0.0.0", + "title": "The underlying version", + "log": "The underlying version\n" + }, + { + "version": "1.0.0", + "title": "The first version", + "log": "The first version\n" + } + ] +} \ No newline at end of file