Merge branch 'develop' into b/incorrect_color_change

This commit is contained in:
DieGurke 2019-12-14 14:03:02 +01:00 committed by GitHub
commit 049b2872db
12 changed files with 315 additions and 292 deletions

View File

@ -1,6 +1,7 @@
package envoy.client; package envoy.client;
import java.util.logging.Logger; import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity; import javax.ws.rs.client.Entity;
@ -10,6 +11,7 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller; import javax.xml.bind.Marshaller;
import envoy.exception.EnvoyException;
import envoy.schema.ObjectFactory; import envoy.schema.ObjectFactory;
import envoy.schema.Sync; import envoy.schema.Sync;
import envoy.schema.User; import envoy.schema.User;
@ -29,14 +31,28 @@ public class Client {
private ObjectFactory objectFactory = new ObjectFactory(); private ObjectFactory objectFactory = new ObjectFactory();
private Config config; private Config config;
private User sender, recipient; private User sender, recipient;
private boolean online = false;
private static final Logger logger = Logger.getLogger(Client.class.getSimpleName()); /**
* Initializes the client. At this state, the client user has yet to be
* initialized, which can be done by calling {@link Client#onlineInit(String).
*
* @param config The {@link Config} instance to use in this client
* @since Envoy v0.2-alpha
*/
public Client(Config config) { this.config = config; }
public Client(Config config, String username) { /**
this.config = config; * Enters the online mode by acquiring a user ID from the server.
sender = getUser(username); *
* @param userName the name of the client user
logger.info("ID: " + sender.getID()); * @throws EnvoyException if the online mode could not be entered or the request
* failed for some other reason
* @since Envoy v0.2-alpha
*/
public void onlineInit(String userName) throws EnvoyException {
sender = getUser(userName);
online = true;
} }
private <T, R> R post(String uri, T body, Class<R> responseBodyClass) { private <T, R> R post(String uri, T body, Class<R> responseBodyClass) {
@ -48,28 +64,26 @@ public class Client {
client.close(); client.close();
return responseBody; return responseBody;
} }
/** /**
* Returns a {@link Sync} with all users on the server. * @return a {@code Map<String, User>} of all users on the server with their
* * user names as keys
* @return Sync - List of all users on the server. * @since Envoy v0.2-alpha
* @since Envoy v0.1-alpha
*/ */
public Sync getUsersListXml() { public Map<String, User> getUsers() {
Sync sendSync = objectFactory.createSync(); Sync sendSync = objectFactory.createSync();
User user = objectFactory.createUser(); User user = objectFactory.createUser();
user.setID(-1); user.setID(-1);
sendSync.getUsers().add(user); sendSync.getUsers().add(user);
Sync returnSendSync = post( Sync returnSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0),
String
.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0),
sendSync, sendSync,
Sync.class); Sync.class);
return returnSendSync;
Map<String, User> users = new HashMap<>();
returnSync.getUsers().forEach(u -> users.put(u.getName(), u));
return users;
} }
/** /**
@ -77,29 +91,29 @@ public class Client {
* *
* @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
* @throws EnvoyException if the server does not return the requested ID
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
private User getUser(String name) { private User getUser(String name) throws EnvoyException {
// Create a sync with only a user with the requested name
Sync senderSync = objectFactory.createSync(); Sync senderSync = objectFactory.createSync();
User user = objectFactory.createUser(); User user = objectFactory.createUser();
user.setName(name); user.setName(name);
senderSync.getUsers().add(user); senderSync.getUsers().add(user);
Sync returnSenderSync = post( try {
String Sync sync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0),
.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0),
senderSync, senderSync,
Sync.class); Sync.class);
User returnSender = objectFactory.createUser(); // Expecting a single user with an ID
if (sync.getUsers().size() == 1) {
if (returnSenderSync.getUsers().size() == 1) { online = true;
returnSender = returnSenderSync.getUsers().get(0); return sync.getUsers().get(0);
} else { } else throw new EnvoyException("Unexpected response from Envoy Server");
logger.warning("ERROR exiting..."); } catch (Exception e) {
throw new EnvoyException("Could not connect to server", e);
} }
return returnSender;
} }
/** /**
@ -134,11 +148,15 @@ public class Client {
* their updated UserStatus to the client.) <br> * their updated UserStatus to the client.) <br>
* *
* @param userId the id of the {@link Client} who sends the {@link Sync} * @param userId the id of the {@link Client} who sends the {@link Sync}
* @param sync the sync object (yet to be converted from java class to sync.xml) * @param sync the sync object (yet to be converted from java class to
* sync.xml)
* @return a returnSync.xml file * @return a returnSync.xml file
* @throws EnvoyException if the client is not in online mode
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public Sync sendSync(long userId, Sync sync) { public Sync sendSync(long userId, Sync sync) throws EnvoyException {
if(!isOnline())
throw new EnvoyException("Client is not in online mode");
// Print sync XML to console // Print sync XML to console
JAXBContext jc; JAXBContext jc;
try { try {
@ -151,10 +169,7 @@ public class Client {
} }
// Send sync // Send sync
return post(String return post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), sync, Sync.class);
.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId),
sync,
Sync.class);
} }
/** /**
@ -163,6 +178,14 @@ public class Client {
*/ */
public User getSender() { return sender; } public User getSender() { return sender; }
/**
* Sets the client user which is used to send messages.
*
* @param sender the client user to set
* @since Envoy v0.2-alpha
*/
public void setSender(User sender) { this.sender = sender; }
/** /**
* @return the current recipient of the current chat. * @return the current recipient of the current chat.
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
@ -172,7 +195,7 @@ public class Client {
/** /**
* Sets the recipient. * Sets the recipient.
* *
* @param recipient - the recipient to set * @param recipient the recipient to set
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public void setRecipient(User recipient) { this.recipient = recipient; } public void setRecipient(User recipient) { this.recipient = recipient; }
@ -182,4 +205,10 @@ public class Client {
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public boolean hasRecipient() { return recipient != null; } public boolean hasRecipient() { return recipient != null; }
/**
* @return {@code true} if a connection to the server could be established
* @since Envoy v0.2-alpha
*/
public boolean isOnline() { return online; }
} }

