diff --git a/pom.xml b/pom.xml index a28c40d0180fadfe40c6165e7866693670bb254f..f8e4177c664e864f9c5875e0cbc2d82dfd9d1d20 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.light GitManagerClientFx - 1.0-SNAPSHOT + 1.0 21 diff --git a/src/main/java/com/light/GitManagerApp.java b/src/main/java/com/light/GitManagerApp.java index b341d43dda339ed59a6023e6ebd507bfa3bb260e..6a75c62aed29ae077fa1718923bcdef99200c8c5 100644 --- a/src/main/java/com/light/GitManagerApp.java +++ b/src/main/java/com/light/GitManagerApp.java @@ -58,6 +58,9 @@ public class GitManagerApp extends Application { .ifPresentOrElse(theme -> Application.setUserAgentStylesheet(theme.getUserAgentStylesheet()), () -> Application.setUserAgentStylesheet(THEME_LIST.getFirst().getUserAgentStylesheet()) ); + + // 查询所有项目数据 + H2PoolUtils.queryGitProjects(); }); } @@ -92,6 +95,7 @@ public class GitManagerApp extends Application { stage.setScene(scene); stage.show(); scene.getStylesheets().add(STYLE_SHEET); + FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("scene", scene); LOGGER.info("项目启动完成,耗时 {} ms", System.currentTimeMillis() - startTime); } diff --git a/src/main/java/com/light/component/AuthenticationPane.java b/src/main/java/com/light/component/AuthenticationPane.java index 31170934a31798adaa86eb2ae7076f7ce609e1c4..b1372b00648bd54dcbd8ba4d113ee060e80a947a 100644 --- a/src/main/java/com/light/component/AuthenticationPane.java +++ b/src/main/java/com/light/component/AuthenticationPane.java @@ -1,31 +1,53 @@ package com.light.component; import com.light.enums.Level; +import com.light.exception.AuthException; +import com.light.exception.H2Exception; +import com.light.exception.JGitException; +import com.light.exception.TimeOutException; import com.light.layout.ModalDialog; import com.light.model.GitAuthInfo; +import com.light.model.GitProject; import com.light.thread.AsyncTask; -import com.light.util.H2PoolUtils; -import com.light.util.JGitUtils; -import com.light.util.NoticeUtils; +import com.light.util.*; +import javafx.application.Platform; +import javafx.beans.property.SimpleDoubleProperty; import javafx.geometry.Insets; +import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.scene.layout.VBox; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jgit.transport.CredentialsProvider; import java.io.File; +import java.util.Date; public class AuthenticationPane extends ModalDialog { - public AuthenticationPane(String repoType, String remoteUrl, File file) { + /** + * 没有权限 + * + * @param clone + * @param index 只有克隆时使用 + * @param remoteUrl + * @param file + */ + public AuthenticationPane(boolean clone, int index, String remoteUrl, File file) { + this(clone, index, remoteUrl, file, null, null, null); + } + + public AuthenticationPane(boolean clone, int index, String remoteUrl, File file, SimpleDoubleProperty rate, GitProject project, Button updateButton) { super(); + String repoType = JGitUtils.getType(remoteUrl); header.setTitle(repoType); - content.setBody(createContent(repoType, remoteUrl, file)); + content.setBody(createContent(clone, index, repoType, remoteUrl, file, rate, project, updateButton)); content.setFooter(null); +// FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("authDialogShowing", true); } - private VBox createContent(String repoType, String remoteUrl, File file) { + private VBox createContent(boolean clone, int index, String repoType, String remoteUrl, File file, SimpleDoubleProperty rate, GitProject project, Button updateButton) { var usernameField = new TextField(); usernameField.setPromptText("手机/邮箱/用户名"); usernameField.setMaxWidth(300); @@ -45,17 +67,66 @@ public class AuthenticationPane extends ModalDialog { NoticeUtils.show(null, "用户名密码不能为空", Level.WARN); return; } - GitAuthInfo authInfo = new GitAuthInfo(0, repoType, username, username, ""); + GitAuthInfo authInfo = new GitAuthInfo(0, repoType, username, password, ""); // 入库 - int num = H2PoolUtils.insertAuthInfo(authInfo); + int num = 0; + try { + GitAuthInfo existsAuthInfo = H2PoolUtils.queryAuthInfo(repoType); + if (existsAuthInfo != null) { + // 克隆或者下载时权限异常会执行这段代码 + num = H2PoolUtils.updateAuthInfo(repoType, username, password); + } else { + num = H2PoolUtils.insertAuthInfo(authInfo); + } + } catch (H2Exception e) { + NoticeUtils.show(null, e.getMessage(), Level.WARN); + return; + } if (num > 0) { - AsyncTask.runOnce("克隆项目", () -> { - JGitUtils.AUTH_INFO_MAP.put(repoType, authInfo); - JGitUtils.cloneRepo(remoteUrl, file, authInfo); - }); + JGitUtils.AUTH_INFO_MAP.put(repoType, authInfo); + if (clone) { + if (-1 != index) { + // 克隆项目时没有权限会执行这段代码 + DownloadHBox downloadHBox = (DownloadHBox) FxApplicationContextUtils.DOWNLOAD_LIST.get(index); + downloadHBox.cloneRepo(JGitUtils.createCredential(username, password), false); + } else { + // 第一次克隆 + FxApplicationContextUtils.DOWNLOAD_LIST.add(new DownloadHBox(remoteUrl, file, authInfo, FxApplicationContextUtils.DOWNLOAD_LIST.size())); + } + } else { + // 更新 + if (null != project) { + // 更新更新数量+1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); + AsyncTask.runOnce("更新项目", () -> { + 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 e) { + // 弹出输入权限界面 + if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { + AuthenticationPane authPane = new AuthenticationPane(false, -1, remoteUrl, file, rate, project, updateButton); + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); + } + } catch (TimeOutException | JGitException e) { + + } + // 更新更新数量-1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + updateButton.setDisable(false); + }); + } + } + // 关闭界面 + close(); + FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("authDialogShowing", false); } }); - return root; } } diff --git a/src/main/java/com/light/component/CustomProgressMonitor.java b/src/main/java/com/light/component/CustomProgressMonitor.java new file mode 100644 index 0000000000000000000000000000000000000000..e403099cdda87a2cf36ca7fb3ab861359e6af8c4 --- /dev/null +++ b/src/main/java/com/light/component/CustomProgressMonitor.java @@ -0,0 +1,52 @@ +package com.light.component; + +import javafx.beans.property.SimpleDoubleProperty; +import javafx.scene.control.ProgressBar; +import org.eclipse.jgit.lib.BatchingProgressMonitor; + +import java.time.Duration; +import java.util.concurrent.atomic.AtomicInteger; + +public class CustomProgressMonitor extends BatchingProgressMonitor { + + private final ProgressBar progressBar; + + private final AtomicInteger progress; + private final AtomicInteger total; + + private final SimpleDoubleProperty rate; + + public CustomProgressMonitor(ProgressBar progressBar, SimpleDoubleProperty rate) { + this.progressBar = progressBar; + this.rate = rate; + progress = new AtomicInteger(0); + total = new AtomicInteger(100); + } + + @Override + protected void onUpdate(String taskName, int workCurr, Duration duration) { + + } + + @Override + protected void onEndTask(String taskName, int workCurr, Duration duration) { + + } + + @Override + protected void onUpdate(String taskName, int workCurr, int workTotal, int percentDone, Duration duration) { + if (progressBar != null) { + progressBar.setProgress((double) (progress.get() + percentDone) / total.get()); + } + if (null != rate) { + rate.set((double) (progress.get() + percentDone) / total.get()); + } + } + + @Override + protected void onEndTask(String taskName, int workCurr, int workTotal, int percentDone, Duration duration) { + progress.addAndGet(percentDone); + total.addAndGet(percentDone); +// System.out.println("taskName: " + taskName + " workCurr: " + workCurr + " workTotal: " + workTotal + " percentDone: " + percentDone); + } +} diff --git a/src/main/java/com/light/component/DownAndUpdatePane.java b/src/main/java/com/light/component/DownAndUpdatePane.java new file mode 100644 index 0000000000000000000000000000000000000000..54672bf47675faf3e8cdd4913be49ad84db2d71b --- /dev/null +++ b/src/main/java/com/light/component/DownAndUpdatePane.java @@ -0,0 +1,22 @@ +package com.light.component; + +import com.light.layout.ModalDialog; +import javafx.collections.ObservableList; +import javafx.scene.control.ListView; +import javafx.scene.layout.HBox; + +public class DownAndUpdatePane extends ModalDialog { + + public DownAndUpdatePane(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); + listView.getStyleClass().add("du-list"); + return new HBox(listView); + } +} diff --git a/src/main/java/com/light/component/DownloadHBox.java b/src/main/java/com/light/component/DownloadHBox.java new file mode 100644 index 0000000000000000000000000000000000000000..4d58311fcee2739c2de49f6a2be6980e32f51b81 --- /dev/null +++ b/src/main/java/com/light/component/DownloadHBox.java @@ -0,0 +1,162 @@ +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.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.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.kordamp.ikonli.bootstrapicons.BootstrapIcons; +import org.kordamp.ikonli.javafx.FontIcon; + +import java.io.File; +import java.util.Date; + +import static com.light.util.JGitUtils.getAuthor; +import static com.light.util.JGitUtils.getRepoName; + +public class DownloadHBox extends HBox { + private final String remoteUrl; + private final File localRepoFile; + private final Button retryButton; + private final ProgressBar progressBar = new ProgressBar(0.0); + private final CustomProgressMonitor customProgressMonitor = new CustomProgressMonitor(progressBar, null); + private final int index; + + private CredentialsProvider provider; + + /** + * 构造方法 + * + * @param remoteUrl 远程仓库路径 + * @param localRepoFile 本地克隆地址 + * @param authInfo 权限 + * @param index 在下载列表中的位置 + */ + public DownloadHBox(String remoteUrl, File localRepoFile, GitAuthInfo authInfo, int index) { + super(10); + setAlignment(Pos.CENTER); + + this.remoteUrl = remoteUrl; + this.localRepoFile = localRepoFile; + this.index = index; + + var label = new Label(getRepoName(remoteUrl)); + + progressBar.setMaxWidth(300); + var vbox = new VBox(10, label, progressBar); + + retryButton = new Button(null, new FontIcon(BootstrapIcons.PLAY)); + retryButton.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT, Styles.ACCENT); + retryButton.setVisible(false); + + Button removeButton = new Button(null, new FontIcon(BootstrapIcons.X)); + removeButton.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT, Styles.ACCENT); + getChildren().addAll(vbox, retryButton, removeButton); + HBox.setHgrow(vbox, Priority.ALWAYS); + + // 监控器和权限 + provider = JGitUtils.createCredential(authInfo.username(), authInfo.password()); + + retryButton.setOnMouseClicked(event -> cloneRepo(provider, true)); + removeButton.setOnMouseClicked(event -> FxApplicationContextUtils.DOWNLOAD_LIST.remove(this)); + // 更新下载数量+1 + FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.incrementAndGet())); + cloneRepo(provider, false); + } + + /** + * 克隆项目 + * + * @param provider 权限 + * @param retry 重试标识 + */ + public void cloneRepo(CredentialsProvider provider, boolean retry) { + this.provider = provider; + AsyncTask.runOnce("克隆项目", () -> { + if (retry) { + deleteFiles(localRepoFile); + retryButton.setVisible(false); + } + + String branch = ""; + try { + // 开始下载 + branch = JGitUtils.cloneRepo(remoteUrl, localRepoFile, provider, customProgressMonitor); + } catch (AuthException e) { + // 弹出输入权限界面 + if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { + AuthenticationPane authPane = new AuthenticationPane(true, index, remoteUrl, localRepoFile); + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); + } + retryButton.setVisible(true); + return; + } catch (TimeOutException | JGitException e) { + retryButton.setVisible(true); + return; + } + + // 下载完成入库 + 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())); + }); + } + + private void deleteFiles(File folder) { + if (folder.exists()) { + // 获取文件夹中的所有文件和子文件夹 + File[] files = folder.listFiles(); + + if (files != null) { + for (File file : files) { + // 如果是文件,则直接删除 + if (file.isFile()) { + file.delete(); + } + // 如果是文件夹,则递归调用deleteFiles方法删除文件夹下的文件 + else if (file.isDirectory()) { + deleteFiles(file); + } + } + } + } + } +} diff --git a/src/main/java/com/light/component/NoticePane.java b/src/main/java/com/light/component/NoticePane.java new file mode 100644 index 0000000000000000000000000000000000000000..25bfa3ae94bc81b0694951eb4495d58949abc1bb --- /dev/null +++ b/src/main/java/com/light/component/NoticePane.java @@ -0,0 +1,26 @@ +package com.light.component; + +import com.light.layout.ModalDialog; +import javafx.collections.ObservableList; +import javafx.scene.control.ListView; +import javafx.scene.layout.HBox; + +public class NoticePane extends ModalDialog { + + 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); + listView.getStyleClass().add("du-list"); + listView.setMaxWidth(800); + listView.setMinWidth(550); + 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 7b5e7fa439be0cd23cc473e95175cc1aaa32ca5f..a383e447344f354f9f5ee77c3f186b51661b73e9 100644 --- a/src/main/java/com/light/component/OperationTableCell.java +++ b/src/main/java/com/light/component/OperationTableCell.java @@ -1,15 +1,29 @@ 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.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.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 java.io.File; +import java.util.Date; /** * 操作列 - 按钮 @@ -51,11 +65,39 @@ public class OperationTableCell extends TableCell { private void initEvent() { // TODO Auto-generated method stub updateButton.setOnMouseClicked(event -> { - rate.set(0.0); - FxApplicationContextUtils.UPDATE_PROPERTY.set(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet() + ""); - for (int i = 0; i <= 100; i++) { - double dRate = (double) i / 100; - rate.set(dRate); + updateButton.setDisable(true); + GitProject project = getTableRow().getItem(); + 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 { + GitAuthInfo existsAuthInfo = JGitUtils.isExistsAuthInfo(project.remote()); + CredentialsProvider provider = null; + if (existsAuthInfo != null) { + provider = JGitUtils.createCredential(existsAuthInfo.username(), existsAuthInfo.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 e) { + // 弹出输入权限界面 + if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { + AuthenticationPane authPane = new AuthenticationPane(false, -1, remoteUrl, localRepoFile, rate, project, updateButton); + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); + } + } catch (TimeOutException | JGitException e) { + + } + // 更新更新数量-1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + updateButton.setDisable(false); + }); } }); } diff --git a/src/main/java/com/light/exception/AuthException.java b/src/main/java/com/light/exception/AuthException.java new file mode 100644 index 0000000000000000000000000000000000000000..f8365b1f35dfb0ff48b31c16f0c3e6caf2cf21df --- /dev/null +++ b/src/main/java/com/light/exception/AuthException.java @@ -0,0 +1,23 @@ +package com.light.exception; + +public class AuthException extends RuntimeException{ + public AuthException() { + super(); + } + + public AuthException(String message) { + super(message); + } + + public AuthException(String message, Throwable cause) { + super(message, cause); + } + + public AuthException(Throwable cause) { + super(cause); + } + + protected AuthException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/light/exception/CustomException.java b/src/main/java/com/light/exception/CustomException.java new file mode 100644 index 0000000000000000000000000000000000000000..4febef6388cbbfc3261a89bf9afc0dee6fd61802 --- /dev/null +++ b/src/main/java/com/light/exception/CustomException.java @@ -0,0 +1,24 @@ +package com.light.exception; + +public class CustomException extends Exception{ + + public CustomException() { + super(); + } + + public CustomException(String message) { + super(message); + } + + public CustomException(String message, Throwable cause) { + super(message, cause); + } + + public CustomException(Throwable cause) { + super(cause); + } + + protected CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/light/exception/H2Exception.java b/src/main/java/com/light/exception/H2Exception.java new file mode 100644 index 0000000000000000000000000000000000000000..72ab1ac8554519a4c30036954a453485091253d0 --- /dev/null +++ b/src/main/java/com/light/exception/H2Exception.java @@ -0,0 +1,23 @@ +package com.light.exception; + +public class H2Exception extends RuntimeException { + public H2Exception() { + super(); + } + + public H2Exception(String message) { + super(message); + } + + public H2Exception(String message, Throwable cause) { + super(message, cause); + } + + public H2Exception(Throwable cause) { + super(cause); + } + + protected H2Exception(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/light/exception/JGitException.java b/src/main/java/com/light/exception/JGitException.java new file mode 100644 index 0000000000000000000000000000000000000000..1a1d4e786eb84907c837b3e4f1f3e54978b48f91 --- /dev/null +++ b/src/main/java/com/light/exception/JGitException.java @@ -0,0 +1,23 @@ +package com.light.exception; + +public class JGitException extends RuntimeException{ + public JGitException() { + super(); + } + + public JGitException(String message) { + super(message); + } + + public JGitException(String message, Throwable cause) { + super(message, cause); + } + + public JGitException(Throwable cause) { + super(cause); + } + + protected JGitException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/light/exception/TimeOutException.java b/src/main/java/com/light/exception/TimeOutException.java new file mode 100644 index 0000000000000000000000000000000000000000..426c37b672df26e857620416f228f22e67ac5c8f --- /dev/null +++ b/src/main/java/com/light/exception/TimeOutException.java @@ -0,0 +1,23 @@ +package com.light.exception; + +public class TimeOutException extends RuntimeException{ + public TimeOutException() { + super(); + } + + public TimeOutException(String message) { + super(message); + } + + public TimeOutException(String message, Throwable cause) { + super(message, cause); + } + + public TimeOutException(Throwable cause) { + super(cause); + } + + protected TimeOutException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/light/layout/MenuPane.java b/src/main/java/com/light/layout/MenuPane.java index 512fb33152ced9c9d44fd8a6a6566cbc0ac9c2f0..0bd572fb1efbf5adb099f764320e056f9fe4d4d1 100644 --- a/src/main/java/com/light/layout/MenuPane.java +++ b/src/main/java/com/light/layout/MenuPane.java @@ -1,6 +1,8 @@ package com.light.layout; import atlantafx.base.theme.Styles; +import com.light.component.DownAndUpdatePane; +import com.light.component.NoticePane; import com.light.theme.ThemeDialog; import com.light.util.FxApplicationContextUtils; import com.light.util.FxUtil; @@ -8,6 +10,7 @@ import com.light.util.Lazy; import com.light.view.HomeView; import com.light.view.ManagerView; import com.light.view.NotificationView; +import javafx.collections.ListChangeListener; import javafx.geometry.Orientation; import javafx.geometry.Pos; import javafx.scene.control.Label; @@ -39,10 +42,10 @@ public class MenuPane extends StackPane { // 底部导航栏 private final Label downloadLabel = new Label("正在下载", new FontIcon(BootstrapIcons.ARROW_DOWN)); - private final Text downloadLabelText = new Text(FxApplicationContextUtils.DOWNLOAD_PROPERTY.getValue().toString()); + 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 Text updateLabelText = new Text(FxApplicationContextUtils.UPDATE_PROPERTY.getValue().toString()); + 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); @@ -107,5 +110,57 @@ public class MenuPane extends StackPane { ThemeDialog themeDialog = (ThemeDialog) setting.getContent().get(); themeDialog.show(getScene()); }); + + // 通知 + NoticePane noticePane = new NoticePane("消息", FxApplicationContextUtils.HISTORY_NOTICE_LIST); + notification.setOnMouseClicked(event -> { + noticePane.show(getScene()); + }); + + DownAndUpdatePane downloadPane = new DownAndUpdatePane("下载", FxApplicationContextUtils.DOWNLOAD_LIST); + downloadLabel.setOnMouseClicked(event -> { + downloadPane.show(getScene()); + }); + + /** + * 正在下载视图 + * 项目名 进度条 暂停按钮 取消按钮 + */ + /*downloadLabel.setOnMouseClicked(event -> { + //纵向布局 + VBox vBox = new VBox(10); + List hBoxList = new ArrayList<>(); + for(int i=1; i<=10; i++){ + //横向布局 + HBox hBox = new HBox(15); + hBox.setAlignment(Pos.CENTER); + hBox.getStyleClass().add("menu"); + + //项目名 + Label projectName = new Label("项目" + i); + projectName.setAlignment(Pos.CENTER_LEFT); + //进度条 + ProgressBar bar = new ProgressBar(0); + bar.setProgress(0.8); + + //暂停按钮 + Button stopBtn = new Button("暂停"); + stopBtn.setAlignment(Pos.CENTER_RIGHT); + stopBtn.setOnAction(ss -> { + if("暂停".equals(stopBtn.getText())){ + stopBtn.setText("开始"); + }else if("开始".equals(stopBtn.getText())){ + stopBtn.setText("暂停"); + } + }); + //取消按钮 + Button cannel = new Button("取消"); + cannel.setAlignment(Pos.CENTER_RIGHT); + hBox.getChildren().addAll(projectName,bar,stopBtn,cannel); + hBoxList.add(hBox); + } + vBox.getChildren().addAll(hBoxList); + contentPane.setContent(vBox); + });*/ } } diff --git a/src/main/java/com/light/model/GitProject.java b/src/main/java/com/light/model/GitProject.java index a5af28b4653a87a67f6c0d5c3ba48e9d55109288..169a15d3b2668613435545a4ffa91caed458c000 100644 --- a/src/main/java/com/light/model/GitProject.java +++ b/src/main/java/com/light/model/GitProject.java @@ -19,13 +19,4 @@ public record GitProject(SimpleIntegerProperty id, SimpleIntegerProperty level, SimpleDoubleProperty downloadRate, SimpleBooleanProperty selected) { - - public void addSelectedListener() { - downloadRate.addListener((observable, oldValue, newValue) -> { - if (newValue != null && newValue.doubleValue() >= 1.0) { - selected.set(false); - FxApplicationContextUtils.UPDATE_PROPERTY.set(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet() + ""); - } - }); - } } diff --git a/src/main/java/com/light/util/FxApplicationContextUtils.java b/src/main/java/com/light/util/FxApplicationContextUtils.java index 7afdffade5335feb48fe02d9945e0bcbe55bf798..0ff48b63a507fd9c7e17220cbd15e345e361564f 100644 --- a/src/main/java/com/light/util/FxApplicationContextUtils.java +++ b/src/main/java/com/light/util/FxApplicationContextUtils.java @@ -1,13 +1,17 @@ package com.light.util; -import atlantafx.base.theme.*; +import atlantafx.base.theme.Theme; import com.light.model.GitProject; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.scene.layout.HBox; +import javafx.scene.text.Text; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; /** @@ -15,24 +19,30 @@ import java.util.concurrent.atomic.AtomicInteger; */ public final class FxApplicationContextUtils { + /** + * 全局容器 + */ + public static final Map GLOBAL_CONTEXT_MAP = new ConcurrentHashMap<>(); + /** * 正在下载数量 */ public static final AtomicInteger DOWNLOAD_NUMBER = new AtomicInteger(0); public static final SimpleStringProperty DOWNLOAD_PROPERTY = new SimpleStringProperty(DOWNLOAD_NUMBER.toString()); + public static final ObservableList DOWNLOAD_LIST = FXCollections.observableArrayList(); + /** * 正在更新数量 */ public static final AtomicInteger UPDATE_NUMBER = new AtomicInteger(0); public static final SimpleStringProperty UPDATE_PROPERTY = new SimpleStringProperty(UPDATE_NUMBER.toString()); - /** * git项目集合 */ public static final ObservableList GIT_PROJECT_OBSERVABLE_LIST = FXCollections.observableArrayList(); /** - * 当前主题民初 + * 当前主题名称 */ public static final SimpleStringProperty CURRENT_THEME_NAME = new SimpleStringProperty(); diff --git a/src/main/java/com/light/util/H2PoolUtils.java b/src/main/java/com/light/util/H2PoolUtils.java index 2ee47914d1502a321601e4dd66a8bd08f4d93739..7f7485ebd1659cbc99b3ad78464bc531e75b8b3e 100644 --- a/src/main/java/com/light/util/H2PoolUtils.java +++ b/src/main/java/com/light/util/H2PoolUtils.java @@ -1,5 +1,6 @@ package com.light.util; +import com.light.exception.H2Exception; import com.light.model.GitAuthInfo; import com.light.model.GitNotice; import com.light.model.GitProject; @@ -98,6 +99,7 @@ public class H2PoolUtils { stmt.executeUpdate("drop table git_project_info if exists"); stmt.executeUpdate("drop table git_project_dict if exists"); stmt.executeUpdate("drop table git_project_notice_history if exists"); + stmt.executeUpdate("drop table git_auth_info if exists"); // 初始化项目信息表 String createGitProjectInfoTable = """ create table git_project_info @@ -202,7 +204,7 @@ public class H2PoolUtils { return list; } - public static int insertAuthInfo(GitAuthInfo authInfo) { + public static int insertAuthInfo(GitAuthInfo authInfo) throws H2Exception { try (Connection conn = getConnection()) { String sql = "INSERT INTO git_auth_info(type, username, password, createtime) values(?,?,?,?)"; PreparedStatement statement = conn.prepareStatement(sql); @@ -213,11 +215,11 @@ public class H2PoolUtils { return statement.executeUpdate(); } catch (SQLException e) { LOGGER.error("记录权限信息异常:{}", e.getMessage()); + throw new H2Exception("记录权限信息异常"); } - return 0; } - public static int updateAuthInfo(String type, String username, String password) { + public static int updateAuthInfo(String type, String username, String password) throws H2Exception { try (Connection conn = getConnection()) { String sql = "update git_auth_info set username = ?, password = ? where type = ?"; PreparedStatement statement = conn.prepareStatement(sql); @@ -227,8 +229,8 @@ public class H2PoolUtils { return statement.executeUpdate(); } catch (SQLException e) { LOGGER.error("通过 {} 更新权限信息为 {} 失败:{}", type, username, e.getMessage()); + throw new H2Exception("更新权限信息异常"); } - return 0; } public static int deleteAuthInfo(String type) { @@ -252,12 +254,19 @@ public class H2PoolUtils { Date currentDate = new Date(); Connection conn = getConnection(); Statement stmt = conn.createStatement(); + String dateTime = DateUtils.formatDateTime(currentDate); String sql = "insert into git_project_dict(label, label_value, description, createtime, updatetime) values('GIT_DB_INIT','1','项目数据库初始化标识:0 未初始化,1 初始化', " + - "'" + DateUtils.formatDateTime(currentDate) + "', '" + DateUtils.formatDateTime(currentDate) + "')"; + "'" + dateTime + "', '" + dateTime + "')"; stmt.addBatch(sql); String sql2 = "insert into git_project_dict(label, label_value, description, createtime, updatetime) values('GIT_CURRENT_THEME','Primer Light','项目当前主题', " + - "'" + DateUtils.formatDateTime(currentDate) + "', '" + DateUtils.formatDateTime(currentDate) + "')"; + "'" + dateTime + "', '" + dateTime + "')"; stmt.addBatch(sql2); + String sql3 = "insert into git_project_dict(label, label_value, description, createtime, updatetime) values('GIT_CURRENT_CLONE_DIR','D:','项目克隆路径', " + + "'" + dateTime + "', '" + dateTime + "')"; + stmt.addBatch(sql3); + String sql4 = "insert into git_project_dict(label, label_value, description, createtime, updatetime) values('GIT_CURRENT_LOCAL_DIR','D:','本地项目路径', " + + "'" + dateTime + "', '" + dateTime + "')"; + stmt.addBatch(sql4); stmt.executeBatch(); LOGGER.info("h2 字典表数据初始化成功"); } @@ -286,8 +295,8 @@ public class H2PoolUtils { statement.setString(1, value); statement.setString(2, label); statement.executeUpdate(); - } catch (SQLException ignored) { - LOGGER.error("通过 {} 更新数据为 {} 失败:{}", label, value, ignored.getMessage()); + } catch (SQLException e) { + LOGGER.error("通过 {} 更新数据为 {} 失败:{}", label, value, e.getMessage()); } LOGGER.info("通过 {} 更新数据为 {} 成功", label, value); } @@ -383,7 +392,6 @@ public class H2PoolUtils { new SimpleDoubleProperty(0.0), new SimpleBooleanProperty(false) ); - gitProject.addSelectedListener(); FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.add(gitProject); } } catch (SQLException e) { diff --git a/src/main/java/com/light/util/JGitUtils.java b/src/main/java/com/light/util/JGitUtils.java index 10fdc1456953c28367494b3ba1f6914aef0cee72..8bd8502577d7a097e17d7dfc0a7f082ea65c0572 100644 --- a/src/main/java/com/light/util/JGitUtils.java +++ b/src/main/java/com/light/util/JGitUtils.java @@ -1,5 +1,9 @@ package com.light.util; +import com.light.component.CustomProgressMonitor; +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 javafx.beans.property.SimpleBooleanProperty; @@ -7,14 +11,14 @@ import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.PullCommand; +import org.eclipse.jgit.api.PullResult; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.IOException; import java.util.*; public class JGitUtils { @@ -84,7 +88,7 @@ public class JGitUtils { */ public static String getAuthor(String remoteUrl) { String author = remoteUrl.substring(0, remoteUrl.lastIndexOf("/")); - return author = author.substring(author.lastIndexOf("/") + 1); + return author.substring(author.lastIndexOf("/") + 1); } /** @@ -159,7 +163,6 @@ public class JGitUtils { newProject = null; } else { // 不存在则继续新增,并设置id - newProject.addSelectedListener(); H2PoolUtils.insertProjectInfo(newProject); FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.add(newProject); } @@ -172,69 +175,47 @@ public class JGitUtils { PROJECT_FILE.clear(); } - public static void cloneRepo(String remoteUrl, File localRepoFile, GitAuthInfo authInfo) { - // 更新下载数量 - FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.incrementAndGet())); - - String name = getRepoName(remoteUrl); - String author = getAuthor(remoteUrl); - String local = localRepoFile.getAbsolutePath(); - + public static String cloneRepo(String remoteUrl, File localRepoFile, CredentialsProvider provider, CustomProgressMonitor monitor) throws JGitException, AuthException, TimeOutException { try (Git git = Git.cloneRepository() - .setCredentialsProvider(createCredential(authInfo.username(), authInfo.password())) - .setURI(remoteUrl).setDirectory(localRepoFile).call()) { - String branch = git.getRepository().getBranch(); - 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) - ); - newProject.addSelectedListener(); - H2PoolUtils.insertProjectInfo(newProject); - FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.add(newProject); + .setCredentialsProvider(provider) + .setURI(remoteUrl).setDirectory(localRepoFile).setProgressMonitor(monitor).call()) { + return git.getRepository().getBranch(); } catch (Exception e) { - LOGGER.error("项目 {},作者 {} 克隆失败:{}", name, author, e.getMessage()); + String message = e.getMessage(); + LOGGER.error("项目 {} 克隆异常:{}", remoteUrl, message); + if (message.contains("authorized") || message.contains("Authentication")) { + // 权限异常 + throw new AuthException(); + } else if (message.contains("time out") || message.contains("timeout")) { + // 超时异常 + throw new TimeOutException(); + } + throw new JGitException(); } - FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.decrementAndGet())); } - /*private static void pull(String localDirPath, String remoteUrl) { - Git git = null; - try { - System.out.println("remoteUrl: " + remoteUrl + " --- localPath: " + localDirPath + " --- 开始拉取数据"); - File localPath = new File(localDirPath); - git = Git.open(localPath); + public static boolean pull(String remoteUrl, File localRepoFile, CredentialsProvider provider, SimpleDoubleProperty rate) throws JGitException, AuthException, TimeOutException { + try (Git git = Git.open(localRepoFile)) { PullCommand pullCommand = git.pull(); - pullCommand.setTimeout(5); - pullCommand.setCredentialsProvider(usernamePasswordCredentialsProvider); - PullResult call = pullCommand.call(); - if (call.isSuccessful()) { - System.out.println("remoteUrl: " + remoteUrl + " --- localPath: " + localDirPath + " --- 拉取成功 --- 合并数据: " + call.getMergeResult()); + pullCommand.setTimeout(10); + if (provider != null) { + pullCommand.setCredentialsProvider(provider); } - } catch (IOException e) { - githubMaxNum++; - System.out.println("IO pull : " + e.getMessage()); - } catch (GitAPIException e) { - githubMaxNum++; - System.out.println("Git pull : " + e.getMessage()); - } finally { - if (Objects.nonNull(git)) { - git.close(); + pullCommand.setProgressMonitor(new CustomProgressMonitor(null, rate)); + PullResult call = pullCommand.call(); + return call.isSuccessful(); + } catch (Exception e) { + String message = e.getMessage(); + LOGGER.error("项目 {} 更新异常:{}", remoteUrl, message); + FxApplicationContextUtils.HISTORY_NOTICE_LIST.add(e.getMessage()); + if (message.contains("authorized") || message.contains("Authentication")) { + // 权限异常 + throw new AuthException(); + } else if (message.contains("time out") || message.contains("timeout")) { + // 超时异常 + throw new TimeOutException(); } + throw new JGitException(); } - }*/ - - private static String getRemoteUrl(File localPath) throws IOException, GitAPIException { - Git git = Git.open(localPath); - return git.remoteList().call().get(0).getURIs().get(0).toString(); } } diff --git a/src/main/java/com/light/view/HomeView.java b/src/main/java/com/light/view/HomeView.java index 8ac4400f68783e741bfdb0a96d8249b5a76b21f4..8e620893a31960e96c247d1f857eeba50c5322ec 100644 --- a/src/main/java/com/light/view/HomeView.java +++ b/src/main/java/com/light/view/HomeView.java @@ -2,9 +2,10 @@ package com.light.view; import atlantafx.base.controls.CustomTextField; import com.light.component.AuthenticationPane; +import com.light.component.DownloadHBox; import com.light.enums.Level; import com.light.model.GitAuthInfo; -import com.light.thread.AsyncTask; +import com.light.util.FxApplicationContextUtils; import com.light.util.H2PoolUtils; import com.light.util.JGitUtils; import javafx.beans.property.SimpleStringProperty; @@ -21,14 +22,13 @@ import org.kordamp.ikonli.javafx.FontIcon; import java.io.File; import static com.light.util.NoticeUtils.show; -import static com.light.view.ManagerView.INIT_DIR; public class HomeView extends BorderPane { private final DirectoryChooser dirChooser = new DirectoryChooser(); private final SimpleStringProperty targetFolderPath = new SimpleStringProperty(); - private final TextField downloadPath = new TextField(); - private final CustomTextField targetPath = new CustomTextField(targetFolderPath.get()); + private final TextField clonePathField = new TextField(); + private final CustomTextField targetPathField = new CustomTextField(targetFolderPath.get()); private final FontIcon right = new FontIcon(AntDesignIconsOutlined.FOLDER); private final Button downloadButton = new Button("下载"); @@ -37,30 +37,31 @@ public class HomeView extends BorderPane { VBox downloadVBox = new VBox(10); downloadVBox.setAlignment(Pos.CENTER); // 下载框 - downloadPath.setPromptText("请输入远程项目地址"); - downloadPath.setMaxWidth(600); + clonePathField.setPromptText("请输入远程项目地址"); + clonePathField.setMaxWidth(600); // 目的地框 - targetPath.setPromptText("请输入本地仓库地址"); - targetPath.setRight(right); - targetPath.setMaxWidth(600); + targetPathField.setPromptText("请输入本地仓库地址"); + targetPathField.setRight(right); + targetPathField.setMaxWidth(600); // 下载按钮 downloadButton.setDisable(true); - downloadVBox.getChildren().addAll(downloadPath, targetPath, downloadButton); + downloadVBox.getChildren().addAll(clonePathField, targetPathField, downloadButton); this.setCenter(downloadVBox); initEvent(); + FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("authDialogShowing", false); } private void initEvent() { downloadButton.setOnAction(btn -> { try { - String remoteUrl = downloadPath.getText(); - String localRepoFile = targetPath.getText(); + String remoteUrl = clonePathField.getText(); + String localRepoFile = targetPathField.getText(); if (StringUtils.isAnyBlank(remoteUrl, localRepoFile)) { show(null, "请检查项目地址和仓库地址不能为空", Level.WARN); } else { // 检查仓库地址是不是为空 - File file = new File(targetPath.getText()); + File file = new File(targetPathField.getText()); if (file.isFile() || (file.isDirectory() && file.listFiles().length > 0)) { show(null, "仓库地址不为空", Level.WARN); return; @@ -70,21 +71,18 @@ public class HomeView extends BorderPane { show(null, "项目已经存在", Level.WARN); return; } - // 项目保存地址不存在则创建 - boolean newFolder = file.exists(); - if (!newFolder) { - newFolder = file.mkdirs(); - } - if (newFolder) { - // 判断权限信息是否存在 - GitAuthInfo authInfo = JGitUtils.isExistsAuthInfo(remoteUrl); - if (authInfo != null) { - AsyncTask.runOnce("克隆项目", () -> JGitUtils.cloneRepo(remoteUrl, file, authInfo)); - } else { - AuthenticationPane authPane = new AuthenticationPane(JGitUtils.getType(remoteUrl), remoteUrl, file); - authPane.show(getScene()); - } + // 判断权限信息是否存在 + GitAuthInfo authInfo = JGitUtils.isExistsAuthInfo(remoteUrl); + if (authInfo != null) { + FxApplicationContextUtils.DOWNLOAD_LIST.add(new DownloadHBox(remoteUrl, file, authInfo, FxApplicationContextUtils.DOWNLOAD_LIST.size())); + } else { + AuthenticationPane authPane = new AuthenticationPane(true, -1, remoteUrl, file); + authPane.show(getScene()); } + // 清空信息 + clonePathField.setText(""); + targetPathField.setText(""); + downloadButton.setDisable(true); } } catch (Exception e) { show(null, "下载失败,请稍后重试", Level.DANGER); @@ -92,27 +90,40 @@ public class HomeView extends BorderPane { }); right.setOnMouseClicked(event -> { - dirChooser.setInitialDirectory(new File(INIT_DIR + File.separator)); + dirChooser.setInitialDirectory(new File(H2PoolUtils.queryDictByLabel("GIT_CURRENT_CLONE_DIR", "D:") + File.separator)); File file = dirChooser.showDialog(getScene().getWindow()); if (null != file) { - targetPath.setText(file.getPath()); targetFolderPath.set(file.getPath()); + H2PoolUtils.updateDictData("GIT_CURRENT_CLONE_DIR", file.getPath()); + + String downloadPathText = clonePathField.getText(); + if (StringUtils.isNotBlank(downloadPathText)) { + if (downloadPathText.contains("/") && !downloadPathText.startsWith("/")) { + String downloadPathFolder = downloadPathText.substring(downloadPathText.lastIndexOf("/") + 1); + String actPath = downloadPathFolder.endsWith(".git") ? downloadPathFolder.substring(0, downloadPathFolder.lastIndexOf(".")) : downloadPathFolder; + targetPathField.setText(file.getPath() + File.separator + actPath); + } else { + targetPathField.setText(file.getPath()); + } + } else { + targetPathField.setText(file.getPath()); + } } event.consume(); }); - downloadPath.setOnKeyReleased(event -> { + clonePathField.setOnKeyReleased(event -> { String targetPathText = StringUtils.isBlank(targetFolderPath.get()) ? "" : targetFolderPath.get() + File.separator; - String downloadPathText = downloadPath.getText(); + String downloadPathText = clonePathField.getText(); if (downloadPathText.contains("/") && !downloadPathText.startsWith("/")) { String downloadPathFolder = downloadPathText.substring(downloadPathText.lastIndexOf("/") + 1); String actPath = downloadPathFolder.endsWith(".git") ? downloadPathFolder.substring(0, downloadPathFolder.lastIndexOf(".")) : downloadPathFolder; if (StringUtils.isNotBlank(targetPathText)) { - targetPath.setText(targetPathText + actPath); + targetPathField.setText(targetPathText + actPath); } downloadButton.setDisable(!downloadPathText.endsWith(".git")); } else { - targetPath.setText(targetPathText); + targetPathField.setText(targetPathText); downloadButton.setDisable(true); } }); diff --git a/src/main/java/com/light/view/ManagerView.java b/src/main/java/com/light/view/ManagerView.java index b81404ef74473840ea24e027e24d4f93e797024c..2ac8bc01f1687d783cd810a4a8d1a885a53eaa0f 100644 --- a/src/main/java/com/light/view/ManagerView.java +++ b/src/main/java/com/light/view/ManagerView.java @@ -3,16 +3,25 @@ package com.light.view; import atlantafx.base.controls.CustomTextField; import atlantafx.base.theme.Styles; import atlantafx.base.theme.Tweaks; +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.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; @@ -25,10 +34,12 @@ import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.stage.DirectoryChooser; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jgit.transport.CredentialsProvider; import org.kordamp.ikonli.bootstrapicons.BootstrapIcons; import org.kordamp.ikonli.javafx.FontIcon; import java.io.File; +import java.util.Date; import java.util.List; public class ManagerView extends StackPane { @@ -37,7 +48,6 @@ public class ManagerView extends StackPane { private CustomTextField searchField; private final Button updateButton = new Button("更新"); private final Button addLocalButton = new Button("添加本地项目"); - public static final String INIT_DIR = "D:"; private final DirectoryChooser dirChooser = new DirectoryChooser(); private final HBox hBox = new HBox(5); @@ -52,8 +62,6 @@ public class ManagerView extends StackPane { this.getChildren().add(vBox); initialize(); initEvent(); - // 异步初始化数据 - AsyncTask.runOnce("初始化项目数据", this::initData); } public void initialize() { @@ -127,11 +135,6 @@ public class ManagerView extends StackPane { tableView.setEditable(true); } - public void initData() { - // 查H2数据库获取数据 - H2PoolUtils.queryGitProjects(); - } - public void initEvent() { // 全选按钮事件 selectAll.setOnAction(event -> { @@ -141,13 +144,13 @@ public class ManagerView extends StackPane { event.consume(); }); - /** + /* * 添加本地项目按钮事件 * 输入框 让用户键入代码存放路径 * 按钮 加载 */ addLocalButton.setOnAction(btn -> { - dirChooser.setInitialDirectory(new File(INIT_DIR + File.separator)); + dirChooser.setInitialDirectory(new File(H2PoolUtils.queryDictByLabel("GIT_CURRENT_LOCAL_DIR", "D:") + File.separator)); File file = dirChooser.showDialog(getScene().getWindow()); if (null != file) { AsyncTask.runOnce("加载本地项目", () -> { @@ -180,14 +183,40 @@ public class ManagerView extends StackPane { List list = tableView.getItems().stream().filter(param -> param.selected().get()).toList(); if (!list.isEmpty()) { updateButton.setDisable(true); - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.addAndGet(list.size()))); } list.forEach(param -> { - param.downloadRate().set(0.0); - for (int i = 0; i <= 100; i++) { - double dRate = (double) i / 100; - param.downloadRate().set(dRate); - } + SimpleDoubleProperty rate = param.downloadRate(); + rate.set(0.0); + // 更新更新数量+1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); + AsyncTask.runOnce("更新项目", () -> { + File localRepoFile = new File(param.local().get()); + String remoteUrl = param.remote(); + try { + GitAuthInfo existsAuthInfo = JGitUtils.isExistsAuthInfo(param.remote()); + CredentialsProvider provider = null; + if (existsAuthInfo != null) { + provider = JGitUtils.createCredential(existsAuthInfo.username(), existsAuthInfo.password()); + } + boolean pull = JGitUtils.pull(remoteUrl, localRepoFile, provider, rate); + if (pull) { + param.updateTime().set(DateUtils.formatDateTime(new Date())); + H2PoolUtils.updateGitProject(param); + param.selected().set(false); + } + } catch (AuthException e) { + // 弹出输入权限界面 + if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { + AuthenticationPane authPane = new AuthenticationPane(false, -1, remoteUrl, localRepoFile, rate, param, updateButton); + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); + } + } catch (TimeOutException | JGitException e) { + + } + // 更新更新数量-1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + updateButton.setDisable(false); + }); }); }); } diff --git a/src/main/java/com/light/view/NotificationView.java b/src/main/java/com/light/view/NotificationView.java index a7870d4ee9ed89c8fdb40e816f533f21d759fa3c..af09622f24eaa18eed5fe732ec447cd7e1039390 100644 --- a/src/main/java/com/light/view/NotificationView.java +++ b/src/main/java/com/light/view/NotificationView.java @@ -1,13 +1,14 @@ package com.light.view; +import atlantafx.base.theme.Styles; import com.light.util.FxApplicationContextUtils; import javafx.collections.ListChangeListener; -import javafx.scene.control.Label; +import javafx.scene.text.Text; -public class NotificationView extends Label { +public class NotificationView extends Text { public NotificationView() { super(FxApplicationContextUtils.HISTORY_NOTICE_LIST.size() + ""); - this.getStyleClass().add("notice-label"); + getStyleClass().addAll(Styles.TEXT, Styles.WARNING); 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 fca6ccaf4e3c09f643103fe624e3c06f2b3a476a..f2a1ba5901ac9a45378b583def9ecf86633dc144 100644 --- a/src/main/resources/css/menu.css +++ b/src/main/resources/css/menu.css @@ -53,7 +53,7 @@ -fx-icon-color: -cf-primary-color; } -/*动态导航栏*/ +/*动态菜单导航栏*/ .menu { -fx-background-insets: 0px; -fx-background-color: transparent; diff --git a/src/main/resources/css/root.css b/src/main/resources/css/root.css index 1e94ac24f857a8aa3643fff6bb68da02ece271f4..b2b9a7998113878ef78777db2b36750a5f43bd04 100644 --- a/src/main/resources/css/root.css +++ b/src/main/resources/css/root.css @@ -51,4 +51,19 @@ .theme-thumbnail > .label { -fx-underline: true; +} + +.du-list { + -fx-background-insets: 0px; + -fx-background-color: transparent; + -fx-padding: 0 0 5px 0; + -fx-border-width: 0; +} + +.du-list .scroll-bar { + -fx-opacity: 0; +} + +.du-list:hover .scroll-bar { + -fx-opacity: 1; } \ No newline at end of file