(IMPORTANT! read description) Merge pull request #166 from informatik-ag-ngl/f/clearable_textfield

Implemented ClearableTextField and redesigned UI.
TAKE CARE:
in order to use SceneBuilder further, you have to import the attached
JAR "CustomComponents.jar" into the SceneBuilder. If you don't do this,
Scenebuilder no longer can load FXML files that depend on a custom
component. If you are implementing another custom component, feel free
to add it to the jar.
Note however that SceneBuilder cannot load any components that rely on
libraries other than the standard Java library or the JavaFX standard.
Meaning that even if you are referencing another Envoy file, the
component will not be importable. Because of this, the
ClearableTextField is also present only in a slimmed down version, as
SceneBuilder additionally has problems when dealing with loading
resources.
This commit is contained in:
delvh 2020-07-02 18:06:43 +02:00 committed by GitHub
commit cf84dd33b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 771 additions and 422 deletions

View File

@ -0,0 +1,174 @@
package envoy.client.ui;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import envoy.client.data.Settings;
/**
* This class offers a text field that is automatically equipped with a clear
* button.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>ClearableTextField.java</strong><br>
* Created: <strong>25.06.2020</strong><br>
*
* @author Leon Hofmeister
* @since Envoy Client v0.1-beta
*/
public class ClearableTextField extends GridPane {
private final TextField textField;
private final Button clearButton;
/**
* Constructs a new {@code ClearableTextField} with no initial text and icon
* size 16.
*
* @since Envoy Client v0.1-beta
*/
public ClearableTextField() { this("", 16); }
/**
* Constructs a new {@code ClearableTextField} with initial text and a
* predetermined icon size.
*
* @param text the text that should be displayed by default
* @param size the size of the icon
* @since Envoy Client v0.1-beta
*/
public ClearableTextField(String text, int size) {
// initializing the textField and the button
textField = new TextField(text);
clearButton = new Button("",
new ImageView(IconUtil.load(
Settings.getInstance().getCurrentTheme().equals("dark") ? "/icons/clear_button_white.png" : "/icons/clear_button_black.png",
size)));
clearButton.setOnAction(e -> textField.clear());
clearButton.setFocusTraversable(false);
clearButton.getStyleClass().clear();
clearButton.setBackground(Background.EMPTY);
// Adding the two elements to the GridPane
add(textField, 0, 0, 2, 1);
add(clearButton, 1, 0, 1, 1);
// Setting the percent - widths of the two columns.
// Used to locate the button on the right.
final var columnConstraints = new ColumnConstraints();
columnConstraints.setPercentWidth(90);
getColumnConstraints().add(columnConstraints);
final var columnConstraints2 = new ColumnConstraints();
columnConstraints2.setPercentWidth(10);
getColumnConstraints().add(columnConstraints2);
}
/**
* @return the underlying {@code textField}
* @since Envoy Client v0.1-beta
*/
public TextField getTextField() { return textField; }
/**
* This method offers the freedom to perform custom actions when the
* {@code clearButton} has been pressed.
* <p>
* The default is
* <b><code> e -> {clearableTextField.getTextField().clear();}</code></b>
*
* @param onClearButtonAction the action that should be performed
* @since Envoy Client v0.1-beta
*/
public void setClearButtonListener(EventHandler<ActionEvent> onClearButtonAction) { clearButton.setOnAction(onClearButtonAction); }
/**
* @return the current property of the prompt text
* @see javafx.scene.control.TextInputControl#promptTextProperty()
* @since Envoy Client v0.1-beta
*/
public final StringProperty promptTextProperty() { return textField.promptTextProperty(); }
/**
* @return the current prompt text
* @see javafx.scene.control.TextInputControl#getPromptText()
* @since Envoy Client v0.1-beta
*/
public final String getPromptText() { return textField.getPromptText(); }
/**
* @param value the prompt text to display
* @see javafx.scene.control.TextInputControl#setPromptText(java.lang.String)
* @since Envoy Client v0.1-beta
*/
public final void setPromptText(String value) { textField.setPromptText(value); }
/**
* @return the current property of the tooltip
* @see javafx.scene.control.Control#tooltipProperty()
* @since Envoy Client v0.1-beta
*/
public final ObjectProperty<Tooltip> tooltipProperty() { return textField.tooltipProperty(); }
/**
* @param value the new tooltip
* @see javafx.scene.control.Control#setTooltip(javafx.scene.control.Tooltip)
* @since Envoy Client v0.1-beta
*/
public final void setTooltip(Tooltip value) { textField.setTooltip(value); }
/**
* @return the current tooltip
* @see javafx.scene.control.Control#getTooltip()
* @since Envoy Client v0.1-beta
*/
public final Tooltip getTooltip() { return textField.getTooltip(); }
/**
* @return the current property of the context menu
* @see javafx.scene.control.Control#contextMenuProperty()
* @since Envoy Client v0.1-beta
*/
public final ObjectProperty<ContextMenu> contextMenuProperty() { return textField.contextMenuProperty(); }
/**
* @param value the new context menu
* @see javafx.scene.control.Control#setContextMenu(javafx.scene.control.ContextMenu)
* @since Envoy Client v0.1-beta
*/
public final void setContextMenu(ContextMenu value) { textField.setContextMenu(value); }
/**
* @return the current context menu
* @see javafx.scene.control.Control#getContextMenu()
* @since Envoy Client v0.1-beta
*/
public final ContextMenu getContextMenu() { return textField.getContextMenu(); }
/**
* @param value whether this ClearableTextField should be editable
* @see javafx.scene.control.TextInputControl#setEditable(boolean)
* @since Envoy Client v0.1-beta
*/
public final void setEditable(boolean value) { textField.setEditable(value); }
/**
* @return the current property whether this ClearableTextField is editable
* @see javafx.scene.control.TextInputControl#editableProperty()
* @since Envoy Client v0.1-beta
*/
public final BooleanProperty editableProperty() { return textField.editableProperty(); }
/**
* @return whether this {@code ClearableTextField} is editable
* @see javafx.scene.control.TextInputControl#isEditable()
* @since Envoy Client v0.1-beta
*/
public final boolean isEditable() { return textField.isEditable(); }
}

