Added chat to the new Flex 4 UI

This commit is contained in:
Chad Pilkey 2016-04-28 19:07:15 -04:00
parent 73ddb24c92
commit 2edfdf450c
10 changed files with 405 additions and 14 deletions

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:views="org.bigbluebutton.lib.common.views.*"
width="100%"
styleName="chatMessageStyle">
<fx:Script>
<![CDATA[
import flashx.textLayout.conversion.TextConverter;
import org.bigbluebutton.lib.chat.models.ChatMessage;
override public function set data(obj:Object):void {
super.data = obj;
var m:ChatMessage = obj as ChatMessage;
if (m) {
time.text = m.time
if (!isHTMLString(m.senderText)) {
message.text = m.senderText;
} else {
message.textFlow = TextConverter.importToFlow(m.senderText, TextConverter.TEXT_FIELD_HTML_FORMAT);
}
var sameUser:Boolean = (m.lastSenderId == m.senderId);
var sameTime:Boolean = (m.lastTime == m.time);
if (sameUser && sameTime) {
nameTimeGroup.includeInLayout = false;
nameTimeGroup.visible = false;
participantIcon.visible = false;
} else {
nameTimeGroup.includeInLayout = true;
nameTimeGroup.visible = true;
if (m.name == " ") {
participantIcon.visible = false;
username.visible = false;
username.includeInLayout = false;
} else {
username.text = m.name;
participantIcon.setFirstLetters(m.name);
participantIcon.visible = true;
username.visible = true;
username.includeInLayout = true;
}
}
}
}
/**
* Checks if message string contains opening and closing HTML tag e.g. <....>
**/
public function isHTMLString(str:String):Boolean {
var pattern:RegExp = new RegExp("(\<+.*\>+)");
var result:Object = pattern.exec(str);
if (result == null) {
return false;
}
return true;
}
]]>
</fx:Script>
<s:states>
<s:State name="others_state" />
<s:State name="me_state" />
</s:states>
<s:VGroup width="100%">
<s:HGroup width="100%">
<views:ParticipantIcon id="participantIcon"
height="100%" />
<s:VGroup width="100%">
<s:Spacer height="10%" />
<s:Group id="nameTimeGroup"
width="100%"
height="100%">
<s:layout>
<s:HorizontalLayout verticalAlign="bottom" />
</s:layout>
<s:Label id="username"
visible="true"
fontSize="{getStyle('nameFontSize')}" />
<s:Label id="time"
fontSize="{getStyle('timeFontSize')}" />
</s:Group>
<s:HGroup width="100%">
<s:RichEditableText editable="false"
selectable="false"
id="message"
width="100%"
fontSize="{getStyle('messageFontSize')}" />
</s:HGroup>
</s:VGroup>
</s:HGroup>
</s:VGroup>
</s:ItemRenderer>

View File

@ -0,0 +1,88 @@
package org.bigbluebutton.lib.chat.views {
import mx.core.ClassFactory;
import mx.core.ScrollPolicy;
import spark.components.Button;
import spark.components.Group;
import spark.components.HGroup;
import spark.components.List;
import spark.components.Scroller;
import spark.components.TextInput;
import spark.components.VGroup;
public class ChatViewBase extends VGroup {
private var _chatList:List;
public function get chatList():List {
return _chatList;
}
private var _inputGroup:HGroup;
private var _sendButton:Button;
public function get sendButton():Button {
return _sendButton;
}
private var _textInput:TextInput;
public function get textInput():TextInput {
return _textInput;
}
public function ChatViewBase() {
super();
var scroller:Scroller = new Scroller();
scroller.percentWidth = 100;
scroller.percentHeight = 100;
scroller.setStyle("horizontalScrollPolicy", "off");
var sGroup:VGroup = new VGroup();
sGroup.percentWidth = 100;
sGroup.percentHeight = 100;
sGroup.setStyle("horizontalScrollPolicy", "off");
scroller.viewport = sGroup;
_chatList = new List();
_chatList.percentWidth = 100;
_chatList.percentHeight = 100;
_chatList.setStyle("horizontalScrollPolicy", "off");
var itemRendererClass:ClassFactory = new ClassFactory(ChatItemRenderer);
_chatList.itemRenderer = itemRendererClass; //org.bigbluebutton.air.chat.views.chat.ChatItemRenderer
sGroup.addElement(_chatList);
addElement(scroller);
_inputGroup = new HGroup();
_inputGroup.percentWidth = 100;
_inputGroup.verticalAlign = "middle";
_inputGroup.horizontalAlign = "center";
_textInput = new TextInput();
_textInput.percentWidth = 100;
_textInput.percentHeight = 100;
//_textInput.showPromptWhenFocused = false;
_textInput.prompt = "Type message here";
_textInput.styleName = "contentFontSize msgInputBoxStyle";
_inputGroup.addElement(_textInput);
_sendButton = new Button();
_sendButton.percentHeight = 100;
_sendButton.label = "Send";
//enabled="{inputMessage0.text!=''}"
_sendButton.styleName = "sendButtonStyle";
_inputGroup.addElement(_sendButton);
addElement(_inputGroup);
}
override protected function updateDisplayList(w:Number, h:Number):void {
_inputGroup.height = getStyle('chatInputTextHeight');
_sendButton.width = getStyle('btnWidth');
super.updateDisplayList(w, h);
}
}
}

