Removed JFXDrawer and JFXHamburger in JFoenix.jar
This commit is contained in:
@@ -55,7 +55,8 @@ public final class Launcher extends Application {
|
|||||||
Main.showErrorAndExit(i18n("fatal.config_loading_failure", Paths.get("").toAbsolutePath().normalize()));
|
Main.showErrorAndExit(i18n("fatal.config_loading_failure", Paths.get("").toAbsolutePath().normalize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// runLater to ensure ConfigHolder.init() finished initialization
|
||||||
|
Platform.runLater(() -> {
|
||||||
// When launcher visibility is set to "hide and reopen" without Platform.implicitExit = false,
|
// When launcher visibility is set to "hide and reopen" without Platform.implicitExit = false,
|
||||||
// Stage.show() cannot work again because JavaFX Toolkit have already shut down.
|
// Stage.show() cannot work again because JavaFX Toolkit have already shut down.
|
||||||
Platform.setImplicitExit(false);
|
Platform.setImplicitExit(false);
|
||||||
@@ -66,9 +67,8 @@ public final class Launcher extends Application {
|
|||||||
UpdateChecker.init();
|
UpdateChecker.init();
|
||||||
|
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
} catch (Throwable e) {
|
});
|
||||||
CRASH_REPORTER.uncaughtException(Thread.currentThread(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -17,33 +17,46 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui;
|
package org.jackhuang.hmcl.ui;
|
||||||
|
|
||||||
|
import com.jfoenix.concurrency.JFXUtilities;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.input.TransferMode;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.jackhuang.hmcl.Launcher;
|
import org.jackhuang.hmcl.Launcher;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
|
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||||
|
import org.jackhuang.hmcl.game.Version;
|
||||||
import org.jackhuang.hmcl.setting.Accounts;
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Profiles;
|
import org.jackhuang.hmcl.setting.Profiles;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||||
import org.jackhuang.hmcl.ui.account.AccountList;
|
import org.jackhuang.hmcl.ui.account.AccountList;
|
||||||
import org.jackhuang.hmcl.ui.account.AuthlibInjectorServersPage;
|
import org.jackhuang.hmcl.ui.account.AuthlibInjectorServersPage;
|
||||||
import org.jackhuang.hmcl.ui.construct.InputDialogPane;
|
import org.jackhuang.hmcl.ui.construct.*;
|
||||||
import org.jackhuang.hmcl.ui.construct.MessageBox;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
|
|
||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorController;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorController;
|
||||||
|
import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider;
|
||||||
import org.jackhuang.hmcl.ui.profile.ProfileList;
|
import org.jackhuang.hmcl.ui.profile.ProfileList;
|
||||||
|
import org.jackhuang.hmcl.ui.versions.GameItem;
|
||||||
import org.jackhuang.hmcl.ui.versions.GameList;
|
import org.jackhuang.hmcl.ui.versions.GameList;
|
||||||
import org.jackhuang.hmcl.ui.versions.VersionPage;
|
import org.jackhuang.hmcl.ui.versions.VersionPage;
|
||||||
|
import org.jackhuang.hmcl.upgrade.UpdateChecker;
|
||||||
import org.jackhuang.hmcl.util.FutureCallback;
|
import org.jackhuang.hmcl.util.FutureCallback;
|
||||||
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
|
import org.jackhuang.hmcl.util.javafx.MultiStepBinding;
|
||||||
import org.jackhuang.hmcl.util.platform.JavaVersion;
|
import org.jackhuang.hmcl.util.platform.JavaVersion;
|
||||||
|
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public final class Controllers {
|
public final class Controllers {
|
||||||
|
|
||||||
@@ -121,8 +134,60 @@ public final class Controllers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static MainPage getMainPage() {
|
public static MainPage getMainPage() {
|
||||||
if (mainPage == null)
|
if (mainPage == null) {
|
||||||
mainPage = new MainPage();
|
mainPage = new MainPage();
|
||||||
|
mainPage.setOnDragOver(event -> {
|
||||||
|
if (event.getGestureSource() != mainPage && event.getDragboard().hasFiles()) {
|
||||||
|
if (event.getDragboard().getFiles().stream().anyMatch(it -> "zip".equals(FileUtils.getExtension(it))))
|
||||||
|
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
|
||||||
|
}
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
|
||||||
|
mainPage.setOnDragDropped(event -> {
|
||||||
|
List<File> files = event.getDragboard().getFiles();
|
||||||
|
if (files != null) {
|
||||||
|
List<File> modpacks = files.stream()
|
||||||
|
.filter(it -> "zip".equals(FileUtils.getExtension(it)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!modpacks.isEmpty()) {
|
||||||
|
File modpack = modpacks.get(0);
|
||||||
|
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(modpack), i18n("install.modpack"));
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
|
||||||
|
FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), version -> {
|
||||||
|
if (version != null) {
|
||||||
|
mainPage.setCurrentGame(version);
|
||||||
|
} else {
|
||||||
|
mainPage.setCurrentGame(i18n("version.empty"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mainPage.showUpdateProperty().bind(UpdateChecker.outdatedProperty());
|
||||||
|
mainPage.latestVersionProperty().bind(
|
||||||
|
MultiStepBinding.of(UpdateChecker.latestVersionProperty())
|
||||||
|
.map(version -> version == null ? "" : i18n("update.bubble.title", version.getVersion())));
|
||||||
|
|
||||||
|
Profiles.registerVersionsListener(profile -> {
|
||||||
|
HMCLGameRepository repository = profile.getRepository();
|
||||||
|
List<Node> children = repository.getVersions().parallelStream()
|
||||||
|
.filter(version -> !version.isHidden())
|
||||||
|
.sorted(Comparator.comparing(Version::getReleaseTime).thenComparing(a -> VersionNumber.asVersion(a.getId())))
|
||||||
|
.map(version -> {
|
||||||
|
Node node = PopupMenu.wrapPopupMenuItem(new GameItem(profile, version.getId()));
|
||||||
|
node.setOnMouseClicked(e -> profile.setSelectedVersion(version.getId()));
|
||||||
|
return node;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
JFXUtilities.runInFX(() -> {
|
||||||
|
if (profile == Profiles.getSelectedProfile())
|
||||||
|
mainPage.getVersions().setAll(children);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
return mainPage;
|
return mainPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +196,8 @@ public final class Controllers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void initialize(Stage stage) {
|
public static void initialize(Stage stage) {
|
||||||
|
Logging.LOG.info("Start initializing application");
|
||||||
|
|
||||||
Controllers.stage = stage;
|
Controllers.stage = stage;
|
||||||
|
|
||||||
stage.setOnCloseRequest(e -> Launcher.stopApplication());
|
stage.setOnCloseRequest(e -> Launcher.stopApplication());
|
||||||
|
|||||||
@@ -46,14 +46,14 @@ public class ListPageSkin extends SkinBase<ListPage> {
|
|||||||
{
|
{
|
||||||
scrollPane.setFitToWidth(true);
|
scrollPane.setFitToWidth(true);
|
||||||
|
|
||||||
VBox accountList = new VBox();
|
VBox list = new VBox();
|
||||||
accountList.maxWidthProperty().bind(scrollPane.widthProperty());
|
list.maxWidthProperty().bind(scrollPane.widthProperty());
|
||||||
accountList.setSpacing(10);
|
list.setSpacing(10);
|
||||||
accountList.setStyle("-fx-padding: 10 10 10 10;");
|
list.setPadding(new Insets(10));
|
||||||
|
|
||||||
Bindings.bindContent(accountList.getChildren(), skinnable.itemsProperty());
|
Bindings.bindContent(list.getChildren(), skinnable.itemsProperty());
|
||||||
|
|
||||||
scrollPane.setContent(accountList);
|
scrollPane.setContent(list);
|
||||||
JFXScrollPane.smoothScrolling(scrollPane);
|
JFXScrollPane.smoothScrolling(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,52 +17,37 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui;
|
package org.jackhuang.hmcl.ui;
|
||||||
|
|
||||||
import com.jfoenix.concurrency.JFXUtilities;
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXPopup;
|
import com.jfoenix.controls.JFXPopup;
|
||||||
import javafx.animation.Interpolator;
|
|
||||||
import javafx.animation.KeyFrame;
|
import javafx.animation.KeyFrame;
|
||||||
import javafx.animation.KeyValue;
|
import javafx.animation.KeyValue;
|
||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.beans.property.ReadOnlyStringProperty;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
import javafx.beans.property.*;
|
||||||
import javafx.fxml.FXML;
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.input.TransferMode;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
|
||||||
import org.jackhuang.hmcl.game.Version;
|
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Profiles;
|
import org.jackhuang.hmcl.setting.Profiles;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.setting.Theme;
|
||||||
import org.jackhuang.hmcl.ui.construct.PopupMenu;
|
import org.jackhuang.hmcl.ui.construct.PopupMenu;
|
||||||
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||||
import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider;
|
|
||||||
import org.jackhuang.hmcl.ui.versions.GameItem;
|
|
||||||
import org.jackhuang.hmcl.ui.versions.Versions;
|
import org.jackhuang.hmcl.ui.versions.Versions;
|
||||||
import org.jackhuang.hmcl.upgrade.RemoteVersion;
|
import org.jackhuang.hmcl.upgrade.RemoteVersion;
|
||||||
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.Logging;
|
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
|
||||||
import org.jackhuang.hmcl.util.javafx.MultiStepBinding;
|
|
||||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.ui.FXUtils.SINE;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public final class MainPage extends StackPane implements DecoratorPage {
|
public final class MainPage extends StackPane implements DecoratorPage {
|
||||||
@@ -71,133 +56,142 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
private final PopupMenu menu = new PopupMenu();
|
private final PopupMenu menu = new PopupMenu();
|
||||||
private final JFXPopup popup = new JFXPopup(menu);
|
private final JFXPopup popup = new JFXPopup(menu);
|
||||||
|
|
||||||
@FXML
|
private final StringProperty currentGame = new SimpleStringProperty(this, "currentGame");
|
||||||
private StackPane main;
|
private final BooleanProperty showUpdate = new SimpleBooleanProperty(this, "showUpdate");
|
||||||
@FXML
|
private final StringProperty latestVersion = new SimpleStringProperty(this, "latestVersion");
|
||||||
|
private final ObservableList<Node> versions = FXCollections.observableArrayList();
|
||||||
|
|
||||||
private StackPane updatePane;
|
private StackPane updatePane;
|
||||||
@FXML
|
private JFXButton menuButton;
|
||||||
private JFXButton btnLaunch;
|
|
||||||
@FXML
|
|
||||||
private JFXButton btnMenu;
|
|
||||||
@FXML
|
|
||||||
private JFXButton closeUpdateButton;
|
|
||||||
@FXML
|
|
||||||
private Label lblCurrentGame;
|
|
||||||
@FXML
|
|
||||||
private Label lblIcon;
|
|
||||||
@FXML
|
|
||||||
private TwoLineListItem lblLatestVersion;
|
|
||||||
@FXML
|
|
||||||
private Rectangle separator;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
FXUtils.loadFXML(this, "/assets/fxml/main.fxml");
|
setPadding(new Insets(25));
|
||||||
|
|
||||||
btnLaunch.setClip(new Rectangle(-100, -100, 310, 200));
|
updatePane = new StackPane();
|
||||||
btnMenu.setClip(new Rectangle(211, -100, 100, 200));
|
|
||||||
menu.setMaxHeight(365);
|
|
||||||
menu.setMaxWidth(545);
|
|
||||||
menu.setAlwaysShowingVBar(true);
|
|
||||||
|
|
||||||
updatePane.visibleProperty().bind(UpdateChecker.outdatedProperty());
|
|
||||||
closeUpdateButton.setGraphic(SVG.close(Theme.whiteFillBinding(), 10, 10));
|
|
||||||
closeUpdateButton.setOnMouseClicked(event -> {
|
|
||||||
Duration duration = Duration.millis(320);
|
|
||||||
Timeline nowAnimation = new Timeline();
|
|
||||||
nowAnimation.getKeyFrames().addAll(
|
|
||||||
new KeyFrame(Duration.ZERO,
|
|
||||||
new KeyValue(updatePane.translateXProperty(), 0, Interpolator.EASE_IN)),
|
|
||||||
new KeyFrame(duration,
|
|
||||||
new KeyValue(updatePane.translateXProperty(), 260, Interpolator.EASE_IN)),
|
|
||||||
new KeyFrame(duration, e -> {
|
|
||||||
updatePane.visibleProperty().unbind();
|
|
||||||
updatePane.setVisible(false);
|
updatePane.setVisible(false);
|
||||||
}));
|
updatePane.getStyleClass().add("bubble");
|
||||||
nowAnimation.play();
|
FXUtils.setLimitWidth(updatePane, 230);
|
||||||
});
|
FXUtils.setLimitHeight(updatePane, 55);
|
||||||
lblIcon.setGraphic(SVG.update(Theme.whiteFillBinding(), 20, 20));
|
StackPane.setAlignment(updatePane, Pos.TOP_RIGHT);
|
||||||
lblLatestVersion.titleProperty().bind(
|
updatePane.setOnMouseClicked(e -> onUpgrade());
|
||||||
MultiStepBinding.of(UpdateChecker.latestVersionProperty())
|
FXUtils.onChange(showUpdateProperty(), this::doAnimation);
|
||||||
.map(version -> version == null ? "" : i18n("update.bubble.title", version.getVersion())));
|
|
||||||
|
|
||||||
|
{
|
||||||
|
HBox hBox = new HBox();
|
||||||
|
hBox.setSpacing(12);
|
||||||
|
hBox.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
StackPane.setAlignment(hBox, Pos.CENTER_LEFT);
|
||||||
|
StackPane.setMargin(hBox, new Insets(9, 12, 9, 16));
|
||||||
|
{
|
||||||
|
Label lblIcon = new Label();
|
||||||
|
lblIcon.setGraphic(SVG.update(Theme.whiteFillBinding(), 20, 20));
|
||||||
|
|
||||||
|
TwoLineListItem prompt = new TwoLineListItem();
|
||||||
|
prompt.setTitleFill(Color.WHITE);
|
||||||
|
prompt.setSubtitleFill(Color.WHITE);
|
||||||
|
prompt.setSubtitle(i18n("update.bubble.subtitle"));
|
||||||
|
prompt.setPickOnBounds(false);
|
||||||
|
prompt.setStyle("-jfx-title-font-weight: BOLD;");
|
||||||
|
prompt.titleProperty().bind(latestVersionProperty());
|
||||||
|
|
||||||
|
hBox.getChildren().setAll(lblIcon, prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
JFXButton closeUpdateButton = new JFXButton();
|
||||||
|
closeUpdateButton.setGraphic(SVG.close(Theme.whiteFillBinding(), 10, 10));
|
||||||
|
StackPane.setAlignment(closeUpdateButton, Pos.TOP_RIGHT);
|
||||||
|
closeUpdateButton.getStyleClass().add("toggle-icon-tiny");
|
||||||
|
StackPane.setMargin(closeUpdateButton, new Insets(5));
|
||||||
|
closeUpdateButton.setOnMouseClicked(e -> closeUpdateBubble());
|
||||||
|
|
||||||
|
updatePane.getChildren().setAll(hBox, closeUpdateButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
StackPane launchPane = new StackPane();
|
||||||
|
launchPane.setMaxWidth(230);
|
||||||
|
launchPane.setMaxHeight(55);
|
||||||
|
StackPane.setAlignment(launchPane, Pos.BOTTOM_RIGHT);
|
||||||
|
{
|
||||||
|
JFXButton launchButton = new JFXButton();
|
||||||
|
launchButton.setPrefWidth(230);
|
||||||
|
launchButton.setPrefHeight(55);
|
||||||
|
launchButton.setButtonType(JFXButton.ButtonType.RAISED);
|
||||||
|
launchButton.getStyleClass().add("jfx-button-raised");
|
||||||
|
launchButton.setOnMouseClicked(e -> launch());
|
||||||
|
launchButton.setClip(new Rectangle(-100, -100, 310, 200));
|
||||||
|
{
|
||||||
|
VBox graphic = new VBox();
|
||||||
|
graphic.setAlignment(Pos.CENTER);
|
||||||
|
graphic.setTranslateX(-7);
|
||||||
|
graphic.setMaxWidth(200);
|
||||||
|
Label launchLabel = new Label(i18n("version.launch"));
|
||||||
|
launchLabel.setStyle("-fx-font-size: 16px;");
|
||||||
|
Label currentLabel = new Label();
|
||||||
|
currentLabel.setStyle("-fx-font-size: 12px;");
|
||||||
|
currentLabel.textProperty().bind(currentGameProperty());
|
||||||
|
graphic.getChildren().setAll(launchLabel, currentLabel);
|
||||||
|
|
||||||
|
launchButton.setGraphic(graphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle separator = new Rectangle();
|
||||||
|
separator.getStyleClass().add("darker-fill");
|
||||||
|
separator.setWidth(1);
|
||||||
|
separator.setHeight(57);
|
||||||
|
separator.setTranslateX(95);
|
||||||
|
separator.setMouseTransparent(true);
|
||||||
|
|
||||||
|
menuButton = new JFXButton();
|
||||||
|
menuButton.setPrefHeight(55);
|
||||||
|
menuButton.setPrefWidth(230);
|
||||||
|
menuButton.setButtonType(JFXButton.ButtonType.RAISED);
|
||||||
|
menuButton.getStyleClass().add("jfx-button-raised");
|
||||||
|
menuButton.setStyle("-fx-font-size: 15px;");
|
||||||
|
menuButton.setOnMouseClicked(e -> onMenu());
|
||||||
|
menuButton.setClip(new Rectangle(211, -100, 100, 200));
|
||||||
StackPane graphic = new StackPane();
|
StackPane graphic = new StackPane();
|
||||||
Node svg = SVG.triangle(Theme.whiteFillBinding(), 10, 10);
|
Node svg = SVG.triangle(Theme.whiteFillBinding(), 10, 10);
|
||||||
StackPane.setAlignment(svg, Pos.CENTER_RIGHT);
|
StackPane.setAlignment(svg, Pos.CENTER_RIGHT);
|
||||||
graphic.getChildren().setAll(svg);
|
graphic.getChildren().setAll(svg);
|
||||||
graphic.setTranslateX(12);
|
graphic.setTranslateX(12);
|
||||||
btnMenu.setGraphic(graphic);
|
menuButton.setGraphic(graphic);
|
||||||
|
|
||||||
FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), version -> {
|
launchPane.getChildren().setAll(launchButton, separator, menuButton);
|
||||||
if (version != null) {
|
|
||||||
lblCurrentGame.setText(version);
|
|
||||||
} else {
|
|
||||||
lblCurrentGame.setText(i18n("version.empty"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Profiles.registerVersionsListener(this::loadVersions);
|
|
||||||
|
|
||||||
setOnDragOver(event -> {
|
|
||||||
if (event.getGestureSource() != this && event.getDragboard().hasFiles()) {
|
|
||||||
if (event.getDragboard().getFiles().stream().anyMatch(it -> "zip".equals(FileUtils.getExtension(it))))
|
|
||||||
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
|
|
||||||
}
|
|
||||||
event.consume();
|
|
||||||
});
|
|
||||||
|
|
||||||
setOnDragDropped(event -> {
|
|
||||||
List<File> files = event.getDragboard().getFiles();
|
|
||||||
if (files != null) {
|
|
||||||
List<File> modpacks = files.stream()
|
|
||||||
.filter(it -> "zip".equals(FileUtils.getExtension(it)))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
if (!modpacks.isEmpty()) {
|
|
||||||
File modpack = modpacks.get(0);
|
|
||||||
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(modpack), i18n("install.modpack"));
|
|
||||||
event.setDropCompleted(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
event.consume();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadVersions(Profile profile) {
|
getChildren().setAll(updatePane, launchPane);
|
||||||
HMCLGameRepository repository = profile.getRepository();
|
|
||||||
List<Node> children = repository.getVersions().parallelStream()
|
menu.setMaxHeight(365);
|
||||||
.filter(version -> !version.isHidden())
|
menu.setMaxWidth(545);
|
||||||
.sorted(Comparator.comparing(Version::getReleaseTime).thenComparing(a -> VersionNumber.asVersion(a.getId())))
|
menu.setAlwaysShowingVBar(true);
|
||||||
.map(version -> {
|
menu.setOnMouseClicked(e -> popup.hide());
|
||||||
StackPane pane = new StackPane();
|
Bindings.bindContent(menu.getContent(), versions);
|
||||||
GameItem item = new GameItem(profile, version.getId());
|
}
|
||||||
pane.getChildren().setAll(item);
|
|
||||||
pane.getStyleClass().setAll("menu-container");
|
private void doAnimation(boolean show) {
|
||||||
item.setMouseTransparent(true);
|
Duration duration = Duration.millis(320);
|
||||||
RipplerContainer container = new RipplerContainer(pane);
|
Timeline nowAnimation = new Timeline();
|
||||||
container.setOnMouseClicked(e -> {
|
nowAnimation.getKeyFrames().addAll(
|
||||||
profile.setSelectedVersion(version.getId());
|
new KeyFrame(Duration.ZERO,
|
||||||
popup.hide();
|
new KeyValue(updatePane.translateXProperty(), show ? 260 : 0, SINE)),
|
||||||
});
|
new KeyFrame(duration,
|
||||||
return container;
|
new KeyValue(updatePane.translateXProperty(), show ? 0 : 260, SINE)));
|
||||||
})
|
if (show) nowAnimation.getKeyFrames().add(
|
||||||
.collect(Collectors.toList());
|
new KeyFrame(Duration.ZERO, e -> updatePane.setVisible(true)));
|
||||||
JFXUtilities.runInFX(() -> {
|
else nowAnimation.getKeyFrames().add(
|
||||||
if (profile == Profiles.getSelectedProfile())
|
new KeyFrame(duration, e -> updatePane.setVisible(false)));
|
||||||
menu.getContent().setAll(children);
|
nowAnimation.play();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void launch() {
|
private void launch() {
|
||||||
Profile profile = Profiles.getSelectedProfile();
|
Profile profile = Profiles.getSelectedProfile();
|
||||||
Versions.launch(profile, profile.getSelectedVersion());
|
Versions.launch(profile, profile.getSelectedVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void onMenu() {
|
private void onMenu() {
|
||||||
popup.show(btnMenu, JFXPopup.PopupVPosition.BOTTOM, JFXPopup.PopupHPosition.RIGHT, 0, -btnMenu.getHeight());
|
popup.show(menuButton, JFXPopup.PopupVPosition.BOTTOM, JFXPopup.PopupHPosition.RIGHT, 0, -menuButton.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void onUpgrade() {
|
private void onUpgrade() {
|
||||||
RemoteVersion target = UpdateChecker.getLatestVersion();
|
RemoteVersion target = UpdateChecker.getLatestVersion();
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
@@ -206,6 +200,11 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
UpdateHandler.updateFrom(target);
|
UpdateHandler.updateFrom(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void closeUpdateBubble() {
|
||||||
|
showUpdate.unbind();
|
||||||
|
showUpdate.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title.get();
|
return title.get();
|
||||||
}
|
}
|
||||||
@@ -218,4 +217,44 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
public void setTitle(String title) {
|
public void setTitle(String title) {
|
||||||
this.title.set(title);
|
this.title.set(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCurrentGame() {
|
||||||
|
return currentGame.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringProperty currentGameProperty() {
|
||||||
|
return currentGame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentGame(String currentGame) {
|
||||||
|
this.currentGame.set(currentGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShowUpdate() {
|
||||||
|
return showUpdate.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanProperty showUpdateProperty() {
|
||||||
|
return showUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowUpdate(boolean showUpdate) {
|
||||||
|
this.showUpdate.set(showUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLatestVersion() {
|
||||||
|
return latestVersion.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringProperty latestVersionProperty() {
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLatestVersion(String latestVersion) {
|
||||||
|
this.latestVersion.set(latestVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableList<Node> getVersions() {
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import javafx.scene.control.Control;
|
|||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.Skin;
|
import javafx.scene.control.Skin;
|
||||||
import javafx.scene.control.SkinBase;
|
import javafx.scene.control.SkinBase;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
|
|
||||||
@@ -60,6 +61,14 @@ public class PopupMenu extends Control {
|
|||||||
return new PopupMenuSkin();
|
return new PopupMenuSkin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Node wrapPopupMenuItem(Node node) {
|
||||||
|
StackPane pane = new StackPane();
|
||||||
|
pane.getChildren().setAll(node);
|
||||||
|
pane.getStyleClass().setAll("menu-container");
|
||||||
|
node.setMouseTransparent(true);
|
||||||
|
return new RipplerContainer(pane);
|
||||||
|
}
|
||||||
|
|
||||||
private class PopupMenuSkin extends SkinBase<PopupMenu> {
|
private class PopupMenuSkin extends SkinBase<PopupMenu> {
|
||||||
|
|
||||||
protected PopupMenuSkin() {
|
protected PopupMenuSkin() {
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import com.jfoenix.controls.JFXButton?>
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.image.Image?>
|
|
||||||
<?import javafx.scene.image.ImageView?>
|
|
||||||
<?import javafx.scene.layout.*?>
|
|
||||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
|
||||||
<fx:root xmlns="http://javafx.com/javafx"
|
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
|
||||||
styleClass="transparent"
|
|
||||||
style="-fx-padding: 10 16 10 16;"
|
|
||||||
type="StackPane" pickOnBounds="false">
|
|
||||||
<BorderPane pickOnBounds="false">
|
|
||||||
<left>
|
|
||||||
<HBox alignment="CENTER" mouseTransparent="true">
|
|
||||||
<StackPane fx:id="imageViewContainer" FXUtils.limitWidth="32" FXUtils.limitHeight="32">
|
|
||||||
<ImageView preserveRatio="true" fx:id="imageView" smooth="false">
|
|
||||||
<Image url="/assets/img/icon.png" />
|
|
||||||
</ImageView>
|
|
||||||
</StackPane>
|
|
||||||
<BorderPane style="-fx-padding: 0 0 0 10;">
|
|
||||||
<top>
|
|
||||||
<Label fx:id="lblTitle" maxWidth="90" style="-fx-font-size: 15;" textAlignment="JUSTIFY" />
|
|
||||||
</top>
|
|
||||||
<bottom>
|
|
||||||
<Label fx:id="lblSubtitle" maxWidth="90" style="-fx-font-size: 10;" textAlignment="JUSTIFY" />
|
|
||||||
</bottom>
|
|
||||||
</BorderPane>
|
|
||||||
</HBox>
|
|
||||||
</left>
|
|
||||||
<right>
|
|
||||||
<HBox alignment="CENTER" pickOnBounds="false">
|
|
||||||
<JFXButton fx:id="btnSettings" maxWidth="40" minWidth="40" prefWidth="40" styleClass="toggle-icon4">
|
|
||||||
<graphic>
|
|
||||||
<fx:include source="/assets/svg/gear.fxml" />
|
|
||||||
</graphic>
|
|
||||||
</JFXButton>
|
|
||||||
</HBox>
|
|
||||||
</right>
|
|
||||||
</BorderPane>
|
|
||||||
</fx:root>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import com.jfoenix.controls.JFXButton?>
|
|
||||||
<?import javafx.scene.layout.StackPane?>
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<?import javafx.scene.shape.Rectangle?>
|
|
||||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
|
||||||
<?import javafx.geometry.Insets?>
|
|
||||||
<?import org.jackhuang.hmcl.ui.construct.TwoLineListItem?>
|
|
||||||
<?import javafx.scene.layout.HBox?>
|
|
||||||
<fx:root type="StackPane" pickOnBounds="false"
|
|
||||||
xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1">
|
|
||||||
<StackPane fx:id="main" style="-fx-padding: 25;">
|
|
||||||
<StackPane fx:id="updatePane" styleClass="bubble" FXUtils.limitWidth="230" FXUtils.limitHeight="55"
|
|
||||||
onMouseClicked="#onUpgrade" StackPane.alignment="TOP_RIGHT">
|
|
||||||
<HBox StackPane.alignment="CENTER_LEFT" alignment="CENTER_LEFT" spacing="12">
|
|
||||||
<Label fx:id="lblIcon" />
|
|
||||||
<TwoLineListItem titleFill="white" subtitleFill="white" subtitle="%update.bubble.subtitle" fx:id="lblLatestVersion" pickOnBounds="false"
|
|
||||||
style="-jfx-title-font-weight: BOLD;" />
|
|
||||||
|
|
||||||
<StackPane.margin>
|
|
||||||
<Insets left="16" top="9" right="12" bottom="9" />
|
|
||||||
</StackPane.margin>
|
|
||||||
</HBox>
|
|
||||||
|
|
||||||
<JFXButton fx:id="closeUpdateButton" StackPane.alignment="TOP_RIGHT" styleClass="toggle-icon-tiny">
|
|
||||||
<StackPane.margin>
|
|
||||||
<Insets topRightBottomLeft="5" />
|
|
||||||
</StackPane.margin>
|
|
||||||
</JFXButton>
|
|
||||||
</StackPane>
|
|
||||||
|
|
||||||
<StackPane maxWidth="230" maxHeight="55" StackPane.alignment="BOTTOM_RIGHT">
|
|
||||||
<JFXButton prefWidth="230" prefHeight="55" buttonType="RAISED" styleClass="jfx-button-raised"
|
|
||||||
onMouseClicked="#launch" fx:id="btnLaunch">
|
|
||||||
<graphic>
|
|
||||||
<VBox alignment="CENTER" translateX="-7" maxWidth="200">
|
|
||||||
<Label style="-fx-font-size: 16;" text="%version.launch"/>
|
|
||||||
<Label style="-fx-font-size: 12px;" fx:id="lblCurrentGame"/>
|
|
||||||
</VBox>
|
|
||||||
</graphic>
|
|
||||||
</JFXButton>
|
|
||||||
<Rectangle fx:id="separator" translateX="95" height="57" styleClass="darker-fill" width="1" mouseTransparent="true"/>
|
|
||||||
<JFXButton prefWidth="230" prefHeight="55" buttonType="RAISED" styleClass="jfx-button-raised"
|
|
||||||
style="-fx-font-size: 15;" onMouseClicked="#onMenu" fx:id="btnMenu" />
|
|
||||||
</StackPane>
|
|
||||||
</StackPane>
|
|
||||||
</fx:root>
|
|
||||||
@@ -165,8 +165,8 @@ launcher=Launcher
|
|||||||
launcher.background=Background Image
|
launcher.background=Background Image
|
||||||
launcher.background.choose=Choose background path.
|
launcher.background.choose=Choose background path.
|
||||||
launcher.background.default=Default
|
launcher.background.default=Default
|
||||||
launcher.common_directory=Cache Directory (Store downloaded files)
|
launcher.common_directory=Download Cache Directory
|
||||||
launcher.common_directory.choose=Choose cache directory.
|
launcher.common_directory.choose=Choose download cache directory
|
||||||
launcher.common_directory.default=Default
|
launcher.common_directory.default=Default
|
||||||
launcher.common_directory.disabled=Disabled
|
launcher.common_directory.disabled=Disabled
|
||||||
launcher.contact=Contact Us
|
launcher.contact=Contact Us
|
||||||
|
|||||||
@@ -165,8 +165,8 @@ launcher=啟動器
|
|||||||
launcher.background=背景位址
|
launcher.background=背景位址
|
||||||
launcher.background.choose=選擇背景路徑
|
launcher.background.choose=選擇背景路徑
|
||||||
launcher.background.default=預設(自動尋找啟動器同目錄下的 background.png/jpg 及 bg 資料夾內的圖片)
|
launcher.background.default=預設(自動尋找啟動器同目錄下的 background.png/jpg 及 bg 資料夾內的圖片)
|
||||||
launcher.common_directory=緩存目錄(檔案下載緩存)
|
launcher.common_directory=檔案下載緩存目錄
|
||||||
launcher.common_directory.choose=選擇緩存目錄
|
launcher.common_directory.choose=選擇檔案下載緩存目錄
|
||||||
launcher.common_directory.default=預設
|
launcher.common_directory.default=預設
|
||||||
launcher.common_directory.disabled=停用
|
launcher.common_directory.disabled=停用
|
||||||
launcher.contact=聯絡我們
|
launcher.contact=聯絡我們
|
||||||
|
|||||||
@@ -165,8 +165,8 @@ launcher=启动器
|
|||||||
launcher.background=背景地址
|
launcher.background=背景地址
|
||||||
launcher.background.choose=选择背景路径
|
launcher.background.choose=选择背景路径
|
||||||
launcher.background.default=默认(自动检索启动器同目录下的 background.png/jpg 及 bg 文件夹内的图片)
|
launcher.background.default=默认(自动检索启动器同目录下的 background.png/jpg 及 bg 文件夹内的图片)
|
||||||
launcher.common_directory=缓存目录(文件下载缓存)
|
launcher.common_directory=文件下载缓存目录
|
||||||
launcher.common_directory.choose=选择缓存目录
|
launcher.common_directory.choose=选择文件下载缓存目录
|
||||||
launcher.common_directory.default=默认(%AppData%/.minecraft 或者 ~/.minecraft)
|
launcher.common_directory.default=默认(%AppData%/.minecraft 或者 ~/.minecraft)
|
||||||
launcher.common_directory.disabled=禁用(总是使用游戏路径)
|
launcher.common_directory.disabled=禁用(总是使用游戏路径)
|
||||||
launcher.contact=联系我们
|
launcher.contact=联系我们
|
||||||
|
|||||||
BIN
lib/JFoenix.jar
BIN
lib/JFoenix.jar
Binary file not shown.
Reference in New Issue
Block a user