* VRFS-1754 - new configure tracks dialog

This commit is contained in:
Seth Call 2014-06-08 22:26:50 -05:00
parent 60c72f29dd
commit 653b03bea1
25 changed files with 1363 additions and 606 deletions

View File

@ -4,9 +4,12 @@
context.JK = context.JK || {};
context.JK.AccountAudioProfile = function (app) {
var self = this;
var EVENTS = context.JK.EVENTS;
var gearUtils = context.JK.GearUtils;
var logger = context.JK.logger;
var rest = context.JK.Rest();
var self = this;
var userId;
function beforeShow(data) {
@ -35,28 +38,26 @@
}
function populateAccountAudio() {
var all = context.jamClient.FTUEGetAllAudioConfigurations();
var good = context.jamClient.FTUEGetGoodAudioConfigurations();
var current = context.jamClient.FTUEGetMusicProfileName();
var profiles = gearUtils.getProfiles();
var profiles = [];
context._.each(all, function(item) {
profiles.push({id: item, good: false, class:'bad', current: current == item, active_text: current == item ? '(active)' : ''})
context._.each(profiles, function(profile) {
profile.active_text = profile.current ? '(active)' : '';
});
if(good) {
for(var i = 0; i < good.length; i++) {
for(var j = 0; j < profiles.length; j++) {
if(good[i] == profiles[j].id) {
profiles[j].good = true;
profiles[j].class = 'good';
break;
}
}
// If you are in the FTUE, and you close the client and/or it crashes
// then you will have 'FTUE' (incomplete) profiles. This is the only time
// the user might see them, so we clean them before they get to see it
var cleansedProfiles = [];
context._.each(profiles, function(profile) {
if(profile.id.indexOf('FTUE') == 0) {
context.jamClient.TrackDeleteProfile(profile.id);
}
}
else {
cleansedProfiles.push(profile)
}
});
var template = context._.template($('#template-account-audio').html(), {is_admin: context.JK.currentUserAdmin, profiles: profiles}, {variable: 'data'});
var template = context._.template($('#template-account-audio').html(), {is_admin: context.JK.currentUserAdmin, profiles: cleansedProfiles}, {variable: 'data'});
appendAudio(template);
}
@ -86,11 +87,34 @@
logger.error("unable to activate audio configuration: " + audioProfileId);
context.JK.alertSupportedNeeded("Unable to activate audio configuration for profile named: " + audioProfileId);
}
else {
// redraw after activation of profile
populateAccountAudio();
}
}
app.layout.showDialog('loopback-wizard');
}
function handleConfigureAudioProfile(audioProfileId) {
if(audioProfileId != context.jamClient.FTUEGetMusicProfileName()) {
var result = context.jamClient.FTUELoadAudioConfiguration(audioProfileId);
if(!result) {
logger.error("unable to activate audio configuration: " + audioProfileId);
context.JK.alertSupportedNeeded("Unable to activate audio configuration for profile named: " + audioProfileId);
}
else {
// redraw after activation of profile
populateAccountAudio();
}
}
app.layout.showDialog('configure-tracks')
.one(EVENTS.DIALOG_CLOSED, populateAccountAudio)
}
function handleActivateAudioProfile(audioProfileId) {
logger.debug("activating audio profile: " + audioProfileId);
@ -171,6 +195,20 @@
return false;
});
$root.on('click', 'a[data-purpose=configure-audio-profile]', function (evt) {
evt.stopPropagation();
var $btn = $(this);
var status = $btn.closest('tr').attr('data-status');
if(status == "good") {
handleConfigureAudioProfile($btn.attr('data-id'));
}
else {
context.JK.Banner.showAlert("Unable to configure this profile. Please verify that the devices associated are connected.");
}
return false;
});
$root.on('click', 'a[data-purpose=add-profile]', function (evt) {
evt.stopPropagation();
handleStartAudioQualification();

View File

@ -11,7 +11,7 @@
sessionScreen.setPromptLeave(false);
app.layout.closeDialog('configure-audio');
app.layout.closeDialog('configure-tracks');
context.location = "/client#/home";

View File

@ -7,13 +7,24 @@
var logger = context.JK.logger;
var ASSIGNMENT = context.JK.ASSIGNMENT;
var VOICE_CHAT = context.JK.VOICE_CHAT;
var gearUtils = context.JK.GearUtils;
var $dialog = null;
var $instructions = null;
var $musicAudioTab = null;
var $musicAudioTabSelector = null;
var $voiceChatTab = null;
var $voiceChatTabSelector = null;
var $certifiedAudioProfile = null;
var $btnCancel = null;
var $btnAddNewGear = null;
var $btnUpdateTrackSettings = null;
var configureTracksHelper = null;
var voiceChatHelper = null;
var profiles = null;
var currentProfile = null;
var $dialog = null;
var $instructions = null;
var $musicAudioTab = null;
var $musicAudioTabSelector = null;
var $voiceChatTab = null;
var $voiceChatTabSelector = null;
var configure_audio_instructions = {
"Win32": "Choose the audio device you would like to use for this session. If needed, use arrow buttons to assign audio inputs " +
@ -38,6 +49,8 @@
function setInstructions(type) {
if (type === 'audio') {
$instructions.html('Choose your audio device. Drag and drop to assign input ports to tracks, and specify the instrument for each track. Drag and drop to assign a pair of output ports for session stereo audio monitoring.')
return;
var os = context.jamClient.GetOSAsString();
$instructions.html(configure_audio_instructions[os]);
}
@ -67,17 +80,16 @@
}
function validateVoiceChatSettings() {
return true;
return voiceChatHelper.trySave();
}
function showMusicAudioPanel() {
setInstructions('audio');
activateTab('audio');
}
function validateAudioSettings() {
return true;
return configureTracksHelper.trySave();
}
function showVoiceChatPanel() {
@ -88,21 +100,92 @@
function events() {
$musicAudioTabSelector.click(function () {
// validate voice chat settings
if (validateVoiceChatSettings(true)) {
showMusicAudioPanel(false);
if (validateVoiceChatSettings()) {
configureTracksHelper.reset();
voiceChatHelper.reset();
showMusicAudioPanel();
}
});
$voiceChatTabSelector.click(function () {
// validate audio settings
if (validateAudioSettings(true)) {
showVoiceChatPanel(false);
if (validateAudioSettings()) {
configureTracksHelper.reset();
voiceChatHelper.reset();
showVoiceChatPanel();
}
});
$btnCancel.click(function() {
app.layout.closeDialog('configure-tracks')
return false;
});
$btnAddNewGear.click(function() {
return false;
});
$btnUpdateTrackSettings.click(function() {
if(configureTracksHelper.trySave() && voiceChatHelper.trySave()) {
app.layout.closeDialog('configure-tracks');
}
return false;
});
$certifiedAudioProfile.change(deviceChanged);
}
function renderCertifiedGearDropdown() {
var optionsHtml = '';
context._.each(profiles, function (profile) {
if(profile.good) {
optionsHtml += '<option title="' + profile.id + '" value="' + profile.id + '"' + (profile.current ? 'selected="selected"' : '') + '>' + profile.id + '</option>';
}
});
$certifiedAudioProfile.html(optionsHtml);
context.JK.dropdown($certifiedAudioProfile);
}
function deviceChanged() {
var profile = $certifiedAudioProfile.val();
if(currentProfile == profile) {
return; // just bail early, because the easydropdown fires change events even when you select the same value
}
logger.debug("activating audio profile: " + profile);
var result = context.jamClient.FTUELoadAudioConfiguration(profile);
if(!result) {
logger.error("unable to activate audio configuration: " + profile);
context.JK.alertSupportedNeeded("Unable to activate audio configuration for profile named: " + profile);
renderCertifiedGearDropdown(); // force the dropdown to be reflective of the actually active profile
}
else {
configureTracksHelper.reset();
}
}
function beforeShow() {
profiles = gearUtils.getProfiles();
renderCertifiedGearDropdown();
showMusicAudioPanel();
currentProfile = context.jamClient.FTUEGetMusicProfileName();
if(currentProfile != $certifiedAudioProfile.val()) {
logger.error("the currently active profile (" + currentProfile + ") is not the same as the Certified Audio Gear dropdown (" + $certifiedAudioProfile.val() + ")");
context.JK.alertSupportedNeeded("Unable to determine the current profile.");
}
configureTracksHelper.reset();
voiceChatHelper.reset();
}
function afterHide() {
@ -124,6 +207,17 @@
$musicAudioTabSelector = $dialog.find('.tab-configure-audio');
$voiceChatTab = $dialog.find('div[tab-id="voice-chat"]');
$voiceChatTabSelector = $dialog.find('.tab-configure-voice');
$certifiedAudioProfile = $dialog.find('.certified-audio-profile');
$btnCancel = $dialog.find('.btn-cancel');
$btnAddNewGear = $dialog.find('.btn-add-new-audio-gear');
$btnUpdateTrackSettings = $dialog.find('.btn-update-settings');
configureTracksHelper = new JK.ConfigureTracksHelper(app);
configureTracksHelper.initialize($dialog);
voiceChatHelper = new JK.VoiceChatHelper(app);
voiceChatHelper.initialize($dialog, false);
events();
}

View File

@ -0,0 +1,422 @@
(function (context, $) {
"use strict";
context.JK = context.JK || {};
context.JK.ConfigureTracksHelper = function (app) {
var logger = context.JK.logger;
var ASSIGNMENT = context.JK.ASSIGNMENT;
var VOICE_CHAT = context.JK.VOICE_CHAT;
var MAX_TRACKS = context.JK.MAX_TRACKS;
var MAX_OUTPUTS = context.JK.MAX_OUTPUTS;
var gearUtils = context.JK.GearUtils;
var $parent = null;
var $templateAssignablePort = null;
var $templateTrackTarget = null;
var $templateOutputTarget = null;
var $unassignedInputsHolder = null;
var $unassignedOutputsHolder = null;
var $tracksHolder = null;
var $outputChannelHolder = null;
var $instrumentsHolder = null;
function loadChannels() {
var musicPorts = jamClient.FTUEGetChannels();
$unassignedInputsHolder.empty();
$unassignedOutputsHolder.empty();
$tracksHolder.find('.ftue-input').remove();
$outputChannelHolder.find('.ftue-input').remove();
var inputChannels = musicPorts.inputs;
var outputChannels = musicPorts.outputs;
context._.each(inputChannels, function (inputChannel) {
var $channel = $(context._.template($templateAssignablePort.html(), inputChannel, { variable: 'data' }));
if(inputChannel.assignment == ASSIGNMENT.UNASSIGNED) {
unassignInputChannel($channel);
}
else if(inputChannel.assignment == ASSIGNMENT.CHAT) {
// well, we can't show it as unused... if there were a place to show chat inputs, we would put it there.
// but we don't have it, so just skip
logger.debug("skipping channel ", inputChannel)
return;
}
else {
// find the track this belongs in
var trackNumber = inputChannel.assignment - 1;
var $track = $tracksHolder.find('.track[data-num="' + trackNumber + '"]')
if($track.length == 0) {
context.JK.alertSupportedNeeded('Unable to find a track for channel with assignment ' + inputChannel.assignment);
return false;
}
addChannelToTrack($channel, $track.find('.track-target'));
}
$channel.draggable({
helper: 'clone',
start: function() {
var $channel = $(this);
var $track = $channel.closest('.track-target');
var isUnassigned = $track.length == 0;
if(isUnassigned) {
$tracksHolder.find('.track-target').addClass('possible-target');
}
else {
$tracksHolder.find('.track-target').addClass('possible-target');
$unassignedInputsHolder.addClass('possible-target');
}
},
stop: function() {
$tracksHolder.find('.track-target').removeClass('possible-target');
$unassignedInputsHolder.removeClass('possible-target')
}
});
})
var outputAssignment = 0;
context._.each(outputChannels, function (outputChannel, index) {
var $channel = $(context._.template($templateAssignablePort.html(), outputChannel, { variable: 'data' }));
if(outputChannel.assignment == ASSIGNMENT.UNASSIGNED) {
unassignOutputChannel($channel);
}
else {
var $output = $outputChannelHolder.find('.output[data-num="' + index + '"]')
if($output.length == 0) {
context.JK.alertSupportedNeeded('Unable to find an output for channel with assignment ' + outputChannel.assignment);
return false;
}
addChannelToOutput($channel, $output.find('.output-target'));
}
$channel.draggable({
helper: 'clone',
start: function() {
var $channel = $(this);
var $output = $channel.closest('.output-target');
var isUnassigned = $output.length == 0;
if(isUnassigned) {
$outputChannelHolder.find('.output-target').addClass('possible-target');
}
else {
$outputChannelHolder.find('.output-target').addClass('possible-target');
$unassignedOutputsHolder.addClass('possible-target');
}
},
stop: function() {
$outputChannelHolder.find('.output-target').removeClass('possible-target');
$unassignedOutputsHolder.removeClass('possible-target')
}
});
});
}
// iterates through the dom and returns a pure data structure for track associations and output channels
function getCurrentState() {
var state = {};
state.tracks = [];
state.unassignedChannels = [];
state.outputs = [];
var $unassignedInputChannels = $unassignedInputsHolder.find('.ftue-input');
var $unassignedOutputChannels = $unassignedOutputsHolder.find('.ftue-input');
var $tracks = $tracksHolder.find('.track-target');
var $outputs = $outputChannelHolder.find('.output-target');
context._.each($unassignedInputChannels, function($unassignedInput) {
$unassignedInput = $($unassignedInput);
var channelId = $unassignedInput.attr('data-input-id');
state.unassignedChannels.push(channelId);
})
context._.each($unassignedOutputChannels, function($unassignedOutput) {
$unassignedOutput = $($unassignedOutput);
var channelId = $unassignedOutput.attr('data-input-id');
state.unassignedChannels.push(channelId);
})
context._.each($tracks, function($track, index) {
$track = $($track);
var $assignedChannels = $track.find('.ftue-input');
var track = {index: index, channels:[]};
context._.each($assignedChannels, function($assignedChannel) {
$assignedChannel = $($assignedChannel);
track.channels.push($assignedChannel.attr('data-input-id'))
});
// sparse array
if(track.channels.length > 0) {
state.tracks.push(track);
}
var $instrument = $instrumentsHolder.find('[data-num="' + index + '"]').find('.icon-instrument-select');
track.instrument_id = $instrument.data('instrument_id');
})
context._.each($outputs, function($output, index) {
$output = $($output);
var $assignedChannel = $output.find('.ftue-input');
// this is overkill since there should only be 1 or 0 .ftue-inputs in a given .output
var outputSlot = {index: index, channels:[]};
context._.each($assignedChannel, function($assignedChannel) {
$assignedChannel = $($assignedChannel);
outputSlot.channels.push($assignedChannel.attr('data-input-id'))
});
// sparse array
if(outputSlot.channels.length > 0) {
state.outputs.push(outputSlot);
}
})
return state;
}
function validate(tracks) {
// there must be at least one assigned channel
if(tracks.tracks.length == 0) {
logger.debug("ConfigureTracks validation error: must have assigned at least one input port to a track.");
context.JK.Banner.showAlert('Must have assigned at least one input port to a track.');
return false;
}
// there must be some instruments
context._.each(tracks.tracks, function(track) {
if(!track.instrument_id) {
logger.debug("ConfigureTracks validation error: all tracks with ports assigned must specify an instrument.");
context.JK.Banner.showAlert('All tracks with ports assigned must specify an instrument.');
return false;
}
});
// there must be exactly 2 output channels assigned
if(tracks.outputs.length != 2 || (tracks.outputs[0].channels.length != 1 && track.outputs[1].channels.length != 1)) {
logger.debug("ConfigureTracks validation error: must have assigned exactly two output ports");
context.JK.Banner.showAlert('Must have assigned exactly 2 output ports.');
return false;
}
return true;
}
function save(state) {
context._.each(state.unassignedChannels, function(unassignedChannelId) {
context.jamClient.TrackSetAssignment(unassignedChannelId, true, ASSIGNMENT.UNASSIGNED);
});
// save input/tracks
context._.each(state.tracks, function(track, index) {
var trackNumber = index + 1;
context._.each(track.channels, function(channelId) {
context.jamClient.TrackSetAssignment(channelId, true, trackNumber);
});
logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", trackNumber, track.instrument_id);
context.jamClient.TrackSetInstrument(trackNumber, context.JK.instrument_id_to_instrument[track.instrument_id].client_id);
});
// save outputs
context._.each(state.outputs, function(output, index) {
context._.each(output.channels, function(channelId) {
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.OUTPUT);
});
});
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
return true;
}
else {
context.JK.Banner.showAlert('Unable to save assignments. ' + result);
return false;
}
}
function loadTrackInstruments() {
var $trackInstruments = $instrumentsHolder.find('.track-instrument');
context._.each($trackInstruments, function(trackInstrument) {
var $trackInstrument = $(trackInstrument);
var trackIndex = parseInt($trackInstrument.attr('data-num')) + 1;
var clientInstrument = context.jamClient.TrackGetInstrument(trackIndex);
var instrument = context.JK.client_to_server_instrument_map[clientInstrument];
$trackInstrument.instrumentSelectorSet(instrument ? instrument.server_id : instrument);
});
}
function trySave() {
var state = getCurrentState();
if(!validate(state)) {
return false;
}
var saved = save(state);
if(saved) {
context.JK.GA.trackConfigureTracksCompletion(context.JK.detectOS());
}
return saved;
}
function reset() {
loadChannels();
loadTrackInstruments();
}
function unassignOutputChannel($channel) {
var $originallyAssignedTrack = $channel.closest('.output-target');
$unassignedOutputsHolder.append($channel);
$originallyAssignedTrack.attr('output-count', $originallyAssignedTrack.find('.ftue-input:not(.ui-draggable-dragging)').length);
}
function unassignInputChannel($channel) {
var $originallyAssignedTrack = $channel.closest('.track-target');
$unassignedInputsHolder.append($channel);
$originallyAssignedTrack.attr('track-count', $originallyAssignedTrack.find('.ftue-input:not(.ui-draggable-dragging)').length);
}
function addChannelToTrack($channel, $track) {
var $originallyAssignedTrack = $channel.closest('.track-target');
$track.append($channel);
$track.attr('track-count', $track.find('.ftue-input:not(.ui-draggable-dragging)').length);
$originallyAssignedTrack.attr('track-count', $originallyAssignedTrack.find('.ftue-input:not(.ui-draggable-dragging)').length)
}
function addChannelToOutput($channel, $slot) {
var $originallyAssignedTrack = $channel.closest('.output-target');
$slot.append($channel);
$slot.attr('output-count', $slot.find('.ftue-input:not(.ui-draggable-dragging)').length);
$originallyAssignedTrack.attr('output-count', $originallyAssignedTrack.find('.ftue-input:not(.ui-draggable-dragging)').length)
}
function initializeUnassignedOutputDroppable() {
$unassignedOutputsHolder.droppable(
{
activeClass: 'drag-in-progress',
hoverClass: 'drag-hovering',
drop: function( event, ui ) {
var $channel = ui.draggable;
//$channel.css('left', '0').css('top', '0');
unassignOutputChannel($channel);
}
});
}
function initializeUnassignedInputDroppable() {
$unassignedInputsHolder.droppable(
{
activeClass: 'drag-in-progress',
hoverClass: 'drag-hovering',
drop: function( event, ui ) {
var $channel = ui.draggable;
//$channel.css('left', '0').css('top', '0');
unassignInputChannel($channel);
}
});
}
function initializeOutputDroppables() {
var i;
for(i = 0; i < MAX_OUTPUTS; i++) {
var $target = $(context._.template($templateOutputTarget.html(), {num: i }, { variable: 'data' }));
$outputChannelHolder.append($target);
$target.find('.output-target').droppable(
{
activeClass: 'drag-in-progress',
hoverClass: 'drag-hovering',
drop: function( event, ui ) {
var $slot = $(this);
if($slot.attr('output-count') == 1) {
return false; // max of 1 output per slot
}
var $channel = ui.draggable;
//$channel.css('left', '0').css('top', '0');
addChannelToOutput($channel, $slot);
}
});
}
}
function initializeTrackDroppables() {
var i;
for(i = 0; i < MAX_TRACKS; i++) {
var $target = $(context._.template($templateTrackTarget.html(), {num: i }, { variable: 'data' }));
$tracksHolder.append($target);
$target.find('.track-target').droppable(
{
activeClass: 'drag-in-progress',
hoverClass: 'drag-hovering',
drop: function( event, ui ) {
var $track = $(this);
if($track.attr('track-count') == 2) {
return false; // max of 2 inputs per track
}
var $channel = ui.draggable;
//$channel.css('left', '0').css('top', '0');
addChannelToTrack($channel, $track);
}
});
}
}
function initializeInstrumentDropdown() {
var i;
for(i = 0; i < MAX_TRACKS; i++) {
var $root = $('<div class="track-instrument"></div>');
$root.instrumentSelector().attr('data-num', i);
$instrumentsHolder.append($root);
}
}
function initialize(_$parent) {
$parent = _$parent;
$templateAssignablePort = $('#template-assignable-port');
$templateTrackTarget = $('#template-track-target');
$templateOutputTarget = $('#template-output-target');
$unassignedInputsHolder = $parent.find('.unassigned-input-channels')
$unassignedOutputsHolder = $parent.find('.unassigned-output-channels');
$tracksHolder = $parent.find('.tracks');
$instrumentsHolder = $parent.find('.instruments');
$outputChannelHolder = $parent.find('.output-channels');
initializeUnassignedInputDroppable();
initializeTrackDroppables();
initializeInstrumentDropdown();
initializeUnassignedOutputDroppable();
initializeOutputDroppables();
}
this.initialize = initialize;
this.trySave = trySave;
this.reset = reset;
return this;
};
})(window, jQuery);

View File

@ -235,21 +235,25 @@
}
function FTUEGetGoodConfigurationList() {
return ['a'];
return ['default'];
}
function FTUEGetAllAudioConfigurations() {
return ['a'];
return ['default'];
}
function FTUEGetGoodAudioConfigurations() {
return ['a'];
return ['default'];
}
function FTUEGetConfigurationDevice() {
return 'Good Device';
}
function FTUELoadAudioConfiguration() {
return true;
}
function FTUEIsMusicDeviceWDM() {
return false;
}
@ -850,6 +854,7 @@
this.FTUEGetGoodAudioConfigurations = FTUEGetGoodAudioConfigurations;
this.FTUEGetConfigurationDevice = FTUEGetConfigurationDevice;
this.FTUEIsMusicDeviceWDM = FTUEIsMusicDeviceWDM;
this.FTUELoadAudioConfiguration = FTUELoadAudioConfiguration;
// Session
this.SessionAddTrack = SessionAddTrack;

View File

@ -27,7 +27,12 @@
CHAT: "1"
};
context.JK.EVENTS = {
DIALOG_CLOSED : 'dialog_closed'
}
context.JK.MAX_TRACKS = 6;
context.JK.MAX_OUTPUTS = 2;
// TODO: store these client_id values in instruments table, or store
// server_id as the client_id to prevent maintenance nightmares. As it's

View File

@ -27,6 +27,7 @@
// privates
var logger = context.JK.logger;
var EVENTS = context.JK.EVENTS;
var NOT_HANDLED = "not handled";
var me = null; // Reference to this instance for context sanity.
@ -433,8 +434,9 @@
var $overlay = $('.dialog-overlay');
unstackDialogs($overlay);
$dialog.hide();
$dialog.triggerHandler(EVENTS.DIALOG_CLOSED, {name: dialog, dialogCount: openDialogs.length});
$(context).triggerHandler(EVENTS.DIALOG_CLOSED, {name: dialog, dialogCount: openDialogs.length})
dialogEvent(dialog, 'afterHide');
$(me).triggerHandler('dialog_closed', {dialogCount: openDialogs.length})
}
function screenEvent(screen, evtName, data) {
@ -538,6 +540,11 @@
*/
layout();
// add an attribute to any dialogs, which let's it know it's current screen (useful for contextual styling)
context._.each(openDialogs, function(dialog) {
addScreenContextToDialog($(dialog));
})
screenEvent(previousScreen, 'afterHide', data);
screenEvent(currentScreen, 'afterShow', data);
@ -631,6 +638,10 @@
}
}
function addScreenContextToDialog($dialog) {
$dialog.attr('current-screen', currentScreen); // useful for contextual styling of dialogs
}
function showDialog(dialog, options) {
if (dialogEvent(dialog, 'beforeShow', options) === false) {
return;
@ -649,8 +660,10 @@
centerDialog(dialog);
var $dialog = $('[layout-id="' + dialog + '"]');
stackDialogs($dialog, $overlay);
addScreenContextToDialog($dialog)
$dialog.show();
dialogEvent(dialog, 'afterShow', options);
return $dialog;
}
function centerDialog(dialog) {
@ -903,7 +916,7 @@
}
this.showDialog = function (dialog, options) {
showDialog(dialog, options);
return showDialog(dialog, options);
};
this.dialogObscuredNotification = function(payload) {
@ -926,6 +939,9 @@
return activeElementEvent(evtName, data);
}
this.getCurrentScreen = function() {
return currentScreen; // will be a string of the layout-id of the active screen
}
this.close = function (evt) {
close(evt);
};

View File

@ -4,6 +4,7 @@
context.JK = context.JK || {};
context.JK.NotificationPanel = function(app) {
var EVENTS = context.JK.EVENTS;
var logger = context.JK.logger;
var friends = [];
var rest = context.JK.Rest();
@ -138,7 +139,7 @@
}
function events() {
$(app.layout).on('dialog_closed', function(e, data) {if(data.dialogCount == 0) userCameBack(); });
$(context).on(EVENTS.DIALOG_CLOSED, function(e, data) {if(data.dialogCount == 0) userCameBack(); });
$(window).focus(userCameBack);
$(window).blur(windowBlurred);
app.user()

View File

@ -142,6 +142,15 @@
$element.data("prodTimer", null);
$element.btOff();
}, options['duration']));
$element.on('remove', function() {
var timer = $element.data('prodTimer')
if(timer) {
clearTimeout(timer);
$element.data("prodTimer", null);
$element.btOff();
}
})
}
/**
* Associates a bubble on hover (by default) with the specified $element, using jquery.bt.js (BeautyTips)

View File

@ -0,0 +1,222 @@
(function (context, $) {
"use strict";
context.JK = context.JK || {};
context.JK.VoiceChatHelper = function (app) {
var logger = context.JK.logger;
var ASSIGNMENT = context.JK.ASSIGNMENT;
var VOICE_CHAT = context.JK.VOICE_CHAT;
var MAX_TRACKS = context.JK.MAX_TRACKS;
var MAX_OUTPUTS = context.JK.MAX_OUTPUTS;
var gearUtils = context.JK.GearUtils;
var $parent = null;
var $reuseAudioInputRadio = null;
var $useChatInputRadio = null;
var $chatInputs = null;
var $templateChatInput = null;
var $selectedChatInput = null;// should only be used if isChatEnabled = true
var saveImmediate = null; // if true, then every action by the user results in a save to the backend immediately, false means you have to call trySave to persist
function defaultReuse() {
$reuseAudioInputRadio.iCheck('check').attr('checked', 'checked');
$useChatInputRadio.removeAttr('checked');
}
function isChatEnabled() {
return $useChatInputRadio.is(':checked');
}
function reset() {
$selectedChatInput = null;
if(context.jamClient.TrackGetChatEnable()) {
enableChat(false);
}
else {
disableChat(false);
}
$chatInputs.empty();
var chatInputs = gearUtils.getChatInputs();
context._.each(chatInputs, function(chatInput) {
if(chatInput.assignment > 0) {
return;
}
var chatChannelName = chatInput.name;
var chatChannelId = chatInput.id;
var isCurrentlyChat = chatInput.assignment == ASSIGNMENT.CHAT;
var $chat = $(context._.template($templateChatInput.html(), {id: chatChannelId, name: chatChannelName}, { variable: 'data' }));
var $chatInput = $chat.find('input');
if(isCurrentlyChat) {
$selectedChatInput = $chatInput;
$selectedChatInput.attr('checked', 'checked');
}
$chat.hide(); // we'll show it once it's styled with iCheck
$chatInputs.append($chat);
});
var $radioButtons = $chatInputs.find('input[name="chat-device"]');
context.JK.checkbox($radioButtons).on('ifChecked', function(e) {
var $input = $(e.currentTarget);
$selectedChatInput = $input; // for use in handleNext
if(saveImmediate) {
var channelId = $input.attr('data-channel-id');
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.CHAT);
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
}
else {
context.JK.Banner.showAlert('Unable to save assignments. ' + result);
return false;
}
}
});
if(!isChatEnabled()) {
$radioButtons.iCheck('disable');
}
$chatInputs.find('.chat-input').show().on('click', function() {
if(!isChatEnabled()) {
context.JK.prodBubble($parent.find('.use-chat-input h3'), 'chat-not-enabled', {}, { positions:['left']});
}
})
}
function disableChat(applyToBackend) {
if(saveImmediate && applyToBackend) {
logger.debug("voiceChatHelper: disabling chat to backend");
context.jamClient.TrackSetChatEnable(false);
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
$reuseAudioInputRadio.iCheck('check').attr('checked', 'checked');
$useChatInputRadio.removeAttr('checked');
}
else {
context.JK.Banner.showAlert('Unable to disable chat. ' + result);
return false;
}
}
else {
logger.debug("voiceChatHelper: disabling chat UI only");
$reuseAudioInputRadio.iCheck('check').attr('checked', 'checked');
$useChatInputRadio.removeAttr('checked');
}
var $radioButtons = $chatInputs.find('input[name="chat-device"]');
$radioButtons.iCheck('disable');
}
function enableChat(applyToBackend) {
if(saveImmediate && applyToBackend) {
logger.debug("voiceChatHelper: enabling chat to backend");
context.jamClient.TrackSetChatEnable(true);
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
$useChatInputRadio.iCheck('check').attr('checked', 'checked');
$reuseAudioInputRadio.removeAttr('checked');
}
else {
context.JK.Banner.showAlert('Unable to enable chat. ' + result);
return false;
}
}
else {
logger.debug("voiceChatHelper: enabling chat UI only");
$useChatInputRadio.iCheck('check').attr('checked', 'checked');
$reuseAudioInputRadio.removeAttr('checked');
}
var $radioButtons = $chatInputs.find('input[name="chat-device"]');
$radioButtons.iCheck('enable');
}
function handleChatEnabledToggle() {
context.JK.checkbox($reuseAudioInputRadio);
context.JK.checkbox($useChatInputRadio);
// plugin sets to relative on the element; have to do this as an override
$reuseAudioInputRadio.closest('.iradio_minimal').css('position', 'absolute');
$useChatInputRadio.closest('.iradio_minimal').css('position', 'absolute');
$reuseAudioInputRadio.on('ifChecked', function() { disableChat(true) });
$useChatInputRadio.on('ifChecked', function() { enableChat(true) });
}
// gets the state of the UI
function getCurrentState() {
var state = {
enabled:null,
chat_channel:null
};
state.enabled = $useChatInputRadio.is(':checked');
state.chat_channel = $selectedChatInput && $selectedChatInput.attr('data-channel-id');
logger.debug("desired chat state: enabled=" + state.enabled + ", chat_channel=" + state.chat_channel)
return state;
}
function trySave() {
var state = getCurrentState();
if(state.enabled && state.chat_channel) {
logger.debug("enabling chat. chat_channel=" + state.chat_channel);
context.jamClient.TrackSetChatEnable(true);
context.jamClient.FTUESetChatInput(state.chat_channel);
//context.jamClient.TrackSetAssignment(state.chat_channel, true, ASSIGNMENT.CHAT);
}
else {
logger.debug("disabling chat.");
context.jamClient.TrackSetChatEnable(false);
if(state.chat_channel) {
context.jamClient.TrackSetAssignment(state.chat_channel, true, ASSIGNMENT.UNASSIGNED);
}
}
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
return true;
}
else {
context.JK.Banner.showAlert('Unable to save chat assignments. ' + result);
return false;
}
}
function initialize(_$step, _saveImmediate) {
$parent = _$step;
saveImmediate = _saveImmediate;
$reuseAudioInputRadio = $parent.find('.reuse-audio-input input');
$useChatInputRadio = $parent.find('.use-chat-input input');
$chatInputs = $parent.find('.chat-inputs');
$templateChatInput = $('#template-chat-input');
handleChatEnabledToggle();
}
this.reset = reset;
this.trySave = trySave;
this.initialize = initialize;
return this;
};
})(window, jQuery);

View File

@ -10,175 +10,13 @@
var MAX_TRACKS = context.JK.MAX_TRACKS;
var logger = context.JK.logger;
var configureTracksHelper = new context.JK.ConfigureTracksHelper(app);
var $step = null;
var $templateAssignablePort = null;
var $templateTrackTarget = null;
var $unassignedChannelsHolder = null;
var $tracksHolder = null;
var $instrumentsHolder = null;
function loadChannels() {
var musicPorts = jamClient.FTUEGetChannels();
$unassignedChannelsHolder.empty();
$tracksHolder.find('.ftue-input').remove();
var inputChannels = musicPorts.inputs;
context._.each(inputChannels, function (inputChannel) {
if(inputChannel.assignment == ASSIGNMENT.UNASSIGNED) {
var $channel = $(context._.template($templateAssignablePort.html(), inputChannel, { variable: 'data' }));
unassignChannel($channel);
}
else {
var $channel = $(context._.template($templateAssignablePort.html(), inputChannel, { variable: 'data' }));
// find the track this belongs in
var trackNumber = inputChannel.assignment - 1;
var $track = $tracksHolder.find('.track[data-num="' + trackNumber + '"]')
if($track.length == 0) {
context.JK.alertSupportedNeeded('Unable to find a track for channel with assignment ' + inputChannel.assignment);
return false;
}
addChannelToTrack($channel, $track.find('.track-target'));
}
$channel.draggable({
helper: 'clone',
start: function() {
var $channel = $(this);
var $track = $channel.closest('.track-target');
var isUnassigned = $track.length == 0;
if(isUnassigned) {
$tracksHolder.find('.track-target').addClass('possible-target');
}
else {
$tracksHolder.find('.track-target').addClass('possible-target');
$unassignedChannelsHolder.addClass('possible-target');
}
},
stop: function() {
$tracksHolder.find('.track-target').removeClass('possible-target');
$unassignedChannelsHolder.removeClass('possible-target')
}
});
})
}
// iterates through the dom and returns a pure data structure for track associations
function trackAssociations() {
var tracks = {};
tracks.tracks = [];
tracks.unassignedChannels = [];
var $unassignedChannels = $unassignedChannelsHolder.find('.ftue-input');
var $tracks = $tracksHolder.find('.track-target');
context._.each($unassignedChannels, function($unassignedTrack) {
$unassignedTrack = $($unassignedTrack);
var channelId = $unassignedTrack.attr('data-input-id');
tracks.unassignedChannels.push(channelId);
})
context._.each($tracks, function($track, index) {
$track = $($track);
var $assignedChannels = $track.find('.ftue-input');
var track = {index: index, channels:[]};
context._.each($assignedChannels, function($assignedChannel) {
$assignedChannel = $($assignedChannel);
track.channels.push($assignedChannel.attr('data-input-id'))
});
// sparse array
if(track.channels.length > 0) {
tracks.tracks.push(track);
}
var $instrument = $instrumentsHolder.find('[data-num="' + index + '"]').find('.icon-instrument-select');
track.instrument_id = $instrument.data('instrument_id');
})
return tracks;
}
function validate(tracks) {
// there must be at least one assigned channel
if(tracks.tracks.length == 0) {
logger.debug("ConfigureTracks validation error: must have assigned at least one input port to a track.");
context.JK.Banner.showAlert('Must have assigned at least one input port to a track.');
return false;
}
context._.each(tracks.tracks, function(track) {
if(!track.instrument_id) {
logger.debug("ConfigureTracks validation error: all tracks with ports assigned must specify an instrument.");
context.JK.Banner.showAlert('All tracks with ports assigned must specify an instrument.');
return false;
}
});
return true;
}
function save(tracks) {
context._.each(tracks.unassignedChannels, function(unassignedChannelId) {
context.jamClient.TrackSetAssignment(unassignedChannelId, true, ASSIGNMENT.UNASSIGNED);
});
context._.each(tracks.tracks, function(track, index) {
var trackNumber = index + 1;
context._.each(track.channels, function(channelId) {
context.jamClient.TrackSetAssignment(channelId, true, trackNumber);
});
logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", trackNumber, track.instrument_id);
context.jamClient.TrackSetInstrument(trackNumber, context.JK.instrument_id_to_instrument[track.instrument_id].client_id);
});
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
return true;
}
else {
context.JK.Banner.showAlert('Unable to save assignments. ' + result);
return false;
}
}
function loadTrackInstruments() {
var $trackInstruments = $instrumentsHolder.find('.track-instrument');
context._.each($trackInstruments, function(trackInstrument) {
var $trackInstrument = $(trackInstrument);
var trackIndex = parseInt($trackInstrument.attr('data-num')) + 1;
var clientInstrument = context.jamClient.TrackGetInstrument(trackIndex);
var instrument = context.JK.client_to_server_instrument_map[clientInstrument];
$trackInstrument.instrumentSelectorSet(instrument ? instrument.server_id : instrument);
});
}
function handleNext() {
var tracks = trackAssociations();
if(!validate(tracks)) {
return false;
}
var saved = save(tracks);
var saved = configureTracksHelper.trySave();
if(saved) {
context.JK.GA.trackConfigureTracksCompletion(context.JK.detectOS());
@ -188,77 +26,13 @@
}
function beforeShow() {
loadChannels();
loadTrackInstruments();
}
function unassignChannel($channel) {
var $originallyAssignedTrack = $channel.closest('.track-target');
$unassignedChannelsHolder.append($channel);
$originallyAssignedTrack.attr('track-count', $originallyAssignedTrack.find('.ftue-input:not(.ui-draggable-dragging)').length);
}
function addChannelToTrack($channel, $track) {
var $originallyAssignedTrack = $channel.closest('.track-target');
$track.append($channel);
$track.attr('track-count', $track.find('.ftue-input:not(.ui-draggable-dragging)').length);
$originallyAssignedTrack.attr('track-count', $originallyAssignedTrack.find('.ftue-input:not(.ui-draggable-dragging)').length)
}
function initializeUnassignedDroppable() {
$unassignedChannelsHolder.droppable(
{
activeClass: 'drag-in-progress',
hoverClass: 'drag-hovering',
drop: function( event, ui ) {
var $channel = ui.draggable;
//$channel.css('left', '0').css('top', '0');
unassignChannel($channel);
}
});
}
function initializeTrackDroppables() {
var i;
for(i = 0; i < MAX_TRACKS; i++) {
var $target = $(context._.template($templateTrackTarget.html(), {num: i }, { variable: 'data' }));
$tracksHolder.append($target);
$target.find('.track-target').droppable(
{
activeClass: 'drag-in-progress',
hoverClass: 'drag-hovering',
drop: function( event, ui ) {
var $track = $(this);
var $channel = ui.draggable;
//$channel.css('left', '0').css('top', '0');
addChannelToTrack($channel, $track);
}
});
}
}
function initializeInstrumentDropdown() {
var i;
for(i = 0; i < MAX_TRACKS; i++) {
var $root = $('<div class="track-instrument"></div>');
$root.instrumentSelector().attr('data-num', i);
$instrumentsHolder.append($root);
}
configureTracksHelper.reset();
}
function initialize(_$step) {
$step = _$step;
$templateAssignablePort = $('#template-assignable-port');
$templateTrackTarget = $('#template-track-target');
$unassignedChannelsHolder = $step.find('.unassigned-channels');
$tracksHolder = $step.find('.tracks');
$instrumentsHolder = $step.find('.instruments');
initializeUnassignedDroppable();
initializeTrackDroppables();
initializeInstrumentDropdown();
configureTracksHelper.initialize($step);
}
this.handleNext = handleNext;

View File

@ -17,144 +17,24 @@
var $templateChatInput = null;
var $selectedChatInput = null;// should only be used if isChatEnabled = true
var voiceChatHelper = new context.JK.VoiceChatHelper(app);
function newSession() {
$reuseAudioInputRadio.attr('checked', 'checked').iCheck('check');
}
function isChannelAvailableForChat(chatChannelId, musicPorts) {
var result = true;
context._.each(musicPorts.input, function(inputChannel) {
// if the channel is currently assigned to a track, it not unassigned
if(inputChannel.id == chatChannelId && (inputChannel.assignment > 0)) {
result = false;
return false; // break
}
});
return result;
}
function isChatEnabled() {
return $useChatInputRadio.is(':checked');
voiceChatHelper.reset();
}
function beforeShow() {
if(isChatEnabled()) {
enableChat();
}
else {
disableChat();
}
var musicPorts = jamClient.FTUEGetChannels();
var chatInputs = context.jamClient.FTUEGetChatInputs();
$chatInputs.empty();
context._.each(chatInputs, function(chatChannelName, chatChannelId) {
if(isChannelAvailableForChat(chatChannelId, musicPorts)) {
var $chat = $(context._.template($templateChatInput.html(), {id: chatChannelId, name: chatChannelName}, { variable: 'data' }));
$chat.hide(); // we'll show it once it's styled with iCheck
$chatInputs.append($chat);
}
});
var $radioButtons = $chatInputs.find('input[name="chat-device"]');
context.JK.checkbox($radioButtons).on('ifChecked', function(e) {
var $input = $(e.currentTarget);
$selectedChatInput = $input; // for use in handleNext
var channelId = $input.attr('data-channel-id');
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.CHAT);
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
}
else {
context.JK.Banner.showAlert('Unable to save assignments. ' + result);
return false;
}
});
if(!isChatEnabled()) {
$radioButtons.iCheck('disable');
}
$chatInputs.find('.chat-input').show().on('click', function() {
if(!isChatEnabled()) {
context.JK.prodBubble($step.find('.use-chat-input h3'), 'chat-not-enabled', {}, { positions:['left']});
}
})
}
function disableChat() {
logger.debug("FTUE: disabling chat");
context.jamClient.TrackSetChatEnable(false);
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
}
else {
context.JK.Banner.showAlert('Unable to disable chat. ' + result);
return false;
}
var $radioButtons = $chatInputs.find('input[name="chat-device"]');
$radioButtons.iCheck('disable');
}
function enableChat() {
logger.debug("FTUE: enabling chat");
context.jamClient.TrackSetChatEnable(true);
var result = context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) {
// success
}
else {
context.JK.Banner.showAlert('Unable to enable chat. ' + result);
return false;
}
var $radioButtons = $chatInputs.find('input[name="chat-device"]');
$radioButtons.iCheck('enable');
}
function handleChatEnabledToggle() {
context.JK.checkbox($reuseAudioInputRadio);
context.JK.checkbox($useChatInputRadio);
// plugin sets to relative on the element; have to do this as an override
$reuseAudioInputRadio.closest('.iradio_minimal').css('position', 'absolute');
$useChatInputRadio.closest('.iradio_minimal').css('position', 'absolute');
$reuseAudioInputRadio.on('ifChecked', disableChat);
$useChatInputRadio.on('ifChecked', enableChat)
}
function handleNext() {
var selectedDeviceInfo = gearUtils.selectedDeviceInfo(context.jamClient.FTUEGetInputMusicDevice(), context.jamClient.FTUEGetOutputMusicDevice());
var chatName = null;
if(isChatEnabled()) {
chatName = $selectedChatInput.attr('data-channel-name');
}
context.jamClient.FTUESetMusicProfileName(gearUtils.createProfileName(selectedDeviceInfo, chatName));
return true;
}
function initialize(_$step) {
$step = _$step;
$reuseAudioInputRadio = $step.find('.reuse-audio-input input');
$useChatInputRadio = $step.find('.use-chat-input input');
$chatInputs = $step.find('.chat-inputs');
$templateChatInput = $('#template-chat-input');
voiceChatHelper.initialize($step, true);
handleChatEnabledToggle();
}
this.handleNext = handleNext;

View File

@ -5,6 +5,7 @@
context.JK = context.JK || {};
context.JK.StepSelectGear = function (app, dialog) {
var EVENTS = context.JK.DIALOG_CLOSED;
var ASSIGNMENT = context.JK.ASSIGNMENT;
var VOICE_CHAT = context.JK.VOICE_CHAT;
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
@ -298,7 +299,7 @@
function initializeLoopback() {
$launchLoopbackBtn.unbind('click').click(function() {
$(dialog.getLoopbackWizard()).one('dialog_closed', function() {
$(dialog.getLoopbackWizard().getDialog()).one(EVENTS.DIALOG_CLOSED, function() {
loopbackShowing = false;
if(dialog.getLoopbackWizard().getGearTest().isGoodFtue()) {

View File

@ -83,7 +83,7 @@
// * Linux
function determineDeviceType(deviceId, displayName) {
if (operatingSystem == "MacOSX") {
if (displayName.toLowerCase().trim() == "built-in") {
if (displayName.toLowerCase().trim().indexOf("built-in") == 0) {
return "MacOSX_builtin";
}
else {
@ -157,6 +157,36 @@
}
}
/**
* Lists all profiles, but marks profiles good: true/false.
* Also, current:true/false indicates which profile is active. (at most 1 profile will be marked current)
* This is to provide a unified view of FTUEGetAllAudioConfigurations & FTUEGetGoodAudioConfigurations
* @returns an array of profiles, where each profile is: {id: profile-name, good: boolean, class: 'bad' | 'good', current: boolean }
*/
gearUtils.getProfiles = function() {
var all = context.jamClient.FTUEGetAllAudioConfigurations();
var good = context.jamClient.FTUEGetGoodAudioConfigurations();
var current = context.jamClient.FTUEGetMusicProfileName();
var profiles = [];
context._.each(all, function(item) {
profiles.push({id: item, good: false, class:'bad', current: current == item})
});
if(good) {
for(var i = 0; i < good.length; i++) {
for(var j = 0; j < profiles.length; j++) {
if(good[i] == profiles[j].id) {
profiles[j].good = true;
profiles[j].class = 'good';
break;
}
}
}
}
return profiles;
}
gearUtils.postDiagnostic = function(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated) {
rest.createDiagnostic({
type: 'GEAR_SELECTION',
@ -169,4 +199,40 @@
});
}
// complete list of possibly chatInputs, whether currently assigned as the chat channel or not
// each item should be {id: channelId, name: channelName, assignment: channel assignment}
gearUtils.getChatInputs = function(){
var musicPorts = jamClient.FTUEGetChannels();
var chatsOnOtherDevices = context.jamClient.FTUEGetChatInputs(false);
var chatInputs = [];
context._.each(musicPorts.inputs, function(input) {
chatInputs.push({id: input.id, name: input.name, assignment:input.assignment});
});
context._.each(chatsOnOtherDevices, function(chatChannelName, chatChannelId) {
var chatInput = {id: chatChannelId, name: chatChannelName, assignment: null};
var assignment = context.jamClient.TrackGetAssignment(chatChannelId, true);
chatInput.assignment = assignment;
chatInputs.push(chatInput);
})
return chatInputs;
}
gearUtils.isChannelAvailableForChat = function(chatChannelId, musicPorts) {
var result = true;
context._.each(musicPorts.inputs, function(inputChannel) {
// if the channel is currently assigned to a track, it not unassigned
if(inputChannel.id == chatChannelId && (inputChannel.assignment > 0)) {
result = false;
return false; // break
}
});
return result;
}
})(window, jQuery);

