#How to live update chat screen when a new chat is entered to the ChatHistory context (Static list)
57 messages · Page 1 of 1 (latest)
⌛ This post has been reserved for your question.
Hey @rain tapir! Please use
/closeor theClose Postbutton above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
There are two Actors Customer and Emplyee
Employee gets a UI to chat and also the customer
This is how the chats are managed across the application
public class ChatHistory {
private static Map<Actor, List<Chat>> chats = new HashMap<>();
public static Map<Actor, List<Chat>> getChats() {
return chats;
}
public static List<Chat> getChatsByActor(Actor actor) {
if (chats != null) {
return chats.get(actor);
}else{
return new LinkedList<>();
}
}
public static void addChat(Actor from,Actor to, String message) {
if (chats != null) {
if (chats.get(from) != null) {
List<Chat> messages = chats.get(from);
Chat chat = new Chat(from, to, message);
messages.add(chat);
chats.put(from, messages);
}
if (chats.get(from) == null) {
List<Chat> messages = new LinkedList<>();
Chat chat = new Chat(from, to, message);
messages.add(chat);
chats.put(from, messages);
}
}
}
}
To display the Chats for each Actor I use a method
which will load the chats
private void loadChat() {
chatScrollPane.removeAll();
rowCount = 0;
Map<Actor, List<Chat>> chats = ChatHistory.getChats();
for (Map.Entry<Actor, List<Chat>> entry : chats.entrySet()) {
Actor key = entry.getKey();
List<Chat> value = entry.getValue();
// if (ChatActorUtil.getName(key).equals(this.customer.getName())) {
if (key instanceof ChatCustomer) {
value.forEach(e -> {
if (e.getSender() instanceof ChatCustomer) {
ChatCustomer customer = (ChatCustomer) key;
if (customer.getName().equals(this.customer.getName())) {
chatScrollPane.add(new ToChatPanel(e.getMessage()));
rowCount++;
}
}
});
}
if (key instanceof ChatEmployee) {
ChatEmployee employee = (ChatEmployee) key;
value.forEach(e -> {
ChatCustomer customer = (ChatCustomer) e.getReceive();
if (customer.getName().equals(this.customer.getName())) {
chatScrollPane.add(new FromChatPanel("Employee", e.getMessage()));
rowCount++;
}
});
}
}
chatScrollPane.setLayout(new GridLayout(rowCount, 1));
chatScrollPane.revalidate();
chatScrollPane.repaint();
}
but the problem is this won't live update I have to manually refresh
or manually call the loadChats method
This is the mediator that manages the chats between actors
public class ConcreteMediator implements Mediator {
private List<Actor> actors;
public ConcreteMediator() {
this.actors = ActorStorage.getActorList();
}
public void addActor(Actor actor) {
ActorStorage.setActor(actor);
// this.actors.add(actor);
}
@Override
public void sendMessage(String message, Actor from, Actor to) {
if (from instanceof ChatEmployee) {
to.receiveMessage(message, from);
}
if (from instanceof ChatCustomer) {
to.receiveMessage(message, from);
}
ChatHistory.addChat(from, to, message);
}
}
when should what change?
Also, in most cases, you want to use ArrayList instead of LinkedList
When someone send a message, it should update the other user's UI
like how we chat in discord
no Just same instance
ah ok
One Swing application
Can you show the Chat class?
yeah
public class Chat {
private Actor sender;
private Actor receiver;
private String message;
public Chat(Actor sender, Actor receiver, String message) {
this.sender = sender;
this.receiver = receiver;
this.message = message;
}
public Actor getSender() {
return sender;
}
public void setSender(Actor sender) {
this.sender = sender;
}
public Actor getReceive() {
return receiver;
}
public void setReceive(Actor receive) {
this.receiver = receive;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
This is the customer's UI after confirming the order
They get a Chat UI to chat
This is the UI what the employee get to chat with the customer
Can you show the receiveMessage method?
Concreate Mediator calls the receiveMessage method
public class ConcreteMediator implements Mediator {
private List<Actor> actors;
public ConcreteMediator() {
this.actors = ActorStorage.getActorList();
}
public void addActor(Actor actor) {
ActorStorage.setActor(actor);
// this.actors.add(actor);
}
@Override
public void sendMessage(String message, Actor from, Actor to) {
if (from instanceof ChatEmployee) {
to.receiveMessage(message, from);
}
if (from instanceof ChatCustomer) {
to.receiveMessage(message, from);
}
ChatHistory.addChat(from, to, message);
}
}
like inside the actors?
yah
public class ChatEmployee implements Actor {
private Mediator mediator;
private String name;
public ChatEmployee(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
ConcreteMediator concreteMediator = (ConcreteMediator) this.mediator;
concreteMediator.addActor(this);
}
public String getName() {
return name;
}
@Override
public void sendMessage(String message, Actor to) {
mediator.sendMessage(message, this, to);
}
@Override
public void receiveMessage(String message, Actor from) {
ChatCustomer customer = (ChatCustomer)from;
System.out.println(this.name + " receives messages " + message+ " from "+customer.getName());
}
}
What about updating the UI there?
I didn't really nothing inside
public interface Actor {
void sendMessage(String message,Actor to);
void receiveMessage(String message, Actor from);
}
Why the
if (from instanceof ChatEmployee) {
to.receiveMessage(message, from);
}
if (from instanceof ChatCustomer) {
to.receiveMessage(message, from);
}
?
You can just do to.receiveMessage(message, from);
I thought about this so I thought it would be convenient in future to check the Actor instance
What about updating the UI there?
I think the best way is to have a reference to the UI in your ChatEmployee (and ChatCustomer)
yah yah
and update it from there
but wouldn't that couple the UI?
you can use an interface
For example, you could create a ChatUpdater interface
with a method addChatMessage
or actually use a listener
that's better
You create an interface like that
public interface ChatListener{
void onChatMessageReceived(Actor from, String message)
}
because of the performance issue ?
yeah
and in your actors, you have a List<ChatListener>
and in the receiveMessage, you call the onChatMessageReceived of all listeners
and the UI class can then do somethng like
customer.addChatListener((from, message) -> {
addMessageToUI(from, message);
});
ook alright
Would that work for you?
yah I will give a try and update you