diff --git a/dashboard-ui/bower_components/iron-meta/.bower.json b/dashboard-ui/bower_components/iron-meta/.bower.json index 8119ebcf41..9e650790be 100644 --- a/dashboard-ui/bower_components/iron-meta/.bower.json +++ b/dashboard-ui/bower_components/iron-meta/.bower.json @@ -25,14 +25,14 @@ "web-component-tester": "*", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" }, - "homepage": "https://github.com/polymerelements/iron-meta", + "homepage": "https://github.com/PolymerElements/iron-meta", "_release": "1.0.3", "_resolution": { "type": "version", "tag": "v1.0.3", "commit": "91529259262b0d8f33fed44bc3fd47aedf35cb04" }, - "_source": "git://github.com/polymerelements/iron-meta.git", + "_source": "git://github.com/PolymerElements/iron-meta.git", "_target": "^1.0.0", - "_originalSource": "polymerelements/iron-meta" + "_originalSource": "PolymerElements/iron-meta" } \ No newline at end of file diff --git a/dashboard-ui/cordova/chromecast.js b/dashboard-ui/cordova/chromecast.js index 0c7807bcfc..d1f14013d3 100644 --- a/dashboard-ui/cordova/chromecast.js +++ b/dashboard-ui/cordova/chromecast.js @@ -282,7 +282,8 @@ "SetAudioStreamIndex", "SetSubtitleStreamIndex", "DisplayContent", - "SetRepeatMode" + "SetRepeatMode", + "EndSession" ]; return target; @@ -664,6 +665,17 @@ } }; + self.endSession = function () { + + if (currentDevice) { + currentDevice.disconnect(); + } + + cleanupSession(); + currentDevice = null; + currentDeviceId = null; + }; + $(MediaController).on('playerchange', function (e, newPlayer, newTarget) { if (newTarget.id != currentDeviceId) { @@ -675,7 +687,6 @@ cleanupSession(); currentDevice = null; currentDeviceId = null; - self.lastPlayerData = {}; } } }); diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index 74daf517b8..e8933e399c 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -421,6 +421,10 @@ span.itemCommunityRating:not(:empty) + .userDataIcons { margin-top: 0 !important; } +.backdropPage .noBackdrop { + background-color: transparent; +} + .itemBackdropContent { position: absolute; bottom: 0; diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 1cca91a594..4f4e688400 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -705,7 +705,8 @@ "SetAudioStreamIndex", "SetSubtitleStreamIndex", "DisplayContent", - "SetRepeatMode"] + "SetRepeatMode", + "EndSession"] }; }; @@ -778,6 +779,11 @@ }); }; + self.endSession = function () { + + castPlayer.stopApp(); + }; + self.volumeUp = function () { castPlayer.sendMessage({ diff --git a/dashboard-ui/scripts/itemdetailpage.js b/dashboard-ui/scripts/itemdetailpage.js index 17736d04f5..dc3bb59e1a 100644 --- a/dashboard-ui/scripts/itemdetailpage.js +++ b/dashboard-ui/scripts/itemdetailpage.js @@ -68,10 +68,13 @@ renderDetails(page, item, context); var hasBackdrop = LibraryBrowser.renderDetailPageBackdrop(page, item); - //$('#itemBackdrop', page).addClass('noBackdrop').css('background-image', 'none'); - //Backdrops.setBackdrops(page, [item]); + // For these types, make the backdrop a little smaller so that the items are more quickly accessible - if (item.Type == "Season" || item.Type == "MusicArtist" || item.Type == "MusicAlbum" || item.Type == "Series" || item.Type == "Playlist" || item.Type == "BoxSet") { + if (item.Type == 'MusicArtist' || item.Type == "MusicAlbum" || item.Type == "Playlist" || item.Type == "BoxSet" || item.Type == "Audio") { + $('#itemBackdrop', page).addClass('noBackdrop').css('background-image', 'none'); + Backdrops.setBackdrops(page, [item]); + } + else if (item.Type == "Season" || item.Type == "Series") { page.querySelector('#itemBackdrop').classList.add('smallBackdrop'); } else { page.querySelector('#itemBackdrop').classList.remove('smallBackdrop'); @@ -411,7 +414,7 @@ var topOverview = page.querySelector('.topOverview'); var bottomOverview = page.querySelector('.bottomOverview'); - var seasonOnBottom = screen.availHeight < 600 || screen.availWidth < 600; + var seasonOnBottom = screen.availHeight < 800 || screen.availWidth < 600; if (item.Type == 'MusicAlbum' || item.Type == 'MusicArtist' || (item.Type == 'Season' && seasonOnBottom) || (item.Type == 'Series' && seasonOnBottom)) { LibraryBrowser.renderOverview([bottomOverview], item); @@ -647,14 +650,20 @@ return; } + var shape = item.Type == "MusicAlbum" || item.Type == "MusicArtist" ? "detailPageSquare" : "detailPagePortrait"; var screenWidth = $(window).width(); + var screenHeight = $(window).height(); var options = { userId: Dashboard.getCurrentUserId(), - limit: screenWidth > 800 ? 5 : 4, + limit: screenWidth > 800 && shape == "detailPagePortrait" ? 5 : 4, fields: "PrimaryImageAspectRatio,UserData,SyncInfo" }; + if (screenWidth >= 800 && screenHeight >= 1000) { + options.limit *= 2; + } + ApiClient.getSimilarItems(item.Id, options).done(function (result) { if (!result.Items.length) { @@ -669,7 +678,7 @@ var html = LibraryBrowser.getPosterViewHtml({ items: result.Items, - shape: item.Type == "MusicAlbum" || item.Type == "MusicArtist" ? "detailPageSquare" : "detailPagePortrait", + shape: shape, showParentTitle: item.Type == "MusicAlbum", centerText: true, showTitle: item.Type == "MusicAlbum" || item.Type == "Game" || item.Type == "MusicArtist", diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index 11fd603142..2f93b66c2a 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -64,119 +64,110 @@ }); } - function getTargetsHtml(targets) { + function showPlayerSelection() { var playerInfo = MediaController.getPlayerInfo(); - var html = ''; - html += '
'; - - html += '

