合并 SettingsPage 与 SettingsView (#4955)
This commit is contained in:
@@ -17,22 +17,40 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui.main;
|
package org.jackhuang.hmcl.ui.main;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXComboBox;
|
||||||
|
import com.jfoenix.controls.JFXRadioButton;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.InvalidationListener;
|
import javafx.beans.InvalidationListener;
|
||||||
import javafx.beans.WeakInvalidationListener;
|
import javafx.beans.WeakInvalidationListener;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.geometry.VPos;
|
||||||
|
import javafx.scene.Cursor;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.layout.*;
|
||||||
|
import javafx.scene.text.TextAlignment;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
|
import org.jackhuang.hmcl.setting.EnumCommonDirectory;
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
import org.jackhuang.hmcl.setting.Settings;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.ComponentSublist;
|
||||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
|
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.MultiFileItem;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.OptionToggleButton;
|
||||||
import org.jackhuang.hmcl.upgrade.RemoteVersion;
|
import org.jackhuang.hmcl.upgrade.RemoteVersion;
|
||||||
import org.jackhuang.hmcl.upgrade.UpdateChannel;
|
import org.jackhuang.hmcl.upgrade.UpdateChannel;
|
||||||
import org.jackhuang.hmcl.upgrade.UpdateChecker;
|
import org.jackhuang.hmcl.upgrade.UpdateChecker;
|
||||||
import org.jackhuang.hmcl.upgrade.UpdateHandler;
|
import org.jackhuang.hmcl.upgrade.UpdateHandler;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
|
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||||
import org.jackhuang.hmcl.util.i18n.SupportedLocale;
|
import org.jackhuang.hmcl.util.i18n.SupportedLocale;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||||
@@ -45,6 +63,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
@@ -52,79 +71,254 @@ import java.util.zip.ZipEntry;
|
|||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
|
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
|
||||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
|
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
public final class SettingsPage extends SettingsView {
|
public final class SettingsPage extends ScrollPane {
|
||||||
|
|
||||||
private InvalidationListener updateListener;
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
|
private final ToggleGroup updateChannelGroup;
|
||||||
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
|
private final InvalidationListener updateListener;
|
||||||
|
|
||||||
public SettingsPage() {
|
public SettingsPage() {
|
||||||
FXUtils.smoothScrolling(scroll);
|
this.setFitToWidth(true);
|
||||||
|
|
||||||
// ==== Languages ====
|
VBox rootPane = new VBox();
|
||||||
cboLanguage.getItems().setAll(SupportedLocale.getSupportedLocales());
|
rootPane.setPadding(new Insets(32, 10, 32, 10));
|
||||||
selectedItemPropertyFor(cboLanguage).bindBidirectional(config().localizationProperty());
|
this.setContent(rootPane);
|
||||||
|
FXUtils.smoothScrolling(this);
|
||||||
|
|
||||||
disableAutoGameOptionsPane.selectedProperty().bindBidirectional(config().disableAutoGameOptionsProperty());
|
ComponentList settingsPane = new ComponentList();
|
||||||
// ====
|
{
|
||||||
|
{
|
||||||
|
StackPane sponsorPane = new StackPane();
|
||||||
|
sponsorPane.setCursor(Cursor.HAND);
|
||||||
|
FXUtils.onClicked(sponsorPane, this::onSponsor);
|
||||||
|
sponsorPane.setPadding(new Insets(8, 0, 8, 0));
|
||||||
|
|
||||||
fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty());
|
GridPane gridPane = new GridPane();
|
||||||
fileCommonLocationSublist.subtitleProperty().bind(
|
|
||||||
Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.instance().getCommonDirectory())
|
|
||||||
.orElse(i18n("launcher.cache_directory.disabled")),
|
|
||||||
config().commonDirectoryProperty(), config().commonDirTypeProperty()));
|
|
||||||
|
|
||||||
// ==== Update ====
|
ColumnConstraints col = new ColumnConstraints();
|
||||||
FXUtils.installFastTooltip(btnUpdate, i18n("update.tooltip"));
|
col.setHgrow(Priority.SOMETIMES);
|
||||||
updateListener = any -> {
|
col.setMaxWidth(Double.POSITIVE_INFINITY);
|
||||||
btnUpdate.setVisible(UpdateChecker.isOutdated());
|
|
||||||
|
|
||||||
if (UpdateChecker.isOutdated()) {
|
gridPane.getColumnConstraints().setAll(col);
|
||||||
lblUpdateSub.setText(i18n("update.newest_version", UpdateChecker.getLatestVersion().getVersion()));
|
|
||||||
lblUpdateSub.getStyleClass().setAll("update-label");
|
|
||||||
|
|
||||||
lblUpdate.setText(i18n("update.found"));
|
RowConstraints row = new RowConstraints();
|
||||||
lblUpdate.getStyleClass().setAll("update-label");
|
row.setMinHeight(Double.NEGATIVE_INFINITY);
|
||||||
} else if (UpdateChecker.isCheckingUpdate()) {
|
row.setValignment(VPos.TOP);
|
||||||
lblUpdateSub.setText(i18n("update.checking"));
|
row.setVgrow(Priority.SOMETIMES);
|
||||||
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
gridPane.getRowConstraints().setAll(row);
|
||||||
|
|
||||||
lblUpdate.setText(i18n("update"));
|
{
|
||||||
lblUpdate.getStyleClass().setAll("title-label");
|
Label label = new Label(i18n("sponsor.hmcl"));
|
||||||
} else {
|
label.setWrapText(true);
|
||||||
lblUpdateSub.setText(i18n("update.latest"));
|
label.setTextAlignment(TextAlignment.JUSTIFY);
|
||||||
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
GridPane.setRowIndex(label, 0);
|
||||||
|
GridPane.setColumnIndex(label, 0);
|
||||||
|
gridPane.getChildren().add(label);
|
||||||
|
}
|
||||||
|
|
||||||
lblUpdate.setText(i18n("update"));
|
sponsorPane.getChildren().setAll(gridPane);
|
||||||
lblUpdate.getStyleClass().setAll("title-label");
|
settingsPane.getContent().add(sponsorPane);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener));
|
|
||||||
UpdateChecker.outdatedProperty().addListener(new WeakInvalidationListener(updateListener));
|
|
||||||
UpdateChecker.checkingUpdateProperty().addListener(new WeakInvalidationListener(updateListener));
|
|
||||||
updateListener.invalidated(null);
|
|
||||||
|
|
||||||
ToggleGroup updateChannelGroup = new ToggleGroup();
|
{
|
||||||
chkUpdateDev.setToggleGroup(updateChannelGroup);
|
ComponentSublist updatePane = new ComponentSublist();
|
||||||
chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
|
updatePane.setTitle(i18n("update"));
|
||||||
chkUpdateStable.setToggleGroup(updateChannelGroup);
|
updatePane.setHasSubtitle(true);
|
||||||
chkUpdateStable.setUserData(UpdateChannel.STABLE);
|
|
||||||
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
|
|
||||||
updateChannel.set(UpdateChannel.getChannel());
|
|
||||||
|
|
||||||
InvalidationListener checkUpdateListener = e -> {
|
final Label lblUpdate;
|
||||||
UpdateChecker.requestCheckUpdate(updateChannel.get(), previewPane.isSelected());
|
final Label lblUpdateSub;
|
||||||
};
|
{
|
||||||
updateChannel.addListener(checkUpdateListener);
|
VBox headerLeft = new VBox();
|
||||||
previewPane.selectedProperty().addListener(checkUpdateListener);
|
|
||||||
// ====
|
lblUpdate = new Label(i18n("update"));
|
||||||
|
lblUpdate.getStyleClass().add("title-label");
|
||||||
|
lblUpdateSub = new Label();
|
||||||
|
lblUpdateSub.getStyleClass().add("subtitle-label");
|
||||||
|
|
||||||
|
headerLeft.getChildren().setAll(lblUpdate, lblUpdateSub);
|
||||||
|
updatePane.setHeaderLeft(headerLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
JFXButton btnUpdate = new JFXButton();
|
||||||
|
btnUpdate.setOnAction(e -> onUpdate());
|
||||||
|
btnUpdate.getStyleClass().add("toggle-icon4");
|
||||||
|
btnUpdate.setGraphic(SVG.UPDATE.createIcon(20));
|
||||||
|
FXUtils.installFastTooltip(btnUpdate, i18n("update.tooltip"));
|
||||||
|
|
||||||
|
updateListener = any -> {
|
||||||
|
btnUpdate.setVisible(UpdateChecker.isOutdated());
|
||||||
|
|
||||||
|
if (UpdateChecker.isOutdated()) {
|
||||||
|
lblUpdateSub.setText(i18n("update.newest_version", UpdateChecker.getLatestVersion().getVersion()));
|
||||||
|
lblUpdateSub.getStyleClass().setAll("update-label");
|
||||||
|
|
||||||
|
lblUpdate.setText(i18n("update.found"));
|
||||||
|
lblUpdate.getStyleClass().setAll("update-label");
|
||||||
|
} else if (UpdateChecker.isCheckingUpdate()) {
|
||||||
|
lblUpdateSub.setText(i18n("update.checking"));
|
||||||
|
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
||||||
|
|
||||||
|
lblUpdate.setText(i18n("update"));
|
||||||
|
lblUpdate.getStyleClass().setAll("title-label");
|
||||||
|
} else {
|
||||||
|
lblUpdateSub.setText(i18n("update.latest"));
|
||||||
|
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
||||||
|
|
||||||
|
lblUpdate.setText(i18n("update"));
|
||||||
|
lblUpdate.getStyleClass().setAll("title-label");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener));
|
||||||
|
UpdateChecker.outdatedProperty().addListener(new WeakInvalidationListener(updateListener));
|
||||||
|
UpdateChecker.checkingUpdateProperty().addListener(new WeakInvalidationListener(updateListener));
|
||||||
|
updateListener.invalidated(null);
|
||||||
|
|
||||||
|
updatePane.setHeaderRight(btnUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
VBox content = new VBox();
|
||||||
|
content.setSpacing(8);
|
||||||
|
|
||||||
|
JFXRadioButton chkUpdateStable = new JFXRadioButton(i18n("update.channel.stable"));
|
||||||
|
JFXRadioButton chkUpdateDev = new JFXRadioButton(i18n("update.channel.dev"));
|
||||||
|
|
||||||
|
updateChannelGroup = new ToggleGroup();
|
||||||
|
chkUpdateDev.setToggleGroup(updateChannelGroup);
|
||||||
|
chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
|
||||||
|
chkUpdateStable.setToggleGroup(updateChannelGroup);
|
||||||
|
chkUpdateStable.setUserData(UpdateChannel.STABLE);
|
||||||
|
|
||||||
|
Label noteWrapper = new Label(i18n("update.note"));
|
||||||
|
VBox.setMargin(noteWrapper, new Insets(10, 0, 0, 0));
|
||||||
|
|
||||||
|
content.getChildren().setAll(chkUpdateStable, chkUpdateDev, noteWrapper);
|
||||||
|
|
||||||
|
updatePane.getContent().add(content);
|
||||||
|
}
|
||||||
|
settingsPane.getContent().add(updatePane);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
OptionToggleButton previewPane = new OptionToggleButton();
|
||||||
|
previewPane.setTitle(i18n("update.preview"));
|
||||||
|
previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty());
|
||||||
|
FXUtils.installFastTooltip(previewPane, i18n("update.preview.tooltip"));
|
||||||
|
|
||||||
|
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
|
||||||
|
updateChannel.set(UpdateChannel.getChannel());
|
||||||
|
InvalidationListener checkUpdateListener = e -> {
|
||||||
|
UpdateChecker.requestCheckUpdate(updateChannel.get(), previewPane.isSelected());
|
||||||
|
};
|
||||||
|
updateChannel.addListener(checkUpdateListener);
|
||||||
|
previewPane.selectedProperty().addListener(checkUpdateListener);
|
||||||
|
|
||||||
|
settingsPane.getContent().add(previewPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
MultiFileItem<EnumCommonDirectory> fileCommonLocation = new MultiFileItem<>();
|
||||||
|
fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty());
|
||||||
|
fileCommonLocation.loadChildren(Arrays.asList(
|
||||||
|
new MultiFileItem.Option<>(i18n("launcher.cache_directory.default"), EnumCommonDirectory.DEFAULT),
|
||||||
|
new MultiFileItem.FileOption<>(i18n("settings.custom"), EnumCommonDirectory.CUSTOM)
|
||||||
|
.setChooserTitle(i18n("launcher.cache_directory.choose"))
|
||||||
|
.setDirectory(true)
|
||||||
|
.bindBidirectional(config().commonDirectoryProperty())
|
||||||
|
));
|
||||||
|
|
||||||
|
ComponentSublist fileCommonLocationSublist = new ComponentSublist();
|
||||||
|
fileCommonLocationSublist.getContent().add(fileCommonLocation);
|
||||||
|
fileCommonLocationSublist.setTitle(i18n("launcher.cache_directory"));
|
||||||
|
fileCommonLocationSublist.setHasSubtitle(true);
|
||||||
|
fileCommonLocationSublist.subtitleProperty().bind(
|
||||||
|
Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.instance().getCommonDirectory())
|
||||||
|
.orElse(i18n("launcher.cache_directory.disabled")),
|
||||||
|
config().commonDirectoryProperty(), config().commonDirTypeProperty()));
|
||||||
|
|
||||||
|
JFXButton cleanButton = FXUtils.newBorderButton(i18n("launcher.cache_directory.clean"));
|
||||||
|
cleanButton.setOnAction(e -> clearCacheDirectory());
|
||||||
|
fileCommonLocationSublist.setHeaderRight(cleanButton);
|
||||||
|
|
||||||
|
settingsPane.getContent().add(fileCommonLocationSublist);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BorderPane languagePane = new BorderPane();
|
||||||
|
|
||||||
|
Label left = new Label(i18n("settings.launcher.language"));
|
||||||
|
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
|
||||||
|
languagePane.setLeft(left);
|
||||||
|
|
||||||
|
SupportedLocale currentLocale = I18n.getLocale();
|
||||||
|
JFXComboBox<SupportedLocale> cboLanguage = new JFXComboBox<>();
|
||||||
|
cboLanguage.setConverter(stringConverter(locale -> {
|
||||||
|
if (locale.isDefault())
|
||||||
|
return locale.getDisplayName(currentLocale);
|
||||||
|
else if (locale.isSameLanguage(currentLocale))
|
||||||
|
return locale.getDisplayName(locale);
|
||||||
|
else
|
||||||
|
return locale.getDisplayName(currentLocale) + " - " + locale.getDisplayName(locale);
|
||||||
|
}));
|
||||||
|
cboLanguage.getItems().setAll(SupportedLocale.getSupportedLocales());
|
||||||
|
selectedItemPropertyFor(cboLanguage).bindBidirectional(config().localizationProperty());
|
||||||
|
|
||||||
|
FXUtils.setLimitWidth(cboLanguage, 300);
|
||||||
|
languagePane.setRight(cboLanguage);
|
||||||
|
|
||||||
|
settingsPane.getContent().add(languagePane);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
OptionToggleButton disableAutoGameOptionsPane = new OptionToggleButton();
|
||||||
|
disableAutoGameOptionsPane.setTitle(i18n("settings.launcher.disable_auto_game_options"));
|
||||||
|
disableAutoGameOptionsPane.selectedProperty().bindBidirectional(config().disableAutoGameOptionsProperty());
|
||||||
|
|
||||||
|
settingsPane.getContent().add(disableAutoGameOptionsPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BorderPane debugPane = new BorderPane();
|
||||||
|
|
||||||
|
Label left = new Label(i18n("settings.launcher.debug"));
|
||||||
|
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
|
||||||
|
debugPane.setLeft(left);
|
||||||
|
|
||||||
|
JFXButton openLogFolderButton = new JFXButton(i18n("settings.launcher.launcher_log.reveal"));
|
||||||
|
openLogFolderButton.setOnAction(e -> openLogFolder());
|
||||||
|
openLogFolderButton.getStyleClass().add("jfx-button-border");
|
||||||
|
if (LOG.getLogFile() == null)
|
||||||
|
openLogFolderButton.setDisable(true);
|
||||||
|
|
||||||
|
JFXButton logButton = FXUtils.newBorderButton(i18n("settings.launcher.launcher_log.export"));
|
||||||
|
logButton.setOnAction(e -> onExportLogs());
|
||||||
|
|
||||||
|
HBox buttonBox = new HBox();
|
||||||
|
buttonBox.setSpacing(10);
|
||||||
|
buttonBox.getChildren().addAll(openLogFolderButton, logButton);
|
||||||
|
BorderPane.setAlignment(buttonBox, Pos.CENTER_RIGHT);
|
||||||
|
debugPane.setRight(buttonBox);
|
||||||
|
|
||||||
|
settingsPane.getContent().add(debugPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
rootPane.getChildren().add(settingsPane);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void openLogFolder() {
|
||||||
protected void onUpdate() {
|
FXUtils.openFolder(LOG.getLogFile().getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUpdate() {
|
||||||
RemoteVersion target = UpdateChecker.getLatestVersion();
|
RemoteVersion target = UpdateChecker.getLatestVersion();
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
return;
|
return;
|
||||||
@@ -168,8 +362,7 @@ public final class SettingsPage extends SettingsView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void onExportLogs() {
|
||||||
protected void onExportLogs() {
|
|
||||||
thread(() -> {
|
thread(() -> {
|
||||||
String nameBase = "hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss"));
|
String nameBase = "hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss"));
|
||||||
List<Path> recentLogFiles = LOG.findRecentLogFiles(5);
|
List<Path> recentLogFiles = LOG.findRecentLogFiles(5);
|
||||||
@@ -249,13 +442,11 @@ public final class SettingsPage extends SettingsView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void onSponsor() {
|
||||||
protected void onSponsor() {
|
|
||||||
FXUtils.openLink("https://github.com/HMCL-dev/HMCL");
|
FXUtils.openLink("https://github.com/HMCL-dev/HMCL");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void clearCacheDirectory() {
|
||||||
protected void clearCacheDirectory() {
|
|
||||||
String commonDirectory = Settings.instance().getCommonDirectory();
|
String commonDirectory = Settings.instance().getCommonDirectory();
|
||||||
if (commonDirectory != null) {
|
if (commonDirectory != null) {
|
||||||
FileUtils.cleanDirectoryQuietly(Path.of(commonDirectory, "cache"));
|
FileUtils.cleanDirectoryQuietly(Path.of(commonDirectory, "cache"));
|
||||||
|
|||||||
@@ -1,255 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher
|
|
||||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.jackhuang.hmcl.ui.main;
|
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
|
||||||
import com.jfoenix.controls.JFXComboBox;
|
|
||||||
import com.jfoenix.controls.JFXRadioButton;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.Pos;
|
|
||||||
import javafx.geometry.VPos;
|
|
||||||
import javafx.scene.Cursor;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.layout.*;
|
|
||||||
import javafx.scene.text.TextAlignment;
|
|
||||||
import org.jackhuang.hmcl.setting.EnumCommonDirectory;
|
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentSublist;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.MultiFileItem;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.OptionToggleButton;
|
|
||||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
|
||||||
import org.jackhuang.hmcl.util.i18n.SupportedLocale;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
|
||||||
|
|
||||||
public abstract class SettingsView extends StackPane {
|
|
||||||
protected final JFXComboBox<SupportedLocale> cboLanguage;
|
|
||||||
protected final OptionToggleButton disableAutoGameOptionsPane;
|
|
||||||
protected final MultiFileItem<EnumCommonDirectory> fileCommonLocation;
|
|
||||||
protected final ComponentSublist fileCommonLocationSublist;
|
|
||||||
protected final Label lblUpdate;
|
|
||||||
protected final Label lblUpdateSub;
|
|
||||||
protected final JFXRadioButton chkUpdateStable;
|
|
||||||
protected final JFXRadioButton chkUpdateDev;
|
|
||||||
protected final JFXButton btnUpdate;
|
|
||||||
protected final OptionToggleButton previewPane;
|
|
||||||
protected final ScrollPane scroll;
|
|
||||||
|
|
||||||
public SettingsView() {
|
|
||||||
scroll = new ScrollPane();
|
|
||||||
getChildren().setAll(scroll);
|
|
||||||
scroll.setStyle("-fx-font-size: 14;");
|
|
||||||
scroll.setFitToWidth(true);
|
|
||||||
|
|
||||||
{
|
|
||||||
VBox rootPane = new VBox();
|
|
||||||
rootPane.setPadding(new Insets(32, 10, 32, 10));
|
|
||||||
{
|
|
||||||
ComponentList settingsPane = new ComponentList();
|
|
||||||
{
|
|
||||||
{
|
|
||||||
StackPane sponsorPane = new StackPane();
|
|
||||||
sponsorPane.setCursor(Cursor.HAND);
|
|
||||||
FXUtils.onClicked(sponsorPane, this::onSponsor);
|
|
||||||
sponsorPane.setPadding(new Insets(8, 0, 8, 0));
|
|
||||||
|
|
||||||
GridPane gridPane = new GridPane();
|
|
||||||
|
|
||||||
ColumnConstraints col = new ColumnConstraints();
|
|
||||||
col.setHgrow(Priority.SOMETIMES);
|
|
||||||
col.setMaxWidth(Double.POSITIVE_INFINITY);
|
|
||||||
|
|
||||||
gridPane.getColumnConstraints().setAll(col);
|
|
||||||
|
|
||||||
RowConstraints row = new RowConstraints();
|
|
||||||
row.setMinHeight(Double.NEGATIVE_INFINITY);
|
|
||||||
row.setValignment(VPos.TOP);
|
|
||||||
row.setVgrow(Priority.SOMETIMES);
|
|
||||||
gridPane.getRowConstraints().setAll(row);
|
|
||||||
|
|
||||||
{
|
|
||||||
Label label = new Label(i18n("sponsor.hmcl"));
|
|
||||||
label.setWrapText(true);
|
|
||||||
label.setTextAlignment(TextAlignment.JUSTIFY);
|
|
||||||
GridPane.setRowIndex(label, 0);
|
|
||||||
GridPane.setColumnIndex(label, 0);
|
|
||||||
gridPane.getChildren().add(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
sponsorPane.getChildren().setAll(gridPane);
|
|
||||||
settingsPane.getContent().add(sponsorPane);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
ComponentSublist updatePane = new ComponentSublist();
|
|
||||||
updatePane.setTitle(i18n("update"));
|
|
||||||
updatePane.setHasSubtitle(true);
|
|
||||||
{
|
|
||||||
VBox headerLeft = new VBox();
|
|
||||||
|
|
||||||
lblUpdate = new Label(i18n("update"));
|
|
||||||
lblUpdate.getStyleClass().add("title-label");
|
|
||||||
lblUpdateSub = new Label();
|
|
||||||
lblUpdateSub.getStyleClass().add("subtitle-label");
|
|
||||||
|
|
||||||
headerLeft.getChildren().setAll(lblUpdate, lblUpdateSub);
|
|
||||||
updatePane.setHeaderLeft(headerLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
btnUpdate = new JFXButton();
|
|
||||||
btnUpdate.setOnAction(e -> onUpdate());
|
|
||||||
btnUpdate.getStyleClass().add("toggle-icon4");
|
|
||||||
btnUpdate.setGraphic(SVG.UPDATE.createIcon(20));
|
|
||||||
|
|
||||||
updatePane.setHeaderRight(btnUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
VBox content = new VBox();
|
|
||||||
content.setSpacing(8);
|
|
||||||
|
|
||||||
chkUpdateStable = new JFXRadioButton(i18n("update.channel.stable"));
|
|
||||||
chkUpdateDev = new JFXRadioButton(i18n("update.channel.dev"));
|
|
||||||
|
|
||||||
Label noteWrapper = new Label(i18n("update.note"));
|
|
||||||
VBox.setMargin(noteWrapper, new Insets(10, 0, 0, 0));
|
|
||||||
|
|
||||||
content.getChildren().setAll(chkUpdateStable, chkUpdateDev, noteWrapper);
|
|
||||||
|
|
||||||
updatePane.getContent().add(content);
|
|
||||||
}
|
|
||||||
settingsPane.getContent().add(updatePane);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
previewPane = new OptionToggleButton();
|
|
||||||
previewPane.setTitle(i18n("update.preview"));
|
|
||||||
previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty());
|
|
||||||
FXUtils.installFastTooltip(previewPane, i18n("update.preview.tooltip"));
|
|
||||||
|
|
||||||
settingsPane.getContent().add(previewPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
fileCommonLocation = new MultiFileItem<>();
|
|
||||||
fileCommonLocationSublist = new ComponentSublist();
|
|
||||||
fileCommonLocationSublist.getContent().add(fileCommonLocation);
|
|
||||||
fileCommonLocationSublist.setTitle(i18n("launcher.cache_directory"));
|
|
||||||
fileCommonLocationSublist.setHasSubtitle(true);
|
|
||||||
fileCommonLocation.loadChildren(Arrays.asList(
|
|
||||||
new MultiFileItem.Option<>(i18n("launcher.cache_directory.default"), EnumCommonDirectory.DEFAULT),
|
|
||||||
new MultiFileItem.FileOption<>(i18n("settings.custom"), EnumCommonDirectory.CUSTOM)
|
|
||||||
.setChooserTitle(i18n("launcher.cache_directory.choose"))
|
|
||||||
.setDirectory(true)
|
|
||||||
.bindBidirectional(config().commonDirectoryProperty())
|
|
||||||
));
|
|
||||||
|
|
||||||
{
|
|
||||||
JFXButton cleanButton = FXUtils.newBorderButton(i18n("launcher.cache_directory.clean"));
|
|
||||||
cleanButton.setOnAction(e -> clearCacheDirectory());
|
|
||||||
|
|
||||||
fileCommonLocationSublist.setHeaderRight(cleanButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
settingsPane.getContent().add(fileCommonLocationSublist);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
BorderPane languagePane = new BorderPane();
|
|
||||||
|
|
||||||
Label left = new Label(i18n("settings.launcher.language"));
|
|
||||||
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
|
|
||||||
languagePane.setLeft(left);
|
|
||||||
|
|
||||||
SupportedLocale currentLocale = I18n.getLocale();
|
|
||||||
cboLanguage = new JFXComboBox<>();
|
|
||||||
cboLanguage.setConverter(stringConverter(locale -> {
|
|
||||||
if (locale.isDefault())
|
|
||||||
return locale.getDisplayName(currentLocale);
|
|
||||||
else if (locale.isSameLanguage(currentLocale))
|
|
||||||
return locale.getDisplayName(locale);
|
|
||||||
else
|
|
||||||
return locale.getDisplayName(currentLocale) + " - " + locale.getDisplayName(locale);
|
|
||||||
}));
|
|
||||||
|
|
||||||
FXUtils.setLimitWidth(cboLanguage, 300);
|
|
||||||
languagePane.setRight(cboLanguage);
|
|
||||||
|
|
||||||
settingsPane.getContent().add(languagePane);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
disableAutoGameOptionsPane = new OptionToggleButton();
|
|
||||||
disableAutoGameOptionsPane.setTitle(i18n("settings.launcher.disable_auto_game_options"));
|
|
||||||
|
|
||||||
settingsPane.getContent().add(disableAutoGameOptionsPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
BorderPane debugPane = new BorderPane();
|
|
||||||
|
|
||||||
Label left = new Label(i18n("settings.launcher.debug"));
|
|
||||||
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
|
|
||||||
debugPane.setLeft(left);
|
|
||||||
|
|
||||||
JFXButton openLogFolderButton = new JFXButton(i18n("settings.launcher.launcher_log.reveal"));
|
|
||||||
openLogFolderButton.setOnAction(e -> openLogFolder());
|
|
||||||
openLogFolderButton.getStyleClass().add("jfx-button-border");
|
|
||||||
if (LOG.getLogFile() == null)
|
|
||||||
openLogFolderButton.setDisable(true);
|
|
||||||
|
|
||||||
JFXButton logButton = FXUtils.newBorderButton(i18n("settings.launcher.launcher_log.export"));
|
|
||||||
logButton.setOnAction(e -> onExportLogs());
|
|
||||||
|
|
||||||
HBox buttonBox = new HBox();
|
|
||||||
buttonBox.setSpacing(10);
|
|
||||||
buttonBox.getChildren().addAll(openLogFolderButton, logButton);
|
|
||||||
BorderPane.setAlignment(buttonBox, Pos.CENTER_RIGHT);
|
|
||||||
debugPane.setRight(buttonBox);
|
|
||||||
|
|
||||||
settingsPane.getContent().add(debugPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
rootPane.getChildren().add(settingsPane);
|
|
||||||
}
|
|
||||||
scroll.setContent(rootPane);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openLogFolder() {
|
|
||||||
FXUtils.openFolder(LOG.getLogFile().getParent());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void onUpdate();
|
|
||||||
|
|
||||||
protected abstract void onExportLogs();
|
|
||||||
|
|
||||||
protected abstract void onSponsor();
|
|
||||||
|
|
||||||
protected abstract void clearCacheDirectory();
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user