View File

@ -0,0 +1,147 @@
package org.bigbluebutton.lib.chat.views {
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
import mx.utils.StringUtil;
import org.bigbluebutton.lib.chat.models.ChatMessage;
import org.bigbluebutton.lib.chat.models.ChatMessageVO;
import org.bigbluebutton.lib.chat.models.ChatMessages;
import org.bigbluebutton.lib.chat.models.IChatMessagesSession;
import org.bigbluebutton.lib.chat.services.IChatMessageService;
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.user.models.User;
import robotlegs.bender.bundles.mvcs.Mediator;
public class ChatViewMediatorBase extends Mediator {
[Inject]
public var view:ChatViewBase;
[Inject]
public var chatMessageService:IChatMessageService;
[Inject]
public var chatMessagesSession:IChatMessagesSession;
[Inject]
public var userSession:IUserSession;
protected var _publicChat:Boolean = true;
protected var _user:User;
override public function initialize():void {
chatMessageService.sendMessageOnSuccessSignal.add(onSendSuccess);
chatMessageService.sendMessageOnFailureSignal.add(onSendFailure);
chatMessagesSession.newChatMessageSignal.add(scrollUpdate);
userSession.userList.userRemovedSignal.add(userRemoved);
userSession.userList.userAddedSignal.add(userAdded);
view.textInput.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
view.sendButton.addEventListener(MouseEvent.CLICK, sendButtonClickHandler);
// TEMP CODE NEED TO REMOVE SOMEHOW
_publicChat = true;
chatMessagesSession.publicChat
openChat(chatMessagesSession.publicChat);
// END OF TEMP CODE
}
protected function openChat(chatMessages:ChatMessages):void {
chatMessages.resetNewMessages();
view.chatList.dataProvider = chatMessages.messages;
}
private function onSendSuccess(result:String):void {
view.textInput.enabled = true;
view.textInput.text = "";
}
private function onSendFailure(status:String):void {
view.textInput.enabled = true;
}
private function scrollUpdate(userId:String = null, publicChat:Boolean = true):void {
if ((_publicChat && publicChat) || (!_publicChat && !publicChat && _user && userId == _user.userID)) {
if (isIndexVisible(view.chatList.dataProvider.length - 2)) {
view.chatList.ensureIndexIsVisible(view.chatList.dataProvider.length - 1);
}
}
}
private function isIndexVisible(itemIndex:int):Boolean {
return view.chatList.dataGroup.getItemIndicesInView().indexOf(itemIndex) > -1;
}
/**
* When user left the conference, add '[Offline]' to the username
* and disable text input
*/
protected function userRemoved(userID:String):void {
if (view != null && _user && _user.userID == userID) {
view.textInput.enabled = false;
}
}
/**
* When user returned(refreshed the page) to the conference, remove '[Offline]' from the username
* and enable text input
*/
protected function userAdded(newuser:User):void {
if ((view != null) && (_user != null) && (_user.userID == newuser.userID)) {
view.textInput.enabled = true;
}
}
private function keyDownHandler(e:KeyboardEvent):void {
if (e.keyCode == Keyboard.ENTER && !e.shiftKey) {
sendButtonClickHandler(null);
}
}
private function sendButtonClickHandler(e:MouseEvent):void {
view.textInput.enabled = false;
var message:String = StringUtil.trim(view.textInput.text);
if (message) {
var currentDate:Date = new Date();
//TODO get info from the right source
var m:ChatMessageVO = new ChatMessageVO();
m.fromUserID = userSession.userId;
m.fromUsername = userSession.userList.getUser(userSession.userId).name;
m.fromColor = "0";
m.fromTime = currentDate.time;
m.fromTimezoneOffset = currentDate.timezoneOffset;
m.fromLang = "en";
m.message = message;
m.toUserID = _publicChat ? "public_chat_userid" : _user.userID;
m.toUsername = _publicChat ? "public_chat_username" : _user.name;
if (_publicChat) {
m.chatType = "PUBLIC_CHAT";
chatMessageService.sendPublicMessage(m);
} else {
m.chatType = "PRIVATE_CHAT";
chatMessageService.sendPrivateMessage(m);
}
}
}
override public function destroy():void {
chatMessageService.sendMessageOnSuccessSignal.remove(onSendSuccess);
chatMessageService.sendMessageOnFailureSignal.remove(onSendFailure);
chatMessagesSession.newChatMessageSignal.remove(scrollUpdate);
userSession.userList.userRemovedSignal.remove(userRemoved);
userSession.userList.userAddedSignal.remove(userAdded);
view.textInput.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
view.sendButton.removeEventListener(MouseEvent.CLICK, sendButtonClickHandler);
super.destroy();
view = null;
}
}
}