' + Globalize.translate('HeaderSelectPlayer') + '

'; - html += '
'; - - var checkedHtml; - - for (var i = 0, length = targets.length; i < length; i++) { - - var target = targets[i]; - - var id = 'radioPlayerTarget' + i; - - var isChecked = target.id == playerInfo.id; - checkedHtml = isChecked ? ' checked="checked"' : ''; - - var mirror = (!target.isLocalPlayer && target.supportedCommands.indexOf('DisplayContent') != -1) ? 'true' : 'false'; - - html += ''; - html += ''; + if (!playerInfo.isLocalPlayer) { + showActivePlayerMenu(playerInfo); + return; } - html += '
'; + Dashboard.showModalLoadingMsg(); - html += '

' + Globalize.translate('LabelAllPlaysSentToPlayer') + '

'; + MediaController.getTargets().done(function (targets) { - checkedHtml = MediaController.enableDisplayMirroring() ? ' checked="checked"' : ''; + var menuItems = targets.map(function (t) { - html += '
'; + var name = t.name; - html += '
'; + if (t.appName && t.appName != t.name) { + name += " - " + t.appName; + } - return html; + return { + name: name, + id: t.id, + ironIcon: 'tablet-android' + }; + + }); + + require(['actionsheet'], function () { + + Dashboard.hideModalLoadingMsg(); + + ActionSheetElement.show({ + title: Globalize.translate('HeaderSelectPlayer'), + items: menuItems, + callback: function (id) { + + var target = targets.filter(function (t) { + return t.id == id; + })[0]; + + MediaController.trySetActivePlayer(target.playerName, target); + + mirrorIfEnabled(); + } + }); + }); + }); } - function showPlayerSelection() { + function showActivePlayerMenu(playerInfo) { - var promise = MediaController.getTargets(); + var id = 'dlg' + new Date().getTime(); + var html = ''; - var html = '
'; + var style = ""; - html += '
'; + html += ''; - html += '
'; - html += '

' + Globalize.translate('ButtonRemoteControl') + '

'; + html += '

'; + html += (playerInfo.deviceName || playerInfo.name); + html += '

