Skip to content

Commit

Permalink
Register the playlist file tab view in the Files app also on NC28
Browse files Browse the repository at this point in the history
The old API for registration is no longer available on NC28 and a new
one has to be used. The core functionality of the view is now
implemented in our stand-alone class, not inheriting any core interface.
It is then just wrapped differently depending on the cloud version used.

What doesn't currently work on NC28, is starting playback of a new list
by clicking a song name in the playlist tab view. This still works on
the older clouds, though.
  • Loading branch information
paulijar committed Dec 30, 2023
1 parent 666c353 commit 8761ea7
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 87 deletions.
2 changes: 1 addition & 1 deletion js/embedded/embeddedplayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ OCA.Music.EmbeddedPlayer = function(onClose, onNext, onPrev, onMenuOpen, onShowL
playlistNumberText = $(document.createElement('span'));
area.append(playlistNumberText);

if (typeof OCA.Music.PlaylistTabView != 'undefined') {
if (typeof OCA.Music.playlistTabView != 'undefined') {
let menuContainer = $(document.createElement('div')).attr('id', 'menu-container');
// "more" button which toggles the popup menu open/closed
menuContainer.append($(document.createElement('button'))
Expand Down
202 changes: 116 additions & 86 deletions js/embedded/playlisttabview.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,104 +11,134 @@
OCA.Music = OCA.Music || {};

OCA.Music.initPlaylistTabView = function(playlistMimes) {
if (typeof OCA.Files.DetailTabView != 'undefined') {
OCA.Music.PlaylistTabView = OCA.Files.DetailTabView.extend({
id: 'musicPlaylistTabView',
className: 'tab musicPlaylistTabView',

getLabel: function() {
return t('music', 'Playlist');
},

getIcon: function() {
return 'icon-music';
},

render: function() {
let container = this.$el;
container.empty(); // erase any previous content

let fileInfo = this.getFileInfo();

if (fileInfo) {

let loadIndicator = $(document.createElement('div')).attr('class', 'loading');
container.append(loadIndicator);

let onPlaylistLoaded = (data) => {
loadIndicator.hide();
class PlaylistTabView {
id = 'musicPlaylistTabView';
name = t('music', 'Playlist');
icon = 'icon-music';
$el = null;
fileInfo = null;

let list = $(document.createElement('ol'));
container.append(list);

let titleForFile = function(file) {
return file.caption || OCA.Music.Utils.titleFromFilename(file.name);
};

let tooltipForFile = function(file) {
return file.path ? `${file.path}/${file.name}` : file.url;
};

for (let i = 0; i < data.files.length; ++i) {
list.append($(document.createElement('li'))
.attr('id', 'music-playlist-item-' + i)
.text(titleForFile(data.files[i]))
.prop('title', tooltipForFile(data.files[i])));
}

// click handler
list.on('click', 'li', (event) => {
let id = event.target.id;
let idx = parseInt(id.split('-').pop());
this.trigger('playlistItemClick', fileInfo.id, fileInfo.attributes.name, idx);
});

if (data.invalid_paths.length > 0) {
container.append($(document.createElement('p')).text(t('music', 'Some files on the playlist were not found') + ':'));
let failList = $(document.createElement('ul'));
container.append(failList);

for (let i = 0; i < data.invalid_paths.length; ++i) {
failList.append($(document.createElement('li')).text(data.invalid_paths[i]));
}
}

this.trigger('rendered');
enabled(fileInfo) {
if (!fileInfo || fileInfo.isDirectory()) {
return false;
}
const mimetype = fileInfo.get('mimetype');
return (mimetype && playlistMimes.indexOf(mimetype) > -1);
}

populate(fileInfo) {
this.$el.empty(); // erase any previous content
this.fileInfo = fileInfo;

if (fileInfo) {

let loadIndicator = $(document.createElement('div')).attr('class', 'loading');
this.$el.append(loadIndicator);

let onPlaylistLoaded = (data) => {
loadIndicator.hide();

let list = $(document.createElement('ol'));
this.$el.append(list);

let titleForFile = function(file) {
return file.caption || OCA.Music.Utils.titleFromFilename(file.name);
};

let onError = function(_error) {
loadIndicator.hide();
container.append($(document.createElement('p')).text(t('music', 'Error reading playlist file')));

let tooltipForFile = function(file) {
return file.path ? `${file.path}/${file.name}` : file.url;
};

for (let i = 0; i < data.files.length; ++i) {
list.append($(document.createElement('li'))
.attr('id', 'music-playlist-item-' + i)
.text(titleForFile(data.files[i]))
.prop('title', tooltipForFile(data.files[i])));
}

// click handler
list.on('click', 'li', (event) => {
let id = event.target.id;
let idx = parseInt(id.split('-').pop());
this.trigger('playlistItemClick', fileInfo.id, fileInfo.attributes?.name ?? fileInfo.name, idx);
});

if (data.invalid_paths.length > 0) {
this.$el.append($(document.createElement('p')).text(t('music', 'Some files on the playlist were not found') + ':'));
let failList = $(document.createElement('ul'));
this.$el.append(failList);

for (let i = 0; i < data.invalid_paths.length; ++i) {
failList.append($(document.createElement('li')).text(data.invalid_paths[i]));
}
}

this.trigger('rendered');
};

let onError = function(_error) {
loadIndicator.hide();
this.$el.append($(document.createElement('p')).text(t('music', 'Error reading playlist file')));
};

OCA.Music.PlaylistFileService.readFile(fileInfo.id, onPlaylistLoaded, onError);
}
}

OCA.Music.PlaylistFileService.readFile(fileInfo.id, onPlaylistLoaded, onError);
}
},

canDisplay: function(fileInfo) {
if (!fileInfo || fileInfo.isDirectory()) {
return false;
}
let mimetype = fileInfo.get('mimetype');
setCurrentTrack(playlistId, trackIndex) {
this.$el.find('ol li.current').removeClass('current');
if (this.fileInfo && this.fileInfo.id == playlistId) {
this.$el.find('ol li#music-playlist-item-' + trackIndex).addClass('current');
}
}
}
_.extend(PlaylistTabView.prototype, OC.Backbone.Events);

return (mimetype && playlistMimes.indexOf(mimetype) > -1);
},
// Registration before NC28
if (OCA.Files?.DetailTabView) {
OCA.Music.playlistTabView = new PlaylistTabView();

setCurrentTrack: function(playlistId, trackIndex) {
this.$el.find('ol li.current').removeClass('current');
let fileInfo = this.getFileInfo();
if (fileInfo && fileInfo.id == playlistId) {
this.$el.find('ol li#music-playlist-item-' + trackIndex).addClass('current');
}
const WrappedPlaylistTabView = OCA.Files.DetailTabView.extend({
id: OCA.Music.playlistTabView.id,
className: 'tab musicPlaylistTabView',
getLabel: () => OCA.Music.playlistTabView.name,
getIcon: () => OCA.Music.playlistTabView.icon,
canDisplay: OCA.Music.playlistTabView.enabled,
render: function() {
OCA.Music.playlistTabView.$el = this.$el;
OCA.Music.playlistTabView.populate(this.getFileInfo());
}
});
_.extend(OCA.Music.PlaylistTabView.prototype, OC.Backbone.Events);
OCA.Music.playlistTabView = new OCA.Music.PlaylistTabView();

OC.Plugins.register('OCA.Files.FileList', {
attach: function(fileList) {
fileList.registerTabView(OCA.Music.playlistTabView);
fileList.registerTabView(new WrappedPlaylistTabView());
}
});
}

// Registration after NC28
else if (OCA.Files?.Sidebar) {
OCA.Music.playlistTabView = new PlaylistTabView();

OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
id: OCA.Music.playlistTabView.id,
name: OCA.Music.playlistTabView.name,
icon: OCA.Music.playlistTabView.icon,

async mount(el, fileInfo, _context) {
OCA.Music.playlistTabView.$el = $(el);
OCA.Music.playlistTabView.$el.addClass('musicPlaylistTabView');
OCA.Music.playlistTabView.populate(fileInfo);
},
update(fileInfo) {
OCA.Music.playlistTabView.populate(fileInfo);
},
destroy() {
},
enabled(fileInfo) {
return OCA.Music.playlistTabView.enabled(fileInfo);
},
}));
}
};

0 comments on commit 8761ea7

Please sign in to comment.