From b17630379f976554ceae980e556926e07bc4bdca Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Mon, 26 Aug 2013 20:03:15 -0600 Subject: [PATCH 01/13] VRFS-375. VRFS-561. Fix subsequent runs of FTUE and ASIO control panel. --- app/assets/javascripts/ftue.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/javascripts/ftue.js b/app/assets/javascripts/ftue.js index 6ccb0f8ce..da6730878 100644 --- a/app/assets/javascripts/ftue.js +++ b/app/assets/javascripts/ftue.js @@ -76,6 +76,10 @@ function settingsInit() { jamClient.FTUEInit(); setLevels(0); + // Always reset the driver select box to "Choose..." which forces everything + // to sync properly when the user reselects their driver of choice. + // VRFS-375 and VRFS-561 + $('[layout-wizard="ftue"] [layout-wizard-step="2"] .asio-settings .settings-driver select').val(""); } function setLevels(db) { From 991a2b476e34d26cb91c8540d4237551d71d3b35 Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Mon, 26 Aug 2013 20:31:18 -0600 Subject: [PATCH 02/13] VRFS-557. Don't set audio mixer value when receiving a peer volume change event. The back-end will have already done it. Just visually update fader position. --- app/assets/javascripts/session.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/session.js b/app/assets/javascripts/session.js index f33881e68..303906c0a 100644 --- a/app/assets/javascripts/session.js +++ b/app/assets/javascripts/session.js @@ -564,11 +564,12 @@ function handleVolumeChangeCallback(mixerId, isLeft, value) { // Visually update mixer + // There is no need to actually set the back-end mixer value as the + // back-end will already have updated the audio mixer directly prior to sending + // me this event. I simply need to visually show the new fader position. // TODO: Use mixer's range var faderValue = percentFromMixerValue(-80, 20, value); context.JK.FaderHelpers.setFaderValue(mixerId, faderValue); - fillTrackVolumeObject(mixerId, false); // don't broadcast - setMixerVolume(mixerId, faderValue); } function handleBridgeCallback() { From 7cf42587344a239870effa1ad49731c5f5c57363 Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Tue, 27 Aug 2013 21:05:53 -0600 Subject: [PATCH 03/13] VRFS-557. Better VU/Fader connection code on track initialization. --- app/assets/javascripts/session.js | 82 ++++++++++++++++--------------- app/assets/javascripts/utils.js | 6 ++- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/app/assets/javascripts/session.js b/app/assets/javascripts/session.js index 303906c0a..c1842477d 100644 --- a/app/assets/javascripts/session.js +++ b/app/assets/javascripts/session.js @@ -195,8 +195,22 @@ volume_left: context.jamClient.SessionGetMasterLocalMix() }; mixers.push(l2m_mixer); + // Clean all the mixer ids, which means removing curly braces and spaces + //$.each(mixers, function(index, mixer) { + //mixer.id = _cleanMixerId(mixer.id); + //}); } + //function _cleanMixerId(id) { + //var cleaned = String(id); + //if (cleaned) { + //cleaned = cleaned.replace("{", ""); + //cleaned = cleaned.replace("}", ""); + //cleaned = context.JK.trimString(cleaned); + //} + //return cleaned; + //} + // TODO FIXME - This needs to support multiple tracks for an individual // client id and group. function _mixerForClientId(clientId, groupIds) { @@ -364,7 +378,6 @@ ]); if (mixer) { myTrack = (mixer.group_id === ChannelGroupIds.AudioInputMusicGroup); - var gainPercent = percentFromMixerValue( mixer.range_low, mixer.range_high, mixer.volume_left); var muteClass = "enabled"; @@ -412,6 +425,25 @@ }); } + function connectTrackToMixer(trackSelector, clientId, mixerId, gainPercent) { + var vuOpts = $.extend({}, trackVuOpts); + var faderOpts = $.extend({}, trackFaderOpts); + faderOpts.faderId = mixerId; + var vuLeftSelector = trackSelector + " .track-vu-left"; + var vuRightSelector = trackSelector + " .track-vu-right"; + var faderSelector = trackSelector + " .track-gain"; + var $track = $('div.track[client-id="' + clientId + '"]'); + // Set mixer-id attributes and render VU/Fader + context.JK.VuHelpers.renderVU(vuLeftSelector, vuOpts); + $track.find('.track-vu-left').attr('mixer-id', mixerId + '_vul'); + context.JK.VuHelpers.renderVU(vuRightSelector, vuOpts); + $track.find('.track-vu-right').attr('mixer-id', mixerId + '_vur'); + context.JK.FaderHelpers.renderFader(faderSelector, faderOpts); + // Set gain position + context.JK.FaderHelpers.setFaderValue(mixerId, gainPercent); + context.JK.FaderHelpers.subscribe(mixerId, faderChanged); + } + // Function called on an interval when participants change. Mixers seem to // show up later, so we render the tracks from participants, but keep track // of the ones there weren't any mixers for, and continually try to find them @@ -428,32 +460,14 @@ ChannelGroupIds.PeerAudioInputMusicGroup ]); if (mixer) { - var vuOpts = $.extend({}, trackVuOpts); - var faderOpts = $.extend({}, trackFaderOpts); - faderOpts.faderId = mixer.id; - var baseSelector = 'div.track[client-id="' + key + '"]'; - var vuLeftSelector = baseSelector + " .track-vu-left"; - var vuRightSelector = baseSelector + " .track-vu-right"; - var faderSelector = baseSelector + " .track-gain"; - keysToDelete.push(key); var gainPercent = percentFromMixerValue( mixer.range_low, mixer.range_high, mixer.volume_left); + var trackSelector = 'div.track[client-id="' + key + '"]'; + connectTrackToMixer(trackSelector, key, mixer.id, gainPercent); var $track = $('div.track[client-id="' + key + '"]'); - // Set mixer-id attributes and render VU/Fader - context.JK.VuHelpers.renderVU(vuLeftSelector, vuOpts); - $track.find('.track-vu-left').attr('mixer-id', mixer.id + '_vul'); - context.JK.VuHelpers.renderVU(vuRightSelector, vuOpts); - $track.find('.track-vu-right').attr('mixer-id', mixer.id + '_vur'); - context.JK.FaderHelpers.renderFader(faderSelector, faderOpts); - context.JK.FaderHelpers.subscribe(mixer.id, faderChanged); - $track.find('.track-icon-mute').attr('mixer-id', mixer.id); $track.find('.track-icon-settings').attr('mixer-id', mixer.id); - - // Set gain position - context.JK.FaderHelpers.setFaderValue(mixer.id, gainPercent); - // Set mute state _toggleVisualMuteControl($track.find('.track-icon-mute'), mixer.mute); } @@ -513,25 +527,9 @@ $destination.append(newTrack); // Render VU meters and gain fader - // Find the last child (just-appended): - var trackCount = $(parentSelector + ' .session-track').length; - var selectorPrefix = parentSelector + ' .session-track:nth-child(' + String(trackCount) + ')'; - var vuOpts = $.extend({}, trackVuOpts); - var faderOpts = $.extend({}, trackFaderOpts); - faderOpts.faderId = trackData.mixerId; - var vuLeftSelector = selectorPrefix + ' .track-vu-left'; - var vuRightSelector = selectorPrefix + ' .track-vu-right'; - var faderSelector = selectorPrefix + ' .track-gain'; - context.JK.VuHelpers.renderVU(vuLeftSelector, vuOpts); - context.JK.VuHelpers.renderVU(vuRightSelector, vuOpts); - context.JK.FaderHelpers.renderFader(faderSelector, faderOpts); - context.JK.FaderHelpers.subscribe(trackData.mixerId, faderChanged); - // Visually update fader to underlying mixer start value. - if (trackData.gainPercent) { - context.JK.FaderHelpers.setFaderValue(trackData.mixerId, trackData.gainPercent); - } else { - context.JK.FaderHelpers.setFaderValue(trackData.mixerId, 0); - } + var trackSelector = parentSelector + ' .session-track[client-id="' + trackData.clientId + '"]'; + var gainPercent = trackData.gainPercent || 0; + connectTrackToMixer(trackSelector, trackData.clientId, trackData.mixerId, gainPercent); var $closeButton = $('#div-track-close', 'div[track-id="' + trackData.trackId + '"]'); if (index === 0) { @@ -568,6 +566,7 @@ // back-end will already have updated the audio mixer directly prior to sending // me this event. I simply need to visually show the new fader position. // TODO: Use mixer's range + //var _mixerId = _cleanMixerId(mixerId); var faderValue = percentFromMixerValue(-80, 20, value); context.JK.FaderHelpers.setFaderValue(mixerId, faderValue); } @@ -581,6 +580,7 @@ eventName = arguments[3*i]; mixerId = arguments[(3*i)+1]; value = arguments[(3*i)+2]; + //mixerId = _cleanMixerId(mixerId); var vuVal = 0.0; if (eventName === 'left_vu' || eventName === 'right_vu') { // TODO - no guarantee range will be -80 to 20. Get from the @@ -594,6 +594,8 @@ } _updateVU(mixerId, vuVal); } else if (eventName === 'add' || eventName === 'remove') { + //logger.dbg('non-vu event: ' + eventName + ',' + mixerId + ',' + value); + // TODO - _renderSession. Note I get streams of these in // sequence, so have Nat fix, or buffer/spam protect // Note - this is already handled from websocket events. diff --git a/app/assets/javascripts/utils.js b/app/assets/javascripts/utils.js index 783bdecdc..bdb02254d 100644 --- a/app/assets/javascripts/utils.js +++ b/app/assets/javascripts/utils.js @@ -147,12 +147,16 @@ }); } + context.JK.trimString = function(str) { + return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + }; + context.JK.padString = function(str, max) { var retVal = '' + str; while (retVal.length < max) { retVal = '0' + retVal; } - + return retVal; } From b3e7327ae32fcb62acf2133d0143c5411c089557 Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Wed, 28 Aug 2013 18:57:13 -0600 Subject: [PATCH 04/13] Remove unused code. --- app/assets/javascripts/session.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/app/assets/javascripts/session.js b/app/assets/javascripts/session.js index c1842477d..b96ea511c 100644 --- a/app/assets/javascripts/session.js +++ b/app/assets/javascripts/session.js @@ -195,22 +195,8 @@ volume_left: context.jamClient.SessionGetMasterLocalMix() }; mixers.push(l2m_mixer); - // Clean all the mixer ids, which means removing curly braces and spaces - //$.each(mixers, function(index, mixer) { - //mixer.id = _cleanMixerId(mixer.id); - //}); } - //function _cleanMixerId(id) { - //var cleaned = String(id); - //if (cleaned) { - //cleaned = cleaned.replace("{", ""); - //cleaned = cleaned.replace("}", ""); - //cleaned = context.JK.trimString(cleaned); - //} - //return cleaned; - //} - // TODO FIXME - This needs to support multiple tracks for an individual // client id and group. function _mixerForClientId(clientId, groupIds) { @@ -566,7 +552,6 @@ // back-end will already have updated the audio mixer directly prior to sending // me this event. I simply need to visually show the new fader position. // TODO: Use mixer's range - //var _mixerId = _cleanMixerId(mixerId); var faderValue = percentFromMixerValue(-80, 20, value); context.JK.FaderHelpers.setFaderValue(mixerId, faderValue); } @@ -580,7 +565,6 @@ eventName = arguments[3*i]; mixerId = arguments[(3*i)+1]; value = arguments[(3*i)+2]; - //mixerId = _cleanMixerId(mixerId); var vuVal = 0.0; if (eventName === 'left_vu' || eventName === 'right_vu') { // TODO - no guarantee range will be -80 to 20. Get from the From c1d2ed901f07b98d2e664a54d041394c717c8c5f Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 29 Aug 2013 12:14:12 +0000 Subject: [PATCH 05/13] * VRFS-509 - set birthdate and gender on account profile screen --- app/controllers/api_users_controller.rb | 32 ++++++++++----------- app/views/clients/_account_profile.html.erb | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/controllers/api_users_controller.rb b/app/controllers/api_users_controller.rb index 48ec198a3..6671a39b8 100644 --- a/app/controllers/api_users_controller.rb +++ b/app/controllers/api_users_controller.rb @@ -53,22 +53,22 @@ class ApiUsersController < ApiController end def update - @user = User.save(params[:id], - current_user.id, - params[:first_name], - params[:last_name], - nil, # Don't allow changing email here, since updating email is something that must be done through it's own API - nil, # Don't allow changing password here, since we want to prompt again for the old password - nil, - params[:musician], - params[:gender], - params[:birth_date], - params[:internet_service_provider], - params[:city], - params[:state], - params[:country], - params[:instruments].nil? ? [] : params[:instruments], # we have to convert nil to empty []. background: http://stackoverflow.com/questions/14647731/rails-converts-empty-arrays-into-nils-in-params-of-the-request - params[:photo_url]) + + @user = User.find(params[:id]) + + + @user.first_name = params[:first_name] if params.has_key?(:first_name) + @user.last_name = params[:last_name] if params.has_key?(:last_name) + @user.gender = params[:gender] if params.has_key?(:gender) + @user.birth_date = Date.strptime(params[:birth_date], '%m-%d-%Y') if params.has_key?(:birth_date) + @user.city = params[:city] if params.has_key?(:city) + @user.state = params[:state] if params.has_key?(:state) + @user.country = params[:country] if params.has_key?(:country) + @user.update_instruments(params[:instruments].nil? ? [] : params[:instruments]) if params.has_key?(:instruments) + + puts params[:birth_date] + @user.save + puts @user.birth_date.inspect if @user.errors.any? respond_with @user, :status => :unprocessable_entity diff --git a/app/views/clients/_account_profile.html.erb b/app/views/clients/_account_profile.html.erb index fb1ba66fc..bbd0e8be7 100644 --- a/app/views/clients/_account_profile.html.erb +++ b/app/views/clients/_account_profile.html.erb @@ -65,7 +65,7 @@
Gender:
-
+

From cabbd0f59216cd80fe0761595345a5b3a1798a85 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 29 Aug 2013 13:39:08 +0000 Subject: [PATCH 06/13] * fix for broken test in VRFS-509, and adding version info in jam-web footer --- app/controllers/api_users_controller.rb | 1 + app/helpers/meta_helper.rb | 7 +++++++ app/views/clients/index.html.erb | 2 ++ app/views/layouts/corporate.html.erb | 1 + build | 7 +++++++ config/application.rb | 4 ++-- lib/jam_web/version.rb | 3 +++ lib/{managers => }/max_mind_manager.rb | 0 lib/{managers => }/music_session_manager.rb | 0 lib/{managers => }/user_manager.rb | 0 10 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 app/helpers/meta_helper.rb create mode 100644 lib/jam_web/version.rb rename lib/{managers => }/max_mind_manager.rb (100%) rename lib/{managers => }/music_session_manager.rb (100%) rename lib/{managers => }/user_manager.rb (100%) diff --git a/app/controllers/api_users_controller.rb b/app/controllers/api_users_controller.rb index 6671a39b8..a663bcec2 100644 --- a/app/controllers/api_users_controller.rb +++ b/app/controllers/api_users_controller.rb @@ -64,6 +64,7 @@ class ApiUsersController < ApiController @user.city = params[:city] if params.has_key?(:city) @user.state = params[:state] if params.has_key?(:state) @user.country = params[:country] if params.has_key?(:country) + @user.musician = params[:musician] if params.has_key?(:musician) @user.update_instruments(params[:instruments].nil? ? [] : params[:instruments]) if params.has_key?(:instruments) puts params[:birth_date] diff --git a/app/helpers/meta_helper.rb b/app/helpers/meta_helper.rb new file mode 100644 index 000000000..0ba8cb259 --- /dev/null +++ b/app/helpers/meta_helper.rb @@ -0,0 +1,7 @@ +module MetaHelper + + def version() + "web=#{::JamWeb::VERSION} lib=#{JamRuby::VERSION} db=#{JamDb::VERSION} pb=#{Jampb::VERSION}" + end + +end diff --git a/app/views/clients/index.html.erb b/app/views/clients/index.html.erb index e6072909a..dfedf5c5c 100644 --- a/app/views/clients/index.html.erb +++ b/app/views/clients/index.html.erb @@ -173,4 +173,6 @@ }) + + diff --git a/app/views/layouts/corporate.html.erb b/app/views/layouts/corporate.html.erb index ac569b446..b08a8e9ac 100644 --- a/app/views/layouts/corporate.html.erb +++ b/app/views/layouts/corporate.html.erb @@ -46,6 +46,7 @@ +
<%= version %>
diff --git a/build b/build index 5bd909b64..05e12fa06 100755 --- a/build +++ b/build @@ -81,6 +81,13 @@ if [ -n "$PACKAGE" ]; then exit 1 fi + cat > lib/jam_web/version.rb << EOF +module JamWeb + VERSION = "0.1.$BUILD_NUMBER" +end +EOF + + type -P dpkg-architecture > /dev/null diff --git a/config/application.rb b/config/application.rb index 92401bd64..32fc7e7e2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -29,8 +29,8 @@ if defined?(Bundler) # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. - # config.autoload_paths += %W(#{config.root}/extras) - config.autoload_paths += %W(#{config.root}/lib/managers) + config.autoload_paths += %W( + #{config.root}/lib) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. diff --git a/lib/jam_web/version.rb b/lib/jam_web/version.rb new file mode 100644 index 000000000..617fcf3d2 --- /dev/null +++ b/lib/jam_web/version.rb @@ -0,0 +1,3 @@ + module JamWeb + VERSION = "0.0.1" +end \ No newline at end of file diff --git a/lib/managers/max_mind_manager.rb b/lib/max_mind_manager.rb similarity index 100% rename from lib/managers/max_mind_manager.rb rename to lib/max_mind_manager.rb diff --git a/lib/managers/music_session_manager.rb b/lib/music_session_manager.rb similarity index 100% rename from lib/managers/music_session_manager.rb rename to lib/music_session_manager.rb diff --git a/lib/managers/user_manager.rb b/lib/user_manager.rb similarity index 100% rename from lib/managers/user_manager.rb rename to lib/user_manager.rb From 61b24d7c8a81ddfe6a0179aadb7edba4d76bbe6d Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 29 Aug 2013 13:42:25 +0000 Subject: [PATCH 07/13] * removing extra whitespace added in autoload_paths --- config/application.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/application.rb b/config/application.rb index 32fc7e7e2..34127c372 100644 --- a/config/application.rb +++ b/config/application.rb @@ -29,8 +29,7 @@ if defined?(Bundler) # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. - config.autoload_paths += %W( - #{config.root}/lib) + config.autoload_paths += %W(#{config.root}/lib) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. From 742c3276b878eb0764a118ab93f414dc349d4434 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 29 Aug 2013 14:49:23 +0000 Subject: [PATCH 08/13] * VRFS-586 - whitespace issues --- lib/jam_web/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jam_web/version.rb b/lib/jam_web/version.rb index 617fcf3d2..d6efd19ab 100644 --- a/lib/jam_web/version.rb +++ b/lib/jam_web/version.rb @@ -1,3 +1,3 @@ - module JamWeb +module JamWeb VERSION = "0.0.1" end \ No newline at end of file From 80a4a9387dba80d18fe5abd0dfd0a14b44b9b0d5 Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Thu, 29 Aug 2013 20:04:13 -0600 Subject: [PATCH 09/13] VRFS-487. VRFS-517. Updates to first FTUE screen. --- app/assets/javascripts/ftue.js | 22 +++++++++++++++ app/assets/stylesheets/client/ftue.css.scss | 19 +++++++++++-- app/views/clients/_ftue.html.erb | 30 +++++++++++---------- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/ftue.js b/app/assets/javascripts/ftue.js index da6730878..9653e0126 100644 --- a/app/assets/javascripts/ftue.js +++ b/app/assets/javascripts/ftue.js @@ -270,7 +270,29 @@ ftueSave(false); } + function videoLinkClicked(evt) { + var myOS = jamClient.GetOSAsString(); + var link; + if (myOS === 'MacOSX') { + link = $(evt.currentTarget).attr('external-link-mac'); + } else if (myOS === 'Win32') { + link = $(evt.currentTarget).attr('external-link-win'); + } + if (link) { + context.jamClient.OpenSystemBrowser(link); + } + } + function events() { + $('.ftue-video-link').hover( + function(evt) { // handlerIn + $(this).addClass('hover'); + }, + function(evt) { // handlerOut + $(this).removeClass('hover'); + } + ); + $('.ftue-video-link').on('click', videoLinkClicked); $('[layout-wizard-step="2"] .settings-driver select').on('change', audioDriverChanged); $('[layout-wizard-step="2"] .settings-controls select').on('change', audioDeviceChanged); $('#btn-asio-control-panel').on('click', openASIOControlPanel); diff --git a/app/assets/stylesheets/client/ftue.css.scss b/app/assets/stylesheets/client/ftue.css.scss index 7dca409a3..a1cb9228d 100644 --- a/app/assets/stylesheets/client/ftue.css.scss +++ b/app/assets/stylesheets/client/ftue.css.scss @@ -18,12 +18,16 @@ div.dialog.ftue .ftue-inner div[layout-wizard-step="1"] { li { text-align:center; - width: 33%; + width: 31%; + height: 170px; margin:0px; - padding:0px; + /*padding:0px;*/ list-style: none; float:left; } + li.first { + width: 34%; + } } div.dialog.ftue .ftue-inner div[layout-wizard-step="3"] { h5 { @@ -421,3 +425,14 @@ table.audiogeartable { font-size:15px; color:#aaa; } + +.ftue-video-link { + padding:4px; + cursor:pointer; + background-color:#333; + border: 1px solid #333; +} +.ftue-video-link.hover { + background-color:#444; + border: 1px solid #555; +} diff --git a/app/views/clients/_ftue.html.erb b/app/views/clients/_ftue.html.erb index cda116b21..04c288aae 100644 --- a/app/views/clients/_ftue.html.erb +++ b/app/views/clients/_ftue.html.erb @@ -10,35 +10,37 @@