'; + + html += '
'; + + if (playerInfo.supportedCommands.indexOf('DisplayContent') != -1) { + + html += '
'; + var checkedHtml = MediaController.enableDisplayMirroring() ? ' checked' : ''; + html += '' + Globalize.translate('OptionEnableDisplayMirroring') + ''; + html += '
'; + } html += '
'; + html += '
'; + html += '' + Globalize.translate('ButtonRemoteControl') + ''; + html += '' + Globalize.translate('ButtonDisconnect') + ''; + html += '' + Globalize.translate('ButtonCancel') + ''; + html += '
'; + + html += '
'; + $(document.body).append(html); - require(['jqmicons']); + setTimeout(function () { - var elem = $('#playerSelectionPanel').panel({}).trigger('create').panel("open").on("panelclose", function () { + var dlg = document.getElementById(id); - $(this).off("panelclose").remove(); - }); + $('.chkMirror', dlg).on('change', onMirrorChange); - promise.done(function (targets) { - - $('.players', elem).html(getTargetsHtml(targets)).trigger('create'); - - $('.chkEnableMirrorMode', elem).on('change', function () { - MediaController.enableDisplayMirroring(this.checked); + dlg.open(); + // Has to be assigned a z-index after the call to .open() + $(dlg).on('iron-overlay-closed', function () { + $(this).remove(); }); - $('.radioSelectPlayerTarget', elem).off('change').on('change', function () { + }, 100); + } - var supportsMirror = this.getAttribute('data-mirror') == 'true'; - - if (supportsMirror) { - $('.fldMirrorMode', elem).show(); - } else { - $('.fldMirrorMode', elem).hide(); - } - - var playerName = this.getAttribute('data-playername'); - var targetId = this.getAttribute('data-targetid'); - var targetName = this.getAttribute('data-targetname'); - var deviceName = this.getAttribute('data-deviceName'); - var playableMediaTypes = this.getAttribute('data-mediatypes').split(','); - var supportedCommands = this.getAttribute('data-commands').split(','); - - MediaController.trySetActivePlayer(playerName, { - id: targetId, - name: targetName, - playableMediaTypes: playableMediaTypes, - supportedCommands: supportedCommands, - deviceName: deviceName - - }); - - mirrorIfEnabled(); - - }); - - if ($('.radioSelectPlayerTarget:checked', elem)[0].getAttribute('data-mirror') == 'true') { - $('.fldMirrorMode', elem).show(); - } else { - $('.fldMirrorMode', elem).hide(); - } - }); + function onMirrorChange() { + MediaController.enableDisplayMirroring(this.checked); } function bindKeys(controller) { @@ -369,6 +360,36 @@ } }; + self.disconnectFromPlayer = function () { + + var playerInfo = self.getPlayerInfo(); + + if (playerInfo.supportedCommands.indexOf('EndSession') != -1) { + + var options = { + callback: function (result) { + + if (result == 0) { + MediaController.getCurrentPlayer().endSession(); + } + + if (result != 2) { + self.setDefaultPlayerActive(); + } + }, + message: Globalize.translate('ConfirmEndPlayerSession'), + title: Globalize.translate('HeaderDisconnectFromPlayer'), + buttons: [Globalize.translate('ButtonYes'), Globalize.translate('ButtonNo'), Globalize.translate('ButtonCancel')] + }; + + Dashboard.dialog(options); + + } else { + + self.setDefaultPlayerActive(); + } + }; + self.getPlayers = function () { return players; }; diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index ae989c75d1..2fcf6d1510 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -20,7 +20,6 @@ $.support.cors = true; $(document).one('click', WebNotifications.requestPermission); var Dashboard = { - jQueryMobileInit: function () { // Page @@ -96,7 +95,7 @@ var Dashboard = { var url = getWindowUrl().toLowerCase(); return url.indexOf('mediabrowser.tv') != -1 || - url.indexOf('emby.media') != -1; + url.indexOf('emby.media') != -1; }, isRunningInCordova: function () { @@ -244,8 +243,7 @@ var Dashboard = { if (document.createStyleSheet) { document.createStyleSheet(url); - } - else { + } else { var link = document.createElement('link'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('type', 'text/css'); @@ -599,6 +597,75 @@ var Dashboard = { } }, + dialog: function (options) { + + var title = options.title; + var message = options.message; + var buttons = options.buttons; + var callback = options.callback; + + // Cordova + if (navigator.notification && navigator.notification.confirm && message.indexOf('<') == -1) { + + navigator.notification.confirm(message, function (index) { + + callback(index); + + }, title, buttons.join(',')); + + } else { + Dashboard.dialogInternal(message, title, buttons, callback); + } + }, + + dialogInternal: function (message, title, buttons, callback) { + + var id = 'paperdlg' + new Date().getTime(); + + var html = ''; + html += '

' + title + '

'; + html += '
' + message + '
'; + html += '
'; + + var index = 0; + html += buttons.map(function (b) { + + var dataIndex = ' data-index="' + index + '"'; + index++; + return '' + b + ''; + + }).join(''); + + html += '
'; + html += '
'; + + $(document.body).append(html); + + // This timeout is obviously messy but it's unclear how to determine when the webcomponent is ready for use + // element onload never fires + setTimeout(function () { + + var dlg = document.getElementById(id); + + $('.dialogButton', dlg).on('click', function () { + + if (callback) { + callback(parseInt(this.getAttribute('data-index'))); + } + + }); + + // Has to be assigned a z-index after the call to .open() + $(dlg).on('iron-overlay-closed', function (e) { + + this.parentNode.removeChild(this); + }); + + dlg.open(); + + }, 300); + }, + confirm: function (message, title, callback) { // Cordova @@ -619,46 +686,43 @@ var Dashboard = { confirmInternal: function (message, title, showCancel, callback) { - require(['paperbuttonstyle'], function () { + var id = 'paperdlg' + new Date().getTime(); - var id = 'paperdlg' + new Date().getTime(); + var html = ''; + html += '

' + title + '

