diff --git a/package.json b/package.json index f18f26fd21..8038de5f90 100644 --- a/package.json +++ b/package.json @@ -303,10 +303,13 @@ "src/scripts/mouseManager.js", "src/scripts/multiDownload.js", "src/scripts/playlists.js", + "src/scripts/scrollHelper.js", + "src/scripts/serverNotifications.js", "src/scripts/routes.js", "src/scripts/settings/appSettings.js", "src/scripts/settings/userSettings.js", "src/scripts/settings/webSettings.js", + "src/scripts/shell.js", "src/scripts/taskbutton.js", "src/scripts/themeLoader.js", "src/scripts/touchHelper.js" diff --git a/src/assets/css/librarybrowser.css b/src/assets/css/librarybrowser.css index 047ae0a1c6..643fb9ca97 100644 --- a/src/assets/css/librarybrowser.css +++ b/src/assets/css/librarybrowser.css @@ -236,12 +236,6 @@ text-align: center; } -.layout-desktop .searchTabButton, -.layout-mobile .searchTabButton, -.layout-tv .headerSearchButton { - display: none !important; -} - .mainDrawer-scrollContainer { padding-bottom: 10vh; } diff --git a/src/components/collectionEditor/collectionEditor.js b/src/components/collectionEditor/collectionEditor.js index a115b86a8f..dd8b3d6837 100644 --- a/src/components/collectionEditor/collectionEditor.js +++ b/src/components/collectionEditor/collectionEditor.js @@ -200,7 +200,7 @@ import 'flexStyles'; } function centerFocus(elem, horiz, on) { - import('scrollHelper').then(scrollHelper => { + import('scrollHelper').then((scrollHelper) => { const fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index 1f11d8a195..77643791ad 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -354,7 +354,7 @@ import 'scrollStyles'; } function centerFocus(elem, horiz, on) { - import('scrollHelper').then(scrollHelper => { + import('scrollHelper').then((scrollHelper) => { const fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); diff --git a/src/components/filtermenu/filtermenu.js b/src/components/filtermenu/filtermenu.js index b02b5fb9f8..37fb66e0d9 100644 --- a/src/components/filtermenu/filtermenu.js +++ b/src/components/filtermenu/filtermenu.js @@ -151,6 +151,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', function centerFocus(elem, horiz, on) { require(['scrollHelper'], function (scrollHelper) { + scrollHelper = scrollHelper.default || scrollHelper; var fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); diff --git a/src/components/guide/guide-settings.js b/src/components/guide/guide-settings.js index c3ba49f283..a644c9c9b0 100644 --- a/src/components/guide/guide-settings.js +++ b/src/components/guide/guide-settings.js @@ -1,6 +1,8 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) { 'use strict'; + scrollHelper = scrollHelper.default || scrollHelper; + function saveCategories(context, options) { var categories = []; diff --git a/src/components/guide/guide.js b/src/components/guide/guide.js index 71d63f82c0..05fa2b608d 100644 --- a/src/components/guide/guide.js +++ b/src/components/guide/guide.js @@ -5,6 +5,8 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', browser = browser.default || browser; loading = loading.default || loading; focusManager = focusManager.default || focusManager; + scrollHelper = scrollHelper.default || scrollHelper; + serverNotifications = serverNotifications.default || serverNotifications; function showViewSettings(instance) { require(['guide-settings-dialog'], function (guideSettingsDialog) { diff --git a/src/components/itemsrefresher.js b/src/components/itemsrefresher.js index 74b08db07f..5ce9a3b6e4 100644 --- a/src/components/itemsrefresher.js +++ b/src/components/itemsrefresher.js @@ -1,6 +1,7 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) { 'use strict'; + serverNotifications = serverNotifications.default || serverNotifications; playbackManager = playbackManager.default || playbackManager; function onUserDataChanged(e, apiClient, userData) { diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 0bf270f2a1..289c784bd9 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -2,6 +2,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir 'use strict'; playbackManager = playbackManager.default || playbackManager; + serverNotifications = serverNotifications.default || serverNotifications; function onOneDocumentClick() { document.removeEventListener('click', onOneDocumentClick); diff --git a/src/components/playlisteditor/playlisteditor.js b/src/components/playlisteditor/playlisteditor.js index 7b1e915e1f..78f0cf3dec 100644 --- a/src/components/playlisteditor/playlisteditor.js +++ b/src/components/playlisteditor/playlisteditor.js @@ -210,7 +210,7 @@ import 'emby-button'; } function centerFocus(elem, horiz, on) { - import('scrollHelper').then(scrollHelper => { + import('scrollHelper').then((scrollHelper) => { const fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); diff --git a/src/components/recordingcreator/recordingcreator.js b/src/components/recordingcreator/recordingcreator.js index ca5c475829..9c2d8fcb68 100644 --- a/src/components/recordingcreator/recordingcreator.js +++ b/src/components/recordingcreator/recordingcreator.js @@ -1,6 +1,8 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'datetime', 'imageLoader', 'recordingFields', 'events', 'emby-checkbox', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) { 'use strict'; + scrollHelper = scrollHelper.default || scrollHelper; + var currentDialog; var closeAction; var currentRecordingFields; diff --git a/src/components/recordingcreator/recordingeditor.js b/src/components/recordingcreator/recordingeditor.js index 2e54b3601c..7117778eb0 100644 --- a/src/components/recordingcreator/recordingeditor.js +++ b/src/components/recordingcreator/recordingeditor.js @@ -1,6 +1,7 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'scrollStyles', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader) { 'use strict'; + scrollHelper = scrollHelper.default || scrollHelper; loading = loading.default || loading; var currentDialog; diff --git a/src/components/recordingcreator/recordingfields.js b/src/components/recordingcreator/recordingfields.js index 741570581e..c93200d053 100644 --- a/src/components/recordingcreator/recordingfields.js +++ b/src/components/recordingcreator/recordingfields.js @@ -1,6 +1,7 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events) { 'use strict'; + serverNotifications = serverNotifications.default || serverNotifications; recordingHelper = recordingHelper.default || recordingHelper; loading = loading.default || loading; diff --git a/src/components/sortmenu/sortmenu.js b/src/components/sortmenu/sortmenu.js index 52a7b95c40..d1cea0c490 100644 --- a/src/components/sortmenu/sortmenu.js +++ b/src/components/sortmenu/sortmenu.js @@ -17,6 +17,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutMana function centerFocus(elem, horiz, on) { require(['scrollHelper'], function (scrollHelper) { + scrollHelper = scrollHelper.default || scrollHelper; var fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); diff --git a/src/components/subtitleeditor/subtitleeditor.js b/src/components/subtitleeditor/subtitleeditor.js index c42658b2d5..b52b911cb9 100644 --- a/src/components/subtitleeditor/subtitleeditor.js +++ b/src/components/subtitleeditor/subtitleeditor.js @@ -337,6 +337,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', function centerFocus(elem, horiz, on) { require(['scrollHelper'], function (scrollHelper) { + scrollHelper = scrollHelper.default || scrollHelper; var fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); diff --git a/src/components/tunerPicker.js b/src/components/tunerPicker.js index 4e78030a2a..5d597f6654 100644 --- a/src/components/tunerPicker.js +++ b/src/components/tunerPicker.js @@ -4,6 +4,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'connectionManager', 'globalize' browser = browser.default || browser; loading = loading.default || loading; focusManager = focusManager.default || focusManager; + scrollHelper = scrollHelper.default || scrollHelper; var enableFocusTransform = !browser.slow && !browser.edge; diff --git a/src/components/viewSettings/viewSettings.js b/src/components/viewSettings/viewSettings.js index 67abc25a9c..9207f8ddbb 100644 --- a/src/components/viewSettings/viewSettings.js +++ b/src/components/viewSettings/viewSettings.js @@ -29,6 +29,7 @@ define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'conne function centerFocus(elem, horiz, on) { require(['scrollHelper'], function (scrollHelper) { + scrollHelper = scrollHelper.default || scrollHelper; var fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); diff --git a/src/controllers/livetv/livetvsuggested.js b/src/controllers/livetv/livetvsuggested.js index 79d9aac6e9..05e852fd0b 100644 --- a/src/controllers/livetv/livetvsuggested.js +++ b/src/controllers/livetv/livetvsuggested.js @@ -169,9 +169,6 @@ define(['layoutManager', 'userSettings', 'inputManager', 'loading', 'globalize', name: globalize.translate('HeaderSchedule') }, { name: globalize.translate('TabSeries') - }, { - name: globalize.translate('ButtonSearch'), - cssClass: 'searchTabButton' }]; } @@ -255,9 +252,6 @@ define(['layoutManager', 'userSettings', 'inputManager', 'loading', 'globalize', case 5: depends.push('controllers/livetv/livetvseriestimers'); break; - - case 6: - depends.push('scripts/searchtab'); } require(depends, function (controllerFactory) { diff --git a/src/controllers/movies/moviesrecommended.js b/src/controllers/movies/moviesrecommended.js index 5cba66d2f8..91163c3412 100644 --- a/src/controllers/movies/moviesrecommended.js +++ b/src/controllers/movies/moviesrecommended.js @@ -236,9 +236,6 @@ import 'emby-button'; name: globalize.translate('TabCollections') }, { name: globalize.translate('TabGenres') - }, { - name: globalize.translate('ButtonSearch'), - cssClass: 'searchTabButton' }]; } @@ -306,10 +303,6 @@ import 'emby-button'; case 5: depends = 'controllers/movies/moviegenres'; break; - - case 6: - depends = 'scripts/searchtab'; - break; } import(depends).then(({default: controllerFactory}) => { diff --git a/src/controllers/music/musicrecommended.js b/src/controllers/music/musicrecommended.js index db7dac9547..9bc449e2a2 100644 --- a/src/controllers/music/musicrecommended.js +++ b/src/controllers/music/musicrecommended.js @@ -191,9 +191,6 @@ import 'flexStyles'; name: globalize.translate('TabSongs') }, { name: globalize.translate('TabGenres') - }, { - name: globalize.translate('ButtonSearch'), - cssClass: 'searchTabButton' }]; } @@ -295,10 +292,6 @@ import 'flexStyles'; case 6: depends = 'controllers/music/musicgenres'; break; - - case 7: - depends = 'scripts/searchtab'; - break; } import(depends).then(({default: controllerFactory}) => { diff --git a/src/controllers/shows/tvrecommended.js b/src/controllers/shows/tvrecommended.js index 4aab69e978..585449d0c0 100644 --- a/src/controllers/shows/tvrecommended.js +++ b/src/controllers/shows/tvrecommended.js @@ -30,9 +30,6 @@ import 'emby-button'; name: globalize.translate('TabNetworks') }, { name: globalize.translate('TabEpisodes') - }, { - name: globalize.translate('ButtonSearch'), - cssClass: 'searchTabButton' }]; } @@ -217,10 +214,6 @@ import 'emby-button'; case 6: depends = 'controllers/shows/episodes'; break; - - case 7: - depends = 'scripts/searchtab'; - break; } import(depends).then(({default: controllerFactory}) => { diff --git a/src/plugins/sessionPlayer/plugin.js b/src/plugins/sessionPlayer/plugin.js index fb1f745df3..c68e0d7a4a 100644 --- a/src/plugins/sessionPlayer/plugin.js +++ b/src/plugins/sessionPlayer/plugin.js @@ -1,6 +1,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) { 'use strict'; + serverNotifications = serverNotifications.default || serverNotifications; playbackManager = playbackManager.default || playbackManager; function getActivePlayerId() { diff --git a/src/scripts/scrollHelper.js b/src/scripts/scrollHelper.js index 8b596571b4..b867123683 100644 --- a/src/scripts/scrollHelper.js +++ b/src/scripts/scrollHelper.js @@ -1,137 +1,138 @@ -define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) { - 'use strict'; +import focusManager from 'focusManager'; +import dom from 'dom'; +import 'scrollStyles'; - focusManager = focusManager.default || focusManager; +function getBoundingClientRect(elem) { + // Support: BlackBerry 5, iOS 3 (original iPhone) + // If we don't have gBCR, just use 0,0 rather than error + if (elem.getBoundingClientRect) { + return elem.getBoundingClientRect(); + } else { + return { top: 0, left: 0 }; + } +} - function getBoundingClientRect(elem) { - // Support: BlackBerry 5, iOS 3 (original iPhone) - // If we don't have gBCR, just use 0,0 rather than error - if (elem.getBoundingClientRect) { - return elem.getBoundingClientRect(); - } else { - return { top: 0, left: 0 }; - } +export function getPosition(scrollContainer, item, horizontal) { + const slideeOffset = getBoundingClientRect(scrollContainer); + const itemOffset = getBoundingClientRect(item); + + let offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; + let size = horizontal ? itemOffset.width : itemOffset.height; + if (!size && size !== 0) { + size = item[horizontal ? 'offsetWidth' : 'offsetHeight']; } - function getPosition(scrollContainer, item, horizontal) { - var slideeOffset = getBoundingClientRect(scrollContainer); - var itemOffset = getBoundingClientRect(item); + const currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop; - var offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; - var size = horizontal ? itemOffset.width : itemOffset.height; - if (!size && size !== 0) { - size = item[horizontal ? 'offsetWidth' : 'offsetHeight']; - } + offset += currentStart; - var currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop; + const frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight; - offset += currentStart; + const currentEnd = currentStart + frameSize; - var frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight; - - var currentEnd = currentStart + frameSize; - - var isVisible = offset >= currentStart && (offset + size) <= currentEnd; - - return { - start: offset, - center: (offset - (frameSize / 2) + (size / 2)), - end: offset - frameSize + size, - size: size, - isVisible: isVisible - }; - } - - function toCenter(container, elem, horizontal, skipWhenVisible) { - var pos = getPosition(container, elem, horizontal); - - if (skipWhenVisible && pos.isVisible) { - return; - } - - if (container.scrollTo) { - if (horizontal) { - container.scrollTo(pos.center, 0); - } else { - container.scrollTo(0, pos.center); - } - } else { - if (horizontal) { - container.scrollLeft = Math.round(pos.center); - } else { - container.scrollTop = Math.round(pos.center); - } - } - } - - function toStart(container, elem, horizontal, skipWhenVisible) { - var pos = getPosition(container, elem, horizontal); - - if (skipWhenVisible && pos.isVisible) { - return; - } - - if (container.scrollTo) { - if (horizontal) { - container.scrollTo(pos.start, 0); - } else { - container.scrollTo(0, pos.start); - } - } else { - if (horizontal) { - container.scrollLeft = Math.round(pos.start); - } else { - container.scrollTop = Math.round(pos.start); - } - } - } - - function centerOnFocus(e, scrollSlider, horizontal) { - var focused = focusManager.focusableParent(e.target); - - if (focused) { - toCenter(scrollSlider, focused, horizontal); - } - } - - function centerOnFocusHorizontal(e) { - centerOnFocus(e, this, true); - } - function centerOnFocusVertical(e) { - centerOnFocus(e, this, false); - } + const isVisible = offset >= currentStart && (offset + size) <= currentEnd; return { - getPosition: getPosition, - centerFocus: { - on: function (element, horizontal) { - if (horizontal) { - dom.addEventListener(element, 'focus', centerOnFocusHorizontal, { - capture: true, - passive: true - }); - } else { - dom.addEventListener(element, 'focus', centerOnFocusVertical, { - capture: true, - passive: true - }); - } - }, - off: function (element, horizontal) { - if (horizontal) { - dom.removeEventListener(element, 'focus', centerOnFocusHorizontal, { - capture: true, - passive: true - }); - } else { - dom.removeEventListener(element, 'focus', centerOnFocusVertical, { - capture: true, - passive: true - }); - } - } - }, - toCenter: toCenter, - toStart: toStart + start: offset, + center: (offset - (frameSize / 2) + (size / 2)), + end: offset - frameSize + size, + size: size, + isVisible: isVisible }; -}); +} + +export function toCenter(container, elem, horizontal, skipWhenVisible) { + const pos = getPosition(container, elem, horizontal); + + if (skipWhenVisible && pos.isVisible) { + return; + } + + if (container.scrollTo) { + if (horizontal) { + container.scrollTo(pos.center, 0); + } else { + container.scrollTo(0, pos.center); + } + } else { + if (horizontal) { + container.scrollLeft = Math.round(pos.center); + } else { + container.scrollTop = Math.round(pos.center); + } + } +} + +export function toStart(container, elem, horizontal, skipWhenVisible) { + const pos = getPosition(container, elem, horizontal); + + if (skipWhenVisible && pos.isVisible) { + return; + } + + if (container.scrollTo) { + if (horizontal) { + container.scrollTo(pos.start, 0); + } else { + container.scrollTo(0, pos.start); + } + } else { + if (horizontal) { + container.scrollLeft = Math.round(pos.start); + } else { + container.scrollTop = Math.round(pos.start); + } + } +} + +function centerOnFocus(e, scrollSlider, horizontal) { + const focused = focusManager.focusableParent(e.target); + + if (focused) { + toCenter(scrollSlider, focused, horizontal); + } +} + +function centerOnFocusHorizontal(e) { + centerOnFocus(e, this, true); +} + +function centerOnFocusVertical(e) { + centerOnFocus(e, this, false); +} + +export const centerFocus = { + on: function (element, horizontal) { + if (horizontal) { + dom.addEventListener(element, 'focus', centerOnFocusHorizontal, { + capture: true, + passive: true + }); + } else { + dom.addEventListener(element, 'focus', centerOnFocusVertical, { + capture: true, + passive: true + }); + } + }, + off: function (element, horizontal) { + if (horizontal) { + dom.removeEventListener(element, 'focus', centerOnFocusHorizontal, { + capture: true, + passive: true + }); + } else { + dom.removeEventListener(element, 'focus', centerOnFocusVertical, { + capture: true, + passive: true + }); + } + } +}; + +export default { + getPosition: getPosition, + centerFocus: centerFocus, + toCenter: toCenter, + toStart: toStart +}; diff --git a/src/scripts/searchtab.js b/src/scripts/searchtab.js deleted file mode 100644 index e012b8a4b2..0000000000 --- a/src/scripts/searchtab.js +++ /dev/null @@ -1,57 +0,0 @@ -define(['searchFields', 'searchResults', 'events'], function (SearchFields, SearchResults, events) { - 'use strict'; - - SearchFields = SearchFields.default || SearchFields; - SearchResults = SearchResults.default || SearchResults; - - function init(instance, tabContent, options) { - tabContent.innerHTML = '
'; - instance.searchFields = new SearchFields({ - element: tabContent.querySelector('.searchFields') - }); - instance.searchResults = new SearchResults({ - element: tabContent.querySelector('.searchResults'), - serverId: ApiClient.serverId(), - parentId: options.parentId, - collectionType: options.collectionType - }); - events.on(instance.searchFields, 'search', function (e, value) { - instance.searchResults.search(value); - }); - } - - function SearchTab(view, tabContent, options) { - var self = this; - options = options || {}; - init(this, tabContent, options); - - self.preRender = function () {}; - - self.renderTab = function () { - var searchFields = this.searchFields; - - if (searchFields) { - searchFields.focus(); - } - }; - } - - SearchTab.prototype.destroy = function () { - var searchFields = this.searchFields; - - if (searchFields) { - searchFields.destroy(); - } - - this.searchFields = null; - var searchResults = this.searchResults; - - if (searchResults) { - searchResults.destroy(); - } - - this.searchResults = null; - }; - - return SearchTab; -}); diff --git a/src/scripts/serverNotifications.js b/src/scripts/serverNotifications.js index 87db52402d..2566d148f6 100644 --- a/src/scripts/serverNotifications.js +++ b/src/scripts/serverNotifications.js @@ -1,214 +1,216 @@ -define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'inputManager', 'focusManager', 'appRouter'], function (connectionManager, playbackManager, syncPlayManager, events, inputManager, focusManager, appRouter) { - 'use strict'; +import connectionManager from 'connectionManager'; +import playbackManager from 'playbackManager'; +import syncPlayManager from 'syncPlayManager'; +import events from 'events'; +import inputManager from 'inputManager'; +import focusManager from 'focusManager'; +import appRouter from 'appRouter'; - playbackManager = playbackManager.default || playbackManager; - focusManager = focusManager.default || focusManager; +const serverNotifications = {}; - var serverNotifications = {}; +function notifyApp() { + inputManager.notify(); +} - function notifyApp() { - inputManager.notify(); - } - - function displayMessage(cmd) { - var args = cmd.Arguments; - if (args.TimeoutMs) { - require(['toast'], function (toast) { - toast({ title: args.Header, text: args.Text }); - }); - } else { - require(['alert'], function (alert) { - alert.default({ title: args.Header, text: args.Text }); - }); - } - } - - function displayContent(cmd, apiClient) { - if (!playbackManager.isPlayingLocally(['Video', 'Book'])) { - appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId()); - } - } - - function playTrailers(apiClient, itemId) { - apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { - playbackManager.playTrailers(item); +function displayMessage(cmd) { + const args = cmd.Arguments; + if (args.TimeoutMs) { + import('toast').then(({default: toast}) => { + toast({ title: args.Header, text: args.Text }); + }); + } else { + import('alert').then(({default: alert}) => { + alert({ title: args.Header, text: args.Text }); }); } +} - function processGeneralCommand(cmd, apiClient) { - console.debug('Received command: ' + cmd.Name); - switch (cmd.Name) { - case 'Select': - inputManager.handleCommand('select'); - return; - case 'Back': - inputManager.handleCommand('back'); - return; - case 'MoveUp': - inputManager.handleCommand('up'); - return; - case 'MoveDown': - inputManager.handleCommand('down'); - return; - case 'MoveLeft': - inputManager.handleCommand('left'); - return; - case 'MoveRight': - inputManager.handleCommand('right'); - return; - case 'PageUp': - inputManager.handleCommand('pageup'); - return; - case 'PageDown': - inputManager.handleCommand('pagedown'); - return; - case 'PlayTrailers': - playTrailers(apiClient, cmd.Arguments.ItemId); - break; - case 'SetRepeatMode': - playbackManager.setRepeatMode(cmd.Arguments.RepeatMode); - break; - case 'SetShuffleQueue': - playbackManager.setQueueShuffleMode(cmd.Arguments.ShuffleMode); - break; - case 'VolumeUp': - inputManager.handleCommand('volumeup'); - return; - case 'VolumeDown': - inputManager.handleCommand('volumedown'); - return; - case 'ChannelUp': - inputManager.handleCommand('channelup'); - return; - case 'ChannelDown': - inputManager.handleCommand('channeldown'); - return; - case 'Mute': - inputManager.handleCommand('mute'); - return; - case 'Unmute': - inputManager.handleCommand('unmute'); - return; - case 'ToggleMute': - inputManager.handleCommand('togglemute'); - return; - case 'SetVolume': - notifyApp(); - playbackManager.setVolume(cmd.Arguments.Volume); - break; - case 'SetAudioStreamIndex': - notifyApp(); - playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index)); - break; - case 'SetSubtitleStreamIndex': - notifyApp(); - playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index)); - break; - case 'ToggleFullscreen': - inputManager.handleCommand('togglefullscreen'); - return; - case 'GoHome': - inputManager.handleCommand('home'); - return; - case 'GoToSettings': - inputManager.handleCommand('settings'); - return; - case 'DisplayContent': - displayContent(cmd, apiClient); - break; - case 'GoToSearch': - inputManager.handleCommand('search'); - return; - case 'DisplayMessage': - displayMessage(cmd); - break; - case 'ToggleOsd': - // todo - break; - case 'ToggleContextMenu': - // todo - break; - case 'TakeScreenShot': - // todo - break; - case 'SendKey': - // todo - break; - case 'SendString': - // todo - focusManager.sendText(cmd.Arguments.String); - break; - default: - console.debug('processGeneralCommand does not recognize: ' + cmd.Name); - break; - } - - notifyApp(); +function displayContent(cmd, apiClient) { + if (!playbackManager.isPlayingLocally(['Video', 'Book'])) { + appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId()); } +} - function onMessageReceived(e, msg) { - var apiClient = this; - if (msg.MessageType === 'Play') { - notifyApp(); - var serverId = apiClient.serverInfo().Id; - if (msg.Data.PlayCommand === 'PlayNext') { - playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId }); - } else if (msg.Data.PlayCommand === 'PlayLast') { - playbackManager.queue({ ids: msg.Data.ItemIds, serverId: serverId }); - } else { - playbackManager.play({ - ids: msg.Data.ItemIds, - startPositionTicks: msg.Data.StartPositionTicks, - mediaSourceId: msg.Data.MediaSourceId, - audioStreamIndex: msg.Data.AudioStreamIndex, - subtitleStreamIndex: msg.Data.SubtitleStreamIndex, - startIndex: msg.Data.StartIndex, - serverId: serverId - }); - } - } else if (msg.MessageType === 'Playstate') { - if (msg.Data.Command === 'Stop') { - inputManager.handleCommand('stop'); - } else if (msg.Data.Command === 'Pause') { - inputManager.handleCommand('pause'); - } else if (msg.Data.Command === 'Unpause') { - inputManager.handleCommand('play'); - } else if (msg.Data.Command === 'PlayPause') { - inputManager.handleCommand('playpause'); - } else if (msg.Data.Command === 'Seek') { - playbackManager.seek(msg.Data.SeekPositionTicks); - } else if (msg.Data.Command === 'NextTrack') { - inputManager.handleCommand('next'); - } else if (msg.Data.Command === 'PreviousTrack') { - inputManager.handleCommand('previous'); - } else { - notifyApp(); - } - } else if (msg.MessageType === 'GeneralCommand') { - var cmd = msg.Data; - processGeneralCommand(cmd, apiClient); - } else if (msg.MessageType === 'UserDataChanged') { - if (msg.Data.UserId === apiClient.getCurrentUserId()) { - for (var i = 0, length = msg.Data.UserDataList.length; i < length; i++) { - events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]); - } - } - } else if (msg.MessageType === 'SyncPlayCommand') { - syncPlayManager.processCommand(msg.Data, apiClient); - } else if (msg.MessageType === 'SyncPlayGroupUpdate') { - syncPlayManager.processGroupUpdate(msg.Data, apiClient); - } else { - events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]); - } - } - function bindEvents(apiClient) { - events.off(apiClient, 'message', onMessageReceived); - events.on(apiClient, 'message', onMessageReceived); - } - - connectionManager.getApiClients().forEach(bindEvents); - events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) { - bindEvents(newApiClient); +function playTrailers(apiClient, itemId) { + apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + playbackManager.playTrailers(item); }); - return serverNotifications; +} + +function processGeneralCommand(cmd, apiClient) { + console.debug('Received command: ' + cmd.Name); + switch (cmd.Name) { + case 'Select': + inputManager.handleCommand('select'); + return; + case 'Back': + inputManager.handleCommand('back'); + return; + case 'MoveUp': + inputManager.handleCommand('up'); + return; + case 'MoveDown': + inputManager.handleCommand('down'); + return; + case 'MoveLeft': + inputManager.handleCommand('left'); + return; + case 'MoveRight': + inputManager.handleCommand('right'); + return; + case 'PageUp': + inputManager.handleCommand('pageup'); + return; + case 'PageDown': + inputManager.handleCommand('pagedown'); + return; + case 'PlayTrailers': + playTrailers(apiClient, cmd.Arguments.ItemId); + break; + case 'SetRepeatMode': + playbackManager.setRepeatMode(cmd.Arguments.RepeatMode); + break; + case 'SetShuffleQueue': + playbackManager.setQueueShuffleMode(cmd.Arguments.ShuffleMode); + break; + case 'VolumeUp': + inputManager.handleCommand('volumeup'); + return; + case 'VolumeDown': + inputManager.handleCommand('volumedown'); + return; + case 'ChannelUp': + inputManager.handleCommand('channelup'); + return; + case 'ChannelDown': + inputManager.handleCommand('channeldown'); + return; + case 'Mute': + inputManager.handleCommand('mute'); + return; + case 'Unmute': + inputManager.handleCommand('unmute'); + return; + case 'ToggleMute': + inputManager.handleCommand('togglemute'); + return; + case 'SetVolume': + notifyApp(); + playbackManager.setVolume(cmd.Arguments.Volume); + break; + case 'SetAudioStreamIndex': + notifyApp(); + playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index)); + break; + case 'SetSubtitleStreamIndex': + notifyApp(); + playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index)); + break; + case 'ToggleFullscreen': + inputManager.handleCommand('togglefullscreen'); + return; + case 'GoHome': + inputManager.handleCommand('home'); + return; + case 'GoToSettings': + inputManager.handleCommand('settings'); + return; + case 'DisplayContent': + displayContent(cmd, apiClient); + break; + case 'GoToSearch': + inputManager.handleCommand('search'); + return; + case 'DisplayMessage': + displayMessage(cmd); + break; + case 'ToggleOsd': + // todo + break; + case 'ToggleContextMenu': + // todo + break; + case 'TakeScreenShot': + // todo + break; + case 'SendKey': + // todo + break; + case 'SendString': + // todo + focusManager.sendText(cmd.Arguments.String); + break; + default: + console.debug('processGeneralCommand does not recognize: ' + cmd.Name); + break; + } + + notifyApp(); +} + +function onMessageReceived(e, msg) { + const apiClient = this; + if (msg.MessageType === 'Play') { + notifyApp(); + const serverId = apiClient.serverInfo().Id; + if (msg.Data.PlayCommand === 'PlayNext') { + playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId }); + } else if (msg.Data.PlayCommand === 'PlayLast') { + playbackManager.queue({ ids: msg.Data.ItemIds, serverId: serverId }); + } else { + playbackManager.play({ + ids: msg.Data.ItemIds, + startPositionTicks: msg.Data.StartPositionTicks, + mediaSourceId: msg.Data.MediaSourceId, + audioStreamIndex: msg.Data.AudioStreamIndex, + subtitleStreamIndex: msg.Data.SubtitleStreamIndex, + startIndex: msg.Data.StartIndex, + serverId: serverId + }); + } + } else if (msg.MessageType === 'Playstate') { + if (msg.Data.Command === 'Stop') { + inputManager.handleCommand('stop'); + } else if (msg.Data.Command === 'Pause') { + inputManager.handleCommand('pause'); + } else if (msg.Data.Command === 'Unpause') { + inputManager.handleCommand('play'); + } else if (msg.Data.Command === 'PlayPause') { + inputManager.handleCommand('playpause'); + } else if (msg.Data.Command === 'Seek') { + playbackManager.seek(msg.Data.SeekPositionTicks); + } else if (msg.Data.Command === 'NextTrack') { + inputManager.handleCommand('next'); + } else if (msg.Data.Command === 'PreviousTrack') { + inputManager.handleCommand('previous'); + } else { + notifyApp(); + } + } else if (msg.MessageType === 'GeneralCommand') { + const cmd = msg.Data; + processGeneralCommand(cmd, apiClient); + } else if (msg.MessageType === 'UserDataChanged') { + if (msg.Data.UserId === apiClient.getCurrentUserId()) { + for (let i = 0, length = msg.Data.UserDataList.length; i < length; i++) { + events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]); + } + } + } else if (msg.MessageType === 'SyncPlayCommand') { + syncPlayManager.processCommand(msg.Data, apiClient); + } else if (msg.MessageType === 'SyncPlayGroupUpdate') { + syncPlayManager.processGroupUpdate(msg.Data, apiClient); + } else { + events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]); + } +} +function bindEvents(apiClient) { + events.off(apiClient, 'message', onMessageReceived); + events.on(apiClient, 'message', onMessageReceived); +} + +connectionManager.getApiClients().forEach(bindEvents); +events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) { + bindEvents(newApiClient); }); + +export default serverNotifications; diff --git a/src/scripts/shell.js b/src/scripts/shell.js index 5a2afd9fd4..e42c7792a0 100644 --- a/src/scripts/shell.js +++ b/src/scripts/shell.js @@ -1,23 +1,20 @@ -define([], function () { - 'use strict'; - - return { - openUrl: function (url, target) { - if (window.NativeShell) { - window.NativeShell.openUrl(url, target); - } else { - window.open(url, target || '_blank'); - } - }, - enableFullscreen: function () { - if (window.NativeShell) { - window.NativeShell.enableFullscreen(); - } - }, - disableFullscreen: function () { - if (window.NativeShell) { - window.NativeShell.disableFullscreen(); - } +// TODO: This seems like a good candidate for deprecation +export default { + openUrl: function (url, target) { + if (window.NativeShell) { + window.NativeShell.openUrl(url, target); + } else { + window.open(url, target || '_blank'); } - }; -}); + }, + enableFullscreen: function () { + if (window.NativeShell) { + window.NativeShell.enableFullscreen(); + } + }, + disableFullscreen: function () { + if (window.NativeShell) { + window.NativeShell.disableFullscreen(); + } + } +};