View File

@ -5,6 +5,7 @@
context.JK = context.JK || {};
context.JK.LoopbackWizard = function (app) {
var EVENTS = context.JK.DIALOG_CLOSED;
var logger = context.JK.logger;
var $dialog = null;
@ -32,7 +33,6 @@
function closeDialog() {
wizard.onCloseDialog();
$self.triggerHandler('dialog_closed');
app.layout.closeDialog('loopback-wizard');
}
@ -71,6 +71,9 @@
$(wizard).on('wizard_close', onClosed);
}
function getDialog() {
return $dialog;
}
function initialize() {
@ -93,6 +96,7 @@
this.setBackState = setBackState;
this.initialize = initialize;
this.getGearTest = getGearTest;
this.getDialog = getDialog;
return this;

View File

@ -34,6 +34,8 @@
*= require ./search
*= require ./ftue
*= require ./jamServer
*= require ./dragDropTracks
*= require ./voiceChatHelper
*= require ./wizard/gearResults
*= require ./wizard/framebuffers
*= require ./wizard/wizard

View File

@ -1,5 +1,121 @@
@import "client/common.css.scss";
@charset "UTF-8";
#configure-tracks-dialog {
min-height: 500px;
max-height: 500px;
min-height: 700px;
max-height: 700px;
width:800px;
&[current-screen="account/audio"] {
.btn-add-new-audio-gear {
display:none;
}
}
.sub-header {
color:white;
margin-bottom:10px;
}
.certified-audio-profile-section {
height:53px;
.easydropdown {
width:120px;
}
.easydropdown-wrapper {
width:120px;
}
.dropdown-container {
min-width:138px;
}
}
.column {
position:relative;
float:left;
vertical-align:top;
@include border_box_sizing;
padding: 20px 20px 0 0;
}
.sub-column {
position:relative;
float:left;
vertical-align:top;
@include border_box_sizing;
}
.tab[tab-id="music-audio"] {
.column {
&:nth-of-type(1) {
width: 30%;
}
&:nth-of-type(2) {
width: 70%;
}
}
.sub-column {
&:nth-of-type(1) {
width: 80%;
}
&:nth-of-type(2) {
width: 20%;
}
}
}
.tab[tab-id="voice-chat"] {
.column {
&:nth-of-type(1) {
width: 50%;
}
&:nth-of-type(2) {
width: 50%;
}
}
}
.unused-audio-inputs-section {
margin-top:20px;
height:270px;
}
.unused-audio-outputs-section {
margin-top:20px;
height:80px;
}
.input-tracks-section {
height:363px;
}
.output-channels-section {
height:80px;
}
.buttons {
bottom: 25px;
position: absolute;
right: 25px;
left:25px;
}
.btn-add-new-audio-gear {
float:left;
}
.btn-cancel {
float:right;
}
.btn-update-settings {
float:right;
}
}

