This commit is contained in:
Brian Smith 2013-01-13 20:47:25 -05:00
commit 7d208517aa
18 changed files with 295 additions and 106 deletions

View File

@ -1,18 +1,17 @@
/**
* The First-Time User Experience (FTUE) Screen to be shown
* to users who have not set up their audio hardware yet.
* Corresponds to the route #/ftue3
* FtueAudioSelectionScreen
* Javascript that goes with the screen where initial
* selection of the audio devices takes place.
* Corresponds to /#ftue2
*/
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.FTUEScreen = function(app) {
context.JK.FtueAudioSelectionScreen = function(app) {
var logger = context.JK.logger;
var jamClient = context.jamClient;
var playbackTestRunning = false;
var recordingTestRunning = false;
function beforeShow(data) {
loadDevices();
@ -24,6 +23,7 @@
function loadDevices() {
$('#choose-input-audio-device select').empty();
$('#choose-output-audio-device select').empty();
$('#choose-input-voice-device select').empty();
var optionTemplate = $('#template_audio_device_item').html();
var devices = context.jamClient.GetASIODevices();
var inputOptions = [];
@ -60,6 +60,7 @@
}
$('#choose-input-audio-device select').html(inputOptions.join(''));
$('#choose-output-audio-device select').html(outputOptions.join(''));
$('#choose-input-voice-device select').html(inputOptions.join(''));
}
/**
@ -89,45 +90,6 @@
$('#latency-testing p').html("Done.");
}
function playbackButtonHandler(evt) {
if (playbackTestRunning) {
$('#playback-testing p').html('Test stopped by user');
$('#playbackTestingButton').html('Start Playback Test');
playbackTestRunning = false;
context.jamClient.StopPlayTest();
} else {
$('#playback-testing p').html('Playback test in progress... Click the button below when things start to sound crappy');
$('#playbackTestingButton').html('Click when things sound bad...');
playbackTestRunning = true;
context.jamClient.StartPlayTest('JK.playbackTestComplete');
}
}
function playbackTestComplete() {
logger.debug('playbackTestComplete. Arguments:');
logger.debug(arguments);
$('#playback-testing p').html('Done');
$('#playbackTestingButton').html('Start Playback Test');
playbackTestRunning = false;
}
function recordingButtonHandler(evt) {
if (recordingTestRunning) {
$('#recording-testing p').html('Recording complete.');
$('#recordingTestingButton').html('Start Recording Test');
recordingTestRunning = false;
context.jamClient.RecordTestEnd();
} else {
$('#recording-testing p').html('Recording in progress... Click the button below to stop recording');
$('#recordingTestingButton').html('Stop Recording');
recordingTestRunning = true;
context.jamClient.RecordTestBegin();
}
}
function recordingPlaybackButtonHandler(evt) {
context.jamClient.RecordTestPlayback();
}
function events() {
$('#enableDevices').click(function() {
@ -135,15 +97,12 @@
testLatency();
});
$('#playbackTestingButton').click(playbackButtonHandler);
$('#recordingTestingButton').click(recordingButtonHandler);
$('#recordingTestPlaybackButton').click(recordingPlaybackButtonHandler);
}
function initialize() {
events();
var screenBindings = { 'beforeShow': beforeShow, 'afterShow': afterShow };
app.bindScreen('ftue3', screenBindings);
app.bindScreen('ftue2', screenBindings);
}
// Expose publics
@ -151,7 +110,6 @@
// Expose callbacks for the bridge on the global namespace
context.JK.latencyTestingComplete = latencyTestingComplete;
context.JK.playbackTestComplete = playbackTestComplete;
return this;
};

View File

@ -0,0 +1,98 @@
/**
* FtueAudioTestingScreen
* Javascript that goes with the screen where
* testing of selected audio devices happens.
* Corresponds to /#ftue3
*/
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.FtueAudioTestingScreen = function(app) {
var logger = context.JK.logger;
var jamClient = context.jamClient;
var selectors = {
step1: 'div[layout-id="ftue3"] div[data-step="step1"]',
step2: 'div[layout-id="ftue3"] div[data-step="step2"]',
step3: 'div[layout-id="ftue3"] div[data-step="step3"]',
good: 'div[layout-id="ftue3"] div[data-step="good"]',
bad: 'div[layout-id="ftue3"] div[data-step="bad"]',
progress1: '#recordingTestProgress1',
progress1Int: '#___recordingTestProgress1___',
progress2: '#recordingTestProgress2',
progress2Int: '#___recordingTestProgress2___'
};
function beforeShow(data) {
$(selectors.step1).show();
$(selectors.step2).hide();
$(selectors.step3).hide();
$(selectors.good).hide();
$(selectors.bad).hide();
}
function afterShow(data) {}
function runProgressBar(selector, seconds, doneFunction) {
var id = "___" + selector.substr(1) + "___";
$(selector).html('<div id="' + id + '" class="progressFull"></div>');
$("#" + id).animate({
width: "400px"
}, seconds * 1000, doneFunction);
}
function startTestButtonHandler(evt) {
$(selectors.step1).hide();
$(selectors.step3).hide();
$(selectors.good).hide();
$(selectors.bad).hide();
$(selectors.step2).show();
runProgressBar(selectors.progress1, 10, good);
context.jamClient.RecordTestBegin();
}
function poorAudioButtonHandler(evt) {
$(selectors.progress1Int).stop();
$(selectors.step2).hide();
$(selectors.step3).show();
runProgressBar(selectors.progress2, 10, bad);
//context.jamClient.RecordTestBegin();
}
function goodAudioButtonHandler(evt) {
good();
}
function good() {
$(selectors.step2).hide();
$(selectors.step3).hide();
$(selectors.good).show();
}
function bad() {
$(selectors.step3).hide();
$(selectors.bad).show();
}
function events() {
$('.startTestButton').click(startTestButtonHandler);
$('#poorAudioButton').click(poorAudioButtonHandler);
$('#goodAudioButton').click(goodAudioButtonHandler);
}
function initialize() {
events();
var screenBindings = { 'beforeShow': beforeShow, 'afterShow': afterShow };
app.bindScreen('ftue3', screenBindings);
}
// Expose publics
this.initialize = initialize;
//context.JK.playbackTestComplete = playbackTestComplete;
return this;
};
})(window,jQuery);

