diff --git a/src/Default.css b/src/Default.css index 12d2fa6..0690cf7 100644 --- a/src/Default.css +++ b/src/Default.css @@ -121,6 +121,11 @@ s|RadioButton skinClass: ClassReference("org.bigbluebutton.view.skins.RadioButtonSkin"); } +s|CheckBox +{ + skinClass: ClassReference("org.bigbluebutton.view.skins.CheckBoxSkin") +} + s|Image.bbbLogoStyle { verticalCenter: 0; @@ -283,6 +288,11 @@ global backgroundImage: Embed(source="assets/res/drawable-mdpi/deskshare.png"); } + ui|NavigationButton.pollsBtnStyle + { + backgroundImage: Embed(source="assets/res/drawable-mdpi/polling.png"); + } + s|Button.logoutButtonStyle { height: 50; @@ -398,6 +408,12 @@ global eclipseBottom: 10; } + s|CheckBox + { + height: 40; + width: 40; + } + s|Image.bbbLogoStyle { imageSource: Embed(source="assets/res/drawable-mdpi/ic_launcher.png"); @@ -550,6 +566,11 @@ global backgroundImage: Embed(source="assets/res/drawable-hdpi/deskshare.png"); } + ui|NavigationButton.pollsBtnStyle + { + backgroundImage: Embed(source="assets/res/drawable-hdpi/polling.png"); + } + s|Button.topButtonStyle { width: 45; @@ -642,6 +663,12 @@ global eclipseBottom: 15; } + s|CheckBox + { + height: 60; + width: 60; + } + s|Image.bbbLogoStyle { imageSource: Embed(source="assets/res/drawable-hdpi/ic_launcher.png"); @@ -793,6 +820,11 @@ global backgroundImage: Embed(source="assets/res/drawable-xhdpi/deskshare.png"); } + ui|NavigationButton.pollsBtnStyle + { + backgroundImage: Embed(source="assets/res/drawable-xhdpi/polling.png"); + } + s|Button.topButtonStyle { width: 60; @@ -880,6 +912,12 @@ global eclipseBottom: 20; } + s|CheckBox + { + height: 80; + width: 80; + } + s|Image.bbbLogoStyle { imageSource: Embed(source="assets/res/drawable-xhdpi/ic_launcher.png"); @@ -1008,6 +1046,11 @@ global backgroundImage: Embed(source="assets/res/drawable-xxhdpi/deskshare.png"); } + ui|NavigationButton.pollsBtnStyle + { + backgroundImage: Embed(source="assets/res/drawable-xxhdpi/polling.png"); + } + s|Button.logoutButtonStyle { height: 150; @@ -1128,6 +1171,12 @@ global eclipseBottom: 30; } + s|CheckBox + { + height: 120; + width: 120; + } + s|Group.userDetailGroupStyle { height: 90; diff --git a/src/Main.mxml b/src/Main.mxml index 88cc6bc..6e46fa5 100644 --- a/src/Main.mxml +++ b/src/Main.mxml @@ -48,6 +48,9 @@ import org.bigbluebutton.view.navigation.pages.selectparticipant.SelectParticipantConfig; import org.bigbluebutton.view.navigation.pages.userdetails.UserDetaisConfig; import org.bigbluebutton.view.navigation.pages.videochat.VideoChatConfig; + import org.bigbluebutton.view.navigation.pages.pollslist.PollsListConfig; + import org.bigbluebutton.view.navigation.pages.takepoll.TakePollConfig; + import org.bigbluebutton.view.navigation.pages.pollresults.PollResultsConfig; import org.bigbluebutton.view.ui.MicButtonConfig; import org.bigbluebutton.view.ui.NavigationButtonConfig; import org.bigbluebutton.view.ui.RecordingStatusConfig; @@ -125,6 +128,9 @@ .configure(DisconnectPageConfig) .configure(DeskshareConfig) .configure(MenuButtonsConfig) + .configure(PollsListConfig) + .configure(TakePollConfig) + .configure(PollResultsConfig) .configure(RecordingStatusConfig) .configure(new ContextView(this)); diff --git a/src/assets/res/drawable-hdpi/polling.png b/src/assets/res/drawable-hdpi/polling.png new file mode 100644 index 0000000..a8dd943 Binary files /dev/null and b/src/assets/res/drawable-hdpi/polling.png differ diff --git a/src/assets/res/drawable-mdpi/polling.png b/src/assets/res/drawable-mdpi/polling.png new file mode 100644 index 0000000..802c6f7 Binary files /dev/null and b/src/assets/res/drawable-mdpi/polling.png differ diff --git a/src/assets/res/drawable-xhdpi/polling.png b/src/assets/res/drawable-xhdpi/polling.png new file mode 100644 index 0000000..40d57f7 Binary files /dev/null and b/src/assets/res/drawable-xhdpi/polling.png differ diff --git a/src/assets/res/drawable-xxhdpi/polling.png b/src/assets/res/drawable-xxhdpi/polling.png new file mode 100644 index 0000000..e58df61 Binary files /dev/null and b/src/assets/res/drawable-xxhdpi/polling.png differ diff --git a/src/assets/res/drawable-xxxhdpi/polling.png b/src/assets/res/drawable-xxxhdpi/polling.png new file mode 100644 index 0000000..12d1ebb Binary files /dev/null and b/src/assets/res/drawable-xxxhdpi/polling.png differ diff --git a/src/locale/en_US/resources.properties b/src/locale/en_US/resources.properties index 9ceec95..4d2e2bb 100644 --- a/src/locale/en_US/resources.properties +++ b/src/locale/en_US/resources.properties @@ -41,4 +41,13 @@ disconnect.reason.userLoggedOut=You have logged out of the meeting disconnect.reason.userKickedOut=You have been kicked out of the meeting disconnect.reason.userExit=Exit deskshare.noDeskshare = No desktop stream to display -deskshare.title = Desktop Sharing \ No newline at end of file +deskshare.title = Desktop Sharing +pollsList.title=Poll List +pollsList.notStarted=[Not Started] +pollsList.closed=[Closed - View Results] +pollsList.alreadyVoted=[Already Voted - View Results] +pollsList.voteNow=[Vote Now] +takePoll.title=Take Poll +takePoll.submit=Submit +takePoll.errorMessage=Please make sure to respond to each question +pollResults.title=Poll Results \ No newline at end of file diff --git a/src/org/bigbluebutton/AppConfig.as b/src/org/bigbluebutton/AppConfig.as index 8fcf638..48df782 100644 --- a/src/org/bigbluebutton/AppConfig.as +++ b/src/org/bigbluebutton/AppConfig.as @@ -38,7 +38,8 @@ package org.bigbluebutton import org.bigbluebutton.model.UserUISession; import org.bigbluebutton.model.chat.ChatMessagesSession; import org.bigbluebutton.model.chat.IChatMessagesSession; - + import org.bigbluebutton.core.IPollService; + import org.bigbluebutton.core.PollService; import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap; @@ -63,6 +64,7 @@ package org.bigbluebutton injector.map(IChatMessageService).toSingleton(ChatMessageService); injector.map(IPresentationService).toSingleton(PresentationService); injector.map(IChatMessagesSession).toSingleton(ChatMessagesSession); + injector.map(IPollService).toSingleton(PollService); injector.map(IDeskshareConnection).toSingleton(DeskshareConnection); // Type mapping diff --git a/src/org/bigbluebutton/command/ConnectCommand.as b/src/org/bigbluebutton/command/ConnectCommand.as index a446b32..a766b7a 100644 --- a/src/org/bigbluebutton/command/ConnectCommand.as +++ b/src/org/bigbluebutton/command/ConnectCommand.as @@ -16,9 +16,10 @@ package org.bigbluebutton.command import org.bigbluebutton.model.IUserSession; import org.bigbluebutton.model.IUserUISession; import org.bigbluebutton.view.navigation.pages.PagesENUM; + import org.bigbluebutton.core.IPollService; import org.osmf.logging.Log; - import robotlegs.bender.bundles.mvcs.Command; + import robotlegs.bender.bundles.mvcs.Command; public class ConnectCommand extends Command { @@ -55,6 +56,9 @@ package org.bigbluebutton.command [Inject] public var presentationService: IPresentationService; + [Inject] + public var pollService:IPollService; + override public function execute():void { connection.uri = uri; @@ -88,6 +92,7 @@ package org.bigbluebutton.command // Set up remaining message sender and receivers: chatService.setupMessageSenderReceiver(); presentationService.setupMessageSenderReceiver(); + pollService.setupMessageSenderReceiver(); // set up and connect the remaining connections videoConnection.uri = userSession.config.getConfigFor("VideoConfModule").@uri + "/" + conferenceParameters.room; @@ -108,20 +113,21 @@ package org.bigbluebutton.command deskshareConnection.connect(); userSession.deskshareConnection = deskshareConnection; - - // Query the server for chat, users, and presentation info + + // Query the server for chat, users, polls, and presentation info chatService.sendWelcomeMessage(); chatService.getPublicChatMessages(); presentationService.getPresentationInfo(); - + userSession.userList.allUsersAddedSignal.add(successUsersAdded); usersService.queryForParticipants(); usersService.queryForRecordingStatus(); + pollService.getPolls(); + userSession.successJoiningMeetingSignal.remove(successJoiningMeeting); userSession.unsuccessJoiningMeetingSignal.remove(unsuccessJoiningMeeting); - usersService.getRoomLockState(); } private function unsuccessJoiningMeeting():void { diff --git a/src/org/bigbluebutton/core/IPollService.as b/src/org/bigbluebutton/core/IPollService.as new file mode 100644 index 0000000..f7a34ca --- /dev/null +++ b/src/org/bigbluebutton/core/IPollService.as @@ -0,0 +1,11 @@ +package org.bigbluebutton.core +{ + import org.bigbluebutton.model.polling.Responses; + + public interface IPollService + { + function setupMessageSenderReceiver():void; + function getPolls():void; + function respondPoll(pollID:String, responses:Array):void; + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/core/PollMessageReceiver.as b/src/org/bigbluebutton/core/PollMessageReceiver.as new file mode 100644 index 0000000..0cdfe26 --- /dev/null +++ b/src/org/bigbluebutton/core/PollMessageReceiver.as @@ -0,0 +1,180 @@ +package org.bigbluebutton.core +{ + import org.bigbluebutton.model.IMessageListener; + import org.bigbluebutton.model.IUserSession; + import org.bigbluebutton.model.polling.Poll; + import org.bigbluebutton.model.polling.Question; + import org.bigbluebutton.model.polling.Responder; + import org.bigbluebutton.model.polling.Response; + + + public class PollMessageReceiver implements IMessageListener + { + public var userSession:IUserSession; + + public function PollMessageReceiver(userSession:IUserSession) { + this.userSession = userSession; + } + + public function onMessage(messageName:String, message:Object):void { + switch(messageName) { + case "pollGetPollsReply": + handleGetPollsReply(message); + break; + case "pollCreatedMessage": + handlePollCreatedMessage(message); + break; + case "pollUpdatedMessage": + handlePollUpdatedMessage(message); + break; + case "pollDestroyedMessage": + handlePollDestroyedMessage(message); + break; + case "pollStartedMessage": + handlePollStartedMessage(message); + break; + case "pollStoppedMessage": + handlePollStoppedMessage(message); + break; + case "pollResultUpdatedMessage": + handlePollResultUpdatedMessage(message); + break; + default: + break; + } + } + + private function handleGetPollsReply(m:Object):void { + var polls:Array = JSON.parse(m.msg) as Array; + trace("PollMessageReceiver::handleGetPollsReply() -- [" + polls.length + "] polls received from server"); + + for(var i:int = 0; i < polls.length; i++) { + userSession.pollModel.createPoll(buildPoll(polls[i])); + } + } + + private function handlePollCreatedMessage(m:Object):void { + var poll:Object = JSON.parse(m.msg); + trace("PollMessageReceiver::handlePollCreatedMessage() -- creating poll [" + poll.title + "]"); + userSession.pollModel.createPoll(buildPoll(poll)); + } + + private function handlePollUpdatedMessage(m:Object):void { + var poll:Object = JSON.parse(m.msg); + trace("PollMessageReceiver::handlePollUpdatedMessage() -- updating poll [" + poll.title + "]"); + if(userSession.pollModel.hasPoll(poll.id)) { + userSession.pollModel.updatePoll(buildPoll(poll)); + } + } + + private function handlePollDestroyedMessage(m:Object):void { + var poll:Object = JSON.parse(m.msg); + trace("PollMessageReceiver::handlePollDestroyedMessage() -- destroying poll [" + poll.title + "]"); + if(userSession.pollModel.hasPoll(poll.pollID)) { + userSession.pollModel.destroyPoll(poll.pollID); + } + } + + private function handlePollStartedMessage(m:Object):void { + var poll:Object = JSON.parse(m.msg); + trace("PollMessageReceiver::handlePollStartedMessage() -- starting poll [" + poll.title + "]"); + if(userSession.pollModel.hasPoll(poll.pollID)) { + userSession.pollModel.startPoll(poll.pollID); + } + } + + private function handlePollStoppedMessage(m:Object):void { + var poll:Object = JSON.parse(m.msg); + trace("PollMessageReceiver::handlePollStoppedMessage() -- stopping poll [" + poll.title + "]"); + if(userSession.pollModel.hasPoll(poll.pollID)) { + userSession.pollModel.stopPoll(poll.pollID); + } + } + + private function handlePollResultUpdatedMessage(m:Object):void { + var message:Object = JSON.parse(m.msg); + + /*** The format of 'message': + * { + * "response": + * { + * "pollID":"pollID-103", + * "responses": + * [ + * { + * "questionID":"q1", + * "responseIDs":["0","1"] + * }, + * + * ... + * ] + * }, + * + * "responder": + * { + * "userID":"enfjadjc5xnn", + * "name":"RED" + * } + * } + */ + + var response:Object = message.response; + + if(userSession.pollModel.hasPoll(response.pollID)) { + var responses:Array = response.responses; + var responder:Responder = buildResponder(message.responder); + + for(var i:int = 0; i < responses.length; i++) { + var individualResponse:Object = responses[i]; + var responseIDs:Array = individualResponse.responseIDs; + + for(var j:int = 0; j < responseIDs.length; j++) { + userSession.pollModel.updateResults(response.pollID, individualResponse.questionID, responseIDs[j], responder); + } + } + } + } + + private function buildPoll(pollObj:Object):Poll { + trace("PollMessageReceiver::handleGetPollsReply() -- building poll [" + pollObj.title + "]"); + var questions:Array = pollObj.questions; + var qs:Array = new Array(); + + for(var i:int = 0; i < questions.length; i++) { + qs.push(buildQuestion(questions[i])); + } + + return new Poll(pollObj.id, pollObj.title, qs, pollObj.started, pollObj.stopped); + } + + private function buildQuestion(questionObj:Object):Question { + trace("PollMessageReceiver::buildQuestion() -- building question [" + questionObj.question + "]"); + var responses:Array = questionObj.responses; + var rs:Array = new Array(); + + for(var i:int = 0; i < responses.length; i++) { + rs.push(buildResponse(responses[i])); + } + + return new Question(questionObj.id, questionObj.multiResponse, questionObj.question, rs); + } + + private function buildResponse(responseObj:Object):Response { + trace("PollMessageReceiver::buildResponse -- building response [" + responseObj.text + "]"); + var responders:Array = responseObj.responders; + var rs:Array = new Array(); + + for(var i:int = 0; i < responders.length; i++) { + rs.push(buildResponder(responders[i])); + } + + return new Response(responseObj.id, responseObj.text, rs); + } + + private function buildResponder(responderObj:Object):Responder { + trace("PollMessageReceiver::buildResponder -- building responder for userID [" + responderObj.userID + "], name [" + responderObj.name + "]"); + return new Responder(responderObj.userID, responderObj.name); + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/core/PollMessageSender.as b/src/org/bigbluebutton/core/PollMessageSender.as new file mode 100644 index 0000000..f08ecbb --- /dev/null +++ b/src/org/bigbluebutton/core/PollMessageSender.as @@ -0,0 +1,33 @@ +package org.bigbluebutton.core +{ + import org.bigbluebutton.model.IUserSession; + + public class PollMessageSender + { + public var userSession:IUserSession; + + // The default callbacks of userSession.mainconnection.sendMessage + private var defaultSuccessResponse:Function = function(result:String):void { trace(result); }; + private var defaultFailureResponse:Function = function(status:String):void { trace(status); }; + + public function PollMessageSender(userSession:IUserSession) { + this.userSession = userSession; + } + + public function getPolls():void { + trace("PollMessageSender::getPolls() -- Sending [poll.getPolls] message to server"); + userSession.mainConnection.sendMessage("poll.getPolls", defaultSuccessResponse, defaultFailureResponse); + } + + public function respondPoll(pollID:String, responses:Array):void { + var messageObject:Object = new Object(); + messageObject["pollID"] = pollID; + messageObject["questions"] = responses; + + var message:String = JSON.stringify(messageObject); + trace("PollMessageSender::getPolls() -- Sending [poll.respondPoll] message to server with message: " + message); + + userSession.mainConnection.sendMessage("poll.respondPoll", defaultSuccessResponse, defaultFailureResponse, message); + } + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/core/PollService.as b/src/org/bigbluebutton/core/PollService.as new file mode 100644 index 0000000..1535026 --- /dev/null +++ b/src/org/bigbluebutton/core/PollService.as @@ -0,0 +1,34 @@ +package org.bigbluebutton.core +{ + import org.bigbluebutton.model.IMessageListener; + import org.bigbluebutton.model.IUserSession; + + public class PollService implements IPollService + { + [Inject] + public var userSession: IUserSession; + + public var pollMessageSender:PollMessageSender; + public var pollMessageReceiver:PollMessageReceiver; + + public function PollService() { + + } + + public function setupMessageSenderReceiver():void { + pollMessageSender = new PollMessageSender(userSession); + pollMessageReceiver = new PollMessageReceiver(userSession); + + userSession.mainConnection.addMessageListener(pollMessageReceiver as IMessageListener); + } + + public function getPolls():void { + pollMessageSender.getPolls(); + } + + public function respondPoll(pollID:String, responses:Array):void { + pollMessageSender.respondPoll(pollID, responses); + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/model/IUserSession.as b/src/org/bigbluebutton/model/IUserSession.as index 75fdba7..5e5371f 100644 --- a/src/org/bigbluebutton/model/IUserSession.as +++ b/src/org/bigbluebutton/model/IUserSession.as @@ -3,17 +3,17 @@ package org.bigbluebutton.model import flash.net.NetConnection; import org.bigbluebutton.core.IBigBlueButtonConnection; + import org.bigbluebutton.core.IDeskshareConnection; import org.bigbluebutton.core.IVideoConnection; import org.bigbluebutton.core.IVoiceConnection; import org.bigbluebutton.core.VideoConnection; import org.bigbluebutton.core.VoiceConnection; import org.bigbluebutton.core.VoiceStreamManager; import org.bigbluebutton.model.chat.ChatMessages; + import org.bigbluebutton.model.polling.PollModel; import org.bigbluebutton.model.presentation.PresentationList; import org.osflash.signals.ISignal; - import org.osflash.signals.Signal; - import org.bigbluebutton.core.IVoiceConnection; - import org.bigbluebutton.core.IDeskshareConnection; + import org.osflash.signals.Signal; public interface IUserSession @@ -34,6 +34,7 @@ package org.bigbluebutton.model function get deskshareConnection():IDeskshareConnection; function set deskshareConnection(value:IDeskshareConnection):void; function get presentationList():PresentationList; + function get pollModel():PollModel; function get guestSignal():ISignal; function get successJoiningMeetingSignal():ISignal; function get unsuccessJoiningMeetingSignal():ISignal; diff --git a/src/org/bigbluebutton/model/UserList.as b/src/org/bigbluebutton/model/UserList.as index ada420e..06b6708 100644 --- a/src/org/bigbluebutton/model/UserList.as +++ b/src/org/bigbluebutton/model/UserList.as @@ -21,6 +21,15 @@ package org.bigbluebutton.model private var _users:ArrayCollection; + public function UserList() + { + _me = new User(); + _users = new ArrayCollection(); + _sort = new Sort(); + _sort.compareFunction = sortFunction; + _users.sort = _sort; + } + [Bindable] public function get users():ArrayCollection { @@ -46,15 +55,6 @@ package org.bigbluebutton.model private var _sort:Sort; - public function UserList() - { - _me = new User(); - _users = new ArrayCollection(); - _sort = new Sort(); - _sort.compareFunction = sortFunction; - _users.sort = _sort; - } - /** * Dispatched when all participants are added */ diff --git a/src/org/bigbluebutton/model/UserSession.as b/src/org/bigbluebutton/model/UserSession.as index 322a5fa..f5f958a 100644 --- a/src/org/bigbluebutton/model/UserSession.as +++ b/src/org/bigbluebutton/model/UserSession.as @@ -11,6 +11,7 @@ package org.bigbluebutton.model import org.bigbluebutton.core.VoiceConnection; import org.bigbluebutton.core.VoiceStreamManager; import org.bigbluebutton.model.chat.ChatMessages; + import org.bigbluebutton.model.polling.PollModel; import org.bigbluebutton.model.presentation.PresentationList; import org.hamcrest.core.throws; import org.osflash.signals.ISignal; @@ -28,6 +29,7 @@ package org.bigbluebutton.model protected var _userList:UserList; protected var _presentationList:PresentationList; protected var _recording:Boolean; + protected var _pollModel:PollModel; protected var _guestSignal:ISignal = new Signal(); protected var _successJoiningMeetingSignal:ISignal = new Signal(); @@ -35,6 +37,14 @@ package org.bigbluebutton.model protected var _recordingStatusChangedSignal:ISignal = new Signal(); protected var _logoutSignal:Signal = new Signal(); + + public function UserSession() + { + _userList = new UserList(); + _presentationList = new PresentationList(); + _pollModel = new PollModel(); + } + public function get userList():UserList { return _userList; @@ -110,18 +120,16 @@ package org.bigbluebutton.model { _deskshareConnection = value; } - - public function UserSession() - { - _userList = new UserList(); - _presentationList = new PresentationList(); - } public function get presentationList():PresentationList { return _presentationList } + public function get pollModel():PollModel { + return _pollModel; + } + public function get guestSignal():ISignal { return _guestSignal; diff --git a/src/org/bigbluebutton/model/polling/Poll.as b/src/org/bigbluebutton/model/polling/Poll.as new file mode 100644 index 0000000..c7fa902 --- /dev/null +++ b/src/org/bigbluebutton/model/polling/Poll.as @@ -0,0 +1,96 @@ +package org.bigbluebutton.model.polling +{ + public class Poll + { + private var _id:String; + private var _title:String; + private var _questions:Array; + + private var _started:Boolean = false; + private var _stopped:Boolean = false; + + private var _startedOn:Date; + private var _stoppedOn:Date; + private var _durationInMinutes:int = 5; + + private var _hasResponded:Boolean = false; + + public function Poll(id:String, title:String, questions:Array, started:Boolean, stopped:Boolean) { + _id = id; + _title = title; + _questions = questions; + _started = started; + _stopped = stopped; + } + + public function get id():String { + return _id; + } + + public function get title():String { + return _title; + } + + public function get questions():Array { + return _questions; + } + + public function get started():Boolean { + return _started; + } + + public function get stopped():Boolean { + return _stopped; + } + + public function get duration():int { + return _durationInMinutes; + } + + public function start():void { + _started = true; + _startedOn = new Date(); + } + + public function stop():void { + _stopped = true; + _stoppedOn = new Date(); + } + + public function timeRemainingInSeconds():int { + var timeRemainingInSeconds:Number = (_durationInMinutes * 60) - (new Date().time - _startedOn.time) / 1000; + if(timeRemainingInSeconds <= 0) { + return 0; + } + else { + return timeRemainingInSeconds; + } + } + + private function getQuestion(questionID:String):Question { + for (var i:int = 0; i < _questions.length; i++) { + var q:Question = _questions[i] as Question; + if(q && q.id == questionID) { + return q; + } + } + + return null; + } + + public function updateResults(questionID:String, responseID:String, responder:Responder):void { + var q:Question = getQuestion(questionID); + if(q) { + q.updateResult(responseID, responder); + } + } + + public function userResponded():void { + _hasResponded = true; + } + + public function get hasResponded():Boolean { + return _hasResponded; + } + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/model/polling/PollModel.as b/src/org/bigbluebutton/model/polling/PollModel.as new file mode 100644 index 0000000..ecf3d57 --- /dev/null +++ b/src/org/bigbluebutton/model/polling/PollModel.as @@ -0,0 +1,132 @@ +package org.bigbluebutton.model.polling +{ + import mx.collections.ArrayCollection; + + import org.osflash.signals.ISignal; + import org.osflash.signals.Signal; + + public class PollModel + { + public static const POLL_CREATED:int = 0; + public static const POLL_DESTROYED:int = 1; + public static const POLL_STARTED:int = 2; + public static const POLL_STOPPED:int = 3; + public static const POLL_UPDATED:int = 4; + public static const POLL_RESULTS_UPDATED:int = 5; + public static const I_RESPONDED_TO_POLL:int = 6; + + public var pollsChangedSignal:ISignal = new Signal(); + public var responseToPollSignal:ISignal = new Signal(); + + private var _polls:ArrayCollection; + + public function PollModel() { + _polls = new ArrayCollection(); + } + + public function get Polls():ArrayCollection { + return _polls; + } + + public function createPoll(poll:Poll):void { + if(poll && !hasPoll(poll.id)) { + _polls.addItem(poll); + } + + pollsChangedSignal.dispatch(POLL_CREATED, poll.id); + } + + public function destroyPoll(pollID:String):void { + if(hasPoll(pollID)) { + _polls.removeItemAt(getPollIndex(pollID)); + } + + pollsChangedSignal.dispatch(POLL_DESTROYED, pollID); + } + + public function startPoll(pollID:String):void { + if(hasPoll(pollID)) { + var poll:Poll = getPoll(pollID); + poll.start(); + } + + pollsChangedSignal.dispatch(POLL_STARTED, pollID); + } + + public function stopPoll(pollID:String):void { + if(hasPoll(pollID)) { + var poll:Poll = getPoll(pollID); + poll.stop(); + } + + pollsChangedSignal.dispatch(POLL_STOPPED, pollID); + } + + public function updatePoll(poll:Poll):void { + if(hasPoll(poll.id)) { + _polls.removeItemAt(getPollIndex(poll.id)); + _polls.addItem(poll); + } + + pollsChangedSignal.dispatch(POLL_UPDATED, poll.id); + } + + public function updateResults(pollID:String, questionID:String, responseID:String, responder:Responder):void { + if(hasPoll(pollID)) { + var poll:Poll = getPoll(pollID); + poll.updateResults(questionID, responseID, responder); + } + + responseToPollSignal.dispatch(pollID, questionID, responseID); + } + + public function getPoll(pollID:String):Poll { + if(hasPoll(pollID)) { + return _polls.getItemAt(getPollIndex(pollID)) as Poll; + } + return null; + } + + private function getPollIndex(pollID:String):int { + for(var i:int = 0; i < _polls.length; i++) { + var p:Poll = _polls.getItemAt(i) as Poll; + if(p && p.id == pollID) { + return i; + } + } + return -1; + } + + public function hasPoll(pollID:String):Boolean { + for(var i:int = 0; i < _polls.length; i++) { + var p:Poll = _polls.getItemAt(i) as Poll; + if(p && p.id == pollID) { + return true; + } + } + return false; + } + + public function userHasResponded(pollID:String):void { + for(var i:int = 0; i < _polls.length; i++) { + var p:Poll = _polls.getItemAt(i) as Poll; + if(p && p.id == pollID) { + p.userResponded(); + } + } + + pollsChangedSignal.dispatch(I_RESPONDED_TO_POLL, pollID); + } + + public function hasUserResponded(pollID:String):Boolean { + for(var i:int = 0; i < _polls.length; i++) { + var p:Poll = _polls.getItemAt(i) as Poll; + if(p && p.id == pollID) { + return p.hasResponded; + } + } + return false; + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/model/polling/Question.as b/src/org/bigbluebutton/model/polling/Question.as new file mode 100644 index 0000000..6b12060 --- /dev/null +++ b/src/org/bigbluebutton/model/polling/Question.as @@ -0,0 +1,43 @@ +package org.bigbluebutton.model.polling +{ + public class Question + { + private var _id: String; + private var _multiResponse:Boolean; + private var _question:String; + private var _responses:Array; + + public function Question(id:String, multiResponse:Boolean, question:String, responses:Array) { + _id = id; + _multiResponse = multiResponse; + _question = question; + _responses = responses; + } + + public function get id():String { + return _id; + } + + public function get multiResponse():Boolean { + return _multiResponse; + } + + public function get question():String { + return _question; + } + + public function get responses():Array { + return _responses; + } + + public function updateResult(responseID:String, responder:Responder):void { + for(var i:int = 0; i < _responses.length; i++) { + var r:Response = _responses[i] as Response; + if(r && r.id == responseID) { + r.addResponder(responder); + } + } + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/model/polling/Responder.as b/src/org/bigbluebutton/model/polling/Responder.as new file mode 100644 index 0000000..86e4cf4 --- /dev/null +++ b/src/org/bigbluebutton/model/polling/Responder.as @@ -0,0 +1,21 @@ +package org.bigbluebutton.model.polling +{ + public class Responder + { + private var _userID:String; + private var _username:String; + + public function Responder(userID:String, username:String) { + _userID = userID; + _username = username; + } + + public function get userID():String { + return _userID; + } + + public function get username():String { + return _username; + } + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/model/polling/Response.as b/src/org/bigbluebutton/model/polling/Response.as new file mode 100644 index 0000000..fec85eb --- /dev/null +++ b/src/org/bigbluebutton/model/polling/Response.as @@ -0,0 +1,31 @@ +package org.bigbluebutton.model.polling +{ + public class Response + { + private var _id:String; + private var _response:String; + private var _responders:Array; + + public function Response(id:String, response:String, responders:Array) { + _id = id; + _response = response; + _responders = responders; + } + + public function get id():String { + return _id; + } + + public function get response():String { + return _response; + } + + public function addResponder(r:Responder):void { + _responders.push(r); + } + + public function get numResponses():int { + return _responders.length; + } + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/model/polling/Responses.as b/src/org/bigbluebutton/model/polling/Responses.as new file mode 100644 index 0000000..cbb0c91 --- /dev/null +++ b/src/org/bigbluebutton/model/polling/Responses.as @@ -0,0 +1,21 @@ +package org.bigbluebutton.model.polling +{ + public class Responses + { + private var _questionID:String; + private var _responses:Array; + + public function Responses(questionID:String, responses:Array) { + _questionID = questionID; + _responses = responses; + } + + public function get questionID():String { + return _questionID; + } + + public function get responseIDs():Array { + return _responses; + } + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/view/navigation/PagesNavigatorViewMediator.as b/src/org/bigbluebutton/view/navigation/PagesNavigatorViewMediator.as index bce96d0..28a91cb 100644 --- a/src/org/bigbluebutton/view/navigation/PagesNavigatorViewMediator.as +++ b/src/org/bigbluebutton/view/navigation/PagesNavigatorViewMediator.as @@ -69,7 +69,13 @@ package org.bigbluebutton.view.navigation break; } } - if(pageName == PagesENUM.PARTICIPANTS || pageName == PagesENUM.PRESENTATION || pageName == PagesENUM.VIDEO_CHAT || pageName == PagesENUM.CHATROOMS) + + if(pageName == PagesENUM.PARTICIPANTS + || pageName == PagesENUM.PRESENTATION + || pageName == PagesENUM.VIDEO_CHAT + || pageName == PagesENUM.CHATROOMS + || pageName == PagesENUM.DESKSHARE + || pageName == PagesENUM.POLLS_LIST) { view.popAll(); view.pushView(PagesENUM.getClassfromName(pageName), null, null, transition); diff --git a/src/org/bigbluebutton/view/navigation/pages/PagesENUM.as b/src/org/bigbluebutton/view/navigation/pages/PagesENUM.as index 6a18fff..4908996 100644 --- a/src/org/bigbluebutton/view/navigation/pages/PagesENUM.as +++ b/src/org/bigbluebutton/view/navigation/pages/PagesENUM.as @@ -13,6 +13,9 @@ package org.bigbluebutton.view.navigation.pages import org.bigbluebutton.view.navigation.pages.userdetails.UserDetaisView; import org.bigbluebutton.view.navigation.pages.videochat.VideoChatView; import org.bigbluebutton.view.navigation.pages.deskshare.DeskshareView; + import org.bigbluebutton.view.navigation.pages.pollslist.PollsListView; + import org.bigbluebutton.view.navigation.pages.takepoll.TakePollView; + import org.bigbluebutton.view.navigation.pages.pollresults.PollResultsView; public class PagesENUM { @@ -27,6 +30,9 @@ package org.bigbluebutton.view.navigation.pages public static const SELECT_PARTICIPANT:String = "selectparticipant"; public static const DISCONNECT:String = "Disconnect"; public static const DESKSHARE:String = "Deskshare"; + public static const POLLS_LIST:String = "PollsList"; + public static const TAKE_POLL:String = "TakePoll"; + public static const POLL_RESULTS:String = "PollResults"; /** * Especials @@ -48,6 +54,9 @@ package org.bigbluebutton.view.navigation.pages dic[SELECT_PARTICIPANT] = SelectParticipantView; dic[DISCONNECT] = DisconnectPageView; dic[DESKSHARE] = DeskshareView; + dic[POLLS_LIST] = PollsListView; + dic[TAKE_POLL] = TakePollView; + dic[POLL_RESULTS] = PollResultsView; dicInitiated = true; } diff --git a/src/org/bigbluebutton/view/navigation/pages/common/MenuButtons.mxml b/src/org/bigbluebutton/view/navigation/pages/common/MenuButtons.mxml index b9d35ad..75a5151 100644 --- a/src/org/bigbluebutton/view/navigation/pages/common/MenuButtons.mxml +++ b/src/org/bigbluebutton/view/navigation/pages/common/MenuButtons.mxml @@ -18,6 +18,7 @@ + diff --git a/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsView.as b/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsView.as index a3d3aec..1b97428 100644 --- a/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsView.as +++ b/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsView.as @@ -4,6 +4,10 @@ package org.bigbluebutton.view.navigation.pages.common public class MenuButtonsView extends MenuButtons implements IMenuButtonsView { + public function get menuPollsButton():NavigationButton + { + return pollsBtn0; + } public function get menuDeskshareButton():NavigationButton { diff --git a/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsViewMediator.as b/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsViewMediator.as index 6e31913..d3dcb0d 100644 --- a/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsViewMediator.as +++ b/src/org/bigbluebutton/view/navigation/pages/common/MenuButtonsViewMediator.as @@ -29,6 +29,9 @@ package org.bigbluebutton.view.navigation.pages.common { /*var users:ArrayCollection = userSession.userList.users;*/ userUISession.loadingSignal.remove(loadingFinished); + + userSession.pollModel.pollsChangedSignal.add(onPollChange); + if (userSession.deskshareConnection != null) { view.menuDeskshareButton.visible = view.menuDeskshareButton.includeInLayout = userSession.deskshareConnection.isStreaming; @@ -45,6 +48,12 @@ package org.bigbluebutton.view.navigation.pages.common }*/ } } + + public function onPollChange(change:int, pollID:String):void + { + view.menuPollsButton.visible = view.menuPollsButton.includeInLayout = true; + } + /** * If we recieve signal that deskshare stream is on - include Deskshare button to the layout */ diff --git a/src/org/bigbluebutton/view/navigation/pages/pollresults/IPollResultsView.as b/src/org/bigbluebutton/view/navigation/pages/pollresults/IPollResultsView.as new file mode 100644 index 0000000..089b256 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollresults/IPollResultsView.as @@ -0,0 +1,11 @@ +package org.bigbluebutton.view.navigation.pages.pollresults +{ + import org.bigbluebutton.core.view.IView; + + import spark.components.Group; + + public interface IPollResultsView extends IView + { + function get resultsList():Group + } +} diff --git a/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsConfig.as b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsConfig.as new file mode 100644 index 0000000..d850cb2 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsConfig.as @@ -0,0 +1,54 @@ +package org.bigbluebutton.view.navigation.pages.pollresults +{ + + import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap; + import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap; + import robotlegs.bender.framework.api.IConfig; + import robotlegs.bender.framework.api.IInjector; + + + public class PollResultsConfig implements IConfig + { + [Inject] + public var injector: IInjector; + + [Inject] + public var mediatorMap: IMediatorMap; + + [Inject] + public var signalCommandMap: ISignalCommandMap; + + public function configure(): void + { + dependencies(); + mediators(); + signals(); + } + + /** + * Specifies all the dependencies for the feature + * that will be injected onto objects used by the + * application. + */ + private function dependencies(): void + { + + } + + /** + * Maps view mediators to views. + */ + private function mediators(): void + { + mediatorMap.map(IPollResultsView).toMediator(PollResultsViewMediator); + } + + /** + * Maps signals to commands using the signalCommandMap. + */ + private function signals(): void + { + + } + } +} diff --git a/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsView.as b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsView.as new file mode 100644 index 0000000..9413878 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsView.as @@ -0,0 +1,19 @@ +package org.bigbluebutton.view.navigation.pages.pollresults +{ + import spark.components.Group; + + public class PollResultsView extends PollResultsViewBase implements IPollResultsView + { + public function get resultsList():Group { + return resultsList0; + } + + override protected function childrenCreated():void { + super.childrenCreated(); + } + + public function dispose():void { + + } + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsViewBase.mxml b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsViewBase.mxml new file mode 100644 index 0000000..937f33a --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsViewBase.mxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsViewMediator.as b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsViewMediator.as new file mode 100644 index 0000000..6da4bbe --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollresults/PollResultsViewMediator.as @@ -0,0 +1,114 @@ +package org.bigbluebutton.view.navigation.pages.pollresults +{ + import mx.core.FlexGlobals; + import mx.resources.ResourceManager; + + import org.bigbluebutton.model.IUserSession; + import org.bigbluebutton.model.IUserUISession; + import org.bigbluebutton.model.polling.PollModel; + import org.bigbluebutton.model.polling.Question; + import org.bigbluebutton.model.polling.Response; + import org.bigbluebutton.view.navigation.pages.PagesENUM; + + import robotlegs.bender.bundles.mvcs.Mediator; + + import spark.components.Group; + + public class PollResultsViewMediator extends Mediator + { + [Inject] + public var userSession:IUserSession; + + [Inject] + public var userUISession: IUserUISession; + + [Inject] + public var view:IPollResultsView; + + private var id:String; + + override public function initialize():void { + id = userUISession.currentPageDetails.id; + + userSession.pollModel.responseToPollSignal.add(handleResponseToPoll); + userSession.pollModel.pollsChangedSignal.add(handlePollModelChanged); + + FlexGlobals.topLevelApplication.pageName.text = ResourceManager.getInstance().getString('resources', 'pollResults.title'); + + addPollResults(); + } + + private function addPollResults():void { + var questions:Array = userSession.pollModel.getPoll(id).questions; + + for(var i:int = 0; i < questions.length; i++) { + var question:Question = questions[i]; + var responseListView:ResponseListView = new ResponseListView(); + + responseListView.initialize(); + responseListView.id = question.id; + responseListView.question.text = question.question; + + var responses:Array = question.responses; + + for(var j:int = 0; j < responses.length; j++) { + var response:Response = responses[j]; + var responseView:ResponseView = new ResponseView(); + + responseView.initialize(); + responseView.id = response.id; + responseView.response.text = response.response; + responseView.numberOfResponses.text = response.numResponses.toString(); + + responseListView.responsesList.addElement(responseView); + } + view.resultsList.addElement(responseListView); + } + } + + private function handleResponseToPoll(pollID:String, questionID:String, responseID:String): void { + if(id == pollID) { + var responseListView:ResponseListView = getResponseListView(questionID); + if(responseListView) { + var responsesList:Group = responseListView.responsesList; + for(var i:int = 0; i < responsesList.numElements; i++) { + var responseView:ResponseView = responsesList.getElementAt(i) as ResponseView; + if(responseView && responseID == responseView.id) { + var temp:Number = Number(responseView.numberOfResponses.text); + temp++; + responseView.numberOfResponses.text = temp.toString(); + } + } + } + } + } + + private function getResponseListView(questionID:String):ResponseListView { + var resultsList:Group = view.resultsList; + for(var i:int = 0; i < resultsList.numElements; i++) { + var responseListView:ResponseListView = resultsList.getElementAt(i) as ResponseListView; + if(responseListView && questionID == responseListView.id) { + return responseListView; + } + } + return null; + } + + private function handlePollModelChanged(change:int, pollID:String):void { + if(change == PollModel.POLL_DESTROYED && id == pollID) { + userUISession.pushPage(PagesENUM.POLLS_LIST); + } + } + + override public function destroy():void { + super.destroy(); + + userSession.pollModel.responseToPollSignal.remove(handleResponseToPoll); + userSession.pollModel.pollsChangedSignal.remove(handlePollModelChanged); + + view.dispose(); + view = null; + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/view/navigation/pages/pollresults/ResponseListView.mxml b/src/org/bigbluebutton/view/navigation/pages/pollresults/ResponseListView.mxml new file mode 100644 index 0000000..fc45990 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollresults/ResponseListView.mxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/navigation/pages/pollresults/ResponseView.mxml b/src/org/bigbluebutton/view/navigation/pages/pollresults/ResponseView.mxml new file mode 100644 index 0000000..01149d4 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollresults/ResponseView.mxml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/navigation/pages/pollslist/IPollsListView.as b/src/org/bigbluebutton/view/navigation/pages/pollslist/IPollsListView.as new file mode 100644 index 0000000..f129032 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollslist/IPollsListView.as @@ -0,0 +1,11 @@ +package org.bigbluebutton.view.navigation.pages.pollslist +{ + import org.bigbluebutton.core.view.IView; + + import spark.components.List; + + public interface IPollsListView extends IView + { + function get list():List; + } +} diff --git a/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListConfig.as b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListConfig.as new file mode 100644 index 0000000..9f5fda5 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListConfig.as @@ -0,0 +1,54 @@ +package org.bigbluebutton.view.navigation.pages.pollslist +{ + + import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap; + import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap; + import robotlegs.bender.framework.api.IConfig; + import robotlegs.bender.framework.api.IInjector; + + + public class PollsListConfig implements IConfig + { + [Inject] + public var injector: IInjector; + + [Inject] + public var mediatorMap: IMediatorMap; + + [Inject] + public var signalCommandMap: ISignalCommandMap; + + public function configure(): void + { + dependencies(); + mediators(); + signals(); + } + + /** + * Specifies all the dependencies for the feature + * that will be injected onto objects used by the + * application. + */ + private function dependencies(): void + { + + } + + /** + * Maps view mediators to views. + */ + private function mediators(): void + { + mediatorMap.map(IPollsListView).toMediator(PollsListViewMediator); + } + + /** + * Maps signals to commands using the signalCommandMap. + */ + private function signals(): void + { + + } + } +} diff --git a/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListItemRenderer.mxml b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListItemRenderer.mxml new file mode 100644 index 0000000..878ff1e --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListItemRenderer.mxml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListView.as b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListView.as new file mode 100644 index 0000000..8cd8d88 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListView.as @@ -0,0 +1,21 @@ +package org.bigbluebutton.view.navigation.pages.pollslist +{ + + import spark.components.List; + + public class PollsListView extends PollsListViewBase implements IPollsListView + { + public function get list():List { + return pollsList; + } + + override protected function childrenCreated():void { + super.childrenCreated(); + } + + public function dispose():void { + + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListViewBase.mxml b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListViewBase.mxml new file mode 100644 index 0000000..5f0f00a --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListViewBase.mxml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListViewMediator.as b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListViewMediator.as new file mode 100644 index 0000000..3d27e3d --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/pollslist/PollsListViewMediator.as @@ -0,0 +1,85 @@ +package org.bigbluebutton.view.navigation.pages.pollslist +{ + import mx.collections.ArrayCollection; + import mx.core.FlexGlobals; + import mx.resources.ResourceManager; + + import org.bigbluebutton.model.IUserSession; + import org.bigbluebutton.model.IUserUISession; + import org.bigbluebutton.model.polling.PollModel; + import org.bigbluebutton.view.navigation.pages.PagesENUM; + + import robotlegs.bender.bundles.mvcs.Mediator; + + import spark.components.List; + import spark.events.IndexChangeEvent; + + + public class PollsListViewMediator extends Mediator + { + [Inject] + public var userSession:IUserSession; + + [Inject] + public var userUISession: IUserUISession; + + [Inject] + public var view:IPollsListView; + + private var pollsList:List; + + private var dataProvider:ArrayCollection = new ArrayCollection(); + + override public function initialize():void { + dataProvider = userSession.pollModel.Polls; + + pollsList = view.list; + pollsList.dataProvider = dataProvider; + + userSession.pollModel.pollsChangedSignal.add(handlePollModelChanged); + pollsList.addEventListener(IndexChangeEvent.CHANGE, onIndexChangeHandler); + + FlexGlobals.topLevelApplication.pageName.text = ResourceManager.getInstance().getString('resources', 'pollsList.title'); + } + + private function onIndexChangeHandler(event:IndexChangeEvent):void { + var item:Object = dataProvider.getItemAt(event.newIndex); + if(item) { + if(!item.started) { + return; + } + else if(item.stopped || item.hasResponded) { + userUISession.pushPage(PagesENUM.POLL_RESULTS, item) + } + else { + userUISession.pushPage(PagesENUM.TAKE_POLL, item); + } + } + } + + private function handlePollModelChanged(change:int, pollID:String):void { + switch(change) { + case PollModel.POLL_CREATED: + case PollModel.POLL_DESTROYED: + case PollModel.POLL_STARTED: + case PollModel.POLL_STOPPED: + case PollModel.I_RESPONDED_TO_POLL: + dataProvider.refresh(); + break; + default: + break; + } + } + + override public function destroy():void { + super.destroy(); + + pollsList.removeEventListener(IndexChangeEvent.CHANGE, onIndexChangeHandler); + userSession.pollModel.pollsChangedSignal.remove(handlePollModelChanged); + + view.dispose(); + view = null; + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/view/navigation/pages/takepoll/ITakePollView.as b/src/org/bigbluebutton/view/navigation/pages/takepoll/ITakePollView.as new file mode 100644 index 0000000..fd3d965 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/takepoll/ITakePollView.as @@ -0,0 +1,14 @@ +package org.bigbluebutton.view.navigation.pages.takepoll +{ + import org.bigbluebutton.core.view.IView; + + import spark.components.Button; + import spark.components.Group; + import spark.components.Label; + + public interface ITakePollView extends IView { + function get questionViews():Group; + function get submitButton():Button; + function get errorMessage():Label; + } +} diff --git a/src/org/bigbluebutton/view/navigation/pages/takepoll/QuestionView.mxml b/src/org/bigbluebutton/view/navigation/pages/takepoll/QuestionView.mxml new file mode 100644 index 0000000..22531ad --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/takepoll/QuestionView.mxml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollConfig.as b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollConfig.as new file mode 100644 index 0000000..fa9b591 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollConfig.as @@ -0,0 +1,54 @@ +package org.bigbluebutton.view.navigation.pages.takepoll +{ + + import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap; + import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap; + import robotlegs.bender.framework.api.IConfig; + import robotlegs.bender.framework.api.IInjector; + + + public class TakePollConfig implements IConfig + { + [Inject] + public var injector: IInjector; + + [Inject] + public var mediatorMap: IMediatorMap; + + [Inject] + public var signalCommandMap: ISignalCommandMap; + + public function configure(): void + { + dependencies(); + mediators(); + signals(); + } + + /** + * Specifies all the dependencies for the feature + * that will be injected onto objects used by the + * application. + */ + private function dependencies(): void + { + + } + + /** + * Maps view mediators to views. + */ + private function mediators(): void + { + mediatorMap.map(ITakePollView).toMediator(TakePollViewMediator); + } + + /** + * Maps signals to commands using the signalCommandMap. + */ + private function signals(): void + { + + } + } +} diff --git a/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollView.as b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollView.as new file mode 100644 index 0000000..693d2dd --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollView.as @@ -0,0 +1,30 @@ +package org.bigbluebutton.view.navigation.pages.takepoll +{ + import spark.components.Button; + import spark.components.Group; + import spark.components.Label; + + public class TakePollView extends TakePollViewBase implements ITakePollView + { + override protected function childrenCreated():void { + super.childrenCreated(); + } + + public function get questionViews():Group { + return questionViewGroup; + } + + public function get submitButton():Button { + return submitButton0; + } + + public function get errorMessage():Label { + return errorMessage0; + } + + public function dispose():void { + + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollViewBase.mxml b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollViewBase.mxml new file mode 100644 index 0000000..0d89286 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollViewBase.mxml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollViewMediator.as b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollViewMediator.as new file mode 100644 index 0000000..a301418 --- /dev/null +++ b/src/org/bigbluebutton/view/navigation/pages/takepoll/TakePollViewMediator.as @@ -0,0 +1,213 @@ +package org.bigbluebutton.view.navigation.pages.takepoll +{ + + import flash.events.MouseEvent; + + import mx.core.FlexGlobals; + import mx.resources.ResourceManager; + + import org.bigbluebutton.core.IPollService; + import org.bigbluebutton.model.IUserSession; + import org.bigbluebutton.model.IUserUISession; + import org.bigbluebutton.model.polling.Poll; + import org.bigbluebutton.model.polling.PollModel; + import org.bigbluebutton.model.polling.Question; + import org.bigbluebutton.model.polling.Responses; + import org.bigbluebutton.view.navigation.pages.PagesENUM; + + import robotlegs.bender.bundles.mvcs.Mediator; + + import spark.components.CheckBox; + import spark.components.Group; + import spark.components.RadioButton; + + + public class TakePollViewMediator extends Mediator + { + [Inject] + public var userSession:IUserSession; + + [Inject] + public var userUISession: IUserUISession; + + [Inject] + public var pollService:IPollService; + + [Inject] + public var view:ITakePollView; + + private var id:String; + private var questionViewGroup:Group; + + override public function initialize():void { + id = userUISession.currentPageDetails.id + questionViewGroup = view.questionViews; + + userSession.pollModel.pollsChangedSignal.add(handlePollModelChanged); + view.submitButton.addEventListener(MouseEvent.CLICK, onSubmit); + + FlexGlobals.topLevelApplication.pageName.text = ResourceManager.getInstance().getString('resources', 'takePoll.title'); + + addPollToView(userSession.pollModel.getPoll(id)); + } + + private function addPollToView(poll:Poll):void { + var questions:Array = poll.questions; + + for(var i:int = 0; i < questions.length; i++) { + var question:Question = questions[i]; + addQuestionToView(question.id, question.question, question.multiResponse, question.responses); + } + } + + private function addQuestionToView(questionID:String, questionText:String, multiResponse:Boolean, responses:Array):void { + var qv:QuestionView = new QuestionView(); + + qv.initialize(); + qv.id = questionID; + qv.question.text = questionText; + qv.multiResponse = multiResponse; + + if(multiResponse) { + for(var i:int = 0; i < responses.length; i++) { + qv.responses.addElement(buildCheckBoxFromResponse(responses[i])); + } + } + else { + for(var j:int = 0; j < responses.length; j++) { + qv.responses.addElement(buildRadioButtonFromResponse(responses[j])); + } + } + + questionViewGroup.addElement(qv); + } + + private function buildCheckBoxFromResponse(response:Object):CheckBox { + var checkBox:CheckBox = new CheckBox(); + checkBox.id = response.id; + checkBox.label = response.response; + checkBox.percentWidth = 100; + return checkBox; + } + + private function buildRadioButtonFromResponse(response:Object):RadioButton { + var radioButton:RadioButton = new RadioButton(); + radioButton.id = response.id; + radioButton.label = response.response; + radioButton.percentWidth = 100; + return radioButton; + } + + private function onSubmit(event:MouseEvent):void { + var questionResponseArray:Array = new Array(); + + for(var i:int = 0; i < questionViewGroup.numElements; i++) { + var q:QuestionView = questionViewGroup.getElementAt(i) as QuestionView; + + if(q) { + if(q.multiResponse) { + var cb_responses:Array = getCheckBoxResponses(q.responses); + if(cb_responses.length == 0) { // User did not respond + view.errorMessage.visible = true; + return; + } + questionResponseArray.push(new Responses(q.id, cb_responses)); + } + else { + var rb_responses:Array = getRadioButtonResponses(q.responses); + if(rb_responses.length == 0) { // User did not respond + view.errorMessage.visible = true; + return; + } + questionResponseArray.push(new Responses(q.id, rb_responses)); + } + } + } + + view.submitButton.enabled = false; + pollService.respondPoll(id, questionResponseArray); + userSession.pollModel.userHasResponded(id); + } + + private function getCheckBoxResponses(groupOfCheckBoxes:Group):Array { + var responses:Array = new Array(); + + for(var j:int = 0; j < groupOfCheckBoxes.numElements; j++) { + var cb:CheckBox = groupOfCheckBoxes.getElementAt(j) as CheckBox; + if(cb && cb.selected) { + responses.push(cb.id); + } + } + + return responses; + } + + private function getRadioButtonResponses(groupOfRadioButton:Group):Array { + var responses:Array = new Array(); + + for(var i:int = 0; i < groupOfRadioButton.numElements; i++) { + var rb:RadioButton = groupOfRadioButton.getElementAt(i) as RadioButton; + if(rb && rb.selected) { + responses.push(rb.id); + } + } + + return responses; + } + + private function handlePollModelChanged(change:int, pollID:String):void { + switch(change) { + case PollModel.POLL_DESTROYED: + handlePollDestroyed(pollID); + break; + case PollModel.POLL_STOPPED: + handlePollStopped(pollID); + break; + case PollModel.POLL_UPDATED: + handlePollUpdated(pollID); + break; + case PollModel.I_RESPONDED_TO_POLL: + handleIRespondedToPoll(pollID); + break; + default: + break; + } + } + + private function handlePollDestroyed(pollID:String):void { + if(id == pollID) { + userUISession.popPage(); + } + } + + private function handlePollStopped(pollID:String):void { + if(id == pollID) { + userUISession.popPage(); + } + } + + private function handlePollUpdated(pollID:String):void { + if(id == pollID) { + questionViewGroup.removeAllElements(); + addPollToView(userSession.pollModel.getPoll(pollID)); + } + } + + private function handleIRespondedToPoll(pollID:String):void { + if(id == pollID) { + userUISession.pushPage(PagesENUM.POLL_RESULTS, {id: id}); + } + } + + override public function destroy():void { + super.destroy(); + + userSession.pollModel.pollsChangedSignal.remove(handlePollModelChanged); + view.submitButton.removeEventListener(MouseEvent.CLICK, onSubmit); + + view.dispose(); + view = null; + } + + } +} \ No newline at end of file diff --git a/src/org/bigbluebutton/view/skins/CheckBoxSkin.mxml b/src/org/bigbluebutton/view/skins/CheckBoxSkin.mxml new file mode 100644 index 0000000..2348cdb --- /dev/null +++ b/src/org/bigbluebutton/view/skins/CheckBoxSkin.mxml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/bigbluebutton/view/skins/RadioButtonSkin.mxml b/src/org/bigbluebutton/view/skins/RadioButtonSkin.mxml index bd367fd..e5b0722 100644 --- a/src/org/bigbluebutton/view/skins/RadioButtonSkin.mxml +++ b/src/org/bigbluebutton/view/skins/RadioButtonSkin.mxml @@ -132,8 +132,8 @@ in accordance with the terms of the license agreement accompanying it. + left="{hostComponent.getStyle('width')}" textAlign="left" verticalCenter="2" fontWeight="normal" />