diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties index 959898afa8..d860eadc9a 100755 --- a/bigbluebutton-client/locale/en_US/bbbResources.properties +++ b/bigbluebutton-client/locale/en_US/bbbResources.properties @@ -649,6 +649,7 @@ bbb.users.settings.lockAll=Lock All Users bbb.users.settings.lockAllExcept=Lock Users Except Presenter bbb.users.settings.lockSettings=Lock Viewers ... bbb.users.settings.breakoutRooms=Breakout Rooms ... +bbb.users.settings.sendBreakoutRoomsInvitations=Send Breakout Rooms Invitations ... bbb.users.settings.unlockAll=Unlock All Viewers bbb.users.settings.roomIsLocked=Locked by default bbb.users.settings.roomIsMuted=Muted by default @@ -670,6 +671,7 @@ bbb.lockSettings.locked=Locked bbb.lockSettings.lockOnJoin=Lock On Join bbb.users.breakout.breakoutRooms = Breakout Rooms +bbb.users.breakout.updateBreakoutRooms = Update Breakout Rooms bbb.users.breakout.remainingTimeBreakout = {0}: {1} remaining bbb.users.breakout.remainingTimeParent = {1} remaining bbb.users.breakout.calculatingRemainingTime = Calculating remaining time... @@ -683,6 +685,7 @@ bbb.users.breakout.record = Record bbb.users.breakout.notAssigned = Not Assigned bbb.users.breakout.dragAndDropToolTip = Tip: You can drag and drop users between rooms bbb.users.breakout.start = Start +bbb.users.breakout.invite = Invite bbb.users.breakout.close = Close bbb.users.breakout.closeAllRooms = Close All Breakout Rooms bbb.users.breakout.insufficientUsers = Insufficient users. You should place at least one user in one breakout room. diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/BreakoutRoomEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/BreakoutRoomEvent.as index a932fdf01f..c7201daa9d 100644 --- a/bigbluebutton-client/src/org/bigbluebutton/main/events/BreakoutRoomEvent.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/BreakoutRoomEvent.as @@ -17,40 +17,44 @@ * */ package org.bigbluebutton.main.events { - + import flash.events.Event; - + public class BreakoutRoomEvent extends Event { public static const OPEN_BREAKOUT_ROOMS_PANEL:String = "OPEN_BREAKOUT_ROOMS_PANEL"; - + public static const CREATE_BREAKOUT_ROOMS:String = "CREATE_BREAKOUT_ROOMS"; - + public static const REQUEST_BREAKOUT_JOIN_URL:String = "REQUEST_BREAKOUT_JOIN_URL"; - + public static const BREAKOUT_JOIN_URL:String = "BREAKOUT_JOIN_URL"; - + public static const LISTEN_IN:String = "LISTEN_IN"; - + public static const END_ALL_BREAKOUT_ROOMS:String = "END_ALL_BREAKOUT_ROOMS"; - + public static const UPDATE_REMAINING_TIME_PARENT:String = "UPDATE_REMAINING_TIME_PARENT"; public static const UPDATE_REMAINING_TIME_BREAKOUT:String = "UPDATE_REMAINING_TIME_BREAKOUT"; - + public var meetingId:String; - + public var breakoutId:String; - + public var rooms:Array; - + public var durationInMinutes:int; - + public var record:Boolean; - + public var joinURL:String; - + public var listen:Boolean; - + + public var joinMode:String; + + public var userId:String; + public function BreakoutRoomEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles, cancelable); } diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as index 2218a23904..7d302e8339 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as @@ -389,6 +389,7 @@ package org.bigbluebutton.main.model.users n.disableMyMic = user.disableMyMic; n.disableMyPrivateChat = user.disableMyPrivateChat; n.disableMyPublicChat = user.disableMyPublicChat; + n.breakoutRooms = user.breakoutRooms.concat(); // concatenate an array with nothing to deliver a new array. return n; } diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as index 1df93a1698..c899cfc0d0 100644 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as @@ -633,6 +633,16 @@ package org.bigbluebutton.main.model.users { } } } + + public function getBreakoutRoomInListen() : BreakoutRoom { + for (var i:int = 0; i < breakoutRooms.length; i++) { + var br:BreakoutRoom = BreakoutRoom(breakoutRooms.getItemAt(i)); + if (br.listenStatus == BreakoutRoom.SELF) { + return br; + } + } + return null; + } public function resetBreakoutRooms():void { for (var i:int = 0; i < breakoutRooms.length; i++) { diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as index a8eedd85b6..73f2f84f68 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as @@ -210,7 +210,7 @@ package org.bigbluebutton.main.model.users } public function requestBreakoutJoinUrl(e:BreakoutRoomEvent):void{ - sender.requestBreakoutJoinUrl(_conferenceParameters.meetingID, e.breakoutId, _conferenceParameters.userid); + sender.requestBreakoutJoinUrl(_conferenceParameters.meetingID, e.breakoutId, e.userId); } public function listenInOnBreakout(e:BreakoutRoomEvent):void { diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml index 873e5af97b..4ec206e18a 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml @@ -624,9 +624,10 @@ with BigBlueButton; if not, see . ls.y = point1.y - (ls.height/2); } - private function openBreakoutRoomsWindow(e:Event = null):void { + private function openBreakoutRoomsWindow(e:BreakoutRoomEvent):void { var popUp:IFlexDisplayObject = PopUpManager.createPopUp(mdiCanvas, BreakoutRoomSettings, true); PopUpManager.centerPopUp(popUp); + BreakoutRoomSettings(popUp).initCreateBreakoutRooms(e.joinMode); } private function onFooterLinkClicked(e:TextEvent):void{ diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml index 68ff9d1c04..b4568e8f68 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml @@ -40,6 +40,7 @@ with BigBlueButton; if not, see . import mx.binding.utils.ChangeWatcher; import mx.collections.ArrayCollection; import mx.controls.Alert; + import mx.controls.Button; import mx.events.FlexEvent; import mx.managers.PopUpManager; @@ -161,6 +162,11 @@ with BigBlueButton; if not, see . if (!captionTabs.contains(textTab)) { addTextTab(); } + + var tab:Button = captionTabs.getTabAt(0); + if (tab != null) { + tab.setStyle("fillColors", new Array(0xFFAE00, 0xD3800A)); + } } private function onTranscriptOwnerIDChange(o:Object):void { @@ -194,6 +200,11 @@ with BigBlueButton; if not, see . captionTabs.addChildAt(textTab, 0); } + private function onTabChange():void { + var tab:Button = captionTabs.getTabAt(captionTabs.selectedIndex); + tab.setStyle("fillColors", new Array(0xFFFFFF, 0xCCCCCC)); + } + private function localeChanged(e:Event):void{ resourcesChanged(); } @@ -228,6 +239,7 @@ with BigBlueButton; if not, see . + dragEnabled="false" popUpButtonPolicy="off" + change="onTabChange()"/> diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutList.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutList.mxml index 9f2a6facc2..48498e52ea 100644 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutList.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutList.mxml @@ -28,6 +28,9 @@ with BigBlueButton; if not, see . . [Bindable] public var notAssignedUsers:Boolean; + + [Bindable] + public var mode:String; + + protected function startDragHandler(event:DragEvent):void { + var selectedNode:BBBUser = usersList.selectedItem as BBBUser; + if (mode == "invite" && selectedNode.breakoutRooms.length > 0) { + event.stopImmediatePropagation(); + } + } ]]> - + diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml index cf9e68509e..7465c056b4 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml @@ -26,7 +26,7 @@ with BigBlueButton; if not, see . xmlns:mate="http://mate.asfusion.com/" width="630" height="650" close="onCloseClicked()" - creationComplete="creationCompleteHandler(event)" + visible="false" showCloseButton="false"> @@ -35,7 +35,6 @@ with BigBlueButton; if not, see . import mx.collections.ArrayCollection; import mx.controls.Alert; - import mx.events.FlexEvent; import mx.managers.PopUpManager; import org.bigbluebutton.core.managers.UserManager; @@ -47,15 +46,17 @@ with BigBlueButton; if not, see . private var roomsProvider:Array; private var dispatcher:Dispatcher; + + [Bindable] + private var mode:String; private function onCloseClicked():void { PopUpManager.removePopUp(this); } - /** * Dispatches a BreakoutRoomEvent to start creating breakout rooms */ - private function onStartClicked():void { + private function createBreakoutRooms():void { // Will be used to check that all the new breakout room contains at least one users var totalUsers:int; var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.CREATE_BREAKOUT_ROOMS); @@ -67,7 +68,7 @@ with BigBlueButton; if not, see . var room:Object = new Object(); room.users = new Array(); room.name = - UserManager.getInstance().getConference().meetingName + " (" + + UserManager.getInstance().getConference().meetingName + " (" + ResourceUtil.getInstance().getString('bbb.users.breakout.room') + " - " + (i + 1).toString() + ")";; for (var j:int = 0; j < users.length; j++) { @@ -78,16 +79,41 @@ with BigBlueButton; if not, see . if (totalUsers > 0) { event.durationInMinutes = durationStepper.value; event.record = recordCheckbox.selected; - dispatcher.dispatchEvent(event); PopUpManager.removePopUp(this); } else { Alert.show(ResourceUtil.getInstance().getString('bbb.users.breakout.insufficientUsers')); } } - - protected function assignUsers():void { - dispatcher = new Dispatcher(); + + /** + * Dispatches a BreakoutRoomEvent to send breakout rooms join URL invitations + */ + private function inviteUsersToBreakoutRooms():void { + var list:BreakoutList; + var user:BBBUser; + var usersInvited:Boolean = false; + for (var i:int; i < roomsContainer.numChildren - 1; i++) { + list = roomsContainer.getChildAt(i) as BreakoutList; + for (var u:int = 0; u < list.users.length; u++) { + user = list.users.getItemAt(u) as BBBUser; + if (user.breakoutRooms.length == 0) { + usersInvited ||= true; + var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.REQUEST_BREAKOUT_JOIN_URL); + event.userId = user.userID; + event.breakoutId = UserManager.getInstance().getConference().internalMeetingID + "-" + (i + 1); + dispatcher.dispatchEvent(event); + } + } + } + if (usersInvited) { + PopUpManager.removePopUp(this); + } else { + Alert.show(ResourceUtil.getInstance().getString('bbb.users.breakout.insufficientUsers')); + } + } + + protected function assignUsersForCreation():void { var originalUsers:ArrayCollection = UserManager.getInstance().getConference().users; var users:ArrayCollection = new ArrayCollection(); var me:BBBUser; @@ -121,19 +147,64 @@ with BigBlueButton; if not, see . unassignedList.roomName = ResourceUtil.getInstance().getString('bbb.users.breakout.notAssigned'); unassignedList.notAssignedUsers = true; startButton.enabled = true; - } - - protected function creationCompleteHandler(event:FlexEvent):void - { + } + + protected function assignUsersForInvitation():void { + var originalUsers:ArrayCollection = UserManager.getInstance().getConference().users; + var users:ArrayCollection = new ArrayCollection(); + // Copy users to avoid removing the references from the original ArrayCollection + for (var l:int = 0; l < originalUsers.length; l++) { + users.addItem(BBBUser.copy(originalUsers[l])); + } + // Create breakout rooms lists + var rooms:int = UserManager.getInstance().getConference().breakoutRooms.length; + var user:BBBUser; + roomsContainer.removeAllChildren(); + for (var r:int = 0; r < rooms; r++) { + var list:BreakoutList = roomsContainer.addChild(new BreakoutList()) as BreakoutList; + list.roomName = ResourceUtil.getInstance().getString('bbb.users.breakout.room') + " " + (r + 1).toString() + list.users = new ArrayCollection(); + list.mode = mode; + } + var unassignedUsers:ArrayCollection = new ArrayCollection(); + for (var j:int = 0; j < users.length; j++) { + user = users[j] as BBBUser; + if (user.breakoutRooms.length > 0) { + for (var b:int = 0; b < user.breakoutRooms.length; b++) { + BreakoutList(roomsContainer.getChildAt(user.breakoutRooms[b] - 1)).users.addItem(user as BBBUser); + } + } else { + unassignedUsers.addItem(user); + } + } + var unassignedList:BreakoutList = roomsContainer.addChild(new BreakoutList()) as BreakoutList; + unassignedList.users = unassignedUsers; + unassignedList.roomName = ResourceUtil.getInstance().getString('bbb.users.breakout.notAssigned'); + unassignedList.notAssignedUsers = true; + startButton.enabled = true; + } + public function initCreateBreakoutRooms(mode:String):void { + dispatcher = new Dispatcher(); roomsProvider = new Array(); - for (var i: int=2; i <=5; i++){ - roomsProvider.push(i.toString() + " " + ResourceUtil.getInstance().getString('bbb.users.breakout.rooms')); + this.mode = mode; + for (var i:int = 2; i <= 5; i++) { + roomsProvider.push(i.toString() + " " + ResourceUtil.getInstance().getString('bbb.users.breakout.rooms')); } roomsCombo.selectedIndex = 0; - - assignUsers(); + if (this.mode == "create") { + startButton.label = ResourceUtil.getInstance().getString('bbb.users.breakout.start'); + textArea.text = ResourceUtil.getInstance().getString('bbb.users.breakout.breakoutRooms'); + assignUsersForCreation(); + visible = true; + } else { + startButton.label = ResourceUtil.getInstance().getString('bbb.users.breakout.invite'); + roomsBox.visible = durationBox.visible = recordBox.visible = + roomsBox.includeInLayout = durationBox.includeInLayout = recordBox.includeInLayout = false; + textArea.text = ResourceUtil.getInstance().getString('bbb.users.breakout.updateBreakoutRooms'); + assignUsersForInvitation(); + visible = true; + } } - ]]> @@ -149,26 +220,27 @@ with BigBlueButton; if not, see . - + - + - + - + diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml index f2b931bbec..bf5ccf4390 100644 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml @@ -45,6 +45,7 @@ protected function requestBreakoutJoinUrl(event:MouseEvent):void { var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.REQUEST_BREAKOUT_JOIN_URL); e.breakoutId = data.breakoutId as String; + e.userId = UserManager.getInstance().getConference().getMyUserId(); globalDispatch.dispatchEvent(e); } ]]> diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UserItemRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UserItemRenderer.mxml new file mode 100644 index 0000000000..11dd8d7408 --- /dev/null +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UserItemRenderer.mxml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml index 4b271da0c8..e19ef0cefb 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml @@ -71,6 +71,7 @@ import org.bigbluebutton.main.events.BreakoutRoomEvent; import org.bigbluebutton.main.events.ShortcutEvent; import org.bigbluebutton.main.model.users.BBBUser; + import org.bigbluebutton.main.model.users.BreakoutRoom; import org.bigbluebutton.main.model.users.events.EmojiStatusEvent; import org.bigbluebutton.main.model.users.events.KickUserEvent; import org.bigbluebutton.main.model.users.events.RoleChangeEvent; @@ -268,8 +269,12 @@ paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.unmuteAll'), icon: images.audio, handler: muteAll}); paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.lockSettings'), icon: images.lock_open, handler: lockSettings}); - if (partOptions.enableBreakoutRooms && breakoutRoomsList.length == 0 && amIModerator && !UserManager.getInstance().getConference().isBreakout) { - paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.breakoutRooms'), handler: breakoutRooms}); + if (partOptions.enableBreakoutRooms && amIModerator && !UserManager.getInstance().getConference().isBreakout) { + if (breakoutRoomsList.length == 0) { + paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.breakoutRooms'), handler: breakoutRooms}); + } else { + paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.sendBreakoutRoomsInvitations'), handler: sendBreakoutRoomsInvitations}); + } } // make sure the previous menu is closed before opening a new one @@ -309,11 +314,18 @@ var event:LockControlEvent = new LockControlEvent(LockControlEvent.OPEN_LOCK_SETTINGS); dispatcher.dispatchEvent(event); } - private function breakoutRooms():void { - dispatcher.dispatchEvent(new BreakoutRoomEvent(BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL)); + var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL); + event.joinMode = "create"; + dispatcher.dispatchEvent(event); } - + + private function sendBreakoutRoomsInvitations():void { + var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL); + event.joinMode = "invite"; + dispatcher.dispatchEvent(event); + } + private function handleRemainingTimeUpdate(event:BreakoutRoomEvent):void { TimerUtil.setCountDownTimer(breakoutTimeLabel, event.durationInMinutes); } @@ -496,11 +508,19 @@ } } } - + private function endAllBreakoutRoomsHandler(event:MouseEvent):void { + // We need to switch the use back to the main audio confrence if he is in a breakout audio conference + var br:BreakoutRoom = UserManager.getInstance().getConference().getBreakoutRoomInListen(); + if (br != null) { + var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.LISTEN_IN); + e.breakoutId = br.breakoutId; + e.listen = false; + dispatcher.dispatchEvent(e); + } dispatcher.dispatchEvent(new BreakoutRoomEvent(BreakoutRoomEvent.END_ALL_BREAKOUT_ROOMS)); } - + private function focusWindow(e:ShortcutEvent):void { focusManager.setFocus(titleBarOverlay); } diff --git a/bigbluebutton-html5/imports/ui/components/logout-confirmation/component.jsx b/bigbluebutton-html5/imports/ui/components/logout-confirmation/component.jsx old mode 100644 new mode 100755 index 58606e4e2b..7d1b198156 --- a/bigbluebutton-html5/imports/ui/components/logout-confirmation/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/logout-confirmation/component.jsx @@ -47,7 +47,7 @@ class LeaveConfirmation extends Component { { + this.clearCredentials(() => { document.location.href = logoutURL; }); };