View File

@ -0,0 +1,38 @@
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
styleName="participantIconStyle">
<fx:Script>
<![CDATA[
public function setFirstLetters(participantName:String):void {
var names:Array = participantName.split(" ");
var firstLettersText:String = names[0].charAt(0);
if (names[1]) {
firstLettersText += names[1].charAt(0);
}
firstLetters.text = firstLettersText.toUpperCase();
}
]]>
</fx:Script>
<s:Label id="firstLetters"
fontSize="{getStyle('fontSize')}"
verticalCenter="0"
horizontalCenter="0" />
<s:Ellipse id="circle"
height="25"
width="25"
verticalCenter="0"
horizontalCenter="0">
<s:stroke>
<s:SolidColorStroke id="circleColor"
color="{getStyle('circleColor')}"
weight="1" />
</s:stroke>
</s:Ellipse>
</s:Group>

View File

@ -104,4 +104,19 @@ s|Application
.handStatusButtonStyle
{
backgroundImage : Embed(source="../../air-client/src/assets/res/drawable-mdpi/hand.png");
}
}
.participantIconStyle
{
circleColor : #8898A5;
width : 32;
height : 32;
fontSize : 12;
}
.chatMessageStyle
{
nameFontSize: 16;
timeFontSize: 16;
messageFontSize: 14;
}

View File

@ -14,6 +14,7 @@
import org.bigbluebutton.lib.whiteboard.views.WhiteboardConfig;
import org.bigbluebutton.web.AppConfig;
import org.bigbluebutton.web.chat.ChatConfig;
import org.bigbluebutton.web.main.MainConfig;
import org.bigbluebutton.web.presentation.views.PresentationConfig;
@ -36,6 +37,7 @@
.configure(MainConfig)
.configure(PresentationConfig)
.configure(WhiteboardConfig)
.configure(ChatConfig)
.configure(new ContextView(this));
// If you wish to change the log level then uncomment the line below and set

View File

@ -1,4 +1,6 @@
package org.bigbluebutton.web.chat {
import org.bigbluebutton.lib.chat.views.ChatViewBase;
import org.bigbluebutton.lib.chat.views.ChatViewMediatorBase;
import org.bigbluebutton.web.chat.views.ChatView;
import org.bigbluebutton.web.chat.views.ChatViewMediator;
import org.bigbluebutton.web.chat.views.ChatWindow;
@ -39,8 +41,7 @@ package org.bigbluebutton.web.chat {
* Maps view mediators to views.
*/
private function mediators():void {
mediatorMap.map(ChatWindow).toMediator(ChatWindowMediator);
mediatorMap.map(ChatView).toMediator(ChatViewMediator);
mediatorMap.map(ChatViewBase).toMediator(ChatViewMediatorBase);
}
/**

View File

@ -1,6 +1,7 @@
package org.bigbluebutton.web.chat.views {
import mx.graphics.SolidColor;
import org.bigbluebutton.lib.chat.views.ChatViewBase;
import org.bigbluebutton.web.common.views.IPanelAdjustable;
import spark.components.Group;
@ -20,15 +21,10 @@ package org.bigbluebutton.web.chat.views {
public function ChatPanel() {
super();
var fillerRect:Rect = new Rect();
fillerRect.percentWidth = 100;
fillerRect.percentHeight = 100;
var fill:SolidColor = new SolidColor();
fill.color = 0x00FF00;
fillerRect.fill = fill;
addElement(fillerRect);
var _chatView:ChatViewBase = new ChatViewBase();
_chatView.percentWidth = 100;
_chatView.percentHeight = 100;
addElement(_chatView);
}
}
}

View File

@ -22,7 +22,9 @@ package org.bigbluebutton.web.main.views {
//this.setStyle("gap", 0);
this.direction = "horizontal";
}
public function createPanels():void {
var appWidth:Number = FlexGlobals.topLevelApplication.width;
var appHeight:Number = FlexGlobals.topLevelApplication.height;

View File

@ -12,8 +12,15 @@ package org.bigbluebutton.web.main.views {
public var uiSession:IUISession;
override public function initialize():void {
uiSession.loadingChangeSignal.add(onLoadingChangeSignal);
uiSession.participantsOpenSignal.add(onParticipantsOpenSignal);
onParticipantsOpenSignal();
}
private function onLoadingChangeSignal(val:Boolean, message:String):void {
if (!val) {
view.createPanels();
onParticipantsOpenSignal();
}
}
private function onParticipantsOpenSignal():void {
@ -21,6 +28,7 @@ package org.bigbluebutton.web.main.views {
}
override public function destroy():void {
uiSession.loadingChangeSignal.remove(onLoadingChangeSignal);
uiSession.participantsOpenSignal.remove(onParticipantsOpenSignal);
super.destroy();