diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index abeb226..da35bd3 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -10,7 +10,7 @@ import envoy.schema.User; public class Chat implements Serializable { private static final long serialVersionUID = -7751248474547242056L; - + private User recipient; private DefaultListModel model = new DefaultListModel<>(); diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 0ebce3c..a0878e2 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -28,9 +28,8 @@ import envoy.schema.Users; * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister - * @since Envoy 0.1 + * @since Envoy v0.1-alpha */ - public class Client { private ObjectFactory objectFactory = new ObjectFactory(); @@ -53,9 +52,8 @@ public class Client { * Because sending a request is a blocking operation, it is executed * asynchronously. * - * @param sender name of the sender - * @param recipient name of the recipient - * @param textContent content (text) of the message + * @param message the {@link Message} we want to send + * @since Envoy v0.1-alpha */ public void sendMessage(Message message) { new Thread(() -> { @@ -90,6 +88,7 @@ public class Client { * * @param textContent The content (text) of the message * @return prepared {@link Message} object + * @since Envoy v0.1-alpha */ public Message createMessage(String textContent) { Message.MetaData metaData = objectFactory.createMessageMetaData(); @@ -109,22 +108,28 @@ public class Client { 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) { - 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} * @return a {@link User} with the specified name * @since Envoy v0.1-alpha */ 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() - .get(0); + return get( + 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; } + /** + * @return the recipient of a message + * @since Envoy v0.1-alpha + */ public User getRecipient() { return recipient; } + /** + * @param recipient the recipient to set + * @since Envoy v0.1-alpha + */ 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; } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 1d107ca..bfa1e57 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -59,7 +59,9 @@ public class Config { * @return {@code true} if server, port and localDB directory are known. * @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 diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d7b3409..1bab251 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -23,16 +23,16 @@ import envoy.schema.User; public class LocalDB { private File localDB; - private User sender; + private User client; private List chats = new ArrayList<>(); /** * 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 **/ - public LocalDB(User sender) { this.sender = sender; } + public LocalDB(User sender) { this.client = sender; } /** * Initializes the local database and fills it with values @@ -43,9 +43,9 @@ public class LocalDB { * @since Envoy v0.1-alpha **/ public void initializeDBFile(File localDBDir) throws EnvoyException { - if (localDBDir.exists() && !localDBDir.isDirectory()) - throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - localDB = new File(localDBDir, sender.getID() + ".db"); + if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException( + String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + localDB = new File(localDBDir, client.getID() + ".db"); if (localDB.exists()) loadFromLocalDB(); } @@ -89,8 +89,14 @@ public class LocalDB { /** * @return all saves {@link Chat} objects that list the client user as the - * sender + * client * @since Envoy v0.1-alpha **/ public List getChats() { return chats; } + + /** + * @return the User who initialised the local Database + * @since Envoy v0.1-alpha + */ + public User getUser() { return client; } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5f79b13..f8c2fcf 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -6,6 +6,8 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; @@ -39,7 +41,7 @@ import envoy.schema.Users; * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister - * @since Envoy 0.1 + * @since Envoy v0.1-alpha */ public class ChatWindow extends JFrame { @@ -53,6 +55,8 @@ public class ChatWindow extends JFrame { private JList userList = new JList<>(); private Chat currentChat; + private JTextArea messageEnterTextArea; + public ChatWindow(Client client, LocalDB localDB) { this.client = client; this.localDB = localDB; @@ -77,7 +81,7 @@ public class ChatWindow extends JFrame { gbl_contentPane.columnWidths = 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.rowWeights = new double[] { 0.05, 1, 0.07 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; contentPane.setLayout(gbl_contentPane); JList messageList = new JList<>(); @@ -113,23 +117,38 @@ public class ChatWindow extends JFrame { contentPane.add(scrollPane, gbc_scrollPane); // Message enter field - JTextArea messageEnterTextfield = new JTextArea(); - messageEnterTextfield.setCaretColor(new Color(255, 255, 255)); - messageEnterTextfield.setForeground(new Color(255, 255, 255)); - messageEnterTextfield.setBackground(new Color(51, 51, 51)); - messageEnterTextfield.setLineWrap(true); - messageEnterTextfield.setBorder(null); - messageEnterTextfield.setFont(new Font("Arial", Font.PLAIN, 17)); - messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); + messageEnterTextArea = new JTextArea(); + messageEnterTextArea.addKeyListener(new KeyAdapter() { - GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); - gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_moveSelectionMessageEnterTextfield.gridx = 1; - gbc_moveSelectionMessageEnterTextfield.gridy = 2; + @Override + public void keyReleased(KeyEvent e) { - gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); + if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) + || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + postMessage(client, messageList); - contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); + } + + } + }); + // Checks for changed Message + messageEnterTextArea.setWrapStyleWord(true); + messageEnterTextArea.setCaretColor(new Color(255, 255, 255)); + messageEnterTextArea.setForeground(new Color(255, 255, 255)); + messageEnterTextArea.setBackground(new Color(51, 51, 51)); + messageEnterTextArea.setLineWrap(true); + messageEnterTextArea.setBorder(null); + messageEnterTextArea.setFont(new Font("Arial", Font.PLAIN, 17)); + messageEnterTextArea.setBorder(new EmptyBorder(5, 5, 5, 5)); + + GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); + gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_messageEnterTextfield.gridx = 1; + gbc_messageEnterTextfield.gridy = 2; + + gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10); + + contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); // Post Button JButton postButton = new JButton("Post"); @@ -145,35 +164,34 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); - postButton.addActionListener((evt) -> { - if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); - return; - } + postButton.addActionListener((evt) -> { postMessage(client, messageList); }); - if (!messageEnterTextfield.getText().isEmpty()) try { + contentPane.add(postButton, gbc_moveSelectionPostButton); - // Create and send message object - final Message message = client.createMessage(messageEnterTextfield.getText()); - client.sendMessage(message); + // Settings Button + JButton settingsButton = new JButton("Settings"); + settingsButton.setForeground(new Color(255, 255, 255)); + settingsButton.setBackground(new Color(102, 51, 153)); + settingsButton.setBorderPainted(false); - // Append message object to chat - currentChat.appendMessage(message); - messageList.setModel(currentChat.getModel()); + GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); - // Clear text field - messageEnterTextfield.setText(""); - contentPane.revalidate(); + 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) { - JOptionPane.showMessageDialog(this, - "An exception occured while sending a message. See the log for more details.", - "Exception occured", - JOptionPane.ERROR_MESSAGE); + SettingsScreen.open(); + System.err.println("An error occured while opening the settings screen: " + e); e.printStackTrace(); } }); - - contentPane.add(postButton, gbc_moveSelectionPostButton); + contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); // Partner name display JTextPane textPane = new JTextPane(); @@ -183,10 +201,9 @@ public class ChatWindow extends JFrame { textPane.setFont(new Font("Arial", Font.PLAIN, 20)); GridBagConstraints gbc_partnerName = new GridBagConstraints(); - gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; - gbc_partnerName.gridwidth = 2; - gbc_partnerName.gridx = 1; - gbc_partnerName.gridy = 0; + gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; + gbc_partnerName.gridx = 1; + gbc_partnerName.gridy = 0; gbc_partnerName.insets = new Insets(0, 10, 0, 10); contentPane.add(textPane, gbc_partnerName); @@ -200,7 +217,11 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); 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); @@ -233,9 +254,51 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } + /** + * Posts a {@link Message}. Is used only twice: Once for clicking on the + * {@code postButton}
+ * and once for pressing the KeyStroke(s) to send a message ( (ctrl+)enter) + * + * @param client the client who wants to send a {@link Message} + * @param messageList the chat in which this {@link Message} belongs + * @since Envoy v0.1-alpha + */ + private void postMessage(Client client, JList messageList) { + if (!client.hasRecipient()) { + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); + return; + } + + if (!messageEnterTextArea.getText().isEmpty()) try { + + // Create and send message object + final Message message = client.createMessage(messageEnterTextArea.getText()); + client.sendMessage(message); + + // Append message object to chat + currentChat.appendMessage(message); + messageList.setModel(currentChat.getModel()); + + // Clear text field + messageEnterTextArea.setText(""); + contentPane.revalidate(); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + /** * Initializes the elements of the user list by downloading them from the * server. + * + * @since Envoy v0.1-alpha */ private void loadUsersAndChats() { new Thread(() -> { @@ -257,14 +320,17 @@ public class ChatWindow extends JFrame { * * @param timeout the amount of time that passes between two requests sent to * the server + * @since Envoy v0.1-alpha */ private void startReceiverThread(int timeout) { new Timer(timeout, (evt) -> { Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); for (int i = 0; i < unreadMessages.getMessage().size(); i++) for (int j = 0; j < localDB.getChats().size(); j++) - if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) - localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); + if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage() + .get(i) + .getMetaData() + .getSender()) localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); }).start(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java new file mode 100644 index 0000000..7d5de28 --- /dev/null +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -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: envoy-client
+ * File: SettingsScreen.java
+ * Created: 31 Oct 2019
+ * + * @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() { open(new SettingsScreen()); } + + /** + * Opens the Settings screen.
+ * Use preferably since everyone is already initialised.
+ * 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! + open(new SettingsScreen(username)); + } + + public static void open(SettingsScreen dialog) { + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setModal(true); + dialog.setVisible(true); + } + + /** + * Builds the Settings screen.
+ * Use only as Dev/Error Mode.
+ * 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.
+ * Use preferreably since everyone is already initialised.
+ * 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 instead of ctrl+enter + * @since Envoy v0.1-alpha + */ + public static boolean isEnterToSend() { return enterToSend; } + + /** + * @param enterToSend
+ * toggles whether a message should be sent via + *
+ * buttonpress "enter" or "ctrl"+"enter" + * @since Envoy v0.1-alpha + */ + public static void setEnterToSend(boolean enterForSend) { enterToSend = enterForSend; } + // TODO: Should be changed to private, but later to avoid warnings +}