- Please identify which of the three types of audio gear below you are going to use with the JamKazam - service, and click either the Windows or Mac link under the appropriate gear to watch a video on how - to navigate this initial setup and testing process. After watching the video, click the 'NEXT' - button to get started. + Please identify which of the three types of audio gear below you + are going to use with the JamKazam service, and click one to + watch a video on how to navigate this initial setup and testing + process. After watching the video, click the 'NEXT' button to + get started. If you don't have your audio gear handy now, click + Cancel.

    -
  • +
  • -
  • +
  • -
  • +
- + CANCEL  NEXT
From dad7ac669134d581e189dba13e3d4938c11bd71e Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sat, 31 Aug 2013 13:54:11 +0000 Subject: [PATCH 10/13] * VRFS-594; add dialog to initiate reconnect if you lose webocket connection --- app/assets/javascripts/JamServer.js | 3 +- app/assets/javascripts/banner.js | 56 ++++++++ app/assets/javascripts/ftue.js | 22 +++ app/assets/javascripts/jam_rest.js | 10 ++ app/assets/javascripts/session.js | 31 ++-- app/assets/javascripts/sessionModel.js | 135 +++++++++++++----- app/assets/stylesheets/client/banner.css.scss | 8 ++ app/assets/stylesheets/client/client.css | 1 + app/assets/stylesheets/client/ftue.css.scss | 19 ++- app/views/clients/_banner.html.erb | 18 +++ app/views/clients/_ftue.html.erb | 30 ++-- .../clients/banners/_disconnected.html.erb | 42 ++++++ app/views/clients/index.html.erb | 7 + app/views/layouts/landing.erb | 2 + 14 files changed, 327 insertions(+), 57 deletions(-) create mode 100644 app/assets/javascripts/banner.js create mode 100644 app/assets/stylesheets/client/banner.css.scss create mode 100644 app/views/clients/_banner.html.erb create mode 100644 app/views/clients/banners/_disconnected.html.erb diff --git a/app/assets/javascripts/JamServer.js b/app/assets/javascripts/JamServer.js index d635bf7fd..da30e3637 100644 --- a/app/assets/javascripts/JamServer.js +++ b/app/assets/javascripts/JamServer.js @@ -95,7 +95,8 @@ context.jamClient.connected = false; } - // TODO: reconnect + context.JK.CurrentSessionModel.onWebsocketDisconnected(); + }; server.send = function(message) { diff --git a/app/assets/javascripts/banner.js b/app/assets/javascripts/banner.js new file mode 100644 index 000000000..d0aa78aa7 --- /dev/null +++ b/app/assets/javascripts/banner.js @@ -0,0 +1,56 @@ +(function(context,$) { + + "use strict"; + + context.JK = context.JK || {}; + context.JK.Banner = (function() { + var self = this; + var logger = context.JK.logger; + + // responsible for updating the contents of the update dialog + // as well as registering for any event handlers + function show(options) { + var text = options.text; + var html = options.html; + + var newContent = null; + if (html) { + newContent = $('#banner .dialog-inner').html(html); + } + else if(text) { + newContent = $('#banner .dialog-inner').html(text); + } + else { + console.error("unable to show banner for empty message") + return newContent; + } + + $('#banner').show() + $('#banner_overlay').show() + + // return the core of the banner so that caller can attach event handlers to newly created HTML + return newContent; + } + + function hide() { + $('#banner').hide(); + $('#banner_overlay .dialog-inner').html(""); + $('#banner_overlay').hide(); + } + + function initialize() { + + return self; + } + + // Expose publics + var me = { + initialize: initialize, + show : show, + hide : hide + } + + return me; + })(); + +})(window,jQuery); \ No newline at end of file diff --git a/app/assets/javascripts/ftue.js b/app/assets/javascripts/ftue.js index da6730878..9653e0126 100644 --- a/app/assets/javascripts/ftue.js +++ b/app/assets/javascripts/ftue.js @@ -270,7 +270,29 @@ ftueSave(false); } + function videoLinkClicked(evt) { + var myOS = jamClient.GetOSAsString(); + var link; + if (myOS === 'MacOSX') { + link = $(evt.currentTarget).attr('external-link-mac'); + } else if (myOS === 'Win32') { + link = $(evt.currentTarget).attr('external-link-win'); + } + if (link) { + context.jamClient.OpenSystemBrowser(link); + } + } + function events() { + $('.ftue-video-link').hover( + function(evt) { // handlerIn + $(this).addClass('hover'); + }, + function(evt) { // handlerOut + $(this).removeClass('hover'); + } + ); + $('.ftue-video-link').on('click', videoLinkClicked); $('[layout-wizard-step="2"] .settings-driver select').on('change', audioDriverChanged); $('[layout-wizard-step="2"] .settings-controls select').on('change', audioDeviceChanged); $('#btn-asio-control-panel').on('click', openASIOControlPanel); diff --git a/app/assets/javascripts/jam_rest.js b/app/assets/javascripts/jam_rest.js index 8ba454931..3236bd28d 100644 --- a/app/assets/javascripts/jam_rest.js +++ b/app/assets/javascripts/jam_rest.js @@ -144,6 +144,15 @@ }); } + /** check if the server is alive */ + function serverHealthCheck(options) { + return $.ajax({ + url: window.host, + cache: false, + dataType: "html" + }); + } + function getId(options) { var id = options && options["id"] @@ -201,6 +210,7 @@ this.getClientDownloads = getClientDownloads this.createInvitation = createInvitation; this.postFeedback = postFeedback; + this.serverHealthCheck = serverHealthCheck; return this; }; diff --git a/app/assets/javascripts/session.js b/app/assets/javascripts/session.js index b96ea511c..2cd3dcf70 100644 --- a/app/assets/javascripts/session.js +++ b/app/assets/javascripts/session.js @@ -121,22 +121,37 @@ } function afterCurrentUserLoaded() { - sessionModel = new context.JK.SessionModel( + // It seems the SessionModel should be a singleton. + // a client can only be in one session at a time, + // and other parts of the code want to know at any certain times + // about the current session, if any (for example, reconnect logic) + context.JK.CurrentSessionModel = sessionModel = new context.JK.SessionModel( context.JK.JamServer, - context.jamClient, - context.JK.userMe + context.jamClient ); + sessionModel.subscribe('sessionScreen', sessionChanged); - sessionModel.joinSession(sessionId); + sessionModel.joinSession(sessionId) + .fail(function(xhr, textStatus, errorMessage) { + if(xhr.status == 404) { + // we tried to join the session, but it's already gone. kick user back to join session screen + window.location = "#/findSession" + app.notify( + { title: "Unable to Join Session", + text: "The session you attempted to join is over." + }, + { no_cancel: true }); + }else { + app.ajaxError(xhr, textStatus, errorMessage); + } + }) } function beforeHide(data) { // track that the screen is inactive, to disable body-level handlers screenActive = false; - sessionModel.leaveCurrentSession(sessionId); - // 'unregister' for callbacks - context.jamClient.SessionRegisterCallback(""); - context.jamClient.SessionSetAlertCallback(""); + sessionModel.leaveCurrentSession() + .fail(app.ajaxError) } function sessionChanged() { diff --git a/app/assets/javascripts/sessionModel.js b/app/assets/javascripts/sessionModel.js index 6c400ea95..859e645b4 100644 --- a/app/assets/javascripts/sessionModel.js +++ b/app/assets/javascripts/sessionModel.js @@ -7,12 +7,13 @@ context.JK = context.JK || {}; var logger = context.JK.logger; - context.JK.SessionModel = function(server, client, currentUser) { + context.JK.SessionModel = function(server, client) { var clientId = client.clientID; var currentSessionId = null; // Set on join, prior to setting currentSession. var currentSession = null; var subscribers = {}; var users = {}; // User info for session participants + var rest = context.JK.Rest(); function id() { return currentSession.id; @@ -32,24 +33,54 @@ function joinSession(sessionId) { currentSessionId = sessionId; logger.debug("SessionModel.joinSession(" + sessionId + ")"); - joinSessionRest(sessionId, function() { - refreshCurrentSession(); - }); - server.registerMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_JOIN, refreshCurrentSession); - server.registerMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_DEPART, refreshCurrentSession); + var deferred = joinSessionRest(sessionId); + + deferred + .done(function(){ + logger.debug("calling jamClient.JoinSession"); + client.JoinSession({ sessionID: sessionId }); + refreshCurrentSession(); + server.registerMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_JOIN, refreshCurrentSession); + server.registerMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_DEPART, refreshCurrentSession); + }); + + return deferred; } /** - * Leave the current session + * Leave the current session, if there is one. + * callback: called in all conditions; either after an attempt is made to tell the server that we are leaving, + * or immediately if there is no session */ function leaveCurrentSession() { - logger.debug("SessionModel.leaveCurrentSession()"); - // TODO - sessionChanged will be called with currentSession = null - server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_JOIN, refreshCurrentSession); - server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_DEPART, refreshCurrentSession); - leaveSessionRest(currentSessionId, sessionChanged); - currentSession = null; - currentSessionId = null; + var deferred; + + if(currentSessionId) { + logger.debug("SessionModel.leaveCurrentSession()"); + // TODO - sessionChanged will be called with currentSession = null + server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_JOIN, refreshCurrentSession); + server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_DEPART, refreshCurrentSession); + // 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("calling jamClient.LeaveSession for clientId=" + clientId); + client.LeaveSession({ sessionID: currentSessionId }); + deferred = leaveSessionRest(currentSessionId); + deferred.done(function() { + sessionChanged(); + }); + + // 'unregister' for callbacks + context.jamClient.SessionRegisterCallback(""); + context.jamClient.SessionSetAlertCallback(""); + currentSession = null; + currentSessionId = null; + } + else { + deferred = rest.serverHealthCheck(); + } + + return deferred; } /** @@ -268,7 +299,7 @@ * Make the server calls to join the current user to * the session provided. */ - function joinSessionRest(sessionId, callback) { + function joinSessionRest(sessionId) { var tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient); var data = { client_id: clientId, @@ -277,38 +308,77 @@ tracks: tracks }; var url = "/api/sessions/" + sessionId + "/participants"; - $.ajax({ + return $.ajax({ type: "POST", dataType: "json", contentType: 'application/json', url: url, async: false, data: JSON.stringify(data), - processData:false, - success: function(response) { - logger.debug("calling jamClient.JoinSession"); - client.JoinSession({ sessionID: sessionId }); - callback(); - }, - error: ajaxError + processData:false }); } - function leaveSessionRest(sessionId, callback) { + function leaveSessionRest(sessionId) { var url = "/api/participants/" + clientId; - $.ajax({ + return $.ajax({ type: "DELETE", url: url, - async: false, - success: function (response) { - logger.debug("calling jamClient.LeaveSession for clientId=" + clientId); - client.LeaveSession({ sessionID: sessionId }); - callback(); - }, - error: ajaxError + async: false }); } + function reconnect() { + window.location.reload(); + } + function registerReconnect(content) { + $('a.disconnected-reconnect', content).click(function() { + + var template = $('#template-reconnecting').html(); + var templateHtml = context.JK.fillTemplate(template, null); + var content = context.JK.Banner.show({ + html : template + }); + + context.JK.CurrentSessionModel.leaveCurrentSession() + .done(function() { + reconnect(); + }) + .fail(function(xhr, textStatus, errorThrown) { + console.log("leaveCurrentSession failed: ", arguments); + + if(xhr && xhr.status >= 100) { + // we could connect to the server, and it's alive + reconnect(); + } + else { + var template = $('#template-could-not-reconnect').html(); + var templateHtml = context.JK.fillTemplate(template, null); + var content = context.JK.Banner.show({ + html : template + }); + + registerReconnect(content); + } + }); + + }); + } + + function onWebsocketDisconnected() { + var template = $('#template-disconnected').html(); + var templateHtml = context.JK.fillTemplate(template, null); + var content = context.JK.Banner.show({ + html : template + }) ; + + // kill the streaming of the session immediately + logger.debug("calling jamClient.LeaveSession for clientId=" + clientId); + client.LeaveSession({ sessionID: currentSessionId }); + + registerReconnect(content); + } + function ajaxError(jqXHR, textStatus, errorMessage) { logger.error("Unexpected ajax error: " + textStatus); } @@ -324,6 +394,7 @@ this.addTrack = addTrack; this.updateTrack = updateTrack; this.deleteTrack = deleteTrack; + this.onWebsocketDisconnected = onWebsocketDisconnected; this.getCurrentSession = function() { return currentSession; }; diff --git a/app/assets/stylesheets/client/banner.css.scss b/app/assets/stylesheets/client/banner.css.scss new file mode 100644 index 000000000..e3b8de209 --- /dev/null +++ b/app/assets/stylesheets/client/banner.css.scss @@ -0,0 +1,8 @@ +#banner { + display:none; +} + +#banner h2 { + font-weight:bold; + font-size:x-large; +} \ No newline at end of file diff --git a/app/assets/stylesheets/client/client.css b/app/assets/stylesheets/client/client.css index 08784199b..7fb658934 100644 --- a/app/assets/stylesheets/client/client.css +++ b/app/assets/stylesheets/client/client.css @@ -30,6 +30,7 @@ *= require ./genreSelector *= require ./sessionList *= require ./searchResults + *= require ./banner *= require ./clientUpdate *= require jquery.Jcrop */ \ No newline at end of file diff --git a/app/assets/stylesheets/client/ftue.css.scss b/app/assets/stylesheets/client/ftue.css.scss index 7dca409a3..a1cb9228d 100644 --- a/app/assets/stylesheets/client/ftue.css.scss +++ b/app/assets/stylesheets/client/ftue.css.scss @@ -18,12 +18,16 @@ div.dialog.ftue .ftue-inner div[layout-wizard-step="1"] { li { text-align:center; - width: 33%; + width: 31%; + height: 170px; margin:0px; - padding:0px; + /*padding:0px;*/ list-style: none; float:left; } + li.first { + width: 34%; + } } div.dialog.ftue .ftue-inner div[layout-wizard-step="3"] { h5 { @@ -421,3 +425,14 @@ table.audiogeartable { font-size:15px; color:#aaa; } + +.ftue-video-link { + padding:4px; + cursor:pointer; + background-color:#333; + border: 1px solid #333; +} +.ftue-video-link.hover { + background-color:#444; + border: 1px solid #555; +} diff --git a/app/views/clients/_banner.html.erb b/app/views/clients/_banner.html.erb new file mode 100644 index 000000000..9a932e3a9 --- /dev/null +++ b/app/views/clients/_banner.html.erb @@ -0,0 +1,18 @@ + + + + \ No newline at end of file diff --git a/app/views/clients/_ftue.html.erb b/app/views/clients/_ftue.html.erb index cda116b21..04c288aae 100644 --- a/app/views/clients/_ftue.html.erb +++ b/app/views/clients/_ftue.html.erb @@ -10,35 +10,37 @@

