package kornell.gui.client.presentation.message; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import com.github.gwtbootstrap.client.ui.constants.AlertType; import com.github.gwtbootstrap.client.ui.constants.IconType; import com.google.gwt.core.shared.GWT; import com.google.gwt.place.shared.PlaceChangeEvent; import com.google.gwt.place.shared.PlaceController; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Widget; import com.google.web.bindery.event.shared.EventBus; import kornell.api.client.Callback; import kornell.api.client.KornellSession; import kornell.core.entity.ChatThreadType; import kornell.core.to.ChatThreadMessageTO; import kornell.core.to.ChatThreadMessagesTO; import kornell.core.to.TOFactory; import kornell.core.to.UnreadChatThreadTO; import kornell.core.util.StringUtils; import kornell.gui.client.KornellConstants; import kornell.gui.client.ViewFactory; import kornell.gui.client.event.UnreadMessagesPerThreadFetchedEvent; import kornell.gui.client.event.UnreadMessagesPerThreadFetchedEventHandler; import kornell.gui.client.presentation.admin.AdminPlace; import kornell.gui.client.presentation.admin.courseclass.courseclass.AdminCourseClassPlace; import kornell.gui.client.presentation.classroom.ClassroomPlace; import kornell.gui.client.util.view.KornellNotification; import kornell.gui.client.util.view.LoadingPopup; public class MessagePresenter implements MessageView.Presenter, UnreadMessagesPerThreadFetchedEventHandler{ private MessageView view; private KornellSession session; private PlaceController placeCtrl; private ViewFactory viewFactory; private MessagePanelType messagePanelType; private static TOFactory toFactory = GWT.create(TOFactory.class); private KornellConstants constants = GWT.create(KornellConstants.class); private UnreadChatThreadTO selectedChatThreadInfo; private Timer chatThreadMessagesTimer; private List<UnreadChatThreadTO> unreadChatThreadsTOFetchedFromEvent; List<ChatThreadMessageTO> chatThreadMessageTOs; private boolean updateMessages = true; private boolean threadBeginningReached; public MessagePresenter(KornellSession session, EventBus bus, PlaceController placeCtrl, final ViewFactory viewFactory, final MessagePanelType messagePanelType) { this.session = session; this.placeCtrl = placeCtrl; this.viewFactory = viewFactory; this.messagePanelType = messagePanelType; bus.addHandler(UnreadMessagesPerThreadFetchedEvent.TYPE, this); bus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() { @Override public void onPlaceChange(PlaceChangeEvent event) { if(event.getNewPlace() instanceof MessagePlace){ initPlaceBar(); if(MessagePanelType.inbox.equals(messagePanelType)){ asWidget().removeStyleName("shy"); } } else { if(MessagePanelType.inbox.equals(messagePanelType)){ asWidget().addStyleName("shy"); } } selectedChatThreadInfo = null; if(MessagePanelType.courseClassSupport.equals(messagePanelType)) updateMessages = false; else if(!(event.getNewPlace() instanceof MessagePlace) && !(event.getNewPlace() instanceof ClassroomPlace)) updateMessages = false; else updateMessages = true; } }); init(); } private void initPlaceBar() { viewFactory.getMenuBarView().initPlaceBar(IconType.COMMENTS, constants.messagesTitle(), constants.messagesDescription()); } private void init() { view = viewFactory.getMessageView(); view.setPresenter(this); view.setMessagePanelType(messagePanelType); chatThreadMessageTOs = new ArrayList<>(); if(placeCtrl.getWhere() instanceof MessagePlace){ initPlaceBar(); } } private void initializeChatThreadMessagesTimer() { if(chatThreadMessagesTimer != null) chatThreadMessagesTimer.cancel(); chatThreadMessagesTimer = new Timer() { public void run() { getChatThreadMessagesSinceLast(); } }; // Schedule the timer to run every 13 secs chatThreadMessagesTimer.scheduleRepeating(13 * 1000); } @Override public void onUnreadMessagesPerThreadFetched(UnreadMessagesPerThreadFetchedEvent event) { unreadChatThreadsTOFetchedFromEvent = event.getUnreadChatThreadTOs(); if(placeCtrl.getWhere() instanceof MessagePlace || placeCtrl.getWhere() instanceof AdminPlace || placeCtrl.getWhere() instanceof ClassroomPlace){ filterAndShowThreads(); } } @Override public void filterAndShowThreads() { if(updateMessages && unreadChatThreadsTOFetchedFromEvent != null){ List<UnreadChatThreadTO> newUnreadChatThreadTOs = new ArrayList<UnreadChatThreadTO>(); for (Iterator<UnreadChatThreadTO> iterator = unreadChatThreadsTOFetchedFromEvent.iterator(); iterator.hasNext();) { UnreadChatThreadTO unreadChatThreadTO = (UnreadChatThreadTO) iterator.next(); if(MessagePanelType.inbox.equals(messagePanelType) || showOnCourseClassSupport(unreadChatThreadTO) || showOnCourseClassGlobal(unreadChatThreadTO) || showOnCourseClassTutor(unreadChatThreadTO)){ newUnreadChatThreadTOs.add(unreadChatThreadTO); } } // create placeholder thread for tutor, since it's only created after the first message if(MessagePanelType.courseClassTutor.equals(messagePanelType) && newUnreadChatThreadTOs.size() == 0){ UnreadChatThreadTO newUnreadChatThreadTO = toFactory.newUnreadChatThreadTO().as(); newUnreadChatThreadTO.setThreadType(ChatThreadType.TUTORING); newUnreadChatThreadTO.setChatThreadCreatorName(session.getCurrentUser().getPerson().getFullName()); if(session.getCurrentCourseClass() != null){ newUnreadChatThreadTO.setEntityUUID(session.getCurrentCourseClass().getCourseClass().getUUID()); newUnreadChatThreadTO.setEntityName(session.getCurrentCourseClass().getCourseClass().getName()); } newUnreadChatThreadTO.setUnreadMessages("0"); newUnreadChatThreadTO.setChatThreadCreatorName(session.getCurrentUser().getPerson().getFullName()); newUnreadChatThreadTOs.add(newUnreadChatThreadTO); selectedChatThreadInfo = newUnreadChatThreadTO; } if(newUnreadChatThreadTOs.size() > 0){ // if no thread is selected, "click" the first one if(selectedChatThreadInfo == null){ selectedChatThreadInfo = newUnreadChatThreadTOs.get(0); if(!(placeCtrl.getWhere() instanceof ClassroomPlace) && (MessagePanelType.inbox.equals(messagePanelType) || MessagePanelType.courseClassSupport.equals(messagePanelType))){ threadClicked(selectedChatThreadInfo); } } view.updateSidePanel(newUnreadChatThreadTOs, selectedChatThreadInfo.getChatThreadUUID(), session.getCurrentUser().getPerson().getFullName()); } else if(placeCtrl.getWhere() instanceof MessagePlace && MessagePanelType.inbox.equals(messagePanelType)){ KornellNotification.show(constants.noThreadsMessage(), AlertType.WARNING, 5000); } asWidget().setVisible(newUnreadChatThreadTOs.size() > 0); } } @Override public void threadClicked(final UnreadChatThreadTO unreadChatThreadTO) { if(unreadChatThreadTO != null){ this.selectedChatThreadInfo = unreadChatThreadTO; } threadBeginningReached = false; chatThreadMessageTOs = new ArrayList<>(); initializeChatThreadMessagesTimer(); if(selectedChatThreadInfo != null){ view.displayThreadPanel(false); view.updateThreadPanel(selectedChatThreadInfo, session.getCurrentUser().getPerson().getFullName()); onScrollToTop(true); } } public void getChatThreadMessagesSinceLast() { if(((placeCtrl.getWhere() instanceof MessagePlace && MessagePanelType.inbox.equals(messagePanelType)) || (placeCtrl.getWhere() instanceof AdminCourseClassPlace && MessagePanelType.courseClassSupport.equals(messagePanelType)) || (placeCtrl.getWhere() instanceof ClassroomPlace && session.getCurrentCourseClass() != null && ( (MessagePanelType.courseClassGlobal.equals(messagePanelType) && session.getCurrentCourseClass().getCourseClass().isCourseClassChatEnabled()) || (MessagePanelType.courseClassTutor.equals(messagePanelType) && session.getCurrentCourseClass().getCourseClass().isTutorChatEnabled()) ) ) && updateMessages)){ if(selectedChatThreadInfo != null && selectedChatThreadInfo.getChatThreadUUID() != null){ final String chatThreadUUID = selectedChatThreadInfo.getChatThreadUUID(); LoadingPopup.show(); session.chatThreads().getChatThreadMessages(chatThreadUUID, lastFetchedMessageSentAt(), null, new Callback<ChatThreadMessagesTO>() { @Override public void ok(ChatThreadMessagesTO to) { if(selectedChatThreadInfo.getChatThreadUUID().equals(chatThreadUUID)){ chatThreadMessageTOs.addAll(0, to.getChatThreadMessageTOs()); view.addMessagesToThreadPanel(to, session.getCurrentUser().getPerson().getFullName(), false); } LoadingPopup.hide(); } }); } } } @Override public void onScrollToTop(final boolean scrollToBottomAfterFetchingMessages) { if(!threadBeginningReached && selectedChatThreadInfo != null && selectedChatThreadInfo.getChatThreadUUID() != null){ final String chatThreadUUID = selectedChatThreadInfo.getChatThreadUUID(); //before LoadingPopup.show(); session.chatThreads().getChatThreadMessages(chatThreadUUID, null, firstFetchedMessageSentAt(), new Callback<ChatThreadMessagesTO>() { @Override public void ok(ChatThreadMessagesTO to) { if(to.getChatThreadMessageTOs().size() == 0){ threadBeginningReached = true; view.addMessagesToThreadPanel(to, session.getCurrentUser().getPerson().getFullName(), true); view.setPlaceholder(messagePanelType.equals(MessagePanelType.courseClassTutor) ? constants.tutorPlaceholderMessage() : ""); } else if(selectedChatThreadInfo != null && selectedChatThreadInfo.getChatThreadUUID().equals(chatThreadUUID)){ chatThreadMessageTOs.addAll(to.getChatThreadMessageTOs()); view.addMessagesToThreadPanel(to, session.getCurrentUser().getPerson().getFullName(), true); } if(scrollToBottomAfterFetchingMessages){ Timer scrollToBottomTimer = new Timer() { @Override public void run() { view.scrollToBottom(); view.displayThreadPanel(true); LoadingPopup.hide(); } }; scrollToBottomTimer.schedule(2000); } else { view.displayThreadPanel(true); LoadingPopup.hide(); } } }); } else { view.displayThreadPanel(true); } } @Override public void sendMessage(final String message) { if(StringUtils.isSome(selectedChatThreadInfo.getChatThreadUUID())){ LoadingPopup.show(); session.chatThreads().postMessageToChatThread(message, selectedChatThreadInfo.getChatThreadUUID(), lastFetchedMessageSentAt(), new Callback<ChatThreadMessagesTO>() { @Override public void ok(ChatThreadMessagesTO to) { chatThreadMessageTOs.addAll(to.getChatThreadMessageTOs()); view.addMessagesToThreadPanel(to, session.getCurrentUser().getPerson().getFullName(), false); view.scrollToBottom(); view.sendSidePanelItemToTop(selectedChatThreadInfo.getChatThreadUUID()); LoadingPopup.hide(); } }); } else if(MessagePanelType.courseClassTutor.equals(messagePanelType) && session.getCurrentCourseClass() != null){ LoadingPopup.show(); session.chatThreads().postMessageToTutoringCourseClassThread(message, session.getCurrentCourseClass().getCourseClass().getUUID(), new Callback<String>() { @Override public void ok(String uuid) { selectedChatThreadInfo.setChatThreadUUID(uuid); threadClicked(selectedChatThreadInfo); LoadingPopup.hide(); } }); } } private boolean isCourseClassThread(String courseClassUUID) { return session.getCurrentCourseClass() != null && session.getCurrentCourseClass().getCourseClass().getUUID().equals(courseClassUUID); } private boolean showOnCourseClassSupport(UnreadChatThreadTO unreadChatThreadTO) { return isCourseClassThread(unreadChatThreadTO.getEntityUUID()) && MessagePanelType.courseClassSupport.equals(messagePanelType) && ChatThreadType.SUPPORT.equals(unreadChatThreadTO.getThreadType()); } private boolean showOnCourseClassTutor(UnreadChatThreadTO unreadChatThreadTO) { return isCourseClassThread(unreadChatThreadTO.getEntityUUID()) && (MessagePanelType.courseClassTutor.equals(messagePanelType) || MessagePanelType.courseClassSupport.equals(messagePanelType)) && ChatThreadType.TUTORING.equals(unreadChatThreadTO.getThreadType()) && unreadChatThreadTO.getChatThreadCreatorName().equals(session.getCurrentUser().getPerson().getFullName()); } private boolean showOnCourseClassGlobal(UnreadChatThreadTO unreadChatThreadTO) { return isCourseClassThread(unreadChatThreadTO.getEntityUUID()) && MessagePanelType.courseClassGlobal.equals(messagePanelType) && ChatThreadType.COURSE_CLASS.equals(unreadChatThreadTO.getThreadType()); } @Override public void enableMessagesUpdate(boolean enable){ this.updateMessages = enable; filterAndShowThreads(); } @Override public Widget asWidget() { return view.asWidget(); } @Override public void clearThreadSelection(){ this.selectedChatThreadInfo = null; } @Override public UnreadChatThreadTO getThreadSelection(){ return this.selectedChatThreadInfo = null; } private Date lastFetchedMessageSentAt() { Date date; date = chatThreadMessageTOs.size() > 0 ? chatThreadMessageTOs.get(0).getSentAt() : null; return date; } private Date firstFetchedMessageSentAt() { Date date; date = chatThreadMessageTOs.size() > 0 ? chatThreadMessageTOs.get(chatThreadMessageTOs.size() - 1).getSentAt() : null; return date; } @Override public void scrollToBottom(){ view.scrollToBottom(); } @Override public MessagePanelType getMessagePanelType() { return messagePanelType; } }