package com.andreiolar.abms.client.widgets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import com.andreiolar.abms.client.exception.MessagesNotFoundException;
import com.andreiolar.abms.client.exception.NoConversationsFoundException;
import com.andreiolar.abms.client.exception.OtherTenantsNotFoundException;
import com.andreiolar.abms.client.exception.UnableToSendMessageException;
import com.andreiolar.abms.client.exception.UserDetailsNotFoundException;
import com.andreiolar.abms.client.rpc.DBConversationDetails;
import com.andreiolar.abms.client.rpc.DBConversationDetailsAsync;
import com.andreiolar.abms.client.rpc.DBGetConversationMessages;
import com.andreiolar.abms.client.rpc.DBGetConversationMessagesAsync;
import com.andreiolar.abms.client.rpc.DBGetOtherTenants;
import com.andreiolar.abms.client.rpc.DBGetOtherTenantsAsync;
import com.andreiolar.abms.client.rpc.DBGetUserDetails;
import com.andreiolar.abms.client.rpc.DBGetUserDetailsAsync;
import com.andreiolar.abms.client.rpc.DBReplyToConversation;
import com.andreiolar.abms.client.rpc.DBReplyToConversationAsync;
import com.andreiolar.abms.client.rpc.DBStartConversation;
import com.andreiolar.abms.client.rpc.DBStartConversationAsync;
import com.andreiolar.abms.client.utils.DateUtil;
import com.andreiolar.abms.shared.ConversationDetails;
import com.andreiolar.abms.shared.ConversationMessage;
import com.andreiolar.abms.shared.ReplyMessage;
import com.andreiolar.abms.shared.UserDetails;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import gwt.material.design.addins.client.combobox.MaterialComboBox;
import gwt.material.design.client.constants.ButtonType;
import gwt.material.design.client.constants.Color;
import gwt.material.design.client.constants.Display;
import gwt.material.design.client.constants.IconPosition;
import gwt.material.design.client.constants.IconSize;
import gwt.material.design.client.constants.IconType;
import gwt.material.design.client.constants.ModalType;
import gwt.material.design.client.constants.Position;
import gwt.material.design.client.constants.TextAlign;
import gwt.material.design.client.ui.MaterialButton;
import gwt.material.design.client.ui.MaterialLabel;
import gwt.material.design.client.ui.MaterialLink;
import gwt.material.design.client.ui.MaterialModal;
import gwt.material.design.client.ui.MaterialModalContent;
import gwt.material.design.client.ui.MaterialModalFooter;
import gwt.material.design.client.ui.MaterialPanel;
import gwt.material.design.client.ui.MaterialTextArea;
import gwt.material.design.client.ui.MaterialTextBox;
import gwt.material.design.client.ui.MaterialTitle;
import gwt.material.design.client.ui.MaterialToast;
import gwt.material.design.client.ui.MaterialTooltip;
import gwt.material.design.client.ui.html.Div;
import gwt.material.design.client.ui.html.Hr;
public class MessengerWidget extends Composite implements CustomWidget {
private UserDetails userDetails;
private List<ConversationDetail> conversationDetailWidgets = new ArrayList<ConversationDetail>();
private List<ConversationDetails> conversationDetailsResults = new ArrayList<ConversationDetails>();
private ConversationDetails selectedConversation;
public MessengerWidget(UserDetails userDetails) {
this.userDetails = userDetails;
initWidget(initializeWidget());
}
@Override
public Widget initializeWidget() {
MaterialPanel panel = new MaterialPanel();
MaterialLabel title = new MaterialLabel("Messenger");
title.setTextColor(Color.BLUE);
title.setTextAlign(TextAlign.CENTER);
title.setFontSize("36px");
title.setFontWeight(FontWeight.BOLD);
panel.add(title);
panel.add(new Hr());
MaterialPanel mainPanel = new MaterialPanel();
mainPanel.setDisplay(Display.FLEX);
MaterialPanel leftConversationPanel = new MaterialPanel();
MaterialPanel newConversationPanel = new MaterialPanel();
MaterialPanel conversationDetailPanel = new MaterialPanel();
MaterialPanel conversationPanel = new MaterialPanel();
MaterialPanel conversationDisplayPanel = new MaterialPanel();
MaterialPanel conversationMessagePanel = new MaterialPanel();
MaterialPanel conversationWithPanel = new MaterialPanel();
newConversationPanel.setHeight("10%");
newConversationPanel.setPaddingTop(25.0);
newConversationPanel.setTextAlign(TextAlign.CENTER);
MaterialLink newConversationLink = new MaterialLink();
newConversationLink.setText("START A NEW CONVERSATION");
newConversationLink.setTextColor(Color.WHITE);
newConversationLink.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
DBGetOtherTenantsAsync otherTenantsRpc = (DBGetOtherTenantsAsync) GWT.create(DBGetOtherTenants.class);
ServiceDefTarget otherTenantsTar = (ServiceDefTarget) otherTenantsRpc;
String otherTenantsUrl = GWT.getModuleBaseURL() + "DBGetOtherTenantsImpl";
otherTenantsTar.setServiceEntryPoint(otherTenantsUrl);
otherTenantsRpc.getOtherTenants(userDetails.getUsername(), new AsyncCallback<List<UserDetails>>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof OtherTenantsNotFoundException) {
MaterialToast.fireToast("No other tenants found. Please try again later.");
} else {
MaterialModal errorModal = ModalCreator.createModal(caught);
RootPanel.get().add(errorModal);
errorModal.open();
}
}
@Override
public void onSuccess(List<UserDetails> result) {
MaterialModal materialModal = new MaterialModal();
materialModal.setType(ModalType.DEFAULT);
materialModal.setDismissible(false);
materialModal.setInDuration(500);
materialModal.setOutDuration(500);
MaterialModalContent materialModalContent = new MaterialModalContent();
Div titleDiv = new Div();
titleDiv.setTextAlign(TextAlign.CENTER);
MaterialTitle materialTitle = new MaterialTitle("Start a conversation");
materialTitle.setTextColor(Color.BLUE);
titleDiv.add(materialTitle);
titleDiv.add(new Hr());
materialModalContent.add(titleDiv);
MaterialComboBox<UserDetails> allUsersBox = new MaterialComboBox<UserDetails>();
allUsersBox.addItem("Select tenant to chat with", new UserDetails());
for (UserDetails ud : result) {
allUsersBox.addItem(ud.getFirstName() + " " + ud.getLastName() + " from Apt." + ud.getApartmentNumber(), ud);
}
allUsersBox.setSelectedIndex(0);
allUsersBox.setMarginTop(50.0);
allUsersBox.addStyleName("center-panel-60");
allUsersBox.setTextAlign(TextAlign.CENTER);
materialModalContent.add(allUsersBox);
MaterialTextArea messageBox = new MaterialTextArea();
messageBox.setMarginTop(50.0);
messageBox.setPlaceholder("Type a message");
messageBox.addStyleName("center-panel-95");
materialModalContent.add(messageBox);
MaterialModalFooter materialModalFooter = new MaterialModalFooter();
MaterialButton sendButton = new MaterialButton();
sendButton.setText("Send");
sendButton.setTextColor(Color.BLUE);
sendButton.setType(ButtonType.FLAT);
sendButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
String message = messageBox.getText();
String username = allUsersBox.getSelectedValue().getUsername();
boolean canProceed = true;
if (username == null) {
canProceed = false;
allUsersBox.setError("Please select a tenant to chat with.");
} else {
allUsersBox.setSuccess("");
}
if (message == null || message.isEmpty()) {
canProceed = false;
messageBox.setError("Message cannot be empty.");
} else {
messageBox.setSuccess("");
}
if (canProceed) {
// materialModal.close();
// RootPanel.get().remove(materialModal);
//
// panel.clear();
// panel.add(new MessengerWidget(userDetails));
DBStartConversationAsync sendMessageRpc = (DBStartConversationAsync) GWT.create(DBStartConversation.class);
ServiceDefTarget sendMessageTar = (ServiceDefTarget) sendMessageRpc;
String sendMessageUrl = GWT.getModuleBaseURL() + "DBStartConversationImpl";
sendMessageTar.setServiceEntryPoint(sendMessageUrl);
sendMessageRpc.startConversation(userDetails.getUsername(), username, message, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof UnableToSendMessageException) {
MaterialToast.fireToast("Unable to send message. Please try again.", "rounded");
} else {
materialModal.close();
RootPanel.get().remove(materialModal);
MaterialModal errorModal = ModalCreator.createModal(caught);
RootPanel.get().add(errorModal);
errorModal.open();
}
}
@Override
public void onSuccess(Void result) {
materialModal.close();
RootPanel.get().remove(materialModal);
panel.clear();
panel.add(new MessengerWidget(userDetails));
}
});
}
}
});
MaterialButton closeButton = new MaterialButton();
closeButton.setText("Close");
closeButton.setTextColor(Color.BLUE);
closeButton.setType(ButtonType.FLAT);
closeButton.addClickHandler(h -> {
materialModal.close();
RootPanel.get().remove(materialModal);
});
materialModalFooter.add(sendButton);
materialModalFooter.add(closeButton);
materialModal.add(materialModalContent);
materialModal.add(materialModalFooter);
materialModal.setWidth("600px");
materialModal.setHeight("500px");
RootPanel.get().add(materialModal);
materialModal.open();
}
});
}
});
newConversationLink.addMouseOverHandler(new MouseOverHandler() {
@Override
public void onMouseOver(MouseOverEvent event) {
newConversationLink.setTextColor(Color.GREY);
}
});
newConversationLink.addMouseOutHandler(new MouseOutHandler() {
@Override
public void onMouseOut(MouseOutEvent event) {
newConversationLink.setTextColor(Color.WHITE);
}
});
newConversationPanel.add(newConversationLink);
leftConversationPanel.setWidth("22%");
leftConversationPanel.setHeight("700px");
leftConversationPanel.setBackgroundColor(Color.BLUE);
conversationPanel.setWidth("58%");
conversationPanel.setHeight("700px");
conversationPanel.setBackgroundColor(Color.GREY_LIGHTEN_5);
conversationDisplayPanel.setBackgroundColor(Color.GREY_LIGHTEN_4);
MaterialLabel noConversationSelectedLabel = new MaterialLabel();
noConversationSelectedLabel.setText("No conversation selected.");
noConversationSelectedLabel.setFontSize("18px");
noConversationSelectedLabel.setPaddingTop(25.0);
conversationDisplayPanel.setHeight("90%");
conversationDisplayPanel.setOverflow(Overflow.SCROLL);
conversationDisplayPanel.setTextAlign(TextAlign.CENTER);
conversationDisplayPanel.add(noConversationSelectedLabel);
conversationMessagePanel.setHeight("8%");
conversationMessagePanel.setDisplay(Display.FLEX);
MaterialTextBox textArea = new MaterialTextBox();
textArea.setPlaceholder("Type a message...");
textArea.setPaddingTop(10.0);
textArea.setPaddingRight(20.0);
textArea.setPaddingLeft(20.0);
textArea.setEnabled(false);
textArea.setWidth("90%");
MaterialLink sendMessageLink = new MaterialLink();
sendMessageLink.setIconType(IconType.SEND);
sendMessageLink.setBackgroundColor(Color.GREY_LIGHTEN_5);
sendMessageLink.setIconSize(IconSize.MEDIUM);
sendMessageLink.setWidth("10%");
sendMessageLink.setPaddingTop(5.0);
sendMessageLink.setPaddingLeft(25.0);
sendMessageLink.setIconPosition(IconPosition.NONE);
sendMessageLink.setEnabled(false);
sendMessageLink.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
doSendMessage(textArea, conversationDisplayPanel, conversationDetailPanel, conversationWithPanel, sendMessageLink);
}
});
MaterialTooltip sendMessageToolTip = new MaterialTooltip(sendMessageLink, "Send Message");
sendMessageToolTip.setPosition(Position.BOTTOM);
conversationMessagePanel.setBackgroundColor(Color.GREY_LIGHTEN_5);
conversationMessagePanel.add(textArea);
conversationMessagePanel.add(sendMessageLink);
conversationWithPanel.setWidth("20%");
conversationWithPanel.setHeight("700px");
MaterialLabel noConversationSelectedLabel2 = new MaterialLabel();
noConversationSelectedLabel2.setText("No conversation selected.");
noConversationSelectedLabel2.setFontSize("18px");
noConversationSelectedLabel2.setMarginTop(25.0);
conversationWithPanel.setTextAlign(TextAlign.CENTER);
conversationWithPanel.add(noConversationSelectedLabel2);
DBConversationDetailsAsync rpc = (DBConversationDetailsAsync) GWT.create(DBConversationDetails.class);
ServiceDefTarget tar = (ServiceDefTarget) rpc;
String moduleURL = GWT.getModuleBaseURL() + "DBConversationDetailsImpl";
tar.setServiceEntryPoint(moduleURL);
rpc.getConversationDetails(userDetails, new AsyncCallback<List<ConversationDetails>>() {
@Override
public void onSuccess(List<ConversationDetails> result) {
conversationDetailPanel.setTextAlign(TextAlign.LEFT);
conversationDetailsResults.addAll(result);
Collections.sort(result, new Comparator<ConversationDetails>() {
@Override
public int compare(ConversationDetails o1, ConversationDetails o2) {
Date conversationDate1 = DateUtil.getConversationDate(o1.getLastMessageDate());
Date conversationDate2 = DateUtil.getConversationDate(o2.getLastMessageDate());
return -Long.compare(conversationDate1.getTime(), conversationDate2.getTime());
}
});
for (ConversationDetails conversationDetails : result) {
ConversationDetail conversationDetailWidget = getConversationDetailWidget(conversationDetails, conversationDisplayPanel, textArea,
conversationWithPanel, sendMessageLink);
conversationDetailPanel.add(conversationDetailWidget);
}
textArea.addKeyDownHandler(new KeyDownHandler() {
@Override
public void onKeyDown(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
doSendMessage(textArea, conversationDisplayPanel, conversationDetailPanel, conversationWithPanel, sendMessageLink);
}
}
});
}
@Override
public void onFailure(Throwable caught) {
if (caught instanceof NoConversationsFoundException) {
MaterialLabel errorLabel = new MaterialLabel();
errorLabel.setText(caught.getMessage());
errorLabel.setFontSize("18px");
errorLabel.setMarginTop(25.0);
conversationDetailPanel.setTextAlign(TextAlign.CENTER);
conversationDetailPanel.add(errorLabel);
} else {
MaterialModal errorModal = ModalCreator.createModal(caught);
RootPanel.get().add(errorModal);
errorModal.open();
}
}
});
conversationPanel.add(conversationDisplayPanel);
conversationPanel.add(conversationMessagePanel);
leftConversationPanel.add(newConversationPanel);
leftConversationPanel.add(conversationDetailPanel);
mainPanel.add(leftConversationPanel);
mainPanel.add(conversationPanel);
mainPanel.add(conversationWithPanel);
panel.add(mainPanel);
return panel;
}
private ConversationDetail getConversationDetailWidget(ConversationDetails conversationDetails, MaterialPanel conversationDisplayPanel,
MaterialTextBox textArea, MaterialPanel conversationWithPanel, MaterialLink sendMessageLink) {
ConversationDetail conversationDetail = new ConversationDetail(conversationDetails, false);
conversationDetailWidgets.add(conversationDetail);
conversationDetail.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
conversationDetailWidgets.stream().forEach(cdw -> cdw.setSelected(false));
conversationDetail.setSelected(true);
selectedConversation = conversationDetails;
conversationDisplayPanel.clear();
conversationDisplayPanel.setTextAlign(TextAlign.DEFAULT);
sendMessageLink.setEnabled(true);
textArea.setEnabled(true);
DBGetConversationMessagesAsync conversationMessageRpc = (DBGetConversationMessagesAsync) GWT.create(DBGetConversationMessages.class);
ServiceDefTarget conversationMessageTar = (ServiceDefTarget) conversationMessageRpc;
String moduleURL = GWT.getModuleBaseURL() + "DBGetConversationMessagesImpl";
conversationMessageTar.setServiceEntryPoint(moduleURL);
conversationMessageRpc.getConversationMessages(String.valueOf(conversationDetails.getId()),
new AsyncCallback<List<ConversationMessage>>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof MessagesNotFoundException) {
MaterialLabel errorLabel = new MaterialLabel();
errorLabel.setText("No messages to display. Send a message instead.");
errorLabel.setFontSize("18px");
errorLabel.setPaddingTop(25.0);
conversationDisplayPanel.setTextAlign(TextAlign.CENTER);
conversationDisplayPanel.add(errorLabel);
} else {
MaterialModal errorModal = ModalCreator.createModal(caught);
RootPanel.get().add(errorModal);
errorModal.open();
}
}
@Override
public void onSuccess(List<ConversationMessage> result) {
for (ConversationMessage message : result) {
Message messageWidget = new Message(message, userDetails.getUsername());
conversationDisplayPanel.add(messageWidget);
}
}
});
conversationWithPanel.clear();
conversationWithPanel.setTextAlign(TextAlign.DEFAULT);
DBGetUserDetailsAsync userDetailsRpc = (DBGetUserDetailsAsync) GWT.create(DBGetUserDetails.class);
ServiceDefTarget userDetailsTar = (ServiceDefTarget) userDetailsRpc;
String userDeatilsURL = GWT.getModuleBaseURL() + "DBGetUserDetailsImpl";
userDetailsTar.setServiceEntryPoint(userDeatilsURL);
userDetailsRpc.geUserDetails(conversationDetails.getConversationWith(), new AsyncCallback<UserDetails>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof UserDetailsNotFoundException) {
MaterialLabel errorLabel = new MaterialLabel();
errorLabel.setText(caught.getMessage());
errorLabel.setFontSize("18px");
errorLabel.setMarginTop(25.0);
conversationWithPanel.setTextAlign(TextAlign.CENTER);
conversationWithPanel.add(errorLabel);
} else {
MaterialModal errorModal = ModalCreator.createModal(caught);
RootPanel.get().add(errorModal);
errorModal.open();
}
}
@Override
public void onSuccess(UserDetails result) {
ConversationWithWidget conversationWithWidget = new ConversationWithWidget(result);
conversationWithPanel.add(conversationWithWidget);
}
});
}
});
return conversationDetail;
}
private void doSendMessage(MaterialTextBox textArea, MaterialPanel conversationDisplayPanel, MaterialPanel conversationDetailPanel,
MaterialPanel conversationWithPanel, MaterialLink sendMessageLink) {
String messageText = textArea.getText();
if (messageText == null || !messageText.isEmpty()) {
textArea.setSuccess("");
ReplyMessage replyMessage = new ReplyMessage(messageText, userDetails.getUsername(), selectedConversation.getId());
DBReplyToConversationAsync replyToConvRpc = (DBReplyToConversationAsync) GWT.create(DBReplyToConversation.class);
ServiceDefTarget replyToConvTar = (ServiceDefTarget) replyToConvRpc;
String replyToConvUrl = GWT.getModuleBaseURL() + "DBReplyToConversationImpl";
replyToConvTar.setServiceEntryPoint(replyToConvUrl);
replyToConvRpc.replyToConversation(replyMessage, new AsyncCallback<ConversationMessage>() {
@Override
public void onSuccess(ConversationMessage convMessage) {
textArea.clear();
convMessage.setGender(userDetails.getGender());
Message message = new Message(convMessage, userDetails.getUsername());
conversationDisplayPanel.add(message);
conversationDetailPanel.clear();
conversationDetailPanel.setTextAlign(TextAlign.LEFT);
for (ConversationDetails cd : conversationDetailsResults) {
if (cd.getId() == replyMessage.getConvId()) {
cd.setLastMessage(convMessage.getMessage());
cd.setLastMessageDate(convMessage.getDate());
}
}
Collections.sort(conversationDetailsResults, new Comparator<ConversationDetails>() {
@Override
public int compare(ConversationDetails o1, ConversationDetails o2) {
Date conversationDate1 = DateUtil.getConversationDate(o1.getLastMessageDate());
Date conversationDate2 = DateUtil.getConversationDate(o2.getLastMessageDate());
return -Long.compare(conversationDate1.getTime(), conversationDate2.getTime());
}
});
for (ConversationDetails conversationDetails : conversationDetailsResults) {
ConversationDetail conversationDetailWidget = getConversationDetailWidget(conversationDetails, conversationDisplayPanel,
textArea, conversationWithPanel, sendMessageLink);
conversationDetailPanel.add(conversationDetailWidget);
if (conversationDetails.getId() == replyMessage.getConvId()) {
conversationDetailWidget.setSelected(true);
}
}
}
@Override
public void onFailure(Throwable caught) {
textArea.clear();
MaterialModal errorModal = ModalCreator.createModal(caught);
RootPanel.get().add(errorModal);
errorModal.open();
}
});
} else {
textArea.setError("Message cannot be empty.");
}
}
}