View File

@ -0,0 +1,162 @@
@import "client/common.css.scss";
@charset "UTF-8";
.dialog.gear-wizard, #configure-tracks-dialog {
.icon-instrument-select {
padding: 3px 0; // to combine 24 of .current-instrument + 3x on either side
margin: 0 0 15px 25px; // 15 margin-bottom to match tracks on the left
width: 30px;
}
.unassigned-output-channels {
min-height: 80px;
overflow-y: auto;
//padding-right:18px; // to keep draggables off of scrollbar. maybe necessary
&.drag-in-progress {
overflow-y: visible;
overflow-x: visible;
}
&.possible-target {
border: solid 1px white;
&.drag-hovering {
border: solid 1px #ED3618;
}
}
}
.unassigned-input-channels {
min-height: 240px;
overflow-y: auto;
//padding-right:18px; // to keep draggables off of scrollbar. maybe necessary
&.drag-in-progress {
overflow-y: visible;
overflow-x: visible;
}
&.possible-target {
border: solid 1px white;
&.drag-hovering {
border: solid 1px #ED3618;
}
}
}
.num {
position: absolute;
height: 29px;
line-height: 29px;
}
.track, .output {
margin-bottom: 15px;
.track-target, .output-target {
&.possible-target {
border-color: white;
}
&.drag-hovering {
border-color: #ED3618;
}
}
}
// do not show tracks with 2 channels as a possible target
.track .track-target.possible-target[track-count="2"] {
border-color:#999;
}
// do now show output slots with 1 channel as a possible target
.output .output-target.possible-target[output-count="1"] {
border-color:#999;
}
.ftue-input {
font-size: 12px;
cursor: move;
padding: 4px;
border: solid 1px #999;
margin-bottom: 15px;
white-space: nowrap;
overflow: hidden;
text-align: left;
direction: rtl;
&.ui-draggable-dragging {
margin-bottom: 0;
}
&:hover {
color: white;
font-weight: bold;
}
/**
&:hover {
color:white;
overflow:visible;
background-color:#333;
width: auto !important;
direction:ltr;
position:absolute;
line-height:19.5px;
}*/
}
.track-target, .output-target {
cursor: move;
padding: 4px;
border: solid 1px #999;
margin-left: 15px;
height: 20px;
overflow: hidden;
&.drag-in-progress {
overflow: visible;
}
.ftue-input {
padding: 0;
border: 0;
margin-bottom: 0;
&.ui-draggable-dragging {
padding: 4px;
border: solid 1px #999;
overflow: visible;
}
}
.placeholder {
display: none;
font-size: 12px;
}
&[track-count="0"], &[output-count="0"] {
.placeholder {
display: inline;
}
}
&[track-count="2"] {
.ftue-input {
width: 49%;
display: inline-block;
&:nth-of-type(1) {
float: left;
/**&:after {
float:right;
content: ',';
padding-right:3px;
}*/
}
&:nth-of-type(2) {
float: right;
}
}
}
}
}