View File

@ -3,6 +3,8 @@ package envoy.client;
import java.io.File; import java.io.File;
import java.util.Properties; import java.util.Properties;
import envoy.exception.EnvoyException;
/** /**
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>Config.java</strong><br> * File: <strong>Config.java</strong><br>
@ -29,17 +31,26 @@ public class Config {
/** /**
* Defaults to the {@code client.properties} file for information. * Defaults to the {@code client.properties} file for information.
* * This file contains information about
* @param properties a {@link Properties} object containing information about
* the server and port, as well as the path to the local * the server and port, as well as the path to the local
* database and the synchronization timeout * database and the synchronization timeout
*
* @throws EnvoyException if the {@code client.properties} file could not be
* loaded
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public void load(Properties properties) { public void load() throws EnvoyException {
ClassLoader loader = getClass().getClassLoader();
try {
Properties properties = new Properties();
properties.load(loader.getResourceAsStream("client.properties"));
if (properties.containsKey("server")) server = properties.getProperty("server"); if (properties.containsKey("server")) server = properties.getProperty("server");
if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port"));
localDB = new File(properties.getProperty("localDB", ".\\localDB")); localDB = new File(properties.getProperty("localDB", ".\\localDB"));
syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000")); syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000"));
} catch (Exception e) {
throw new EnvoyException("Failed to load client.properties", e);
}
} }
/** /**
@ -47,9 +58,10 @@ public class Config {
* -s, --port / -p and --localDB / -db. * -s, --port / -p and --localDB / -db.
* *
* @param args the command line arguments to parse * @param args the command line arguments to parse
* @throws EnvoyException if the command line arguments contain an unknown token
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public void load(String[] args) { public void load(String[] args) throws EnvoyException {
for (int i = 0; i < args.length; i++) for (int i = 0; i < args.length; i++)
switch (args[i]) { switch (args[i]) {
case "--server": case "--server":
@ -64,6 +76,8 @@ public class Config {
case "-db": case "-db":
localDB = new File(args[++i]); localDB = new File(args[++i]);
break; break;
default:
throw new EnvoyException("Unknown token " + args[i] + " found");
} }
} }
@ -71,9 +85,7 @@ 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() { public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; }
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

@ -8,7 +8,9 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConfigurationException;
@ -34,9 +36,11 @@ import envoy.schema.User;
*/ */
public class LocalDB { public class LocalDB {
private File localDB; private File localDBDir, localDBFile, usersFile;
private User sender; private User user;
private Map<String, User> users = new HashMap<>();
private List<Chat> chats = new ArrayList<>(); private List<Chat> chats = new ArrayList<>();
private ObjectFactory objectFactory = new ObjectFactory(); private ObjectFactory objectFactory = new ObjectFactory();
private DatatypeFactory datatypeFactory; private DatatypeFactory datatypeFactory;
@ -47,64 +51,91 @@ public class LocalDB {
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. * Constructs an empty local database. To serialize any chats to the file
* system, call {@link LocalDB#initializeDBFile(File)}.
* *
* @param sender the user that is logged in with this client * @param localDBDir the directory in which to store users and chats
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public LocalDB(User sender) { public LocalDB(File localDBDir) throws IOException {
this.sender = sender; this.localDBDir = localDBDir;
try { try {
datatypeFactory = DatatypeFactory.newInstance(); datatypeFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException e) { } catch (DatatypeConfigurationException e) {
e.printStackTrace(); e.printStackTrace();
} }
// Initialize local database directory
if (localDBDir.exists() && !localDBDir.isDirectory())
throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath()));
usersFile = new File(localDBDir, "users.db");
} }
/** /**
* Initializes the local database and fills it with values * Creates a database file for a user-specific list of chats.
* if the user has already sent or received messages.
* *
* @param localDBDir the directory where we wish to save/load the database from. * @throws NullPointerException if the client user is not yet specified
* @throws EnvoyException if the directory selected is not an actual directory.
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public void initializeDBFile(File localDBDir) throws EnvoyException { public void initializeDBFile() {
if (localDBDir.exists() && !localDBDir.isDirectory()) if (user == null) throw new NullPointerException("Client user is null");
throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); localDBFile = new File(localDBDir, user.getID() + ".db");
localDB = new File(localDBDir, sender.getID() + ".db");
if (localDB.exists()) loadFromLocalDB();
} }
/** /**
* Saves the database into a file for future use. * Stores all users to the local database. If the client user is specified, the
* chats related to this user are stored as well.
* *
* @throws IOException if something went wrong during saving * @throws IOException if something went wrong during saving
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public void saveToLocalDB() throws IOException { public void save() throws IOException {
localDB.getParentFile().mkdirs(); // Save users
localDB.createNewFile(); write(usersFile, users);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) {
out.writeObject(chats); // Save chats
} catch (IOException ex) { write(localDBFile, chats);
throw ex;
}
} }
/**
* Loads all users that are stored in the local database.
*
* @throws EnvoyException if the loading process failed
* @since Envoy v0.2-alpha
*/
@SuppressWarnings("unchecked")
public void loadUsers() throws EnvoyException { users = read(usersFile, HashMap.class); }
/** /**
* Loads all chats saved by Envoy for the client user. * Loads all chats saved by Envoy for the client user.
* *
* @throws EnvoyException if something fails while loading. * @throws EnvoyException if the loading process failed
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void loadFromLocalDB() throws EnvoyException { public void loadChats() throws EnvoyException { chats = read(localDBFile, ArrayList.class); }
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) {
Object obj = in.readObject(); private <T> T read(File file, Class<T> serializedClass) throws EnvoyException {
if (obj instanceof ArrayList<?>) chats = (ArrayList<Chat>) obj; if (file == null) throw new NullPointerException("File is null");
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) {
return serializedClass.cast(in.readObject());
} catch (ClassNotFoundException | IOException e) { } catch (ClassNotFoundException | IOException e) {
throw new EnvoyException(e); throw new EnvoyException("Could not load serialized object", e);
}
}
private <T> void write(File file, T obj) throws IOException {
if (file == null) throw new NullPointerException("File is null");
if (obj == null) throw new NullPointerException("Object to serialize is null");
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
out.writeObject(obj);
} catch (IOException e) {
throw e;
} }
} }
@ -118,7 +149,7 @@ public class LocalDB {
*/ */
public Message createMessage(String textContent, long recipientID) { public Message createMessage(String textContent, long recipientID) {
Message.Metadata metaData = objectFactory.createMessageMetadata(); Message.Metadata metaData = objectFactory.createMessageMetadata();
metaData.setSender(sender.getID()); metaData.setSender(user.getID());
metaData.setRecipient(recipientID); metaData.setRecipient(recipientID);
metaData.setState(MessageState.WAITING); metaData.setState(MessageState.WAITING);
metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString()));
@ -280,6 +311,17 @@ public class LocalDB {
*/ */
public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); }
/**
* @return a {@code Map<String, User>} of all users stored locally with their user names as keys
* @since Envoy v0.2-alpha
*/
public Map<String, User> getUsers() { return users; }
/**
* @param users the users to set
*/
public void setUsers(Map<String, User> users) { this.users = users; }
/** /**
* @return all saved {@link Chat} objects that list the client user as the * @return all saved {@link Chat} objects that list the client user as the
* sender * sender
@ -288,8 +330,19 @@ public class LocalDB {
public List<Chat> getChats() { return chats; } public List<Chat> getChats() { return chats; }
/** /**
* @return the {@link User} who initialized the local database * @param chats the chats to set
* @since Envoy v0.1-alpha
*/ */
public User getUser() { return sender; } public void setChats(List<Chat> chats) { this.chats = chats; }
/**
* @return the {@link User} who initialized the local database
* @since Envoy v0.2-alpha
*/
public User getUser() { return user; }
/**
* @param user the user to set
* @since Envoy v0.2-alpha
*/
public void setUser(User user) { this.user = user; }
} }

