diff --git a/pom.xml b/pom.xml index 0843f06ec81e26f3bee40c58599ff9dad1397a28..36c00ec57d450a2720a3dbd4e21c79eb4984ff17 100644 --- a/pom.xml +++ b/pom.xml @@ -6,13 +6,13 @@ com.light GitManagerClientFx - 1.0 + 3.0 21 21 UTF-8 - 21 + 21.0.1 2.0.1 diff --git a/src/main/java/com/light/GitManagerApp.java b/src/main/java/com/light/GitManagerApp.java index c6df68b6a6900c6c78b76f051310f628b26383ba..1586e3b10a971f1dea9f69aefaa9fc2ba26efe6f 100644 --- a/src/main/java/com/light/GitManagerApp.java +++ b/src/main/java/com/light/GitManagerApp.java @@ -4,8 +4,8 @@ import atlantafx.base.controls.ModalPane; import atlantafx.base.theme.*; import com.light.layout.ContentPane; import com.light.layout.MenuPane; -import com.light.thread.AsyncTask; -import com.light.thread.GitThreadPool; +import com.light.thread.FxAsyncTask; +import com.light.thread.FxThreadPoolTask; import com.light.util.FxApplicationContextUtils; import com.light.util.FxUtil; import com.light.util.H2PoolUtils; @@ -30,34 +30,37 @@ public class GitManagerApp extends Application { public void init() throws Exception { startTime = System.currentTimeMillis(); super.init(); - AsyncTask.runOnce("初始化数据库和主题数据", () -> { - String gitDbInit = H2PoolUtils.queryDictByLabel("GIT_DB_INIT", "0"); - if ("1".equals(gitDbInit)) { - H2PoolUtils.createTable(); - H2PoolUtils.initGitProjectDictData(); - } - - FxApplicationContextUtils.THEME_LIST.add(new PrimerLight()); - FxApplicationContextUtils.THEME_LIST.add(new PrimerDark()); - FxApplicationContextUtils.THEME_LIST.add(new NordLight()); - FxApplicationContextUtils.THEME_LIST.add(new NordDark()); - FxApplicationContextUtils.THEME_LIST.add(new CupertinoLight()); - FxApplicationContextUtils.THEME_LIST.add(new CupertinoDark()); - FxApplicationContextUtils.THEME_LIST.add(new Dracula()); - - // 设置主题 - String themeName = H2PoolUtils.queryDictByLabel("GIT_CURRENT_THEME", "Primer Light"); - FxApplicationContextUtils.CURRENT_THEME_NAME.set(themeName); - FxApplicationContextUtils.THEME_LIST.stream() - .filter(theme -> theme.getName().equals(themeName)) - .findFirst() - .ifPresentOrElse(theme -> Application.setUserAgentStylesheet(theme.getUserAgentStylesheet()), - () -> Application.setUserAgentStylesheet(FxApplicationContextUtils.THEME_LIST.getFirst().getUserAgentStylesheet()) - ); - - // 查询所有项目数据 - H2PoolUtils.queryGitProjects(); - }); + + FxAsyncTask.runOnceBack(startTime, "初始化数据库和主题数据", + () -> { + String gitDbInit = H2PoolUtils.queryDictByLabel("GIT_DB_INIT", "0"); + if ("0".equals(gitDbInit)) { + H2PoolUtils.createTable(); + H2PoolUtils.initGitProjectDictData(); + } + + FxApplicationContextUtils.THEME_LIST.add(new PrimerLight()); + FxApplicationContextUtils.THEME_LIST.add(new PrimerDark()); + FxApplicationContextUtils.THEME_LIST.add(new NordLight()); + FxApplicationContextUtils.THEME_LIST.add(new NordDark()); + FxApplicationContextUtils.THEME_LIST.add(new CupertinoLight()); + FxApplicationContextUtils.THEME_LIST.add(new CupertinoDark()); + FxApplicationContextUtils.THEME_LIST.add(new Dracula()); + // 设置主题 + return H2PoolUtils.queryDictByLabel("GIT_CURRENT_THEME", "Primer Light"); + }, + success -> { + FxApplicationContextUtils.CURRENT_THEME_NAME.set(success); + FxApplicationContextUtils.THEME_LIST.stream() + .filter(theme -> theme.getName().equals(success)) + .findFirst() + .ifPresentOrElse(theme -> Application.setUserAgentStylesheet(theme.getUserAgentStylesheet()), + () -> Application.setUserAgentStylesheet(FxApplicationContextUtils.THEME_LIST.getFirst().getUserAgentStylesheet()) + ); + + // 查询所有项目数据 + H2PoolUtils.queryGitProjects(); + }); } @Override @@ -99,7 +102,7 @@ public class GitManagerApp extends Application { public void stop() throws Exception { super.stop(); H2PoolUtils.closeConnectionPool(); - GitThreadPool.close(); + FxThreadPoolTask.close(); } public static void main(String[] args) { diff --git a/src/main/java/com/light/component/DownloadHBox.java b/src/main/java/com/light/component/DownloadHBox.java index c4e26105a6dbbf2e4befeb1bb292c38161a8cdc5..4bff0d3ec7e98b5d186c354128efef6f3f99ae1d 100644 --- a/src/main/java/com/light/component/DownloadHBox.java +++ b/src/main/java/com/light/component/DownloadHBox.java @@ -2,20 +2,15 @@ package com.light.component; import atlantafx.base.theme.Styles; import com.light.exception.AuthException; -import com.light.exception.JGitException; -import com.light.exception.TimeOutException; import com.light.model.GitAuthInfo; import com.light.model.GitProject; -import com.light.thread.AsyncTask; +import com.light.thread.FxAsyncTask; import com.light.util.DateUtils; import com.light.util.FxApplicationContextUtils; import com.light.util.H2PoolUtils; import com.light.util.JGitUtils; -import javafx.application.Platform; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.*; +import javafx.concurrent.Task; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; @@ -95,51 +90,55 @@ public class DownloadHBox extends HBox { */ public void cloneRepo(CredentialsProvider provider, boolean retry) { this.provider = provider; - AsyncTask.runOnce("克隆项目", () -> { - if (retry) { - deleteFiles(localRepoFile); - retryButton.setVisible(false); - } + AuthenticationPane authPane = AuthenticationPane.getInstance(); - String branch = ""; - try { - // 开始下载 - branch = JGitUtils.cloneRepo(remoteUrl, localRepoFile, provider, customProgressMonitor); - } catch (AuthException e) { - // 弹出输入权限界面 - AuthenticationPane authPane = AuthenticationPane.getInstance(); - authPane.refreshData(remoteUrl, (username, password) -> this.cloneRepo(JGitUtils.createCredential(username, password), true)); - Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); - retryButton.setVisible(true); - return; - } catch (TimeOutException | JGitException e) { - retryButton.setVisible(true); - return; - } + Task task = FxAsyncTask.runOnceBack(System.currentTimeMillis(), "克隆项目", + () -> { + if (retry) { + deleteFiles(localRepoFile); + retryButton.setVisible(false); + } - // 下载完成入库 - String name = getRepoName(remoteUrl); - String author = getAuthor(remoteUrl); - String local = localRepoFile.getAbsolutePath(); - GitProject newProject = new GitProject(new SimpleIntegerProperty(0), - new SimpleStringProperty(name), - new SimpleStringProperty(author), - new SimpleStringProperty(branch), - DateUtils.formatDateTime(new Date()), - new SimpleStringProperty(DateUtils.formatDateTime(new Date())), - remoteUrl, - new SimpleStringProperty(local), - new SimpleStringProperty(), - new SimpleStringProperty(), - new SimpleIntegerProperty(0), - new SimpleDoubleProperty(0.0), - new SimpleBooleanProperty(false) - ); - H2PoolUtils.insertProjectInfo(newProject); - FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.add(newProject); - // 更新下载数量-1 - FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.decrementAndGet())); - }); + try { + // 开始下载 + String branch = JGitUtils.cloneRepo(remoteUrl, localRepoFile, provider, customProgressMonitor); + // 下载完成入库 + String name = getRepoName(remoteUrl); + String author = getAuthor(remoteUrl); + String local = localRepoFile.getAbsolutePath(); + GitProject newProject = new GitProject(new SimpleIntegerProperty(0), + new SimpleStringProperty(name), + new SimpleStringProperty(author), + new SimpleStringProperty(branch), + DateUtils.formatDateTime(new Date()), + new SimpleStringProperty(DateUtils.formatDateTime(new Date())), + remoteUrl, + new SimpleStringProperty(local), + new SimpleStringProperty(), + new SimpleStringProperty(), + new SimpleIntegerProperty(0), + new SimpleDoubleProperty(0.0), + new SimpleBooleanProperty(false) + ); + H2PoolUtils.insertProjectInfo(newProject); + + return newProject; + } catch (AuthException e) { + authPane.refreshData(remoteUrl, (username, password) -> cloneRepo(JGitUtils.createCredential(username, password), true)); + throw new AuthException(); + } + }, + success -> { + FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.add(success); + // 更新下载数量-1 + FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.decrementAndGet())); + }, + fail -> { + if (authPane != null) { + authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene")); + } + retryButton.setVisible(true); + }); } private void deleteFiles(File folder) { diff --git a/src/main/java/com/light/component/LevelTableCell.java b/src/main/java/com/light/component/LevelTableCell.java index 74cd218f6bcda0fcd27ceef23de602bc185f083b..664590785160af105ce7c967782179a226ae7c5e 100644 --- a/src/main/java/com/light/component/LevelTableCell.java +++ b/src/main/java/com/light/component/LevelTableCell.java @@ -1,7 +1,7 @@ package com.light.component; import com.light.model.GitProject; -import com.light.thread.AsyncTask; +import com.light.thread.FxAsyncTask; import com.light.util.H2PoolUtils; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -61,7 +61,7 @@ public class LevelTableCell extends TableCell { if (!choiceBox.isShowing()) { commitEdit(choiceBox.getValue()); if (oldValue != choiceBox.getValue()) { - AsyncTask.runOnce("更新学习等级", () -> H2PoolUtils.updateGitProject(getTableRow().getItem())); + FxAsyncTask.runOnce("更新学习等级", () -> H2PoolUtils.updateGitProject(getTableRow().getItem())); } } }); diff --git a/src/main/java/com/light/component/NoticePane.java b/src/main/java/com/light/component/NoticePane.java index 25bfa3ae94bc81b0694951eb4495d58949abc1bb..02115ac7662fe1956e9fd0e23045b3c3ddbb2284 100644 --- a/src/main/java/com/light/component/NoticePane.java +++ b/src/main/java/com/light/component/NoticePane.java @@ -7,18 +7,18 @@ import javafx.scene.layout.HBox; public class NoticePane extends ModalDialog { - public NoticePane(String title, ObservableList list) { + public NoticePane(String title, ObservableList list) { super(); header.setTitle(title); content.setBody(createContent(list)); content.setFooter(null); } - private HBox createContent(ObservableList list) { - ListView listView = new ListView<>(list); + private HBox createContent(ObservableList list) { + ListView listView = new ListView<>(list); listView.getStyleClass().add("du-list"); - listView.setMaxWidth(800); - listView.setMinWidth(550); + listView.setMaxWidth(600); + listView.setMinWidth(600); return new HBox(listView); } diff --git a/src/main/java/com/light/component/OperationTableCell.java b/src/main/java/com/light/component/OperationTableCell.java index ebaee278bf916ef97ab2e0740418e4c572ff88d5..8bb1900dfce72ae8934d3e74fe27a2e164b9acd4 100644 --- a/src/main/java/com/light/component/OperationTableCell.java +++ b/src/main/java/com/light/component/OperationTableCell.java @@ -4,25 +4,37 @@ import atlantafx.base.theme.Styles; import com.light.exception.AuthException; import com.light.exception.JGitException; import com.light.exception.TimeOutException; +import com.light.model.GitAuthInfo; import com.light.model.GitProject; -import com.light.thread.AsyncTask; +import com.light.thread.FxAsyncTask; +import com.light.util.DateUtils; import com.light.util.FxApplicationContextUtils; +import com.light.util.H2PoolUtils; import com.light.util.JGitUtils; import com.light.view.ManagerView; +import javafx.application.Platform; import javafx.beans.property.SimpleDoubleProperty; +import javafx.concurrent.Task; import javafx.geometry.Pos; +import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.layout.HBox; import javafx.util.Callback; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; +import java.util.Date; /** * 操作列 - 按钮 */ public class OperationTableCell extends TableCell { + + public static final Logger LOGGER = LoggerFactory.getLogger(OperationTableCell.class); Button updateButton = new Button("更新"); Button detailButton = new Button("详情"); HBox operationBox = new HBox(updateButton, detailButton); @@ -66,19 +78,71 @@ public class OperationTableCell extends TableCell { if (null != project) { // 更新更新数量+1 FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); - AsyncTask.runOnce("更新项目", () -> { - File localRepoFile = new File(project.local().get()); - String remoteUrl = project.remote(); - try { - ManagerView.pull(project, localRepoFile, remoteUrl, rate); - } catch (AuthException e) { - ManagerView.showAuthPane(remoteUrl, localRepoFile, project, rate, updateButton); - } catch (TimeOutException | JGitException ignored) { + String message = "更新项目"; + long startTime = System.currentTimeMillis(); + FxAsyncTask.runOnceTask(message, new Task() { + private AuthenticationPane authPane; + + @Override + protected Object call() throws Exception { + File localRepoFile = new File(project.local().get()); + String remoteUrl = project.remote(); + try { + authPane = null; + ManagerView.pull(project, localRepoFile, remoteUrl, rate); + } catch (AuthException e) { + authPane = AuthenticationPane.getInstance(); + authPane.refreshData(remoteUrl, (username, password) -> { + GitAuthInfo authInfo = authPane.dealAuthInfo(username, password, JGitUtils.getType(remoteUrl)); + if (authInfo != null) { + // 更新 + // 更新更新数量+1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); + try { + CredentialsProvider provider = JGitUtils.createCredential(username, password); + boolean pull = JGitUtils.pull(remoteUrl, localRepoFile, provider, rate); + if (pull) { + project.updateTime().set(DateUtils.formatDateTime(new Date())); + H2PoolUtils.updateGitProject(project); + project.selected().set(false); + } + } catch (AuthException e1) { + // 弹出输入权限界面 + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); + } catch (TimeOutException | JGitException ignored) { + + } + // 更新更新数量-1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + } + }); + throw new AuthException(); + } + return null; + } + + @Override + protected void succeeded() { + super.succeeded(); + // 更新更新数量-1 + authPane = null; + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + updateButton.setDisable(false); + LOGGER.info("Task {} 执行成功,耗时 {} ms", message, System.currentTimeMillis() - startTime); + } + + @Override + protected void failed() { + super.failed(); + if (authPane != null) { + authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene")); + } + // 更新更新数量-1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + updateButton.setDisable(false); + LOGGER.info("Task {} 执行失败,耗时 {} ms", message, System.currentTimeMillis() - startTime); } - // 更新更新数量-1 - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); - updateButton.setDisable(false); }); } }); diff --git a/src/main/java/com/light/component/PaymentQRCodePane.java b/src/main/java/com/light/component/PaymentQRCodePane.java new file mode 100644 index 0000000000000000000000000000000000000000..aaf793bcde271705cf11e0803d12fca09bb0fa00 --- /dev/null +++ b/src/main/java/com/light/component/PaymentQRCodePane.java @@ -0,0 +1,18 @@ +package com.light.component; + +import com.light.layout.ModalDialog; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; + + +public class PaymentQRCodePane extends ModalDialog { + + public PaymentQRCodePane(){ + header.setTitle("打赏作者"); + Image qrCode = new Image("/icons/qrcode.jpg"); + ImageView qrCodeView = new ImageView(qrCode); + qrCodeView.setFitWidth(300); + qrCodeView.setFitHeight(350); + content.setBody(qrCodeView); + } +} diff --git a/src/main/java/com/light/layout/MenuPane.java b/src/main/java/com/light/layout/MenuPane.java index 2a4a86ab4dcaecc3aebf6b5585733b4cc1414f0b..c0c2224653a16991b870dc64231a19c74ba8d289 100644 --- a/src/main/java/com/light/layout/MenuPane.java +++ b/src/main/java/com/light/layout/MenuPane.java @@ -3,6 +3,7 @@ package com.light.layout; import atlantafx.base.theme.Styles; import com.light.component.DownAndUpdatePane; import com.light.component.NoticePane; +import com.light.component.PaymentQRCodePane; import com.light.theme.ThemeDialog; import com.light.util.FxApplicationContextUtils; import com.light.util.FxUtil; @@ -11,15 +12,20 @@ import com.light.view.HomeView; import com.light.view.ManagerView; import com.light.view.NotificationView; import javafx.collections.ListChangeListener; +import javafx.event.Event; import javafx.geometry.Orientation; import javafx.geometry.Pos; +import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ListView; import javafx.scene.control.Separator; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import javafx.scene.text.Font; import javafx.scene.text.Text; import org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled; import org.kordamp.ikonli.antdesignicons.AntDesignIconsOutlined; @@ -41,15 +47,20 @@ public class MenuPane extends StackPane { private final ListView dynamicMenu = new ListView<>(); // 底部导航栏 - private final Label downloadLabel = new Label("正在下载", new FontIcon(BootstrapIcons.ARROW_DOWN)); + private final Label downloadLabel = new Label("下载中", new FontIcon(BootstrapIcons.ARROW_DOWN)); private final Text downloadLabelText = new Text(FxApplicationContextUtils.DOWNLOAD_PROPERTY.getValue()); private final HBox downloadBox = new HBox(10, downloadLabel, downloadLabelText); - private final Label updateLabel = new Label("正在更新", new FontIcon(BootstrapIcons.ARROW_DOWN)); + private final Label updateLabel = new Label("更新中", new FontIcon(BootstrapIcons.ARROW_DOWN)); private final Text updateLabelText = new Text(FxApplicationContextUtils.UPDATE_PROPERTY.getValue()); private final HBox updateBox = new HBox(10, updateLabel, updateLabelText); private final VBox bottomMenu = new VBox(downloadBox, updateBox); - private final VBox asideContainer = new VBox(topMenu, new Separator(Orientation.HORIZONTAL), dynamicMenu, new Separator(Orientation.HORIZONTAL), bottomMenu); + //底部导航栏打赏作者 + private final Button payQRCodeBtn = new Button(); + + private final HBox bottomBox = new HBox(10, bottomMenu, payQRCodeBtn); + + private final VBox asideContainer = new VBox(topMenu, new Separator(Orientation.HORIZONTAL), dynamicMenu, new Separator(Orientation.HORIZONTAL), bottomBox); private final ContentPane contentPane; @@ -80,13 +91,16 @@ public class MenuPane extends StackPane { this.bottomMenu.getStyleClass().add("down-update"); this.downloadLabel.getStyleClass().add("download-label"); this.updateLabel.getStyleClass().add("update-label"); - + Image author = new Image("/icons/author.png"); + ImageView authorView = new ImageView(author); + this.payQRCodeBtn.setGraphic(authorView); + payQRCodeBtn.getStyleClass().addAll(Styles.FLAT, Styles.ACCENT); // 直接设置样式 downloadBox.setAlignment(Pos.CENTER_LEFT); downloadLabelText.getStyleClass().addAll(Styles.TEXT, Styles.SUCCESS); updateBox.setAlignment(Pos.CENTER_LEFT); updateLabelText.getStyleClass().addAll(Styles.TEXT, Styles.WARNING); - + HBox.setHgrow(bottomMenu, Priority.ALWAYS); initEvent(); } @@ -121,5 +135,9 @@ public class MenuPane extends StackPane { downloadLabel.setOnMouseClicked(event -> { downloadPane.show(getScene()); }); + + PaymentQRCodePane paymentQRCodePane = new PaymentQRCodePane(); + payQRCodeBtn.setOnMouseClicked(Event -> paymentQRCodePane.show(getScene())); + } } diff --git a/src/main/java/com/light/theme/ThemeDialog.java b/src/main/java/com/light/theme/ThemeDialog.java index 8058c7648f3c1d7b208b2277df050aaf5e6855d8..7c2e9f7b41d64d11e9f9a77f6de13d34a575f494 100644 --- a/src/main/java/com/light/theme/ThemeDialog.java +++ b/src/main/java/com/light/theme/ThemeDialog.java @@ -4,7 +4,7 @@ package com.light.theme; import atlantafx.base.theme.Theme; import com.light.layout.ModalDialog; -import com.light.thread.AsyncTask; +import com.light.thread.FxAsyncTask; import com.light.util.FxApplicationContextUtils; import com.light.util.H2PoolUtils; import javafx.application.Application; @@ -39,7 +39,7 @@ public final class ThemeDialog extends ModalDialog { if (val != null && val.getUserData() instanceof Theme theme) { FxApplicationContextUtils.CURRENT_THEME_NAME.set(theme.getName()); Application.setUserAgentStylesheet(theme.getUserAgentStylesheet()); - AsyncTask.runOnce("主题更新", () -> H2PoolUtils.updateDictData("GIT_CURRENT_THEME", theme.getName())); + FxAsyncTask.runOnce("主题更新同步数据库", () -> H2PoolUtils.updateDictData("GIT_CURRENT_THEME", theme.getName())); } }); } diff --git a/src/main/java/com/light/thread/AsyncTask.java b/src/main/java/com/light/thread/AsyncTask.java deleted file mode 100644 index 8fff8da66b0e2211f707cb69635e31a3b966b1a4..0000000000000000000000000000000000000000 --- a/src/main/java/com/light/thread/AsyncTask.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.light.thread; - -import javafx.concurrent.Task; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AsyncTask extends Task { - - public static final Logger LOGGER = LoggerFactory.getLogger(AsyncTask.class); - - private final String description; - - private final long startTime; - - private final AsyncEvent asyncEvent; - - public AsyncTask(String description, AsyncEvent asyncEvent) { - this.description = description; - this.asyncEvent = asyncEvent; - this.startTime = System.currentTimeMillis(); - } - - @Override - protected Void call() throws Exception { - try { - LOGGER.info("Task {} 开始执行", description); - asyncEvent.handler(); - } catch (Exception e) { - LOGGER.info("Task {} 执行异常:{}", description, e.getMessage()); - } - return null; - } - - @Override - protected void succeeded() { - super.succeeded(); - LOGGER.info("Task {} 执行结束,耗时 {} ms", description, System.currentTimeMillis() - startTime); - } - - @Override - protected void failed() { - super.failed(); - LOGGER.info("Task {} 执行失败", description); - } - - public static void runOnce(AsyncEvent event) { - runOnce("任务", event); - } - - public static void runOnce(String description, AsyncEvent event) { - GitThreadPool.EXECUTOR_SERVICE.execute(new AsyncTask(description, event)); - } -} diff --git a/src/main/java/com/light/thread/FxAsyncTask.java b/src/main/java/com/light/thread/FxAsyncTask.java new file mode 100644 index 0000000000000000000000000000000000000000..2ce9c6aa154ebc9c216e6dc8692ff8c9e1fd292c --- /dev/null +++ b/src/main/java/com/light/thread/FxAsyncTask.java @@ -0,0 +1,159 @@ +package com.light.thread; + +import javafx.concurrent.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.function.Consumer; + +/** + * 启用虚拟线程异步执行任务 - 工具类 + *

+ * 注意:为了能正确执行 成功和失败 方法,自定义方法中有异常要抛出,不要处理 + *

+ * 虚拟线程的应用场景主要包括 IO 密集型任务和高并发 Web 服务器等领域 + *

+ * 不支持 CPU 密集型任务、无法直接访问线程本地变量 + */ +public final class FxAsyncTask { + + public static final Logger LOGGER = LoggerFactory.getLogger(FxAsyncTask.class); + + /** + * 异步执行一次 + * + * @param run + * @param + * @return + */ + public static Task runOnce(Run run) { + return runOnce("异步执行一次", run); + } + + /** + * 异步执行一次 + * + * @param message + * @param run + * @param + * @return + */ + public static Task runOnce(String message, Run run) { + return runOnce(System.currentTimeMillis(), message, run); + } + + /** + * 异步执行一次 + * + * @param startTime + * @param message + * @param run + * @param + * @return + */ + public static Task runOnce(long startTime, String message, Run run) { + return runOnce(startTime, message, run, null); + } + + /** + * 异步执行一次 + * + * @param startTime + * @param message + * @param run + * @param success + * @param + * @return + */ + public static Task runOnce(long startTime, String message, Run run, RunSuccess success) { + return runOnce(startTime, message, run, success, null); + } + + /** + * 异步执行一次 + * + * @param startTime + * @param message + * @param run + * @param success + * @param fail + * @param + * @return + */ + public static Task runOnce(long startTime, String message, Run run, RunSuccess success, RunFail fail) { + Task task = FxTask.createTask(startTime, message, run, success, fail); + Thread.startVirtualThread(task); + return task; + } + + /** + * 异步执行一次有返回值 + * + * @param runBack + * @param + * @return + */ + public static Task runOnceBack(RunBack runBack) { + return runOnceBack("异步执行一次有返回值", runBack); + } + + /** + * 异步执行一次有返回值 + * + * @param message + * @param runBack + * @param + * @return + */ + public static Task runOnceBack(String message, RunBack runBack) { + return runOnceBack(System.currentTimeMillis(), message, runBack); + } + + /** + * 异步执行一次有返回值 + * + * @param startTime + * @param message + * @param runBack + * @param + * @return + */ + public static Task runOnceBack(long startTime, String message, RunBack runBack) { + return runOnceBack(startTime, message, runBack, null); + } + + /** + * 异步执行一次有返回值 + * + * @param startTime + * @param message + * @param runBack + * @param + * @return + */ + public static Task runOnceBack(long startTime, String message, RunBack runBack, Consumer success) { + return runOnceBack(startTime, message, runBack, success, null); + } + + /** + * 异步执行一次有返回值 + * + * @param startTime + * @param message + * @param runBack 要处理的方法 + * @param success 成功后执行的方法 + * @param fail 失败后执行的方法 + * @param + * @return + */ + public static Task runOnceBack(long startTime, String message, RunBack runBack, Consumer success, Consumer fail) { + Task task = FxTask.createTaskBack(startTime, message, runBack, success, fail); + Thread.startVirtualThread(task); + return task; + } + + public static void runOnceTask(String message, Task task) { + LOGGER.info("Task {} 开始执行", message); + Thread.startVirtualThread(task); + } +} diff --git a/src/main/java/com/light/thread/FxTask.java b/src/main/java/com/light/thread/FxTask.java new file mode 100644 index 0000000000000000000000000000000000000000..a79c7b2d4e421356d39936391948ca6e45aefd5e --- /dev/null +++ b/src/main/java/com/light/thread/FxTask.java @@ -0,0 +1,68 @@ +package com.light.thread; + +import javafx.concurrent.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; +import java.util.function.Consumer; + +/** + * 创建task工具类 + */ +public class FxTask { + public static final Logger LOGGER = LoggerFactory.getLogger(FxTask.class); + + public static Task createTask(long startTime, String message, Run run, RunSuccess success, RunFail fail) { + return new Task<>() { + @Override + protected T call() throws Exception { + LOGGER.info("Task {} 开始执行", message); + run.run(); + return null; + } + + @Override + protected void succeeded() { + super.succeeded(); + if (null != success) { + success.run(); + } + LOGGER.info("Task {} 执行成功,耗时 {} ms", message, System.currentTimeMillis() - startTime); + } + + @Override + protected void failed() { + super.failed(); + if (null != fail) { + fail.run(); + } + LOGGER.info("Task {} 执行失败,耗时 {} ms", message, System.currentTimeMillis() - startTime); + } + }; + } + + public static Task createTaskBack(long startTime, String message, RunBack runBack, Consumer success, Consumer fail) { + return new Task<>() { + @Override + protected T call() throws Exception { + LOGGER.info("Task {} 开始执行", message); + return runBack.get(); + } + + @Override + protected void succeeded() { + super.succeeded(); + Optional.of(success).ifPresent(success -> success.accept(getValue())); + LOGGER.info("Task {} 执行成功,耗时 {} ms", message, System.currentTimeMillis() - startTime); + } + + @Override + protected void failed() { + super.failed(); + Optional.of(fail).ifPresent(fail -> fail.accept(getValue())); + LOGGER.info("Task {} 执行失败,耗时 {} ms", message, System.currentTimeMillis() - startTime); + } + }; + } +} diff --git a/src/main/java/com/light/thread/FxThreadPoolTask.java b/src/main/java/com/light/thread/FxThreadPoolTask.java new file mode 100644 index 0000000000000000000000000000000000000000..41f227dd370d3b81a683655344a28b7567c18a1d --- /dev/null +++ b/src/main/java/com/light/thread/FxThreadPoolTask.java @@ -0,0 +1,87 @@ +package com.light.thread; + +import javafx.concurrent.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 利用线程池处理异步任务 + */ +public class FxThreadPoolTask { + public static final Logger LOGGER = LoggerFactory.getLogger(FxThreadPoolTask.class); + + // 普通线程池 + public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10); + // 虚拟线程池 + public static final ExecutorService EXECUTOR_VIRTUAL_SERVICE = Executors.newVirtualThreadPerTaskExecutor(); + + // 当前正在处理的任务数(目前设定同时最多处理5个任务) + public static final AtomicInteger THREAD_DEALING_NUM = new AtomicInteger(0); + + public static void close() { + if (!EXECUTOR_SERVICE.isShutdown()) { + EXECUTOR_SERVICE.shutdown(); + LOGGER.info("普通线程池关闭"); + } + if (!EXECUTOR_VIRTUAL_SERVICE.isShutdown()) { + EXECUTOR_VIRTUAL_SERVICE.shutdown(); + LOGGER.info("虚拟线程池关闭"); + } + } + + /** + * 普通线程池执行task任务 + * + * @param message + * @param run + */ + public static void runPool(String message, Run run) { + runPool(System.currentTimeMillis(), message, run, null, null); + } + + /** + * 普通线程池执行task任务 + * + * @param startTime + * @param message + * @param run + * @param success + * @param fail + */ + public static void runPool(long startTime, String message, Run run, RunSuccess success, RunFail fail) { + runPool(FxTask.createTask(startTime, message, run, success, fail)); + } + + public static void runPool(Task task) { + // 正在运行task +1 + THREAD_DEALING_NUM.incrementAndGet(); + EXECUTOR_SERVICE.execute(task); + } + + public static void runVirtualPool(String message, Run run) { + runVirtualPool(System.currentTimeMillis(), message, run, null, null); + } + + /** + * 虚拟线程池执行task任务 + * + * @param startTime + * @param message + * @param run + * @param success + * @param fail + */ + public static void runVirtualPool(long startTime, String message, Run run, RunSuccess success, RunFail fail) { + runVirtualPool(FxTask.createTask(startTime, message, run, success, fail)); + } + + public static void runVirtualPool(Task task) { + // 正在运行task +1 + THREAD_DEALING_NUM.incrementAndGet(); + EXECUTOR_VIRTUAL_SERVICE.execute(task); + } +} diff --git a/src/main/java/com/light/thread/GitThreadPool.java b/src/main/java/com/light/thread/GitThreadPool.java deleted file mode 100644 index 0572585c426895897f7fdb04914147cbc0169af5..0000000000000000000000000000000000000000 --- a/src/main/java/com/light/thread/GitThreadPool.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.light.thread; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -public class GitThreadPool { - public static final Logger LOGGER = LoggerFactory.getLogger(GitThreadPool.class); - - // 普通线程池 - public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10); - - // 定时线程池 - public static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newScheduledThreadPool(5); - - public static void close() { - if (!EXECUTOR_SERVICE.isShutdown()) { - EXECUTOR_SERVICE.shutdown(); - } - if (!SCHEDULED_EXECUTOR_SERVICE.isShutdown()) { - SCHEDULED_EXECUTOR_SERVICE.shutdown(); - } - LOGGER.info("线程池关闭"); - } -} diff --git a/src/main/java/com/light/thread/Run.java b/src/main/java/com/light/thread/Run.java new file mode 100644 index 0000000000000000000000000000000000000000..5eea1c09752d160e912e221492099745f756adca --- /dev/null +++ b/src/main/java/com/light/thread/Run.java @@ -0,0 +1,5 @@ +package com.light.thread; + +public interface Run { + void run() throws Exception; +} diff --git a/src/main/java/com/light/thread/AsyncEvent.java b/src/main/java/com/light/thread/RunBack.java similarity index 30% rename from src/main/java/com/light/thread/AsyncEvent.java rename to src/main/java/com/light/thread/RunBack.java index 0ec782afbc59c93e31c44bd7c5f001ee6ed3df41..999a7e5164508c7df0f5ba8d8e464a06cf7cbba5 100644 --- a/src/main/java/com/light/thread/AsyncEvent.java +++ b/src/main/java/com/light/thread/RunBack.java @@ -1,6 +1,6 @@ package com.light.thread; -public interface AsyncEvent { +public interface RunBack { - void handler() throws Exception; + T get() throws Exception; } diff --git a/src/main/java/com/light/thread/RunFail.java b/src/main/java/com/light/thread/RunFail.java new file mode 100644 index 0000000000000000000000000000000000000000..bbf518ca53af2b493ddedba61d2a9f4b177fbfb3 --- /dev/null +++ b/src/main/java/com/light/thread/RunFail.java @@ -0,0 +1,5 @@ +package com.light.thread; + +public interface RunFail { + void run(); +} diff --git a/src/main/java/com/light/thread/RunSuccess.java b/src/main/java/com/light/thread/RunSuccess.java new file mode 100644 index 0000000000000000000000000000000000000000..943ee74058a9275840dfed044c7b3a5b8be798e8 --- /dev/null +++ b/src/main/java/com/light/thread/RunSuccess.java @@ -0,0 +1,6 @@ +package com.light.thread; + +public interface RunSuccess { + + void run(); +} diff --git a/src/main/java/com/light/util/FxApplicationContextUtils.java b/src/main/java/com/light/util/FxApplicationContextUtils.java index 0ff48b63a507fd9c7e17220cbd15e345e361564f..02e16f6636e2baa95c5cd5cf608d8a632353ec0c 100644 --- a/src/main/java/com/light/util/FxApplicationContextUtils.java +++ b/src/main/java/com/light/util/FxApplicationContextUtils.java @@ -54,5 +54,5 @@ public final class FxApplicationContextUtils { /** * 历史通知集合 */ - public static final ObservableList HISTORY_NOTICE_LIST = FXCollections.observableArrayList(); + public static final ObservableList HISTORY_NOTICE_LIST = FXCollections.observableArrayList(); } diff --git a/src/main/java/com/light/util/FxUtil.java b/src/main/java/com/light/util/FxUtil.java index db43480d74e4684b0bf657ee5a7d6bcf5c002d39..c631cf6d1786f13f8d0739fb6690a9e8ae0f97a9 100644 --- a/src/main/java/com/light/util/FxUtil.java +++ b/src/main/java/com/light/util/FxUtil.java @@ -1,18 +1,27 @@ package com.light.util; +import atlantafx.base.theme.Styles; +import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.geometry.Bounds; import javafx.geometry.Insets; +import javafx.geometry.Pos; import javafx.scene.Node; +import javafx.scene.control.Button; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.shape.Rectangle; +import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.stage.Window; +import org.kordamp.ikonli.bootstrapicons.BootstrapIcons; +import org.kordamp.ikonli.javafx.FontIcon; import java.util.Objects; import java.util.concurrent.Callable; @@ -166,6 +175,17 @@ public class FxUtil { * @param message */ public static void addNoticeList(String message) { - FxApplicationContextUtils.HISTORY_NOTICE_LIST.add(0, message); + if (message.length() > 200) { + message = message.substring(0, 200); + } + Text text = new Text(message); + text.setWrappingWidth(500d); + Button removeButton = new Button(null, new FontIcon(BootstrapIcons.X)); + removeButton.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT, Styles.ACCENT); + HBox hBox = new HBox(10, text, removeButton); + hBox.setAlignment(Pos.CENTER); + HBox.setHgrow(text, Priority.ALWAYS); + removeButton.setOnMouseClicked(event -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.remove(hBox)); + Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add(0, hBox)); } } diff --git a/src/main/java/com/light/util/JGitUtils.java b/src/main/java/com/light/util/JGitUtils.java index 7602c0572446c6b2df0e13106353d36b13e36d90..a30b5e4f9a1367d3afbfb3bfe35aa6f1d3d060cb 100644 --- a/src/main/java/com/light/util/JGitUtils.java +++ b/src/main/java/com/light/util/JGitUtils.java @@ -6,7 +6,6 @@ import com.light.exception.JGitException; import com.light.exception.TimeOutException; import com.light.model.GitAuthInfo; import com.light.model.GitProject; -import javafx.application.Platform; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleIntegerProperty; @@ -183,7 +182,7 @@ public class JGitUtils { // 插入之前验证是否已经存在 if (H2PoolUtils.existsGitProjects(newProject)) { LOGGER.warn("项目 {},作者 {} 已经存在,不再新增", name, author); - Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("项目 " + name + ",作者 " + author + " 已经存在,不再新增")); + FxUtil.addNoticeList("项目 " + name + ",作者 " + author + " 已经存在,不再新增"); newProject = null; } else { // 不存在则继续新增,并设置id @@ -192,7 +191,7 @@ public class JGitUtils { } } catch (Exception e) { LOGGER.error("本地项目 {} 解析失败:{}", path.getAbsolutePath(), e.getMessage()); - Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("本地项目 " + path.getAbsolutePath() + " 解析失败:" + e.getMessage())); + FxUtil.addNoticeList("本地项目 " + path.getAbsolutePath() + " 解析失败:" + e.getMessage()); } }); @@ -208,7 +207,7 @@ public class JGitUtils { } catch (Exception e) { String message = e.getMessage(); LOGGER.error("项目 {} 克隆异常:{}", remoteUrl, message); - Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("项目 " + remoteUrl + " 克隆异常:" + message)); + FxUtil.addNoticeList("项目 " + remoteUrl + " 克隆异常:" + message); if (message.contains("authorized") || message.contains("Authentication")) { // 权限异常 throw new AuthException(); @@ -233,7 +232,7 @@ public class JGitUtils { } catch (Exception e) { String message = e.getMessage(); LOGGER.error("项目 {} 更新异常:{}", remoteUrl, message); - Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("项目 " + remoteUrl + " 更新异常:" + message)); + FxUtil.addNoticeList("项目 " + remoteUrl + " 更新异常:" + message); if ("Github".equals(getType(remoteUrl))) { GITHUB_FAIL_NUMBER.incrementAndGet(); } diff --git a/src/main/java/com/light/view/ManagerView.java b/src/main/java/com/light/view/ManagerView.java index 2f5596d3212b7a984113cde9c478465adcf6e1fc..56efdb5c6ecd4a832ab0a8ebe65e46d317794fc0 100644 --- a/src/main/java/com/light/view/ManagerView.java +++ b/src/main/java/com/light/view/ManagerView.java @@ -3,26 +3,21 @@ package com.light.view; import atlantafx.base.controls.CustomTextField; import atlantafx.base.theme.Styles; import atlantafx.base.theme.Tweaks; -import com.google.common.collect.Lists; -import com.light.component.AuthenticationPane; import com.light.component.LevelTableCell; import com.light.component.OperationTableCell; import com.light.component.TooltipTableRow; -import com.light.exception.AuthException; -import com.light.exception.JGitException; -import com.light.exception.TimeOutException; import com.light.model.GitAuthInfo; import com.light.model.GitProject; -import com.light.thread.AsyncTask; +import com.light.thread.FxAsyncTask; +import com.light.thread.FxTask; +import com.light.thread.FxThreadPoolTask; import com.light.util.DateUtils; import com.light.util.FxApplicationContextUtils; import com.light.util.H2PoolUtils; import com.light.util.JGitUtils; -import javafx.application.Platform; import javafx.beans.property.SimpleDoubleProperty; import javafx.collections.FXCollections; import javafx.geometry.Insets; -import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.TableColumn; @@ -43,6 +38,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.util.Date; +import java.util.Iterator; import java.util.List; public class ManagerView extends StackPane { @@ -158,7 +154,7 @@ public class ManagerView extends StackPane { dirChooser.setInitialDirectory(new File(H2PoolUtils.queryDictByLabel("GIT_CURRENT_LOCAL_DIR", "D:") + File.separator)); File file = dirChooser.showDialog(getScene().getWindow()); if (null != file) { - AsyncTask.runOnce("加载本地项目", () -> { + FxAsyncTask.runOnce("加载本地项目", () -> { JGitUtils.parseLocalProjectPath(file); JGitUtils.parseLocalProject(); }); @@ -185,6 +181,7 @@ public class ManagerView extends StackPane { // 全部更新按钮 updateButton.setOnMouseClicked(event -> { + event.consume(); JGitUtils.GITHUB_FAIL_NUMBER.set(0); JGitUtils.GITEE_FAIL_NUMBER.set(0); List list = tableView.getItems().stream().filter(param -> param.selected().get()).toList(); @@ -193,31 +190,39 @@ public class ManagerView extends StackPane { } // 更新更新数量 FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.addAndGet(list.size()))); - List> partitioned = Lists.partition(list, list.size() / 5); - partitioned.forEach(partitionList -> AsyncTask.runOnce("更新项目", () -> { - partitionList.forEach(param -> { - SimpleDoubleProperty rate = param.downloadRate(); - File localRepoFile = new File(param.local().get()); - String remoteUrl = param.remote(); - try { - if ("Gitee".equals(JGitUtils.getType(remoteUrl)) && JGitUtils.GITEE_FAIL_NUMBER.get() < 10) { - pull(param, localRepoFile, remoteUrl, rate); - } else if ("Github".equals(JGitUtils.getType(remoteUrl)) && JGitUtils.GITHUB_FAIL_NUMBER.get() < 5) { - pull(param, localRepoFile, remoteUrl, rate); + Iterator iterator = list.iterator(); + FxAsyncTask.runOnce(System.currentTimeMillis(), "批量更新", () -> { + while (iterator.hasNext()) { + if (FxThreadPoolTask.THREAD_DEALING_NUM.get() >= 5) { + Thread.sleep(1500); + continue; + } + GitProject project = iterator.next(); + FxThreadPoolTask.runVirtualPool(FxTask.createTask(System.currentTimeMillis(), "更新项目", + () -> { + SimpleDoubleProperty rate = project.downloadRate(); + File localRepoFile = new File(project.local().get()); + String remoteUrl = project.remote(); + if ("Gitee".equals(JGitUtils.getType(remoteUrl)) && JGitUtils.GITEE_FAIL_NUMBER.get() < 10) { + pull(project, localRepoFile, remoteUrl, rate); + } else if ("Github".equals(JGitUtils.getType(remoteUrl)) && JGitUtils.GITHUB_FAIL_NUMBER.get() < 5) { + pull(project, localRepoFile, remoteUrl, rate); + } + }, + () -> { + // 正在运行task -1 + FxThreadPoolTask.THREAD_DEALING_NUM.decrementAndGet(); + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + selectAll.setSelected(false); + }, () -> { + // 正在运行task -1 + FxThreadPoolTask.THREAD_DEALING_NUM.decrementAndGet(); + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + })); } - } catch (AuthException e) { - LOGGER.error("项目 {} 需要权限", remoteUrl); - } catch (TimeOutException | JGitException ignored) { - - } catch (Exception e) { - LOGGER.error("项目更新异常:{}", e.getMessage()); - } - // 更新更新数量-1 - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); - }); - updateButton.setDisable(false); - })); - event.consume(); + }, + () -> updateButton.setDisable(false), + () -> updateButton.setDisable(false)); }); // 删除 @@ -235,36 +240,6 @@ public class ManagerView extends StackPane { }); } - public static void showAuthPane(String remoteUrl, File file, GitProject project, SimpleDoubleProperty rate, Button updateButton) throws Exception { - // 弹出输入权限界面 - AuthenticationPane authPane = AuthenticationPane.getInstance(); - authPane.refreshData(remoteUrl, (username, password) -> { - GitAuthInfo authInfo = authPane.dealAuthInfo(username, password, JGitUtils.getType(remoteUrl)); - if (authInfo != null) { - // 更新 - // 更新更新数量+1 - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); - try { - CredentialsProvider provider = JGitUtils.createCredential(username, password); - boolean pull = JGitUtils.pull(remoteUrl, file, provider, rate); - if (pull) { - project.updateTime().set(DateUtils.formatDateTime(new Date())); - H2PoolUtils.updateGitProject(project); - project.selected().set(false); - } - } catch (AuthException e1) { - // 弹出输入权限界面 - Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); - } catch (TimeOutException | JGitException ignored) { - - } - // 更新更新数量-1 - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); - } - }); - Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); - } - public static void pull(GitProject project, File localRepoFile, String remoteUrl, SimpleDoubleProperty rate) { GitAuthInfo existsAuthInfo = JGitUtils.isExistsAuthInfo(project.remote()); CredentialsProvider provider = null; diff --git a/src/main/java/com/light/view/NotificationView.java b/src/main/java/com/light/view/NotificationView.java index af09622f24eaa18eed5fe732ec447cd7e1039390..7b203a037c8e7801783f1a7cf283d13b16669dd9 100644 --- a/src/main/java/com/light/view/NotificationView.java +++ b/src/main/java/com/light/view/NotificationView.java @@ -3,12 +3,13 @@ package com.light.view; import atlantafx.base.theme.Styles; import com.light.util.FxApplicationContextUtils; import javafx.collections.ListChangeListener; +import javafx.scene.layout.HBox; import javafx.scene.text.Text; public class NotificationView extends Text { public NotificationView() { super(FxApplicationContextUtils.HISTORY_NOTICE_LIST.size() + ""); getStyleClass().addAll(Styles.TEXT, Styles.WARNING); - FxApplicationContextUtils.HISTORY_NOTICE_LIST.addListener((ListChangeListener) c -> setText(FxApplicationContextUtils.HISTORY_NOTICE_LIST.size() + "")); + FxApplicationContextUtils.HISTORY_NOTICE_LIST.addListener((ListChangeListener) c -> setText(FxApplicationContextUtils.HISTORY_NOTICE_LIST.size() + "")); } } diff --git a/src/main/resources/css/menu.css b/src/main/resources/css/menu.css index f2a1ba5901ac9a45378b583def9ecf86633dc144..6eb5422b58c69fc5c434680eb77191be2aaec4f2 100644 --- a/src/main/resources/css/menu.css +++ b/src/main/resources/css/menu.css @@ -151,4 +151,9 @@ .cf-message.danger > .ikonli-font-icon { -fx-icon-color: -cf-danger-color; +} + +.payment-qrcode { + -fx-pref-width: 50px; + -fx-pref-height: 50px; } \ No newline at end of file diff --git a/src/main/resources/icons/author.png b/src/main/resources/icons/author.png new file mode 100644 index 0000000000000000000000000000000000000000..5ee94d2d0529fbd76aa26b7237da76ff33528904 Binary files /dev/null and b/src/main/resources/icons/author.png differ diff --git a/src/main/resources/icons/qrcode.jpg b/src/main/resources/icons/qrcode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6816c812f9591854379517f620bd929ae4d91168 Binary files /dev/null and b/src/main/resources/icons/qrcode.jpg differ