diff --git a/.gitignore b/.gitignore
index e12b13a..2b99822 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/target/
-/localDB/
\ No newline at end of file
+/localDB/
+/themes.ser
diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java
index 4c775e1..8f96739 100644
--- a/src/main/java/envoy/client/Client.java
+++ b/src/main/java/envoy/client/Client.java
@@ -134,8 +134,8 @@ public class Client {
* their updated UserStatus to the client.)
*
* @param userId the id of the {@link Client} who sends the {@link Sync}
- * @param sync the {@link Sync} to send
- * @return a sync
+ * @param sync the sync object (yet to be converted from java class to sync.xml)
+ * @return a returnSync.xml file
* @since Envoy v0.1-alpha
*/
public Sync sendSync(long userId, Sync sync) {
diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java
index 116a341..bbd3b72 100644
--- a/src/main/java/envoy/client/Config.java
+++ b/src/main/java/envoy/client/Config.java
@@ -63,6 +63,7 @@ public class Config {
case "--localDB":
case "-db":
localDB = new File(args[++i]);
+ break;
}
}
@@ -113,13 +114,22 @@ public class Config {
/**
* Changes the default local database.
* Exclusively intended for development purposes.
- *
+ *
* @param localDB the file containing the local database
* @since Envoy v0.1-alpha
**/
public void setLocalDB(File localDB) { this.localDB = localDB; }
+ /**
+ * @return the current time (milliseconds) that is waited between Syncs
+ * @since Envoy v0.1-alpha
+ */
public int getSyncTimeout() { return syncTimeout; }
+ /**
+ * @param syncTimeout sets the time (milliseconds) during which Sync waits
+ * @since Envoy v0.1-alpha
+ */
public void setSyncTimeout(int syncTimeout) { this.syncTimeout = syncTimeout; }
+
}
diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java
index d952bef..f061b28 100644
--- a/src/main/java/envoy/client/LocalDB.java
+++ b/src/main/java/envoy/client/LocalDB.java
@@ -44,7 +44,7 @@ public class LocalDB {
private Sync sync = objectFactory.createSync();
private Sync readMessages = objectFactory.createSync();
- private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName());
+ private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName());
/**
* Constructs an empty local database.
@@ -112,14 +112,14 @@ public class LocalDB {
* Creates a {@link Message} object serializable to XML.
*
* @param textContent The content (text) of the message
- * @param recipient The recipient of the message
+ * @param recipientID The recipient of the message
* @return prepared {@link Message} object
* @since Envoy v0.1-alpha
*/
- public Message createMessage(String textContent, User recipient) {
+ public Message createMessage(String textContent, long recipientID) {
Message.Metadata metaData = objectFactory.createMessageMetadata();
metaData.setSender(sender.getID());
- metaData.setRecipient(recipient.getID());
+ metaData.setRecipient(recipientID);
metaData.setState(MessageState.WAITING);
metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString()));
diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java
new file mode 100644
index 0000000..91f696f
--- /dev/null
+++ b/src/main/java/envoy/client/Settings.java
@@ -0,0 +1,189 @@
+package envoy.client;
+
+import java.awt.Color;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.prefs.Preferences;
+
+import envoy.client.ui.Theme;
+
+/**
+ * Project: envoy-client
+ * File: Settings.java
+ * Created: 11 Nov 2019
+ *
+ * @author Leon Hofmeister
+ * @author Maximilian Käfer
+ * @author Kai S. K. Engelbart
+ * @since Envoy v0.2-alpha
+ */
+public class Settings {
+
+ // Actual settings accessible by the rest of the application
+ private String username;
+ private String email;
+ private boolean enterToSend = true;
+ private Map themes;
+ private String currentTheme;
+
+ /**
+ * Required to save the settings.
+ */
+ private Preferences prefs = Preferences.userNodeForPackage(Settings.class);
+
+ /**
+ * User-defined themes are stored inside this file.
+ */
+ private File themeFile = new File("themes.ser");
+
+ /**
+ * Singleton instance of this class.
+ */
+ private static Settings settings = new Settings();
+
+ /**
+ * The way to instantiate the settings.
+ * Is set to private to deny other instances of that object.
+ *
+ * @since Envoy v0.2-alpha
+ */
+ private Settings() { load(); }
+
+ /**
+ * This method is used to ensure that there is only one instance of Settings.
+ *
+ * @return the instance of Settings
+ * @since Envoy v0.2-alpha
+ */
+ public static Settings getInstance() { return settings; }
+
+ @SuppressWarnings("unchecked")
+ private void load() {
+ setUsername(prefs.get("username", ""));
+ setEmail(prefs.get("email", ""));
+ setEnterToSend(prefs.getBoolean("enterToSend", true));
+ setCurrentTheme(prefs.get("theme", "dark"));
+
+ // Load themes from theme file
+ try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) {
+ Object obj = in.readObject();
+ if(obj instanceof HashMap) themes = (Map) obj;
+ } catch (IOException | ClassNotFoundException e) {
+ themes = new HashMap<>();
+ currentTheme = "dark";
+ e.printStackTrace();
+ }
+
+ // Load standard themes not defined in the themes file
+ themes.put("dark",
+ new Theme("dark", Color.black, Color.darkGray, Color.white, Color.blue, Color.white, Color.orange, Color.blue, Color.white,
+ Color.white));
+ themes.put("light",
+ new Theme("light", new Color(235, 235, 235), Color.white, Color.white, Color.darkGray, Color.black, Color.orange, Color.darkGray,
+ Color.black, Color.black));
+ }
+
+ /**
+ * updates prefs when save button is clicked
+ *
+ * @throws IOException
+ * @since Envoy v0.2-alpha
+ */
+ public void save() throws IOException{
+ prefs.put("username", getUsername());
+ prefs.put("email", getEmail());
+ prefs.put("theme", currentTheme);
+ prefs.putBoolean("enterToSend", isEnterToSend());
+
+ // Save themes to theme file
+ themeFile.createNewFile();
+ try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) {
+ out.writeObject(themes);
+ }
+ }
+
+ /**
+ * adds new theme to the theme map and sets current theme to the new theme.
+ *
+ * @param theme
+ * @since Envoy v0.2-alpha
+ */
+ public void addNewThemeToMap(Theme theme) {
+ settings.getThemes().put(theme.getThemeName(), theme);
+ currentTheme = theme.getThemeName();
+ }
+
+ /**
+ * @return {@link currentTheme}
+ * @since Envoy v0.2-alpha
+ */
+ public String getCurrentTheme() { return currentTheme; }
+
+ /**
+ * Sets the currentTheme
+ *
+ * @param themeName
+ * @since Envoy v0.2-alpha
+ */
+ public void setCurrentTheme(String themeName) { currentTheme = themeName; }
+
+ /**
+ * @return the user name
+ * @since Envoy v0.2-alpha
+ */
+ public String getUsername() { return username; }
+
+ /**
+ * @param username the user name to set
+ * @since Envoy v0.2-alpha
+ */
+ public void setUsername(String username) { this.username = username; }
+
+ /**
+ * @return the email associated with that user.
+ * @since Envoy v0.2-alpha
+ */
+ public String getEmail() { return email; }
+
+ /**
+ * @param email the email to set
+ * @since Envoy v0.2-alpha
+ */
+ public void setEmail(String email) { this.email = email; }
+
+ /**
+ * @return true, if "enter" suffices to send a message, else it has to be "ctrl"
+ * + "enter"
+ * @since Envoy v0.2-alpha
+ */
+ public boolean isEnterToSend() { return enterToSend; }
+
+ /**
+ * Change mode of posting a message via Keystroke.
+ *
+ * @param enterToSend if true, "enter" suffices to send a message,
+ * else it has to be "ctrl" + "enter"
+ * @since Envoy v0.2-alpha
+ */
+ public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; }
+
+ /**
+ * @return {@link themes} map
+ * @since Envoy v0.2-alpha
+ */
+ public Map getThemes() { return themes; }
+
+ /**
+ * Sets {@link themes}
+ *
+ * @param themes
+ * @since Envoy v0.2-alpha
+ */
+ public void setThemes(Map themes) { this.themes = themes; }
+}
\ No newline at end of file
diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java
index 05da3c3..6867f5e 100644
--- a/src/main/java/envoy/client/ui/ChatWindow.java
+++ b/src/main/java/envoy/client/ui/ChatWindow.java
@@ -1,6 +1,5 @@
package envoy.client.ui;
-import java.awt.Color;
import java.awt.ComponentOrientation;
import java.awt.Font;
import java.awt.GridBagConstraints;
@@ -33,6 +32,7 @@ import envoy.client.Chat;
import envoy.client.Client;
import envoy.client.Config;
import envoy.client.LocalDB;
+import envoy.client.Settings;
import envoy.schema.Message;
import envoy.schema.Sync;
import envoy.schema.User;
@@ -51,15 +51,22 @@ public class ChatWindow extends JFrame {
private static final long serialVersionUID = 6865098428255463649L;
- private JPanel contentPane = new JPanel();
-
+ // user specific objects
private Client client;
private LocalDB localDB;
+ // GUI components
+ private JPanel contentPane = new JPanel();
+ private JTextArea messageEnterTextArea = new JTextArea();
+ private JList userList = new JList<>();
+ private Chat currentChat;
+ private JList messageList = new JList<>();
+ private JScrollPane scrollPane = new JScrollPane();
+ private JTextPane textPane = new JTextPane();
+ // private JCheckBox jCbChangeMode;
+ private JButton postButton = new JButton("Post");
+ private JButton settingsButton = new JButton("Settings");
- private JList userList = new JList<>();
- private Chat currentChat;
-
- private JTextArea messageEnterTextArea;
+ private static int space = 4;
private static final Logger logger = Logger.getLogger(ChatWindow.class.getSimpleName());
@@ -80,6 +87,7 @@ public class ChatWindow extends JFrame {
public void windowClosing(WindowEvent evt) {
try {
localDB.saveToLocalDB();
+ Settings.getInstance().save();
} catch (IOException e1) {
e1.printStackTrace();
logger.log(Level.WARNING, "Unable to save the messages", e1);
@@ -87,9 +95,7 @@ public class ChatWindow extends JFrame {
}
});
- contentPane.setBackground(new Color(0, 0, 0));
- contentPane.setForeground(Color.white);
- contentPane.setBorder(new EmptyBorder(0, 5, 0, 0));
+ contentPane.setBorder(new EmptyBorder(space, space, space, space));
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[] { 1, 1, 1 };
@@ -98,25 +104,16 @@ public class ChatWindow extends JFrame {
gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 };
contentPane.setLayout(gbl_contentPane);
- JList messageList = new JList<>();
messageList.setCellRenderer(new MessageListRenderer());
-
messageList.setFocusTraversalKeysEnabled(false);
- messageList.setSelectionForeground(new Color(255, 255, 255));
- messageList.setSelectionBackground(new Color(102, 0, 153));
messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
- messageList.setForeground(new Color(255, 255, 255));
- messageList.setBackground(new Color(51, 51, 51));
DefaultListModel messageListModel = new DefaultListModel<>();
messageList.setModel(messageListModel);
messageList.setFont(new Font("Arial", Font.PLAIN, 17));
messageList.setFixedCellHeight(60);
- messageList.setBorder(new EmptyBorder(5, 5, 5, 5));
+ messageList.setBorder(new EmptyBorder(space, space, space, space));
- JScrollPane scrollPane = new JScrollPane();
- scrollPane.setForeground(new Color(0, 0, 0));
- scrollPane.setBackground(new Color(51, 51, 51));
scrollPane.setViewportView(messageList);
scrollPane.setBorder(null);
@@ -126,61 +123,51 @@ public class ChatWindow extends JFrame {
gbc_scrollPane.gridx = 1;
gbc_scrollPane.gridy = 1;
- gbc_scrollPane.insets = new Insets(0, 10, 10, 10);
-
+ gbc_scrollPane.insets = new Insets(space, space, space, space);
contentPane.add(scrollPane, gbc_scrollPane);
// Message enter field
- messageEnterTextArea = new JTextArea();
messageEnterTextArea.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER
- && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK)))
+ && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0)
+ || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) {
postMessage(messageList);
+ }
}
});
// 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));
+ messageEnterTextArea.setBorder(new EmptyBorder(space, space, space, space));
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);
+ gbc_messageEnterTextfield.insets = new Insets(space, space, space, space);
contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield);
// Post Button
- JButton postButton = new JButton("Post");
- postButton.setForeground(new Color(255, 255, 255));
- postButton.setBackground(new Color(102, 51, 153));
postButton.setBorderPainted(false);
-
GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints();
gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH;
gbc_moveSelectionPostButton.gridx = 2;
gbc_moveSelectionPostButton.gridy = 2;
- gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10);
+ gbc_moveSelectionPostButton.insets = new Insets(space, space, space, space);
postButton.addActionListener((evt) -> { postMessage(messageList); });
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();
@@ -189,12 +176,13 @@ public class ChatWindow extends JFrame {
gbc_moveSelectionSettingsButton.gridx = 2;
gbc_moveSelectionSettingsButton.gridy = 0;
- gbc_moveSelectionSettingsButton.insets = new Insets(10, 10, 10, 10);
+ gbc_moveSelectionSettingsButton.insets = new Insets(space, space, space, space);
settingsButton.addActionListener((evt) -> {
try {
- SettingsScreen.open(localDB.getUser().getName());
- } catch (Exception e) {
+ SettingsScreen.open();
+ changeChatWindowColors(Settings.getInstance().getCurrentTheme());
+ } catch (Exception e) {
SettingsScreen.open();
logger.log(Level.WARNING, "An error occured while opening the settings screen", e);
e.printStackTrace();
@@ -203,18 +191,15 @@ public class ChatWindow extends JFrame {
contentPane.add(settingsButton, gbc_moveSelectionSettingsButton);
// Partner name display
- JTextPane textPane = new JTextPane();
- textPane.setBackground(new Color(0, 0, 0));
- textPane.setForeground(new Color(255, 255, 255));
-
textPane.setFont(new Font("Arial", Font.PLAIN, 20));
+ textPane.setEditable(false);
GridBagConstraints gbc_partnerName = new GridBagConstraints();
gbc_partnerName.fill = GridBagConstraints.HORIZONTAL;
gbc_partnerName.gridx = 1;
gbc_partnerName.gridy = 0;
- gbc_partnerName.insets = new Insets(0, 10, 0, 10);
+ gbc_partnerName.insets = new Insets(space, space, space, space);
contentPane.add(textPane, gbc_partnerName);
userList.setCellRenderer(new UserListRenderer());
@@ -232,7 +217,6 @@ public class ChatWindow extends JFrame {
readCurrentChat();
client.setRecipient(user);
-
textPane.setText(currentChat.getRecipient().getName());
messageList.setModel(currentChat.getModel());
@@ -240,20 +224,18 @@ public class ChatWindow extends JFrame {
}
});
- userList.setSelectionForeground(new Color(255, 255, 255));
- userList.setSelectionBackground(new Color(102, 0, 153));
- userList.setForeground(new Color(255, 255, 255));
- userList.setBackground(new Color(51, 51, 51));
userList.setFont(new Font("Arial", Font.PLAIN, 17));
- userList.setBorder(new EmptyBorder(5, 5, 5, 5));
+ userList.setBorder(new EmptyBorder(space, space, space, space));
GridBagConstraints gbc_userList = new GridBagConstraints();
gbc_userList.fill = GridBagConstraints.VERTICAL;
gbc_userList.gridx = 0;
gbc_userList.gridy = 1;
gbc_userList.anchor = GridBagConstraints.PAGE_START;
- gbc_userList.insets = new Insets(0, 0, 10, 0);
+ gbc_userList.insets = new Insets(space, space, space, space);
+ changeChatWindowColors(Settings.getInstance().getCurrentTheme());
+
contentPane.add(userList, gbc_userList);
contentPane.revalidate();
@@ -262,17 +244,61 @@ public class ChatWindow extends JFrame {
contentPane.revalidate();
}
+
+
+ /**
+ * Used to immediately reload the ChatWindow when settings were changed.
+ *
+ * @since Envoy v0.1-alpha
+ */
+ public void changeChatWindowColors(String key) {
+ Theme theme = Settings.getInstance().getThemes().get(key);
+
+ // contentPane
+ contentPane.setBackground(theme.getBackgroundColor());
+ contentPane.setForeground(theme.getUserNameColor());
+ // messageList
+ messageList.setSelectionForeground(theme.getUserNameColor());
+ messageList.setSelectionBackground(theme.getSelectionColor());
+ messageList.setForeground(theme.getMessageColorChat());
+ messageList.setBackground(theme.getCellColor());
+ // scrollPane
+ scrollPane.setForeground(theme.getBackgroundColor());
+ scrollPane.setBackground(theme.getCellColor());
+ // messageEnterTextArea
+ messageEnterTextArea.setCaretColor(theme.getTypingMessageColor());
+ messageEnterTextArea.setForeground(theme.getTypingMessageColor());
+ messageEnterTextArea.setBackground(theme.getCellColor());
+ // postButton
+ postButton.setForeground(theme.getInteractableForegroundColor());
+ postButton.setBackground(theme.getInteractableBackgroundColor());
+ // settingsButton
+ settingsButton.setForeground(theme.getInteractableForegroundColor());
+ settingsButton.setBackground(theme.getInteractableBackgroundColor());
+ // textPane
+ textPane.setBackground(theme.getBackgroundColor());
+ textPane.setForeground(theme.getUserNameColor());
+ // userList
+ userList.setSelectionForeground(theme.getUserNameColor());
+ userList.setSelectionBackground(theme.getSelectionColor());
+ userList.setForeground(theme.getUserNameColor());
+ userList.setBackground(theme.getCellColor());
+ }
private void postMessage(JList messageList) {
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;
}
if (!messageEnterTextArea.getText().isEmpty()) try {
// Create and send message object
- final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient());
+ final Message message = localDB.createMessage(messageEnterTextArea.getText(),
+ currentChat.getRecipient().getID());
currentChat.appendMessage(message);
messageList.setModel(currentChat.getModel());
@@ -322,7 +348,8 @@ public class ChatWindow extends JFrame {
new Thread(() -> {
// Synchronize
- localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID())));
+ localDB.applySync(
+ client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID())));
// Process unread messages
localDB.addUnreadMessagesToLocalDB();
@@ -332,7 +359,8 @@ public class ChatWindow extends JFrame {
readCurrentChat();
// Update UI
- SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); });
+ SwingUtilities
+ .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); });
}).start();
}).start();
}
@@ -349,3 +377,4 @@ public class ChatWindow extends JFrame {
*/
private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } }
}
+
diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java
index 3e6eb23..2e6b65f 100644
--- a/src/main/java/envoy/client/ui/MessageListRenderer.java
+++ b/src/main/java/envoy/client/ui/MessageListRenderer.java
@@ -1,5 +1,6 @@
package envoy.client.ui;
+import java.awt.Color;
import java.awt.Component;
import java.text.SimpleDateFormat;
@@ -7,6 +8,7 @@ import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
+import envoy.client.Settings;
import envoy.schema.Message;
/**
@@ -40,10 +42,35 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer%s
%s :%s