diff --git a/src/apps/dashboard/controllers/library.js b/src/apps/dashboard/controllers/library.js index 86d7a1b4cd..f174e86ff1 100644 --- a/src/apps/dashboard/controllers/library.js +++ b/src/apps/dashboard/controllers/library.js @@ -7,7 +7,7 @@ import dom from 'scripts/dom'; import imageHelper from 'utils/image'; import 'components/cardbuilder/card.scss'; import 'elements/emby-itemrefreshindicator/emby-itemrefreshindicator'; -import Dashboard, { pageClassOn, pageIdOn } from 'utils/dashboard'; +import { pageClassOn, pageIdOn } from 'utils/dashboard'; import confirm from 'components/confirm/confirm'; import { getDefaultBackgroundClass } from 'components/cardbuilder/cardBuilderUtils'; @@ -256,14 +256,9 @@ function getCollectionTypeOptions() { function getVirtualFolderHtml(page, virtualFolder, index) { let html = ''; - let style = ''; - - if (page.classList.contains('wizardPage')) { - style += 'min-width:33.3%;'; - } const elementId = virtualFolder.elementId ? `id="${virtualFolder.elementId}" ` : ''; - html += '
'; + html += '
'; html += '
'; html += '
'; @@ -364,11 +359,6 @@ function getVirtualFolderHtml(page, virtualFolder, index) { return html; } -window.WizardLibraryPage = { - next: function () { - Dashboard.navigate('wizardsettings.html'); - } -}; pageClassOn('pageshow', 'mediaLibraryPage', function () { reloadLibrary(this); }); diff --git a/src/apps/experimental/routes/legacyRoutes/public.ts b/src/apps/experimental/routes/legacyRoutes/public.ts index 4fdb6a9395..1fec40eaad 100644 --- a/src/apps/experimental/routes/legacyRoutes/public.ts +++ b/src/apps/experimental/routes/legacyRoutes/public.ts @@ -53,7 +53,7 @@ export const LEGACY_PUBLIC_ROUTES: LegacyRoute[] = [ { path: 'wizardlibrary.html', pageProps: { - controller: 'dashboard/library', + controller: 'wizard/library', view: 'wizard/library.html' } }, diff --git a/src/apps/stable/routes/legacyRoutes/public.ts b/src/apps/stable/routes/legacyRoutes/public.ts index 4fdb6a9395..1fec40eaad 100644 --- a/src/apps/stable/routes/legacyRoutes/public.ts +++ b/src/apps/stable/routes/legacyRoutes/public.ts @@ -53,7 +53,7 @@ export const LEGACY_PUBLIC_ROUTES: LegacyRoute[] = [ { path: 'wizardlibrary.html', pageProps: { - controller: 'dashboard/library', + controller: 'wizard/library', view: 'wizard/library.html' } }, diff --git a/src/controllers/wizard/library.js b/src/controllers/wizard/library.js new file mode 100644 index 0000000000..27bcde9c52 --- /dev/null +++ b/src/controllers/wizard/library.js @@ -0,0 +1,388 @@ +import escapeHtml from 'escape-html'; + +import taskButton from 'scripts/taskbutton'; +import loading from 'components/loading/loading'; +import globalize from 'lib/globalize'; +import dom from 'scripts/dom'; +import imageHelper from 'utils/image'; +import 'components/cardbuilder/card.scss'; +import 'elements/emby-itemrefreshindicator/emby-itemrefreshindicator'; +import Dashboard, { pageClassOn, pageIdOn } from 'utils/dashboard'; +import confirm from 'components/confirm/confirm'; +import { getDefaultBackgroundClass } from 'components/cardbuilder/cardBuilderUtils'; + +function addVirtualFolder(page) { + import('components/mediaLibraryCreator/mediaLibraryCreator').then(({ default: MediaLibraryCreator }) => { + new MediaLibraryCreator({ + collectionTypeOptions: getCollectionTypeOptions().filter(function (f) { + return !f.hidden; + }), + refresh: shouldRefreshLibraryAfterChanges(page) + }).then(function (hasChanges) { + if (hasChanges) { + reloadLibrary(page); + } + }); + }); +} + +function editVirtualFolder(page, virtualFolder) { + import('components/mediaLibraryEditor/mediaLibraryEditor').then(({ default: MediaLibraryEditor }) => { + new MediaLibraryEditor({ + refresh: shouldRefreshLibraryAfterChanges(page), + library: virtualFolder + }).then(function (hasChanges) { + if (hasChanges) { + reloadLibrary(page); + } + }); + }); +} + +function deleteVirtualFolder(page, virtualFolder) { + let msg = globalize.translate('MessageAreYouSureYouWishToRemoveMediaFolder'); + + if (virtualFolder.Locations.length) { + msg += '

' + globalize.translate('MessageTheFollowingLocationWillBeRemovedFromLibrary') + '

'; + msg += virtualFolder.Locations.join('
'); + } + + confirm({ + text: msg, + title: globalize.translate('HeaderRemoveMediaFolder'), + confirmText: globalize.translate('Delete'), + primary: 'delete' + }).then(function () { + const refreshAfterChange = shouldRefreshLibraryAfterChanges(page); + ApiClient.removeVirtualFolder(virtualFolder.Name, refreshAfterChange).then(function () { + reloadLibrary(page); + }); + }); +} + +function refreshVirtualFolder(page, virtualFolder) { + import('components/refreshdialog/refreshdialog').then(({ default: RefreshDialog }) => { + new RefreshDialog({ + itemIds: [virtualFolder.ItemId], + serverId: ApiClient.serverId(), + mode: 'scan' + }).show(); + }); +} + +function renameVirtualFolder(page, virtualFolder) { + import('components/prompt/prompt').then(({ default: prompt }) => { + prompt({ + label: globalize.translate('LabelNewName'), + description: globalize.translate('MessageRenameMediaFolder'), + confirmText: globalize.translate('ButtonRename') + }).then(function (newName) { + if (newName && newName != virtualFolder.Name) { + const refreshAfterChange = shouldRefreshLibraryAfterChanges(page); + ApiClient.renameVirtualFolder(virtualFolder.Name, newName, refreshAfterChange).then(function () { + reloadLibrary(page); + }); + } + }); + }); +} + +function showCardMenu(page, elem, virtualFolders) { + const card = dom.parentWithClass(elem, 'card'); + const index = parseInt(card.getAttribute('data-index'), 10); + const virtualFolder = virtualFolders[index]; + const menuItems = []; + menuItems.push({ + name: globalize.translate('EditImages'), + id: 'editimages', + icon: 'photo' + }); + menuItems.push({ + name: globalize.translate('ManageLibrary'), + id: 'edit', + icon: 'folder' + }); + menuItems.push({ + name: globalize.translate('ButtonRename'), + id: 'rename', + icon: 'mode_edit' + }); + menuItems.push({ + name: globalize.translate('ScanLibrary'), + id: 'refresh', + icon: 'refresh' + }); + menuItems.push({ + name: globalize.translate('ButtonRemove'), + id: 'delete', + icon: 'delete' + }); + + import('components/actionSheet/actionSheet').then((actionsheet) => { + actionsheet.show({ + items: menuItems, + positionTo: elem, + callback: function (resultId) { + switch (resultId) { + case 'edit': + editVirtualFolder(page, virtualFolder); + break; + + case 'editimages': + editImages(page, virtualFolder); + break; + + case 'rename': + renameVirtualFolder(page, virtualFolder); + break; + + case 'delete': + deleteVirtualFolder(page, virtualFolder); + break; + + case 'refresh': + refreshVirtualFolder(page, virtualFolder); + } + } + }); + }); +} + +function reloadLibrary(page) { + loading.show(); + ApiClient.getVirtualFolders().then(function (result) { + reloadVirtualFolders(page, result); + }); +} + +function shouldRefreshLibraryAfterChanges(page) { + return page.id === 'mediaLibraryPage'; +} + +function reloadVirtualFolders(page, virtualFolders) { + let html = ''; + virtualFolders.push({ + Name: globalize.translate('ButtonAddMediaLibrary'), + icon: 'add_circle', + Locations: [], + showType: false, + showLocations: false, + showMenu: false, + showNameWithIcon: false, + elementId: 'addLibrary' + }); + + for (let i = 0; i < virtualFolders.length; i++) { + const virtualFolder = virtualFolders[i]; + html += getVirtualFolderHtml(page, virtualFolder, i); + } + + const divVirtualFolders = page.querySelector('#divVirtualFolders'); + divVirtualFolders.innerHTML = html; + divVirtualFolders.classList.add('itemsContainer'); + divVirtualFolders.classList.add('vertical-wrap'); + const btnCardMenuElements = divVirtualFolders.querySelectorAll('.btnCardMenu'); + btnCardMenuElements.forEach(function (btn) { + btn.addEventListener('click', function () { + showCardMenu(page, btn, virtualFolders); + }); + }); + divVirtualFolders.querySelector('#addLibrary').addEventListener('click', function () { + addVirtualFolder(page); + }); + + const libraryEditElements = divVirtualFolders.querySelectorAll('.editLibrary'); + libraryEditElements.forEach(function (btn) { + btn.addEventListener('click', function () { + const card = dom.parentWithClass(btn, 'card'); + const index = parseInt(card.getAttribute('data-index'), 10); + const virtualFolder = virtualFolders[index]; + + if (virtualFolder.ItemId) { + editVirtualFolder(page, virtualFolder); + } + }); + }); + loading.hide(); +} + +function editImages(page, virtualFolder) { + import('components/imageeditor/imageeditor').then((imageEditor) => { + imageEditor.show({ + itemId: virtualFolder.ItemId, + serverId: ApiClient.serverId() + }).then(function () { + reloadLibrary(page); + }); + }); +} + +function getLink(text, url) { + return globalize.translate(text, '', ''); +} + +function getCollectionTypeOptions() { + return [{ + name: '', + value: '' + }, { + name: globalize.translate('Movies'), + value: 'movies', + message: getLink('MovieLibraryHelp', 'https://jellyfin.org/docs/general/server/media/movies') + }, { + name: globalize.translate('TabMusic'), + value: 'music', + message: getLink('MusicLibraryHelp', 'https://jellyfin.org/docs/general/server/media/music') + }, { + name: globalize.translate('Shows'), + value: 'tvshows', + message: getLink('TvLibraryHelp', 'https://jellyfin.org/docs/general/server/media/shows') + }, { + name: globalize.translate('Books'), + value: 'books', + message: getLink('BookLibraryHelp', 'https://jellyfin.org/docs/general/server/media/books') + }, { + name: globalize.translate('HomeVideosPhotos'), + value: 'homevideos' + }, { + name: globalize.translate('MusicVideos'), + value: 'musicvideos' + }, { + name: globalize.translate('MixedMoviesShows'), + value: 'mixed', + message: globalize.translate('MessageUnsetContentHelp') + }]; +} + +function getVirtualFolderHtml(page, virtualFolder, index) { + let html = ''; + + const elementId = virtualFolder.elementId ? `id="${virtualFolder.elementId}" ` : ''; + html += '
'; + + html += '
'; + html += '
'; + html += '
'; + html += '
'; + let imgUrl = ''; + + if (virtualFolder.PrimaryImageItemId) { + imgUrl = ApiClient.getScaledImageUrl(virtualFolder.PrimaryImageItemId, { + maxWidth: Math.round(dom.getScreenWidth() * 0.40), + type: 'Primary' + }); + } + + let hasCardImageContainer; + + if (imgUrl) { + html += `
`; + html += ``; + hasCardImageContainer = true; + } else if (!virtualFolder.showNameWithIcon) { + html += `
`; + html += ''; + hasCardImageContainer = true; + } + + if (hasCardImageContainer) { + html += '
'; + html += '
'; + html += '
'; + html += '
'; + } + + if (!imgUrl && virtualFolder.showNameWithIcon) { + html += '

'; + html += ''; + + if (virtualFolder.showNameWithIcon) { + html += '
'; + html += escapeHtml(virtualFolder.Name); + html += '
'; + } + + html += '

'; + } + + html += '
'; + html += '
'; + html += '
'; // always show menu unless explicitly hidden + + if (virtualFolder.showMenu !== false) { + const dirTextAlign = globalize.getIsRTL() ? 'left' : 'right'; + html += '
'; + html += ''; + html += '
'; + } + + html += "
"; + + if (virtualFolder.showNameWithIcon) { + html += ' '; + } else { + html += escapeHtml(virtualFolder.Name); + } + + html += '
'; + let typeName = getCollectionTypeOptions().filter(function (t) { + return t.value == virtualFolder.CollectionType; + })[0]; + typeName = typeName ? typeName.name : globalize.translate('Other'); + html += "
"; + + if (virtualFolder.showType === false) { + html += ' '; + } else { + html += typeName; + } + + html += '
'; + + if (virtualFolder.showLocations === false) { + html += "
"; + html += ' '; + html += '
'; + } else if (virtualFolder.Locations.length && virtualFolder.Locations.length === 1) { + html += "
"; + html += virtualFolder.Locations[0]; + html += '
'; + } else { + html += "
"; + html += globalize.translate('NumLocationsValue', virtualFolder.Locations.length); + html += '
'; + } + + html += '
'; + html += '
'; + html += '
'; + return html; +} + +window.WizardLibraryPage = { + next: function () { + Dashboard.navigate('wizardsettings.html'); + } +}; +pageClassOn('pageshow', 'mediaLibraryPage', function () { + reloadLibrary(this); +}); +pageIdOn('pageshow', 'mediaLibraryPage', function () { + const page = this; + taskButton({ + mode: 'on', + progressElem: page.querySelector('.refreshProgress'), + taskKey: 'RefreshLibrary', + button: page.querySelector('.btnRefresh') + }); +}); +pageIdOn('pagebeforehide', 'mediaLibraryPage', function () { + const page = this; + taskButton({ + mode: 'off', + progressElem: page.querySelector('.refreshProgress'), + taskKey: 'RefreshLibrary', + button: page.querySelector('.btnRefresh') + }); +}); +