View File

@ -26,8 +26,6 @@ import envoy.client.ui.Theme;
public class Settings { public class Settings {
// Actual settings accessible by the rest of the application // Actual settings accessible by the rest of the application
private String username;
private String email;
private boolean enterToSend = true; private boolean enterToSend = true;
private Map<String, Theme> themes; private Map<String, Theme> themes;
private String currentTheme; private String currentTheme;
@ -65,8 +63,6 @@ public class Settings {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void load() { private void load() {
setUsername(prefs.get("username", ""));
setEmail(prefs.get("email", ""));
setEnterToSend(prefs.getBoolean("enterToSend", true)); setEnterToSend(prefs.getBoolean("enterToSend", true));
setCurrentTheme(prefs.get("theme", "dark")); setCurrentTheme(prefs.get("theme", "dark"));
@ -90,14 +86,12 @@ public class Settings {
} }
/** /**
* updates prefs when save button is clicked * Updates the preferences when the save button is clicked.
* *
* @throws IOException * @throws IOException
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void save() throws IOException { public void save() throws IOException {
prefs.put("username", getUsername());
prefs.put("email", getEmail());
prefs.put("theme", currentTheme); prefs.put("theme", currentTheme);
prefs.putBoolean("enterToSend", isEnterToSend()); prefs.putBoolean("enterToSend", isEnterToSend());
@ -133,30 +127,6 @@ public class Settings {
*/ */
public void setCurrentTheme(String themeName) { currentTheme = themeName; } 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" * @return true, if "enter" suffices to send a message, else it has to be "ctrl"
* + "enter" * + "enter"

View File

@ -32,7 +32,6 @@ import envoy.client.Config;
import envoy.client.LocalDB; import envoy.client.LocalDB;
import envoy.client.Settings; import envoy.client.Settings;
import envoy.schema.Message; import envoy.schema.Message;
import envoy.schema.Sync;
import envoy.schema.User; import envoy.schema.User;
/** /**
@ -54,15 +53,15 @@ public class ChatWindow extends JFrame {
private LocalDB localDB; private LocalDB localDB;
// GUI components // GUI components
private JPanel contentPane = new JPanel(); private JPanel contentPane = new JPanel();
private PrimaryTextArea messageEnterTextArea; private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space);
private JList<User> userList = new JList<>(); private JList<User> userList = new JList<>();
private Chat currentChat; private Chat currentChat;
private JList<Message> messageList = new JList<>(); private JList<Message> messageList = new JList<>();
private JScrollPane scrollPane = new JScrollPane(); private JScrollPane scrollPane = new JScrollPane();
private JTextPane textPane = new JTextPane(); private JTextPane textPane = new JTextPane();
// private JCheckBox jCbChangeMode; // private JCheckBox jCbChangeMode;
private PrimaryButton postButton; private PrimaryButton postButton = new PrimaryButton("Post");
private PrimaryButton settingsButton; private PrimaryButton settingsButton = new PrimaryButton("Settings");
private static int space = 4; private static int space = 4;
@ -84,7 +83,7 @@ public class ChatWindow extends JFrame {
@Override @Override
public void windowClosing(WindowEvent evt) { public void windowClosing(WindowEvent evt) {
try { try {
localDB.saveToLocalDB(); localDB.save();
Settings.getInstance().save(); Settings.getInstance().save();
} catch (IOException e1) { } catch (IOException e1) {
e1.printStackTrace(); e1.printStackTrace();
@ -124,23 +123,18 @@ public class ChatWindow extends JFrame {
gbc_scrollPane.insets = new Insets(space, space, space, space); gbc_scrollPane.insets = new Insets(space, space, space, space);
contentPane.add(scrollPane, gbc_scrollPane); contentPane.add(scrollPane, gbc_scrollPane);
// Checks for changed Message
messageEnterTextArea = new PrimaryTextArea(space);
// Message enter field // Message enter field
messageEnterTextArea.addKeyListener(new KeyAdapter() { messageEnterTextArea.addKeyListener(new KeyAdapter() {
@Override @Override
public void keyReleased(KeyEvent e) { public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER if (e.getKeyCode() == KeyEvent.VK_ENTER
&& ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) {
|| (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) {
postMessage(messageList); postMessage(messageList);
} }
} }
}); });
GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints();
gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH;
gbc_messageEnterTextfield.gridx = 1; gbc_messageEnterTextfield.gridx = 1;
@ -151,7 +145,6 @@ public class ChatWindow extends JFrame {
contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield);
// Post Button // Post Button
postButton = new PrimaryButton("Post");
GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints();
gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH;
@ -164,8 +157,6 @@ public class ChatWindow extends JFrame {
contentPane.add(postButton, gbc_moveSelectionPostButton); contentPane.add(postButton, gbc_moveSelectionPostButton);
// Settings Button // Settings Button
settingsButton = new PrimaryButton("Settings");
GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints();
gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH;
@ -236,12 +227,12 @@ public class ChatWindow extends JFrame {
contentPane.revalidate(); contentPane.revalidate();
loadUsersAndChats(); loadUsersAndChats();
startSyncThread(Config.getInstance().getSyncTimeout());
if (client.isOnline()) startSyncThread(Config.getInstance().getSyncTimeout());
contentPane.revalidate(); contentPane.revalidate();
} }
/** /**
* Used to immediately reload the ChatWindow when settings were changed. * Used to immediately reload the ChatWindow when settings were changed.
* *
@ -283,18 +274,14 @@ public class ChatWindow extends JFrame {
private void postMessage(JList<Message> messageList) { private void postMessage(JList<Message> messageList) {
if (!client.hasRecipient()) { if (!client.hasRecipient()) {
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE);
"Please select a recipient!",
"Cannot send message",
JOptionPane.INFORMATION_MESSAGE);
return; return;
} }
if (!messageEnterTextArea.getText().isEmpty()) try { if (!messageEnterTextArea.getText().isEmpty()) try {
// Create and send message object // Create and send message object
final Message message = localDB.createMessage(messageEnterTextArea.getText(), final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID());
currentChat.getRecipient().getID());
currentChat.appendMessage(message); currentChat.appendMessage(message);
messageList.setModel(currentChat.getModel()); messageList.setModel(currentChat.getModel());
@ -318,9 +305,8 @@ public class ChatWindow extends JFrame {
*/ */
private void loadUsersAndChats() { private void loadUsersAndChats() {
new Thread(() -> { new Thread(() -> {
Sync users = client.getUsersListXml();
DefaultListModel<User> userListModel = new DefaultListModel<>(); DefaultListModel<User> userListModel = new DefaultListModel<>();
users.getUsers().forEach(user -> { localDB.getUsers().values().forEach(user -> {
userListModel.addElement(user); userListModel.addElement(user);
// Check if user exists in local DB // Check if user exists in local DB
@ -344,8 +330,11 @@ public class ChatWindow extends JFrame {
new Thread(() -> { new Thread(() -> {
// Synchronize // Synchronize
localDB.applySync( try {
client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID())));
} catch (Exception e) {
logger.log(Level.SEVERE, "Could not perform sync", e);
}
// Process unread messages // Process unread messages
localDB.addUnreadMessagesToLocalDB(); localDB.addUnreadMessagesToLocalDB();
@ -355,8 +344,7 @@ public class ChatWindow extends JFrame {
readCurrentChat(); readCurrentChat();
// Update UI // Update UI
SwingUtilities SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); });
.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); });
}).start(); }).start();
}).start(); }).start();
} }
@ -373,4 +361,3 @@ public class ChatWindow extends JFrame {
*/ */
private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } }
} }

