Listening to message status changes, sending READ status updates
This commit is contained in:
		| @@ -1,11 +1,14 @@ | ||||
| package envoy.client; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| import envoy.client.net.Client; | ||||
| import envoy.client.ui.list.ComponentListModel; | ||||
| import envoy.data.Message; | ||||
| import envoy.data.Message.MessageStatus; | ||||
| import envoy.data.User; | ||||
| import envoy.event.MessageStatusChangeEvent; | ||||
|  | ||||
| /** | ||||
|  * Represents a chat between two {@link User}s <br> | ||||
| @@ -49,14 +52,25 @@ public class Chat implements Serializable { | ||||
| 	 * {@code READ} starting from the bottom and stopping once a read message is | ||||
| 	 * found. | ||||
| 	 * | ||||
| 	 * @param client the client instance used to notify the server about the message | ||||
| 	 *               status changes | ||||
| 	 * @throws IOException if a {@link MessageStatusChangeEvent} could not be | ||||
| 	 *                     delivered to the server | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public void read() { | ||||
| 		for (int i = model.size() - 1; i >= 0; --i) | ||||
| 			if (model.get(i).getSenderId() == recipient.getId()) { | ||||
| 				if (model.get(i).getStatus() == MessageStatus.READ) break; | ||||
| 				else model.get(i).setStatus(MessageStatus.READ); | ||||
| 	public void read(Client client) throws IOException { | ||||
| 		for (int i = model.size() - 1; i >= 0; --i) { | ||||
| 			final Message m = model.get(i); | ||||
| 			if (m.getSenderId() == recipient.getId()) { | ||||
| 				if (m.getStatus() == MessageStatus.READ) break; | ||||
| 				else { | ||||
| 					m.setStatus(MessageStatus.READ); | ||||
|  | ||||
| 					// TODO: Cache events in offline mode | ||||
| 					client.sendEvent(new MessageStatusChangeEvent(m)); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -13,7 +13,9 @@ import envoy.client.Config; | ||||
| import envoy.client.database.LocalDb; | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.data.*; | ||||
| import envoy.event.Event; | ||||
| import envoy.event.IdGeneratorRequest; | ||||
| import envoy.event.MessageStatusChangeEvent; | ||||
| import envoy.util.SerializationUtils; | ||||
|  | ||||
| /** | ||||
| @@ -42,7 +44,7 @@ public class Client implements Closeable { | ||||
|  | ||||
| 	// Configuration and logging | ||||
| 	private static final Config	config	= Config.getInstance(); | ||||
| 	private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); | ||||
| 	private static final Logger	logger	= EnvoyLog.getLogger(Client.class.getSimpleName()); | ||||
|  | ||||
| 	/** | ||||
| 	 * Enters the online mode by acquiring a user ID from the server. As a | ||||
| @@ -103,19 +105,21 @@ public class Client implements Closeable { | ||||
| 		// Relay cached unread messages | ||||
| 		cache.setProcessor(receivedMessageProcessor); | ||||
|  | ||||
| 		// TODO: Status handling | ||||
| 		// Process message status changes | ||||
| 		receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor()); | ||||
|  | ||||
| 		// Process message ID generation | ||||
| 		receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator); | ||||
|  | ||||
| 		// Request a generator if none is present | ||||
| 		// Request a generator if none is present or the existing one is consumed | ||||
| 		if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); | ||||
|  | ||||
| 		return cache; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sends a message to the server. | ||||
| 	 * Sends a message to the server. The message's status will be incremented once | ||||
| 	 * it was delivered successfully. | ||||
| 	 * | ||||
| 	 * @param message the message to send | ||||
| 	 * @throws IOException if the message does not reach the server | ||||
| @@ -126,6 +130,14 @@ public class Client implements Closeable { | ||||
| 		message.nextStatus(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sends an event to the server. | ||||
| 	 * | ||||
| 	 * @param evt the event to send | ||||
| 	 * @throws IOException if the event did not reach the server | ||||
| 	 */ | ||||
| 	public void sendEvent(Event<?> evt) throws IOException { writeObject(evt); } | ||||
|  | ||||
| 	/** | ||||
| 	 * Requests a new {@link IdGenerator} from the server. | ||||
| 	 * | ||||
|   | ||||
| @@ -0,0 +1,38 @@ | ||||
| package envoy.client.net; | ||||
|  | ||||
| import java.util.function.Consumer; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.data.Message.MessageStatus; | ||||
| import envoy.event.EventBus; | ||||
| import envoy.event.MessageStatusChangeEvent; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|  * File: <strong>MessageStatusChangeEventProcessor.java</strong><br> | ||||
|  * Created: <strong>4 Feb 2020</strong><br> | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since Envoy v0.3-alpha | ||||
|  */ | ||||
| public class MessageStatusChangeEventProcessor implements Consumer<MessageStatusChangeEvent> { | ||||
|  | ||||
| 	private static final Logger logger = EnvoyLog.getLogger(MessageStatusChangeEventProcessor.class.getSimpleName()); | ||||
|  | ||||
| 	/** | ||||
| 	 * Dispatches a {@link MessageStatusChangeEvent} if the status is | ||||
| 	 * {@code RECEIVED} or {@code READ}. | ||||
| 	 * | ||||
| 	 * @param evt the status change event | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public void accept(MessageStatusChangeEvent evt) { | ||||
| 		if (evt.get().ordinal() <= MessageStatus.RECEIVED.ordinal()) logger.info("Received invalid message status change " + evt); | ||||
| 		else { | ||||
| 			logger.info("Received " + evt.toString()); | ||||
| 			EventBus.getInstance().dispatch(evt); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -3,6 +3,7 @@ package envoy.client.ui; | ||||
| import java.awt.*; | ||||
| import java.awt.event.KeyAdapter; | ||||
| import java.awt.event.KeyEvent; | ||||
| import java.io.IOException; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| @@ -19,9 +20,11 @@ import envoy.client.ui.list.ComponentList; | ||||
| import envoy.client.ui.settings.SettingsScreen; | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.data.Message; | ||||
| import envoy.data.Message.MessageStatus; | ||||
| import envoy.data.MessageBuilder; | ||||
| import envoy.data.User; | ||||
| import envoy.event.EventBus; | ||||
| import envoy.event.MessageStatusChangeEvent; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
| @@ -173,7 +176,12 @@ public class ChatWindow extends JFrame { | ||||
| 				currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); | ||||
|  | ||||
| 				// Read current Chat | ||||
| 				currentChat.read(); | ||||
| 				try { | ||||
| 					currentChat.read(client); | ||||
| 				} catch (IOException e) { | ||||
| 					e.printStackTrace(); | ||||
| 					logger.log(Level.WARNING, "Could notify server about message status change", e); | ||||
| 				} | ||||
|  | ||||
| 				// Set chat title | ||||
| 				textPane.setText(currentChat.getRecipient().getName()); | ||||
| @@ -213,6 +221,26 @@ public class ChatWindow extends JFrame { | ||||
| 			repaint(); | ||||
| 		}); | ||||
|  | ||||
| 		// Listen to message status changes | ||||
| 		EventBus.getInstance().register(MessageStatusChangeEvent.class, (evt) -> { | ||||
| 			final long			id		= ((MessageStatusChangeEvent) evt).getId(); | ||||
| 			final MessageStatus	status	= (MessageStatus) evt.get(); | ||||
|  | ||||
| 			for (Chat c : localDb.getChats()) | ||||
| 				for (Message m : c.getModel()) | ||||
| 					if (m.getId() == id) { | ||||
|  | ||||
| 						// Update message status | ||||
| 						m.setStatus(status); | ||||
|  | ||||
| 						// Update model and scroll down if current chat | ||||
| 						if (c == currentChat) { | ||||
| 							messageList.setModel(currentChat.getModel()); | ||||
| 							scrollPane.setChatOpened(true); | ||||
| 						} | ||||
| 					} | ||||
| 		}); | ||||
|  | ||||
| 		revalidate(); | ||||
| 	} | ||||
|  | ||||
| @@ -286,10 +314,7 @@ public class ChatWindow extends JFrame { | ||||
| 			if (!localDb.getIdGenerator().hasNext()) client.requestIdGenerator(); | ||||
|  | ||||
| 		} catch (Exception e) { | ||||
| 			JOptionPane.showMessageDialog(this, | ||||
| 					"Error sending message:\n" + e.toString(), | ||||
| 					"Message sending error", | ||||
| 					JOptionPane.ERROR_MESSAGE); | ||||
| 			JOptionPane.showMessageDialog(this, "Error sending message:\n" + e.toString(), "Message sending error", JOptionPane.ERROR_MESSAGE); | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
| 	} | ||||
| @@ -320,9 +345,7 @@ public class ChatWindow extends JFrame { | ||||
| 	 * @param client the {@link Client} used to send and receive messages | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public void setClient(Client client) { | ||||
| 		this.client = client; | ||||
| 	} | ||||
| 	public void setClient(Client client) { this.client = client; } | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the {@link LocalDb} used by this {@link ChatWindow}. After | ||||
|   | ||||
		Reference in New Issue
	
	Block a user