Skip to content

Commit d2c9854

Browse files
authored
合并 SettingsPage 与 SettingsView (#4955)
1 parent f7f0d55 commit d2c9854

File tree

2 files changed

+259
-323
lines changed

2 files changed

+259
-323
lines changed

HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java

Lines changed: 259 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,40 @@
1717
*/
1818
package org.jackhuang.hmcl.ui.main;
1919

20+
import com.jfoenix.controls.JFXButton;
21+
import com.jfoenix.controls.JFXComboBox;
22+
import com.jfoenix.controls.JFXRadioButton;
2023
import javafx.application.Platform;
2124
import javafx.beans.InvalidationListener;
2225
import javafx.beans.WeakInvalidationListener;
2326
import javafx.beans.binding.Bindings;
2427
import javafx.beans.property.ObjectProperty;
28+
import javafx.geometry.Insets;
29+
import javafx.geometry.Pos;
30+
import javafx.geometry.VPos;
31+
import javafx.scene.Cursor;
32+
import javafx.scene.control.Label;
33+
import javafx.scene.control.ScrollPane;
2534
import javafx.scene.control.ToggleGroup;
35+
import javafx.scene.layout.*;
36+
import javafx.scene.text.TextAlignment;
2637
import org.jackhuang.hmcl.Metadata;
38+
import org.jackhuang.hmcl.setting.EnumCommonDirectory;
2739
import org.jackhuang.hmcl.setting.Settings;
2840
import org.jackhuang.hmcl.ui.Controllers;
2941
import org.jackhuang.hmcl.ui.FXUtils;
42+
import org.jackhuang.hmcl.ui.SVG;
43+
import org.jackhuang.hmcl.ui.construct.ComponentList;
44+
import org.jackhuang.hmcl.ui.construct.ComponentSublist;
3045
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
46+
import org.jackhuang.hmcl.ui.construct.MultiFileItem;
47+
import org.jackhuang.hmcl.ui.construct.OptionToggleButton;
3148
import org.jackhuang.hmcl.upgrade.RemoteVersion;
3249
import org.jackhuang.hmcl.upgrade.UpdateChannel;
3350
import org.jackhuang.hmcl.upgrade.UpdateChecker;
3451
import org.jackhuang.hmcl.upgrade.UpdateHandler;
3552
import org.jackhuang.hmcl.util.StringUtils;
53+
import org.jackhuang.hmcl.util.i18n.I18n;
3654
import org.jackhuang.hmcl.util.i18n.SupportedLocale;
3755
import org.jackhuang.hmcl.util.io.FileUtils;
3856
import org.jackhuang.hmcl.util.io.IOUtils;
@@ -45,86 +63,262 @@
4563
import java.nio.file.Path;
4664
import java.time.LocalDateTime;
4765
import java.time.format.DateTimeFormatter;
66+
import java.util.Arrays;
4867
import java.util.List;
4968
import java.util.Optional;
5069
import java.util.zip.GZIPInputStream;
5170
import java.util.zip.ZipEntry;
5271
import java.util.zip.ZipOutputStream;
5372

5473
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
74+
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
5575
import static org.jackhuang.hmcl.util.Lang.thread;
5676
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
5777
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
5878
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
5979

60-
public final class SettingsPage extends SettingsView {
80+
public final class SettingsPage extends ScrollPane {
6181

62-
private InvalidationListener updateListener;
82+
@SuppressWarnings("FieldCanBeLocal")
83+
private final ToggleGroup updateChannelGroup;
84+
@SuppressWarnings("FieldCanBeLocal")
85+
private final InvalidationListener updateListener;
6386

6487
public SettingsPage() {
65-
FXUtils.smoothScrolling(scroll);
66-
67-
// ==== Languages ====
68-
cboLanguage.getItems().setAll(SupportedLocale.getSupportedLocales());
69-
selectedItemPropertyFor(cboLanguage).bindBidirectional(config().localizationProperty());
70-
71-
disableAutoGameOptionsPane.selectedProperty().bindBidirectional(config().disableAutoGameOptionsProperty());
72-
// ====
73-
74-
fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty());
75-
fileCommonLocationSublist.subtitleProperty().bind(
76-
Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.instance().getCommonDirectory())
77-
.orElse(i18n("launcher.cache_directory.disabled")),
78-
config().commonDirectoryProperty(), config().commonDirTypeProperty()));
79-
80-
// ==== Update ====
81-
FXUtils.installFastTooltip(btnUpdate, i18n("update.tooltip"));
82-
updateListener = any -> {
83-
btnUpdate.setVisible(UpdateChecker.isOutdated());
84-
85-
if (UpdateChecker.isOutdated()) {
86-
lblUpdateSub.setText(i18n("update.newest_version", UpdateChecker.getLatestVersion().getVersion()));
87-
lblUpdateSub.getStyleClass().setAll("update-label");
88-
89-
lblUpdate.setText(i18n("update.found"));
90-
lblUpdate.getStyleClass().setAll("update-label");
91-
} else if (UpdateChecker.isCheckingUpdate()) {
92-
lblUpdateSub.setText(i18n("update.checking"));
93-
lblUpdateSub.getStyleClass().setAll("subtitle-label");
94-
95-
lblUpdate.setText(i18n("update"));
96-
lblUpdate.getStyleClass().setAll("title-label");
97-
} else {
98-
lblUpdateSub.setText(i18n("update.latest"));
99-
lblUpdateSub.getStyleClass().setAll("subtitle-label");
100-
101-
lblUpdate.setText(i18n("update"));
102-
lblUpdate.getStyleClass().setAll("title-label");
88+
this.setFitToWidth(true);
89+
90+
VBox rootPane = new VBox();
91+
rootPane.setPadding(new Insets(32, 10, 32, 10));
92+
this.setContent(rootPane);
93+
FXUtils.smoothScrolling(this);
94+
95+
ComponentList settingsPane = new ComponentList();
96+
{
97+
{
98+
StackPane sponsorPane = new StackPane();
99+
sponsorPane.setCursor(Cursor.HAND);
100+
FXUtils.onClicked(sponsorPane, this::onSponsor);
101+
sponsorPane.setPadding(new Insets(8, 0, 8, 0));
102+
103+
GridPane gridPane = new GridPane();
104+
105+
ColumnConstraints col = new ColumnConstraints();
106+
col.setHgrow(Priority.SOMETIMES);
107+
col.setMaxWidth(Double.POSITIVE_INFINITY);
108+
109+
gridPane.getColumnConstraints().setAll(col);
110+
111+
RowConstraints row = new RowConstraints();
112+
row.setMinHeight(Double.NEGATIVE_INFINITY);
113+
row.setValignment(VPos.TOP);
114+
row.setVgrow(Priority.SOMETIMES);
115+
gridPane.getRowConstraints().setAll(row);
116+
117+
{
118+
Label label = new Label(i18n("sponsor.hmcl"));
119+
label.setWrapText(true);
120+
label.setTextAlignment(TextAlignment.JUSTIFY);
121+
GridPane.setRowIndex(label, 0);
122+
GridPane.setColumnIndex(label, 0);
123+
gridPane.getChildren().add(label);
124+
}
125+
126+
sponsorPane.getChildren().setAll(gridPane);
127+
settingsPane.getContent().add(sponsorPane);
128+
}
129+
130+
{
131+
ComponentSublist updatePane = new ComponentSublist();
132+
updatePane.setTitle(i18n("update"));
133+
updatePane.setHasSubtitle(true);
134+
135+
final Label lblUpdate;
136+
final Label lblUpdateSub;
137+
{
138+
VBox headerLeft = new VBox();
139+
140+
lblUpdate = new Label(i18n("update"));
141+
lblUpdate.getStyleClass().add("title-label");
142+
lblUpdateSub = new Label();
143+
lblUpdateSub.getStyleClass().add("subtitle-label");
144+
145+
headerLeft.getChildren().setAll(lblUpdate, lblUpdateSub);
146+
updatePane.setHeaderLeft(headerLeft);
147+
}
148+
149+
{
150+
JFXButton btnUpdate = new JFXButton();
151+
btnUpdate.setOnAction(e -> onUpdate());
152+
btnUpdate.getStyleClass().add("toggle-icon4");
153+
btnUpdate.setGraphic(SVG.UPDATE.createIcon(20));
154+
FXUtils.installFastTooltip(btnUpdate, i18n("update.tooltip"));
155+
156+
updateListener = any -> {
157+
btnUpdate.setVisible(UpdateChecker.isOutdated());
158+
159+
if (UpdateChecker.isOutdated()) {
160+
lblUpdateSub.setText(i18n("update.newest_version", UpdateChecker.getLatestVersion().getVersion()));
161+
lblUpdateSub.getStyleClass().setAll("update-label");
162+
163+
lblUpdate.setText(i18n("update.found"));
164+
lblUpdate.getStyleClass().setAll("update-label");
165+
} else if (UpdateChecker.isCheckingUpdate()) {
166+
lblUpdateSub.setText(i18n("update.checking"));
167+
lblUpdateSub.getStyleClass().setAll("subtitle-label");
168+
169+
lblUpdate.setText(i18n("update"));
170+
lblUpdate.getStyleClass().setAll("title-label");
171+
} else {
172+
lblUpdateSub.setText(i18n("update.latest"));
173+
lblUpdateSub.getStyleClass().setAll("subtitle-label");
174+
175+
lblUpdate.setText(i18n("update"));
176+
lblUpdate.getStyleClass().setAll("title-label");
177+
}
178+
};
179+
UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener));
180+
UpdateChecker.outdatedProperty().addListener(new WeakInvalidationListener(updateListener));
181+
UpdateChecker.checkingUpdateProperty().addListener(new WeakInvalidationListener(updateListener));
182+
updateListener.invalidated(null);
183+
184+
updatePane.setHeaderRight(btnUpdate);
185+
}
186+
187+
{
188+
VBox content = new VBox();
189+
content.setSpacing(8);
190+
191+
JFXRadioButton chkUpdateStable = new JFXRadioButton(i18n("update.channel.stable"));
192+
JFXRadioButton chkUpdateDev = new JFXRadioButton(i18n("update.channel.dev"));
193+
194+
updateChannelGroup = new ToggleGroup();
195+
chkUpdateDev.setToggleGroup(updateChannelGroup);
196+
chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
197+
chkUpdateStable.setToggleGroup(updateChannelGroup);
198+
chkUpdateStable.setUserData(UpdateChannel.STABLE);
199+
200+
Label noteWrapper = new Label(i18n("update.note"));
201+
VBox.setMargin(noteWrapper, new Insets(10, 0, 0, 0));
202+
203+
content.getChildren().setAll(chkUpdateStable, chkUpdateDev, noteWrapper);
204+
205+
updatePane.getContent().add(content);
206+
}
207+
settingsPane.getContent().add(updatePane);
103208
}
104-
};
105-
UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener));
106-
UpdateChecker.outdatedProperty().addListener(new WeakInvalidationListener(updateListener));
107-
UpdateChecker.checkingUpdateProperty().addListener(new WeakInvalidationListener(updateListener));
108-
updateListener.invalidated(null);
109-
110-
ToggleGroup updateChannelGroup = new ToggleGroup();
111-
chkUpdateDev.setToggleGroup(updateChannelGroup);
112-
chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
113-
chkUpdateStable.setToggleGroup(updateChannelGroup);
114-
chkUpdateStable.setUserData(UpdateChannel.STABLE);
115-
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
116-
updateChannel.set(UpdateChannel.getChannel());
117-
118-
InvalidationListener checkUpdateListener = e -> {
119-
UpdateChecker.requestCheckUpdate(updateChannel.get(), previewPane.isSelected());
120-
};
121-
updateChannel.addListener(checkUpdateListener);
122-
previewPane.selectedProperty().addListener(checkUpdateListener);
123-
// ====
209+
210+
{
211+
OptionToggleButton previewPane = new OptionToggleButton();
212+
previewPane.setTitle(i18n("update.preview"));
213+
previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty());
214+
FXUtils.installFastTooltip(previewPane, i18n("update.preview.tooltip"));
215+
216+
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
217+
updateChannel.set(UpdateChannel.getChannel());
218+
InvalidationListener checkUpdateListener = e -> {
219+
UpdateChecker.requestCheckUpdate(updateChannel.get(), previewPane.isSelected());
220+
};
221+
updateChannel.addListener(checkUpdateListener);
222+
previewPane.selectedProperty().addListener(checkUpdateListener);
223+
224+
settingsPane.getContent().add(previewPane);
225+
}
226+
227+
{
228+
MultiFileItem<EnumCommonDirectory> fileCommonLocation = new MultiFileItem<>();
229+
fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty());
230+
fileCommonLocation.loadChildren(Arrays.asList(
231+
new MultiFileItem.Option<>(i18n("launcher.cache_directory.default"), EnumCommonDirectory.DEFAULT),
232+
new MultiFileItem.FileOption<>(i18n("settings.custom"), EnumCommonDirectory.CUSTOM)
233+
.setChooserTitle(i18n("launcher.cache_directory.choose"))
234+
.setDirectory(true)
235+
.bindBidirectional(config().commonDirectoryProperty())
236+
));
237+
238+
ComponentSublist fileCommonLocationSublist = new ComponentSublist();
239+
fileCommonLocationSublist.getContent().add(fileCommonLocation);
240+
fileCommonLocationSublist.setTitle(i18n("launcher.cache_directory"));
241+
fileCommonLocationSublist.setHasSubtitle(true);
242+
fileCommonLocationSublist.subtitleProperty().bind(
243+
Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.instance().getCommonDirectory())
244+
.orElse(i18n("launcher.cache_directory.disabled")),
245+
config().commonDirectoryProperty(), config().commonDirTypeProperty()));
246+
247+
JFXButton cleanButton = FXUtils.newBorderButton(i18n("launcher.cache_directory.clean"));
248+
cleanButton.setOnAction(e -> clearCacheDirectory());
249+
fileCommonLocationSublist.setHeaderRight(cleanButton);
250+
251+
settingsPane.getContent().add(fileCommonLocationSublist);
252+
}
253+
254+
{
255+
BorderPane languagePane = new BorderPane();
256+
257+
Label left = new Label(i18n("settings.launcher.language"));
258+
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
259+
languagePane.setLeft(left);
260+
261+
SupportedLocale currentLocale = I18n.getLocale();
262+
JFXComboBox<SupportedLocale> cboLanguage = new JFXComboBox<>();
263+
cboLanguage.setConverter(stringConverter(locale -> {
264+
if (locale.isDefault())
265+
return locale.getDisplayName(currentLocale);
266+
else if (locale.isSameLanguage(currentLocale))
267+
return locale.getDisplayName(locale);
268+
else
269+
return locale.getDisplayName(currentLocale) + " - " + locale.getDisplayName(locale);
270+
}));
271+
cboLanguage.getItems().setAll(SupportedLocale.getSupportedLocales());
272+
selectedItemPropertyFor(cboLanguage).bindBidirectional(config().localizationProperty());
273+
274+
FXUtils.setLimitWidth(cboLanguage, 300);
275+
languagePane.setRight(cboLanguage);
276+
277+
settingsPane.getContent().add(languagePane);
278+
}
279+
280+
{
281+
OptionToggleButton disableAutoGameOptionsPane = new OptionToggleButton();
282+
disableAutoGameOptionsPane.setTitle(i18n("settings.launcher.disable_auto_game_options"));
283+
disableAutoGameOptionsPane.selectedProperty().bindBidirectional(config().disableAutoGameOptionsProperty());
284+
285+
settingsPane.getContent().add(disableAutoGameOptionsPane);
286+
}
287+
288+
{
289+
BorderPane debugPane = new BorderPane();
290+
291+
Label left = new Label(i18n("settings.launcher.debug"));
292+
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
293+
debugPane.setLeft(left);
294+
295+
JFXButton openLogFolderButton = new JFXButton(i18n("settings.launcher.launcher_log.reveal"));
296+
openLogFolderButton.setOnAction(e -> openLogFolder());
297+
openLogFolderButton.getStyleClass().add("jfx-button-border");
298+
if (LOG.getLogFile() == null)
299+
openLogFolderButton.setDisable(true);
300+
301+
JFXButton logButton = FXUtils.newBorderButton(i18n("settings.launcher.launcher_log.export"));
302+
logButton.setOnAction(e -> onExportLogs());
303+
304+
HBox buttonBox = new HBox();
305+
buttonBox.setSpacing(10);
306+
buttonBox.getChildren().addAll(openLogFolderButton, logButton);
307+
BorderPane.setAlignment(buttonBox, Pos.CENTER_RIGHT);
308+
debugPane.setRight(buttonBox);
309+
310+
settingsPane.getContent().add(debugPane);
311+
}
312+
313+
rootPane.getChildren().add(settingsPane);
314+
}
315+
}
316+
317+
private void openLogFolder() {
318+
FXUtils.openFolder(LOG.getLogFile().getParent());
124319
}
125320

126-
@Override
127-
protected void onUpdate() {
321+
private void onUpdate() {
128322
RemoteVersion target = UpdateChecker.getLatestVersion();
129323
if (target == null) {
130324
return;
@@ -168,8 +362,7 @@ private static boolean exportLogFile(ZipOutputStream output,
168362
}
169363
}
170364

171-
@Override
172-
protected void onExportLogs() {
365+
private void onExportLogs() {
173366
thread(() -> {
174367
String nameBase = "hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss"));
175368
List<Path> recentLogFiles = LOG.findRecentLogFiles(5);
@@ -249,13 +442,11 @@ protected void onExportLogs() {
249442
});
250443
}
251444

252-
@Override
253-
protected void onSponsor() {
445+
private void onSponsor() {
254446
FXUtils.openLink("https://github.com/HMCL-dev/HMCL");
255447
}
256448

257-
@Override
258-
protected void clearCacheDirectory() {
449+
private void clearCacheDirectory() {
259450
String commonDirectory = Settings.instance().getCommonDirectory();
260451
if (commonDirectory != null) {
261452
FileUtils.cleanDirectoryQuietly(Path.of(commonDirectory, "cache"));

0 commit comments

Comments
 (0)