View File

@ -4,4 +4,11 @@
position: absolute;
right: 25px;
}
.network-test {
.network-test-results {
height:268px ! important;
}
}
}

View File

@ -0,0 +1,60 @@
.dialog.configure-tracks, .dialog.gear-wizard {
.voicechat-option {
position: relative;
div {
}
h3 {
padding-left: 30px;
margin-top: 14px;
font-weight: bold;
display: inline-block;
}
p {
padding-left: 30px;
margin-top: 5px;
display: inline-block;
}
input {
position: absolute;
margin: auto;
width: 30px;
}
.iradio_minimal {
margin-top: 15px;
display: inline-block;
}
}
.ftue-box {
background-color: #222222;
font-size: 13px;
padding: 8px;
&.chat-inputs {
height: 230px !important;
overflow: auto;
p {
white-space: nowrap;
display: inline-block;
height: 32px;
vertical-align: middle;
}
.chat-input {
white-space: nowrap;
.iradio_minimal {
display: inline-block;
}
}
}
}
}

View File

@ -1,5 +1,4 @@
@import "client/common.css.scss";
@charset "UTF-8";
.dialog.gear-wizard, .dialog.network-test {
@ -193,132 +192,8 @@
margin-top: 45px;
}
.icon-instrument-select {
padding: 3px 0; // to combine 24 of .current-instrument + 3x on either side
margin: 0 0 15px 25px; // 15 margin-bottom to match tracks on the left
width: 30px;
}
.unassigned-channels {
min-height: 240px;
overflow-y: auto;
//padding-right:18px; // to keep draggables off of scrollbar. maybe necessary
&.drag-in-progress {
overflow-y: visible;
overflow-x: visible;
}
&.possible-target {
border: solid 1px white;
&.drag-hovering {
border: solid 1px #ED3618;
}
}
}
.num {
position: absolute;
height: 29px;
line-height: 29px;
}
.track {
margin-bottom: 15px;
.track-target {
&.possible-target {
border-color: white;
}
&.drag-hovering {
border-color: #ED3618;
}
}
}
.ftue-input {
font-size: 12px;
cursor: move;
padding: 4px;
border: solid 1px #999;
margin-bottom: 15px;
white-space: nowrap;
overflow: hidden;
text-align: left;
direction: rtl;
&.ui-draggable-dragging {
margin-bottom: 0;
}
&:hover {
color: white;
font-weight: bold;
}
/**
&:hover {
color:white;
overflow:visible;
background-color:#333;
width: auto !important;
direction:ltr;
position:absolute;
line-height:19.5px;
}*/
}
.track-target {
cursor: move;
padding: 4px;
border: solid 1px #999;
margin-left: 15px;
height: 20px;
overflow: hidden;
&.drag-in-progress {
overflow: visible;
}
.ftue-input {
padding: 0;
border: 0;
margin-bottom: 0;
&.ui-draggable-dragging {
padding: 4px;
border: solid 1px #999;
overflow: visible;
}
}
.placeholder {
display: none;
font-size: 12px;
}
&[track-count="0"] {
.placeholder {
display: inline;
}
}
&[track-count="2"] {
.ftue-input {
width: 49%;
display: inline-block;
&:nth-of-type(1) {
float: left;
/**&:after {
float:right;
content: ',';
padding-right:3px;
}*/
}
&:nth-of-type(2) {
float: right;
}
}
}
.output-channels, .unassigned-output-channels {
display:none;
}
}
@ -333,67 +208,9 @@
}
.watch-video {
margin-top: 97px;
margin-top: 25px;
}
.voicechat-option {
position: relative;
div {
}
h3 {
padding-left: 30px;
margin-top: 14px;
font-weight: bold;
display: inline-block;
}
p {
padding-left: 30px;
margin-top: 5px;
display: inline-block;
}
input {
position: absolute;
margin: auto;
width: 30px;
}
.iradio_minimal {
margin-top: 15px;
display: inline-block;
}
}
.ftue-box {
&.chat-inputs {
height: 230px !important;
overflow: auto;
p {
white-space: nowrap;
display: inline-block;
height: 32px;
vertical-align: middle;
}
.chat-input {
white-space: nowrap;
.iradio_minimal {
display: inline-block;
}
}
}
.watch-video {
margin-top: 25px;
}
}
}
.wizard-step[layout-wizard-step="4"] {
@ -442,11 +259,6 @@
}
}
.network-test {
.network-test-results {
height:268px ! important;
}
}
.wizard-step[layout-wizard-step="5"], .network-test {
.wizard-step-content .wizard-step-column {
@ -557,7 +369,7 @@
}
.network-test-results {
height: 248px;
height: 248px !important;
@include border_box_sizing;
&.testing {

View File

@ -53,6 +53,7 @@
{% if(data.is_admin) { %}
<a href="#" data-id="{{profile.id}}" data-purpose="loopback-audio-profile" class="button-orange">LOOPBACK (admin only)</a>
{% } %}
<a href="#" data-id="{{profile.id}}" data-purpose="configure-audio-profile" class="button-orange">CONFIGURE</a>
<a href="#" data-id="{{profile.id}}" data-purpose="delete-audio-profile" class="button-orange">DELETE</a></td>
</tr>
{% } %}

View File

@ -1,4 +1,4 @@
.dialog{ layout: 'dialog', 'layout-id' => 'configure-tracks', id: 'configure-tracks-dialog'}
.dialog.configure-tracks{ layout: 'dialog', 'layout-id' => 'configure-tracks', id: 'configure-tracks-dialog'}
.content-head
= image_tag "content/icon_add.png", {:width => 19, :height => 19, :class => 'content-icon' }
%h1 configure tracks
@ -9,14 +9,63 @@
.instructions
%span
Choose your audio device. Drag and drop to assign input ports to tracks, and specify the instrument
for each track. Drag and drop to assign a pair of output ports for session stereo audio monitoring.
.clearall
.tab{'tab-id' => 'music-audio'}
.column
.certified-audio-profile-section
.sub-header Certified Audio Profile
%select.certified-audio-profile
.clearall
.unused-audio-inputs-section.no-selection-range
.sub-header Unused Input Ports
.unassigned-input-channels
.unused-audio-outputs-section.no-selection-range
.sub-header Unused Output Ports
.unassigned-output-channels
.column
.input-tracks-section
.sub-column
.sub-header Track Input Port(s)
.input-tracks.tracks.no-selection-range
.sub-column
.sub-header Instrument
.instruments.no-selection-range
.output-channels-section
.sub-header Audio Output Port
.output-channels.no-selection-range
.clearall
.tab{'tab-id' => 'voice-chat'}
.column
%form.select-voice-chat-option.section
.sub-header Select Voice Chat Option
.voicechat-option.reuse-audio-input
%input{type:"radio", name: "voicechat", checked:"checked"}
%h3 Use Music Microphone
%p I am already using a microphone to capture my vocal or instrumental music, so I can talk with other musicians using that microphone
.voicechat-option.use-chat-input
%input{type:"radio", name: "voicechat"}
%h3 Use Chat Microphone
%p I am not using a microphone for acoustic instruments or vocals, so use the input selected to the right for voice chat during my sessions
.column
.select-voice-chat
.sub-header Voice Chat Input
.ftue-box.chat-inputs
.clearall
.buttons
%a.btn-add-new-audio-gear.button-grey{'layout-link' => 'add-new-audio-gear'} ADD NEW AUDIO GEAR
%a.button-orange.btn-update-settings{href:'#'} UPDATE SETTINGS
%a.button-grey.btn-cancel{href:'#'} CANCEL

View File

@ -52,7 +52,7 @@
<!-- my tracks -->
<div class="session-mytracks">
<h2>my tracks</h2>
<div id="track-settings" class="session-add" style="display:block;" layout-link="configure-audio">
<div id="track-settings" class="session-add" style="display:block;" layout-link="configure-tracks">
<%= image_tag "content/icon_settings_lg.png", {:width => 18, :height => 18} %>&nbsp;&nbsp;Settings
</div>

View File

@ -74,15 +74,17 @@
%li Select the instrument for each track.
.center
%a.button-orange.watch-video{href:'#'} WATCH VIDEO
.wizard-step-column.no-selection-range
.wizard-step-column
%h2 Unassigned Ports
.unassigned-channels
.wizard-step-column.no-selection-range
.unassigned-input-channels.no-selection-range
.wizard-step-column
%h2 Track Input Port(s)
.tracks
.wizard-step-column.no-selection-range
.tracks.no-selection-range
.wizard-step-column
%h2 Instrument
.instruments
.instruments.no-selection-range
.output-channels
.unassigned-output-channels
.wizard-step{ 'layout-wizard-step' => "3", 'dialog-title' => "Configure Voice Chat", 'dialog-purpose' => "ConfigureVoiceChat" }
.ftuesteps
@ -98,14 +100,15 @@
%a.button-orange.watch-video{href:'#'} WATCH VIDEO
.wizard-step-column
%h2 Select Voice Chat Option
.voicechat-option.reuse-audio-input
%input{type:"radio", name: "voicechat", checked:"checked"}
%h3 Use Music Microphone
%p I am already using a microphone to capture my vocal or instrumental music, so I can talk with other musicians using that microphone
.voicechat-option.use-chat-input
%input{type:"radio", name: "voicechat"}
%h3 Use Chat Microphone
%p I am not using a microphone for acoustic instruments or vocals, so use the input selected to the right for voice chat during my sessions
%form
.voicechat-option.reuse-audio-input
%input{type:"radio", name: "voicechat", checked:"checked"}
%h3 Use Music Microphone
%p I am already using a microphone to capture my vocal or instrumental music, so I can talk with other musicians using that microphone
.voicechat-option.use-chat-input
%input{type:"radio", name: "voicechat"}
%h3 Use Chat Microphone
%p I am not using a microphone for acoustic instruments or vocals, so use the input selected to the right for voice chat during my sessions
.wizard-step-column
%h2 Voice Chat Input
.ftue-box.chat-inputs
@ -220,8 +223,16 @@
.track-target{'data-num' => '{{data.num}}', 'track-count' => 0}
%span.placeholder None
%script{type: 'text/template', id: 'template-output-target'}
.output{'data-num' => '{{data.num}}'}
.num {{data.num + 1}}:
.output-target{'data-num' => '{{data.num}}', 'output-count' => 0}
%span.placeholder None
%script{type: 'text/template', id: 'template-chat-input'}
.chat-input
%input{type:"radio", name: "chat-device", 'data-channel-id' => '{{data.id}}', 'data-channel-name' => '{{data.name}}'}
%p
= '{{data.name}}'
%span {{data.name}}