View File

@ -42,22 +42,18 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer<Mess
final String text = value.getContent().get(0).getText(); final String text = value.getContent().get(0).getText();
final String state = value.getMetadata().getState().toString(); final String state = value.getMetadata().getState().toString();
final String date = value.getMetadata().getDate() == null ? "" final String date = value.getMetadata().getDate() == null ? ""
: new SimpleDateFormat("dd.MM.yyyy HH:mm ") : new SimpleDateFormat("dd.MM.yyyy HH:mm ").format(value.getMetadata().getDate().toGregorianCalendar().getTime());
.format(value.getMetadata().getDate().toGregorianCalendar().getTime());
// Getting the MessageColor in the Chat of the current theme // Getting the MessageColor in the Chat of the current theme
String textColor = null; String textColor = null;
textColor = toHex( textColor = toHex(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat());
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat());
// Getting the DateColor in the Chat of the current theme // Getting the DateColor in the Chat of the current theme
String dateColor = null; String dateColor = null;
dateColor = toHex( dateColor = toHex(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat());
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat());
setText(String.format( setText(String.format("<html><p style=\"color:%s\"><b><small>%s</b></small><br><p style=\"color:%s\">%s :%s</html>",
"<html><p style=\"color:%s\"><b><small>%s</b></small><br><p style=\"color:%s\">%s :%s</html>",
dateColor, dateColor,
date, date,
textColor, textColor,

View File

@ -11,6 +11,7 @@ import javax.swing.JButton;
* *
* @author Kai S. K. Engelbart * @author Kai S. K. Engelbart
* @author Maximilian K&auml;fer * @author Maximilian K&auml;fer
* @since Envoy v0.2-alpha
*/ */
public class PrimaryButton extends JButton { public class PrimaryButton extends JButton {
@ -35,8 +36,6 @@ public class PrimaryButton extends JButton {
*/ */
public PrimaryButton(String title, int arcSize) { public PrimaryButton(String title, int arcSize) {
super(title); super(title);
// setForeground(new Color(255, 255, 255));
// setBackground(new Color(102, 51, 153));
setBorderPainted(false); setBorderPainted(false);
setFocusPainted(false); setFocusPainted(false);
setContentAreaFilled(false); setContentAreaFilled(false);

View File

@ -12,15 +12,15 @@ import javax.swing.border.EmptyBorder;
* Created: <strong>07.12.2019</strong><br> * Created: <strong>07.12.2019</strong><br>
* *
* @author Maximilian K&auml;fer * @author Maximilian K&auml;fer
* @since Envoy v0.2-alpha
*/ */
public class PrimaryTextArea extends JTextArea { public class PrimaryTextArea extends JTextArea {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = -5829028696155434913L;
private int arcSize; private int arcSize;
/** /**
* Creates TextArea * Creates the text area
* *
* @param borderSpace * @param borderSpace
* @since Envoy 0.2-alpha * @since Envoy 0.2-alpha
@ -28,10 +28,10 @@ public class PrimaryTextArea extends JTextArea {
public PrimaryTextArea(int borderSpace) { this(6, borderSpace); } public PrimaryTextArea(int borderSpace) { this(6, borderSpace); }
/** /**
* Creates TextArea * Creates the text area
* *
* @param arcSize * @param arcSize is the diameter of the arc at the four corners.
* @param borderSpace * @param borderSpace is the insets of the border on all four sides.
* @since Envoy 0.2-alpha * @since Envoy 0.2-alpha
*/ */
public PrimaryTextArea(int arcSize, int borderSpace) { public PrimaryTextArea(int arcSize, int borderSpace) {
@ -54,7 +54,7 @@ public class PrimaryTextArea extends JTextArea {
} }
/** /**
* @return the arcSize * @return the arcSize - the diameter of the arc at the four corners.
* @since Envoy 0.2-alpha * @since Envoy 0.2-alpha
*/ */
public int getArcSize() { return arcSize; } public int getArcSize() { return arcSize; }

View File

@ -101,8 +101,7 @@ public class SettingsScreen extends JDialog {
createNewThemeButton.setEnabled(false); createNewThemeButton.setEnabled(false);
temporaryTheme = new Theme("temporaryTheme", temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
// Content pane // Content pane
GridBagLayout gbl_contentPanel = new GridBagLayout(); GridBagLayout gbl_contentPanel = new GridBagLayout();
@ -190,20 +189,8 @@ public class SettingsScreen extends JDialog {
colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS));
colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
buildCustomizeElement(new JPanel(), buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 0);
new JButton(), buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 1);
new JTextPane(),
theme,
theme.getBackgroundColor(),
"Background",
0);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getCellColor(),
"Cells",
1);
buildCustomizeElement(new JPanel(), buildCustomizeElement(new JPanel(),
new JButton(), new JButton(),
new JTextPane(), new JTextPane(),
@ -218,41 +205,11 @@ public class SettingsScreen extends JDialog {
theme.getInteractableBackgroundColor(), theme.getInteractableBackgroundColor(),
"Interactable Background", "Interactable Background",
3); 3);
buildCustomizeElement(new JPanel(), buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 4);
new JButton(), buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 5);
new JTextPane(), buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 6);
theme, buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 7);
theme.getMessageColorChat(), buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 8);
"Messages Chat",
4);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getDateColorChat(),
"Date Chat",
5);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getSelectionColor(),
"Selection",
6);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getTypingMessageColor(),
"Typing Message",
7);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getUserNameColor(),
"User Names",
8);
GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); GridBagConstraints gbc_colorsPanel = new GridBagConstraints();
gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL;
@ -273,16 +230,14 @@ public class SettingsScreen extends JDialog {
String s = JOptionPane.showInputDialog("Enter a name for the new theme"); String s = JOptionPane.showInputDialog("Enter a name for the new theme");
System.out.println(s); System.out.println(s);
Settings.getInstance() Settings.getInstance()
.addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(),
temporaryTheme.getCellColor(), temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(),
temporaryTheme.getInteractableBackgroundColor(), temporaryTheme.getMessageColorChat(), temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(),
temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(),
temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor()));
themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1);
themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName();
temporaryTheme = new Theme("temporaryTheme", temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
createNewThemeButton.setEnabled(false); createNewThemeButton.setEnabled(false);
themes.addItem(themeArray[themeArray.length - 1]); themes.addItem(themeArray[themeArray.length - 1]);
@ -336,10 +291,6 @@ public class SettingsScreen extends JDialog {
getRootPane().setDefaultButton(okButton); getRootPane().setDefaultButton(okButton);
okButton.addActionListener((evt) -> { okButton.addActionListener((evt) -> {
try { try {
Settings.getInstance().setUsername(Settings.getInstance().getUsername());// still temporary
Settings.getInstance().setEmail(Settings.getInstance().getEmail());// still temporary value
Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary
Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName());
@ -400,21 +351,12 @@ public class SettingsScreen extends JDialog {
temporaryTheme = new Theme("temporaryTheme", temporaryTheme = new Theme("temporaryTheme",
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(),
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(),
Settings.getInstance() Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableForegroundColor(),
.getThemes() Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor(),
.get(Settings.getInstance().getCurrentTheme())
.getInteractableForegroundColor(),
Settings.getInstance()
.getThemes()
.get(Settings.getInstance().getCurrentTheme())
.getInteractableBackgroundColor(),
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(),
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(),
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(),
Settings.getInstance() Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getTypingMessageColor(),
.getThemes()
.get(Settings.getInstance().getCurrentTheme())
.getTypingMessageColor(),
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor());
colorsPanel.removeAll(); colorsPanel.removeAll();
@ -501,8 +443,7 @@ public class SettingsScreen extends JDialog {
private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); }
private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) {
String name, int yIndex) {
textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setFont(new Font("Arial", Font.PLAIN, 14));
textPane.setBackground(theme.getBackgroundColor()); textPane.setBackground(theme.getBackgroundColor());
textPane.setForeground(getInvertedColor(theme.getBackgroundColor())); textPane.setForeground(getInvertedColor(theme.getBackgroundColor()));

View File

@ -2,7 +2,6 @@ package envoy.client.ui;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.io.IOException; import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -11,12 +10,12 @@ import javax.swing.JOptionPane;
import envoy.client.Client; import envoy.client.Client;
import envoy.client.Config; import envoy.client.Config;
import envoy.client.LocalDB; import envoy.client.LocalDB;
import envoy.client.Settings;
import envoy.exception.EnvoyException; import envoy.exception.EnvoyException;
import envoy.schema.User;
/** /**
* Starts the Envoy client and prompts the user to enter their name. * Starts the Envoy client and prompts the user to enter their name.
* * <br>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>Startup.java</strong><br> * File: <strong>Startup.java</strong><br>
* Created: <strong>12 Oct 2019</strong><br> * Created: <strong>12 Oct 2019</strong><br>
@ -35,34 +34,69 @@ public class Startup {
Config config = Config.getInstance(); Config config = Config.getInstance();
// Load the configuration from client.properties first
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try { try {
Properties configProperties = new Properties(); // Load the configuration from client.properties first
configProperties.load(loader.getResourceAsStream("client.properties")); config.load();
config.load(configProperties);
} catch (IOException e) {
e.printStackTrace();
}
// Override configuration values with command line arguments // Override configuration values with command line arguments
if (args.length > 0) config.load(args); if (args.length > 0) config.load(args);
if (!config.isInitialized()) { // Check if all configuration values have been initialized
logger.severe("Server or port are not defined. Exiting..."); if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined");
JOptionPane.showMessageDialog(null, "Error loading configuration values.", "Configuration error", JOptionPane.ERROR_MESSAGE); } catch (Exception e) {
JOptionPane
.showMessageDialog(null, "Error loading configuration values: \n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE);
System.exit(1); System.exit(1);
e.printStackTrace();
} }
// Ask the user for their user name
String userName = JOptionPane.showInputDialog("Please enter your username"); String userName = JOptionPane.showInputDialog("Please enter your username");
if (userName == null || userName.isEmpty()) { if (userName == null || userName.isEmpty()) {
logger.severe("User name is not set or empty. Exiting..."); logger.severe("User name is not set or empty. Exiting...");
System.exit(1); System.exit(1);
} }
Client client = new Client(config, userName);
LocalDB localDB = new LocalDB(client.getSender()); // Initialize the local database
LocalDB localDB;
try { try {
localDB.initializeDBFile(config.getLocalDB()); localDB = new LocalDB(config.getLocalDB());
} catch (IOException e3) {
logger.log(Level.SEVERE, "Could not initialize local database", e3);
JOptionPane.showMessageDialog(null, "Could not initialize local database!\n" + e3.toString());
System.exit(1);
return;
}
// Acquire the client user (with ID) either from the server or from the local
// database, which triggers offline mode
Client client = new Client(config);
try {
// Try entering online mode first
client.onlineInit(userName);
} catch (Exception e1) {
logger.warning("Could not connect to server. Trying offline mode...");
try {
// Try entering offline mode
localDB.loadUsers();
User clientUser = localDB.getUsers().get(userName);
if(clientUser == null)
throw new EnvoyException("Could not enter offline mode: user name unknown");
client.setSender(clientUser);
} catch(Exception e2) {
JOptionPane.showMessageDialog(null, e1.toString(), "Client error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
return;
}
}
// Set client user in local database
localDB.setUser(client.getSender());
// Initialize chats in local database
try {
localDB.initializeDBFile();
localDB.loadChats();
} catch (EnvoyException e) { } catch (EnvoyException e) {
e.printStackTrace(); e.printStackTrace();
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
@ -70,13 +104,23 @@ public class Startup {
"Local DB error", "Local DB error",
JOptionPane.WARNING_MESSAGE); JOptionPane.WARNING_MESSAGE);
} }
Settings.getInstance().setUsername(userName);
logger.info("Client user ID: " + client.getSender().getID());
// Save all users to the local database
if(client.isOnline())
localDB.setUsers(client.getUsers());
EventQueue.invokeLater(() -> { EventQueue.invokeLater(() -> {
try { try {
ChatWindow chatWindow = new ChatWindow(client, localDB); ChatWindow chatWindow = new ChatWindow(client, localDB);
new StatusTrayIcon(chatWindow).show();
chatWindow.setVisible(true); chatWindow.setVisible(true);
try {
new StatusTrayIcon(chatWindow).show();
} catch (EnvoyException e) {
logger.warning("The StatusTrayIcon is not supported on this platform!");
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -26,9 +26,8 @@ public class Theme implements Serializable {
private Color selectionColor; private Color selectionColor;
private Color typingMessageColor; private Color typingMessageColor;
public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor,
Color interactableBackgroundColor, Color messageColorChat, Color dateColorChat, Color selectionColor, Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) {
Color typingMessageColor, Color userNameColor) {
this.themeName = themeName; this.themeName = themeName;

View File

@ -45,22 +45,15 @@ public class UserListRenderer extends JLabel implements ListCellRenderer<User> {
// Getting the UserNameColor of the current theme // Getting the UserNameColor of the current theme
String textColor = null; String textColor = null;
textColor = toHex( textColor = toHex(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor());
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor());
switch (status) { switch (status) {
case ONLINE: case ONLINE:
setText(String.format( setText(String
"<html><p style=\"color:#03fc20\"><b><small>%s</b></small><br><p style=\"color:%s\">%s</html>", .format("<html><p style=\"color:#03fc20\"><b><small>%s</b></small><br><p style=\"color:%s\">%s</html>", status, textColor, name));
status,
textColor,
name));
break; break;
case OFFLINE: case OFFLINE:
setText(String.format( setText(String
"<html><p style=\"color:#fc0303\"><b><small>%s</b></small><br><p style=\"color:%s\">%s</html>", .format("<html><p style=\"color:#fc0303\"><b><small>%s</b></small><br><p style=\"color:%s\">%s</html>", status, textColor, name));
status,
textColor,
name));
break; break;
} }
return this; return this;