This commit is contained in:
Seth Call 2015-06-15 19:35:59 -05:00
parent c28d8f3e7f
commit a769dd37bf
18 changed files with 229 additions and 38 deletions

View File

@ -94,6 +94,7 @@ gem 'react-rails', '~> 1.0'
source 'https://rails-assets.org' do
gem 'rails-assets-reflux'
gem 'rails-assets-classnames'
end
group :development, :test do

View File

@ -38,6 +38,7 @@
//= require jquery.exists
//= require jquery.payment
//= require jquery.visible
//= require classnames
//= require reflux
//= require howler.core.js
//= require jstz

View File

@ -78,7 +78,7 @@
if (type === 2) { // BACKEND_MIXER_CHANGE
context.MixerActions.mixersChanged(type, text)
context.SessionActions.mixersChanged(type, text)
if(context.JK.CurrentSessionModel)
context.JK.CurrentSessionModel.onBackendMixerChanged(type, text)

View File

@ -479,7 +479,7 @@
}
function deleteParticipant(clientId) {
var url = "/api/participants/" + lientId;
var url = "/api/participants/" + clientId;
return $.ajax({
type: "DELETE",
url: url

View File

@ -2,8 +2,21 @@ context = window
@SessionLeaveBtn = React.createClass({
onLeave: (e) ->
e.preventDefault()
@rateSession()
SessionActions.leaveSession.trigger({location: '/client#/home'})
rateSession: () ->
unless @rateSessionDialog?
@rateSessionDialog = new context.JK.RateSessionDialog(context.JK.app);
@rateSessionDialog.initialize();
@rateSessionDialog.showDialog();
render: () ->
`<a className="session-leave button-grey right leave">
`<a className="session-leave button-grey right leave" onClick={this.onLeave}>
X LEAVE
</a>`
})

View File

@ -29,12 +29,17 @@ MixerActions = @MixerActions
muteMixer = this.state.mixers.muteMixer
vuMixer = this.state.mixers.vuMixer
classes = React.addons.classSet({
classes = classNames({
'track-icon-mute': true
'enabled' : !muteMixer.mute
'muted' : muteMixer.mute
})
panStyle = {
transform: "rotate(#{this.state.mixers.mixer.pan}deg)"
WebkitTransform: "rotate(#{this.state.mixers.mixer.pan}deg)"
}
`<div className="session-track my-track">
<div className="name">{this.props.name}</div>
<div className="track-avatar"><img src={this.props.photoUrl}/></div>
@ -43,7 +48,7 @@ MixerActions = @MixerActions
<SessionTrackVU orientation="horizontal" lightCount={4} lightWidth={17} lightHeight={3} side="vul" mixers={this.state.mixers} />
<div className="track-buttons">
<div className={classes} data-control="mute" data-mixer-id={muteMixer.id} onClick={this.handleMute}/>
<div className="track-icon-pan"/>
<div className="track-icon-pan" style={panStyle}/>
<div className="track-icon-equalizer" />
</div>
<br className="clearall"/>

View File

@ -4,7 +4,7 @@ SessionActions = @SessionActions
@SessionScreen = React.createClass({
mixins: [Reflux.listenTo(@AppStore,"onAppInit")]
mixins: [Reflux.listenTo(@AppStore,"onAppInit"), Reflux.listenTo(@SessionActions.allowLeaveSession, "onAllowLeaveSession")]
render: () ->
`<div className="session-container">
@ -29,8 +29,9 @@ SessionActions = @SessionActions
componentDidMount: () ->
@logger = context.JK.logger
beforeShow: (data) =>
beforeShow: (data) ->
@logger.debug("session beforeShow")
@allowLeave = false
afterShow: (data) ->
@logger.debug("session afterShow")
@ -38,14 +39,30 @@ SessionActions = @SessionActions
SessionActions.joinSession.trigger(data.id)
beforeHide: () ->
@logger.debug("session beforeHide")
context.JK.HelpBubbleHelper.clearJamTrackGuide();
beforeLeave: () ->
@logger.debug("session beforeLeave")
beforeLeave: (data) ->
@logger.debug("session beforeLeave", @allowLeave)
if @allowLeave
return true
else
leaveSessionWarningDialog = new context.JK.LeaveSessionWarningDialog(context.JK.app,
() =>
@allowLeave = true
context.location.hash = data.hash
)
leaveSessionWarningDialog.initialize()
@app.layout.showDialog('leave-session-warning')
return false
beforeDisconnect: () ->
@logger.debug("session beforeDisconnect")
onAllowLeaveSession: () ->
@allowLeave = true
onAppInit: (@app) ->
screenBindings = {

View File

@ -16,11 +16,11 @@ context = window
for i in [0..this.props.lightCount-1]
lightClass = if i >= redSwitch then 'vu-red-off' else 'vu-green-off'
lightClasses = React.addons.classSet('vulight', 'vu' + i, lightClass)
lightClasses = classNames('vulight', 'vu' + i, lightClass)
lights.push(`<td width={this.props.lightWidth} height={this.props.lightHeight} className={lightClasses}></td>`)
lights.push(`<td key={i} width={this.props.lightWidth} height={this.props.lightHeight} className={lightClasses}></td>`)
tableClasses = React.addons.classSet('vu', 'horizontal', this.props.side + '-' + this.state.mixers.mixer.mixerId)
tableClasses = classNames('vu', 'horizontal', this.props.side + '-' + this.state.mixers.mixer.mixerId)
`<table className={tableClasses} data-light-count={this.props.lightCount}>
<tr>
@ -32,11 +32,11 @@ context = window
for i in [0..this.props.lightCount-1].reverse()
lightClass = if (i >= redSwitch) then "vu-red-off" else "vu-green-off"
lightClasses = React.addons.classSet('vulight', 'vu' + i, lightClass)
lightClasses = classNames('vulight', 'vu' + i, lightClass)
lights.push(`<tr><td width={this.props.lightWidth} height={this.props.lightHeight} className={lightClasses}></td></tr>`)
lights.push(`<tr><td key={i} width={this.props.lightWidth} height={this.props.lightHeight} className={lightClasses}></td></tr>`)
tableClasses = React.addons.classSet('vu', 'vertical', this.props.side + '-' + this.state.mixers.mixer.mixerId)
tableClasses = classNames('vu', 'vertical', this.props.side + '-' + this.state.mixers.mixer.mixerId)
`<table className={tableClasses} data-light-count={this.props.lightCount}>
{lights}

View File

@ -32,7 +32,7 @@ MixerActions = @MixerActions
muteMixer = this.state.mixers.muteMixer
classes = React.addons.classSet({
classes = classNames({
'track-icon-mute': true
'enabled' : !muteMixer.mute
'muted' : muteMixer.mute

View File

@ -4,5 +4,5 @@ context = window
joinSession: {}
leaveSession: {}
resyncServer: {asyncResult: true}
myTracksChanged: {}
mixersChanged: {}
})

View File

@ -17,15 +17,12 @@ MIX_MODES = context.JK.MIX_MODES;
@muteBothMasterAndPersonalGroups = [ChannelGroupIds.AudioInputMusicGroup, ChannelGroupIds.MediaTrackGroup,
ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup]
@organize()
updateMixers: (type, text, @masterMixers, @personalMixers) ->
@organize()
if @session.inSession() && text == 'RebuildAudioIoControl'
SessionActions.myTracksChanged.trigger()
@ -62,7 +59,7 @@ MIX_MODES = context.JK.MIX_MODES;
localMediaMixers = @mixersForGroupIds(@mediaTrackGroups, MIX_MODES.MASTER)
peerLocalMediaMixers = @mixersForGroupId(ChannelGroupIds.PeerMediaTrackGroup, MIX_MODES.MASTER)
logger.debug("localMediaMixers", localMediaMixers)
#logger.debug("localMediaMixers", localMediaMixers)
#logger.debug("peerLocalMediaMixers", peerLocalMediaMixers)
# get the server data regarding various media tracks
@ -263,7 +260,7 @@ MIX_MODES = context.JK.MIX_MODES;
else if oppositeMixer.group_id != ChannelGroupIds.AudioInputMusicGroup
logger.error("found local mixer in opposite mode that was not of groupID: AudioInputMusicGroup", mixer, oppositeMixer)
else
logger.debug("local track is not present: ", track, mixer)
logger.debug("local track is not present: ", track, @allMixers)
else
switch @mixMode
when MIX_MODES.MASTER
@ -459,3 +456,6 @@ MIX_MODES = context.JK.MIX_MODES;
context.JK.VuHelpers.updateVU2('vul', mixer, value)
# Do the right
context.JK.VuHelpers.updateVU2('vur', mixer, value)
getTrackInfo: () ->
context.JK.TrackHelpers(context.jamClient, @masterMixers)

View File

@ -13,7 +13,6 @@ MIX_MODES = context.JK.MIX_MODES;
this.listenTo(context.MixerActions.initGain, this.onInitGain)
this.listenTo(context.MixerActions.initPan, this.onInitPan)
this.listenTo(context.MixerActions.panChanged, this.onPanChanged)
this.listenTo(context.MixerActions.mixersChanged, this.onMixersChanged)
context.JK.HandleVolumeChangeCallback2 = @handleVolumeChangeCallback
context.JK.HandleMetronomeCallback2 = @handleMetronomeCallback
@ -104,6 +103,8 @@ MIX_MODES = context.JK.MIX_MODES;
# TODO: grab correct mix mode , line 870 sessionModel.js
@mixers.updateMixers(type, text, masterMixers, personalMixers)
this.trigger({session: @session, mixers: @mixers})
SessionActions.mixersChanged.trigger(type, text, @mixers.getTrackInfo())
this.trigger({session: @session, mixers: @mixers})
}
)

View File

@ -4,6 +4,7 @@ logger = context.JK.logger
rest = context.JK.Rest()
EVENTS = context.JK.EVENTS;
SessionActions = @SessionActions
@SessionStore = Reflux.createStore(
@ -24,27 +25,77 @@ SessionActions = @SessionActions
sessionPageEnterDeferred: null
gearUtils: null
sessionUtils: null
joinDeffered: null
recordingModel: null
currentTrackChanges: 0
init: ->
# Register with the app store to get @app
this.listenTo(context.AppStore, this.onAppInit);
this.listenTo(context.AppStore, this.onAppInit)
onAppInit: (@app) ->
@gearUtils = context.JK.GearUtilsInstance
@sessionUtils = context.JK.SessionUtils
@recordingModel = new context.JK.RecordingModel(@app, this, rest, context.jamClient);
onWatchedInputs: (inputTracks) ->
logger.debug("obtained tracks at start of session")
@sessionPageEnterDeferred.resolve(inputTracks);
@sessionPageEnterDeferred = null
onMixersChanged: (type, text, trackInfo) ->
return unless @inSession()
if text == 'RebuildAudioIoControl'
if @backendMixerAlertThrottleTimer
clearTimeout(@backendMixerAlertThrottleTimer)
@backendMixerAlertThrottleTimer = setTimeout(
() =>
@backendMixerAlertThrottleTimer = null
if @sessionPageEnterDeferred
# this means we are still waiting for the BACKEND_MIXER_CHANGE that indicates we have user tracks built-out/ready
# we will get at least one BACKEND_MIXER_CHANGE that corresponds to the backend doing a 'audio pause', which won't matter much
# so we need to check that we actaully have userTracks before considering ourselves done
if trackInfo.userTracks.length > 0
logger.debug("obtained tracks at start of session")
@sessionPageEnterDeferred.resolve(trackInfo.userTracks);
@sessionPageEnterDeferred = null
return
// wait until we are fully in session before trying to sync tracks to server
if @joinDeferred
@joinDeferred
.done(()=>
@syncTracks()
, 100)
else if @session.inSession() && text == 'RebuildMediaControl'
SessionActions.mediaTracksChanged.trigger(@mixers.getTrackInfo())
else if @session.inSession() && text == 'RebuildRemoteUserControl'
SessionActions.otherTracksChanged.trigger(@mixers.getTrackInfo())
onJoinSession: (sessionId) ->
# initialize webcamViewer
if gon.global.video_available && gon.global.video_available != "none"
webcamViewer.beforeShow()
@webcamViewer.beforeShow()
# double-check that we are connected to the server via websocket
return unless @ensureConnected()
# just make double sure a previous session state is cleared out
@sessionEnded()
# update the session data to be empty
@updateCurrentSession(null)
@ -153,7 +204,7 @@ SessionActions = @SessionActions
# tell the server we want to join
rest.joinSession({
@joinDeferred = rest.joinSession({
client_id: @app.clientId,
ip_address: context.JK.JamServer.publicIP,
as_musician: true,
@ -177,7 +228,7 @@ SessionActions = @SessionActions
else
context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.join);
#recordingModel.reset();
@recordingModel.reset(response.id);
context.jamClient.JoinSession({sessionID: response.id});
@ -417,7 +468,96 @@ SessionActions = @SessionActions
context.JK.JamServer.connected
# called by anyone wanting to leave the session with a certain behavior
onLeaveSession: (behavior) ->
logger.debug("attempting to leave session", behavior)
if behavior.notify
@app.layout.notify(behavior.notify)
SessionActions.allowLeaveSession.trigger()
if behavior.location
if jQuery.isNumeric(behavior.location)
window.history.go(behavior.location)
else
window.location = behavior.location
else
logger.warn("no location specified in leaveSession action", behavior)
window.location = '/client#/home'
if gon.global.video_available && gon.global.video_available != "none"
@webcamViewer.setVideoOff()
@leaveSession()
@sessionUtils.SessionPageLeave()
leaveSession: () ->
if @joinDeferred?.state() == 'resolved'
deferred = new $.Deferred()
@recordingModel.stopRecordingIfNeeded()
.always(()=>
@performLeaveSession(deferred)
)
performLeaveSession: (deferred) ->
logger.debug("SessionModel.leaveCurrentSession()")
# TODO - sessionChanged will be called with currentSession = null\
# leave the session right away without waiting on REST. Why? If you can't contact the server, or if it takes a long
# time, for that entire duration you'll still be sending voice data to the other users.
# this may be bad if someone decides to badmouth others in the left-session during this time
logger.debug("performLeaveSession: calling jamClient.LeaveSession for clientId=" + @app.clientId)
context.jamClient.LeaveSession({ sessionID: @currentSessionId })
@leaveSessionRest(@currentSessionId)
.done(=>
deferred.resolve(arguments[0], arguments[1], arguments[2]))
.fail(=>
deferred.reject(arguments[0], arguments[1], arguments[2]);
)
# 'unregister' for callbacks
context.jamClient.SessionRegisterCallback("");
#context.jamClient.SessionSetAlertCallback("");
context.jamClient.SessionSetConnectionStatusRefreshRate(0);
@sessionEnded()
this.trigger(new context.SessionHelper(@app, @currentSession))
sessionEnded: () ->
# cleanup
context.JK.JamServer.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, @trackChanges);
context.JK.JamServer.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, @trackChanges);
context.JK.JamServer.unregisterMessageCallback(context.JK.MessageType.TRACKS_CHANGED, @trackChanges);
context.JK.JamServer.unregisterMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, @trackChanges);
if @sessionPageEnterDeferred?
@sessionPageEnterDeferred.reject('session_over')
@sessionPageEnterDeferred = null
if @backendMixerAlertThrottleTimer
clearTimeout(@backendMixerAlertThrottleTimer)
@backendMixerAlertThrottleTimer = null
@userTracks = null;
@startTime = null;
if @joinDeffered?.state() == 'resolved'
$(document).trigger(EVENTS.SESSION_ENDED, {session: {id: @currentSessionId}})
@currentTrackChanges = 0
@currentSession = null
@joinDeferred = null
@currentSessionId = null
@currentParticipants = {}
@previousAllTracks = {userTracks: [], backingTracks: [], metronomeTracks: []}
@openBackingTrack = null
@shownAudioMediaMixerHelp = false
@controlsLockedForJamTrackRecording = false;
}
)

View File

@ -18,7 +18,7 @@
context.JK = context.JK || {};
var logger = context.JK.logger;
context.JK.RecordingModel = function(app, sessionModel, _rest, _jamClient) {
context.JK.RecordingModel = function(app, _rest, _jamClient) {
var currentRecording = null; // the JSON response from the server for a recording
var currentOrLastRecordingId = null;
var currentRecordingId = null;
@ -31,7 +31,7 @@
var waitingOnStopTimer = null;
var jamClient = _jamClient;
var sessionModel = sessionModel;
var sessionId = null;
var $self = $(this);
function isRecording (recordingId) {
@ -46,7 +46,7 @@
}
/** called every time a session is joined, to ensure clean state */
function reset() {
function reset(_sessionId) {
currentlyRecording = false;
waitingOnServerStop = false;
waitingOnClientStop = false;
@ -57,6 +57,7 @@
currentRecording = null;
currentRecordingId = null;
stoppingRecording = false;
sessionId = _sessionId
}
@ -84,7 +85,7 @@
currentlyRecording = true;
stoppingRecording = false;
currentRecording = rest.startRecording({"music_session_id": sessionModel.id()})
currentRecording = rest.startRecording({"music_session_id": sessionId})
.done(function(recording) {
currentRecordingId = recording.id;
currentOrLastRecordingId = recording.id;

View File

@ -720,7 +720,7 @@
// we redirect to the session screen, which handles the REST call to POST /participants.
logger.debug("joining session screen: " + sessionId)
context.location = '/client#/session/' + sessionId;
context.location = '/client#/session2/' + sessionId;
};
if (createSessionSettings.createType == '<%= MusicSession::CREATE_TYPE_START_SCHEDULED%>') {

View File

@ -16,12 +16,14 @@
// take all necessary arguments to complete its work.
context.JK.TrackHelpers = {
getTrackInfo: function(jamClient) {
getTrackInfo: function(jamClient, masterTracks) {
var allTracks = context.jamClient.SessionGetAllControlState(true);
if(masterTracks === undefined) {
masterTracks = context.jamClient.SessionGetAllControlState(true);
}
var userTracks = context.JK.TrackHelpers.getUserTracks(jamClient, allTracks);
var backingTracks = context.JK.TrackHelpers.getBackingTracks(jamClient, allTracks);
var userTracks = context.JK.TrackHelpers.getUserTracks(jamClient, masterTracks);
var backingTracks = context.JK.TrackHelpers.getBackingTracks(jamClient, masterTracks);
var metronomeTracks = context.JK.TrackHelpers.getTracks(jamClient, ChannelGroupIds.MetronomeGroup);
return {

View File

@ -22,6 +22,8 @@
var os = null;
var reactHovers = []
context.JK.stringToBool = function (s) {
switch (s.toLowerCase()) {
case "true":
@ -217,6 +219,11 @@
if(!options) options = {};
context._.each(reactHovers, function(react) {
reactHovers.btOff();
})
reactHovers = []
function waitForBubbleHover($bubble) {
$bubble.hoverIntent({
over: function() {
@ -235,6 +242,7 @@
options.trigger = 'none'
options.clickAnywhereToClose = true
options.closeWhenOthersOpen = true
options.preShow = function(container) {
var reactElement = context[reactElementName]
if(!reactElementName) {

View File

@ -301,6 +301,8 @@
background-repeat:no-repeat;
text-align: center;
margin-left:10px;
//-webkit-transform: rotate(7deg); /* Chrome, Safari, Opera */
//transform: rotate(7deg);
}
.track-icon-equalizer {