mirror of
https://github.com/octopusYan/alist-gui.git
synced 2024-11-22 03:56:42 +08:00
feat: 语言切换支持、布局重写、配置读取切换为jackson-yaml
This commit is contained in:
parent
7599524df1
commit
fecdee3664
7
config/gui.yaml
Normal file
7
config/gui.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
autoStart: false
|
||||
silentStartup: false
|
||||
proxyInfo: {}
|
||||
proxySetup: "no_proxy"
|
||||
language: "zh"
|
||||
aListVersion: "unknown"
|
61
pom.xml
61
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>cn.octopusyan</groupId>
|
||||
<artifactId>alist-gui</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<version>0.1</version>
|
||||
<name>alist-gui</name>
|
||||
|
||||
<organization>
|
||||
@ -15,7 +15,7 @@
|
||||
</organization>
|
||||
|
||||
<inceptionYear>2024</inceptionYear>
|
||||
<description>alist windows gui</description>
|
||||
<description>AList windows gui</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
@ -28,11 +28,13 @@
|
||||
<javafx.version>17.0.6</javafx.version>
|
||||
<slf4j.version>2.0.16</slf4j.version>
|
||||
<logback.version>1.4.14</logback.version>
|
||||
<fastjson.version>2.0.52</fastjson.version>
|
||||
<hutool.version>5.8.25</hutool.version>
|
||||
<hutool.version>5.8.32</hutool.version>
|
||||
<common-lang3.version>3.16.0</common-lang3.version>
|
||||
<common-io.version>2.16.1</common-io.version>
|
||||
<!-- <common-io.version>2.16.1</common-io.version>-->
|
||||
<common-exec.version>1.4.0</common-exec.version>
|
||||
<lombok.version>1.18.32</lombok.version>
|
||||
<ikonli.version>12.3.1</ikonli.version>
|
||||
<gluonhq-emoji.version>1.0.1</gluonhq-emoji.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -48,6 +50,13 @@
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.mkpaz</groupId>
|
||||
<artifactId>atlantafx-base</artifactId>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- slf4j -->
|
||||
<!-- https://slf4j.org/manual.html -->
|
||||
<dependency>
|
||||
@ -87,12 +96,6 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${common-lang3.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${common-io.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-exec -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@ -100,24 +103,45 @@
|
||||
<version>${common-exec.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON -->
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
|
||||
<!-- hutool -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
<version>2.15.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.kordamp.ikonli/ikonli-javafx -->
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-javafx</artifactId>
|
||||
<version>12.3.1</version>
|
||||
<version>${ikonli.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-fontawesome-pack</artifactId>
|
||||
<version>${ikonli.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-coreui-pack</artifactId>
|
||||
<version>12.3.1</version>
|
||||
<version>${ikonli.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.gluonhq</groupId>
|
||||
<artifactId>emoji</artifactId>
|
||||
<version>${gluonhq-emoji.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
@ -164,6 +188,7 @@
|
||||
<nonFilteredFileExtensions>
|
||||
<nonFilteredFileExtension>exe</nonFilteredFileExtension>
|
||||
<nonFilteredFileExtension>dll</nonFilteredFileExtension>
|
||||
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
|
||||
</nonFilteredFileExtensions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
@ -1,79 +1,82 @@
|
||||
package cn.octopusyan.alistgui;
|
||||
|
||||
import atlantafx.base.theme.PrimerLight;
|
||||
import cn.octopusyan.alistgui.config.AppConstant;
|
||||
import cn.octopusyan.alistgui.config.CustomConfig;
|
||||
import cn.octopusyan.alistgui.controller.MainController;
|
||||
import cn.octopusyan.alistgui.config.ConfigManager;
|
||||
import cn.octopusyan.alistgui.config.Context;
|
||||
import cn.octopusyan.alistgui.enums.ProxySetup;
|
||||
import cn.octopusyan.alistgui.manager.http.HttpConfig;
|
||||
import cn.octopusyan.alistgui.manager.http.HttpUtil;
|
||||
import cn.octopusyan.alistgui.manager.thread.ThreadPoolManager;
|
||||
import cn.octopusyan.alistgui.util.AlertUtil;
|
||||
import cn.octopusyan.alistgui.util.FxmlUtil;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.StageStyle;
|
||||
import lombok.Getter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProxySelector;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Application extends javafx.application.Application {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Application.class);
|
||||
@Getter
|
||||
private static Stage primaryStage;
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
logger.info("application init ...");
|
||||
// 初始化客户端配置
|
||||
CustomConfig.init();
|
||||
ConfigManager.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException {
|
||||
Application.primaryStage = primaryStage;
|
||||
|
||||
logger.info("application start ...");
|
||||
|
||||
// 初始化弹窗工具
|
||||
AlertUtil.initOwner(primaryStage);
|
||||
|
||||
// http请求工具初始化
|
||||
HttpConfig httpConfig = new HttpConfig();
|
||||
if (CustomConfig.hasProxy()) {
|
||||
InetSocketAddress unresolved = InetSocketAddress.createUnresolved(CustomConfig.proxyHost(), CustomConfig.proxyPort());
|
||||
httpConfig.setProxySelector(ProxySelector.of(unresolved));
|
||||
}
|
||||
httpConfig.setConnectTimeout(10);
|
||||
HttpUtil.init(httpConfig);
|
||||
|
||||
// 全局异常处理
|
||||
Thread.setDefaultUncaughtExceptionHandler(this::showErrorDialog);
|
||||
Thread.currentThread().setUncaughtExceptionHandler(this::showErrorDialog);
|
||||
|
||||
// http请求工具初始化
|
||||
HttpConfig httpConfig = new HttpConfig();
|
||||
|
||||
if(!ProxySetup.NO_PROXY.equals(ConfigManager.proxySetup())) {
|
||||
// 系统代理
|
||||
if (ProxySetup.SYSTEM.equals(ConfigManager.proxySetup())) {
|
||||
httpConfig.setProxySelector(ProxySelector.getDefault());
|
||||
}
|
||||
// 自定义代理
|
||||
if (ProxySetup.MANUAL.equals(ConfigManager.proxySetup()) && ConfigManager.hasProxy()) {
|
||||
InetSocketAddress unresolved = InetSocketAddress.createUnresolved(ConfigManager.proxyHost(), ConfigManager.getProxyPort());
|
||||
httpConfig.setProxySelector(ProxySelector.of(unresolved));
|
||||
}
|
||||
}
|
||||
|
||||
httpConfig.setConnectTimeout(10);
|
||||
HttpUtil.init(httpConfig);
|
||||
|
||||
// i18n
|
||||
Context.setLanguage(ConfigManager.language());
|
||||
|
||||
// 主题样式
|
||||
Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet());
|
||||
|
||||
// 启动主界面
|
||||
try {
|
||||
FXMLLoader loader = FxmlUtil.load("root-view");
|
||||
loader.setControllerFactory(c -> new MainController(primaryStage));
|
||||
Parent root = loader.load();//底层面板
|
||||
|
||||
Scene scene = new Scene(root);
|
||||
scene.getStylesheets().addAll(Objects.requireNonNull(getClass().getResource("/css/root.css")).toExternalForm());
|
||||
scene.setFill(Color.TRANSPARENT);
|
||||
|
||||
Scene scene = Context.initScene();
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.initStyle(StageStyle.TRANSPARENT);
|
||||
primaryStage.setTitle(String.format("%s v%s", AppConstant.APP_TITLE, AppConstant.APP_VERSION));
|
||||
primaryStage.show();
|
||||
|
||||
MainController controller = loader.getController();
|
||||
controller.setApplication(this);
|
||||
} catch (Throwable t) {
|
||||
showErrorDialog(Thread.currentThread(), t);
|
||||
}
|
||||
|
||||
logger.info("application start over ...");
|
||||
}
|
||||
|
||||
@ -85,9 +88,12 @@ public class Application extends javafx.application.Application {
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
logger.info("application stop ...");
|
||||
// 保存应用数据
|
||||
ConfigManager.save();
|
||||
// 停止所有线程
|
||||
ThreadPoolManager.getInstance().shutdown();
|
||||
// 保存应用数据
|
||||
CustomConfig.store();
|
||||
// 关闭主界面
|
||||
Platform.exit();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
@ -1,26 +1,16 @@
|
||||
package cn.octopusyan.alistgui.base;
|
||||
|
||||
import cn.octopusyan.alistgui.config.AppConstant;
|
||||
import cn.octopusyan.alistgui.Application;
|
||||
import cn.octopusyan.alistgui.config.Context;
|
||||
import cn.octopusyan.alistgui.util.FxmlUtil;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
@ -30,58 +20,14 @@ import java.util.ResourceBundle;
|
||||
*/
|
||||
public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private Application application;
|
||||
private final Stage primaryStage;
|
||||
|
||||
private double xOffSet = 0, yOffSet = 0;
|
||||
|
||||
protected BaseController(Stage primaryStage) {
|
||||
this.primaryStage = primaryStage;
|
||||
}
|
||||
|
||||
public void jumpTo(BaseController<P> controller) throws IOException {
|
||||
FXMLLoader fxmlLoader = FxmlUtil.load(controller.getRootFxml());
|
||||
|
||||
Scene scene = getRootPanel().getScene();
|
||||
double oldHeight = getRootPanel().getPrefHeight();
|
||||
double oldWidth = getRootPanel().getPrefWidth();
|
||||
|
||||
Pane root = fxmlLoader.load();
|
||||
Stage stage = (Stage) scene.getWindow();
|
||||
// 窗口大小
|
||||
double newWidth = root.getPrefWidth();
|
||||
double newHeight = root.getPrefHeight();
|
||||
// 窗口位置
|
||||
double newX = stage.getX() - (newWidth - oldWidth) / 2;
|
||||
double newY = stage.getY() - (newHeight - oldHeight) / 2;
|
||||
scene.setRoot(root);
|
||||
stage.setX(newX < 0 ? 0 : newX);
|
||||
stage.setY(newY < 0 ? 0 : newY);
|
||||
stage.setWidth(newWidth);
|
||||
stage.setHeight(newHeight);
|
||||
|
||||
controller = fxmlLoader.getController();
|
||||
controller.setApplication(getApplication());
|
||||
}
|
||||
|
||||
protected void open(Class<? extends BaseController<?>> clazz, String title) {
|
||||
try {
|
||||
FXMLLoader load = FxmlUtil.load(clazz.getDeclaredConstructor().newInstance().getRootFxml());
|
||||
Parent root = load.load();
|
||||
Scene scene = new Scene(root);
|
||||
scene.getStylesheets().addAll(Objects.requireNonNull(getClass().getResource("/css/root.css")).toExternalForm());
|
||||
Stage stage = new Stage();
|
||||
stage.setScene(scene);
|
||||
stage.setTitle(title);
|
||||
stage.initOwner(getWindow());
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.show();
|
||||
load.getController();
|
||||
} catch (Exception e) {
|
||||
logger.error("", e);
|
||||
}
|
||||
public BaseController() {
|
||||
//初始化时保存当前Controller实例
|
||||
Context.getControllers().put(this.getClass().getSimpleName(), this);
|
||||
}
|
||||
|
||||
@FXML
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
// 全局窗口拖拽
|
||||
@ -92,23 +38,11 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
yOffSet = event.getSceneY();
|
||||
});
|
||||
getRootPanel().setOnMouseDragged(event -> {
|
||||
Stage stage = (Stage) getWindow();
|
||||
stage.setX(event.getScreenX() - xOffSet);
|
||||
stage.setY(event.getScreenY() - yOffSet);
|
||||
getWindow().setX(event.getScreenX() - xOffSet);
|
||||
getWindow().setY(event.getScreenY() - yOffSet);
|
||||
});
|
||||
}
|
||||
|
||||
// 窗口初始化完成监听
|
||||
getRootPanel().sceneProperty().addListener((observable, oldValue, newValue) -> {
|
||||
newValue.windowProperty().addListener(new ChangeListener<Window>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Window> observable, Window oldValue, Window newValue) {
|
||||
//关闭窗口监听
|
||||
getWindow().setOnCloseRequest(windowEvent -> onDestroy());
|
||||
|
||||
// app 版本信息
|
||||
if (getAppVersionLabel() != null) getAppVersionLabel().setText("v" + AppConstant.APP_VERSION);
|
||||
|
||||
// 初始化数据
|
||||
initData();
|
||||
|
||||
@ -118,28 +52,15 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
// 初始化视图事件
|
||||
initViewAction();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void setApplication(Application application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
public Application getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
public Stage getPrimaryStage() {
|
||||
return primaryStage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 窗口拖拽设置
|
||||
*
|
||||
* @return 是否启用
|
||||
*/
|
||||
public abstract boolean dragWindow();
|
||||
public boolean dragWindow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取根布局
|
||||
@ -150,25 +71,17 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
|
||||
/**
|
||||
* 获取根布局
|
||||
* <p> 搭配 <code>FxmlUtil.load</code> 使用
|
||||
* <p> 搭配 {@link FxmlUtil#load(String)} 使用
|
||||
*
|
||||
* @return 根布局对象
|
||||
* @see FxmlUtil#load(String)
|
||||
*/
|
||||
protected String getRootFxml() {
|
||||
System.out.println(getClass().getSimpleName());
|
||||
return "";
|
||||
}
|
||||
|
||||
protected Window getWindow() {
|
||||
return getRootPanel().getScene().getWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* App版本信息标签
|
||||
*/
|
||||
public Label getAppVersionLabel() {
|
||||
return null;
|
||||
protected Stage getWindow() {
|
||||
return Application.getPrimaryStage();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,19 +98,4 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
* 视图事件
|
||||
*/
|
||||
public abstract void initViewAction();
|
||||
|
||||
/**
|
||||
* 关闭窗口
|
||||
*/
|
||||
public void onDestroy() {
|
||||
Stage stage = (Stage) getWindow();
|
||||
stage.hide();
|
||||
stage.close();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
Platform.exit();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package cn.octopusyan.alistgui.config;
|
||||
|
||||
import cn.octopusyan.alistgui.util.PropertiesUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* 应用信息
|
||||
@ -14,8 +14,9 @@ public class AppConstant {
|
||||
public static final String APP_TITLE = PropertiesUtils.getInstance().getProperty("app.title");
|
||||
public static final String APP_NAME = PropertiesUtils.getInstance().getProperty("app.name");
|
||||
public static final String APP_VERSION = PropertiesUtils.getInstance().getProperty("app.version");
|
||||
public static final String DATA_DIR_PATH = System.getProperty("user.home") + File.separator + "AppData" + File.separator + "Local" + File.separator + APP_NAME;
|
||||
public static final String TMP_DIR_PATH = FileUtils.getTempDirectoryPath() + APP_NAME;
|
||||
public static final String CUSTOM_CONFIG_PATH = DATA_DIR_PATH + File.separator + "config.properties";
|
||||
public static final String DATA_DIR_PATH = Paths.get(".").toFile().getAbsolutePath();
|
||||
public static final String TMP_DIR_PATH = System.getProperty("java.io.tmpdir") + APP_NAME;
|
||||
public static final String CONFIG_DIR_PATH = DATA_DIR_PATH + File.separator + "config";
|
||||
public static final String GUI_CONFIG_PATH = CONFIG_DIR_PATH + File.separator + "gui.yaml";
|
||||
public static final String BAK_FILE_PATH = AppConstant.TMP_DIR_PATH + File.separator + "bak";
|
||||
}
|
||||
|
127
src/main/java/cn/octopusyan/alistgui/config/ConfigManager.java
Normal file
127
src/main/java/cn/octopusyan/alistgui/config/ConfigManager.java
Normal file
@ -0,0 +1,127 @@
|
||||
package cn.octopusyan.alistgui.config;
|
||||
|
||||
import cn.hutool.core.lang.PatternPool;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.octopusyan.alistgui.enums.ProxySetup;
|
||||
import cn.octopusyan.alistgui.manager.http.HttpUtil;
|
||||
import cn.octopusyan.alistgui.model.GuiConfig;
|
||||
import cn.octopusyan.alistgui.model.ProxyInfo;
|
||||
import org.apache.commons.lang3.LocaleUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* 客户端设置
|
||||
*
|
||||
* @author octopus_yan@foxmail.com
|
||||
*/
|
||||
public class ConfigManager {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
|
||||
public static final Locale DEFAULT_LANGUAGE = Locale.CHINESE;
|
||||
private static GuiConfig guiConfig;
|
||||
|
||||
public static void load() {
|
||||
try {
|
||||
guiConfig = GuiConfig.getInstance();
|
||||
} catch (IOException e) {
|
||||
logger.error("load config error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasProxy() {
|
||||
if (guiConfig == null)
|
||||
return false;
|
||||
ProxyInfo proxyInfo = guiConfig.getProxyInfo();
|
||||
return proxyInfo != null
|
||||
&& StringUtils.isNoneEmpty(proxyInfo.getHost())
|
||||
&& StringUtils.isNoneEmpty(proxyInfo.getPort())
|
||||
&& Integer.parseInt(proxyInfo.getPort()) > 0;
|
||||
}
|
||||
|
||||
public static ProxyInfo getProxyInfo() {
|
||||
return guiConfig.getProxyInfo();
|
||||
}
|
||||
|
||||
public static String proxyHost() {
|
||||
return guiConfig.getProxyInfo().getHost();
|
||||
}
|
||||
|
||||
public static void proxyHost(String host) {
|
||||
final Matcher matcher = PatternPool.IPV4.matcher(host);
|
||||
if (matcher.matches()) {
|
||||
guiConfig.getProxyInfo().setHost(host);
|
||||
}
|
||||
}
|
||||
|
||||
public static String proxyPort() {
|
||||
return guiConfig.getProxyInfo().getPort();
|
||||
}
|
||||
|
||||
public static int getProxyPort() {
|
||||
return Integer.parseInt(guiConfig.getProxyInfo().getPort());
|
||||
}
|
||||
|
||||
public static void proxyPort(String port) {
|
||||
if (NumberUtil.isNumber(port))
|
||||
guiConfig.getProxyInfo().setPort(port);
|
||||
}
|
||||
|
||||
public static Locale language() {
|
||||
String language = guiConfig.getLanguage();
|
||||
return LocaleUtils.toLocale(Optional.ofNullable(language).orElse(DEFAULT_LANGUAGE.toString()));
|
||||
}
|
||||
|
||||
public static void language(Locale locale) {
|
||||
guiConfig.setLanguage(locale.toString());
|
||||
}
|
||||
|
||||
public static boolean autoStart() {
|
||||
return guiConfig.getAutoStart();
|
||||
}
|
||||
|
||||
public static void autoStart(Boolean autoStart) {
|
||||
guiConfig.setAutoStart(autoStart);
|
||||
}
|
||||
|
||||
public static ProxySetup proxySetup() {
|
||||
return ProxySetup.valueOf(StringUtils.upperCase(guiConfig.getProxySetup()));
|
||||
}
|
||||
|
||||
public static void proxySetup(ProxySetup setup) {
|
||||
guiConfig.setProxySetup(setup.getName());
|
||||
|
||||
if (!ProxySetup.NO_PROXY.equals(setup) && hasProxy()) {
|
||||
HttpUtil.getInstance().proxy(setup, ConfigManager.getProxyInfo());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean silentStartup() {
|
||||
return guiConfig.getSilentStartup();
|
||||
}
|
||||
|
||||
public static void silentStartup(Boolean startup) {
|
||||
guiConfig.setSilentStartup(startup);
|
||||
}
|
||||
|
||||
public static String aListVersion() {
|
||||
return guiConfig.getAListVersion();
|
||||
}
|
||||
|
||||
public static void aListVersion(String version) {
|
||||
guiConfig.setAListVersion(version);
|
||||
}
|
||||
|
||||
public static void save() {
|
||||
try {
|
||||
guiConfig.save();
|
||||
} catch (IOException e) {
|
||||
logger.error("save config error", e);
|
||||
}
|
||||
}
|
||||
}
|
209
src/main/java/cn/octopusyan/alistgui/config/Context.java
Normal file
209
src/main/java/cn/octopusyan/alistgui/config/Context.java
Normal file
@ -0,0 +1,209 @@
|
||||
package cn.octopusyan.alistgui.config;
|
||||
|
||||
import cn.octopusyan.alistgui.base.BaseController;
|
||||
import cn.octopusyan.alistgui.controller.MainController;
|
||||
import cn.octopusyan.alistgui.controller.RootController;
|
||||
import cn.octopusyan.alistgui.controller.SetupController;
|
||||
import cn.octopusyan.alistgui.util.FxmlUtil;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.effect.DropShadow;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.util.Callback;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* test contect
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
public class Context {
|
||||
private static final Logger log = LoggerFactory.getLogger(Context.class);
|
||||
private static Scene scene;
|
||||
private static final IntegerProperty currentViewIndexProperty = new SimpleIntegerProperty(0);
|
||||
/**
|
||||
* 控制器集合
|
||||
*/
|
||||
private static final Map<String, BaseController<?>> controllers = new HashMap<>();
|
||||
/**
|
||||
* 默认语言文件 Base Name
|
||||
*/
|
||||
private static final String LANGUAGE_RESOURCE_NAME = "language/language";
|
||||
/**
|
||||
* 语言资源工厂
|
||||
*/
|
||||
private static final ObservableResourceBundleFactory LANGUAGE_RESOURCE_FACTORY = new ObservableResourceBundleFactory();
|
||||
/**
|
||||
* 支持的语言集合,应与语言资源文件同步手动更新
|
||||
*/
|
||||
public static final List<Locale> SUPPORT_LANGUAGE_LIST = Arrays.asList(Locale.CHINESE, Locale.ENGLISH);
|
||||
/**
|
||||
* 记录当前所选时区
|
||||
*/
|
||||
private static final ObjectProperty<Locale> currentLocale = new SimpleObjectProperty<>();
|
||||
|
||||
|
||||
private Context() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// 获取控制器集合
|
||||
public static Map<String, BaseController<?>> getControllers() {
|
||||
return controllers;
|
||||
}
|
||||
|
||||
// 获取控制工厂
|
||||
public static Callback<Class<?>, Object> getControlFactory() {
|
||||
return type -> {
|
||||
if (type.equals(RootController.class)) {
|
||||
return new RootController();
|
||||
} else if (type.equals(MainController.class)) {
|
||||
return new MainController();
|
||||
} else if (type.equals(SetupController.class)) {
|
||||
return new SetupController();
|
||||
}
|
||||
throw new IllegalStateException("Unexpected value: " + type);
|
||||
};
|
||||
}
|
||||
|
||||
// 获取当前所选时区属性
|
||||
public static ObjectProperty<Locale> currentLocaleProperty() {
|
||||
return currentLocale;
|
||||
}
|
||||
|
||||
// 设置当前所选时区
|
||||
public static void setCurrentLocale(Locale locale) {
|
||||
currentLocaleProperty().set(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更换语言的组件使用此方法初始化自己的值,调用 {@link Context#setLanguage(Locale)} 来更新界面语言
|
||||
*
|
||||
* @return 当前界面语言
|
||||
*/
|
||||
// 获取当前界面语言
|
||||
public static Locale getCurrentLocale() {
|
||||
return currentLocaleProperty().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新界面语言
|
||||
*
|
||||
* @param locale 区域
|
||||
*/
|
||||
// 更新界面语言
|
||||
public static void setLanguage(Locale locale) {
|
||||
setCurrentLocale(locale);
|
||||
ConfigManager.language(locale);
|
||||
LANGUAGE_RESOURCE_FACTORY.setResourceBundle(ResourceBundle.getBundle(LANGUAGE_RESOURCE_NAME, locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定标识的字符串绑定
|
||||
*
|
||||
* @param key 标识
|
||||
* @return 对应该标识的字符串属性绑定
|
||||
*/
|
||||
// 获取指定标识的字符串绑定
|
||||
public static StringBinding getLanguageBinding(String key) {
|
||||
return LANGUAGE_RESOURCE_FACTORY.getStringBinding(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语言资源属性
|
||||
*/
|
||||
public static ObjectProperty<ResourceBundle> getLanguageResource() {
|
||||
return LANGUAGE_RESOURCE_FACTORY.getResourceBundleProperty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 语言
|
||||
*/
|
||||
private static void initI18n() {
|
||||
currentLocaleProperty().addListener((observable, oldValue, newValue) -> {
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
loadScene();
|
||||
} catch (IOException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 有此类所在路径决定相对路径
|
||||
*
|
||||
* @param path 资源文件相对路径
|
||||
* @return 资源文件路径
|
||||
*/
|
||||
// 加载资源文件
|
||||
public static URL load(String path) {
|
||||
return Context.class.getResource(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化场景
|
||||
*
|
||||
* @return Scene
|
||||
* @throws IOException 如果在加载过程中发生错误
|
||||
*/
|
||||
public static Scene initScene() throws IOException {
|
||||
initI18n();
|
||||
loadScene();
|
||||
return scene;
|
||||
}
|
||||
|
||||
private static void loadScene() throws IOException {
|
||||
FXMLLoader loader = FxmlUtil.load("root-view");
|
||||
loader.setControllerFactory(Context.getControlFactory());
|
||||
Parent root = loader.load();//底层面板
|
||||
// bindShadow((Pane) root);
|
||||
Optional.ofNullable(scene).ifPresentOrElse(
|
||||
s -> s.setRoot(root),
|
||||
() -> {
|
||||
scene = new Scene(root);
|
||||
URL resource = Objects.requireNonNull(Context.class.getResource("/css/root.css"));
|
||||
scene.getStylesheets().addAll(resource.toExternalForm());
|
||||
scene.setFill(Color.TRANSPARENT);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// 设置当前展示的界面
|
||||
public static void setCurrentViewIndex(Number newValue) {
|
||||
currentViewIndexProperty.setValue(newValue);
|
||||
}
|
||||
|
||||
// 获取当前展示的界面Index
|
||||
public static Integer getCurrentViewIndex() {
|
||||
return currentViewIndexProperty.get();
|
||||
}
|
||||
|
||||
private static void bindShadow(Pane pane) {
|
||||
Pane root = new Pane();
|
||||
root.setPadding(new Insets(20, 20, 20, 20));
|
||||
DropShadow dropshadow = new DropShadow();// 阴影向外
|
||||
dropshadow.setRadius(10);// 颜色蔓延的距离
|
||||
dropshadow.setOffsetX(0);// 水平方向,0则向左右两侧,正则向右,负则向左
|
||||
dropshadow.setOffsetY(0);// 垂直方向,0则向上下两侧,正则向下,负则向上
|
||||
dropshadow.setSpread(0.1);// 颜色变淡的程度
|
||||
dropshadow.setColor(Color.BLACK);// 设置颜色
|
||||
root.setEffect(dropshadow);// 绑定指定窗口控件
|
||||
root.getChildren().addAll(pane);
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
package cn.octopusyan.alistgui.config;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 客户端设置
|
||||
*
|
||||
* @author octopus_yan@foxmail.com
|
||||
*/
|
||||
public class CustomConfig {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CustomConfig.class);
|
||||
private static final Properties properties = new Properties();
|
||||
public static final String PROXY_HOST_KEY = "proxy.host";
|
||||
public static final String PROXY_PORT_KEY = "proxy.port";
|
||||
|
||||
public static void init() {
|
||||
FileReader reader = null;
|
||||
try {
|
||||
File file = new File(AppConstant.CUSTOM_CONFIG_PATH);
|
||||
if (!file.exists()) {
|
||||
// 创建配置文件
|
||||
if (!file.getParentFile().exists()) {
|
||||
FileUtils.createParentDirectories(file);
|
||||
}
|
||||
boolean newFile = file.createNewFile();
|
||||
// 保存配置
|
||||
store();
|
||||
} else {
|
||||
reader = new FileReader(file);
|
||||
properties.load(reader);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("读取配置文件失败", e);
|
||||
} finally {
|
||||
try {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("关闭配置文件流", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否配置代理
|
||||
*/
|
||||
public static boolean hasProxy() {
|
||||
String host = proxyHost();
|
||||
Integer port = proxyPort();
|
||||
|
||||
return StringUtils.isNoneBlank(host) && Objects.nonNull(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理地址
|
||||
*/
|
||||
public static String proxyHost() {
|
||||
return properties.getProperty(PROXY_HOST_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理地址
|
||||
*/
|
||||
public static void proxyHost(String host) {
|
||||
properties.setProperty(PROXY_HOST_KEY, host);
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理端口
|
||||
*/
|
||||
public static Integer proxyPort() {
|
||||
try {
|
||||
return Integer.parseInt(properties.getProperty(PROXY_PORT_KEY));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return 10809;
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理端口
|
||||
*/
|
||||
public static void proxyPort(int port) {
|
||||
properties.setProperty(PROXY_PORT_KEY, String.valueOf(port));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存配置
|
||||
*/
|
||||
public static void store() {
|
||||
// 生成配置文件
|
||||
try {
|
||||
properties.store(new PrintStream(AppConstant.CUSTOM_CONFIG_PATH), String.valueOf(StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
logger.error("保存客户端配置失败", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package cn.octopusyan.alistgui.config;
|
||||
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* 多国语言属性绑定
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
@Getter
|
||||
public class ObservableResourceBundleFactory {
|
||||
|
||||
private final ObjectProperty<ResourceBundle> resourceBundleProperty = new SimpleObjectProperty<>();
|
||||
|
||||
public ResourceBundle getResourceBundle() {
|
||||
return getResourceBundleProperty().get();
|
||||
}
|
||||
|
||||
public void setResourceBundle(ResourceBundle resourceBundle) {
|
||||
getResourceBundleProperty().set(resourceBundle);
|
||||
}
|
||||
|
||||
public StringBinding getStringBinding(String key) {
|
||||
return new StringBinding() {
|
||||
{
|
||||
bind(resourceBundleProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String computeValue() {
|
||||
return getResourceBundle().getString(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,102 +1,39 @@
|
||||
package cn.octopusyan.alistgui.controller;
|
||||
|
||||
import cn.octopusyan.alistgui.base.BaseController;
|
||||
import javafx.css.PseudoClass;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 主页面控制器
|
||||
* 主界面控制器
|
||||
*
|
||||
* @author octopus_yan@foxmail.com
|
||||
* @author octopus_yan
|
||||
*/
|
||||
public class MainController extends BaseController<VBox> implements Initializable {
|
||||
public class MainController extends BaseController<VBox> {
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private double xOffset;
|
||||
private double yOffset;
|
||||
@FXML
|
||||
public VBox mainView;
|
||||
|
||||
// 布局
|
||||
@FXML
|
||||
public VBox rootPane;
|
||||
@FXML
|
||||
public HBox windowHeader;
|
||||
@FXML
|
||||
public Button alwaysOnTopIcon;
|
||||
@FXML
|
||||
public Button minimizeIcon;
|
||||
@FXML
|
||||
public Button closeIcon;
|
||||
|
||||
// 界面
|
||||
@FXML
|
||||
public TabPane tabPane;
|
||||
|
||||
public MainController(Stage primaryStage) {
|
||||
super(primaryStage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 窗口拖拽设置
|
||||
*
|
||||
* @return 是否启用
|
||||
*/
|
||||
@Override
|
||||
public boolean dragWindow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取根布局
|
||||
*
|
||||
* @return 根布局对象
|
||||
*/
|
||||
@Override
|
||||
public VBox getRootPanel() {
|
||||
return rootPane;
|
||||
return mainView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
@Override
|
||||
public void initData() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图样式
|
||||
*/
|
||||
@Override
|
||||
public void initViewStyle() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图事件
|
||||
*/
|
||||
@Override
|
||||
public void initViewAction() {
|
||||
closeIcon.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> onDestroy());
|
||||
minimizeIcon.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> ((Stage) rootPane.getScene().getWindow()).setIconified(true));
|
||||
alwaysOnTopIcon.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
|
||||
boolean newVal = !getPrimaryStage().isAlwaysOnTop();
|
||||
alwaysOnTopIcon.pseudoClassStateChanged(PseudoClass.getPseudoClass("always-on-top"), newVal);
|
||||
getPrimaryStage().setAlwaysOnTop(newVal);
|
||||
});
|
||||
|
||||
windowHeader.setOnMousePressed(event -> {
|
||||
xOffset = getPrimaryStage().getX() - event.getScreenX();
|
||||
yOffset = getPrimaryStage().getY() - event.getScreenY();
|
||||
});
|
||||
windowHeader.setOnMouseDragged(event -> {
|
||||
getPrimaryStage().setX(event.getScreenX() + xOffset);
|
||||
getPrimaryStage().setY(event.getScreenY() + yOffset);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,108 @@
|
||||
package cn.octopusyan.alistgui.controller;
|
||||
|
||||
import cn.octopusyan.alistgui.base.BaseController;
|
||||
import cn.octopusyan.alistgui.config.Context;
|
||||
import com.gluonhq.emoji.EmojiData;
|
||||
import com.gluonhq.emoji.util.EmojiImageUtils;
|
||||
import javafx.css.PseudoClass;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
/**
|
||||
* 主页面控制器
|
||||
*
|
||||
* @author octopus_yan@foxmail.com
|
||||
*/
|
||||
public class RootController extends BaseController<VBox> {
|
||||
|
||||
private double xOffset;
|
||||
private double yOffset;
|
||||
|
||||
// 布局
|
||||
@FXML
|
||||
private VBox rootPane;
|
||||
@FXML
|
||||
private HBox windowHeader;
|
||||
@FXML
|
||||
private FontIcon alwaysOnTopIcon;
|
||||
@FXML
|
||||
private FontIcon minimizeIcon;
|
||||
@FXML
|
||||
private FontIcon closeIcon;
|
||||
|
||||
// 界面
|
||||
@FXML
|
||||
private TabPane tabPane;
|
||||
|
||||
// footer
|
||||
@FXML
|
||||
public Button document;
|
||||
@FXML
|
||||
public Button github;
|
||||
@FXML
|
||||
public Button sponsor;
|
||||
/**
|
||||
* 获取根布局
|
||||
*
|
||||
* @return 根布局对象
|
||||
*/
|
||||
@Override
|
||||
public VBox getRootPanel() {
|
||||
return rootPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
@Override
|
||||
public void initData() {
|
||||
tabPane.getSelectionModel().select(Context.getCurrentViewIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图样式
|
||||
*/
|
||||
@Override
|
||||
public void initViewStyle() {
|
||||
// 设置图标
|
||||
ImageView book = EmojiImageUtils.emojiView(EmojiData.emojiFromShortName("book").get(), 25);
|
||||
document.setGraphic(book);
|
||||
ImageView githubIcon = EmojiImageUtils.emojiView(EmojiData.emojiFromShortName("cat").get(), 25);
|
||||
github.setGraphic(githubIcon);
|
||||
ImageView juice = EmojiImageUtils.emojiView(EmojiData.emojiFromShortName("tropical_drink").get(), 25);
|
||||
sponsor.setGraphic(juice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图事件
|
||||
*/
|
||||
@Override
|
||||
public void initViewAction() {
|
||||
closeIcon.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> getWindow().close());
|
||||
minimizeIcon.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> getWindow().setIconified(true));
|
||||
alwaysOnTopIcon.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
|
||||
boolean newVal = !getWindow().isAlwaysOnTop();
|
||||
alwaysOnTopIcon.pseudoClassStateChanged(PseudoClass.getPseudoClass("always-on-top"), newVal);
|
||||
getWindow().setAlwaysOnTop(newVal);
|
||||
});
|
||||
|
||||
windowHeader.setOnMousePressed(event -> {
|
||||
xOffset = getWindow().getX() - event.getScreenX();
|
||||
yOffset = getWindow().getY() - event.getScreenY();
|
||||
});
|
||||
windowHeader.setOnMouseDragged(event -> {
|
||||
getWindow().setX(event.getScreenX() + xOffset);
|
||||
getWindow().setY(event.getScreenY() + yOffset);
|
||||
});
|
||||
|
||||
tabPane.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
|
||||
Context.setCurrentViewIndex(newValue);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package cn.octopusyan.alistgui.controller;
|
||||
|
||||
import cn.octopusyan.alistgui.base.BaseController;
|
||||
import cn.octopusyan.alistgui.config.ConfigManager;
|
||||
import cn.octopusyan.alistgui.config.Context;
|
||||
import cn.octopusyan.alistgui.enums.ProxySetup;
|
||||
import cn.octopusyan.alistgui.viewModel.SetupViewModel;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 设置页面控制器
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
public class SetupController extends BaseController<GridPane> implements Initializable {
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@FXML
|
||||
public GridPane setupView;
|
||||
@FXML
|
||||
public CheckBox autoStartCheckBox;
|
||||
@FXML
|
||||
public CheckBox silentStartupCheckBox;
|
||||
@FXML
|
||||
public ComboBox<Locale> languageComboBox;
|
||||
@FXML
|
||||
public ComboBox<ProxySetup> proxySetupComboBox;
|
||||
// @FXML
|
||||
// public RadioButton noProxy;
|
||||
// @FXML
|
||||
// public RadioButton systemProxy;
|
||||
// @FXML
|
||||
// public RadioButton manualProxy;
|
||||
@FXML
|
||||
public Pane proxySetupPane;
|
||||
@FXML
|
||||
public TextField proxyHost;
|
||||
@FXML
|
||||
public TextField proxyPort;
|
||||
@FXML
|
||||
public Label alistVersion;
|
||||
|
||||
private final SetupViewModel setupViewModel = new SetupViewModel();
|
||||
private final ToggleGroup proxySetupGroup = new ToggleGroup();
|
||||
|
||||
@Override
|
||||
public GridPane getRootPanel() {
|
||||
return setupView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initData() {
|
||||
languageComboBox.setItems(FXCollections.observableList(Context.SUPPORT_LANGUAGE_LIST));
|
||||
proxySetupComboBox.setItems(FXCollections.observableList(List.of(ProxySetup.values())));
|
||||
|
||||
// noProxy.setToggleGroup(proxySetupGroup);
|
||||
// systemProxy.setToggleGroup(proxySetupGroup);
|
||||
// manualProxy.setToggleGroup(proxySetupGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initViewStyle() {
|
||||
proxySetupComboBox.getSelectionModel().selectedItemProperty().addListener(observable -> {
|
||||
proxySetupPane.setVisible(ProxySetup.MANUAL.equals(setupViewModel.proxySetupProperty().get()));
|
||||
});
|
||||
proxySetupComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
proxySetupPane.setVisible(ProxySetup.MANUAL.equals(newValue));
|
||||
});
|
||||
|
||||
languageComboBox.getSelectionModel().select(ConfigManager.language());
|
||||
proxySetupComboBox.getSelectionModel().select(ConfigManager.proxySetup());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initViewAction() {
|
||||
autoStartCheckBox.selectedProperty().bindBidirectional(setupViewModel.autoStartProperty());
|
||||
silentStartupCheckBox.selectedProperty().bindBidirectional(setupViewModel.silentStartupProperty());
|
||||
proxySetupComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
setupViewModel.proxySetupProperty().set(newValue);
|
||||
});
|
||||
proxyHost.textProperty().bindBidirectional(setupViewModel.proxyHostProperty());
|
||||
proxyPort.textProperty().bindBidirectional(setupViewModel.proxyPortProperty());
|
||||
languageComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
setupViewModel.languageProperty().set(newValue);
|
||||
logger.info("language changed to {}", newValue);
|
||||
});
|
||||
alistVersion.textProperty().bindBidirectional(setupViewModel.aListVersionProperty());
|
||||
}
|
||||
}
|
25
src/main/java/cn/octopusyan/alistgui/enums/ProxySetup.java
Normal file
25
src/main/java/cn/octopusyan/alistgui/enums/ProxySetup.java
Normal file
@ -0,0 +1,25 @@
|
||||
package cn.octopusyan.alistgui.enums;
|
||||
|
||||
import cn.octopusyan.alistgui.config.Context;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 代理类型
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ProxySetup {
|
||||
NO_PROXY("no_proxy"),
|
||||
SYSTEM("system"),
|
||||
MANUAL("manual");
|
||||
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Context.getLanguageBinding("proxy.setup.label." + getName()).getValue();
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package cn.octopusyan.alistgui.manager.http;
|
||||
|
||||
import lombok.Data;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -23,6 +24,7 @@ import java.util.concurrent.Executor;
|
||||
*
|
||||
* @author octopus_yan@foxmail.com
|
||||
*/
|
||||
@Data
|
||||
public class HttpConfig {
|
||||
private static final Logger logger = LoggerFactory.getLogger(HttpConfig.class);
|
||||
/**
|
||||
@ -95,8 +97,7 @@ public class HttpConfig {
|
||||
}};
|
||||
sslParameters = new SSLParameters();
|
||||
sslParameters.setEndpointIdentificationAlgorithm("");
|
||||
|
||||
|
||||
sslParameters.setProtocols(new String[]{"TLSv1.2"});
|
||||
try {
|
||||
sslContext = SSLContext.getInstance("TLSv1.2");
|
||||
System.setProperty("jdk.internal.httpclient.disableHostnameVerification", "true");//取消主机名验证
|
||||
@ -104,80 +105,5 @@ public class HttpConfig {
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
logger.error("", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public HttpClient.Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(HttpClient.Version version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
|
||||
public HttpClient.Redirect getRedirect() {
|
||||
return redirect;
|
||||
}
|
||||
|
||||
public void setRedirect(HttpClient.Redirect redirect) {
|
||||
this.redirect = redirect;
|
||||
}
|
||||
|
||||
public Executor getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public void setExecutor(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public Authenticator getAuthenticator() {
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
public void setAuthenticator(Authenticator authenticator) {
|
||||
this.authenticator = authenticator;
|
||||
}
|
||||
|
||||
public ProxySelector getProxySelector() {
|
||||
return proxySelector;
|
||||
}
|
||||
|
||||
public void setProxySelector(ProxySelector proxySelector) {
|
||||
this.proxySelector = proxySelector;
|
||||
}
|
||||
|
||||
public CookieHandler getCookieHandler() {
|
||||
return cookieHandler;
|
||||
}
|
||||
|
||||
public void setCookieHandler(CookieHandler cookieHandler) {
|
||||
this.cookieHandler = cookieHandler;
|
||||
}
|
||||
|
||||
public int getDefaultReadTimeout() {
|
||||
return defaultReadTimeout;
|
||||
}
|
||||
|
||||
public void setDefaultReadTimeout(int defaultReadTimeout) {
|
||||
this.defaultReadTimeout = defaultReadTimeout;
|
||||
}
|
||||
|
||||
public SSLContext getSslContext() {
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
public SSLParameters getSslParameters() {
|
||||
return sslParameters;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
package cn.octopusyan.alistgui.manager.http;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import cn.octopusyan.alistgui.config.ConfigManager;
|
||||
import cn.octopusyan.alistgui.enums.ProxySetup;
|
||||
import cn.octopusyan.alistgui.model.ProxyInfo;
|
||||
import cn.octopusyan.alistgui.util.JsonUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
@ -12,7 +16,7 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@ -57,15 +61,20 @@ public class HttpUtil {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public HttpUtil proxy(String host, int port) {
|
||||
public void proxy(ProxySetup setup, ProxyInfo proxy) {
|
||||
if (httpClient == null)
|
||||
throw new RuntimeException("are you ready ?");
|
||||
|
||||
InetSocketAddress unresolved = InetSocketAddress.createUnresolved(host, port);
|
||||
ProxySelector other = ProxySelector.of(unresolved);
|
||||
this.httpConfig.setProxySelector(other);
|
||||
switch (setup) {
|
||||
case NO_PROXY -> clearProxy();
|
||||
case SYSTEM -> httpConfig.setProxySelector(ProxySelector.getDefault());
|
||||
case MANUAL -> {
|
||||
InetSocketAddress unresolved = InetSocketAddress.createUnresolved(ConfigManager.proxyHost(), ConfigManager.getProxyPort());
|
||||
httpConfig.setProxySelector(ProxySelector.of(unresolved));
|
||||
}
|
||||
}
|
||||
|
||||
this.httpClient = createClient(httpConfig);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void clearProxy() {
|
||||
@ -76,24 +85,20 @@ public class HttpUtil {
|
||||
httpClient = createClient(httpConfig);
|
||||
}
|
||||
|
||||
public HttpClient getHttpClient() {
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public String get(String uri, JSONObject header, JSONObject param) throws IOException, InterruptedException {
|
||||
public String get(String uri, JsonNode header, JsonNode param) throws IOException, InterruptedException {
|
||||
HttpRequest.Builder request = getRequest(uri + createFormParams(param), header).GET();
|
||||
HttpResponse<String> response = httpClient.send(request.build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
return response.body();
|
||||
}
|
||||
|
||||
public String post(String uri, JSONObject header, JSONObject param) throws IOException, InterruptedException {
|
||||
public String post(String uri, JsonNode header, JsonNode param) throws IOException, InterruptedException {
|
||||
HttpRequest.Builder request = getRequest(uri, header)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(param.toJSONString()));
|
||||
.POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJsonString(param)));
|
||||
HttpResponse<String> response = httpClient.send(request.build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
return response.body();
|
||||
}
|
||||
|
||||
public String postForm(String uri, JSONObject header, JSONObject param) throws IOException, InterruptedException {
|
||||
public String postForm(String uri, JsonNode header, JsonNode param) throws IOException, InterruptedException {
|
||||
HttpRequest.Builder request = getRequest(uri + createFormParams(param), header)
|
||||
.POST(HttpRequest.BodyPublishers.noBody());
|
||||
|
||||
@ -101,35 +106,37 @@ public class HttpUtil {
|
||||
return response.body();
|
||||
}
|
||||
|
||||
private HttpRequest.Builder getRequest(String uri, JSONObject header) {
|
||||
private HttpRequest.Builder getRequest(String uri, JsonNode header) {
|
||||
HttpRequest.Builder request = HttpRequest.newBuilder();
|
||||
// 请求地址
|
||||
request.uri(URI.create(uri));
|
||||
// 请求头
|
||||
if (header != null && !header.isEmpty()) {
|
||||
for (String key : header.keySet()) {
|
||||
request.header(key, header.getString(key));
|
||||
for (Map.Entry<String, JsonNode> property : header.properties()) {
|
||||
String key = property.getKey();
|
||||
request.header(key, JsonUtil.toJsonString(property.getValue()));
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private String createFormParams(JSONObject params) {
|
||||
private String createFormParams(JsonNode params) {
|
||||
StringBuilder formParams = new StringBuilder();
|
||||
if (params == null) {
|
||||
return formParams.toString();
|
||||
}
|
||||
for (String key : params.keySet()) {
|
||||
Object value = params.get(key);
|
||||
if (value instanceof String) {
|
||||
value = URLEncoder.encode(String.valueOf(value), StandardCharsets.UTF_8);
|
||||
for (Map.Entry<String, JsonNode> property : params.properties()) {
|
||||
String key = property.getKey();
|
||||
JsonNode value = params.get(key);
|
||||
if (value.isTextual()) {
|
||||
String value_ = URLEncoder.encode(String.valueOf(value), StandardCharsets.UTF_8);
|
||||
formParams.append("&").append(key).append("=").append(value_);
|
||||
} else if (value.isNumber()) {
|
||||
formParams.append("&").append(key).append("=").append(value);
|
||||
} else if (value instanceof Number) {
|
||||
formParams.append("&").append(key).append("=").append(value);
|
||||
} else if (value instanceof List) {
|
||||
formParams.append("&").append(key).append("=").append(params.getJSONArray(key));
|
||||
} else if (value.isArray()) {
|
||||
formParams.append("&").append(key).append("=").append(JsonUtil.toJsonString(value));
|
||||
} else {
|
||||
formParams.append("&").append(key).append("=").append(params.getJSONObject(key));
|
||||
formParams.append("&").append(key).append("=").append(JsonUtil.toJsonString(value));
|
||||
}
|
||||
}
|
||||
if (!formParams.isEmpty()) {
|
||||
|
71
src/main/java/cn/octopusyan/alistgui/model/GuiConfig.java
Normal file
71
src/main/java/cn/octopusyan/alistgui/model/GuiConfig.java
Normal file
@ -0,0 +1,71 @@
|
||||
package cn.octopusyan.alistgui.model;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.octopusyan.alistgui.config.AppConstant;
|
||||
import cn.octopusyan.alistgui.config.ConfigManager;
|
||||
import cn.octopusyan.alistgui.enums.ProxySetup;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import lombok.Data;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* GUI配置信息
|
||||
* 通过Jackson 写入yaml
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
@Data
|
||||
public class GuiConfig {
|
||||
private static final Logger log = LoggerFactory.getLogger(GuiConfig.class);
|
||||
public static GuiConfig INSTANCE;
|
||||
public static ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
|
||||
|
||||
private Boolean autoStart = false;
|
||||
private Boolean silentStartup = false;
|
||||
private ProxyInfo proxyInfo = new ProxyInfo();
|
||||
private String proxySetup = ProxySetup.NO_PROXY.getName();
|
||||
private String language = ConfigManager.DEFAULT_LANGUAGE.toString();
|
||||
@JsonProperty("aListVersion")
|
||||
private String aListVersion = "unknown";
|
||||
|
||||
static {
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
|
||||
}
|
||||
|
||||
private GuiConfig() {
|
||||
|
||||
}
|
||||
|
||||
public static GuiConfig getInstance() throws IOException {
|
||||
File src = new File(AppConstant.GUI_CONFIG_PATH);
|
||||
if (INSTANCE == null) {
|
||||
if (!src.exists()) {
|
||||
checkFile(src);
|
||||
}
|
||||
INSTANCE = objectMapper.readValue(src, GuiConfig.class);
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static void checkFile(File src) throws IOException {
|
||||
File parent = FileUtil.getParent(src, 1);
|
||||
if (!parent.exists()) {
|
||||
boolean wasSuccessful = parent.mkdirs();
|
||||
objectMapper.writeValue(src, new GuiConfig());
|
||||
if (!wasSuccessful)
|
||||
log.error("{} 创建失败", src.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
public void save() throws IOException {
|
||||
objectMapper.writeValue(new File(AppConstant.GUI_CONFIG_PATH), INSTANCE);
|
||||
}
|
||||
}
|
16
src/main/java/cn/octopusyan/alistgui/model/ProxyInfo.java
Normal file
16
src/main/java/cn/octopusyan/alistgui/model/ProxyInfo.java
Normal file
@ -0,0 +1,16 @@
|
||||
package cn.octopusyan.alistgui.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 代理信息
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
@Data
|
||||
public class ProxyInfo {
|
||||
private String host = "";
|
||||
private String port = "";
|
||||
private String username = "";
|
||||
private String password = "";
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package cn.octopusyan.alistgui.util;
|
||||
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
|
||||
/**
|
||||
* 剪切板工具
|
||||
*
|
||||
* @author octopus_yan@foxmail.com
|
||||
*/
|
||||
public class ClipUtil {
|
||||
//获取系统剪切板
|
||||
private static final Clipboard clipboard = Clipboard.getSystemClipboard();
|
||||
|
||||
public static void setClip(String data) {
|
||||
clipboard.clear();
|
||||
// 设置剪切板内容
|
||||
ClipboardContent clipboardContent = new ClipboardContent();
|
||||
clipboardContent.putString(data);
|
||||
clipboard.setContent(clipboardContent);
|
||||
|
||||
}
|
||||
|
||||
public static String getString() {
|
||||
// javafx 从剪切板获取文本
|
||||
return clipboard.getString();
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
package cn.octopusyan.alistgui.util;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.filefilter.CanReadFileFilter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
*
|
||||
* @author octopus_yan@foxmail.com
|
||||
*/
|
||||
public class FileUtil {
|
||||
private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);
|
||||
|
||||
public static File[] ls(String path) {
|
||||
File dir = new File(path);
|
||||
if (!dir.exists())
|
||||
throw new RuntimeException(path + "不存在!");
|
||||
|
||||
if (!dir.isDirectory())
|
||||
throw new RuntimeException(path + "不是一个文件夹!");
|
||||
|
||||
return dir.listFiles();
|
||||
}
|
||||
|
||||
public static void copyFilesFromDir(String path, String dest) throws IOException {
|
||||
if (StringUtils.isBlank(path) || StringUtils.isBlank(dest)) {
|
||||
logger.error("path is blank !");
|
||||
return;
|
||||
}
|
||||
File dir = new File(path);
|
||||
if (!dir.exists()) {
|
||||
logger.error("[" + path + "] 不存在!");
|
||||
return;
|
||||
}
|
||||
if (!dir.isDirectory()) {
|
||||
logger.error("[" + path + "] 不是一个文件夹!");
|
||||
}
|
||||
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) return;
|
||||
|
||||
File directory = new File(dest);
|
||||
if (directory.exists() && !directory.isDirectory()) {
|
||||
logger.error("[" + dest + "] 不是一个文件夹!");
|
||||
}
|
||||
|
||||
FileUtils.forceMkdir(directory);
|
||||
|
||||
for (File file : files) {
|
||||
copyFile(file, new File(dest + File.separator + file.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyFile(File in, File out) throws IOException {
|
||||
copyFile(Files.newInputStream(in.toPath()), out);
|
||||
}
|
||||
|
||||
public static void copyFile(InputStream input, File out) throws IOException {
|
||||
OutputStream output = null;
|
||||
try {
|
||||
output = Files.newOutputStream(out.toPath());
|
||||
byte[] buf = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = input.read(buf)) > 0) {
|
||||
output.write(buf, 0, bytesRead);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("", e);
|
||||
} finally {
|
||||
if (output != null) input.close();
|
||||
if (output != null) output.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件主名称
|
||||
*
|
||||
* @param file 文件对象
|
||||
* @return 文件名称
|
||||
*/
|
||||
public static String mainName(File file) {
|
||||
//忽略判断
|
||||
String fileName = file.getName();
|
||||
return fileName.substring(0, fileName.lastIndexOf("."));
|
||||
}
|
||||
|
||||
public static List<String> listFileNames(String path) {
|
||||
Collection<File> files = FileUtils.listFiles(new File(path), CanReadFileFilter.CAN_READ, null);
|
||||
return files.stream().map(File::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回被查找到的文件的绝对路径(匹配到一个就返回)
|
||||
*
|
||||
* @param root 根目录文件
|
||||
* @param fileName 要找的文件名
|
||||
* @return 绝对路径
|
||||
*/
|
||||
private static String findFiles(File root, String fileName) {
|
||||
//定义一个返回值
|
||||
String path = null;
|
||||
//如果传进来的是目录,并且存在
|
||||
if (root.exists() && root.isDirectory()) {
|
||||
//遍历文件夹中的各个文件
|
||||
File[] files = root.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
//如果path的值没有变化
|
||||
if (path == null) {
|
||||
if (file.isFile() && file.getName().contains(fileName)) {
|
||||
path = file.getAbsolutePath();
|
||||
} else {
|
||||
path = findFiles(file, fileName);
|
||||
}
|
||||
} else {
|
||||
break;//跳出循环,增加性能
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package cn.octopusyan.alistgui.util;
|
||||
|
||||
import cn.octopusyan.alistgui.config.Context;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.JavaFXBuilderFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* FXML 工具
|
||||
@ -13,11 +15,15 @@ import java.nio.charset.StandardCharsets;
|
||||
public class FxmlUtil {
|
||||
|
||||
public static FXMLLoader load(String name) {
|
||||
return load(name, Context.getLanguageResource().get());
|
||||
}
|
||||
|
||||
public static FXMLLoader load(String name, ResourceBundle bundle) {
|
||||
String prefix = "/fxml/";
|
||||
String suffix = ".fxml";
|
||||
return new FXMLLoader(
|
||||
FxmlUtil.class.getResource(prefix + name + suffix),
|
||||
null,
|
||||
bundle,
|
||||
new JavaFXBuilderFactory(),
|
||||
null,
|
||||
StandardCharsets.UTF_8
|
||||
|
187
src/main/java/cn/octopusyan/alistgui/util/JsonUtil.java
Normal file
187
src/main/java/cn/octopusyan/alistgui/util/JsonUtil.java
Normal file
@ -0,0 +1,187 @@
|
||||
package cn.octopusyan.alistgui.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/**
|
||||
* Jackson 封装工具类
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
public class JsonUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 时间日期格式
|
||||
*/
|
||||
private static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
static {
|
||||
//对象的所有字段全部列入序列化
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
|
||||
//取消默认转换timestamps形式
|
||||
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
//忽略空Bean转json的错误
|
||||
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
//所有的日期格式都统一为以下的格式,即yyyy-MM-dd HH:mm:ss
|
||||
objectMapper.setDateFormat(new SimpleDateFormat(STANDARD_FORMAT));
|
||||
//忽略 在json字符串中存在,但在java对象中不存在对应属性的情况。防止错误
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Json字符串 转 JavaBean
|
||||
*
|
||||
* @param jsonString Json字符串
|
||||
* @param clazz Java类对象
|
||||
* @param <T> Java类
|
||||
* @return JavaBean
|
||||
*/
|
||||
public static <T> T parseObject(String jsonString, Class<T> clazz) {
|
||||
T t = null;
|
||||
try {
|
||||
t = objectMapper.readValue(jsonString, clazz);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取Json文件 转 JavaBean
|
||||
*
|
||||
* @param file Json文件
|
||||
* @param clazz Java类对象
|
||||
* @param <T> Java类
|
||||
* @return JavaBean
|
||||
*/
|
||||
public static <T> T parseObject(File file, Class<T> clazz) {
|
||||
T t = null;
|
||||
try {
|
||||
t = objectMapper.readValue(file, clazz);
|
||||
} catch (IOException e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取Json字符串 转 JavaBean集合
|
||||
*
|
||||
* @param jsonArray Json字符串
|
||||
* @param reference 类型
|
||||
* @param <T> JavaBean类型
|
||||
* @return JavaBean集合
|
||||
*/
|
||||
public static <T> T parseJsonArray(String jsonArray, TypeReference<T> reference) {
|
||||
T t = null;
|
||||
try {
|
||||
t = objectMapper.readValue(jsonArray, reference);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JavaBean 转 Json字符串
|
||||
*
|
||||
* @param object JavaBean
|
||||
* @return Json字符串
|
||||
*/
|
||||
public static String toJsonString(Object object) {
|
||||
String jsonString = null;
|
||||
try {
|
||||
jsonString = objectMapper.writeValueAsString(object);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaBean 转 字节数组
|
||||
*
|
||||
* @param object JavaBean
|
||||
* @return 字节数组
|
||||
*/
|
||||
public static byte[] toByteArray(Object object) {
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
bytes = objectMapper.writeValueAsBytes(object);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaBean序列化到文件
|
||||
*
|
||||
* @param file 写入文件对象
|
||||
* @param object JavaBean
|
||||
*/
|
||||
public static void objectToFile(File file, Object object) {
|
||||
try {
|
||||
objectMapper.writeValue(file, object);
|
||||
} catch (Exception e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Json字符串 转 JsonNode
|
||||
*
|
||||
* @param jsonString Json字符串
|
||||
* @return JsonNode
|
||||
*/
|
||||
public static JsonNode parseJsonObject(String jsonString) {
|
||||
JsonNode jsonNode = null;
|
||||
try {
|
||||
jsonNode = objectMapper.readTree(jsonString);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
return jsonNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaBean 转 JsonNode
|
||||
*
|
||||
* @param object JavaBean
|
||||
* @return JsonNode
|
||||
*/
|
||||
public static JsonNode parseJsonObject(Object object) {
|
||||
return objectMapper.valueToTree(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* JsonNode 转 Json字符串
|
||||
*
|
||||
* @param jsonNode JsonNode
|
||||
* @return Json字符串
|
||||
*/
|
||||
public static String toJsonString(JsonNode jsonNode) {
|
||||
String jsonString = null;
|
||||
try {
|
||||
jsonString = objectMapper.writeValueAsString(jsonNode);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("失败:{}", e.getMessage());
|
||||
}
|
||||
return jsonString;
|
||||
}
|
||||
}
|
@ -12,33 +12,14 @@ import java.io.IOException;
|
||||
* @author octopus_yan@foxmail.com
|
||||
*/
|
||||
public class ProcessesUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProcessesUtil.class);
|
||||
private static final String NEWLINE = System.lineSeparator();
|
||||
private static final String NEW_LINE = System.lineSeparator();
|
||||
private static final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
|
||||
|
||||
public static boolean exec(String command) {
|
||||
try {
|
||||
exec(command, new OnExecuteListener() {
|
||||
@Override
|
||||
public void onExecute(String msg) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecuteSuccess(int exitValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecuteError(Exception e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecuteOver() {
|
||||
|
||||
}
|
||||
});
|
||||
exec(command, msg -> {});
|
||||
handler.waitFor();
|
||||
} catch (Exception e) {
|
||||
logger.error("", e);
|
||||
@ -50,7 +31,7 @@ public class ProcessesUtil {
|
||||
LogOutputStream logout = new LogOutputStream() {
|
||||
@Override
|
||||
protected void processLine(String line, int logLevel) {
|
||||
if (listener != null) listener.onExecute(line + NEWLINE);
|
||||
if (listener != null) listener.onExecute(line + NEW_LINE);
|
||||
}
|
||||
};
|
||||
|
||||
@ -81,11 +62,8 @@ public class ProcessesUtil {
|
||||
|
||||
public interface OnExecuteListener {
|
||||
void onExecute(String msg);
|
||||
|
||||
void onExecuteSuccess(int exitValue);
|
||||
|
||||
void onExecuteError(Exception e);
|
||||
void onExecuteOver();
|
||||
default void onExecuteSuccess(int exitValue){}
|
||||
default void onExecuteError(Exception e){}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,87 @@
|
||||
package cn.octopusyan.alistgui.viewModel;
|
||||
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.net.url.UrlBuilder;
|
||||
import cn.octopusyan.alistgui.config.ConfigManager;
|
||||
import cn.octopusyan.alistgui.config.Context;
|
||||
import cn.octopusyan.alistgui.enums.ProxySetup;
|
||||
import javafx.beans.property.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 设置视图数据
|
||||
*
|
||||
* @author octopus_yan
|
||||
*/
|
||||
public class SetupViewModel {
|
||||
private final BooleanProperty autoStart = new SimpleBooleanProperty(ConfigManager.autoStart());
|
||||
private final BooleanProperty silentStartup = new SimpleBooleanProperty(ConfigManager.silentStartup());
|
||||
private final StringProperty proxyHost = new SimpleStringProperty(ConfigManager.proxyHost());
|
||||
private final StringProperty proxyPort = new SimpleStringProperty(ConfigManager.proxyPort());
|
||||
private final BooleanProperty proxyVerify = new SimpleBooleanProperty(false);
|
||||
private final ObjectProperty<Locale> language = new SimpleObjectProperty<>(ConfigManager.language());
|
||||
private final ObjectProperty<ProxySetup> proxySetup = new SimpleObjectProperty<>(ConfigManager.proxySetup());
|
||||
private final SimpleStringProperty aListVersion = new SimpleStringProperty(ConfigManager.aListVersion());
|
||||
|
||||
public SetupViewModel() {
|
||||
aListVersion.addListener((observable, oldValue, newValue) -> ConfigManager.aListVersion(newValue));
|
||||
autoStart.addListener((observable, oldValue, newValue) -> ConfigManager.autoStart(newValue));
|
||||
silentStartup.addListener((observable, oldValue, newValue) -> ConfigManager.silentStartup(newValue));
|
||||
proxySetup.addListener((observable, oldValue, newValue) -> ConfigManager.proxySetup(newValue));
|
||||
proxyHost.addListener((observable, oldValue, newValue) -> ConfigManager.proxyHost(newValue));
|
||||
proxyPort.addListener((observable, oldValue, newValue) -> ConfigManager.proxyPort(newValue));
|
||||
language.addListener((observable, oldValue, newValue) -> Context.setLanguage(newValue));
|
||||
}
|
||||
|
||||
public BooleanProperty autoStartProperty() {
|
||||
return autoStart;
|
||||
}
|
||||
|
||||
public BooleanProperty silentStartupProperty() {
|
||||
return silentStartup;
|
||||
}
|
||||
|
||||
public ObjectProperty<Locale> languageProperty() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public ObjectProperty<ProxySetup> proxySetupProperty() {
|
||||
return proxySetup;
|
||||
}
|
||||
|
||||
public StringProperty proxyHostProperty() {
|
||||
return proxyHost;
|
||||
}
|
||||
|
||||
public StringProperty proxyPortProperty() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
public Property<String> aListVersionProperty() {
|
||||
return aListVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证代理地址
|
||||
*
|
||||
* @param address 新的代理地址
|
||||
* @return UrlBuilder, 验证失败时为null
|
||||
*/
|
||||
public UrlBuilder validateAddress(String address) {
|
||||
if (StringUtils.isEmpty(address))
|
||||
return null;
|
||||
|
||||
// 验证 URL 的可用性
|
||||
UrlBuilder ub = UrlBuilder.of(address);
|
||||
boolean isUrlValid = Validator.isUrl(address) && ub.getPort() > 0;
|
||||
|
||||
// 设置 proxyVerify 和 proxyVerifyMsg
|
||||
proxyVerify.setValue(isUrlValid);
|
||||
|
||||
if (isUrlValid)
|
||||
return ub;
|
||||
else return null;
|
||||
}
|
||||
}
|
@ -3,15 +3,21 @@ module cn.octopusyan.alistgui {
|
||||
requires javafx.controls;
|
||||
requires javafx.fxml;
|
||||
requires javafx.graphics;
|
||||
requires org.apache.commons.io;
|
||||
requires org.apache.commons.lang3;
|
||||
requires org.apache.commons.exec;
|
||||
requires org.slf4j;
|
||||
requires ch.qos.logback.core;
|
||||
requires ch.qos.logback.classic;
|
||||
requires com.alibaba.fastjson2;
|
||||
requires cn.hutool.core;
|
||||
requires org.kordamp.ikonli.javafx;
|
||||
requires com.gluonhq.emoji;
|
||||
requires static lombok;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
requires com.fasterxml.jackson.dataformat.yaml;
|
||||
requires atlantafx.base;
|
||||
|
||||
exports cn.octopusyan.alistgui;
|
||||
opens cn.octopusyan.alistgui to javafx.fxml;
|
||||
opens cn.octopusyan.alistgui.model to com.fasterxml.jackson.databind;
|
||||
opens cn.octopusyan.alistgui.controller to javafx.fxml;
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
app.name=${project.name}
|
||||
app.title=alist gui
|
||||
app.title=AList GUI
|
||||
app.version=${project.version}
|
87
src/main/resources/css/main-view.css
Normal file
87
src/main/resources/css/main-view.css
Normal file
@ -0,0 +1,87 @@
|
||||
/**************************************************
|
||||
* Main View
|
||||
**************************************************/
|
||||
#homeLabel {
|
||||
-fx-font-size: 35;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
#statusLabel {
|
||||
-fx-padding: 2 5 2 5;
|
||||
-fx-text-fill: white;
|
||||
-fx-font-size: 15;
|
||||
-fx-background-color: #1bc964;
|
||||
-fx-background-radius: 10;
|
||||
-fx-text-alignment: CENTER;
|
||||
-fx-border-radius: 10;
|
||||
}
|
||||
|
||||
.control-menu {
|
||||
-fx-font-size: 15;
|
||||
-fx-background-radius: 15;
|
||||
-fx-padding: 10 40 10 40;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-width: 2;
|
||||
-fx-opacity: 0.9;
|
||||
}
|
||||
.control-menu:hover {
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
#startButton {
|
||||
-fx-background-color: #fa6057;
|
||||
-fx-border-color: #fa6057;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
#passwordButton {
|
||||
-fx-background-color: #1bc964;
|
||||
-fx-border-color: #1bc964;
|
||||
}
|
||||
|
||||
#restartButton {
|
||||
-fx-background-color: linear-gradient(#57b4f2, #9198e5);
|
||||
-fx-border-color: linear-gradient(#57b4f2, #9198e5);
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
#moreButton {
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-fill: #9254d1;
|
||||
-fx-border-color: #9254d1;
|
||||
-fx-border-width: 2;
|
||||
}
|
||||
|
||||
#logArea {
|
||||
-fx-font-family: "Lucida Console";
|
||||
-fx-font-size: 20;
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-color: #e9e9e9;
|
||||
}
|
||||
#logArea:focused {
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-color: #e9e9e9;
|
||||
}
|
||||
#logArea .content {
|
||||
-fx-padding: 0 15 0 15;
|
||||
-fx-background-radius: 15;
|
||||
-fx-background-color: #e9e9e9;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
}
|
||||
#logArea .content:focused {
|
||||
-fx-background-color: #e9e9e9;
|
||||
}
|
||||
#logArea .scroll-pane {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
#logArea .scroll-pane .viewport {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=main-view.css.map */
|
1
src/main/resources/css/main-view.css.map
Normal file
1
src/main/resources/css/main-view.css.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["main-view.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAGA;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;;AAEA;EACE","file":"main-view.css"}
|
91
src/main/resources/css/main-view.scss
Normal file
91
src/main/resources/css/main-view.scss
Normal file
@ -0,0 +1,91 @@
|
||||
/**************************************************
|
||||
* Main View
|
||||
**************************************************/
|
||||
#homeLabel {
|
||||
-fx-font-size: 35;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
#statusLabel {
|
||||
-fx-padding: 2 5 2 5;
|
||||
-fx-text-fill: white;
|
||||
-fx-font-size: 15;
|
||||
-fx-background-color: #1bc964;
|
||||
-fx-background-radius: 10;
|
||||
-fx-text-alignment: CENTER;
|
||||
-fx-border-radius: 10;
|
||||
}
|
||||
|
||||
.control-menu {
|
||||
-fx-font-size: 15;
|
||||
-fx-background-radius: 15;
|
||||
-fx-padding: 10 40 10 40;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-width: 2;
|
||||
-fx-opacity: 0.9;
|
||||
|
||||
&:hover {
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
#startButton {
|
||||
-fx-background-color: #fa6057;
|
||||
-fx-border-color: #fa6057;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
#passwordButton {
|
||||
-fx-background-color: #1bc964;
|
||||
-fx-border-color: #1bc964;
|
||||
}
|
||||
|
||||
#restartButton {
|
||||
-fx-background-color: linear-gradient(#57b4f2, #9198e5);
|
||||
-fx-border-color: linear-gradient(#57b4f2, #9198e5);
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
#moreButton {
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-fill: #9254d1;
|
||||
-fx-border-color: #9254d1;
|
||||
-fx-border-width: 2;
|
||||
}
|
||||
|
||||
#logArea {
|
||||
-fx-font-family: "Lucida Console";
|
||||
-fx-font-size: 20;
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-color: #e9e9e9;
|
||||
|
||||
&:focused {
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-color: #e9e9e9;
|
||||
}
|
||||
|
||||
.content {
|
||||
-fx-padding: 0 15 0 15;
|
||||
-fx-background-radius: 15;
|
||||
-fx-background-color: #e9e9e9;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
|
||||
&:focused {
|
||||
-fx-background-color: #e9e9e9;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-pane {
|
||||
-fx-background-color: transparent;
|
||||
|
||||
.viewport {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,176 +1,99 @@
|
||||
@import "root.css";
|
||||
|
||||
/**************************************************
|
||||
* Window Header
|
||||
**************************************************/
|
||||
#windowHeader .iconButton {
|
||||
/*-fx-max-height: 5px;*/
|
||||
/*-fx-max-width: 5px;*/
|
||||
-fx-border-radius: 15;
|
||||
#windowHeader .icon-button {
|
||||
-fx-icon-code: fa-circle;
|
||||
-fx-opacity: 0.5;
|
||||
}
|
||||
|
||||
#rootPane #closeIcon {
|
||||
#windowHeader .icon-button:hover {
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
#windowHeader #closeIcon {
|
||||
-fx-color: #fa6057;
|
||||
-fx-opacity: 0.5;
|
||||
-fx-background-color: #fa6057;
|
||||
-fx-icon-color: #fa6057;
|
||||
}
|
||||
|
||||
#rootPane #closeIcon:hover {
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
|
||||
#rootPane #minimizeIcon {
|
||||
#windowHeader #minimizeIcon {
|
||||
-fx-color: #fbbc2e;
|
||||
-fx-opacity: 0.5;
|
||||
-fx-background-color: #fbbc2e;
|
||||
-fx-icon-color: #fbbc2e;
|
||||
}
|
||||
|
||||
#rootPane #minimizeIcon:hover {
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
|
||||
#rootPane #alwaysOnTopIcon {
|
||||
#windowHeader #alwaysOnTopIcon {
|
||||
-fx-color: #27c940;
|
||||
-fx-opacity: 0.5;
|
||||
-fx-background-color: #27c940;
|
||||
-fx-icon-color: #27c940;
|
||||
}
|
||||
|
||||
#rootPane #alwaysOnTopIcon:hover {
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
|
||||
#rootPane #alwaysOnTopIcon:always-on-top {
|
||||
-fx-opacity: 1.0;
|
||||
#windowHeader #alwaysOnTopIcon:always-on-top {
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Tab label
|
||||
**************************************************/
|
||||
|
||||
#tabPane .tab-header-area {
|
||||
-fx-background-radius: 10;
|
||||
-fx-background-color: #0000;
|
||||
-fx-background-radius: 0 0 0 0;
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
#tabPane .headers-region {
|
||||
-fx-alignment: TOP_CENTER;
|
||||
-fx-background-color: #18181a;
|
||||
-fx-background-radius: 10;
|
||||
-fx-background-color: #e9e9e9;
|
||||
-fx-background-radius: 15;
|
||||
-fx-padding: 5 0 5 0;
|
||||
}
|
||||
|
||||
#tabPane .tab-header-background {
|
||||
-fx-background-color: #0000;
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
#tabPane .tab {
|
||||
-fx-text-fill: white;
|
||||
-fx-padding: 10 20 10 20;
|
||||
-fx-background-radius: 10;
|
||||
-fx-background-color: #0000;
|
||||
-fx-background-radius: 15;
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-width: 0;
|
||||
}
|
||||
|
||||
#tabPane .tab-label {
|
||||
-fx-font-size: 15px;
|
||||
-fx-text-fill: #707079;
|
||||
#tabPane .tab .ikonli-font-icon {
|
||||
-fx-icon-color: black;
|
||||
}
|
||||
#tabPane .tab .tab-label {
|
||||
-fx-text-alignment: CENTER;
|
||||
-fx-alignment: CENTER;
|
||||
}
|
||||
|
||||
#tabPane .tab:selected {
|
||||
-fx-background-color: #2c69e0;
|
||||
}
|
||||
|
||||
#tabPane .tab:selected .ikonli-font-icon {
|
||||
-fx-icon-color: white;
|
||||
}
|
||||
#tabPane .tab:selected .tab-label {
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Main View
|
||||
**************************************************/
|
||||
#homeLabel {
|
||||
-fx-font-size: 35px;
|
||||
-fx-font-weight: bold;
|
||||
-fx-text-fill: white;
|
||||
-fx-font-family: 'JetBrains Mono';
|
||||
}
|
||||
|
||||
#statusLabel {
|
||||
-fx-padding: 2 5 2 5;
|
||||
-fx-text-fill: black;
|
||||
-fx-background-color: #1bc964;
|
||||
-fx-background-radius: 10;
|
||||
-fx-text-alignment: CENTER;
|
||||
-fx-border-radius: 10;
|
||||
-fx-border-color: black;
|
||||
}
|
||||
|
||||
.controlMenu {
|
||||
-fx-font-size: 15;
|
||||
-fx-background-radius: 10px;
|
||||
-fx-padding: 10 40 10 40;
|
||||
-fx-border-radius: 10;
|
||||
}
|
||||
|
||||
.controlMenu:focused {
|
||||
-fx-opacity: 0.5;
|
||||
}
|
||||
|
||||
#startButton {
|
||||
-fx-background-color: #fa6057;
|
||||
-fx-text-fill: white;
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
|
||||
#passwordButton {
|
||||
-fx-background-color: #1bc964;
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
|
||||
#restartButton {
|
||||
-fx-background-color: linear-gradient(#57b4f2, #9198e5);
|
||||
-fx-text-fill: white;
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
|
||||
#moreButton {
|
||||
-fx-background-color: #0000;
|
||||
-fx-text-fill: #9254d1;
|
||||
-fx-border-color: #9254d1;
|
||||
-fx-border-width: 2px;
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
|
||||
#tabPane .tab:selected .focus-indicator {
|
||||
-fx-border-width: 0;
|
||||
-fx-border-color: #0000;
|
||||
}
|
||||
|
||||
#logArea {
|
||||
-fx-text-fill: #e3e4e4;
|
||||
-fx-font-family: 'JetBrains Mono';
|
||||
-fx-font-size: 20;
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-color: #18181c;
|
||||
-fx-border-insets: 0;
|
||||
}
|
||||
#tabPane .tab-label {
|
||||
-fx-font-size: 15px;
|
||||
}
|
||||
|
||||
#logArea .content {
|
||||
-fx-padding: 15;
|
||||
-fx-background-radius: 15;
|
||||
-fx-background-color: #18181c;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
}
|
||||
|
||||
#logArea .scroll-pane {
|
||||
/**************************************************
|
||||
* Window Footer
|
||||
**************************************************/
|
||||
#windowFooter .button {
|
||||
-fx-font-size: 15;
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-alignment: CENTER;
|
||||
}
|
||||
#logArea .scroll-pane .viewport{
|
||||
-fx-background-color: transparent;
|
||||
#windowFooter #document {
|
||||
-fx-text-fill: #1bc964;
|
||||
}
|
||||
#windowFooter #github {
|
||||
-fx-text-fill: #1f4ca6;
|
||||
}
|
||||
#windowFooter #sponsor {
|
||||
-fx-text-fill: #f22760;
|
||||
}
|
||||
#windowFooter .ikonli-font-icon {
|
||||
-fx-font-size: 15;
|
||||
}
|
||||
|
||||
#logArea:focused {
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-color: #18181c;
|
||||
}
|
||||
/*# sourceMappingURL=root-view.css.map */
|
||||
|
1
src/main/resources/css/root-view.css.map
Normal file
1
src/main/resources/css/root-view.css.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["root-view.scss"],"names":[],"mappings":"AAAQ;AACR;AAAA;AAAA;AAIE;EACE;EACA;;AAEA;EACE;;AAIJ;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAEA;EACE;;;AAMN;AAAA;AAAA;AAME;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAKN;EACE;;;AAIJ;AAAA;AAAA;AAKE;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE","file":"root-view.css"}
|
126
src/main/resources/css/root-view.scss
Normal file
126
src/main/resources/css/root-view.scss
Normal file
@ -0,0 +1,126 @@
|
||||
@import "root.css";
|
||||
/**************************************************
|
||||
* Window Header
|
||||
**************************************************/
|
||||
#windowHeader {
|
||||
.icon-button {
|
||||
-fx-icon-code: fa-circle;
|
||||
-fx-opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
#closeIcon {
|
||||
-fx-color: #fa6057;
|
||||
-fx-background-color: #fa6057;
|
||||
-fx-icon-color: #fa6057;
|
||||
}
|
||||
|
||||
#minimizeIcon {
|
||||
-fx-color: #fbbc2e;
|
||||
-fx-background-color: #fbbc2e;
|
||||
-fx-icon-color: #fbbc2e;
|
||||
}
|
||||
|
||||
#alwaysOnTopIcon {
|
||||
-fx-color: #27c940;
|
||||
-fx-background-color: #27c940;
|
||||
-fx-icon-color: #27c940;
|
||||
|
||||
&:always-on-top {
|
||||
-fx-opacity: 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************
|
||||
* Tab label
|
||||
**************************************************/
|
||||
|
||||
#tabPane {
|
||||
|
||||
.tab-header-area {
|
||||
-fx-background-radius: 0 0 0 0;
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.headers-region {
|
||||
-fx-alignment: TOP_CENTER;
|
||||
-fx-background-color: #e9e9e9;
|
||||
-fx-background-radius: 15;
|
||||
-fx-padding: 5 0 5 0;
|
||||
}
|
||||
|
||||
.tab-header-background {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.tab {
|
||||
-fx-padding: 10 20 10 20;
|
||||
-fx-background-radius: 15;
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-width: 0;
|
||||
|
||||
.ikonli-font-icon {
|
||||
-fx-icon-color: black;
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
-fx-text-alignment: CENTER;
|
||||
-fx-alignment: CENTER;
|
||||
}
|
||||
|
||||
&:selected {
|
||||
-fx-background-color: #2c69e0;
|
||||
|
||||
.ikonli-font-icon {
|
||||
-fx-icon-color: white;
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.focus-indicator {
|
||||
-fx-border-width: 0;
|
||||
-fx-border-color: transparent;
|
||||
-fx-border-insets: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
-fx-font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Window Footer
|
||||
**************************************************/
|
||||
|
||||
#windowFooter {
|
||||
.button {
|
||||
-fx-font-size: 15;
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-alignment: CENTER;
|
||||
}
|
||||
|
||||
#document {
|
||||
-fx-text-fill: #1bc964;
|
||||
}
|
||||
|
||||
#github {
|
||||
-fx-text-fill: #1f4ca6;
|
||||
}
|
||||
|
||||
#sponsor {
|
||||
-fx-text-fill: #f22760;
|
||||
}
|
||||
|
||||
.ikonli-font-icon {
|
||||
-fx-font-size: 15;
|
||||
}
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
|
||||
/**************************************************
|
||||
* Root
|
||||
**************************************************/
|
||||
|
||||
.rootPane {
|
||||
-fx-background-color: black;
|
||||
-fx-background-radius: 10;
|
||||
-fx-border-radius: 10;
|
||||
}
|
||||
|
||||
.root {
|
||||
-fx-font-family: "Comic Sans MS";
|
||||
-fx-font-size: 15;
|
||||
-fx-font-weight: normal;
|
||||
}
|
||||
|
||||
.root-pane {
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=root.css.map */
|
||||
|
1
src/main/resources/css/root.css.map
Normal file
1
src/main/resources/css/root.css.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["root.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAIA;EACE;EACA;;;AAGF;EACE;EACA","file":"root.css"}
|
14
src/main/resources/css/root.scss
Normal file
14
src/main/resources/css/root.scss
Normal file
@ -0,0 +1,14 @@
|
||||
/**************************************************
|
||||
* Root
|
||||
**************************************************/
|
||||
|
||||
.root {
|
||||
-fx-font-size: 15;
|
||||
-fx-font-weight: normal;
|
||||
}
|
||||
|
||||
.root-pane {
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
}
|
||||
|
34
src/main/resources/css/setup-view.css
Normal file
34
src/main/resources/css/setup-view.css
Normal file
@ -0,0 +1,34 @@
|
||||
/**************************************************
|
||||
* Setup View
|
||||
**************************************************/
|
||||
#setupView .check-box {
|
||||
-fx-font-size: 15;
|
||||
}
|
||||
#setupView .proxy-panel {
|
||||
-fx-background-color: #e9e9e9;
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-width: 5;
|
||||
}
|
||||
#setupView .proxy-panel .radio-button {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
#setupView .proxy-label {
|
||||
-fx-font-size: 15;
|
||||
-fx-text-fill: #2c69e0;
|
||||
-fx-text-alignment: CENTER;
|
||||
}
|
||||
#setupView .shield .label {
|
||||
-fx-text-fill: white;
|
||||
-fx-label-padding: 3 5 3 5;
|
||||
}
|
||||
#setupView .shield .shield-name {
|
||||
-fx-background-color: #555555;
|
||||
-fx-background-radius: 5 0 0 5;
|
||||
}
|
||||
#setupView .shield .shield-version {
|
||||
-fx-background-color: #6969AA;
|
||||
-fx-background-radius: 0 5 5 0;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=setup-view.css.map */
|
1
src/main/resources/css/setup-view.css.map
Normal file
1
src/main/resources/css/setup-view.css.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["setup-view.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAKE;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;EACA;EACA;;AAKA;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA","file":"setup-view.css"}
|
45
src/main/resources/css/setup-view.scss
Normal file
45
src/main/resources/css/setup-view.scss
Normal file
@ -0,0 +1,45 @@
|
||||
/**************************************************
|
||||
* Setup View
|
||||
**************************************************/
|
||||
|
||||
#setupView {
|
||||
.check-box {
|
||||
-fx-font-size: 15;
|
||||
}
|
||||
|
||||
.proxy-panel {
|
||||
-fx-background-color: #e9e9e9;
|
||||
-fx-background-radius: 15;
|
||||
-fx-border-radius: 15;
|
||||
-fx-border-width: 5;
|
||||
|
||||
.radio-button {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.proxy-label {
|
||||
-fx-font-size: 15;
|
||||
-fx-text-fill: #2c69e0;
|
||||
-fx-text-alignment: CENTER;
|
||||
}
|
||||
|
||||
.shield {
|
||||
|
||||
.label {
|
||||
-fx-text-fill: white;
|
||||
-fx-label-padding: 3 5 3 5;
|
||||
}
|
||||
|
||||
.shield-name {
|
||||
-fx-background-color: #555555;
|
||||
-fx-background-radius: 5 0 0 5;
|
||||
}
|
||||
|
||||
.shield-version {
|
||||
-fx-background-color: #6969AA;
|
||||
-fx-background-radius: 0 5 5 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
src/main/resources/fxml/main-view.fxml
Normal file
39
src/main/resources/fxml/main-view.fxml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<VBox fx:id="mainView" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
|
||||
stylesheets="@../css/main-view.css" prefWidth="720" prefHeight="700"
|
||||
fx:controller="cn.octopusyan.alistgui.controller.MainController">
|
||||
<padding>
|
||||
<Insets left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<HBox alignment="TOP_CENTER" prefWidth="Infinity">
|
||||
<Label fx:id="homeLabel" alignment="CENTER" text="AList GUI"/>
|
||||
<Label fx:id="statusLabel" alignment="TOP_CENTER" text="%main.status.label-running">
|
||||
<HBox.margin>
|
||||
<Insets left="-10.0" top="-5"/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
</HBox>
|
||||
<HBox alignment="TOP_CENTER" prefWidth="Infinity" spacing="25.0">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<VBox.margin>
|
||||
<Insets bottom="10.0" top="10.0"/>
|
||||
</VBox.margin>
|
||||
<Button fx:id="startButton" styleClass="control-menu" text="%main.control.start"/>
|
||||
<Button fx:id="passwordButton" styleClass="control-menu" text="%main.control.password"/>
|
||||
<Button fx:id="restartButton" styleClass="control-menu" text="%main.control.restart"/>
|
||||
<Button fx:id="moreButton" styleClass="control-menu" text="%main.control.more"/>
|
||||
</HBox>
|
||||
<TextArea fx:id="logArea" editable="false" prefWidth="Infinity"
|
||||
text="123d1a32s1d3as21d3a2s1d3a2s1d3a2s1d3a2s1d3a2s1d3a2s1d32aasda3s21da32s1d32a1sd"
|
||||
wrapText="true" VBox.vgrow="ALWAYS">
|
||||
<VBox.margin>
|
||||
<Insets bottom="10.0" top="10.0"/>
|
||||
</VBox.margin>
|
||||
</TextArea>
|
||||
</VBox>
|
@ -1,90 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import org.kordamp.ikonli.javafx.*?>
|
||||
<VBox fx:id="rootPane" styleClass="rootPane" alignment="TOP_CENTER" prefHeight="620.0" prefWidth="700.0" spacing="10.0"
|
||||
stylesheets="@../css/root-view.css" xmlns="http://javafx.com/javafx/11.0.14-internal"
|
||||
xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.octopusyan.alistgui.controller.MainController">
|
||||
|
||||
<VBox fx:id="rootPane" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
|
||||
alignment="TOP_CENTER" prefHeight="720.0" prefWidth="770.0" spacing="10.0"
|
||||
styleClass="root-pane" stylesheets="@../css/root-view.css"
|
||||
fx:controller="cn.octopusyan.alistgui.controller.RootController">
|
||||
|
||||
<HBox fx:id="windowHeader" alignment="CENTER_RIGHT" prefWidth="Infinity" spacing="10.0">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<Button fx:id="alwaysOnTopIcon" styleClass="iconButton"/>
|
||||
<Button fx:id="minimizeIcon" styleClass="iconButton"/>
|
||||
<Button fx:id="closeIcon" styleClass="iconButton"/>
|
||||
<FontIcon fx:id="alwaysOnTopIcon" styleClass="icon-button"/>
|
||||
<FontIcon fx:id="minimizeIcon" styleClass="icon-button"/>
|
||||
<FontIcon fx:id="closeIcon" styleClass="icon-button"/>
|
||||
</HBox>
|
||||
|
||||
<TabPane fx:id="tabPane" prefWidth="Infinity" VBox.vgrow="ALWAYS" tabClosingPolicy="UNAVAILABLE">
|
||||
<TabPane fx:id="tabPane" prefWidth="Infinity" tabClosingPolicy="UNAVAILABLE" VBox.vgrow="ALWAYS">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="20.0" right="20.0" top="10.0"/>
|
||||
<Insets left="20.0" right="20.0"/>
|
||||
</padding>
|
||||
<Tab text="主页">
|
||||
<Tab text="%root.tab.main">
|
||||
<graphic>
|
||||
<FontIcon iconLiteral="cil-library" iconColor="white"/>
|
||||
<FontIcon iconColor="white" iconLiteral="fa-th-large"/>
|
||||
</graphic>
|
||||
<VBox>
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<HBox styleClass="mainViewHeader" prefWidth="Infinity" alignment="TOP_CENTER">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<Label fx:id="homeLabel" text="AList GUI" alignment="CENTER"/>
|
||||
<Label fx:id="statusLabel" text="运行中" alignment="TOP_CENTER">
|
||||
<HBox.margin>
|
||||
<Insets left="-10.0" top="-5"/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
</HBox>
|
||||
<HBox prefWidth="Infinity" alignment="TOP_CENTER" spacing="25.0">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<VBox.margin>
|
||||
<Insets bottom="10.0" top="10.0"/>
|
||||
</VBox.margin>
|
||||
<Button fx:id="startButton" styleClass="controlMenu" text="开始"/>
|
||||
<Button fx:id="passwordButton" styleClass="controlMenu" text="密码"/>
|
||||
<Button fx:id="restartButton" styleClass="controlMenu" text="重启"/>
|
||||
<Button fx:id="moreButton" styleClass="controlMenu" text="更多"/>
|
||||
</HBox>
|
||||
<TextArea fx:id="logArea" editable="false" wrapText="true" prefWidth="Infinity" VBox.vgrow="ALWAYS"
|
||||
text="123d1a32s1d3as21d3a2s1d3a2s1d3a2s1d3a2s1d3a2s1d3a2s1d32aasda3s21da32s1d32a1sd">
|
||||
<VBox.margin>
|
||||
<Insets bottom="10.0" top="10.0"/>
|
||||
</VBox.margin>
|
||||
</TextArea>
|
||||
<HBox prefWidth="Infinity" alignment="CENTER" spacing="25.0">
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="30.0"/>
|
||||
</padding>
|
||||
<Button fx:id="docmentLabel" text="文档" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<FontIcon iconLiteral="cib-readme"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="gethubLabel" text="Github" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<FontIcon iconLiteral="cib-github"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="otherLabel" text="赞助" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<FontIcon iconLiteral="cib-buy-me-a-coffee"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
</VBox>
|
||||
<!-- 引入主页 -->
|
||||
<fx:include fx:id="mainController" source="main-view.fxml" prefWidth="Infinity" prefHeight="-Infinity"/>
|
||||
</Tab>
|
||||
<Tab fx:id="setupTab" text="设置">
|
||||
<Tab text="%root.tab.setup">
|
||||
<graphic>
|
||||
<FontIcon iconLiteral="cil-settings" iconColor="white"/>
|
||||
<FontIcon iconColor="white" iconLiteral="fa-cog"/>
|
||||
</graphic>
|
||||
<!-- 引入设置页 -->
|
||||
<fx:include fx:id="setupController" source="setup-view.fxml" prefWidth="Infinity" prefHeight="-Infinity"/>
|
||||
</Tab>
|
||||
</TabPane>
|
||||
<HBox fx:id="windowFooter" alignment="CENTER" prefWidth="Infinity" spacing="25.0">
|
||||
<padding>
|
||||
<Insets bottom="30.0"/>
|
||||
</padding>
|
||||
<Button fx:id="document" text="%root.foot.doc"/>
|
||||
<Button fx:id="github" text="%root.foot.github"/>
|
||||
<Button fx:id="sponsor" text="%root.foot.sponsor"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
61
src/main/resources/fxml/setup-view.fxml
Normal file
61
src/main/resources/fxml/setup-view.fxml
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<GridPane fx:id="setupView" prefHeight="700" prefWidth="720" stylesheets="@../css/setup-view.css"
|
||||
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="cn.octopusyan.alistgui.controller.SetupController">
|
||||
<padding>
|
||||
<Insets left="10.0" right="10.0" top="20.0"/>
|
||||
</padding>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" percentWidth="100"/>
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
</rowConstraints>
|
||||
<VBox spacing="20">
|
||||
<CheckBox fx:id="autoStartCheckBox" text="%setup.auto-start.label"/>
|
||||
<CheckBox fx:id="silentStartupCheckBox" text="%setup.silent-startup.label"/>
|
||||
<HBox alignment="CENTER_LEFT" spacing="10">
|
||||
<Label text="%setup.language"/>
|
||||
<ComboBox fx:id="languageComboBox"/>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER_LEFT" spacing="20">
|
||||
<Label text="%setup.proxyInfo" styleClass="proxyInfo-label"/>
|
||||
<ComboBox fx:id="proxySetupComboBox"/>
|
||||
</HBox>
|
||||
<!-- <HBox spacing="10" visible="false">-->
|
||||
<!-- <RadioButton fx:id="noProxy" text="%proxyInfo.setup.label.no_proxy"/>-->
|
||||
<!-- <RadioButton fx:id="systemProxy" text="%proxyInfo.setup.label.system"/>-->
|
||||
<!-- <RadioButton fx:id="manualProxy" text="%proxyInfo.setup.label.manual"/>-->
|
||||
<!-- </HBox>-->
|
||||
<VBox fx:id="proxySetupPane" spacing="10">
|
||||
<HBox spacing="20" alignment="CENTER_LEFT">
|
||||
<Label text="%setup.proxyInfo.host"/>
|
||||
<TextField fx:id="proxyHost" promptText="127.0.0.1"/>
|
||||
</HBox>
|
||||
<HBox spacing="20" alignment="CENTER_LEFT">
|
||||
<Label text="%setup.proxyInfo.port"/>
|
||||
<TextField fx:id="proxyPort" promptText="8080"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
</VBox>
|
||||
<AnchorPane GridPane.rowIndex="1">
|
||||
<VBox alignment="CENTER" spacing="10"
|
||||
AnchorPane.bottomAnchor="50" AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0">
|
||||
<HBox alignment="CENTER" styleClass="shield">
|
||||
<Label text="%alist.version" styleClass="shield-name"/>
|
||||
<Label fx:id="alistVersion" styleClass="shield-version"/>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER" styleClass="shield">
|
||||
<Label text="%app.version" styleClass="shield-name"/>
|
||||
<Label text="${project.version}" styleClass="shield-version"/>
|
||||
</HBox>
|
||||
<Button text="%app.update"/>
|
||||
<Button text="%alist.update"/>
|
||||
</VBox>
|
||||
</AnchorPane>
|
||||
</GridPane>
|
27
src/main/resources/language/language.properties
Normal file
27
src/main/resources/language/language.properties
Normal file
@ -0,0 +1,27 @@
|
||||
root.tab.main=\u4E3B\u9875
|
||||
root.tab.setup=\u8BBE\u7F6E
|
||||
root.foot.doc=\u6587\u6863
|
||||
root.foot.github=GitHub
|
||||
root.foot.sponsor=\u8D5E\u52A9
|
||||
main.control.start=\u5F00\u59CB
|
||||
main.control.password=\u5BC6\u7801
|
||||
main.control.restart=\u91CD\u542F
|
||||
main.control.more=\u66F4\u591A
|
||||
main.status.label-running=\u8FD0\u884C\u4E2D
|
||||
main.status.label-stop=\u5DF2\u505C\u6B62
|
||||
main.more.browser=\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00
|
||||
main.more.open-log=\u6253\u5F00\u65E5\u5FD7\u6587\u4EF6\u5939
|
||||
setup.proxyInfo=HTTP\u4EE3\u7406
|
||||
setup.auto-start.label=\u5F00\u673A\u81EA\u542F
|
||||
setup.silent-startup.label=\u9759\u9ED8\u542F\u52A8
|
||||
setup.language=\u8BED\u8A00
|
||||
alist.version=AList \u7248\u672C
|
||||
app.version=GUI \u7248\u672C
|
||||
alist.update=\u68C0\u67E5 AList \u7248\u672C
|
||||
app.update=\u68C0\u67E5 GUI \u7248\u672C
|
||||
setup.proxyInfo.host=\u4E3B\u673A
|
||||
setup.proxyInfo.port=\u7AEF\u53E3
|
||||
proxy.setup.label.no_proxy=\u4E0D\u4EE3\u7406
|
||||
proxy.setup.label.system=\u7CFB\u7EDF\u4EE3\u7406
|
||||
proxy.setup.label.manual=\u624B\u52A8\u8BBE\u7F6E
|
||||
|
27
src/main/resources/language/language_en.properties
Normal file
27
src/main/resources/language/language_en.properties
Normal file
@ -0,0 +1,27 @@
|
||||
root.tab.main=Home
|
||||
root.tab.setup=Setup
|
||||
root.foot.doc=Document
|
||||
root.foot.github=GitHub
|
||||
root.foot.sponsor=Sponsor
|
||||
main.control.start=Start
|
||||
main.control.password=Password
|
||||
main.control.restart=Restart
|
||||
main.control.more=More
|
||||
main.status.label-running=Running
|
||||
main.status.label-stop=Stoped
|
||||
main.more.browser=Open in browser
|
||||
main.more.open-log=Open the log folder
|
||||
setup.proxyInfo=HTTP PROXY
|
||||
setup.auto-start.label=Auto start with PC
|
||||
setup.silent-startup.label=Silent startup
|
||||
setup.language=language
|
||||
alist.version=AList Version
|
||||
app.version=GUI Version
|
||||
alist.update=Check AList Version
|
||||
app.update=Check GUI Version
|
||||
setup.proxyInfo.host=Host
|
||||
setup.proxyInfo.port=Port
|
||||
proxy.setup.label.no_proxy=No Proxy
|
||||
proxy.setup.label.system=System Proxy
|
||||
proxy.setup.label.manual=Manual Config
|
||||
|
27
src/main/resources/language/language_zh.properties
Normal file
27
src/main/resources/language/language_zh.properties
Normal file
@ -0,0 +1,27 @@
|
||||
root.tab.main=\u4E3B\u9875
|
||||
root.tab.setup=\u8BBE\u7F6E
|
||||
root.foot.doc=\u6587\u6863
|
||||
root.foot.github=GitHub
|
||||
root.foot.sponsor=\u8D5E\u52A9
|
||||
main.control.start=\u5F00\u59CB
|
||||
main.control.password=\u5BC6\u7801
|
||||
main.control.restart=\u91CD\u542F
|
||||
main.control.more=\u66F4\u591A
|
||||
main.status.label-running=\u8FD0\u884C\u4E2D
|
||||
main.status.label-stop=\u5DF2\u505C\u6B62
|
||||
main.more.browser=\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00
|
||||
main.more.open-log=\u6253\u5F00\u65E5\u5FD7\u6587\u4EF6\u5939
|
||||
setup.proxyInfo=HTTP\u4EE3\u7406
|
||||
setup.auto-start.label=\u5F00\u673A\u81EA\u542F
|
||||
setup.silent-startup.label=\u9759\u9ED8\u542F\u52A8
|
||||
setup.language=\u8BED\u8A00
|
||||
alist.version=AList \u7248\u672C
|
||||
app.version=GUI \u7248\u672C
|
||||
alist.update=\u68C0\u67E5 AList \u7248\u672C
|
||||
app.update=\u68C0\u67E5 GUI \u7248\u672C
|
||||
setup.proxyInfo.host=\u4E3B\u673A
|
||||
setup.proxyInfo.port=\u7AEF\u53E3
|
||||
proxy.setup.label.no_proxy=\u4E0D\u4EE3\u7406
|
||||
proxy.setup.label.system=\u7CFB\u7EDF\u4EE3\u7406
|
||||
proxy.setup.label.manual=\u624B\u52A8\u8BBE\u7F6E
|
||||
|
@ -5,7 +5,7 @@
|
||||
<property name="CHARSET" value="utf-8"/>
|
||||
<property name="logback.app" value="alist-gui"/>
|
||||
<!-- 彩色日志格式 -->
|
||||
<property name="CONSOLE_LOG_PATTERN" value="%highlight(%d{HH:mm:ss.SSS}) ${logback.app} %boldYellow([%thread]) %highlight(%-5level) %cyan(%logger{36}) - %mdc{client} [%X{trace_id}] %msg%n"/>
|
||||
<property name="CONSOLE_LOG_PATTERN" value="%highlight(%d{YYYY:MM:dd HH:mm:ss.SSS}) ${logback.app} %boldYellow([%thread]) %highlight(%-5level) %cyan(%logger{36}) - %mdc{client} [%X{trace_id}] %msg%n"/>
|
||||
|
||||
<!--输出到控制台 ConsoleAppender-->
|
||||
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
|
||||
|
Loading…
Reference in New Issue
Block a user