View File

@ -0,0 +1,42 @@
/* Custom Styles for the FTUE Screens */
@import "client/common.css.scss";
@charset "UTF-8";
div[layout-id="ftue2"] {
.formrow {
position:relative;
clear:both;
border:none;
margin: 12px;
padding:4px;
}
label {
text-align:left;
}
select {
display:block;
position:absolute;
left: 140px;
top: 0px;
}
}
div[layout-id="ftue3"] {
button {
margin: 0px 2em;
}
.progressContainer {
margin: 2em;
border: 1px solid #fff;
width: 400px;
height: 10px;
}
.progressFull {
height: 10px;
width: 2px;
background-color:#0f0;
}
}

View File

@ -21,9 +21,12 @@ body {
font-weight: 300;
}
b { font-weight: bold; }
a {
cursor:pointer;
color: $ColorLink;
text-decoration: none;
}
a:hover {
@ -258,4 +261,4 @@ input[type="text"] {
.right {
float:right;
}
}

View File

@ -8,6 +8,7 @@
.screen.secondary {
border: 1px solid $ColorScreenPrimary;
background-color:$ColorScreenBackground;
.footer button {
margin:1em 0em 1em 1em;
}
@ -139,4 +140,4 @@ textarea {
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
box-shadow: inset 2px 2px 3px 0px #888;
color:#333;
}
}

View File

@ -52,7 +52,7 @@ class UsersController < ApplicationController
end
def signup_confirm
@user = UserManager.new.signup_confirm(params[:signup_token])
@user = UserManager.new.signup_confirm(params[:signup_token], request.remote_ip)
unless @user.nil? || @user.errors.any?
sign_in @user

View File

@ -1,10 +1,17 @@
<!-- First time user experience screen 1 -->
<div layout="screen" layout-id="ftue1" class="screen secondary">
<div class="content-head">
<h1>Welcome to JamKazam!</h1>
<h1>Audio Gear Setup</h1>
<%= render "screen_navigation" %>
</div>
<p>You'll need appropriate audio gear. Here are some links to where you can buy some.</p>
<p>Make sure your audio gear is plugged in, then <a href="#/ftue2">CONTINUE</a>.</p>
<p>If you already have audio gear to get your instrumental or vocal music into your computer, please set up your gear and instrument now. Then click the Next button below. For Windows this will be ASIO-compatible audio devices, and Mac gear will use Core Audio. We strongly recommend using headphones with your gear vs. speakers or powered monitors to avoid feedback problems. If you don't already have this gear handy or are not sure what will work, please use the help links below for some guidance:</p>
<ul>
<li><a href="#"><b>Microphones</b></a> (for vocals and/or acoustic instruments like piano, drums, or sax)</li>
<li><a href="#"><b>Electric lead or bass guitar only</b></a> (no vocals, just the guitar)</li>
<li><a href="#"><b>Electric/digital instruments with or without vocals</b></a> (for guitars, keyboards, etc.)</li>
</ul>
<div class="buttonrow">
<p><a href="#/ftue2"><button>Next</button></a></p>
</div>
</div>

View File

@ -1,10 +1,42 @@
<!-- First time user experience screen 1 -->
<div layout="screen" layout-id="ftue2" class="screen secondary">
<div class="content-head">
<h1>Welcome to JamKazam!</h1>
<h1>Audio Gear Settings</h1>
<%= render "screen_navigation" %>
</div>
<p>Next we'll show you how to hook up a cable for a loopback test, so we can test your latency.</p>
<p>Once your cables are all connected, then <a href="#/ftue3">CONTINUE</a>.</p>
<p>Please choose the audio gear you want to use for audio input, chat input, and audio output below. Then play and either sing or speak to ensure that you can hear both your instrument and voice through your headphones. After verifying that you hear your music and voice properly, please click the Next button below. If you don't hear things correctly, please press the Help button below for troubleshooting guidance.</p>
<div id="choose-devices">
<div class="formrow">
<label id="choose-input-audio-device">Audio Input
<select>
</select>
</label>
</div>
<div class="formrow">
<label id="choose-output-audio-device">Audio Output
<select>
</select>
</label>
</div>
<div class="formrow">
<label id="choose-input-voice-device">Voice Chat Input
<select>
</select>
</label>
</div>
</div>
<div class="buttonrow">
<p>
<a href="#/ftue1"><button>Back</button></a>
<a href="#/ftue3"><button>Next</button></a>
<a href="#"><button>Help</button></a>
</p>
</div>
</div>
<script id="template_audio_device_item" type="text/template">
<option value="{value}">{label}</option>
</script>

View File

@ -1,45 +1,44 @@
<!-- First time user experience screen 1 -->
<div layout="screen" layout-id="ftue3" class="screen secondary">
<div class="content-head">
<h1>Welcome to JamKazam!</h1>
<h1>Audio Gear Test</h1>
<%= render "screen_navigation" %>
</div>
<div id="choose-devices">
<h2>Step 1: Choose Devices</h2>
<label id="choose-input-audio-device">Select input
<select>
</select>
</label>
<label id="choose-output-audio-device">Select output
<select>
</select>
</label>
<button id="enableDevices">Enable Selected and Test Latency</button>
<div data-step="step1">
<p>We will now test your audio gear to ensure it works and to find its ideal settings. When you are ready, please click the Start Test button below, and be ready to start playing your instrument or singing.</p>
<button class="startTestButton">Start Test</button>
</div>
<div id="latency-testing">
<h2>Latency Testing</h2>
<p></p>
<div data-step="step2" style="display:none;">
<p>Please play your instrument and/or sing, and listen to the audio. If the quality of the audio becomes poor, please click the Poor Audio button below. This test will last about 45 seconds.</p>
<button id="poorAudioButton">Poor Audio</button>
<div id="recordingTestProgress1" class="progressContainer"></div>
</div>
<div id="playback-testing">
<h2>Playback Testing</h2>
<p>Click the button below to start a playback test. We'll start with safe settings, and then lower the values for better latency. When things begin to sound bad, click the button again.</p>
<button id="playbackTestingButton">Start Playback Test</button>
<div data-step="step3" style="display:none;">
<p>Please press the Good Audio button when the audio quality improves to an acceptable level.</p>
<button id="goodAudioButton">Good Audio</button>
<div id="recordingTestProgress2" class="progressContainer"></div>
</div>
<div id="recording-testing">
<h2>Recording Testing</h2>
<p>When ready, click the button below to enable recording of your audio input. When done, click the button again, and use the other button for playback to see how things sound.</p>
<button id="recordingTestingButton">Start Recording Test</button>
<button id="recordingTestPlaybackButton">Playback Recorded Audio</button>
<div data-step="good" style="display:none;">
<p>Congratulations! Your audio gear is now ready to use, and you may create or join sessions with other musicians in JamKazam.</p>
<a cucumber-id="ftue-home-link" href="#/home"><button>Finish</button></a>
</div>
<p>If everything looks good, then <a cucumber-id="ftue-home-link" href="#/home">WE'RE DONE</a>.</p>
<div data-step="bad" style="display:none;">
<p>We're sorry, but it appears you are not happy with the quality of your audio, so we cannot recommend that you use JamKazam with this audio gear.</p>
<button class="startTestButton">Restart Test</button>
<button>Help</button>
</div>
<div class="buttonrow">
<p>
<a href="#/ftue2"><button>Back</button></a>
<a href="#"><button>Help</button></a>
</p>
</div>
</div>
<script type="text/template" id="template_audio_device_item">
<option value="{value}">{label}</option>
</script>

View File

@ -72,13 +72,15 @@
var sessionScreen = new JK.SessionScreen(jk);
sessionScreen.initialize();
var ftueScreen = new JK.FTUEScreen(jk);
ftueScreen.initialize();
var ftueAudioSelectionScreen = new JK.FtueAudioSelectionScreen(jk);
ftueAudioSelectionScreen.initialize();
var ftueAudioTestingScreen = new JK.FtueAudioTestingScreen(jk);
ftueAudioTestingScreen.initialize();
var testBridgeScreen = new JK.TestBridgeScreen(jk);
testBridgeScreen.initialize();
} else {
var landing = new JK.LandingPage(jk);
landing.initialize();

View File

@ -18,6 +18,7 @@
<%= stylesheet_link_tag "client/findSession", media: "all" %>
<%= stylesheet_link_tag "client/session", media: "all" %>
<%= stylesheet_link_tag "client/search", media: "all" %>
<%= stylesheet_link_tag "client/ftue", media: "all" %>
<%= stylesheet_link_tag "client/lato", media: "all" %>
<%= stylesheet_link_tag "client/createSession", media: "all" %>
<%= include_gon %>

18
build
View File

@ -48,14 +48,16 @@ if [ -z $SKIP_TESTS ]; then
exit 1
fi
echo "running cucumber tests"
DISPLAY=":99" bundle exec cucumber
if [ "$?" = "0" ]; then
echo "success: cucumber tests completed"
else
echo "running cucumber tests failed"
exit 1
fi
if [ -z "$SKIP_CUCUMBER_TESTS" ]; then
echo "running cucumber tests"
DISPLAY=":99" bundle exec cucumber
if [ "$?" = "0" ]; then
echo "success: cucumber tests completed"
else
echo "running cucumber tests failed"
exit 1
fi
fi
fi
if [ -n "$PACKAGE" ]; then

View File

@ -9,4 +9,5 @@ if Rails.env == "development" && Rails.application.config.bootstrap_dev_users
User.create_dev_user("David", "Wilson", "david@jamkazam.com", "jam123", "Austin", "TX", "US", nil, nil)
User.create_dev_user("Nat", "Meo", "nat@jamkazam.com", "jam123", "Raleigh", "Virginia", "US", nil, nil)
User.create_dev_user("Jonathon", "Wilson", "jonathon@jamkazam.com", "jam123", "Denver", "Colorado", "US", nil, nil)
end
User.create_dev_user("Jonathan", "Kolyer", "jonathan@jamkazam.com", "jam123", "San Francisco", "CA", "US", nil, nil)
end

View File

@ -14,11 +14,11 @@ When /^I create a public music session$/ do
sleep 1
page.find("a[href='#/ftue3']").click
sleep 1
page.find('div[data-step="step1"] button.startTestButton').click
page.find("#poorAudioButton").click
page.find("#goodAudioButton").click
page.find("[cucumber-id='ftue-home-link']").click
sleep 1
page.find("[layout-link='createSession']").click
sleep 1
# pick a genre, any genre
page.find("input[value='african']").click
@ -45,6 +45,12 @@ Then /^I should be in a music session that another musician can find$/ do
sleep 1
@second_session.find("a[href='#/ftue3']").click
sleep 1
@second_session.find('div[data-step="step1"] button.startTestButton').click
sleep 1
@second_session.find("#poorAudioButton").click
sleep 1
@second_session.find("#goodAudioButton").click
sleep 1
@second_session.find("[cucumber-id='ftue-home-link']").click
sleep 1

View File

@ -2,10 +2,12 @@ require 'active_record'
require 'action_mailer'
require 'jam_db'
require 'jam_ruby'
require 'capybara'
require 'selenium/webdriver'
require File.expand_path('../../../spec/spec_db', __FILE__)
include JamRuby
# put this in a class, so that multiple loads of this file
# don't cause the database to be recreated multiple times
class BeforeCucumber
@ -18,4 +20,33 @@ class BeforeCucumber
ActionMailer::Base.delivery_method = :test
end
end
end
if ENV['SHOW_JS_ERRORS'] == "1"
# we need a firefox extension to start intercepting javascript errors before the page
# scripts load
Capybara.register_driver :selenium do |app|
profile = Selenium::WebDriver::Firefox::Profile.new
# see https://github.com/mguillem/JSErrorCollector
profile.add_extension File.join(Rails.root, "features/support/extensions/JSErrorCollector.xpi")
Capybara::Selenium::Driver.new app, :profile => profile
end
After do |scenario|
if page.driver.to_s.match("Selenium")
errors = page.execute_script("return window.JSErrorCollector_errors.pump()")
if errors.any?
puts '-------------------------------------------------------------'
puts "Found #{errors.length} javascript errors"
puts '-------------------------------------------------------------'
errors.each do |error|
puts " #{error["errorMessage"]} (#{error["sourceName"]}:#{error["lineNumber"]})"
end
# raise "Javascript error detected, see above"
end
end
end
end

Binary file not shown.

View File

@ -2,6 +2,11 @@ module LoginHelper
def login(user, context)
context.visit root_path
# When troubleshooting JS errors, sleeping when the UI first comes up is helpful.
# It allows you to bring up a JS console on the test browser and see what the problem is.
# sleep 60
# verify that the root page is showing
context.should have_content "Welcome to JamKazam"
@ -20,4 +25,4 @@ module LoginHelper
end
end
World(LoginHelper)
World(LoginHelper)

View File

@ -33,9 +33,10 @@ class UserManager < BaseManager
#end
end
def signup_confirm(signup_token)
def signup_confirm(signup_token, remote_ip=nil)
begin
@user = User.signup_confirm(signup_token)
@user.location = MaxMindManager.lookup(remote_ip) if remote_ip
rescue ActiveRecord::RecordNotFound
@user = nil
end