- Please identify which of the three types of audio gear below you are going to use with the JamKazam - service, and click either the Windows or Mac link under the appropriate gear to watch a video on how - to navigate this initial setup and testing process. After watching the video, click the 'NEXT' - button to get started. + Please identify which of the three types of audio gear below you + are going to use with the JamKazam service, and click one to + watch a video on how to navigate this initial setup and testing + process. After watching the video, click the 'NEXT' button to + get started. If you don't have your audio gear handy now, click + Cancel.

    -
  • +
  • -
  • +
  • -
  • +
- + CANCEL  NEXT
diff --git a/app/views/clients/banners/_disconnected.html.erb b/app/views/clients/banners/_disconnected.html.erb new file mode 100644 index 000000000..4a5b341be --- /dev/null +++ b/app/views/clients/banners/_disconnected.html.erb @@ -0,0 +1,42 @@ + + + + + \ No newline at end of file diff --git a/app/views/clients/index.html.erb b/app/views/clients/index.html.erb index dfedf5c5c..d2f129f30 100644 --- a/app/views/clients/index.html.erb +++ b/app/views/clients/index.html.erb @@ -29,6 +29,8 @@ <%= render "account_audio_profile" %> <%= render "notify" %> <%= render "client_update" %> +<%= render "banner" %> +<%= render "clients/banners/disconnected" %> <%= render "overlay_small" %>