* VRFS-946 and VRFS-922 - in-session recording features complete

This commit is contained in:
Seth Call 2014-01-06 20:35:35 +00:00
parent 17486c6ed2
commit fa23c267f5
27 changed files with 370 additions and 122 deletions

View File

@ -83,3 +83,4 @@ bands_geocoding.sql
store_s3_filenames.sql
discardable_recorded_tracks.sql
music_sessions_have_claimed_recording.sql
discardable_recorded_tracks2.sql

View File

@ -0,0 +1,2 @@
ALTER TABLE recorded_tracks ALTER COLUMN discard DROP DEFAULT;
ALTER TABLE recorded_tracks ALTER COLUMN discard DROP NOT NULL;

View File

@ -49,6 +49,7 @@ module ValidationMessages
ALREADY_PLAYBACK_RECORDING = "already playing a recording"
NO_LONGER_RECORDING = "no longer recording"
NOT_IN_SESSION = "not in session"
PREVIOUS_RECORDING_STILL_BEING_FINALIZED = "still has previous recording being finalized"
# recorded tracks
ALREADY_UPLOADED = "already set"

View File

@ -179,6 +179,10 @@ module JamRuby
return self.users.exists? user
end
def most_recent_recording
recordings.where(:music_session_id => self.id).order('created_at desc').limit(1).first
end
# is this music session currently recording?
def is_recording?
recordings.where(:duration => nil).count > 0

View File

@ -14,6 +14,7 @@ module JamRuby
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id
validates :music_session, :presence => true
validate :not_already_recording, :on => :create
validate :not_still_finalizing_previous, :on => :create
validate :not_playback_recording, :on => :create
validate :already_stopped_recording
@ -23,6 +24,28 @@ module JamRuby
end
end
def not_still_finalizing_previous
# after a recording is done, users need to keep or discard it.
# this checks if the previous recording is still being finalized
unless music_session.is_recording?
previous_recording = music_session.most_recent_recording
if previous_recording
previous_recording.recorded_tracks.each do |recorded_track|
# if at least one user hasn't taken any action yet...
if recorded_track.discard.nil?
# and they are still around and in this music session still...
connection = Connection.find_by_client_id(recorded_track.client_id)
if !connection.nil? && connection.music_session == music_session
errors.add(:music_session, ValidationMessages::PREVIOUS_RECORDING_STILL_BEING_FINALIZED)
break
end
end
end
end
end
end
def not_playback_recording
if music_session.is_playing_recording?
errors.add(:music_session, ValidationMessages::ALREADY_PLAYBACK_RECORDING)
@ -39,7 +62,7 @@ module JamRuby
unless self.users.exists?(user)
raise PermissionError, "user was not in this session"
end
RecordedTrack.where(:recording_id=> self.id).where(:user_id=> user.id)
recorded_tracks.where(:user_id=> user.id)
end
def has_access?(user)
@ -91,12 +114,13 @@ module JamRuby
self
end
# Called when a user wants to "claim" a recording. To do this, the user must have been one of the tracks in the recording.
def claim(user, name, description, genre, is_public, is_downloadable)
unless self.users.exists?(user)
raise PermissionError, "user was not in this session"
end
end
claimed_recording = ClaimedRecording.new
claimed_recording.user = user
@ -108,8 +132,17 @@ module JamRuby
claimed_recording.is_downloadable = is_downloadable
self.claimed_recordings << claimed_recording
if claimed_recording.save
discard(user)
end
claimed_recording
end
# the user votes to discard their tracks for this recording
def discard(user)
recorded_tracks_for_user(user).update_all(:discard => true)
end
# Find out if all the tracks for this recording have been uploaded
def uploaded?
@ -119,11 +152,6 @@ module JamRuby
return true
end
# Discards this recording and schedules deletion of all files associated with it.
def discard
self.destroy
end
def self.list_downloads(user, limit = 100, since = 0)
since = 0 unless since || since == '' # guard against nil
downloads = []

View File

@ -1,12 +1,15 @@
require 'spec_helper'
def valid_claimed_recording
@claimed_recording.name = "hello"
@claimed_recording.description = "description"
@claimed_recording.genre = Genre.first
@claimed_recording.is_public = true
@claimed_recording.is_downloadable = true
@claimed_recording
@name = "hello"
@description = "description"
@genre = Genre.first
@is_public = true
@is_downloadable = true
end
def make_claim
@claimed_recording = @recording.claim(@user, @name, @description, @genre, @is_public, @is_downloadable)
end
describe ClaimedRecording do
@ -22,33 +25,37 @@ describe ClaimedRecording do
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(@user, "name", "description", @genre, true, true)
@recording.reload
@claimed_recording = @recording.claimed_recordings.first
end
describe "sucessful save" do
it "with default case" do
valid_claimed_recording
@claimed_recording.save.should be_true
make_claim
@claimed_recording.errors.any?.should be_false
@recording.reload
@recording.recorded_tracks.first.discard.should be_false
end
end
describe "update name" do
it "with nil" do
valid_claimed_recording
@claimed_recording.name = nil
@claimed_recording.save.should be_false
@name = nil
make_claim
@claimed_recording.errors.any?.should be_true
@claimed_recording.errors[:name].length.should == 2
@claimed_recording.errors[:name].select { |value| value.include?("can't be blank") }.length.should == 1
@claimed_recording.errors[:name].select { |value| value.include?("is too short") }.length.should == 1
@recording.reload
@recording.recorded_tracks.first.discard.should be_nil
end
it "too short" do
valid_claimed_recording
@claimed_recording.name = "a"
@claimed_recording.save.should be_false
@name = "a"
make_claim
@claimed_recording.errors.any?.should be_true
@claimed_recording.errors[:name].length.should == 1
@claimed_recording.errors[:name].select { |value| value.include?("is too short") }.length.should == 1
end
@ -57,16 +64,18 @@ describe ClaimedRecording do
describe "update description" do
it "with nil" do
valid_claimed_recording
@claimed_recording.description = nil
@claimed_recording.save.should be_true
@description = nil
make_claim
@claimed_recording.errors.any?.should be_false
end
end
describe "update is_public" do
it "with nil" do
valid_claimed_recording
@claimed_recording.is_public = nil
@claimed_recording.save.should be_false
@is_public = nil
make_claim
@claimed_recording.errors.any?.should be_true
@claimed_recording.errors[:is_public].length.should == 1
@claimed_recording.errors[:is_public].should == ["is not included in the list"]
end
@ -75,8 +84,9 @@ describe ClaimedRecording do
describe "update is_downloadable" do
it "with nil" do
valid_claimed_recording
@claimed_recording.is_downloadable = nil
@claimed_recording.save.should be_false
@is_downloadable = nil
make_claim
@claimed_recording.errors.any?.should be_true
@claimed_recording.errors[:is_downloadable].length.should == 1
@claimed_recording.errors[:is_downloadable].should == ["is not included in the list"]
end
@ -85,8 +95,9 @@ describe ClaimedRecording do
describe "update genre" do
it "with nil" do
valid_claimed_recording
@claimed_recording.genre = nil
@claimed_recording.save.should be_false
@genre = nil
make_claim
@claimed_recording.errors.any?.should be_true
@claimed_recording.errors[:genre].length.should == 1
@claimed_recording.errors[:genre].should == ["can't be blank"]
end
@ -94,6 +105,8 @@ describe ClaimedRecording do
describe "multiple claims" do
it "not valid" do
valid_claimed_recording
make_claim
duplicate = @recording.claim(@user, "name", "description", @genre, true, true)
duplicate.valid?.should be_false
duplicate.errors[:recording_id].should == ['has already been taken']

View File

@ -316,6 +316,44 @@ describe Recording do
timeline.last["end"].should == true
end
describe "chance for everyone to keep or discard" do
before(:each) do
@user2 = FactoryGirl.create(:user)
@connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session)
@track2 = FactoryGirl.create(:track, :connection => @connection2, :instrument => @instrument)
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
end
it "no one votes" do
@recording2 = Recording.start(@music_session, @user)
@recording2.errors.any?.should be_true
@recording2.errors[:music_session].should == [ValidationMessages::PREVIOUS_RECORDING_STILL_BEING_FINALIZED]
end
it "only one discards" do
@recording.discard(@user)
@recording2 = Recording.start(@music_session, @user)
@recording2.errors.any?.should be_true
@recording2.errors[:music_session].should == [ValidationMessages::PREVIOUS_RECORDING_STILL_BEING_FINALIZED]
end
it "everyone discards" do
@recording.discard(@user)
@recording.discard(@user2)
@recording2 = Recording.start(@music_session, @user)
@recording2.errors.any?.should be_false
end
it "one discards, the other leaves the session" do
@recording.discard(@user)
@connection2.delete
@recording2 = Recording.start(@music_session, @user2)
@recording2.errors.any?.should be_false
end
end
end

View File

@ -549,7 +549,7 @@
var possibleAnswers = ['HQ', 'RT', 'MISSING', 'PARTIALLY_MISSING'];
$.each(recordings.claimed_recordings, function(i, recordings) {
$.each(recordings, function(i, recording) {
// just make up a random yes-hq/yes-rt/missing answer
var recordingResult = {};
recordingResult['aggregate_state'] = possibleAnswers[Math.floor((Math.random()*4))];

View File

@ -48,10 +48,10 @@
emptyList();
var recordings = [];
var $tbody = tbody();
var localResults = context.jamClient.GetLocalRecordingState({claimed_recordings: claimedRecordings});
var recordings = $.map(claimedRecordings, function(val, i) { return val.recording; });
var localResults = context.jamClient.GetLocalRecordingState({recordings: recordings});
if(localResults['error']) {
app.notify({
@ -113,7 +113,7 @@
rest.startPlayClaimedRecording({id: context.JK.CurrentSessionModel.id(), claimed_recording_id: claimedRecording.id})
.done(function(response) {
var recordingId = $(this).attr('data-recording-id');
var openRecordingResult = context.jamClient.OpenRecording(claimedRecording);
var openRecordingResult = context.jamClient.OpenRecording(claimedRecording.recording);
logger.debug("OpenRecording response: %o", openRecordingResult);

View File

@ -5,15 +5,34 @@
"use strict";
var PlaybackMode = {
NoPlayback: 0,
EveryWhere: 1,
PrivatePreview: 2,
PreviewToAll: 3,
LastPbMode: 4
};
context.JK = context.JK || {};
context.JK.PlaybackControls = function($parentElement){
context.JK.PlaybackControls = function($parentElement, options){
options = $.extend(false, {playmodeControlsVisible:false}, options);
var logger = context.JK.logger;
if($parentElement.length == 0) {
logger.debug("no $parentElement specified in PlaybackControls");
}
var $playButton = $('.play-button img.playbutton', $parentElement);
var $pauseButton = $('.play-button img.pausebutton', $parentElement);
var $currentTime = $('.recording-current', $parentElement);
var $duration = $('.duration-time', $parentElement);
var $sliderBar = $('.recording-playback', $parentElement);
var $slider = $('.recording-slider', $parentElement);
var $playmodeButton = $('.playback-mode-buttons.icheckbuttons input', $parentElement);
var $self = $(this);
var playbackPlaying = false;
@ -26,13 +45,15 @@
var playingWhenDragStart = false;
var draggingUpdateTimer = null;
var canUpdateBackend = false;
var playbackMode = PlaybackMode.EveryWhere;
var monitorPlaybackTimeout = null;
function startPlay() {
updateIsPlaying(true);
if(endReached) {
update(0, playbackDurationMs, playbackPlaying);
}
$self.triggerHandler('play');
$self.triggerHandler('play', {playbackMode: playbackMode});
}
function stopPlay() {
@ -94,7 +115,7 @@
updateOffsetBasedOnPosition(offset);
updateSliderPosition(playbackPositionMs);
return false;
})
});
$slider.draggable({
axis: 'x',
@ -104,6 +125,34 @@
drag: onDrag
});
if(options.playmodeControlsVisible) {
$('.playback-mode-buttons.icheckbuttons', $parentElement).show();
}
$playmodeButton.iCheck({
checkboxClass: 'icheckbox_minimal',
radioClass: 'iradio_minimal',
inheritClass: true
});
$playmodeButton.on('ifChecked', function(e) {
var playmode = $(this).val();
console.log("set new playmode", playmode);
setPlaybackMode(playmode);
});
function monitorRecordingPlayback() {
var isPlaying = context.jamClient.isSessionTrackPlaying();
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
update(positionMs, durationMs, isPlaying);
monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500);
}
function update(currentTimeMs, durationTimeMs, isPlaying) {
if(dragging) {
@ -111,6 +160,7 @@
}
// at the end of the play, the duration sets to 0, as does currentTime. but isPlaying does not reset to
console.log("currentTimeMs, durationTimeMs", currentTimeMs, durationTimeMs);
if(currentTimeMs == 0 && durationTimeMs == 0) {
if(isPlaying) {
isPlaying = false;
@ -175,9 +225,43 @@
}
}
function setPlaybackMode(mode) {
if(mode == 'preview-to-all') {
playbackMode = PlaybackMode.PreviewToAll;
}
else if(mode == 'preview-to-me') {
playbackMode = PlaybackMode.PrivatePreview;
}
else if(mode == 'eveywhere') {
playbackMode = PlaybackMode.EveryWhere;
}
else {
logger.error("unable to set playback mode", mode);
}
// let the mode change immediately affect the behavior of the stream
if(playbackPlaying) {
stopPlay();
startPlay();
}
}
function startMonitor() {
monitorRecordingPlayback();
}
function stopMonitor() {
if(monitorPlaybackTimeout!= null) {
clearTimeout(monitorPlaybackTimeout);
monitorPlaybackTimeout = null;
}
}
this.update = update;
this.setPlaybackMode = setPlaybackMode;
this.startMonitor = startMonitor;
this.stopMonitor = stopMonitor;
return this;
}

View File

@ -6,14 +6,22 @@
var logger = context.JK.logger;
var rest = context.JK.Rest();
var playbackControls = null;
var recording = null; // deferred object
function resetForm() {
// remove all display errors
$('#recording-finished-dialog form .error-text').remove()
$('#recording-finished-dialog form .error').removeClass("error")
}
function beforeShow() {
if(recording == null) {
alert("recording data should not be null");
app.layout.closeDialog('recordingFinished');
return false;
}
resetForm();
var parentSelector = '#recording-finished-dialog div.genre-selector';
@ -25,26 +33,73 @@
var genreDescription = currentOrLastSession.genres[0];
context.JK.GenreSelectorHelper.setSelectedGenres(parentSelector, [genreDescription]);
}
var localResults = context.jamClient.GetLocalRecordingState({recordings: [recording]});
if(localResults['error']) {
app.notify({
title : "Unable to Open Recording for Playback",
text : localResults['error'],
icon_url: "/assets/content/icon_alert_big.png"
});
}
else {
var localResult = localResults.recordings[0];
if(localResult.aggregate_state == 'MISSING') {
app.notify({
title : "Unable to Open Recording for Playback",
text : "All tracks associated with the recording are missing",
icon_url: "/assets/content/icon_alert_big.png"
});
}
else if(localResult.aggregate_state == 'PARTIALLY_MISSING') {
app.notify({
title : "Unable to Open Recording for Playback",
text: "Some tracks associated with the recording are missing",
icon_url: "/assets/content/icon_alert_big.png"
})
}
else {
// load recording
var openRecordingResult = context.jamClient.OpenRecording(recording);
logger.debug("OpenRecording response: %o", openRecordingResult);
if(openRecordingResult.error) {
app.notify({
"title": "Can't Open Recording",
"text": openRecordingResult.error,
"icon_url": "/assets/content/icon_alert_big.png"
});
}
playbackControls.startMonitor();
}
}
}
function afterHide() {
recording = null;
playbackControls.stopMonitor();
context.jamClient.CloseRecording();
}
function discardRecording(e) {
resetForm();
registerDiscardRecordingHandlers(false);
var recordingId = JK.CurrentSessionModel.recordingModel.currentOrLastRecordingId();
rest.discardRecording({
id: recordingId
id: recording.id
})
.done(function() {
console.error("recording discarded by user. recordingId=%o", recordingId);
console.error("recording discarded by user. recordingId=%o", recording.id);
})
.fail(function(jqXHR){
console.error("recording discard by user failed. recordingId=%o. reason: %o", recordingId, jqXHR.responseText);
console.error("recording discard by user failed. recordingId=%o. reason: %o", recording.id, jqXHR.responseText);
})
.always(function() {
app.layout.closeDialog('recordingFinished')
@ -56,7 +111,6 @@
resetForm();
registerClaimRecordingHandlers(false);
var recordingId = JK.CurrentSessionModel.recordingModel.currentOrLastRecordingId();
var name = $('#recording-finished-dialog form input[name=name]').val();
var description = $('#recording-finished-dialog form textarea[name=description]').val();
@ -65,7 +119,7 @@
var is_downloadable = $('#recording-finished-dialog form input[name=is_downloadable]').is(':checked');
rest.claimRecording({
id : recordingId,
id : recording.id,
name: name,
description: description,
genre: genre,
@ -136,12 +190,12 @@
context.jamClient.SessionStopPlay();
}
function onPlay() {
function onPlay(e, data) {
logger.debug("calling jamClient.SessionStartPlay");
context.jamClient.SessionStartPlay();
context.jamClient.SessionStartPlay(data.playbackMode);
}
function onChangePlayPosition() {
function onChangePlayPosition(e, data) {
logger.debug("calling jamClient.SessionTrackSeekMs(" + data.positionMs + ")");
context.jamClient.SessionTrackSeekMs(data.positionMs);
}
@ -155,6 +209,15 @@
.on('change-position', onChangePlayPosition);
}
function setRecording(recordingData) {
if(recording != null) {
//XXX - prevent start/stop recording mashing; protect this dialog
logger.error("unable to set recording data over existing recording data. this coudld be due to start/stop recording mashing");
return;
}
recording = recordingData;
}
function initialize(){
var dialogBindings = {
'beforeShow' : beforeShow,
@ -170,6 +233,7 @@
this.initialize = initialize;
this.setRecording = setRecording;
}
return this;

View File

@ -13,6 +13,7 @@
var configureTrackDialog;
var addNewGearDialog;
var localRecordingsDialog = null;
var recordingFinishedDialog = null;
var screenActive = false;
var currentMixerRangeMin = null;
var currentMixerRangeMax = null;
@ -25,7 +26,6 @@
var startingRecording = false; // double-click guard
var claimedRecording = null;
var playbackControls = null;
var monitorPlaybackTimeout = null;
var rest = JK.Rest();
@ -364,16 +364,6 @@
.fail(app.ajaxError);
}
function monitorRecordingPlayback() {
var isPlaying = context.jamClient.isSessionTrackPlaying();
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
playbackControls.update(positionMs, durationMs, isPlaying);
monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500);
}
function handleTransitionsInRecordingPlayback() {
// let's see if we detect a transition to start playback or stop playback
@ -382,10 +372,10 @@
if(claimedRecording == null && (currentSession && currentSession.claimed_recording != null)) {
// this is a 'started with a claimed_recording' transition.
// we need to start a timer to watch for the state of the play session
monitorRecordingPlayback();
playbackControls.startMonitor();
}
else if(claimedRecording && (currentSession == null || currentSession.claimed_recording == null)) {
clearTimeout(monitorPlaybackTimeout);
playbackControls.stopMonitor();
}
claimedRecording = currentSession == null ? null : currentSession.claimed_recording;
@ -434,7 +424,7 @@
if ($('.session-recordings .track').length === 0) {
$('.session-recordings .when-empty').show();
$('.session-recording-name-wrapper').hide();
$('.recording-controls').hide();
$('.session-recordings .recording-controls').hide();
}
}
@ -917,14 +907,13 @@
var $destination = $(parentSelector);
$('.session-recordings .when-empty').hide();
$('.session-recording-name-wrapper').show();
$('.recording-controls').show();
$('.session-recordings .recording-controls').show();
var template = $('#template-session-track').html();
var newTrack = $(context.JK.fillTemplate(template, trackData));
$destination.append(newTrack);
if(trackData.preMasteredClass) {
context.JK.helpBubble($('.track-instrument', newTrack), 'pre-processed-track', {}, {offsetParent: newTrack.closest('.content-body')});
}
// Render VU meters and gain fader
@ -1247,6 +1236,7 @@
function promptUserToSave(recordingId) {
rest.getRecording( {id: recordingId} )
.done(function(recording) {
recordingFinishedDialog.setRecording(recording);
app.layout.showDialog('recordingFinished');
})
.fail(app.ajaxError);
@ -1293,9 +1283,9 @@
context.jamClient.SessionStopPlay();
}
function onPlay() {
function onPlay(e, data) {
logger.debug("calling jamClient.SessionStartPlay");
context.jamClient.SessionStartPlay();
context.jamClient.SessionStartPlay(data.playbackMode);
}
function onChangePlayPosition(e, data){
@ -1312,7 +1302,6 @@
}
}
function events() {
$('#session-resync').on('click', sessionResync);
$('#session-contents').on("click", '[action="delete"]', deleteSession);
@ -1330,13 +1319,13 @@
.on('change-position', onChangePlayPosition);
}
this.initialize = function(localRecordingsDialogInstance) {
this.initialize = function(localRecordingsDialogInstance, recordingFinishedDialogInstance) {
localRecordingsDialog = localRecordingsDialogInstance;
recordingFinishedDialog = recordingFinishedDialogInstance;
context.jamClient.SetVURefreshRate(150);
playbackControls = new context.JK.PlaybackControls($('.session-recordings .recording-controls'));
events();
var screenBindings = {
'beforeShow': beforeShow,
'afterShow': afterShow,

View File

@ -38,7 +38,7 @@
function recordedTracks() {
if(currentSession && currentSession.claimed_recording) {
return currentSession.claimed_recording.recorded_tracks
return currentSession.claimed_recording.recording.recorded_tracks
}
else {
return null;

View File

@ -111,20 +111,4 @@
padding:10px;
border-bottom:solid 1px #999;
cursor:pointer;
}
div[layout-id="createSession"] .icheckbuttons {
margin-top:5px;
div.iradio_minimal {
float:left;
}
label {
float:left;
margin:0 10px 0 3px;
}
}
}

View File

@ -460,4 +460,19 @@ div[layout-id=session], div[layout-id=ftue], .no-selection-range {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
}
.icheckbuttons {
margin-top:5px;
div.iradio_minimal {
float:left;
}
label {
float:left;
margin:0 10px 0 3px;
}
}

View File

@ -1,12 +1,20 @@
#recording-finished-dialog {
width:1000px;
height:auto;
div[purpose=description], div[purpose=is_public], div[purpose=is_downloadable] {
margin-top:20px;
}
label[for=is_downloadable], label[for=is_public] {
label[for=is_downloadable], label[for=is_public], label[for=playback-mode-preview-all], label[for=playback-mode-preview-me] {
display:inline;
}
.recording-controls {
position:relative;
}
.icheckbuttons {
margin-top:20px;
}
}

View File

@ -491,6 +491,12 @@ table.vu td {
background-color:#666;
}
.session-mytracks {
.track-connection {
display:none;
}
}
.session-recordings {
.track-connection {
display:none;
@ -513,6 +519,10 @@ table.vu td {
}
}
#recording-finished-dialog .recording-controls {
display:block;
}
.voicechat {
margin-top:10px;

View File

@ -0,0 +1,5 @@
.recording-controls {
.playback-mode-buttons {
display:none;
}
}

View File

@ -24,13 +24,13 @@ class ApiClaimedRecordingsController < ApiController
end
def delete
begin
@claimed_recording.discard(current_user)
render :json => {}, :status => 204
#begin
#@claimed_recording.discard(current_user)
#render :json => {}, :status => 204
# respond_with responder: ApiResponder, :status => 204
rescue
render :json => { :message => "claimed_recording could not be deleted" }, :status => 403
end
#rescue
#render :json => { :message => "claimed_recording could not be deleted" }, :status => 403
#end
end
private

View File

@ -71,7 +71,6 @@ class ApiRecordingsController < ApiController
# claim will create a claimed recording for the creator
def claim
claim = @recording.claim(current_user, params[:name], params[:description], Genre.find_by_id(params[:genre]), params[:is_public], params[:is_downloadable])
claim.save
if claim.errors.any?
response.status = :unprocessable_entity
@ -83,8 +82,7 @@ class ApiRecordingsController < ApiController
# discard will tell the server the user has no interest in the recording
def discard
@recorded_tracks = @recording.recorded_tracks_for_user(current_user)
RecordedTrack.update(@recorded_tracks, :discard => true)
@recording.discard(current_user)
render :json => {}, :status => 200
end

View File

@ -15,13 +15,13 @@ child(:recording => :recording) {
child(:mixes => :mixes) {
attributes :id, :url, :is_completed
}
}
child(:recorded_tracks => :recorded_tracks) {
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
child(:recorded_tracks => :recorded_tracks) {
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
child(:user => :user) {
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
child(:user => :user) {
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
}
}
}

View File

@ -54,13 +54,13 @@ node(:claimed_recording, :if => lambda { |music_session| music_session.users.exi
child(:mixes => :mixes) {
attributes :id, :url, :is_completed
}
}
child(:recorded_tracks => :recorded_tracks) {
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
child(:recorded_tracks => :recorded_tracks) {
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
child(:user => :user) {
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
child(:user => :user) {
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
}
}
}
}

View File

@ -3,12 +3,9 @@ object @recording
attributes :id, :band, :created_at, :duration
child(:recorded_tracks => :recorded_tracks) {
attributes :id, :client_id, :track_id, :user_id, :fully_uploaded, :url
child(:instrument => :instrument) {
attributes :id, :description
}
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
child(:user => :user) {
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
}
}

View File

@ -25,5 +25,11 @@
<!-- current playback time -->
<div class="recording-current">0:00</div>
<div class="playback-mode-buttons icheckbuttons">
<input type="radio" name="playback-mode" checked="checked" value="preview-to-all" class="preview-to-all" /><label for="playback-mode-preview-all" class="radio-text">Preview to All</label>
<input type="radio" name="playback-mode" value="preview-to-me" class="preview-to-me" /><label for="playback-mode-preview-me" class="radio-text">Preview Only to Me</label>
</div>
</div>
<!-- end recording play controls -->

View File

@ -40,6 +40,7 @@
</form>
<div class="left w50 ml30">
Preview Recording:
<%= render "play_controls" %>

View File

@ -97,6 +97,9 @@
var localRecordingsDialog = new JK.LocalRecordingsDialog(JK.app);
localRecordingsDialog.initialize();
var recordingFinishedDialog = new JK.RecordingFinishedDialog(JK.app);
recordingFinishedDialog.initialize();
var friendSelectorDialog = new JK.FriendSelectorDialog(JK.app);
friendSelectorDialog.initialize();
@ -165,14 +168,11 @@
findBandScreen.initialize();
var sessionScreen = new JK.SessionScreen(JK.app);
sessionScreen.initialize(localRecordingsDialog);
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog);
var sessionSettingsDialog = new JK.SessionSettingsDialog(JK.app, sessionScreen);
sessionSettingsDialog.initialize();
var recordingFinishedDialog = new JK.RecordingFinishedDialog(JK.app);
recordingFinishedDialog.initialize();
var whatsNextDialog = new JK.WhatsNextDialog(JK.app);
whatsNextDialog.initialize(invitationDialog);

View File

@ -33,11 +33,11 @@ describe ApiClaimedRecordingsController do
json["recording"]["id"].should == @recording.id
json["recording"]["mixes"].length.should == 0
json["recording"]["band"].should be_nil
json["recorded_tracks"].length.should == 1
json["recorded_tracks"].first["id"].should == @recording.recorded_tracks.first.id
json["recorded_tracks"].first["url"].should == @recording.recorded_tracks.first.url
json["recorded_tracks"].first["instrument"]["id"].should == @instrument.id
json["recorded_tracks"].first["user"]["id"].should == @user.id
json["recording"]["recorded_tracks"].length.should == 1
json["recording"]["recorded_tracks"].first["id"].should == @recording.recorded_tracks.first.id
json["recording"]["recorded_tracks"].first["url"].should == @recording.recorded_tracks.first.url
json["recording"]["recorded_tracks"].first["instrument_id"].should == @instrument.id
json["recording"]["recorded_tracks"].first["user"]["id"].should == @user.id
end
it "should show the right thing when one recording was just uploaded" do