Skip to content

Commit

Permalink
Merge pull request bigbluebutton#5975 from riadvice/user-typing-feature
Browse files Browse the repository at this point in the history
Implementation of user typing feature to chat
  • Loading branch information
ritzalam authored Sep 12, 2018
2 parents 408a780 + 83031aa commit cdaf447
Show file tree
Hide file tree
Showing 15 changed files with 328 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class ChatApp2x(implicit val context: ActorContext)
extends GetChatHistoryReqMsgHdlr
with SendPublicMessagePubMsgHdlr
with SendPrivateMessagePubMsgHdlr
with ClearPublicChatHistoryPubMsgHdlr {
with ClearPublicChatHistoryPubMsgHdlr
with UserTypingPubMsgHdlr {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.bigbluebutton.core.apps.chat

import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.running.{ LiveMeeting, LogHelper }

trait UserTypingPubMsgHdlr extends LogHelper {
def handle(msg: UserTypingPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastEvent(msg: UserTypingPubMsg): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(UserTypingEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserTypingEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)

val body = UserTypingEvtMsgBody(msg.body.chatId, msg.header.userId)
val event = UserTypingEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
broadcastEvent(msg)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ class ReceivedJsonMsgHandlerActor(
routeGenericMsg[SendPrivateMessagePubMsg](envelope, jsonNode)
case ClearPublicChatHistoryPubMsg.NAME =>
routeGenericMsg[ClearPublicChatHistoryPubMsg](envelope, jsonNode)
case UserTypingPubMsg.NAME =>
routeGenericMsg[UserTypingPubMsg](envelope, jsonNode)

// Meeting
case EndMeetingSysCmdMsg.NAME =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,45 +42,43 @@ object MeetingActor {
props: DefaultProps,
eventBus: InternalEventBus,
outGW: OutMsgRouter,
liveMeeting: LiveMeeting
): Props =
liveMeeting: LiveMeeting): Props =
Props(classOf[MeetingActor], props, eventBus, outGW, liveMeeting)
}

class MeetingActor(
val props: DefaultProps,
val eventBus: InternalEventBus,
val outGW: OutMsgRouter,
val liveMeeting: LiveMeeting
)
extends BaseMeetingActor
with SystemConfiguration
with GuestsApp
with LayoutApp2x
with VoiceApp2x
with BreakoutApp2x
with UsersApp2x

with UserBroadcastCamStartMsgHdlr
with UserJoinMeetingReqMsgHdlr
with UserJoinMeetingAfterReconnectReqMsgHdlr
with UserBroadcastCamStopMsgHdlr
with UserConnectedToGlobalAudioMsgHdlr
with UserDisconnectedFromGlobalAudioMsgHdlr
with MuteAllExceptPresentersCmdMsgHdlr
with MuteMeetingCmdMsgHdlr
with IsMeetingMutedReqMsgHdlr

with EjectUserFromVoiceCmdMsgHdlr
with EndMeetingSysCmdMsgHdlr
with DestroyMeetingSysCmdMsgHdlr
with SendTimeRemainingUpdateHdlr
with SendBreakoutTimeRemainingMsgHdlr
with ChangeLockSettingsInMeetingCmdMsgHdlr
with SyncGetMeetingInfoRespMsgHdlr
with ClientToServerLatencyTracerMsgHdlr
with ValidateConnAuthTokenSysMsgHdlr
with UserActivitySignCmdMsgHdlr {
val liveMeeting: LiveMeeting)
extends BaseMeetingActor
with SystemConfiguration
with GuestsApp
with LayoutApp2x
with VoiceApp2x
with BreakoutApp2x
with UsersApp2x

with UserBroadcastCamStartMsgHdlr
with UserJoinMeetingReqMsgHdlr
with UserJoinMeetingAfterReconnectReqMsgHdlr
with UserBroadcastCamStopMsgHdlr
with UserConnectedToGlobalAudioMsgHdlr
with UserDisconnectedFromGlobalAudioMsgHdlr
with MuteAllExceptPresentersCmdMsgHdlr
with MuteMeetingCmdMsgHdlr
with IsMeetingMutedReqMsgHdlr

with EjectUserFromVoiceCmdMsgHdlr
with EndMeetingSysCmdMsgHdlr
with DestroyMeetingSysCmdMsgHdlr
with SendTimeRemainingUpdateHdlr
with SendBreakoutTimeRemainingMsgHdlr
with ChangeLockSettingsInMeetingCmdMsgHdlr
with SyncGetMeetingInfoRespMsgHdlr
with ClientToServerLatencyTracerMsgHdlr
with ValidateConnAuthTokenSysMsgHdlr
with UserActivitySignCmdMsgHdlr {

override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case e: Exception => {
Expand All @@ -98,8 +96,7 @@ class MeetingActor(
*/
var actorMonitor = context.actorOf(
MeetingActorAudit.props(props, eventBus, outGW),
"actorMonitor-" + props.meetingProp.intId
)
"actorMonitor-" + props.meetingProp.intId)

val msgBus = MessageBus(eventBus, outGW)

Expand All @@ -121,8 +118,7 @@ class MeetingActor(
TimeUtil.minutesToMillis(props.durationProps.warnMinutesBeforeMax),
lastActivityTimestampInMs = TimeUtil.timeNowInMs(),
warningSent = false,
warningSentOnTimestampInMs = 0L
)
warningSentOnTimestampInMs = 0L)

val expiryTracker = new MeetingExpiryTracker(
startedOnInMs = TimeUtil.timeNowInMs(),
Expand All @@ -134,8 +130,7 @@ class MeetingActor(
meetingExpireWhenLastUserLeftInMs = TimeUtil.minutesToMillis(props.durationProps.meetingExpireWhenLastUserLeftInMinutes),
userInactivityInspectTimerInMs = TimeUtil.minutesToMillis(props.durationProps.userInactivityInspectTimerInMinutes),
userInactivityThresholdInMs = TimeUtil.minutesToMillis(props.durationProps.userInactivityInspectTimerInMinutes),
userActivitySignResponseDelayInMs = TimeUtil.minutesToMillis(props.durationProps.userActivitySignResponseDelayInMinutes)
)
userActivitySignResponseDelayInMs = TimeUtil.minutesToMillis(props.durationProps.userActivitySignResponseDelayInMinutes))

val recordingTracker = new MeetingRecordingTracker(startedOnInMs = 0L, previousDurationInMs = 0L, currentDurationInMs = 0L)

Expand All @@ -145,8 +140,7 @@ class MeetingActor(
None,
inactivityTracker,
expiryTracker,
recordingTracker
)
recordingTracker)

var lastRttTestSentOn = System.currentTimeMillis()

Expand Down Expand Up @@ -402,6 +396,7 @@ class MeetingActor(
chatApp2x.handle(m, liveMeeting, msgBus)
updateUserLastActivity(m.body.message.fromUserId)
case m: ClearPublicChatHistoryPubMsg => state = chatApp2x.handle(m, state, liveMeeting, msgBus)
case m: UserTypingPubMsg => chatApp2x.handle(m, liveMeeting, msgBus)

// Screenshare
case m: ScreenshareStartedVoiceConfEvtMsg => screenshareApp2x.handle(m, liveMeeting, msgBus)
Expand Down Expand Up @@ -460,8 +455,7 @@ class MeetingActor(
screenshareApp2x.handleScreenshareStoppedVoiceConfEvtMsg(
liveMeeting.props.voiceProp.voiceConf,
liveMeeting.props.screenshareProps.screenshareConf,
liveMeeting, msgBus
)
liveMeeting, msgBus)

newState

Expand Down Expand Up @@ -552,8 +546,7 @@ class MeetingActor(
if (authedUsers.isEmpty) {
sendEndMeetingDueToExpiry(
MeetingEndReason.ENDED_DUE_TO_NO_AUTHED_USER,
eventBus, outGW, liveMeeting
)
eventBus, outGW, liveMeeting)
}
}
}
Expand Down Expand Up @@ -581,8 +574,7 @@ class MeetingActor(

val event = buildRecordingStatusChangedEvtMsg(
liveMeeting.props.meetingProp.intId,
"system", MeetingStatus2x.isRecording(liveMeeting.status)
)
"system", MeetingStatus2x.isRecording(liveMeeting.status))
outGW.send(event)

}
Expand All @@ -606,8 +598,7 @@ class MeetingActor(

val event = buildRecordingStatusChangedEvtMsg(
liveMeeting.props.meetingProp.intId,
"system", MeetingStatus2x.isRecording(liveMeeting.status)
)
"system", MeetingStatus2x.isRecording(liveMeeting.status))
outGW.send(event)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ object AllowedMessageNames {
SendGroupChatMessageMsg.NAME,
ClearPublicChatHistoryPubMsg.NAME,
CreateGroupChatReqMsg.NAME,
UserTypingPubMsg.NAME,

// Presentation Messages
ResizeAndMovePagePubMsg.NAME,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,42 @@
package org.bigbluebutton.common2.msgs


/* In Messages */
object GetChatHistoryReqMsg { val NAME = "GetChatHistoryReqMsg"}
object GetChatHistoryReqMsg { val NAME = "GetChatHistoryReqMsg" }
case class GetChatHistoryReqMsg(header: BbbClientMsgHeader, body: GetChatHistoryReqMsgBody) extends StandardMsg
case class GetChatHistoryReqMsgBody()

object SendPublicMessagePubMsg { val NAME = "SendPublicMessagePubMsg"}
object SendPublicMessagePubMsg { val NAME = "SendPublicMessagePubMsg" }
case class SendPublicMessagePubMsg(header: BbbClientMsgHeader, body: SendPublicMessagePubMsgBody) extends StandardMsg
case class SendPublicMessagePubMsgBody(message: ChatMessageVO)

object SendPrivateMessagePubMsg { val NAME = "SendPrivateMessagePubMsg"}
object SendPrivateMessagePubMsg { val NAME = "SendPrivateMessagePubMsg" }
case class SendPrivateMessagePubMsg(header: BbbClientMsgHeader, body: SendPrivateMessagePubMsgBody) extends StandardMsg
case class SendPrivateMessagePubMsgBody(message: ChatMessageVO)

object ClearPublicChatHistoryPubMsg { val NAME = "ClearPublicChatHistoryPubMsg"}
object ClearPublicChatHistoryPubMsg { val NAME = "ClearPublicChatHistoryPubMsg" }
case class ClearPublicChatHistoryPubMsg(header: BbbClientMsgHeader, body: ClearPublicChatHistoryPubMsgBody) extends StandardMsg
case class ClearPublicChatHistoryPubMsgBody(chatId: String)

/* Out Messages */
object GetChatHistoryRespMsg { val NAME = "GetChatHistoryRespMsg"}
object GetChatHistoryRespMsg { val NAME = "GetChatHistoryRespMsg" }
case class GetChatHistoryRespMsg(header: BbbClientMsgHeader, body: GetChatHistoryRespMsgBody) extends StandardMsg
case class GetChatHistoryRespMsgBody(history: Array[ChatMessageVO])

object SendPublicMessageEvtMsg { val NAME = "SendPublicMessageEvtMsg"}
object SendPublicMessageEvtMsg { val NAME = "SendPublicMessageEvtMsg" }
case class SendPublicMessageEvtMsg(header: BbbClientMsgHeader, body: SendPublicMessageEvtMsgBody) extends StandardMsg
case class SendPublicMessageEvtMsgBody(message: ChatMessageVO)

object SendPrivateMessageEvtMsg { val NAME = "SendPrivateMessageEvtMsg"}
object SendPrivateMessageEvtMsg { val NAME = "SendPrivateMessageEvtMsg" }
case class SendPrivateMessageEvtMsg(header: BbbClientMsgHeader, body: SendPrivateMessageEvtMsgBody) extends StandardMsg
case class SendPrivateMessageEvtMsgBody(message: ChatMessageVO)

object ClearPublicChatHistoryEvtMsg { val NAME = "ClearPublicChatHistoryEvtMsg"}
object ClearPublicChatHistoryEvtMsg { val NAME = "ClearPublicChatHistoryEvtMsg" }
case class ClearPublicChatHistoryEvtMsg(header: BbbClientMsgHeader, body: ClearPublicChatHistoryEvtMsgBody) extends StandardMsg
case class ClearPublicChatHistoryEvtMsgBody(chatId: String)

object UserTypingEvtMsg { val NAME = "UserTypingEvtMsg" }
case class UserTypingEvtMsg(header: BbbClientMsgHeader, body: UserTypingEvtMsgBody) extends StandardMsg
case class UserTypingEvtMsgBody(chatId: String, userId: String)

case class ChatMessageVO(fromUserId: String, fromUsername: String, fromColor: String, fromTime: Long, fromTimezoneOffset: Int,
toUserId: String, toUsername: String, message: String)
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ object GroupChatMessageBroadcastEvtMsg { val NAME = "GroupChatMessageBroadcastEv
case class GroupChatMessageBroadcastEvtMsg(header: BbbClientMsgHeader, body: GroupChatMessageBroadcastEvtMsgBody) extends BbbCoreMsg
case class GroupChatMessageBroadcastEvtMsgBody(chatId: String, msg: GroupChatMsgToUser)

object UserTypingPubMsg { val NAME = "UserTypingPubMsg"}
case class UserTypingPubMsg(header: BbbClientMsgHeader, body: UserTypingPubMsgBody) extends StandardMsg
case class UserTypingPubMsgBody(chatId: String)

// html5 client only
object SyncGetGroupChatsRespMsg { val NAME = "SyncGetGroupChatsRespMsg"}
case class SyncGetGroupChatsRespMsg(header: BbbClientMsgHeader, body: SyncGetGroupChatsRespMsgBody) extends BbbCoreMsg
Expand Down
17 changes: 17 additions & 0 deletions bigbluebutton-client/branding/default/style/css/V2Theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,23 @@ chat|ChatMessageRenderer {
paddingRight : 12;
}

.userTypingCanvas {
backgroundColor : #FFFFFF;
}

.msgTooLongLabel {
color : #DE2721;
}

.userTypingLabel {
fontSize : 13;
color : #4E5A66;
paddingBottom : 2;
paddingTop : 2;
paddingLeft : 4;
paddingRight : 4;
}

/*
//------------------------------
// CheckBox
Expand Down
3 changes: 3 additions & 0 deletions bigbluebutton-client/locale/en_US/bbbResources.properties
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ bbb.chat.fontSize = Chat Message Font Size
bbb.chat.cmbFontSize.toolTip = Select Chat Message Font Size
bbb.chat.messageList = Chat Messages
bbb.chat.unreadMessages = You have new unread messages ▼
bbb.chat.usersTyping.one = {0} is typing…
bbb.chat.usersTyping.many = {0} & {1} are typing…
bbb.chat.usersTyping.multiple = Multiple users are typing…
bbb.chat.minimizeBtn.accessibilityName = Minimize the Chat Window
bbb.chat.maximizeRestoreBtn.accessibilityName = Maximize the Chat Window
bbb.chat.closeBtn.accessibilityName = Close the Chat Window
Expand Down
42 changes: 25 additions & 17 deletions ...ules/videoconf/events/UserTalkingEvent.as → ...on/modules/chat/events/UserTypingEvent.as
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/*
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
*
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; either version 3.0 of the License, or (at your option) any later
* version.
*
*
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
Expand All @@ -16,17 +16,25 @@
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.modules.videoconf.events
{
import flash.events.Event;

public class UserTalkingEvent extends Event
{
public static const TALKING:String = "USER TALKING PRIORITIZE";

public function UserTalkingEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
package org.bigbluebutton.modules.chat.events {
import flash.events.Event;

public class UserTypingEvent extends Event {
// Used to send user typing to server
public static const USER_TYPING_EVENT:String = 'userTypingEvent';

// Used when receiving user typing message from the server
public static const USER_TYPING_MESSAGE:String = 'userTypingMessage';

public var chatId:String;

public var userId:String;

public function UserTypingEvent(type:String, chatId:String, userId:String) {
super(type, false, false);
this.chatId = chatId;
this.userId = userId;
}

}
}
Loading

0 comments on commit cdaf447

Please sign in to comment.