'; + html += '
' + message + '
'; + html += '
'; - var html = ''; - html += '

' + title + '

'; - html += '
' + message + '
'; - html += '
'; + html += '' + Globalize.translate('ButtonOk') + ''; - if (showCancel) { - html += '' + Globalize.translate('ButtonCancel') + ''; - } + if (showCancel) { + html += '' + Globalize.translate('ButtonCancel') + ''; + } - html += '' + Globalize.translate('ButtonOk') + ''; + html += '
'; + html += '
'; - html += '
'; - html += '
'; + $(document.body).append(html); - $(document.body).append(html); + // This timeout is obviously messy but it's unclear how to determine when the webcomponent is ready for use + // element onload never fires + setTimeout(function () { - // This timeout is obviously messy but it's unclear how to determine when the webcomponent is ready for use - // element onload never fires - setTimeout(function () { + var dlg = document.getElementById(id); - var dlg = document.getElementById(id); + // Has to be assigned a z-index after the call to .open() + $(dlg).on('iron-overlay-closed', function (e) { + var confirmed = this.closingReason.confirmed; + this.parentNode.removeChild(this); - // Has to be assigned a z-index after the call to .open() - $(dlg).on('iron-overlay-closed', function (e) { - var confirmed = this.closingReason.confirmed; - this.parentNode.removeChild(this); + if (callback) { + callback(confirmed); + } + }); - if (callback) { - callback(confirmed); - } - }); + dlg.open(); - dlg.open(); - - }, 300); - }); + }, 300); }, refreshSystemInfoFromServer: function () { diff --git a/dashboard-ui/strings/javascript/en-US.json b/dashboard-ui/strings/javascript/en-US.json index 98884da779..184aa55fd6 100644 --- a/dashboard-ui/strings/javascript/en-US.json +++ b/dashboard-ui/strings/javascript/en-US.json @@ -860,5 +860,10 @@ "OptionBudget": "Budget", "ForAdditionalLiveTvOptions": "For additional Live TV providers, click on the External Services tab to see the available options.", "ButtonGuide": "Guide", - "ButtonRecordedTv": "Recorded TV" + "ButtonRecordedTv": "Recorded TV", + "HeaderDisconnectFromPlayer": "Disconnect from Player", + "ConfirmEndPlayerSession": "Would you like to shutdown the app on the remote device?", + "ButtonDisconnect": "Disconnect", + "ButtonYes": "Yes", + "ButtonNo": "No" } \ No newline at end of file diff --git a/dashboard-ui/strings/javascript/javascript.json b/dashboard-ui/strings/javascript/javascript.json index cb642d3982..3da851aea3 100644 --- a/dashboard-ui/strings/javascript/javascript.json +++ b/dashboard-ui/strings/javascript/javascript.json @@ -421,7 +421,7 @@ "ButtonScenes": "Scenes", "ButtonQuality": "Quality", "HeaderNotifications": "Notifications", - "HeaderSelectPlayer": "Select Player:", + "HeaderSelectPlayer": "Select Player", "ButtonSelect": "Select", "ButtonNew": "New", "MessageInternetExplorerWebm": "For best results with Internet Explorer please install the WebM playback plugin.", @@ -860,6 +860,7 @@ "OptionDatePlayed": "Date Played", "OptionDateAdded": "Date Added", "OptionPlayCount": "Play Count", + "ButtonDisconnect": "Disconnect", "ButtonSort": "Sort", "ButtonMenu": "Menu", "ButtonFilter": "Filter", @@ -870,5 +871,9 @@ "OptionBudget": "Budget", "ForAdditionalLiveTvOptions": "For additional Live TV providers, click on the External Services tab to see the available options.", "ButtonGuide": "Guide", - "ButtonRecordedTv": "Recorded TV" + "ButtonRecordedTv": "Recorded TV", + "HeaderDisconnectFromPlayer": "Disconnect from Player", + "ConfirmEndPlayerSession": "Would you like to shutdown the app on the remote device?", + "ButtonYes": "Yes", + "ButtonNo": "No" } diff --git a/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js b/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js index c6bc456f16..2579d48adf 100644 --- a/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js +++ b/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js @@ -307,96 +307,6 @@ timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay ); }; - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - window.attachEvent && !window.addEventListener && !supports_onhashchange && (function(){ - // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8 - // when running in "IE7 compatibility" mode. - - var iframe, - iframe_src; - - // When the event is bound and polling starts in IE 6/7, create a hidden - // Iframe for history handling. - self.start = function(){ - if ( !iframe ) { - iframe_src = $.fn[ str_hashchange ].src; - iframe_src = iframe_src && iframe_src + get_fragment(); - - // Create hidden Iframe. Attempt to make Iframe as hidden as possible - // by using techniques from http://www.paciellogroup.com/blog/?p=604. - iframe = $('