View File

@ -1,82 +0,0 @@
package envoy.client.ui;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.PopupWindow.AnchorLocation;
import envoy.data.Message;
import envoy.data.Message.MessageStatus;
import envoy.data.User;
/**
* Displays a single message inside the message list.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>MessageListCell.java</strong><br>
* Created: <strong>28.03.2020</strong><br>
*
* @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta
*/
public class MessageListCell extends ListCell<Message> {
private final ListView<Message> listView;
private static User client;
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16);
/**
* @param listView the list view inside which this cell is contained
* @since Envoy Client v0.1-beta
*/
public MessageListCell(ListView<Message> listView) { this.listView = listView; }
/**
* Displays the text, the data of creation and the status of a message.
*
* @since Envoy v0.1-beta
*/
@Override
protected void updateItem(Message message, boolean empty) {
super.updateItem(message, empty);
if (empty || message == null) {
setText(null);
setGraphic(null);
} else {
// Creating the underlying VBox, the dateLabel and the textLabel
final var cell = new VBox(new Label(dateFormat.format(message.getCreationDate())));
final var textLabel = new Label(message.getText());
textLabel.setWrapText(true);
cell.getChildren().add(textLabel);
// Setting the message status icon and background color
if (message.getRecipientID() != client.getID()) {
final var statusIcon = new Label("", new ImageView(statusImages.get(message.getStatus())));
statusIcon.setPadding(new Insets(1, 0, 5, 5));
cell.getChildren().add(statusIcon);
cell.getStyleClass().add("own-message");
} else cell.getStyleClass().add("received-message");
// Adjusting height and weight of the cell to the corresponding ListView
cell.paddingProperty().setValue(new Insets(5, 20, 5, 20));
cell.prefWidthProperty().bind(listView.widthProperty().subtract(40));
// Creating the Tooltip to deselect a message
final var tooltip = new Tooltip("You can select a message by clicking on it \nand deselect it by pressing \"ctrl\" and clicking on it");
tooltip.setWrapText(true);
tooltip.setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT);
setTooltip(tooltip);
setGraphic(cell);
}
}
/**
* @param client the user who chats with another person
* @since Envoy Client v0.1-beta
*/
public static void setUser(User client) { MessageListCell.client = client; }
}

View File

