diff --git a/dashboard-ui/components/apphost.js b/dashboard-ui/components/apphost.js
index d4e88df7ba..4d988b34a1 100644
--- a/dashboard-ui/components/apphost.js
+++ b/dashboard-ui/components/apphost.js
@@ -153,6 +153,14 @@ define(['appStorage', 'browser'], function (appStorage, browser) {
features.push('imageanalysis');
}
+ if (Dashboard.isConnectMode()) {
+ features.push('multiserver');
+ }
+
+ if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
+ features.push('physicalvolumecontrol');
+ }
+
return features;
}();
diff --git a/dashboard-ui/components/dockedtabs/dockedtabs.js b/dashboard-ui/components/dockedtabs/dockedtabs.js
index 7d55601620..da57c5337f 100644
--- a/dashboard-ui/components/dockedtabs/dockedtabs.js
+++ b/dashboard-ui/components/dockedtabs/dockedtabs.js
@@ -124,7 +124,7 @@
});
}
- if (Dashboard.isConnectMode()) {
+ if (appHost.supports('multiserver')) {
commands.push({
name: globalize.translate('HeaderSelectServer'),
id: 'selectserver'
diff --git a/dashboard-ui/components/playerselection.js b/dashboard-ui/components/playerselection.js
index d6f8e24615..e9963cbabb 100644
--- a/dashboard-ui/components/playerselection.js
+++ b/dashboard-ui/components/playerselection.js
@@ -1,47 +1,53 @@
-define(['appSettings', 'events', 'browser', 'libraryMenu', 'loading'], function (appSettings, events, browser, libraryMenu, loading) {
+define(['appSettings', 'events', 'browser', 'libraryMenu', 'loading', 'playbackManager'], function (appSettings, events, browser, libraryMenu, loading, playbackManager) {
'use strict';
var currentDisplayInfo;
- function mirrorItem(info) {
+ function mirrorItem(info, player) {
var item = info.item;
- MediaController.getCurrentPlayer().displayContent({
+ playbackManager.displayContent({
ItemName: item.Name,
ItemId: item.Id,
ItemType: item.Type,
Context: info.context
- });
+ }, player);
}
function mirrorIfEnabled(info) {
info = info || currentDisplayInfo;
- if (info && MediaController.enableDisplayMirroring()) {
+ if (info && playbackManager.enableDisplayMirroring()) {
- var player = MediaController.getPlayerInfo();
+ var player = playbackManager.getPlayerInfo();
- if (!player.isLocalPlayer && player.supportedCommands.indexOf('DisplayContent') != -1) {
- mirrorItem(info);
+ if (player) {
+ if (!player.isLocalPlayer && player.supportedCommands.indexOf('DisplayContent') != -1) {
+ mirrorItem(info, player);
+ }
}
}
}
function showPlayerSelection(button, enableHistory) {
- var playerInfo = MediaController.getPlayerInfo();
+ var currentPlayerInfo = playbackManager.getPlayerInfo();
- if (!playerInfo.isLocalPlayer) {
- showActivePlayerMenu(playerInfo);
- return;
+ if (currentPlayerInfo) {
+ if (!currentPlayerInfo.isLocalPlayer) {
+ showActivePlayerMenu(currentPlayerInfo);
+ return;
+ }
}
+ var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null;
+
loading.show();
- MediaController.getTargets().then(function (targets) {
+ playbackManager.getTargets().then(function (targets) {
var menuItems = targets.map(function (t) {
@@ -54,7 +60,7 @@
return {
name: name,
id: t.id,
- selected: playerInfo.id == t.id
+ selected: currentPlayerId === t.id
};
});
@@ -84,7 +90,7 @@
return t.id == id;
})[0];
- MediaController.trySetActivePlayer(target.playerName, target);
+ playbackManager.trySetActivePlayer(target.playerName, target);
mirrorIfEnabled();
@@ -127,7 +133,7 @@
if (playerInfo.supportedCommands.indexOf('DisplayContent') != -1) {
html += '';
@@ -162,7 +168,7 @@
}
dlg.querySelector('.btnDisconnect').addEventListener('click', function () {
- MediaController.disconnectFromPlayer();
+ playbackManager.disconnectFromPlayer();
dialogHelper.close(dlg);
});
@@ -178,7 +184,7 @@
}
function onMirrorChange() {
- MediaController.enableDisplayMirroring(this.checked);
+ playbackManager.enableDisplayMirroring(this.checked);
}
function onCastButtonClicked() {
diff --git a/dashboard-ui/components/remotecontrol.js b/dashboard-ui/components/remotecontrol.js
index 54cf846430..56ced61a72 100644
--- a/dashboard-ui/components/remotecontrol.js
+++ b/dashboard-ui/components/remotecontrol.js
@@ -1,4 +1,4 @@
-define(['browser', 'datetime', 'libraryBrowser', 'listView', 'userdataButtons', 'imageLoader', 'cardStyle'], function (browser, datetime, libraryBrowser, listView, userdataButtons, imageLoader) {
+define(['browser', 'datetime', 'libraryBrowser', 'listView', 'userdataButtons', 'imageLoader', 'playbackManager', 'nowPlayingHelper', 'events', 'apphost', 'cardStyle'], function (browser, datetime, libraryBrowser, listView, userdataButtons, imageLoader, playbackManager, nowPlayingHelper, events, appHost) {
'use strict';
function showSlideshowMenu(context) {
@@ -16,24 +16,8 @@
var menuItems = streams.map(function (s) {
- var name = (s.Codec || '').toUpperCase();
-
- if (s.Profile) {
- name += ' ' + s.Profile;
- }
-
- if (s.Language) {
- name += ' · ' + s.Language;
- }
- if (s.Layout) {
- name += ' · ' + s.Layout;
- }
- else if (s.Channels) {
- name += ' · ' + s.Channels + ' ch';
- }
-
var menuItem = {
- name: s.DisplayTitle || name,
+ name: s.DisplayTitle,
id: s.Index
};
@@ -67,24 +51,8 @@
var menuItems = streams.map(function (s) {
- var name = (s.Language || Globalize.translate('LabelUnknownLanguage'));
-
- if (s.IsDefault && s.IsForced) {
- name += ' · ' + Globalize.translate('LabelDefaultForcedStream');
- }
- else if (s.IsDefault) {
- name += ' · ' + Globalize.translate('LabelDefaultStream');
- }
- else if (s.IsForced) {
- name += ' · ' + Globalize.translate('LabelForcedStream');
- }
-
- if (s.Codec) {
- name += ' · ' + s.Codec.toUpperCase();
- }
-
var menuItem = {
- name: s.DisplayTitle || name,
+ name: s.DisplayTitle,
id: s.Index
};
@@ -129,11 +97,22 @@
}).length > 0;
}
+ function getNowPlayingNameHtml(nowPlayingItem, includeNonNameInfo) {
+
+ var names = nowPlayingHelper.getNowPlayingNames(nowPlayingItem, includeNonNameInfo);
+
+ return names.map(function (i) {
+
+ return i.text;
+
+ }).join('
');
+ }
+
var currentImgUrl;
function updateNowPlayingInfo(context, state) {
var item = state.NowPlayingItem;
- var displayName = item ? MediaController.getNowPlayingNameHtml(item).replace('
', ' - ') : '';
+ var displayName = item ? getNowPlayingNameHtml(item).replace('
', ' - ') : '';
context.querySelector('.nowPlayingPageTitle').innerHTML = displayName;
@@ -248,25 +227,27 @@
var dlg;
var currentPlayer;
+ var currentPlayerSupportedCommands = [];
var lastPlayerState;
var lastUpdateTime = 0;
+ var currentRuntimeTicks = 0;
var self = this;
var playlistNeedsRefresh = true;
function toggleRepeat(player) {
-
+
if (player && lastPlayerState) {
var state = lastPlayerState;
switch ((state.PlayState || {}).RepeatMode) {
case 'RepeatNone':
- player.setRepeatMode('RepeatAll');
+ playbackManager.setRepeatMode('RepeatAll', player);
break;
case 'RepeatAll':
- player.setRepeatMode('RepeatOne');
+ playbackManager.setRepeatMode('RepeatOne', player);
break;
case 'RepeatOne':
- player.setRepeatMode('RepeatNone');
+ playbackManager.setRepeatMode('RepeatNone', player);
break;
}
}
@@ -278,7 +259,7 @@
var item = state.NowPlayingItem;
- var playerInfo = MediaController.getPlayerInfo();
+ var playerInfo = playbackManager.getPlayerInfo();
var supportedCommands = playerInfo.supportedCommands;
var playState = state.PlayState || {};
@@ -310,53 +291,16 @@
buttonEnabled(context.querySelector('.btnNextTrack'), item != null);
buttonEnabled(context.querySelector('.btnPreviousTrack'), item != null);
- var btnPause = context.querySelector('.btnPause');
- var btnPlay = context.querySelector('.btnPlay');
-
- buttonEnabled(btnPause, item != null);
- buttonEnabled(btnPlay, item != null);
-
- if (playState.IsPaused) {
-
- hideButton(btnPause);
- showButton(btnPlay);
-
- } else {
-
- showButton(btnPause);
- hideButton(btnPlay);
- }
-
var positionSlider = context.querySelector('.nowPlayingPositionSlider');
-
- if (!positionSlider.dragging) {
-
- if (item && item.RunTimeTicks) {
-
- var pct = playState.PositionTicks / item.RunTimeTicks;
- pct *= 100;
-
- positionSlider.value = pct;
-
- } else {
-
- positionSlider.value = 0;
- }
-
+ if (positionSlider && !positionSlider.dragging) {
positionSlider.disabled = !playState.CanSeek;
}
- if (playState.PositionTicks == null) {
- context.querySelector('.positionTime').innerHTML = '--:--';
- } else {
- context.querySelector('.positionTime').innerHTML = datetime.getDisplayRunningTime(playState.PositionTicks);
- }
+ updatePlayPauseState(playState.IsPaused, item != null);
- if (item && item.RunTimeTicks != null) {
- context.querySelector('.runtime').innerHTML = datetime.getDisplayRunningTime(item.RunTimeTicks);
- } else {
- context.querySelector('.runtime').innerHTML = '--:--';
- }
+ var runtimeTicks = item ? item.RunTimeTicks : null;
+ updateTimeDisplay(playState.PositionTicks, runtimeTicks);
+ updatePlayerVolumeState(playState.IsMuted, playState.VolumeLevel);
if (item && item.MediaType == 'Video') {
context.classList.remove('hideVideoButtons');
@@ -364,7 +308,7 @@
context.classList.add('hideVideoButtons');
}
- if (playerInfo.isLocalPlayer && AppInfo.hasPhysicalVolumeButtons) {
+ if (playerInfo.isLocalPlayer && appHost.supports('physicalvolumecontrol')) {
context.classList.add('hideVolumeButtons');
} else {
context.classList.remove('hideVolumeButtons');
@@ -393,6 +337,65 @@
updateNowPlayingInfo(context, state);
}
+ function updatePlayerVolumeState(isMuted, volumeLevel) {
+
+ }
+
+ function updatePlayPauseState(isPaused, isActive) {
+
+ var context = dlg;
+
+ var btnPause = context.querySelector('.btnPause');
+ var btnPlay = context.querySelector('.btnPlay');
+
+ buttonEnabled(btnPause, isActive);
+ buttonEnabled(btnPlay, isActive);
+
+ if (isPaused) {
+
+ hideButton(btnPause);
+ showButton(btnPlay);
+
+ } else {
+
+ showButton(btnPause);
+ hideButton(btnPlay);
+ }
+ }
+
+ function updateTimeDisplay(positionTicks, runtimeTicks) {
+
+ // See bindEvents for why this is necessary
+ var context = dlg;
+ var positionSlider = context.querySelector('.nowPlayingPositionSlider');
+
+ if (positionSlider && !positionSlider.dragging) {
+ if (runtimeTicks) {
+
+ var pct = positionTicks / runtimeTicks;
+ pct *= 100;
+
+ positionSlider.value = pct;
+
+ } else {
+
+ positionSlider.value = 0;
+ }
+ }
+
+ if (positionTicks == null) {
+ context.querySelector('.positionTime').innerHTML = '--:--';
+ } else {
+ context.querySelector('.positionTime').innerHTML = datetime.getDisplayRunningTime(positionTicks);
+ }
+
+ if (runtimeTicks != null) {
+ context.querySelector('.runtime').innerHTML = datetime.getDisplayRunningTime(runtimeTicks);
+ } else {
+ context.querySelector('.runtime').innerHTML = '--:--';
+ }
+ }
+
function loadPlaylist(context) {
var html = '';
@@ -420,7 +423,7 @@
//});
html += listView.getListViewHtml({
- items: MediaController.playlist(),
+ items: playbackManager.playlist(),
smallIcon: true,
action: 'setplaylistindex'
});
@@ -435,7 +438,7 @@
itemsContainer.innerHTML = html;
- var index = MediaController.currentPlaylistIndex();
+ var index = playbackManager.currentPlaylistIndex();
if (index != -1) {
@@ -452,27 +455,12 @@
});
}
- function onStateChanged(e, state) {
-
- if (e.type == 'positionchange') {
- // Try to avoid hammering the document with changes
- var now = new Date().getTime();
- if ((now - lastUpdateTime) < 700) {
-
- return;
- }
- lastUpdateTime = now;
- }
-
- updatePlayerState(dlg, state);
- }
-
function onPlaybackStart(e, state) {
+ console.log('remotecontrol event: ' + e.type);
+
var player = this;
-
- player.beginPlayerUpdates();
-
+ playbackManager.beginPlayerUpdates(player);
onStateChanged.call(player, e, state);
loadPlaylist(dlg);
@@ -480,26 +468,66 @@
function onPlaybackStopped(e, state) {
+ console.log('remotecontrol event: ' + e.type);
var player = this;
- player.endPlayerUpdates();
-
- onStateChanged.call(player, e, {});
+ playbackManager.endPlayerUpdates(player);
loadPlaylist(dlg);
}
+ function onPlayPauseStateChanged(e) {
+
+ var player = this;
+ updatePlayPauseState(player.paused(), true);
+ }
+
+ function onStateChanged(event, state) {
+
+ //console.log('nowplaying event: ' + e.type);
+ var player = this;
+
+ updatePlayerState(dlg, state);
+ }
+
+ function onTimeUpdate(e) {
+
+ // Try to avoid hammering the document with changes
+ var now = new Date().getTime();
+ if ((now - lastUpdateTime) < 700) {
+
+ return;
+ }
+ lastUpdateTime = now;
+
+ var player = this;
+ var state = lastPlayerState;
+ var nowPlayingItem = state.NowPlayingItem || {};
+ currentRuntimeTicks = playbackManager.duration(player);
+ updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks);
+ }
+
+ function onVolumeChanged(e) {
+
+ var player = this;
+
+ updatePlayerVolumeState(player.isMuted(), player.getVolume());
+ }
+
function releaseCurrentPlayer() {
- if (currentPlayer) {
+ var player = currentPlayer;
- Events.off(currentPlayer, 'playbackstart', onPlaybackStart);
- Events.off(currentPlayer, 'playbackstop', onPlaybackStopped);
- Events.off(currentPlayer, 'volumechange', onStateChanged);
- Events.off(currentPlayer, 'playstatechange', onStateChanged);
- Events.off(currentPlayer, 'positionchange', onStateChanged);
+ if (player) {
- currentPlayer.endPlayerUpdates();
+ events.off(player, 'playbackstart', onPlaybackStart);
+ events.off(player, 'playbackstop', onPlaybackStopped);
+ events.off(player, 'volumechange', onVolumeChanged);
+ events.off(player, 'pause', onPlayPauseStateChanged);
+ events.off(player, 'playing', onPlayPauseStateChanged);
+ events.off(player, 'timeupdate', onTimeUpdate);
+
+ playbackManager.endPlayerUpdates(player);
currentPlayer = null;
}
}
@@ -510,67 +538,58 @@
currentPlayer = player;
- player.getPlayerState().then(function (state) {
+ if (!player) {
+ return;
+ }
+
+ playbackManager.getPlayerState(player).then(function (state) {
if (state.NowPlayingItem) {
- player.beginPlayerUpdates();
+ playbackManager.beginPlayerUpdates(player);
}
onStateChanged.call(player, { type: 'init' }, state);
});
- Events.on(player, 'playbackstart', onPlaybackStart);
- Events.on(player, 'playbackstop', onPlaybackStopped);
- Events.on(player, 'volumechange', onStateChanged);
- Events.on(player, 'playstatechange', onStateChanged);
- Events.on(player, 'positionchange', onStateChanged);
+ events.on(player, 'playbackstart', onPlaybackStart);
+ events.on(player, 'playbackstop', onPlaybackStopped);
+ events.on(player, 'volumechange', onVolumeChanged);
+ events.on(player, 'pause', onPlayPauseStateChanged);
+ events.on(player, 'playing', onPlayPauseStateChanged);
+ events.on(player, 'timeupdate', onTimeUpdate);
- var playerInfo = MediaController.getPlayerInfo();
+ var playerInfo = playbackManager.getPlayerInfo();
var supportedCommands = playerInfo.supportedCommands;
+ currentPlayerSupportedCommands = supportedCommands;
updateSupportedCommands(context, supportedCommands);
}
function updateCastIcon(context) {
- var info = MediaController.getPlayerInfo();
+ var info = playbackManager.getPlayerInfo();
var btnCast = context.querySelector('.nowPlayingCastIcon');
- if (info.isLocalPlayer) {
-
- btnCast.querySelector('i').innerHTML = 'cast';
- btnCast.classList.remove('btnActiveCast');
- context.querySelector('.nowPlayingSelectedPlayer').innerHTML = '';
-
- } else {
+ if (info && !info.isLocalPlayer) {
btnCast.querySelector('i').innerHTML = 'cast_connected';
btnCast.classList.add('btnActiveCast');
context.querySelector('.nowPlayingSelectedPlayer').innerHTML = info.deviceName || info.name;
+ } else {
+ btnCast.querySelector('i').innerHTML = 'cast';
+ btnCast.classList.remove('btnActiveCast');
+ context.querySelector('.nowPlayingSelectedPlayer').innerHTML = '';
}
}
- function parentWithClass(elem, className) {
-
- while (!elem.classList || !elem.classList.contains(className)) {
- elem = elem.parentNode;
-
- if (!elem) {
- return null;
- }
- }
-
- return elem;
- }
-
function onBtnCommandClick() {
if (currentPlayer) {
if (this.classList.contains('repeatToggleButton')) {
toggleRepeat(currentPlayer);
} else {
- MediaController.sendCommand({
+ playbackManager.sendCommand({
Name: this.getAttribute('data-command')
}, currentPlayer);
@@ -588,7 +607,7 @@
context.querySelector('.btnToggleFullscreen').addEventListener('click', function (e) {
if (currentPlayer) {
- MediaController.sendCommand({
+ playbackManager.sendCommand({
Name: e.target.getAttribute('data-command')
}, currentPlayer);
@@ -625,7 +644,7 @@
context.querySelector('.btnStop').addEventListener('click', function () {
if (currentPlayer) {
- currentPlayer.stop();
+ playbackManager.stop(currentPlayer);
}
});
@@ -646,14 +665,14 @@
context.querySelector('.btnNextTrack').addEventListener('click', function () {
if (currentPlayer) {
- currentPlayer.nextTrack();
+ playbackManager.nextTrack(currentPlayer);
}
});
context.querySelector('.btnPreviousTrack').addEventListener('click', function () {
if (currentPlayer) {
- currentPlayer.previousTrack();
+ playbackManager.previousTrack(currentPlayer);
}
});
@@ -661,11 +680,10 @@
var value = this.value;
- if (currentPlayer && lastPlayerState) {
+ if (currentPlayer) {
var newPercent = parseFloat(value);
- var newPositionTicks = (newPercent / 100) * lastPlayerState.NowPlayingItem.RunTimeTicks;
- currentPlayer.seek(Math.floor(newPositionTicks));
+ playbackManager.seekPercent(newPercent, currentPlayer);
}
});
@@ -673,11 +691,11 @@
var state = lastPlayerState;
- if (!state || !state.NowPlayingItem || !state.NowPlayingItem.RunTimeTicks) {
+ if (!state || !state.NowPlayingItem || !currentRuntimeTicks) {
return '--:--';
}
- var ticks = state.NowPlayingItem.RunTimeTicks;
+ var ticks = currentRuntimeTicks;
ticks /= 100;
ticks *= value;
@@ -689,14 +707,14 @@
var context = dlg;
updateCastIcon(context);
- bindToPlayer(context, MediaController.getCurrentPlayer());
+ bindToPlayer(context, playbackManager.getCurrentPlayer());
}
function onMessageSubmit(e) {
var form = e.target;
- MediaController.sendCommand({
+ playbackManager.sendCommand({
Name: 'DisplayMessage',
Arguments: {
@@ -720,7 +738,7 @@
var form = e.target;
- MediaController.sendCommand({
+ playbackManager.sendCommand({
Name: 'SendString',
Arguments: {
@@ -774,14 +792,14 @@
}
});
- Events.on(MediaController, 'playerchange', onPlayerChange);
+ events.on(playbackManager, 'playerchange', onPlayerChange);
}
function onDialogClosed(e) {
releaseCurrentPlayer();
- Events.off(MediaController, 'playerchange', onPlayerChange);
+ events.off(playbackManager, 'playerchange', onPlayerChange);
lastPlayerState = null;
}
@@ -790,7 +808,7 @@
currentImgUrl = null;
- bindToPlayer(context, MediaController.getCurrentPlayer());
+ bindToPlayer(context, playbackManager.getCurrentPlayer());
updateCastIcon(context);
}
diff --git a/dashboard-ui/components/remotecontrolautoplay.js b/dashboard-ui/components/remotecontrolautoplay.js
index 900dc46596..de7bd8b445 100644
--- a/dashboard-ui/components/remotecontrolautoplay.js
+++ b/dashboard-ui/components/remotecontrolautoplay.js
@@ -1,7 +1,7 @@
-define(['events'], function (events) {
+define(['events', 'playbackManager'], function (events, playbackManager) {
'use strict';
- function transferPlayback(oldPlayer) {
+ function transferPlayback(oldPlayer, newPlayer) {
oldPlayer.getPlayerState().then(function (state) {
@@ -18,7 +18,7 @@
var itemId = item.Id;
var resumePositionTicks = playState.PositionTicks || 0;
- MediaController.play({
+ playbackManager.play({
ids: [itemId],
startPositionTicks: resumePositionTicks
});
@@ -26,10 +26,9 @@
});
}
- events.on(MediaController, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) {
+ events.on(playbackManager, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) {
- if (!oldPlayer) {
- console.log('Skipping remote control autoplay because oldPlayer is null');
+ if (!oldPlayer || !newPlayer) {
return;
}
@@ -45,7 +44,7 @@
// If playback is playing locally and a new player is activated, transfer the media to that player
if (oldPlayer.isPlaying()) {
- transferPlayback(oldPlayer);
+ transferPlayback(oldPlayer, newPlayer);
}
});
diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css
index 050819752c..253f6d248f 100644
--- a/dashboard-ui/css/librarybrowser.css
+++ b/dashboard-ui/css/librarybrowser.css
@@ -13,7 +13,7 @@
.background-theme-b .backgroundContainer.withBackdrop {
background-color: rgba(6, 6, 6, .94) !important;
- background: linear-gradient(to right, rgba(0, 0, 0, .99), rgba(0, 0, 0, .92), rgba(0, 0, 0, .5)) !important;
+ background: linear-gradient(to right, rgba(0, 0, 0, .99), rgba(0, 0, 0, .94), rgba(0, 0, 0, .5)) !important;
}
.ui-body-b {
@@ -797,17 +797,10 @@ span.itemCommunityRating:not(:empty) + .userDataIcons {
}
.mediaInfoText {
- background: rgba(31,31,31,.7);
- padding: .3em .5em;
- border-radius: .25em;
- color: #ddd;
+ padding: .3em .5em !important;
margin-right: .5em;
margin-bottom: .5em;
- font-size: 94%;
- background: rgba(170,170,190, .2);
- display: flex;
- align-items: center;
- white-space: nowrap;
+ font-size: 94% !important;
}
.mediaInfoText-upper {
diff --git a/dashboard-ui/css/nowplayingbar.css b/dashboard-ui/css/nowplayingbar.css
index b7055e0512..2d2112726d 100644
--- a/dashboard-ui/css/nowplayingbar.css
+++ b/dashboard-ui/css/nowplayingbar.css
@@ -54,6 +54,11 @@
will-change: transform;
contain: layout style;
font-size: 90%;
+ transition: transform 200ms ease-out;
+}
+
+.nowPlayingBar-hidden {
+ transform: translate3d(0,100%,0);
}
.hiddenNowPlayingBar .nowPlayingBar {
diff --git a/dashboard-ui/index.html b/dashboard-ui/index.html
index 5610bf04c7..4701232462 100644
--- a/dashboard-ui/index.html
+++ b/dashboard-ui/index.html
@@ -2,6 +2,14 @@