Added automatic line separation and Keylistener for posting

Improvements yet to be made (help wanted!):
* automatic line separation does not work
* automatic line separation needs a case for insertion of a String
* Keylistener for Posting does not work
* Method for listening to multiple keys needed (ctrl+enter)
* A template Settings screen was added, has yet to be polished
This commit is contained in:
delvh 2019-10-31 22:11:50 +01:00
parent f5037916c9
commit 4adc23d902
6 changed files with 301 additions and 31 deletions

View File

@ -28,9 +28,8 @@ import envoy.schema.Users;
* @author Kai S. K. Engelbart * @author Kai S. K. Engelbart
* @author Maximilian Käfer * @author Maximilian Käfer
* @author Leon Hofmeister * @author Leon Hofmeister
* @since Envoy 0.1 * @since Envoy v0.1-alpha
*/ */
public class Client { public class Client {
private ObjectFactory objectFactory = new ObjectFactory(); private ObjectFactory objectFactory = new ObjectFactory();
@ -53,9 +52,8 @@ public class Client {
* Because sending a request is a blocking operation, it is executed * Because sending a request is a blocking operation, it is executed
* asynchronously. * asynchronously.
* *
* @param sender name of the sender * @param message the {@link Message} we want to send
* @param recipient name of the recipient * @since Envoy v0.1-alpha
* @param textContent content (text) of the message
*/ */
public void sendMessage(Message message) { public void sendMessage(Message message) {
new Thread(() -> { new Thread(() -> {
@ -90,6 +88,7 @@ public class Client {
* *
* @param textContent The content (text) of the message * @param textContent The content (text) of the message
* @return prepared {@link Message} object * @return prepared {@link Message} object
* @since Envoy v0.1-alpha
*/ */
public Message createMessage(String textContent) { public Message createMessage(String textContent) {
Message.MetaData metaData = objectFactory.createMessageMetaData(); Message.MetaData metaData = objectFactory.createMessageMetaData();
@ -109,22 +108,28 @@ public class Client {
return message; return message;
} }
public Users getUsersListXml() { return get(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort()), Users.class); } public Users getUsersListXml() {
return get(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort()), Users.class);
}
public Messages getUnreadMessages(long userId) { public Messages getUnreadMessages(long userId) {
return get(String.format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId), Messages.class); return get(String
.format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId),
Messages.class);
} }
/** /**
* Returns a {@link User} with a specific name by name. * Returns a {@link User} with a specific id by name.
* *
* @param name - the name of the {@link User} * @param name - the name of the {@link User}
* @return a {@link User} with the specified name * @return a {@link User} with the specified name
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
private User getUser(String name) { private User getUser(String name) {
return get(String.format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name), Users.class).getUser() return get(
.get(0); String
.format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name),
Users.class).getUser().get(0);
} }
/** /**
@ -166,9 +171,21 @@ public class Client {
*/ */
public User getSender() { return sender; } public User getSender() { return sender; }
/**
* @return the recipient of a message.
* @since Envoy v0.1-alpha
*/
public User getRecipient() { return recipient; } public User getRecipient() { return recipient; }
/**
* @param recipient the recipient to set
* @since Envoy v0.1-alpha
*/
public void setRecipient(User recipient) { this.recipient = recipient; } public void setRecipient(User recipient) { this.recipient = recipient; }
/**
* @return true, if a recipient is selected
* @since Envoy v0.1-alpha
*/
public boolean hasRecipient() { return recipient != null; } public boolean hasRecipient() { return recipient != null; }
} }

View File

@ -59,7 +59,9 @@ public class Config {
* @return {@code true} if server, port and localDB directory are known. * @return {@code true} if server, port and localDB directory are known.
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } public boolean isInitialized() {
return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null;
}
/** /**
* @return the host name of the Envoy server * @return the host name of the Envoy server

View File

@ -23,16 +23,16 @@ import envoy.schema.User;
public class LocalDB { public class LocalDB {
private File localDB; private File localDB;
private User sender; private User client;
private List<Chat> chats = new ArrayList<>(); private List<Chat> chats = new ArrayList<>();
/** /**
* Constructs an empty local database. * Constructs an empty local database.
* *
* @param sender the user that is logged in with this client * @param client the user that is logged in with this client
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
**/ **/
public LocalDB(User sender) { this.sender = sender; } public LocalDB(User sender) { this.client = sender; }
/** /**
* Initializes the local database and fills it with values * Initializes the local database and fills it with values
@ -43,9 +43,9 @@ public class LocalDB {
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
**/ **/
public void initializeDBFile(File localDBDir) throws EnvoyException { public void initializeDBFile(File localDBDir) throws EnvoyException {
if (localDBDir.exists() && !localDBDir.isDirectory()) if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException(
throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath()));
localDB = new File(localDBDir, sender.getID() + ".db"); localDB = new File(localDBDir, client.getID() + ".db");
if (localDB.exists()) loadFromLocalDB(); if (localDB.exists()) loadFromLocalDB();
} }
@ -89,8 +89,14 @@ public class LocalDB {
/** /**
* @return all saves {@link Chat} objects that list the client user as the * @return all saves {@link Chat} objects that list the client user as the
* sender * client
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
**/ **/
public List<Chat> getChats() { return chats; } public List<Chat> getChats() { return chats; }
/**
* @return the User who initialised the local Database
* @since Envoy v0.1-alpha
*/
public User getUser() { return client; }
} }

View File

@ -6,6 +6,9 @@ import java.awt.Font;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.awt.Insets; import java.awt.Insets;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
@ -39,7 +42,7 @@ import envoy.schema.Users;
* @author Kai S. K. Engelbart * @author Kai S. K. Engelbart
* @author Maximilian K&auml;fer * @author Maximilian K&auml;fer
* @author Leon Hofmeister * @author Leon Hofmeister
* @since Envoy 0.1 * @since Envoy v0.1-alpha
*/ */
public class ChatWindow extends JFrame { public class ChatWindow extends JFrame {
@ -53,6 +56,8 @@ public class ChatWindow extends JFrame {
private JList<User> userList = new JList<>(); private JList<User> userList = new JList<>();
private Chat currentChat; private Chat currentChat;
private String messageText;
public ChatWindow(Client client, LocalDB localDB) { public ChatWindow(Client client, LocalDB localDB) {
this.client = client; this.client = client;
this.localDB = localDB; this.localDB = localDB;
@ -77,7 +82,7 @@ public class ChatWindow extends JFrame {
gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; gbl_contentPane.columnWidths = new int[] { 1, 1, 1 };
gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; gbl_contentPane.rowHeights = new int[] { 1, 1, 1 };
gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 };
gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 };
contentPane.setLayout(gbl_contentPane); contentPane.setLayout(gbl_contentPane);
JList<Message> messageList = new JList<>(); JList<Message> messageList = new JList<>();
@ -114,6 +119,30 @@ public class ChatWindow extends JFrame {
// Message enter field // Message enter field
JTextArea messageEnterTextfield = new JTextArea(); JTextArea messageEnterTextfield = new JTextArea();
// checks for changed Message
messageEnterTextfield.addInputMethodListener(new InputMethodListener() {
public void caretPositionChanged(InputMethodEvent arg0) {}
public void inputMethodTextChanged(InputMethodEvent arg0) {
String message = messageEnterTextfield.getText();
int messageSize = message.length();
int lineSize = 45;
String[] tempString = message.split(System.getProperty("line.separator"));
int currentLineAmount = tempString.length;
int wantedLineAmount = Math.floorDiv(messageSize, lineSize);
if (currentLineAmount != wantedLineAmount) {
if (Math.abs(messageText.length() - messageSize) == 1
&& currentLineAmount == wantedLineAmount - 1) {// Check for "normal" Keystroke/Backspace
messageEnterTextfield.setText(transformLastSpace(message, wantedLineAmount, lineSize));
}
} else {// That's the case if a group of chars was a)inserted or b)deleted
// TODO
}
messageText = message;
}
});
messageEnterTextfield.setCaretColor(new Color(255, 255, 255)); messageEnterTextfield.setCaretColor(new Color(255, 255, 255));
messageEnterTextfield.setForeground(new Color(255, 255, 255)); messageEnterTextfield.setForeground(new Color(255, 255, 255));
messageEnterTextfield.setBackground(new Color(51, 51, 51)); messageEnterTextfield.setBackground(new Color(51, 51, 51));
@ -122,17 +151,20 @@ public class ChatWindow extends JFrame {
messageEnterTextfield.setFont(new Font("Arial", Font.PLAIN, 17)); messageEnterTextfield.setFont(new Font("Arial", Font.PLAIN, 17));
messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints();
gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH;
gbc_moveSelectionMessageEnterTextfield.gridx = 1; gbc_messageEnterTextfield.gridx = 1;
gbc_moveSelectionMessageEnterTextfield.gridy = 2; gbc_messageEnterTextfield.gridy = 2;
gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10);
contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); contentPane.add(messageEnterTextfield, gbc_messageEnterTextfield);
// Post Button // Post Button
JButton postButton = new JButton("Post"); JButton postButton = new JButton("Post");
if (SettingsScreen.isEnterToSend() == true) { postButton.setMnemonic(KeyEvent.VK_ENTER); }
// TODO: Other option to send only on "ctrl"+"enter" needs to be implemented.
// TODO: Difficult. Also above statement doesn't work!
postButton.setForeground(new Color(255, 255, 255)); postButton.setForeground(new Color(255, 255, 255));
postButton.setBackground(new Color(102, 51, 153)); postButton.setBackground(new Color(102, 51, 153));
postButton.setBorderPainted(false); postButton.setBorderPainted(false);
@ -147,7 +179,10 @@ public class ChatWindow extends JFrame {
postButton.addActionListener((evt) -> { postButton.addActionListener((evt) -> {
if (!client.hasRecipient()) { if (!client.hasRecipient()) {
JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); JOptionPane.showMessageDialog(this,
"Please select a recipient!",
"Cannot send message",
JOptionPane.INFORMATION_MESSAGE);
return; return;
} }
@ -175,6 +210,31 @@ public class ChatWindow extends JFrame {
contentPane.add(postButton, gbc_moveSelectionPostButton); contentPane.add(postButton, gbc_moveSelectionPostButton);
// Settings Button
JButton settingsButton = new JButton("Settings");
settingsButton.setForeground(new Color(255, 255, 255));
settingsButton.setBackground(new Color(102, 51, 153));
settingsButton.setBorderPainted(false);
GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints();
gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH;
gbc_moveSelectionSettingsButton.gridx = 2;
gbc_moveSelectionSettingsButton.gridy = 0;
gbc_moveSelectionSettingsButton.insets = new Insets(10, 10, 10, 10);
settingsButton.addActionListener((evt) -> {
try {
SettingsScreen.open(localDB.getUser().getName());
} catch (Exception e) {
SettingsScreen.open();
System.err.println("An Error occured while opening the Settings screen");
e.printStackTrace();
}
});
contentPane.add(settingsButton, gbc_moveSelectionSettingsButton);
// Partner name display // Partner name display
JTextPane textPane = new JTextPane(); JTextPane textPane = new JTextPane();
textPane.setBackground(new Color(0, 0, 0)); textPane.setBackground(new Color(0, 0, 0));
@ -200,7 +260,11 @@ public class ChatWindow extends JFrame {
final User user = selectedUserList.getSelectedValue(); final User user = selectedUserList.getSelectedValue();
client.setRecipient(user); client.setRecipient(user);
currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); currentChat = localDB.getChats()
.stream()
.filter(chat -> chat.getRecipient().getID() == user.getID())
.findFirst()
.get();
client.setRecipient(user); client.setRecipient(user);
@ -233,9 +297,31 @@ public class ChatWindow extends JFrame {
contentPane.revalidate(); contentPane.revalidate();
} }
/**
* takes care of too long or not needed lines in the message.
*
* @param message the message that is currently written in the textfield
* @param wantedLine the line at which we currently are positioned
* @param lineSize the amount of chars per line
* @return the transformed message
* @since Envoy v0.1-alpha
*/
private String transformLastSpace(String message, int wantedLine, int lineSize) {
int index = wantedLine * lineSize;
int lastSpace = message.lastIndexOf(" ", index);
if (index - lastSpace > lineSize) {// Fall Wort länger als Zeile
return message.substring(0, index) + System.getProperty("line.separator") + message.substring(index);
} else {
return message.substring(0, lastSpace - 1) + System.getProperty("line.separator")
+ message.substring(lastSpace + 1);
}
}
/** /**
* Initializes the elements of the user list by downloading them from the * Initializes the elements of the user list by downloading them from the
* server. * server.
*
* @since Envoy v0.1-alpha
*/ */
private void loadUsersAndChats() { private void loadUsersAndChats() {
new Thread(() -> { new Thread(() -> {
@ -257,14 +343,17 @@ public class ChatWindow extends JFrame {
* *
* @param timeout the amount of time that passes between two requests sent to * @param timeout the amount of time that passes between two requests sent to
* the server * the server
* @since Envoy v0.1-alpha
*/ */
private void startReceiverThread(int timeout) { private void startReceiverThread(int timeout) {
new Timer(timeout, (evt) -> { new Timer(timeout, (evt) -> {
Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); Messages unreadMessages = client.getUnreadMessages(client.getSender().getID());
for (int i = 0; i < unreadMessages.getMessage().size(); i++) for (int i = 0; i < unreadMessages.getMessage().size(); i++)
for (int j = 0; j < localDB.getChats().size(); j++) for (int j = 0; j < localDB.getChats().size(); j++)
if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage()
localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); .get(i)
.getMetaData()
.getSender()) localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i));
}).start(); }).start();
} }
} }

View File

@ -0,0 +1,156 @@
package envoy.client.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
/**
* Project: <strong>envoy-client</strong><br>
* File: <strong>SettingsScreen.java</strong><br>
* Created: <strong>31 Oct 2019</strong><br>
*
* @author Leon Hofmeister
*/
public class SettingsScreen extends JDialog {
private static final long serialVersionUID = -4476913491263077107L;
private final JPanel contentPanel = new JPanel();
public static boolean EnterToSend = true;
// TODO: Add a JPanel with all the Information necessary:
// change (Picture,Username, Email, Password) and toggle(light/dark mode,
// "ctrl+enter"/"enter"
// to send a message directly)
/**
* Open the Settings screen.
* Only suited for Dev/Error mode.
* Avoid usage.
*
* @since Envoy v0.1-alpha
*/
public static void open() {
SettingsScreen dialog = new SettingsScreen();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
}
/**
* Opens the Settings screen.<br>
* Use preferreably since everyone is already initialised.<br>
* It personalises the screen more.
*
* @param Username The name of the User
* @param Email The Email that is associated with that Account
* @since Envoy v0.1-alpha
*/
public static void open(String Username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER
// EMAIL IMPLEMENTIERT IST!
SettingsScreen dialog = new SettingsScreen(Username);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
}
/**
* Builds the Settings screen.<br>
* Use only as Dev/Error Mode.<br>
* Avoid usage.
*
* @since Envoy v0.1-alpha
*/
public SettingsScreen() {
setBackground(Color.BLACK);
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBackground(Color.BLACK);
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(new BorderLayout(0, 0));
{
JPanel buttonPane = new JPanel();
buttonPane.setBackground(Color.BLACK);
getContentPane().add(buttonPane, BorderLayout.SOUTH);
buttonPane.setLayout(new BorderLayout(0, 0));
{
JButton okButton = new JButton("Save");
okButton.setActionCommand("OK");
buttonPane.add(okButton, BorderLayout.EAST);
getRootPane().setDefaultButton(okButton);
okButton.addActionListener((evt) -> {
// Hier später die Daten abspeichern, wenn Datenmodell implementiert ist
dispose();
});
}
{
JButton cancelButton = new JButton("Cancel");
cancelButton.setActionCommand("Cancel");
buttonPane.add(cancelButton, BorderLayout.WEST);
cancelButton.addActionListener((evt) -> { dispose(); });
}
}
}
/**
* Builds the Settings screen.<br>
* Use preferreably since everyone is already initialised.<br>
* It personalises the screen more.
*
* @param Username The name of the User
* @param Email The Email that is associated with that Account
* @since Envoy v0.1-alpha
*/
public SettingsScreen(String Username) {// , String Email, String hashedPwd) {AUSKLAMMERN, WENN ANMELDUNG PER EMAIL
// IMPLEMENTIERT IST!
setBackground(Color.BLACK);
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBackground(Color.BLACK);
contentPanel.setLayout(new FlowLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
{
JPanel buttonPane = new JPanel();
buttonPane.setBackground(Color.BLACK);
getContentPane().add(buttonPane, BorderLayout.SOUTH);
buttonPane.setLayout(new BorderLayout(0, 0));
{
JButton okButton = new JButton("Save");
okButton.setActionCommand("OK");
buttonPane.add(okButton, BorderLayout.EAST);
getRootPane().setDefaultButton(okButton);
okButton.addActionListener((evt) -> {
// Hier später die Daten abspeichern, wenn Datenmodell implementiert ist
dispose();
});
}
{
JButton cancelButton = new JButton("Cancel");
cancelButton.setActionCommand("Cancel");
buttonPane.add(cancelButton, BorderLayout.WEST);
cancelButton.addActionListener((evt) -> { dispose(); });
}
}
}
/**
* @return true if Enter should be used to send a message
* @since Envoy v0.1-alpha
*/
public static boolean isEnterToSend() { return EnterToSend; }
/**
* @param enterToSend <br>
* toggles whether a message should be sent via
* <br>
* buttonpress "enter" or "ctrl"+"enter"
* @since Envoy v0.1-alpha
*/
public static void setEnterToSend(boolean enterToSend) { EnterToSend = enterToSend; }
// TODO: Should be changed to private, but later to avoid warnings
}