Merge pull request #161 from informatik-ag-ngl/f/notify_user_of_empty_IDGenerator
Notify user of empty IDGenerators
Added:
    automatically disabled user of posting after that condition is reached
    an infoLabel used to communicate some events with the user
    (in parts) a new UI design
    cleaned up Envoy client: no more <br><br>, is now <p>
    deleted annoying alert notifying me that I'm offline
			
			
This commit is contained in:
		@@ -12,9 +12,9 @@ import envoy.data.Message.MessageStatus;
 | 
				
			|||||||
import envoy.event.MessageStatusChange;
 | 
					import envoy.event.MessageStatusChange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents a chat between two {@link User}s <br>
 | 
					 * Represents a chat between two {@link User}s
 | 
				
			||||||
 * as a list of {@link Message} objects.
 | 
					 * as a list of {@link Message} objects.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>Chat.java</strong><br>
 | 
					 * File: <strong>Chat.java</strong><br>
 | 
				
			||||||
 * Created: <strong>19 Oct 2019</strong><br>
 | 
					 * Created: <strong>19 Oct 2019</strong><br>
 | 
				
			||||||
@@ -32,7 +32,7 @@ public final class Chat implements Serializable {
 | 
				
			|||||||
	private static final long serialVersionUID = 1L;
 | 
						private static final long serialVersionUID = 1L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Provides the list of messages that the recipient receives.<br>
 | 
						 * Provides the list of messages that the recipient receives.<p>
 | 
				
			||||||
	 * Saves the Messages in the corresponding chat at that Point.
 | 
						 * Saves the Messages in the corresponding chat at that Point.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param recipient the user who receives the messages
 | 
						 * @param recipient the user who receives the messages
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,8 @@ import envoy.data.LoginCredentials;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Implements a configuration specific to the Envoy Client with default values
 | 
					 * Implements a configuration specific to the Envoy Client with default values
 | 
				
			||||||
 * and convenience methods.<br>
 | 
					 * and convenience methods.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>ClientConfig.java</strong><br>
 | 
					 * File: <strong>ClientConfig.java</strong><br>
 | 
				
			||||||
 * Created: <strong>01.03.2020</strong><br>
 | 
					 * Created: <strong>01.03.2020</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,8 @@ import envoy.event.NameChange;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Stores information about the current {@link User} and their {@link Chat}s.
 | 
					 * Stores information about the current {@link User} and their {@link Chat}s.
 | 
				
			||||||
 * For message ID generation a {@link IDGenerator} is stored as well.<br>
 | 
					 * For message ID generation a {@link IDGenerator} is stored as well.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>LocalDB.java</strong><br>
 | 
					 * File: <strong>LocalDB.java</strong><br>
 | 
				
			||||||
 * Created: <strong>3 Feb 2020</strong><br>
 | 
					 * Created: <strong>3 Feb 2020</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,8 @@ import envoy.util.SerializationUtils;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Implements a {@link LocalDB} in a way that stores all information inside a
 | 
					 * Implements a {@link LocalDB} in a way that stores all information inside a
 | 
				
			||||||
 * folder on the local file system.<br>
 | 
					 * folder on the local file system.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>PersistentLocalDB.java</strong><br>
 | 
					 * File: <strong>PersistentLocalDB.java</strong><br>
 | 
				
			||||||
 * Created: <strong>27.10.2019</strong><br>
 | 
					 * Created: <strong>27.10.2019</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,8 @@ import envoy.util.SerializationUtils;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Manages all application settings, which are different objects that can be
 | 
					 * Manages all application settings, which are different objects that can be
 | 
				
			||||||
 * changed during runtime and serialized them by using either the file system or
 | 
					 * changed during runtime and serialized them by using either the file system or
 | 
				
			||||||
 * the {@link Preferences} API.<br>
 | 
					 * the {@link Preferences} API.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>Settings.java</strong><br>
 | 
					 * File: <strong>Settings.java</strong><br>
 | 
				
			||||||
 * Created: <strong>11 Nov 2019</strong><br>
 | 
					 * Created: <strong>11 Nov 2019</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,8 @@ import javax.swing.JComponent;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Encapsulates a persistent value that is directly or indirectly mutable by the
 | 
					 * Encapsulates a persistent value that is directly or indirectly mutable by the
 | 
				
			||||||
 * user.<br>
 | 
					 * user.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>SettingsItem.java</strong><br>
 | 
					 * File: <strong>SettingsItem.java</strong><br>
 | 
				
			||||||
 * Created: <strong>23.12.2019</strong><br>
 | 
					 * Created: <strong>23.12.2019</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@ package envoy.client.data;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Implements a {@link LocalDB} in a way that does not persist any information
 | 
					 * Implements a {@link LocalDB} in a way that does not persist any information
 | 
				
			||||||
 * after application shutdown.<br>
 | 
					 * after application shutdown.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>TransientLocalDB.java</strong><br>
 | 
					 * File: <strong>TransientLocalDB.java</strong><br>
 | 
				
			||||||
 * Created: <strong>3 Feb 2020</strong><br>
 | 
					 * Created: <strong>3 Feb 2020</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@ import envoy.event.Event;
 | 
				
			|||||||
 * Created: <strong>11.02.2020</strong><br>
 | 
					 * Created: <strong>11.02.2020</strong><br>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author: Maximilian Käfer
 | 
					 * @author: Maximilian Käfer
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class SendEvent extends Event<Event<?>> {
 | 
					public class SendEvent extends Event<Event<?>> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,8 @@ import envoy.util.SerializationUtils;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Establishes a connection to the server, performs a handshake and delivers
 | 
					 * Establishes a connection to the server, performs a handshake and delivers
 | 
				
			||||||
 * certain objects to the server.<br>
 | 
					 * certain objects to the server.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>Client.java</strong><br>
 | 
					 * File: <strong>Client.java</strong><br>
 | 
				
			||||||
 * Created: <strong>28 Sep 2019</strong><br>
 | 
					 * Created: <strong>28 Sep 2019</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,8 @@ import envoy.util.EnvoyLog;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Implements methods to send {@link Message}s and
 | 
					 * Implements methods to send {@link Message}s and
 | 
				
			||||||
 * {@link MessageStatusChange}s to the server or cache them inside a
 | 
					 * {@link MessageStatusChange}s to the server or cache them inside a
 | 
				
			||||||
 * {@link LocalDB} depending on the online status.<br>
 | 
					 * {@link LocalDB} depending on the online status.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>WriteProxy.java</strong><br>
 | 
					 * File: <strong>WriteProxy.java</strong><br>
 | 
				
			||||||
 * Created: <strong>6 Feb 2020</strong><br>
 | 
					 * Created: <strong>6 Feb 2020</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,11 +7,11 @@ import javafx.scene.image.Image;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides static utility methods for loading icons from the resource
 | 
					 * Provides static utility methods for loading icons from the resource
 | 
				
			||||||
 * folder.<br>
 | 
					 * folder.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>IconUtil.java</strong>
 | 
					 * File: <strong>IconUtil.java</strong><br>
 | 
				
			||||||
 * Created: <strong>16.03.2020</strong>
 | 
					 * Created: <strong>16.03.2020</strong><br>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ import javafx.scene.image.ImageView;
 | 
				
			|||||||
import javafx.scene.input.KeyCode;
 | 
					import javafx.scene.input.KeyCode;
 | 
				
			||||||
import javafx.scene.input.KeyEvent;
 | 
					import javafx.scene.input.KeyEvent;
 | 
				
			||||||
import javafx.scene.paint.Color;
 | 
					import javafx.scene.paint.Color;
 | 
				
			||||||
 | 
					import javafx.scene.paint.Paint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Chat;
 | 
					import envoy.client.data.Chat;
 | 
				
			||||||
import envoy.client.data.LocalDB;
 | 
					import envoy.client.data.LocalDB;
 | 
				
			||||||
@@ -62,6 +63,9 @@ public final class ChatScene {
 | 
				
			|||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private Label remainingChars;
 | 
						private Label remainingChars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@FXML
 | 
				
			||||||
 | 
						private Label infoLabel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private MenuItem deleteContactMenuItem;
 | 
						private MenuItem deleteContactMenuItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,6 +74,8 @@ public final class ChatScene {
 | 
				
			|||||||
	private WriteProxy		writeProxy;
 | 
						private WriteProxy		writeProxy;
 | 
				
			||||||
	private SceneContext	sceneContext;
 | 
						private SceneContext	sceneContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private boolean postingPermanentlyDisabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Chat currentChat;
 | 
						private Chat currentChat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final Settings	settings			= Settings.getInstance();
 | 
						private static final Settings	settings			= Settings.getInstance();
 | 
				
			||||||
@@ -161,6 +167,7 @@ public final class ChatScene {
 | 
				
			|||||||
		userList.setItems(FXCollections.observableList(localDB.getChats().stream().map(Chat::getRecipient).collect(Collectors.toList())));
 | 
							userList.setItems(FXCollections.observableList(localDB.getChats().stream().map(Chat::getRecipient).collect(Collectors.toList())));
 | 
				
			||||||
		contactLabel.setText(localDB.getUser().getName());
 | 
							contactLabel.setText(localDB.getUser().getName());
 | 
				
			||||||
		MessageListCell.setUser(localDB.getUser());
 | 
							MessageListCell.setUser(localDB.getUser());
 | 
				
			||||||
 | 
							if (!client.isOnline()) updateInfoLabel("You are offline", Color.YELLOW);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -193,7 +200,7 @@ public final class ChatScene {
 | 
				
			|||||||
			remainingChars
 | 
								remainingChars
 | 
				
			||||||
				.setText(String.format("remaining chars: %d/%d", MAX_MESSAGE_LENGTH - messageTextArea.getText().length(), MAX_MESSAGE_LENGTH));
 | 
									.setText(String.format("remaining chars: %d/%d", MAX_MESSAGE_LENGTH - messageTextArea.getText().length(), MAX_MESSAGE_LENGTH));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		messageTextArea.setDisable(currentChat == null);
 | 
							messageTextArea.setDisable(currentChat == null || postingPermanentlyDisabled);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -240,10 +247,18 @@ public final class ChatScene {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void checkPostConditions(KeyEvent e) {
 | 
						private void checkPostConditions(KeyEvent e) {
 | 
				
			||||||
		if (!postButton.isDisabled() && (settings.isEnterToSend() && e.getCode() == KeyCode.ENTER
 | 
							if (!postingPermanentlyDisabled) {
 | 
				
			||||||
				|| !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown()))
 | 
								if (!postButton.isDisabled() && (settings.isEnterToSend() && e.getCode() == KeyCode.ENTER
 | 
				
			||||||
			postMessage();
 | 
										|| !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown()))
 | 
				
			||||||
		postButton.setDisable(messageTextArea.getText().isBlank() || currentChat == null);
 | 
									postMessage();
 | 
				
			||||||
 | 
								postButton.setDisable(messageTextArea.getText().isBlank() || currentChat == null);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								final var noMoreMessaging = "Go online to send messages";
 | 
				
			||||||
 | 
								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);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -282,6 +297,14 @@ public final class ChatScene {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void postMessage() {
 | 
						private void postMessage() {
 | 
				
			||||||
 | 
							postingPermanentlyDisabled = !(client.isOnline() || localDB.getIDGenerator().hasNext());
 | 
				
			||||||
 | 
							if (postingPermanentlyDisabled) {
 | 
				
			||||||
 | 
								postButton.setDisable(true);
 | 
				
			||||||
 | 
								messageTextArea.setDisable(true);
 | 
				
			||||||
 | 
								messageTextArea.clear();
 | 
				
			||||||
 | 
								updateInfoLabel("You need to go online to send more messages", Color.RED);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		final var text = messageTextArea.getText().strip();
 | 
							final var text = messageTextArea.getText().strip();
 | 
				
			||||||
		if (text.isBlank()) throw new IllegalArgumentException("A message without visible text can not be sent.");
 | 
							if (text.isBlank()) throw new IllegalArgumentException("A message without visible text can not be sent.");
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
@@ -318,6 +341,19 @@ public final class ChatScene {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	private void scrollToMessageListEnd() { messageList.scrollTo(messageList.getItems().size() - 1); }
 | 
						private void scrollToMessageListEnd() { messageList.scrollTo(messageList.getItems().size() - 1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Updates the {@code infoLabel}.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param text     the text to use
 | 
				
			||||||
 | 
						 * @param textfill the color in which to display information
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private void updateInfoLabel(String text, Paint textfill) {
 | 
				
			||||||
 | 
							infoLabel.setText(text);
 | 
				
			||||||
 | 
							infoLabel.setTextFill(textfill);
 | 
				
			||||||
 | 
							infoLabel.setVisible(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Context menu actions
 | 
						// Context menu actions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,7 +164,6 @@ public final class LoginScene {
 | 
				
			|||||||
			final User clientUser = (User) localDB.getUsers().get(credentials.getIdentifier());
 | 
								final User clientUser = (User) localDB.getUsers().get(credentials.getIdentifier());
 | 
				
			||||||
			if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown");
 | 
								if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown");
 | 
				
			||||||
			client.setSender(clientUser);
 | 
								client.setSender(clientUser);
 | 
				
			||||||
			new Alert(AlertType.WARNING, "A connection to the server could not be established. Starting in offline mode.").showAndWait();
 | 
					 | 
				
			||||||
			loadChatScene();
 | 
								loadChatScene();
 | 
				
			||||||
		} catch (final Exception e) {
 | 
							} catch (final Exception e) {
 | 
				
			||||||
			new Alert(AlertType.ERROR, "Client error: " + e).showAndWait();
 | 
								new Alert(AlertType.ERROR, "Client error: " + e).showAndWait();
 | 
				
			||||||
@@ -194,9 +193,8 @@ public final class LoginScene {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		localDB.synchronize();
 | 
							localDB.synchronize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (client.isOnline()) {
 | 
							if (client.isOnline()) writeProxy.flushCache();
 | 
				
			||||||
			writeProxy.flushCache();
 | 
							else
 | 
				
			||||||
		} else
 | 
					 | 
				
			||||||
			// Set all contacts to offline mode
 | 
								// Set all contacts to offline mode
 | 
				
			||||||
			localDB.getChats()
 | 
								localDB.getChats()
 | 
				
			||||||
				.stream()
 | 
									.stream()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This package contains classes used for representing the settings
 | 
					 * This package contains classes used for representing the settings
 | 
				
			||||||
 * visually.<br>
 | 
					 * visually.
 | 
				
			||||||
 * <br>
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 * File: <strong>package-info.java</strong><br>
 | 
				
			||||||
 * Created: <strong>19 Apr 2020</strong><br>
 | 
					 * Created: <strong>19 Apr 2020</strong><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,27 +19,27 @@
 | 
				
			|||||||
	fx:controller="envoy.client.ui.controller.ChatScene">
 | 
						fx:controller="envoy.client.ui.controller.ChatScene">
 | 
				
			||||||
	<columnConstraints>
 | 
						<columnConstraints>
 | 
				
			||||||
		<ColumnConstraints hgrow="SOMETIMES"
 | 
							<ColumnConstraints hgrow="SOMETIMES"
 | 
				
			||||||
			maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="20.0"
 | 
								maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="25.0"
 | 
				
			||||||
			prefWidth="161.0" />
 | 
								prefWidth="161.0" />
 | 
				
			||||||
		<ColumnConstraints hgrow="SOMETIMES"
 | 
							<ColumnConstraints hgrow="SOMETIMES"
 | 
				
			||||||
			maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="65.0"
 | 
								maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="65.0"
 | 
				
			||||||
			prefWidth="357.0" />
 | 
								prefWidth="357.0" />
 | 
				
			||||||
		<ColumnConstraints hgrow="SOMETIMES"
 | 
							<ColumnConstraints hgrow="SOMETIMES" maxWidth="10.0"
 | 
				
			||||||
			maxWidth="1.7976931348623157E308" minWidth="6.285736083984375"
 | 
								minWidth="10.0" percentWidth="10.0" prefWidth="10.0" />
 | 
				
			||||||
			percentWidth="15.0" prefWidth="48.000030517578125" />
 | 
					 | 
				
			||||||
	</columnConstraints>
 | 
						</columnConstraints>
 | 
				
			||||||
	<rowConstraints>
 | 
						<rowConstraints>
 | 
				
			||||||
		<RowConstraints maxHeight="1.7976931348623157E308"
 | 
							<RowConstraints maxHeight="1.7976931348623157E308"
 | 
				
			||||||
			minHeight="10.0" percentHeight="10.0" prefHeight="70.0"
 | 
								minHeight="10.0" percentHeight="10.0" prefHeight="70.0"
 | 
				
			||||||
			vgrow="SOMETIMES" />
 | 
								vgrow="SOMETIMES" />
 | 
				
			||||||
		<RowConstraints maxHeight="1.7976931348623157E308"
 | 
							<RowConstraints maxHeight="1.7976931348623157E308"
 | 
				
			||||||
			minHeight="10.0" percentHeight="70.0" prefHeight="326.2857404436384"
 | 
								minHeight="10.0" percentHeight="7.0" vgrow="SOMETIMES" />
 | 
				
			||||||
			vgrow="SOMETIMES" />
 | 
					 | 
				
			||||||
		<RowConstraints maxHeight="1.7976931348623157E308"
 | 
							<RowConstraints maxHeight="1.7976931348623157E308"
 | 
				
			||||||
			minHeight="10.0" percentHeight="5.0" prefHeight="50.0"
 | 
								minHeight="10.0" percentHeight="60.0" prefHeight="50.0"
 | 
				
			||||||
			vgrow="SOMETIMES" />
 | 
								vgrow="SOMETIMES" />
 | 
				
			||||||
 | 
							<RowConstraints maxHeight="50.0" minHeight="10.0"
 | 
				
			||||||
 | 
								percentHeight="2.0" prefHeight="50.0" vgrow="SOMETIMES" />
 | 
				
			||||||
		<RowConstraints maxHeight="1.7976931348623157E308"
 | 
							<RowConstraints maxHeight="1.7976931348623157E308"
 | 
				
			||||||
			minHeight="10.0" percentHeight="15.0" prefHeight="100.0"
 | 
								minHeight="10.0" percentHeight="21.0" prefHeight="100.0"
 | 
				
			||||||
			vgrow="SOMETIMES" />
 | 
								vgrow="SOMETIMES" />
 | 
				
			||||||
	</rowConstraints>
 | 
						</rowConstraints>
 | 
				
			||||||
	<children>
 | 
						<children>
 | 
				
			||||||
@@ -56,7 +56,7 @@
 | 
				
			|||||||
				<ContextMenu anchorLocation="CONTENT_TOP_LEFT">
 | 
									<ContextMenu anchorLocation="CONTENT_TOP_LEFT">
 | 
				
			||||||
					<items>
 | 
										<items>
 | 
				
			||||||
						<MenuItem fx:id="deleteContactMenuItem"
 | 
											<MenuItem fx:id="deleteContactMenuItem"
 | 
				
			||||||
							mnemonicParsing="false" text="Delete" onAction="#deleteContact" />
 | 
												mnemonicParsing="false" onAction="#deleteContact" text="Delete" />
 | 
				
			||||||
					</items>
 | 
										</items>
 | 
				
			||||||
				</ContextMenu>
 | 
									</ContextMenu>
 | 
				
			||||||
			</contextMenu>
 | 
								</contextMenu>
 | 
				
			||||||
@@ -72,8 +72,8 @@
 | 
				
			|||||||
		</Label>
 | 
							</Label>
 | 
				
			||||||
		<Button fx:id="settingsButton" mnemonicParsing="true"
 | 
							<Button fx:id="settingsButton" mnemonicParsing="true"
 | 
				
			||||||
			onAction="#settingsButtonClicked" text="_Settings"
 | 
								onAction="#settingsButtonClicked" text="_Settings"
 | 
				
			||||||
			GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.halignment="RIGHT"
 | 
								GridPane.columnIndex="1" GridPane.columnSpan="2"
 | 
				
			||||||
			GridPane.valignment="CENTER">
 | 
								GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
 | 
				
			||||||
			<GridPane.margin>
 | 
								<GridPane.margin>
 | 
				
			||||||
				<Insets bottom="10.0" left="5.0" right="10.0" top="10.0" />
 | 
									<Insets bottom="10.0" left="5.0" right="10.0" top="10.0" />
 | 
				
			||||||
			</GridPane.margin>
 | 
								</GridPane.margin>
 | 
				
			||||||
@@ -82,7 +82,7 @@
 | 
				
			|||||||
			</padding>
 | 
								</padding>
 | 
				
			||||||
		</Button>
 | 
							</Button>
 | 
				
			||||||
		<ListView fx:id="messageList" prefHeight="257.0"
 | 
							<ListView fx:id="messageList" prefHeight="257.0"
 | 
				
			||||||
			prefWidth="155.0" GridPane.columnIndex="1" GridPane.columnSpan="2"
 | 
								prefWidth="465.0" GridPane.columnIndex="1" GridPane.columnSpan="2"
 | 
				
			||||||
			GridPane.rowIndex="1" GridPane.rowSpan="2">
 | 
								GridPane.rowIndex="1" GridPane.rowSpan="2">
 | 
				
			||||||
			<GridPane.margin>
 | 
								<GridPane.margin>
 | 
				
			||||||
				<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
 | 
									<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
 | 
				
			||||||
@@ -93,25 +93,25 @@
 | 
				
			|||||||
			<contextMenu>
 | 
								<contextMenu>
 | 
				
			||||||
				<ContextMenu anchorLocation="CONTENT_TOP_LEFT">
 | 
									<ContextMenu anchorLocation="CONTENT_TOP_LEFT">
 | 
				
			||||||
					<items>
 | 
										<items>
 | 
				
			||||||
						<MenuItem mnemonicParsing="false" text="Copy"
 | 
											<MenuItem mnemonicParsing="false" onAction="#copyMessage"
 | 
				
			||||||
							onAction="#copyMessage" />
 | 
												text="Copy" />
 | 
				
			||||||
						<MenuItem mnemonicParsing="false" text="Delete"
 | 
											<MenuItem mnemonicParsing="false"
 | 
				
			||||||
							onAction="#deleteMessage" />
 | 
												onAction="#deleteMessage" text="Delete" />
 | 
				
			||||||
						<MenuItem mnemonicParsing="false" text="Forward"
 | 
											<MenuItem mnemonicParsing="false"
 | 
				
			||||||
							onAction="#forwardMessage" />
 | 
												onAction="#forwardMessage" text="Forward" />
 | 
				
			||||||
						<MenuItem mnemonicParsing="false" text="Quote"
 | 
											<MenuItem mnemonicParsing="false"
 | 
				
			||||||
							onAction="#quoteMessage" />
 | 
												onAction="#quoteMessage" text="Quote" />
 | 
				
			||||||
					</items>
 | 
										</items>
 | 
				
			||||||
				</ContextMenu>
 | 
									</ContextMenu>
 | 
				
			||||||
			</contextMenu>
 | 
								</contextMenu>
 | 
				
			||||||
		</ListView>
 | 
							</ListView>
 | 
				
			||||||
		<Button fx:id="postButton" defaultButton="true" disable="true"
 | 
							<Button fx:id="postButton" defaultButton="true" disable="true"
 | 
				
			||||||
			mnemonicParsing="true" onAction="#postMessage" prefHeight="10.0"
 | 
								mnemonicParsing="true" onAction="#postMessage" prefHeight="10.0"
 | 
				
			||||||
			prefWidth="65.0" text="_Post" GridPane.columnIndex="2"
 | 
								prefWidth="75.0" text="_Post" GridPane.columnIndex="2"
 | 
				
			||||||
			GridPane.halignment="CENTER" GridPane.rowIndex="3"
 | 
								GridPane.halignment="CENTER" GridPane.rowIndex="4"
 | 
				
			||||||
			GridPane.valignment="CENTER">
 | 
								GridPane.valignment="BOTTOM">
 | 
				
			||||||
			<GridPane.margin>
 | 
								<GridPane.margin>
 | 
				
			||||||
				<Insets bottom="5.0" left="5.0" right="5.0"/>
 | 
									<Insets bottom="10.0" left="5.0" right="10.0" />
 | 
				
			||||||
			</GridPane.margin>
 | 
								</GridPane.margin>
 | 
				
			||||||
			<padding>
 | 
								<padding>
 | 
				
			||||||
				<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
									<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
				
			||||||
@@ -125,8 +125,8 @@
 | 
				
			|||||||
			<contextMenu>
 | 
								<contextMenu>
 | 
				
			||||||
				<ContextMenu anchorLocation="CONTENT_TOP_LEFT">
 | 
									<ContextMenu anchorLocation="CONTENT_TOP_LEFT">
 | 
				
			||||||
					<items>
 | 
										<items>
 | 
				
			||||||
						<MenuItem mnemonicParsing="false" text="Copy and Send"
 | 
											<MenuItem mnemonicParsing="false"
 | 
				
			||||||
							onAction="#copyAndPostMessage" />
 | 
												onAction="#copyAndPostMessage" text="Copy and Send" />
 | 
				
			||||||
					</items>
 | 
										</items>
 | 
				
			||||||
				</ContextMenu>
 | 
									</ContextMenu>
 | 
				
			||||||
			</contextMenu>
 | 
								</contextMenu>
 | 
				
			||||||
@@ -135,7 +135,7 @@
 | 
				
			|||||||
			onInputMethodTextChanged="#messageTextUpdated"
 | 
								onInputMethodTextChanged="#messageTextUpdated"
 | 
				
			||||||
			onKeyPressed="#checkPostConditions" onKeyTyped="#checkKeyCombination"
 | 
								onKeyPressed="#checkPostConditions" onKeyTyped="#checkKeyCombination"
 | 
				
			||||||
			prefHeight="200.0" prefWidth="200.0" wrapText="true"
 | 
								prefHeight="200.0" prefWidth="200.0" wrapText="true"
 | 
				
			||||||
			GridPane.columnIndex="1" GridPane.rowIndex="3">
 | 
								GridPane.columnIndex="1" GridPane.rowIndex="4">
 | 
				
			||||||
			<GridPane.margin>
 | 
								<GridPane.margin>
 | 
				
			||||||
				<Insets bottom="10.0" left="5.0" right="5.0" top="5.0" />
 | 
									<Insets bottom="10.0" left="5.0" right="5.0" top="5.0" />
 | 
				
			||||||
			</GridPane.margin>
 | 
								</GridPane.margin>
 | 
				
			||||||
@@ -145,20 +145,20 @@
 | 
				
			|||||||
		</TextArea>
 | 
							</TextArea>
 | 
				
			||||||
		<Button mnemonicParsing="true"
 | 
							<Button mnemonicParsing="true"
 | 
				
			||||||
			onAction="#addContactButtonClicked" text="_Add Contacts"
 | 
								onAction="#addContactButtonClicked" text="_Add Contacts"
 | 
				
			||||||
			GridPane.halignment="CENTER" GridPane.rowIndex="3"
 | 
								GridPane.halignment="CENTER" GridPane.rowIndex="4"
 | 
				
			||||||
			GridPane.valignment="CENTER">
 | 
								GridPane.valignment="CENTER">
 | 
				
			||||||
			<padding>
 | 
								<padding>
 | 
				
			||||||
				<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
									<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
				
			||||||
			</padding>
 | 
								</padding>
 | 
				
			||||||
			<GridPane.margin>
 | 
								<GridPane.margin>
 | 
				
			||||||
				<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
									<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
 | 
				
			||||||
			</GridPane.margin>
 | 
								</GridPane.margin>
 | 
				
			||||||
		</Button>
 | 
							</Button>
 | 
				
			||||||
		<Label id="remainingCharsLabel" fx:id="remainingChars"
 | 
							<Label id="remainingCharsLabel" fx:id="remainingChars"
 | 
				
			||||||
			ellipsisString="" maxHeight="30.0" maxWidth="180.0" prefHeight="30.0"
 | 
								ellipsisString="" maxHeight="30.0" maxWidth="180.0" prefHeight="30.0"
 | 
				
			||||||
			prefWidth="180.0" text="remaining chars: 0/x" textFill="LIME"
 | 
								prefWidth="180.0" text="remaining chars: 0/x" textFill="LIME"
 | 
				
			||||||
			textOverrun="LEADING_WORD_ELLIPSIS" visible="false"
 | 
								textOverrun="LEADING_WORD_ELLIPSIS" visible="false"
 | 
				
			||||||
			GridPane.columnIndex="1" GridPane.rowIndex="2">
 | 
								GridPane.columnIndex="1" GridPane.rowIndex="3">
 | 
				
			||||||
			<GridPane.margin>
 | 
								<GridPane.margin>
 | 
				
			||||||
				<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
									<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
				
			||||||
			</GridPane.margin>
 | 
								</GridPane.margin>
 | 
				
			||||||
@@ -174,5 +174,15 @@
 | 
				
			|||||||
					wrapText="true" />
 | 
										wrapText="true" />
 | 
				
			||||||
			</tooltip>
 | 
								</tooltip>
 | 
				
			||||||
		</Label>
 | 
							</Label>
 | 
				
			||||||
 | 
							<Label fx:id="infoLabel" text="Something happened"
 | 
				
			||||||
 | 
								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>
 | 
				
			||||||
 | 
								<padding>
 | 
				
			||||||
 | 
									<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
				
			||||||
 | 
								</padding>
 | 
				
			||||||
 | 
							</Label>
 | 
				
			||||||
	</children>
 | 
						</children>
 | 
				
			||||||
</GridPane>
 | 
					</GridPane>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user