@ -40,21 +40,21 @@ public final class SceneContext {
public enum SceneInfo {
/**
* The main scene in which chats are displayed.
* The main scene in which the chat screen is displayed.
*
* @since Envoy Client v0.1-beta
*/
CHAT_SCENE("/fxml/ChatScene.fxml"),
/**
* The scene in which settings are displayed.
* The scene in which the settings screen is displayed.
*
* @since Envoy Client v0.1-beta
*/
SETTINGS_SCENE("/fxml/SettingsScene.fxml"),
/**
* The scene in which the contact search is displayed.
* The scene in which the contact search screen is displayed.
*
* @since Envoy Client v0.1-beta
*/
@ -72,7 +72,14 @@ public final class SceneContext {
*
* @since Envoy Client v0.1-beta
*/
LOGIN_SCENE("/fxml/LoginScene.fxml");
LOGIN_SCENE("/fxml/LoginScene.fxml"),
/**
* The scene in which the info screen is displayed.
*
* @since Envoy Client v0.1-beta
*/
MESSAGE_INFO_SCENE("/fxml/MessageInfoScene.fxml");
/**
* The path to the FXML resource.

View File

@ -16,7 +16,6 @@ import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import envoy.client.data.Chat;
import envoy.client.data.LocalDB;
@ -24,7 +23,11 @@ import envoy.client.data.Settings;
import envoy.client.event.MessageCreationEvent;
import envoy.client.net.Client;
import envoy.client.net.WriteProxy;
import envoy.client.ui.*;
import envoy.client.ui.IconUtil;
import envoy.client.ui.SceneContext;
import envoy.client.ui.listcell.ContactListCellFactory;
import envoy.client.ui.listcell.MessageControl;
import envoy.client.ui.listcell.MessageListCellFactory;
import envoy.data.*;
import envoy.event.EventBus;
import envoy.event.MessageStatusChange;
@ -92,8 +95,8 @@ public final class ChatScene {
private void initialize() {
// Initialize message and user rendering
messageList.setCellFactory(MessageListCell::new);
userList.setCellFactory(ContactListCell::new);
messageList.setCellFactory(MessageListCellFactory::new);
userList.setCellFactory(ContactListCellFactory::new);
settingsButton.setGraphic(new ImageView(IconUtil.load("/icons/settings.png", 16)));
@ -166,8 +169,8 @@ public final class ChatScene {
userList.setItems(FXCollections.observableList(localDB.getChats().stream().map(Chat::getRecipient).collect(Collectors.toList())));
contactLabel.setText(localDB.getUser().getName());
MessageListCell.setUser(localDB.getUser());
if (!client.isOnline()) updateInfoLabel("You are offline", Color.YELLOW);
MessageControl.setUser(localDB.getUser());
if (!client.isOnline()) updateInfoLabel("You are offline", "infoLabel-info");
}
/**
@ -179,7 +182,6 @@ public final class ChatScene {
private void userListClicked() {
final Contact user = userList.getSelectionModel().getSelectedItem();
if (user != null && (currentChat == null || !user.equals(currentChat.getRecipient()))) {
logger.log(Level.FINEST, "Loading chat with " + user);
// LEON: JFC <===> JAVA FRIED CHICKEN <=/=> Java Foundation Classes
@ -187,6 +189,9 @@ public final class ChatScene {
currentChat = localDB.getChat(user.getID()).get();
messageList.setItems(FXCollections.observableList(currentChat.getMessages()));
final var scrollIndex = messageList.getItems().size() - 1;
messageList.scrollTo(scrollIndex);
logger.log(Level.FINEST, "Loading chat with " + user + " at index " + scrollIndex);
deleteContactMenuItem.setText("Delete " + user.getName());
// Read the current chat
@ -257,7 +262,7 @@ public final class ChatScene {
if (!infoLabel.getText().equals(noMoreMessaging))
// Informing the user that he is a f*cking moron and should use Envoy online
// because he ran out of messageIDs to use
updateInfoLabel(noMoreMessaging, Color.RED);
updateInfoLabel(noMoreMessaging, "infoLabel-error");
}
}
@ -302,7 +307,7 @@ public final class ChatScene {
postButton.setDisable(true);
messageTextArea.setDisable(true);
messageTextArea.clear();
updateInfoLabel("You need to go online to send more messages", Color.RED);
updateInfoLabel("You need to go online to send more messages", "infoLabel-error");
return;
}
final var text = messageTextArea.getText().strip();
@ -345,13 +350,14 @@ public final class ChatScene {
/**
* Updates the {@code infoLabel}.
*
* @param text the text to use
* @param textfill the color in which to display information
* @param text the text to use
* @param infoLabelID the id the the {@code infoLabel} should have so that it
* can be styled accordingly in CSS
* @since Envoy Client v0.1-beta
*/
private void updateInfoLabel(String text, Paint textfill) {
private void updateInfoLabel(String text, String infoLabelID) {
infoLabel.setText(text);
infoLabel.setTextFill(textfill);
infoLabel.setId(infoLabelID);
infoLabel.setVisible(true);
}
@ -387,4 +393,7 @@ public final class ChatScene {
updateRemainingCharsLabel();
postButton.setDisable(messageText.isBlank());
}
@FXML
private void loadMessageInfoScene() { try {} catch (final NullPointerException e) {} }
}

View File

@ -5,13 +5,16 @@ import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ListView;
import envoy.client.data.LocalDB;
import envoy.client.event.SendEvent;
import envoy.client.ui.ContactListCell;
import envoy.client.ui.ClearableTextField;
import envoy.client.ui.SceneContext;
import envoy.client.ui.listcell.ContactListCellFactory;
import envoy.data.Contact;
import envoy.event.ElementOperation;
import envoy.event.EventBus;
@ -31,19 +34,7 @@ import envoy.util.EnvoyLog;
public class ContactSearchScene {
@FXML
private Button backButton;
@FXML
private Button clearButton;
@FXML
private Button searchButton;
@FXML
private Button newGroupButton;
@FXML
private TextField searchBar;
private ClearableTextField searchBar;
@FXML
private ListView<Contact> contactList;
@ -67,7 +58,8 @@ public class ContactSearchScene {
@FXML
private void initialize() {
contactList.setCellFactory(ContactListCell::new);
contactList.setCellFactory(ContactListCellFactory::new);
searchBar.setClearButtonListener(e -> { searchBar.getTextField().clear(); contactList.getItems().clear(); });
eventBus.register(ContactSearchResult.class,
response -> Platform.runLater(() -> { contactList.getItems().clear(); contactList.getItems().addAll(response.get()); }));
}
@ -78,20 +70,12 @@ public class ContactSearchScene {
* @since Envoy Client v0.1-beta
*/
@FXML
private void checkClearButton() {
final var containsContent = searchBar.getText().strip().isEmpty();
clearButton.setDisable(containsContent);
searchButton.setDisable(containsContent);
private void sendRequest() {
final var text = searchBar.getTextField().getText().strip();
if (!text.isBlank()) eventBus.dispatch(new SendEvent(new ContactSearchRequest(text)));
else contactList.getItems().clear();
}
/**
* Sends a {@link ContactSearchRequest} to the server.
*
* @since Envoy Client v0.1-beta
*/
@FXML
private void suggestContacts() { eventBus.dispatch(new SendEvent(new ContactSearchRequest(searchBar.getText()))); }
/**
* Clears the text in the search bar and the items shown in the list.
* Additionally disables both clear and search button.
@ -100,10 +84,8 @@ public class ContactSearchScene {
*/
@FXML
private void clear() {
searchBar.setText(null);
searchBar.getTextField().setText(null);
contactList.getItems().clear();
clearButton.setDisable(true);
searchButton.setDisable(true);
}
/**

View File

@ -9,8 +9,9 @@ import javafx.scene.control.Alert.AlertType;
import envoy.client.data.LocalDB;
import envoy.client.event.SendEvent;
import envoy.client.ui.ContactListCell;
import envoy.client.ui.ClearableTextField;
import envoy.client.ui.SceneContext;
import envoy.client.ui.listcell.ContactListCellFactory;
import envoy.data.Contact;
import envoy.event.EventBus;
import envoy.event.GroupCreation;
@ -30,7 +31,7 @@ public class GroupCreationScene {
private Button createButton;
@FXML
private TextField groupNameField;
private ClearableTextField groupNameField;
@FXML
private ListView<Contact> contactList;
@ -41,8 +42,9 @@ public class GroupCreationScene {
@FXML
private void initialize() {
contactList.setCellFactory(ContactListCell::new);
contactList.setCellFactory(ContactListCellFactory::new);
contactList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
groupNameField.setClearButtonListener(e -> { groupNameField.getTextField().clear(); createButton.setDisable(true); });
}
/**
@ -63,7 +65,18 @@ public class GroupCreationScene {
* @since Envoy Client v0.1-beta
*/
@FXML
private void contactListClicked() { createButton.setDisable(contactList.getSelectionModel().isEmpty()); }
private void contactListClicked() {
createButton.setDisable(contactList.getSelectionModel().isEmpty() || groupNameField.getTextField().getText().isBlank());
}
/**
* Checks, whether the {@code createButton} can be enabled because text is
* present in the textfield.
*
* @since Envoy Client v0.1-beta
*/
@FXML
private void textUpdated() { createButton.setDisable(groupNameField.getTextField().getText().isBlank()); }
/**
* Sends a {@link GroupCreation} to the server and closes this scene.
@ -74,10 +87,10 @@ public class GroupCreationScene {
*/
@FXML
private void createButtonClicked() {
final var name = groupNameField.getText();
final var name = groupNameField.getTextField().getText();
if (!Bounds.isValidContactName(name)) {
new Alert(AlertType.ERROR, "The entered group name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
groupNameField.clear();
groupNameField.getTextField().clear();
} else {
eventBus.dispatch(new SendEvent(new GroupCreation(name,
contactList.getSelectionModel().getSelectedItems().stream().map(Contact::getID).collect(Collectors.toSet()))));

View File

@ -13,6 +13,7 @@ import javafx.scene.control.Alert.AlertType;
import envoy.client.data.*;
import envoy.client.net.Client;
import envoy.client.ui.ClearableTextField;
import envoy.client.ui.SceneContext;
import envoy.client.ui.Startup;
import envoy.data.LoginCredentials;
@ -38,7 +39,7 @@ import envoy.util.EnvoyLog;
public final class LoginScene {
@FXML
private TextField userTextField;
private ClearableTextField userTextField;
@FXML
private PasswordField passwordField;
@ -116,17 +117,17 @@ public final class LoginScene {
if (registerCheckBox.isSelected() && !passwordField.getText().equals(repeatPasswordField.getText())) {
new Alert(AlertType.ERROR, "The entered password is unequal to the repeated one").showAndWait();
repeatPasswordField.clear();
} else if (!Bounds.isValidContactName(userTextField.getText())) {
} else if (!Bounds.isValidContactName(userTextField.getTextField().getText())) {
new Alert(AlertType.ERROR, "The entered user name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
userTextField.clear();
} else
performHandshake(
new LoginCredentials(userTextField.getText(), passwordField.getText().toCharArray(), registerCheckBox.isSelected(), Startup.VERSION));
userTextField.getTextField().clear();
} else performHandshake(new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText().toCharArray(),
registerCheckBox.isSelected(), Startup.VERSION));
}
@FXML
private void offlineModeButtonPressed() {
attemptOfflineMode(new LoginCredentials(userTextField.getText(), passwordField.getText().toCharArray(), false, Startup.VERSION));
attemptOfflineMode(
new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText().toCharArray(), false, Startup.VERSION));
}
@FXML

View File

@ -0,0 +1,40 @@
package envoy.client.ui.listcell;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import envoy.data.Contact;
import envoy.data.Group;
import envoy.data.User;
/**
* This class formats a single {@link Contact} into a UI component.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>ContactControl.java</strong><br>
* Created: <strong>01.07.2020</strong><br>
*
* @author Leon Hofmeister
* @since Envoy Client v0.1-beta
*/
public class ContactControl extends VBox {
/**
* @param contact the contact that should be formatted
* @since Envoy Client v0.1-beta
*/
public ContactControl(Contact contact) {
// Container with contact name
final var nameLabel = new Label(contact.getName());
nameLabel.setWrapText(true);
getChildren().add(nameLabel);
if (contact instanceof User) {
// Online status
final var user = (User) contact;
final var statusLabel = new Label(user.getStatus().toString());
statusLabel.getStyleClass().add(user.getStatus().toString().toLowerCase());
getChildren().add(statusLabel);
} else // Member count
getChildren().add(new Label(((Group) contact).getContacts().size() + " members"));
}
}

View File

@ -1,13 +1,9 @@
package envoy.client.ui;
package envoy.client.ui.listcell;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import envoy.data.Contact;
import envoy.data.Group;
import envoy.data.User;
/**
* Project: <strong>envoy-client</strong><br>
@ -17,7 +13,7 @@ import envoy.data.User;
* @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta
*/
public class ContactListCell extends ListCell<Contact> {
public class ContactListCellFactory extends ListCell<Contact> {
private final ListView<Contact> listView;
@ -25,7 +21,7 @@ public class ContactListCell extends ListCell<Contact> {
* @param listView the list view inside which this cell is contained
* @since Envoy Client v0.1-beta
*/
public ContactListCell(ListView<Contact> listView) { this.listView = listView; }
public ContactListCellFactory(ListView<Contact> listView) { this.listView = listView; }
/**
* Displays the name of a contact. If the contact is a user, their online status
@ -40,20 +36,9 @@ public class ContactListCell extends ListCell<Contact> {
setText(null);
setGraphic(null);
} else {
// Container with contact name
final var nameLabel = new Label(contact.getName());
nameLabel.setWrapText(true);
final var vbox = new VBox(nameLabel);
if (contact instanceof User) {
// Online status
final var user = (User) contact;
final var statusLabel = new Label(user.getStatus().toString());
statusLabel.getStyleClass().add(user.getStatus().toString().toLowerCase());
vbox.getChildren().add(statusLabel);
} else // Member count
vbox.getChildren().add(new Label(((Group) contact).getContacts().size() + " members"));
final var control = new ContactControl(contact);
prefWidthProperty().bind(listView.widthProperty().subtract(40));
setGraphic(vbox);
setGraphic(control);
}
}
}

View File

@ -0,0 +1,60 @@
package envoy.client.ui.listcell;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import envoy.client.ui.IconUtil;
import envoy.data.Message;
import envoy.data.Message.MessageStatus;
import envoy.data.User;
/**
* This class formats a single {@link Message} into a UI component.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>MessageControl.java</strong><br>
* Created: <strong>01.07.2020</strong><br>
*
* @author Leon Hofmeister
* @since Envoy Client v0.1-beta
*/
public class MessageControl extends VBox {
private static User client;
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16);
/**
*
* @param message the message that should be formatted
* @since Envoy Client v0.1-beta
*/
public MessageControl(Message message) {
// Creating the underlying VBox, the dateLabel and the textLabel
super(new Label(dateFormat.format(message.getCreationDate())));
final var textLabel = new Label(message.getText());
textLabel.setWrapText(true);
getChildren().add(textLabel);
// Setting the message status icon and background color
if (message.getRecipientID() != client.getID()) {
final var statusIcon = new ImageView(statusImages.get(message.getStatus()));
statusIcon.setPreserveRatio(true);
getChildren().add(statusIcon);
getStyleClass().add("own-message");
} else getStyleClass().add("received-message");
// Adjusting height and weight of the cell to the corresponding ListView
paddingProperty().setValue(new Insets(5, 20, 5, 20));
}
/**
* @param client the user who has logged in
* @since Envoy Client v0.1-beta
*/
public static void setUser(User client) { MessageControl.client = client; }
}

View File

@ -0,0 +1,52 @@
package envoy.client.ui.listcell;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Tooltip;
import javafx.stage.PopupWindow.AnchorLocation;
import envoy.data.Message;
/**
* Displays a single message inside the message list.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>MessageListCellFactory.java</strong><br>
* Created: <strong>28.03.2020</strong><br>
*
* @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta
*/
public class MessageListCellFactory extends ListCell<Message> {
private final ListView<Message> listView;
/**
* @param listView the list view inside which this cell is contained
* @since Envoy Client v0.1-beta
*/
public MessageListCellFactory(ListView<Message> listView) { this.listView = listView; }
/**
* Displays the text, the data of creation and the status of a message.
*
* @since Envoy v0.1-beta
*/
@Override
protected void updateItem(Message message, boolean empty) {
super.updateItem(message, empty);
if (empty || message == null) {
setText(null);
setGraphic(null);
} else {
final var control = new MessageControl(message);
control.prefWidthProperty().bind(listView.widthProperty().subtract(40));
// Creating the Tooltip to deselect a message
final var tooltip = new Tooltip("You can select a message by clicking on it \nand deselect it by pressing \"ctrl\" and clicking on it");
tooltip.setWrapText(true);
tooltip.setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT);
setTooltip(tooltip);
setGraphic(control);
}
}
}

View File

@ -0,0 +1,12 @@
/**
* This package contains custom list cells that are used to display certain
* things.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>package-info.java</strong><br>
* Created: <strong>30.06.2020</strong><br>
*
* @author Leon Hofmeister
* @since Envoy Client v0.1-beta
*/
package envoy.client.ui.listcell;

Binary file not shown.

View File

@ -3,7 +3,7 @@
}
.context-menu, .context-menu > * {
-fx-background-radius: 15px;
-fx-background-radius: 15.0px;
/*TODO: solution below does not work */
-fx-background-color: transparent;
}
@ -58,3 +58,19 @@
-fx-text-fill: #00FF00;
-fx-background-color: transparent;
}
#infoLabel-success {
-fx-text-fill: #00FF00;
}
#infoLabel-info {
-fx-text-fill: yellow;
}
#infoLabel-warning {
-fx-text-fill: orange;
}
#infoLabel-error {
-fx-text-fill: red;
}

View File

@ -12,9 +12,9 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity"
<GridPane hgap="5.0" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="400.0" minWidth="350.0" prefHeight="400.0" prefWidth="600.0"
xmlns="http://javafx.com/javafx/11.0.1"
vgap="2.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="envoy.client.ui.controller.ChatScene">
<columnConstraints>
@ -47,7 +47,7 @@
prefHeight="211.0" prefWidth="300.0" GridPane.rowIndex="1"
GridPane.rowSpan="2147483647">
<GridPane.margin>
<Insets bottom="10.0" left="10.0" right="5.0" top="5.0" />
<Insets bottom="10.0" left="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
@ -64,7 +64,7 @@
<Label fx:id="contactLabel" prefHeight="16.0" prefWidth="250.0"
text="Select a contact to chat with" GridPane.columnSpan="2">
<GridPane.margin>
<Insets left="15.0" right="5.0" top="5.0" />
<Insets left="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
@ -75,17 +75,18 @@
GridPane.columnIndex="1" GridPane.columnSpan="2"
GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="10.0" top="10.0" />
<Insets bottom="10.0" right="10.0" top="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Button>
<ListView fx:id="messageList" prefHeight="257.0"
prefWidth="465.0" GridPane.columnIndex="1" GridPane.columnSpan="2"
GridPane.rowIndex="1" GridPane.rowSpan="2">
prefWidth="465.0" GridPane.columnIndex="1"
GridPane.columnSpan="2147483647" GridPane.rowIndex="1"
GridPane.rowSpan="2">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
<Insets left="5.0" right="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
@ -101,6 +102,8 @@
onAction="#forwardMessage" text="Forward" />
<MenuItem mnemonicParsing="false"
onAction="#quoteMessage" text="Quote" />
<MenuItem mnemonicParsing="false"
onAction="#loadMessageInfoScene" text="Info" />
</items>
</ContextMenu>
</contextMenu>
@ -111,11 +114,8 @@
GridPane.halignment="CENTER" GridPane.rowIndex="4"
GridPane.valignment="BOTTOM">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="10.0" />
<Insets bottom="10.0" right="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip anchorLocation="WINDOW_TOP_LEFT" autoHide="true"
maxWidth="350.0"
@ -130,6 +130,9 @@
</items>
</ContextMenu>
</contextMenu>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Button>
<TextArea fx:id="messageTextArea" disable="true"
onInputMethodTextChanged="#messageTextUpdated"
@ -137,7 +140,7 @@
prefHeight="200.0" prefWidth="200.0" wrapText="true"
GridPane.columnIndex="1" GridPane.rowIndex="4">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="5.0" top="5.0" />
<Insets bottom="10.0" left="5.0" top="3.0" />
</GridPane.margin>
<opaqueInsets>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
@ -163,7 +166,7 @@
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
<Insets bottom="5.0" top="5.0" />
</padding>
<opaqueInsets>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
@ -175,8 +178,8 @@
</tooltip>
</Label>
<Label fx:id="infoLabel" text="Something happened"
textFill="#faa007" visible="false" GridPane.columnIndex="1"
GridPane.rowIndex="1">
wrapText="true" textFill="#faa007" visible="false"
GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>

View File

@ -1,77 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import envoy.client.ui.ClearableTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="envoy.client.ui.controller.ContactSearchScene">
<children>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<TextField fx:id="searchBar" onInputMethodTextChanged="#checkClearButton" onKeyTyped="#checkClearButton" prefColumnCount="22" promptText="Enter username to search for">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip text="Enter a name. If an account by that name exists, it will be displayed below." wrapText="true" />
</tooltip>
</TextField>
<Button fx:id="clearButton" disable="true" mnemonicParsing="true" onAction="#clear" prefHeight="26.0" prefWidth="110.0" text="Clea_r">
<tooltip>
<Tooltip autoHide="true" text="Clears the text to the left and the elements below" wrapText="true" />
</tooltip>
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Button>
<Button fx:id="searchButton" defaultButton="true" disable="true" mnemonicParsing="true" onAction="#suggestContacts" prefHeight="26.0" prefWidth="124.0" text="_Search" textOverrun="LEADING_WORD_ELLIPSIS">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<HBox.margin>
<Insets bottom="5.0" right="20.0" top="5.0" />
</HBox.margin>
<tooltip>
<Tooltip autoHide="true" text="Search for accounts with the name entered to the left" wrapText="true" />
</tooltip>
</Button>
<Button mnemonicParsing="false" onAction="#newGroupButtonClicked" prefHeight="26.0" prefWidth="139.0" text="New Group">
<HBox.margin>
<Insets bottom="5.0" left="20.0" right="5.0" top="5.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Button>
</children>
</HBox>
<ListView fx:id="contactList" onMouseClicked="#contactListClicked" prefHeight="314.0" prefWidth="600.0">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin></ListView>
<Button fx:id="backButton" cancelButton="true" mnemonicParsing="true" onAction="#backButtonClicked" text="_Back">
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip autoHide="true" text="Takes you back to the screen where you can chat with others" wrapText="true" />
</tooltip>
</Button>
</children>
<VBox maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="envoy.client.ui.controller.ContactSearchScene">
<children>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<ClearableTextField fx:id="searchBar"
prefWidth="310.0">
<textField onInputMethodTextChanged="#sendRequest"
onKeyTyped="#sendRequest" prefColumnCount="22"
promptText="Enter username to search for">
</textField>
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="15.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip
text="Enter a name. If an account by that name exists, it will be displayed below."
wrapText="true" />
</tooltip>
</ClearableTextField>
<Button mnemonicParsing="false"
onAction="#newGroupButtonClicked" prefHeight="26.0"
prefWidth="139.0" text="New Group">
<HBox.margin>
<Insets bottom="5.0" left="30.0" right="5.0" top="5.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Button>
</children>
</HBox>
<ListView fx:id="contactList"
onMouseClicked="#contactListClicked" prefHeight="314.0"
prefWidth="600.0">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</ListView>
<Button cancelButton="true" mnemonicParsing="true"
onAction="#backButtonClicked" text="_Back">
<VBox.margin>
<Insets bottom="10.0" left="10.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip autoHide="true"
text="Takes you back to the screen where you can chat with others"
wrapText="true" />
</tooltip>
</Button>
</children>
</VBox>

View File

@ -1,67 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import envoy.client.ui.ClearableTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="envoy.client.ui.controller.GroupCreationScene">
<children>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<TextField fx:id="groupNameField" prefColumnCount="22" promptText="Enter Group Name">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip text="Enter a name. If an account by that name exists, it will be displayed below." wrapText="true" />
</tooltip>
</TextField>
</children>
</HBox>
<Label text="Choose Members:">
<font>
<Font size="16.0" />
</font>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Label>
<ListView fx:id="contactList" onMouseClicked="#contactListClicked" prefHeight="314.0" prefWidth="600.0">
<VBox.margin>
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding></ListView>
<Button fx:id="createButton" defaultButton="true" disable="true" mnemonicParsing="false" onAction="#createButtonClicked" text="Create">
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding></Button>
<Button cancelButton="true" mnemonicParsing="true" onAction="#backButtonClicked" text="_Back">
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip autoHide="true" text="Takes you back to the screen where you can chat with others" wrapText="true" />
</tooltip>
</Button>
</children>
<VBox maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="envoy.client.ui.controller.GroupCreationScene">
<children>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<ClearableTextField fx:id="groupNameField">
<textField prefColumnCount="22"
promptText="Enter Group Name"
onInputMethodTextChanged="#textUpdated" onKeyTyped="#textUpdated" />
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip
text="Enter something. A group with this name will be created."
wrapText="true" />
</tooltip>
</ClearableTextField>
</children>
</HBox>
<Label text="Choose Members:">
<font>
<Font size="16.0" />
</font>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Label>
<ListView fx:id="contactList"
onMouseClicked="#contactListClicked" prefHeight="314.0"
prefWidth="600.0">
<VBox.margin>
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</ListView>
<BorderPane prefHeight="50.0">
<left>
<Button cancelButton="true" mnemonicParsing="true"
onAction="#backButtonClicked" text="_Back"
BorderPane.alignment="CENTER">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<tooltip>
<Tooltip autoHide="true"
text="Takes you back to the screen where you can chat with others"
wrapText="true" />
</tooltip>
<BorderPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</BorderPane.margin>
</Button>
</left>
<right>
<Button fx:id="createButton" alignment="CENTER_RIGHT"
defaultButton="true" disable="true" mnemonicParsing="false"
onAction="#createButtonClicked" text="Create"
BorderPane.alignment="CENTER">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<BorderPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</BorderPane.margin>
</Button>
</right>
</BorderPane>
</children>
</VBox>

View File

@ -1,104 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import envoy.client.ui.ClearableTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox prefHeight="206.0" prefWidth="440.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="envoy.client.ui.controller.LoginScene">
<children>
<Label text="User Login">
<font>
<Font size="26.0" />
</font>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<VBox prefHeight="206.0" prefWidth="440.0"
xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="envoy.client.ui.controller.LoginScene">
<children>
<Label text="User Login">
<font>
<Font size="26.0" />
</font>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Label>
<GridPane hgap="5.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES"
minWidth="10.0" percentWidth="40.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES"
minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0"
vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0"
vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0"
vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="User Name:">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding>
</Label>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="40.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="User Name:">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding></Label>
<Label text="Password" GridPane.rowIndex="1">
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding>
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin></Label>
<Label fx:id="repeatPasswordLabel" text="Repeat Password:" visible="false" GridPane.rowIndex="2">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding></Label>
<TextField fx:id="userTextField" GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding></TextField>
<PasswordField fx:id="passwordField" GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="5.0" top="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding></PasswordField>
<PasswordField fx:id="repeatPasswordField" visible="false" GridPane.columnIndex="1" GridPane.rowIndex="2">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding></PasswordField>
</children>
</GridPane>
<CheckBox fx:id="registerCheckBox" mnemonicParsing="true" onAction="#registerCheckboxChanged" prefHeight="17.0" prefWidth="181.0" text="_Register">
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding>
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin></CheckBox>
<Label fx:id="connectionLabel" />
<ButtonBar prefHeight="40.0" prefWidth="200.0">
<buttons>
<Button mnemonicParsing="false" onAction="#abortLogin" text="Close">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Button>
<Button mnemonicParsing="false" onAction="#offlineModeButtonPressed" text="Offline mode" />
<Button defaultButton="true" mnemonicParsing="false" onAction="#loginButtonPressed" text="Login" />
</buttons>
</ButtonBar>
</children>
<Label text="Password:" GridPane.rowIndex="1">
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding>
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
</Label>
<Label fx:id="repeatPasswordLabel" text="Repeat Password:"
visible="false" GridPane.rowIndex="2">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding>
</Label>
<ClearableTextField fx:id="userTextField"
GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
</ClearableTextField>
<PasswordField fx:id="passwordField"
GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="5.0" top="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</PasswordField>
<PasswordField fx:id="repeatPasswordField"
visible="false" GridPane.columnIndex="1" GridPane.rowIndex="2">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</PasswordField>
</children>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
</GridPane>
<CheckBox fx:id="registerCheckBox" mnemonicParsing="true"
onAction="#registerCheckboxChanged" prefHeight="17.0"
prefWidth="181.0" text="_Register">
<VBox.margin>
<Insets left="5.0" right="3.0" />
</VBox.margin>
</CheckBox>
<Label fx:id="connectionLabel">
<VBox.margin>
<Insets left="5.0" />
</VBox.margin>
</Label>
<BorderPane prefWidth="200.0">
<left>
<Button cancelButton="true" mnemonicParsing="false"
onAction="#abortLogin" text="Close" BorderPane.alignment="CENTER">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<BorderPane.margin>
<Insets />
</BorderPane.margin>
</Button>
</left>
<center>
<Button mnemonicParsing="false"
onAction="#offlineModeButtonPressed" text="Offline mode"
BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
</Button>
</center>
<right>
<Button defaultButton="true" mnemonicParsing="false"
onAction="#loginButtonPressed" text="Login"
BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
</Button>
</right>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" />
</VBox.margin>
</BorderPane>
</children>
</VBox>

View File

@ -7,39 +7,50 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox alignment="TOP_RIGHT" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="envoy.client.ui.controller.SettingsScene">
<VBox alignment="TOP_RIGHT" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
prefHeight="400.0" prefWidth="600.0"
xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="envoy.client.ui.controller.SettingsScene">
<children>
<HBox prefHeight="389.0" prefWidth="600.0">
<children>
<ListView fx:id="settingsList" onMouseClicked="#settingsListClicked" prefHeight="200.0" prefWidth="200.0">
<opaqueInsets>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</opaqueInsets>
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="5.0" top="10.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding></ListView>
<TitledPane fx:id="titledPane" collapsible="false" prefHeight="325.0" prefWidth="300.0">
<HBox.margin>
<Insets bottom="10.0" left="5.0" right="10.0" top="10.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding></TitledPane>
</children>
<children>
<ListView fx:id="settingsList"
onMouseClicked="#settingsListClicked" prefHeight="200.0"
prefWidth="200.0">
<opaqueInsets>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</opaqueInsets>
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="5.0" top="10.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</ListView>
<TitledPane fx:id="titledPane" collapsible="false"
prefHeight="325.0" prefWidth="300.0">
<HBox.margin>
<Insets bottom="10.0" left="5.0" right="10.0" top="10.0" />
</HBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</TitledPane>
</children>
</HBox>
<Button defaultButton="true" mnemonicParsing="true" onMouseClicked="#backButtonClicked" text="_Back">
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
</Button>
<Button defaultButton="true" mnemonicParsing="true"
onMouseClicked="#backButtonClicked" text="_Back">
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
</Button>
</children>
</VBox>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB