Merge branch 'develop' of bitbucket.org:jamkazam/jam-cloud into develop
This commit is contained in:
commit
2b89cc208b
|
|
@ -123,19 +123,31 @@ module JamRuby
|
|||
|
||||
|
||||
|
||||
|
||||
if query.length == 0
|
||||
[query, nil]
|
||||
elsif query.length < limit
|
||||
[query, nil]
|
||||
else
|
||||
if sort == 'date'
|
||||
[query, query.last.id]
|
||||
if params[:hash]
|
||||
if query.length == 0
|
||||
{ query:query, next: nil}
|
||||
elsif query.length < limit
|
||||
{ query:query, next: nil}
|
||||
else
|
||||
[query, start + limit]
|
||||
if sort == 'date'
|
||||
{ query:query, next: query.last.id}
|
||||
else
|
||||
{ query:query, next: start + limit}
|
||||
end
|
||||
end
|
||||
else
|
||||
if query.length == 0
|
||||
[query, nil]
|
||||
elsif query.length < limit
|
||||
[query, nil]
|
||||
else
|
||||
if sort == 'date'
|
||||
[query, query.last.id]
|
||||
else
|
||||
[query, start + limit]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -345,7 +345,8 @@ module JamRuby
|
|||
|
||||
# meant to be used as a way to 'pluck' a claimed_recording appropriate for user.
|
||||
def candidate_claimed_recording
|
||||
claimed_recordings.where(is_public: true).first
|
||||
#claimed_recordings.where(is_public: true).first
|
||||
claimed_recordings.first
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -103,17 +103,17 @@ module JamRuby
|
|||
|
||||
DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]]
|
||||
|
||||
F_SORT_RECENT = ['Most Recent', :recent]
|
||||
F_SORT_OLDEST = ['Ending Soonest', :ending_soon]
|
||||
F_SORT_LENGTH = ['Session Length', :session_length]
|
||||
F_SORT_RECENT = ['Most Recent', :date]
|
||||
F_SORT_OLDEST = ['Most Liked', :likes]
|
||||
F_SORT_LENGTH = ['Most Played', :plays]
|
||||
F_SORT_OPTS = [F_SORT_RECENT, F_SORT_LENGTH, F_SORT_OLDEST]
|
||||
|
||||
SHOW_BOTH = ['Both', :both]
|
||||
SHOW_SESSIONS = ['Sessions', :sessions]
|
||||
SHOW_RECORDINGS = ['Recordings', :recordings]
|
||||
SHOW_BOTH = ['Sessions & Recordings', :all]
|
||||
SHOW_SESSIONS = ['Sessions', :music_session_history]
|
||||
SHOW_RECORDINGS = ['Recordings', :recording]
|
||||
SHOW_OPTS = [SHOW_BOTH, SHOW_SESSIONS, SHOW_RECORDINGS]
|
||||
|
||||
DATE_OPTS = [['Today', 0], ['This week', 7], ['Past 2 weeks', 14], ['This month', 30], ['Past year', 365], ['All', -1]]
|
||||
DATE_OPTS = [['Today', 'today'], ['This Week', 'week'], ['This Month', 'month'], ['All Time', 'all']]
|
||||
|
||||
def self.order_param(params, keys=M_ORDERING_KEYS)
|
||||
ordering = params[:orderby]
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ else
|
|||
gem 'jam_websockets', "0.1.#{ENV["BUILD_NUMBER"]}"
|
||||
ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true"
|
||||
end
|
||||
gem 'oj'
|
||||
gem 'builder'
|
||||
gem 'rails', '~>3.2.11'
|
||||
gem 'jquery-rails', '2.0.2'
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -26,6 +26,8 @@
|
|||
//= require jquery.easydropdown
|
||||
//= require jquery.scrollTo
|
||||
//= require jquery.infinitescroll
|
||||
//= require jquery.hoverIntent
|
||||
//= require jquery.dotdotdot
|
||||
//= require globals
|
||||
//= require AAB_message_factory
|
||||
//= require AAC_underscore
|
||||
|
|
|
|||
|
|
@ -6,15 +6,366 @@
|
|||
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var currentQuery = null;
|
||||
var currentPage = 0;
|
||||
var LIMIT = 20;
|
||||
var $screen = null;
|
||||
var $next = null;
|
||||
var $scroller = null;
|
||||
var $content = null;
|
||||
var $noMoreFeeds = null;
|
||||
var $refresh = null;
|
||||
var $sortFeedBy = null;
|
||||
var $includeDate = null;
|
||||
var $includeType = null;
|
||||
var next = null;
|
||||
|
||||
function defaultQuery() {
|
||||
var query = { limit:LIMIT, page:currentPage};
|
||||
|
||||
if(next) {
|
||||
query.since = next;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
function buildQuery() {
|
||||
currentQuery = defaultQuery();
|
||||
|
||||
// specify search criteria based on form
|
||||
currentQuery.sort = $sortFeedBy.val();
|
||||
currentQuery.time_range = $includeDate.val();
|
||||
currentQuery.type = $includeType.val();
|
||||
|
||||
return currentQuery;
|
||||
}
|
||||
|
||||
function beforeShow(data) {
|
||||
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
function clearResults() {
|
||||
currentPage = 0;
|
||||
$content.empty(); // TODO: do we need to delete audio elements?
|
||||
$noMoreFeeds.hide();
|
||||
next = null;
|
||||
}
|
||||
|
||||
function handleFeedResponse(response) {
|
||||
next = response.next;
|
||||
|
||||
renderFeeds(response);
|
||||
|
||||
if(response.next == null) {
|
||||
// if we less results than asked for, end searching
|
||||
$scroller.infinitescroll('pause');
|
||||
logger.debug("end of feeds")
|
||||
|
||||
if(currentPage > 0) {
|
||||
$noMoreFeeds.show();
|
||||
// there are bugs with infinitescroll not removing the 'loading'.
|
||||
// it's most noticeable at the end of the list, so whack all such entries
|
||||
$('.infinite-scroll-loader').remove();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentPage++;
|
||||
buildQuery();
|
||||
registerInfiniteScroll();
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
|
||||
clearResults();
|
||||
|
||||
currentQuery = buildQuery();
|
||||
rest.getFeeds(currentQuery)
|
||||
.done(function(response) {
|
||||
handleFeedResponse(response);
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, 'Feed Unavailable')
|
||||
})
|
||||
}
|
||||
|
||||
function registerInfiniteScroll() {
|
||||
|
||||
$scroller.infinitescroll({
|
||||
behavior: 'local',
|
||||
navSelector: '#feedScreen .btn-next-pager',
|
||||
nextSelector: '#feedScreen .btn-next-pager',
|
||||
binder: $scroller,
|
||||
dataType: 'json',
|
||||
appendCallback: false,
|
||||
prefill: false,
|
||||
bufferPx:100,
|
||||
loading: {
|
||||
msg: $('<div class="infinite-scroll-loader">Loading ...</div>'),
|
||||
img: '/assets/shared/spinner.gif'
|
||||
},
|
||||
path: function(page) {
|
||||
return '/api/feeds?' + $.param(buildQuery());
|
||||
}
|
||||
},function(json, opts) {
|
||||
handleFeedResponse(json);
|
||||
});
|
||||
$scroller.infinitescroll('resume');
|
||||
}
|
||||
|
||||
|
||||
function toggleSessionDetails() {
|
||||
var $detailsLink = $(this);
|
||||
var $feedItem = $detailsLink.closest('.feed-entry');
|
||||
var $musicians = $feedItem.find('.musician-detail');
|
||||
var $description = $feedItem.find('.description');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
$feedItem.css('height', $feedItem.height() + 'px')
|
||||
$feedItem.animate({'height': $feedItem.data('original-max-height')}).promise().done(function() {
|
||||
$feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height'));
|
||||
|
||||
$musicians.hide();
|
||||
$description.css('height', $description.data('original-height'));
|
||||
$description.dotdotdot();
|
||||
});
|
||||
}
|
||||
else {
|
||||
$description.trigger('destroy.dot');
|
||||
$description.data('original-height', $description.css('height')).css('height', 'auto');
|
||||
$musicians.show();
|
||||
$feedItem.animate({'max-height': '1000px'});
|
||||
}
|
||||
|
||||
toggledOpen = !toggledOpen;
|
||||
$detailsLink.data('toggledOpen', toggledOpen);
|
||||
return false;
|
||||
}
|
||||
|
||||
function startSessionPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
img.attr('src', '/assets/content/icon_pausebutton.png');
|
||||
$controls.trigger('play.listenBroadcast');
|
||||
$feedItem.data('playing', true);
|
||||
}
|
||||
|
||||
function stopSessionPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
img.attr('src', '/assets/content/icon_playbutton.png');
|
||||
$controls.trigger('pause.listenBroadcast');
|
||||
$feedItem.data('playing', false);
|
||||
}
|
||||
|
||||
function toggleSessionPlay() {
|
||||
var $playLink = $(this);
|
||||
var $feedItem = $playLink.closest('.feed-entry');
|
||||
|
||||
var $status = $feedItem.find('.session-status')
|
||||
var playing = $feedItem.data('playing');
|
||||
|
||||
if(playing) {
|
||||
$status.text('SESSION IN PROGRESS');
|
||||
stopSessionPlay($feedItem);
|
||||
}
|
||||
else {
|
||||
startSessionPlay($feedItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function stateChangeSession(e, data) {
|
||||
var $controls = data.element;
|
||||
var $feedItem = $controls.closest('.feed-entry');
|
||||
var $status = $feedItem.find('.session-status');
|
||||
|
||||
if(data.displayText) $status.text(data.displayText);
|
||||
|
||||
if(data.isEnd) stopSessionPlay();
|
||||
|
||||
if(data.isSessionOver) {
|
||||
$controls.removeClass('inprogress').addClass('ended')
|
||||
}
|
||||
}
|
||||
|
||||
function startRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_pausebutton.png');
|
||||
$controls.trigger('play.listenRecording');
|
||||
$feedItem.data('playing', true);
|
||||
}
|
||||
|
||||
function stopRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_playbutton.png');
|
||||
$controls.trigger('pause.listenRecording');
|
||||
$feedItem.data('playing', false);
|
||||
}
|
||||
|
||||
function toggleRecordingPlay() {
|
||||
|
||||
var $playLink = $(this);
|
||||
var $feedItem = $playLink.closest('.feed-entry');
|
||||
var playing = $feedItem.data('playing');
|
||||
|
||||
if(playing) {
|
||||
stopRecordingPlay($feedItem);
|
||||
}
|
||||
else {
|
||||
startRecordingPlay($feedItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function stateChangeRecording(e, data) {
|
||||
var $controls = data.element;
|
||||
var $feedItem = $controls.closest('.feed-entry');
|
||||
|
||||
var $sliderBar = $('.recording-position', $feedItem);
|
||||
var $statusBar = $('.recording-status', $feedItem);
|
||||
var $currentTime = $('.recording-current', $feedItem);
|
||||
var $status = $('.status-text', $feedItem);
|
||||
var $playButton = $('.play-button', $feedItem);
|
||||
|
||||
if(data.isEnd) stopRecordingPlay($feedItem);
|
||||
if(data.isError) {
|
||||
$sliderBar.hide();
|
||||
$playButton.hide();
|
||||
$currentTime.hide();
|
||||
$statusBar.show();
|
||||
$status.text(data.displayText);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleRecordingDetails() {
|
||||
var $detailsLink = $(this);
|
||||
var $feedItem = $detailsLink.closest('.feed-entry');
|
||||
var $musicians = $feedItem.find('.musician-detail');
|
||||
var $description = $feedItem.find('.description');
|
||||
var $name = $feedItem.find('.name');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
$feedItem.css('height', $feedItem.height() + 'px')
|
||||
$feedItem.animate({'height': $feedItem.data('original-max-height')}).promise().done(function() {
|
||||
$feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height'));
|
||||
|
||||
$musicians.hide();
|
||||
$description.css('height', $description.data('original-height'));
|
||||
$description.dotdotdot();
|
||||
$name.css('height', $name.data('original-height'));
|
||||
$name.dotdotdot();
|
||||
});
|
||||
}
|
||||
else {
|
||||
$description.trigger('destroy.dot');
|
||||
$description.data('original-height', $description.css('height')).css('height', 'auto');
|
||||
$name.trigger('destroy.dot');
|
||||
$name.data('original-height', $name.css('height')).css('height', 'auto');
|
||||
$musicians.show();
|
||||
$feedItem.animate({'max-height': '1000px'});
|
||||
}
|
||||
|
||||
toggledOpen = !toggledOpen;
|
||||
$detailsLink.data('toggledOpen', toggledOpen);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function renderFeeds(feeds) {
|
||||
|
||||
$.each(feeds.entries, function(i, feed) {
|
||||
if(feed.type == 'music_session_history') {
|
||||
var options = {
|
||||
feed_item: feed,
|
||||
status_class: feed['is_over?'] ? 'ended' : 'inprogress',
|
||||
mount_class: feed['has_mount?'] ? 'has-mount' : 'no-mount'
|
||||
}
|
||||
var $feedItem = $(context._.template($('#template-feed-music-session').html(), options, {variable: 'data'}));
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
|
||||
// do everything we can before we attach the item to the page
|
||||
$('.timeago', $feedItem).timeago();
|
||||
context.JK.prettyPrintElements($('.duration', $feedItem).show());
|
||||
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
|
||||
$('.details', $feedItem).click(toggleSessionDetails);
|
||||
$('.details-arrow', $feedItem).click(toggleSessionDetails);
|
||||
$('.play-button', $feedItem).click(toggleSessionPlay);
|
||||
|
||||
// put the feed item on the page
|
||||
renderFeed($feedItem);
|
||||
|
||||
// these routines need the item to have height to work (must be after renderFeed)
|
||||
$controls.listenBroadcast();
|
||||
$controls.bind('statechange.listenBroadcast', stateChangeSession);
|
||||
$('.dotdotdot', $feedItem).dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedItem.css('height'));
|
||||
context.JK.bindHoverEvents($feedItem);
|
||||
}
|
||||
else if(feed.type == 'recording') {
|
||||
if(feed.claimed_recordings.length == 0) {
|
||||
logger.error("a recording in the feed should always have one claimed_recording")
|
||||
return;
|
||||
}
|
||||
var options = {
|
||||
feed_item: feed,
|
||||
candidate_claimed_recording: feed.claimed_recordings[0],
|
||||
mix_class: feed['has_mix?'] ? 'has-mix' : 'no-mix',
|
||||
}
|
||||
|
||||
var $feedItem = $(context._.template($('#template-feed-recording').html(), options, {variable: 'data'}));
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
|
||||
$('.timeago', $feedItem).timeago();
|
||||
context.JK.prettyPrintElements($('.duration', $feedItem));
|
||||
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
|
||||
$('.details', $feedItem).click(toggleRecordingDetails);
|
||||
$('.details-arrow', $feedItem).click(toggleRecordingDetails);
|
||||
$('.play-button', $feedItem).click(toggleRecordingPlay);
|
||||
|
||||
// put the feed item on the page
|
||||
renderFeed($feedItem);
|
||||
|
||||
// these routines need the item to have height to work (must be after renderFeed)
|
||||
$controls.listenRecording({recordingId: feed.id, claimedRecordingId: options.candidate_claimed_recording.id, sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'});
|
||||
$controls.bind('statechange.listenRecording', stateChangeRecording);
|
||||
$('.dotdotdot', $feedItem).dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedItem.css('height'));
|
||||
context.JK.bindHoverEvents($feedItem);
|
||||
}
|
||||
else {
|
||||
logger.warn("skipping feed type: " + feed.type);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function renderFeed(feed) {
|
||||
$content.append(feed);
|
||||
}
|
||||
|
||||
function search() {
|
||||
logger.debug("Searching for feeds...");
|
||||
refresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$refresh.on("click", search);
|
||||
$sortFeedBy.on('change', search);
|
||||
$includeDate.on('change', search);
|
||||
$includeType.on('change', search);
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
|
|
@ -23,6 +374,21 @@
|
|||
};
|
||||
app.bindScreen('feed', screenBindings);
|
||||
|
||||
$screen = $('[layout-id="feed"]');
|
||||
$scroller = $screen.find('.content-body-scroller');
|
||||
$content = $screen.find('.feed-content');
|
||||
$noMoreFeeds = $('#end-of-feeds-list');
|
||||
$refresh = $screen.find('#btn-refresh-feed');
|
||||
$sortFeedBy = $screen.find('#feed_order_by');
|
||||
$includeDate = $screen.find('#feed_date');
|
||||
$includeType = $screen.find('#feed_show');
|
||||
|
||||
// set default search criteria
|
||||
$sortFeedBy.val('date')
|
||||
$includeDate.val('month')
|
||||
$includeType.val('all')
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -618,6 +618,18 @@
|
|||
});
|
||||
}
|
||||
|
||||
function getFeeds(options) {
|
||||
if(!options) { options = {}; }
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
dataType: "json",
|
||||
url: "/api/feeds?" + $.param(options),
|
||||
processData:false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
function sendFriendRequest(app, userId, callback) {
|
||||
var url = "/api/users/" + context.JK.currentUserId + "/friend_requests";
|
||||
$.ajax({
|
||||
|
|
@ -929,6 +941,7 @@
|
|||
this.getClientDownloads = getClientDownloads;
|
||||
this.createEmailInvitations = createEmailInvitations;
|
||||
this.postFeedback = postFeedback;
|
||||
this.getFeeds = getFeeds;
|
||||
this.serverHealthCheck = serverHealthCheck;
|
||||
this.sendFriendRequest = sendFriendRequest;
|
||||
this.acceptFriendRequest = acceptFriendRequest;
|
||||
|
|
|
|||
|
|
@ -347,6 +347,7 @@
|
|||
|
||||
$parent.triggerHandler('statechange.listenRecording',
|
||||
{
|
||||
element: $parent,
|
||||
state: playState,
|
||||
displayText: displayText,
|
||||
isEnd: isEnd,
|
||||
|
|
|
|||
|
|
@ -389,6 +389,7 @@
|
|||
|
||||
$parent.triggerHandler('statechange.listenBroadcast',
|
||||
{
|
||||
element: $parent,
|
||||
state: playState,
|
||||
displayText: displayText,
|
||||
isEnd: isEnd,
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@
|
|||
$element.bt(text, options);
|
||||
}
|
||||
|
||||
context.JK.bindHoverEvents = function ($parent) {
|
||||
context.JK.bindHoverEvents = function ($parent) {
|
||||
|
||||
if($parent) {
|
||||
$parent = $('body');
|
||||
|
|
|
|||
|
|
@ -43,12 +43,16 @@
|
|||
*= require ./leaveSessionWarning
|
||||
*= require ./terms
|
||||
*= require ./createSession
|
||||
*= require ./feed
|
||||
*= require ./genreSelector
|
||||
*= require ./sessionList
|
||||
*= require ./searchResults
|
||||
*= require ./banner
|
||||
*= require ./clientUpdate
|
||||
*= require ./musician
|
||||
*= require web/audioWidgets
|
||||
*= require web/recordings
|
||||
#= require web/sessions
|
||||
*= require jquery.Jcrop
|
||||
*= require icheck/minimal/minimal
|
||||
*/
|
||||
|
|
@ -95,6 +95,10 @@
|
|||
.filter-head {
|
||||
position: absolute;
|
||||
padding:11px 0;
|
||||
|
||||
.btn-refresh-entries {
|
||||
margin-top:7px;
|
||||
}
|
||||
}
|
||||
.filter-body {
|
||||
height:100%;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
#feedScreen {
|
||||
.recording-current {
|
||||
position:absolute; // solves a problem with duration wrapping--only in firefox
|
||||
}
|
||||
}
|
||||
|
|
@ -48,14 +48,6 @@
|
|||
height:20px;
|
||||
}
|
||||
|
||||
#end-of-session-list {
|
||||
display:none;
|
||||
overflow: visibility;
|
||||
margin:40px auto 10px;
|
||||
width:100%;
|
||||
height:20px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.btn-next {
|
||||
display:none;
|
||||
|
|
|
|||
|
|
@ -525,3 +525,17 @@ hr {
|
|||
height: 1px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
// infinitescroll required element
|
||||
.btn-next-pager {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.end-of-list {
|
||||
display:none;
|
||||
overflow: visibility;
|
||||
margin:40px auto 10px;
|
||||
width:100%;
|
||||
height:20px;
|
||||
text-align:center;
|
||||
}
|
||||
|
|
@ -112,6 +112,7 @@
|
|||
|
||||
.feed-entry {
|
||||
.session-controls, .recording-controls {
|
||||
display:inline-block;
|
||||
&.ended {
|
||||
background-color: #471f18;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,15 +3,19 @@ class ApiFeedsController < ApiController
|
|||
respond_to :json
|
||||
|
||||
def index
|
||||
@feeds, @next = Feed.index(current_user,
|
||||
data = Feed.index(current_user,
|
||||
start: params[:since],
|
||||
limit: params[:limit],
|
||||
sort: params[:sort],
|
||||
time_range: params[:time_range],
|
||||
type: params[:type],
|
||||
user: params[:user],
|
||||
band: params[:band])
|
||||
band: params[:band],
|
||||
hash: true)
|
||||
|
||||
|
||||
@feeds = data[:query]
|
||||
@next = data[:next]
|
||||
render "api_feeds/index", :layout => nil
|
||||
end
|
||||
end
|
||||
|
|
@ -7,14 +7,18 @@ module FeedsHelper
|
|||
image_tag resolve_avatarables(music_session_history.band, music_session_history.user)
|
||||
end
|
||||
|
||||
def session_duration(music_session_history, options={})
|
||||
def session_duration_value(music_session_history)
|
||||
if music_session_history.session_removed_at.nil?
|
||||
duration(Time.now - music_session_history.created_at, options)
|
||||
Time.now - music_session_history.created_at
|
||||
else
|
||||
duration(music_session_history.session_removed_at - music_session_history.created_at, options)
|
||||
music_session_history.session_removed_at - music_session_history.created_at
|
||||
end
|
||||
end
|
||||
|
||||
def session_duration(music_session_history, options={})
|
||||
duration(session_duration_value(music_session_history), options)
|
||||
end
|
||||
|
||||
def session_text(music_session_history)
|
||||
if music_session_history.is_over?
|
||||
'SESSION ENDED'
|
||||
|
|
|
|||
|
|
@ -7,8 +7,22 @@ glue :music_session_history do
|
|||
'music_session_history'
|
||||
end
|
||||
|
||||
attributes :id, :description, :genres, :created_at, :session_removed_at, :comment_count, :like_count, :play_count, :fan_access
|
||||
attributes :id, :description, :genres, :created_at, :session_removed_at, :comment_count, :like_count, :play_count, :fan_access, :is_over?, :has_mount?
|
||||
|
||||
node do |history|
|
||||
{
|
||||
helpers: {
|
||||
avatar: asset_path(resolve_avatarables(history.band, history.user)),
|
||||
artist_name: session_artist_name(history),
|
||||
utc_created_at: history.created_at.getutc.iso8601,
|
||||
description: session_description(history),
|
||||
status: session_text(history),
|
||||
duration: session_duration_value(history),
|
||||
duration_secs: history.created_at.to_i,
|
||||
genre: session_genre(history)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
child(:user => :creator) {
|
||||
attributes :id, :first_name, :last_name, :photo_url
|
||||
|
|
@ -17,17 +31,25 @@ glue :music_session_history do
|
|||
child(:unique_user_histories => :participants) {
|
||||
attributes :first_name, :last_name, :photo_url
|
||||
|
||||
node :id do |history|
|
||||
history.user_id
|
||||
node :id do |user|
|
||||
user.user_id
|
||||
end
|
||||
|
||||
node do |user|
|
||||
{
|
||||
helpers: {
|
||||
avatar: asset_path(resolve_avatarables(user))
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# total_duration comes back from the database as a string
|
||||
node :duration do |history|
|
||||
history.total_duration.nil? ? 0 : history.total_duration.to_i
|
||||
node :duration do |user|
|
||||
user.total_duration.nil? ? 0 : user.total_duration.to_i
|
||||
end
|
||||
|
||||
node :instruments do |history|
|
||||
history.total_instruments.nil? ? [] : history.total_instruments.split('|').uniq
|
||||
node :instruments do |user|
|
||||
user.total_instruments.nil? ? [] : user.total_instruments.split('|').uniq
|
||||
end
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +74,20 @@ glue :recording do
|
|||
'recording'
|
||||
end
|
||||
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :has_mix?
|
||||
|
||||
node do |recording|
|
||||
{
|
||||
helpers: {
|
||||
avatar: asset_path(resolve_avatarables(recording.band, recording.owner)),
|
||||
artist_name: recording_artist_name(recording),
|
||||
utc_created_at: recording.created_at.getutc.iso8601,
|
||||
name: recording_name(recording),
|
||||
description: recording_description(recording),
|
||||
genre: recording_genre(recording)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
child(:owner => :owner) {
|
||||
attributes :id, :name, :location, :photo_url
|
||||
|
|
@ -70,6 +105,23 @@ glue :recording do
|
|||
}
|
||||
}
|
||||
|
||||
child(:grouped_tracks => :grouped_tracks) {
|
||||
|
||||
:instrument_ids
|
||||
|
||||
child(:musician => :musician) {
|
||||
attributes :id, :first_name, :last_name, :city, :state, :country, :location, :photo_url
|
||||
|
||||
node do |user|
|
||||
{
|
||||
helpers: {
|
||||
avatar: asset_path(resolve_avatarables(user))
|
||||
}
|
||||
}
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
child(:comments => :comments) {
|
||||
attributes :comment, :created_at
|
||||
|
||||
|
|
@ -80,7 +132,7 @@ glue :recording do
|
|||
|
||||
child(:claimed_recordings => :claimed_recordings) {
|
||||
|
||||
attributes :id, :name, :description, :is_public, :genre_id
|
||||
attributes :id, :name, :description, :is_public, :genre_id, :has_mix?
|
||||
|
||||
child(:user => :creator) {
|
||||
attributes :id, :first_name, :last_name, :photo_url
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%div{ layout: 'screen', :'layout-id' => 'feed', :class => 'screen secondary'}
|
||||
%div{ layout: 'screen', :'layout-id' => 'feed', id: 'feedScreen', :class => 'screen secondary'}
|
||||
.content
|
||||
.content-head
|
||||
.content-icon= image_tag("content/icon_feed.png", {:height => 19, :width => 19})
|
||||
|
|
@ -9,5 +9,7 @@
|
|||
= render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_FEED})
|
||||
.filter-body
|
||||
.content-body-scroller
|
||||
%p This feature not yet implemented
|
||||
.content-wrapper
|
||||
.profile-wrapper
|
||||
.feed-content
|
||||
%a{href: "/api/feeds?page=1", class: "btn-next-pager"}= 'Next'
|
||||
%div{id: 'end-of-feeds-list', class: 'end-of-list'}= 'No more feed entries'
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
There are currently no public sessions.
|
||||
</div>
|
||||
|
||||
<div id="end-of-session-list">
|
||||
<div id="end-of-session-list" class="end-of-list">
|
||||
No more sessions.
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -60,5 +60,11 @@
|
|||
<!-- @end distance filter -->
|
||||
<% end %>
|
||||
<% end -%>
|
||||
|
||||
<% if :feed == filter_label %>
|
||||
<div class="right mr10">
|
||||
<a class="button-grey btn-refresh-entries" href="/client#/feed" id="btn-refresh-feed">REFRESH</a>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
<!-- @end web_filter -->
|
||||
|
|
@ -25,6 +25,8 @@
|
|||
<%= render "bandProfile" %>
|
||||
<%= render "band_setup" %>
|
||||
<%= render "band_setup_photo" %>
|
||||
<%= render "users/feed_music_session_ajax" %>
|
||||
<%= render "users/feed_recording_ajax" %>
|
||||
<%= render "feed" %>
|
||||
<%= render "bands" %>
|
||||
<%= render "musicians" %>
|
||||
|
|
@ -268,6 +270,8 @@
|
|||
var clientUpdate = new JK.ClientUpdate(JK.app)
|
||||
clientUpdate.initialize().check()
|
||||
|
||||
JK.TickDuration('.feed-entry.music-session-history-entry .inprogress .tick-duration');
|
||||
|
||||
JK.JamServer.connect(); // singleton here defined in JamServer.js
|
||||
// this ensures that there is always a CurrentSessionModel, even if it's for a non-active session
|
||||
JK.CurrentSessionModel = new JK.SessionModel(JK.app, JK.JamServer, window.jamClient);
|
||||
|
|
|
|||
|
|
@ -1,48 +1,49 @@
|
|||
%script {type: 'text/javascript'}
|
||||
.feed-entry.music-session-history-entry{'data-music-session' => feed_item.id}
|
||||
%script{type: 'text/template', id: 'template-feed-music-session'}
|
||||
.feed-entry.music-session-history-entry{'data-music-session' => '{{data.feed_item.id}}' }
|
||||
/ avatar
|
||||
.avatar-small.ib
|
||||
= session_avatar(feed_item)
|
||||
%img{ src: '{{data.feed_item.helpers.avatar}}' }
|
||||
/ type and artist
|
||||
.left.ml20.w15
|
||||
.title{hoveraction: 'session', :'session-id' => feed_item.id } SESSION
|
||||
.title{hoveraction: 'session', :'session-id' => '{{data.feed_item.id}}' } SESSION
|
||||
.artist
|
||||
= session_artist_name(feed_item)
|
||||
= timeago(feed_item.created_at, class: 'small created_at')
|
||||
= '{{data.feed_item.helpers.artist_name}}'
|
||||
%time.small.created_at.timeago{datetime: '{{data.feed_item.helpers.utc_created_at}}'}= '{{data.feed_item.created_at}}'
|
||||
/ name and description
|
||||
.left.ml20.w30
|
||||
.description.dotdotdot
|
||||
= session_description(feed_item)
|
||||
= '{{data.feed_item.helpers.description}}'
|
||||
/ timeline and controls
|
||||
.right.w40
|
||||
/ recording play controls
|
||||
.session-controls{ class: "#{(feed_item.is_over? ? 'ended' : 'inprogress')} #{feed_item.has_mount? ? 'has-mount' : 'no-mount'}", 'data-music-session' => feed_item.id, 'fan-access' => feed_item.fan_access.to_s}
|
||||
.session-controls{class:'{{data.status_class}} {{data.mount_class}}', :'data-music-session' => '{{data.feed_item.id}}', 'fan-access' => '{{data.feed_item.fan_access}}'}
|
||||
/ session status
|
||||
%a.left.play-button{href:'#'}
|
||||
= image_tag 'content/icon_playbutton.png', width:20, height:20, class:'play-icon'
|
||||
- if feed_item.has_mount?
|
||||
%audio{preload: 'none'}
|
||||
%source{src: feed_item.music_session.mount.url, type: feed_item.music_session.mount.resolve_string(:mime_type)}
|
||||
= "{% if(data.feed_item['has_mount?']) { %}"
|
||||
%audio{preload: 'none'}
|
||||
%source{src: '{{data.feed_item.music_session.mount.url}}', type: '{{data.feed_item.music_session.mime_type}}'}
|
||||
= '{% } %}'
|
||||
%span.session-status
|
||||
= session_text(feed_item)
|
||||
= '{{data.feed_item.helpers.status}}'
|
||||
/ current playback time
|
||||
= session_duration(feed_item, class: 'session-duration tick-duration recording-current', 'data-created-at' => feed_item.created_at.to_i)
|
||||
%time{class: 'session-duration tick-duration recording-current duration', 'data-created-at' => '{{data.feed_item.helpers.duration_secs}}', 'duration' => '{{data.feed_item.helpers.duration}}'}
|
||||
= '{{data.feed_item.helpers.duration}}'
|
||||
/ end recording play controls
|
||||
/ genre and social
|
||||
.left.small
|
||||
= session_genre(feed_item)
|
||||
.left.small= '{{data.feed_item.helpers.genre}}'
|
||||
.right.small.feed-details
|
||||
%span.play-count
|
||||
%span.plays
|
||||
= feed_item.play_count
|
||||
= '{{data.feed_item.play_count}}'
|
||||
= image_tag 'content/icon_arrow.png', :height => "12", :width => "7"
|
||||
%span.comment-count
|
||||
%span.comments
|
||||
= feed_item.comment_count
|
||||
= '{{data.feed_item.comment_count}}'
|
||||
= image_tag 'content/icon_comment.png', :height => "12", :width => "13"
|
||||
%span.like-count
|
||||
%span.likes
|
||||
= feed_item.like_count
|
||||
= '{{data.feed_item.comment_count}}'
|
||||
= image_tag 'content/icon_like.png', :height => "12", :width => "12"
|
||||
%a.details{:href => "#"} Details
|
||||
%a.details-arrow.arrow-down-orange{:href => "#"}
|
||||
|
|
@ -51,22 +52,24 @@
|
|||
/ sub-table of musicians
|
||||
%table.musicians{:cellpadding => "0", :cellspacing => "5"}
|
||||
%tbody
|
||||
- feed_item.unique_user_histories.each do |user|
|
||||
%tr
|
||||
%td{:width => "24"}
|
||||
%a.avatar-tiny{:href => "#"}
|
||||
= render_avatarable(user)
|
||||
%td
|
||||
%a{:href => "#"}
|
||||
= "#{user.first_name} #{user.last_name}"
|
||||
%td
|
||||
.nowrap
|
||||
- if user.total_instruments
|
||||
- user.total_instruments.split('|').uniq.each do |instrument_id|
|
||||
%img.instrument-icon{'instrument-id' =>instrument_id, height:24, width:24}
|
||||
- else
|
||||
%img.instrument-icon{'instrument-id' =>'default', height:24, width:24}
|
||||
|
||||
= '{% _.each(data.feed_item.participants, function(user) { %}'
|
||||
%tr
|
||||
%td{:width => "24"}
|
||||
%a.avatar-tiny{:href => "#"}
|
||||
%img{src: '{{user.helpers.avatar}}'}
|
||||
%td
|
||||
%a{:href => "#"}
|
||||
= '{{user.first_name}} {{user.last_name}}'
|
||||
%td
|
||||
.nowrap
|
||||
= '{% if(user.total_instruments) { %}'
|
||||
= '{% _.each(_.uniq(user.total_instruments), function(instrument_id) { %}'
|
||||
%img.instrument-icon{'instrument-id' =>'{{instrument_id}}', height:24, width:24}
|
||||
= '{% }) %}'
|
||||
= '{% } else { %}'
|
||||
%img.instrument-icon{'instrument-id' =>'default', height:24, width:24}
|
||||
= '{% } %}'
|
||||
= '{% }) %}'
|
||||
|
||||
%br{:clear => "all"}/
|
||||
%br/
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
%script{type: 'text/template', id: 'template-feed-recording'}
|
||||
.feed-entry.recording-entry{:'data-claimed-recording-id' => '{{data.candidate_claimed_recording.id}}' }
|
||||
/ avatar
|
||||
.avatar-small.ib
|
||||
%img{ src: '{{data.feed_item.helpers.avatar}}' }
|
||||
/ type and artist
|
||||
.left.ml20.w15
|
||||
.title{hoveraction: 'recording', :'recording-id' => '{{data.candidate_claimed_recording.id}}' } RECORDING
|
||||
.artist
|
||||
= '{{data.feed_item.helpers.artist_name}}'
|
||||
%time.small.created_at.timeago{datetime: '{{data.feed_item.helpers.utc_created_at}}'}
|
||||
= '{{data.feed_item.created_at}}'
|
||||
/ name and description
|
||||
.left.ml20.w30
|
||||
.name.dotdotdot
|
||||
= '{{data.feed_item.helpers.name}}'
|
||||
.description.dotdotdot
|
||||
= '{{data.feed_item.helpers.description}}'
|
||||
/ timeline and controls
|
||||
.right.w40
|
||||
/ recording play controls
|
||||
.recording-controls{ class: '{{data.mix_class}}'}
|
||||
/ play button
|
||||
%a.left.play-button{:href => "#"}
|
||||
= image_tag 'content/icon_playbutton.png', width:20, height:20, class:'play-icon'
|
||||
= "{% if(data.feed_item['has_mix?']) { %}"
|
||||
%audio{preload: 'none'}
|
||||
%source{src: '{{data.candidate_claimed_recording.mix.mp3_url}}', type:'audio/mpeg'}
|
||||
%source{src: '{{data.candidate_claimed_recording.mix.ogg_url}}', type:'audio/ogg'}
|
||||
= "{% } %}"
|
||||
.recording-status
|
||||
%span.status-text STILL MIXING
|
||||
.recording-duration
|
||||
%time{class: 'tick-duration duration', duration: '{{data.feed_item.duration}}'}
|
||||
= '{{data.feed_item.duration}}'
|
||||
/ playback position
|
||||
.recording-position
|
||||
/ start time
|
||||
.recording-time 0:00
|
||||
/ playback background & slider
|
||||
.recording-playback
|
||||
.recording-slider
|
||||
= image_tag 'content/slider_playcontrols.png', width:5, height:16
|
||||
/ end time
|
||||
.recording-time.recording-duration
|
||||
%time{class: 'tick-duration duration', duration: '{{data.feed_item.duration}}'}
|
||||
= '{{data.feed_item.duration}}'
|
||||
/ end playback position
|
||||
/ current playback time
|
||||
.recording-current
|
||||
0:00
|
||||
/ end recording play controls
|
||||
/ genre and social
|
||||
.left.small= '{{data.feed_item.helpers.genre}}'
|
||||
.right.small.feed-details
|
||||
%span.play-count
|
||||
%span.plays
|
||||
= '{{data.feed_item.play_count}}'
|
||||
= image_tag 'content/icon_arrow.png', :height => "12", :width => "7"
|
||||
%span.comment-count
|
||||
%span.comments
|
||||
= '{{data.feed_item.comment_count}}'
|
||||
= image_tag 'content/icon_comment.png', :height => "12", :width => "13"
|
||||
%span.like-count
|
||||
%span.likes
|
||||
= '{{data.feed_item.like_count}}'
|
||||
= image_tag 'content/icon_like.png', :height => "12", :width => "12"
|
||||
%a.details{:href => "#"} Details
|
||||
%a.details-arrow.arrow-down-orange{:href => "#"}
|
||||
%br/
|
||||
.musician-detail.hidden
|
||||
/ sub-table of musicians
|
||||
%table.musicians{:cellpadding => "0", :cellspacing => "5"}
|
||||
%tbody
|
||||
= '{% _.each(data.feed_item.grouped_tracks, function(track) { %}'
|
||||
%tr
|
||||
%td{:width => "24"}
|
||||
%a.avatar-tiny{:href => "#"}
|
||||
%img{src: '{{track.musician.helpers.avatar}}'}
|
||||
%td
|
||||
%a{:href => "#"}
|
||||
= '{{track.musician.first_name}} {{track.musician.last_name}}'
|
||||
%td
|
||||
.nowrap
|
||||
= '{% if(track.instrument_ids) { %}'
|
||||
= '{% _.each(_.uniq(track.instrument_ids), function(instrument_id) { %}'
|
||||
%img.instrument-icon{'instrument-id' =>'{{instrument_id}}', height:24, width:24}
|
||||
= '{% }) %}'
|
||||
= '{% } else { %}'
|
||||
%img.instrument-icon{'instrument-id' =>'default', height:24, width:24}
|
||||
= '{% } %}'
|
||||
= '{% }) %}'
|
||||
|
||||
%br{:clear => "all"}/
|
||||
%br/
|
||||
|
|
@ -60,7 +60,7 @@ SampleApp::Application.routes.draw do
|
|||
|
||||
match '/gmail_contacts', to: 'gmail#gmail_contacts'
|
||||
|
||||
match '/events/:slug', to: 'events#show', :via => :get
|
||||
match '/events/:slug', to: 'events#show', :via => :get, :as => 'event'
|
||||
|
||||
# temporarily allow for debugging--only allows admini n
|
||||
match '/listen_in', to: 'spikes#listen_in'
|
||||
|
|
|
|||
Loading…
Reference in New Issue