mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 10:25:06 -04:00
way improved account login dialog
This commit is contained in:
parent
d8ce48f102
commit
569b9f4ba4
@ -198,6 +198,7 @@ public final class Minosoft {
|
||||
config.saveToFile();
|
||||
return;
|
||||
}
|
||||
if (account.needsRefresh()) {
|
||||
MojangAccount.RefreshStates refreshState = account.refreshToken();
|
||||
if (refreshState == MojangAccount.RefreshStates.ERROR) {
|
||||
account.delete();
|
||||
@ -205,6 +206,7 @@ public final class Minosoft {
|
||||
selectedAccount = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
config.putString(ConfigurationPaths.StringPaths.ACCOUNT_SELECTED, account.getUserId());
|
||||
if (Launcher.getMainWindow() != null) {
|
||||
Launcher.getMainWindow().selectAccount(selectedAccount);
|
||||
|
@ -80,6 +80,7 @@ public enum Strings {
|
||||
|
||||
LOGIN_DIALOG_TITLE,
|
||||
LOGIN_DIALOG_HEADER,
|
||||
LOGIN_ACCOUNT_ALREADY_PRESENT,
|
||||
|
||||
MINOSOFT_STILL_STARTING_TITLE,
|
||||
MINOSOFT_STILL_STARTING_HEADER,
|
||||
|
@ -13,27 +13,19 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.main;
|
||||
|
||||
import com.jfoenix.controls.*;
|
||||
import de.bixilon.minosoft.Minosoft;
|
||||
import de.bixilon.minosoft.data.locale.LocaleManager;
|
||||
import de.bixilon.minosoft.data.locale.Strings;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.util.mojang.api.MojangAccount;
|
||||
import de.bixilon.minosoft.util.mojang.api.MojangAccountAuthenticationAttempt;
|
||||
import de.bixilon.minosoft.util.mojang.api.MojangAuthentication;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.Modality;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@ -55,72 +47,11 @@ public class AccountWindow implements Initializable {
|
||||
|
||||
@FXML
|
||||
public void addAccount() {
|
||||
JFXAlert<?> dialog = new JFXAlert<>();
|
||||
dialog.setTitle(LocaleManager.translate(Strings.LOGIN_DIALOG_TITLE));
|
||||
GUITools.initializePane(dialog.getDialogPane());
|
||||
JFXDialogLayout layout = new JFXDialogLayout();
|
||||
layout.setHeading(new Label(LocaleManager.translate(Strings.LOGIN_DIALOG_HEADER)));
|
||||
|
||||
JFXButton loginButton = new JFXButton(LocaleManager.translate(Strings.BUTTON_LOGIN));
|
||||
layout.setActions(loginButton);
|
||||
|
||||
GridPane gridPane = new GridPane();
|
||||
gridPane.setHgap(15);
|
||||
gridPane.setVgap(15);
|
||||
|
||||
JFXTextField emailField = new JFXTextField();
|
||||
emailField.setPromptText(LocaleManager.translate(Strings.EMAIL));
|
||||
|
||||
JFXPasswordField passwordField = new JFXPasswordField();
|
||||
passwordField.setPromptText(LocaleManager.translate(Strings.PASSWORD));
|
||||
|
||||
gridPane.add(new Label(LocaleManager.translate(Strings.EMAIL) + ":"), 0, 0);
|
||||
gridPane.add(emailField, 1, 0);
|
||||
gridPane.add(new Label(LocaleManager.translate(Strings.PASSWORD) + ":"), 0, 1);
|
||||
gridPane.add(passwordField, 1, 1);
|
||||
|
||||
emailField.textProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue.trim().isEmpty()));
|
||||
loginButton.setDisable(true);
|
||||
|
||||
layout.setBody(gridPane);
|
||||
dialog.setContent(layout);
|
||||
|
||||
Platform.runLater(emailField::requestFocus);
|
||||
loginButton.addEventFilter(ActionEvent.ACTION, event -> {
|
||||
MojangAccountAuthenticationAttempt attempt = MojangAuthentication.login(emailField.getText(), passwordField.getText());
|
||||
if (attempt.succeeded()) {
|
||||
// login okay
|
||||
MojangAccount account = attempt.getAccount();
|
||||
Minosoft.getConfig().putMojangAccount(account);
|
||||
account.saveToConfig();
|
||||
AccountListCell.MOJANG_ACCOUNT_LIST_VIEW.getItems().add(account);
|
||||
Log.info(String.format("Added and saved account (playerName=%s, email=%s, uuid=%s)", account.getPlayerName(), account.getMojangUserName(), account.getUUID()));
|
||||
dialog.close();
|
||||
return;
|
||||
}
|
||||
event.consume();
|
||||
Label error = new Label();
|
||||
error.setStyle("-fx-text-fill: red");
|
||||
error.setText(attempt.getError());
|
||||
|
||||
gridPane.add(new Label(LocaleManager.translate(Strings.ERROR)), 0, 2);
|
||||
gridPane.add(error, 1, 2);
|
||||
// ToDo resize window
|
||||
});
|
||||
|
||||
Window window = dialog.getDialogPane().getScene().getWindow();
|
||||
window.setOnCloseRequest(windowEvent -> window.hide());
|
||||
|
||||
dialog.getDialogPane().setOnKeyReleased(keyEvent -> {
|
||||
if (keyEvent.getCode() != KeyCode.ENTER) {
|
||||
return;
|
||||
}
|
||||
if (emailField.getText().trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
loginButton.fire();
|
||||
});
|
||||
|
||||
dialog.showAndWait();
|
||||
try {
|
||||
GUITools.showPane("/layout/dialogs/login_mojang.fxml", Modality.APPLICATION_MODAL, LocaleManager.translate(Strings.LOGIN_DIALOG_TITLE));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,16 @@ import de.bixilon.minosoft.data.mappings.versions.Versions;
|
||||
import de.bixilon.minosoft.logging.LogLevels;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
@ -82,4 +86,25 @@ public class GUITools {
|
||||
initializeScene(pane.getScene());
|
||||
return pane;
|
||||
}
|
||||
|
||||
public static <T> T showPane(String fxmlPath, Modality modality, String title) throws IOException {
|
||||
FXMLLoader loader = new FXMLLoader(GUITools.class.getResource(fxmlPath));
|
||||
Parent root = loader.load();
|
||||
Stage stage = new Stage();
|
||||
stage.initModality(modality);
|
||||
double width = 600;
|
||||
double height = 400;
|
||||
if (root instanceof Pane pane) {
|
||||
width = pane.getPrefWidth();
|
||||
height = pane.getPrefHeight();
|
||||
}
|
||||
Scene scene = new Scene(root, width, height);
|
||||
stage.setScene(scene);
|
||||
|
||||
stage.setTitle(title);
|
||||
initializeScene(scene);
|
||||
|
||||
stage.show();
|
||||
return loader.getController();
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +37,6 @@ import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
@ -48,7 +46,6 @@ import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextFlow;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
@ -418,15 +415,8 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
|
||||
|
||||
public void manageSessions() {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/layout/sessions.fxml"));
|
||||
Parent parent = loader.load();
|
||||
((SessionsWindow) loader.getController()).setServer(this.server);
|
||||
Stage stage = new Stage();
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
stage.setTitle(LocaleManager.translate(Strings.SESSIONS_DIALOG_TITLE, this.server.getName()));
|
||||
stage.setScene(new Scene(parent));
|
||||
GUITools.initializeScene(stage.getScene());
|
||||
stage.show();
|
||||
SessionsWindow sessionsWindow = GUITools.showPane("/layout/dialogs/login_mojang.fxml", Modality.APPLICATION_MODAL, LocaleManager.translate(Strings.SESSIONS_DIALOG_TITLE, this.server.getName()));
|
||||
sessionsWindow.setServer(this.server);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.main.dialogs;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXPasswordField;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import de.bixilon.minosoft.Minosoft;
|
||||
import de.bixilon.minosoft.data.locale.LocaleManager;
|
||||
import de.bixilon.minosoft.data.locale.Strings;
|
||||
import de.bixilon.minosoft.gui.main.AccountListCell;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.util.mojang.api.MojangAccount;
|
||||
import de.bixilon.minosoft.util.mojang.api.MojangAccountAuthenticationAttempt;
|
||||
import de.bixilon.minosoft.util.mojang.api.MojangAuthentication;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class MojangLoginController implements Initializable {
|
||||
public HBox hBox;
|
||||
public Label header;
|
||||
public Label emailLabel;
|
||||
public JFXTextField email;
|
||||
public Label passwordLabel;
|
||||
public JFXPasswordField password;
|
||||
public JFXButton loginButton;
|
||||
public Label errorMessage;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
// translate
|
||||
|
||||
this.header.setText(LocaleManager.translate(Strings.LOGIN_DIALOG_HEADER));
|
||||
this.emailLabel.setText(LocaleManager.translate(Strings.EMAIL));
|
||||
this.passwordLabel.setText(LocaleManager.translate(Strings.PASSWORD));
|
||||
this.loginButton.setText(LocaleManager.translate(Strings.BUTTON_LOGIN));
|
||||
|
||||
|
||||
this.email.textProperty().addListener(this::checkData);
|
||||
this.password.textProperty().addListener(this::checkData);
|
||||
|
||||
|
||||
this.hBox.setOnKeyReleased(keyEvent -> {
|
||||
if (keyEvent.getCode() == KeyCode.ENTER) {
|
||||
if (this.loginButton.isDisable()) {
|
||||
return;
|
||||
}
|
||||
this.loginButton.fire();
|
||||
return;
|
||||
}
|
||||
if (keyEvent.getCode() == KeyCode.ESCAPE) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void login(ActionEvent event) {
|
||||
event.consume();
|
||||
this.email.setDisable(true);
|
||||
this.password.setDisable(true);
|
||||
this.loginButton.setDisable(true);
|
||||
this.errorMessage.setVisible(false);
|
||||
|
||||
|
||||
new Thread(() -> { // ToDo: recycle thread
|
||||
MojangAccountAuthenticationAttempt attempt = MojangAuthentication.login(this.email.getText(), this.password.getText());
|
||||
if (attempt.succeeded()) {
|
||||
// login okay
|
||||
final MojangAccount account = attempt.getAccount();
|
||||
if (Minosoft.getConfig().getAccountList().containsValue(account)) {
|
||||
// account already present
|
||||
// replace access token
|
||||
MojangAccount existingAccount = Minosoft.getConfig().getAccountList().get(account.getUserId());
|
||||
existingAccount.setAccessToken(attempt.getAccount().getAccessToken());
|
||||
existingAccount.saveToConfig();
|
||||
Platform.runLater(() -> {
|
||||
this.errorMessage.setText(LocaleManager.translate(Strings.LOGIN_ACCOUNT_ALREADY_PRESENT));
|
||||
this.errorMessage.setVisible(true);
|
||||
this.email.setDisable(false);
|
||||
this.password.setDisable(false);
|
||||
this.loginButton.setDisable(true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
Minosoft.getConfig().putMojangAccount(account);
|
||||
account.saveToConfig();
|
||||
Log.info(String.format("Added and saved account (playerName=%s, email=%s, uuid=%s)", account.getPlayerName(), account.getMojangUserName(), account.getUUID()));
|
||||
Platform.runLater(() -> {
|
||||
AccountListCell.MOJANG_ACCOUNT_LIST_VIEW.getItems().add(account);
|
||||
close();
|
||||
});
|
||||
if (Minosoft.getSelectedAccount() == null) {
|
||||
// select account
|
||||
Minosoft.selectAccount(account);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
this.errorMessage.setText(attempt.getError());
|
||||
this.errorMessage.setVisible(true);
|
||||
this.email.setDisable(false);
|
||||
this.password.setDisable(false);
|
||||
this.loginButton.setDisable(true);
|
||||
});
|
||||
}, "AccountLoginThread").start();
|
||||
|
||||
}
|
||||
|
||||
private void checkData(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
|
||||
if (newValue.isEmpty()) {
|
||||
this.loginButton.setDisable(true);
|
||||
return;
|
||||
}
|
||||
this.loginButton.setDisable(this.email.getText().isBlank() || this.password.getText().isBlank());
|
||||
}
|
||||
|
||||
public void close() {
|
||||
getStage().close();
|
||||
}
|
||||
|
||||
public Stage getStage() {
|
||||
return ((Stage) this.hBox.getScene().getWindow());
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ public class MojangAccount {
|
||||
final String mojangUserName;
|
||||
String accessToken;
|
||||
RefreshStates lastRefreshStatus;
|
||||
private boolean needsRefresh = true;
|
||||
|
||||
public MojangAccount(String username, JsonObject json) {
|
||||
this.accessToken = json.get("accessToken").getAsString();
|
||||
@ -137,6 +138,15 @@ public class MojangAccount {
|
||||
return account.getUserId().equals(getUserId());
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
this.needsRefresh = false;
|
||||
}
|
||||
|
||||
public boolean needsRefresh() {
|
||||
return this.needsRefresh;
|
||||
}
|
||||
|
||||
public enum RefreshStates {
|
||||
SUCCESSFUL,
|
||||
ERROR, // account not valid anymore
|
||||
|
@ -56,6 +56,7 @@ public final class MojangAuthentication {
|
||||
return new MojangAccountAuthenticationAttempt(new MojangAccount(username, jsonResponse));
|
||||
}
|
||||
|
||||
|
||||
public static void joinServer(MojangAccount account, String serverId) {
|
||||
if (StaticConfiguration.SKIP_MOJANG_AUTHENTICATION) {
|
||||
return;
|
||||
|
@ -54,8 +54,9 @@
|
||||
"SETTINGS_GENERAL": "Allgemein",
|
||||
"SETTINGS_GENERAL_LOG_LEVEL": "Log Level",
|
||||
"SETTINGS_DOWNLOAD": "Download",
|
||||
"LOGIN_DIALOG_TITLE": "Anmelden - Minosoft",
|
||||
"LOGIN_DIALOG_HEADER": "Bitte gib deine Minecraft Zugangsdaten ein dich anzumelden",
|
||||
"LOGIN_DIALOG_TITLE": "Anmelden (Mojang) - Minosoft",
|
||||
"LOGIN_DIALOG_HEADER": "Bitte gib deine Mojang Zugangsdaten ein dich anzumelden",
|
||||
"LOGIN_ACCOUNT_ALREADY_PRESENT": "Account existiert bereits!",
|
||||
"ERROR": "Fehler",
|
||||
"MINOSOFT_STILL_STARTING_TITLE": "Bitte warten",
|
||||
"MINOSOFT_STILL_STARTING_HEADER": "Minosoft muss noch ein paar Dinge erledigen, bevor du es verwenden kannst.\nBitte warte noch ein paar Sekunden...",
|
||||
|
@ -55,8 +55,9 @@
|
||||
"SETTINGS_GENERAL": "General",
|
||||
"SETTINGS_GENERAL_LOG_LEVEL": "Log level",
|
||||
"SETTINGS_DOWNLOAD": "Download",
|
||||
"LOGIN_DIALOG_TITLE": "Login - Minosoft",
|
||||
"LOGIN_DIALOG_TITLE": "Login (Mojang) - Minosoft",
|
||||
"LOGIN_DIALOG_HEADER": "Please login to your mojang account",
|
||||
"LOGIN_ACCOUNT_ALREADY_PRESENT": "Account is already present!",
|
||||
"ERROR": "Error",
|
||||
"MINOSOFT_STILL_STARTING_TITLE": "Please wait",
|
||||
"MINOSOFT_STILL_STARTING_HEADER": "Minosoft is still starting up...",
|
||||
|
72
src/main/resources/layout/dialogs/login_mojang.fxml
Normal file
72
src/main/resources/layout/dialogs/login_mojang.fxml
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.jfoenix.controls.JFXButton?>
|
||||
<?import com.jfoenix.controls.JFXPasswordField?>
|
||||
<?import com.jfoenix.controls.JFXTextField?>
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml/1" fx:id="hBox" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="de.bixilon.minosoft.gui.main.dialogs.MojangLoginController">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<GridPane HBox.hgrow="ALWAYS">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="ALWAYS"/>
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints vgrow="NEVER"/>
|
||||
<RowConstraints vgrow="ALWAYS"/>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS"/>
|
||||
<RowConstraints vgrow="ALWAYS"/>
|
||||
</rowConstraints>
|
||||
<Label fx:id="header" text="Please login to your mojang account" textAlignment="CENTER" GridPane.halignment="CENTER">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</GridPane.margin>
|
||||
<font>
|
||||
<Font size="23.0"/>
|
||||
</font>
|
||||
</Label>
|
||||
<GridPane GridPane.rowIndex="1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="NEVER"/>
|
||||
<ColumnConstraints hgrow="ALWAYS"/>
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints vgrow="ALWAYS"/>
|
||||
<RowConstraints vgrow="ALWAYS"/>
|
||||
</rowConstraints>
|
||||
<Label fx:id="emailLabel" text="EMAIL">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</GridPane.margin>
|
||||
</Label>
|
||||
<JFXTextField fx:id="email" GridPane.columnIndex="1">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</GridPane.margin>
|
||||
</JFXTextField>
|
||||
<Label fx:id="passwordLabel" text="PASSWORD" GridPane.rowIndex="1">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</GridPane.margin>
|
||||
</Label>
|
||||
<JFXPasswordField fx:id="password" minWidth="-Infinity" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.vgrow="ALWAYS">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</GridPane.margin>
|
||||
</JFXPasswordField>
|
||||
</GridPane>
|
||||
<JFXButton fx:id="loginButton" disable="true" maxHeight="Infinity" maxWidth="Infinity" mnemonicParsing="false" text="LOGIN" GridPane.rowIndex="3" onAction="#login">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</GridPane.margin>
|
||||
<font>
|
||||
<Font name="System Bold" size="31.0"/>
|
||||
</font>
|
||||
</JFXButton>
|
||||
<Label fx:id="errorMessage" styleClass="error" text="Error" textAlignment="CENTER" textFill="RED" visible="false" wrapText="true" GridPane.halignment="CENTER" GridPane.rowIndex="2"/>
|
||||
</GridPane>
|
||||
</HBox>
|
@ -37,7 +37,7 @@
|
||||
</Menu>
|
||||
</MenuBar>
|
||||
<AnchorPane VBox.vgrow="ALWAYS" styleClass="anchor-pane">
|
||||
<ScrollPane fitToHeight="true" fitToWidth="true" layoutX="14.0" layoutY="14.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="700.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<ScrollPane fitToHeight="true" fitToWidth="true" layoutX="14.0" layoutY="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<BorderPane fx:id="serversPane"/>
|
||||
</ScrollPane>
|
||||
</AnchorPane>
|
||||
|
@ -201,3 +201,7 @@
|
||||
.obfuscated {
|
||||
-fx-font-family: "Hack";
|
||||
}
|
||||
|
||||
.error {
|
||||
-fx-text-fill: red;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user