From 2da642c90a2254b496602d452ef2c107751d5ffd Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 17 Oct 2019 17:42:37 +0300 Subject: [PATCH] sample discover picker linked with stremio core --- src/routes/Discover/Discover.js | 9 +- src/routes/Discover/styles.less | 4 +- src/routes/Discover/useCatalog.js | 189 +++++++++++++++--------------- 3 files changed, 102 insertions(+), 100 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index e060cb12f..6954cbed0 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -1,14 +1,15 @@ const React = require('react'); const classnames = require('classnames'); -const { Dropdown, MainNavBar, MetaItem, MetaPreview } = require('stremio/common'); +const { MainNavBar, MetaItem, MetaPreview, Multiselect } = require('stremio/common'); const useCatalog = require('./useCatalog'); const styles = require('./styles'); +// TODO render only 4 pickers and a more button that opens a modal with all pickers const Discover = ({ urlParams, queryParams }) => { const [dropdowns, metaItems] = useCatalog(urlParams, queryParams); const [selectedItem, setSelectedItem] = React.useState(null); const metaItemsOnMouseDown = React.useCallback((event) => { - event.nativeEvent.blurPrevented = true; + event.nativeEvent.buttonBlurPrevented = true; }, []); const metaItemsOnFocus = React.useCallback((event) => { const metaItem = metaItems.find(({ id }) => { @@ -27,8 +28,8 @@ const Discover = ({ urlParams, queryParams }) => {
- {dropdowns.map((dropdown) => ( - + {dropdowns.map((dropdown, index) => ( + ))}
diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 0f8251548..8f972da85 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -17,7 +17,7 @@ align-self: stretch; display: grid; grid-template-columns: 1fr 26rem; - grid-template-rows: fit-content(15rem) 1fr; + grid-template-rows: 7rem 1fr; grid-template-areas: "dropdowns-area meta-preview-area" "meta-items-area meta-preview-area"; @@ -29,7 +29,7 @@ grid-gap: 1rem; margin: 2rem 0; padding: 0 2rem; - overflow-y: auto; + overflow: visible; .dropdown { height: 3rem; diff --git a/src/routes/Discover/useCatalog.js b/src/routes/Discover/useCatalog.js index 77dc11da4..bb81dbf13 100644 --- a/src/routes/Discover/useCatalog.js +++ b/src/routes/Discover/useCatalog.js @@ -1,104 +1,105 @@ const React = require('react'); +const { useServices } = require('stremio/services'); + +const DEFAULT_TYPE = 'movie'; +const DEFAULT_ADDON_ID = 'com.linvo.cinemeta'; +const DEFAULT_CATALOG_ID = 'top'; const useCatalog = (urlParams, queryParams) => { - const queryString = new URLSearchParams(queryParams).toString(); - const [addon, catalog] = React.useMemo(() => { - // TODO impl this logic to stremio-core for code-reuse: - // TODO use type if it is part of user's addons - // TODO fallback to first type from user's addons - // TODO find catalog for addonId, catalogId and type - // TODO fallback to first catalog for the type from user's catalogs - const addon = { - id: 'com.linvo.cinemeta', - version: '2.11.0', - name: 'Cinemeta' - }; - const catalog = { - id: 'top', - type: 'movie', - name: 'Top', - extra: [ - { - name: 'genre', - isRequired: false, - options: ['Action', 'Drama', 'Boring'] - }, - { - name: 'year', - isRequired: false, - options: ['2017', '2016', '2015'] + const { core } = useServices(); + const [selectInputs, setSelectInputs] = React.useState([]); + React.useEffect(() => { + const onNewModel = () => { + const state = core.getState(); + const typeSelectInput = { + options: [{ value: urlParams.type, label: urlParams.type }].concat(state.discover.types.map(({ type_name }) => ({ + value: type_name, + label: type_name + }))).filter((item, index, array) => { + // TODO findIndexRight + return array.findIndex(({ value }) => value === item.value) === index; + }), + selected: [urlParams.type].concat(state.discover.types.filter(({ is_selected }) => is_selected) + .map(({ type_name }) => type_name)) + .filter((item, index, array) => { + return array.indexOf(item) === index; + }), + onSelect: (event) => { + const value = event.reactEvent.currentTarget.dataset.value; + // TODO queryparams + window.location = `#/discover/${value}/${typeof urlParams.catalog === 'string' ? urlParams.catalog : ''}`; } - ] + }; + console.log(typeSelectInput); + setSelectInputs([typeSelectInput]); }; - return [addon, catalog]; - }, [urlParams.type, urlParams.catalog]); - const dropdowns = React.useMemo(() => { - const onTypeChange = (event) => { - const { value } = event.currentTarget.dataset; - const query = new URLSearchParams(queryParams); - window.location = `#/discover/${value}/${addon.id}:${catalog.id}?${query}`; + core.on('NewModel', onNewModel); + return () => { + core.off('NewModel', onNewModel); }; - const onCatalogChange = (event) => { - const { value } = event.currentTarget.dataset; - const query = new URLSearchParams(queryParams); - window.location = `#/discover/${catalog.type}/${value}?${query}`; - }; - const onQueryParamChange = (event) => { - const { name, value } = event.currentTarget.dataset; - const query = new URLSearchParams({ ...queryParams, [name]: value }); - window.location = `#/discover/${catalog.type}/${addon.id}:${catalog.id}?${query}`; - }; - const requiredDropdowns = [ - { - name: 'type', - selected: [catalog.type], - options: [ - { value: 'movie', label: 'movie' }, - { value: 'series', label: 'series' }, - { value: 'channels', label: 'channels' }, - { value: 'games', label: 'games' } - ], - onSelect: onTypeChange - }, - { - name: 'catalog', - selected: [`${addon.id}:${catalog.id}`], - options: [ - { value: 'com.linvo.cinemeta:top', label: 'Top' }, - { value: 'com.linvo.cinemeta:year', label: 'By year' } - ], - onSelect: onCatalogChange + }, [urlParams, queryParams]); + React.useEffect(() => { + const state = core.getState(); + let type = DEFAULT_TYPE; + let addonId = DEFAULT_ADDON_ID; + let catalogId = DEFAULT_CATALOG_ID; + if (typeof urlParams.type === 'string' && urlParams.type.length > 0) { + type = urlParams.type; + addonId = null; + catalogId = null; + if (typeof urlParams.catalog === 'string' && urlParams.catalog.includes(':')) { + [addonId = '', catalogId = ''] = urlParams.catalog.split(':'); } - ]; - const extraDropdowns = catalog.extra - .filter((extra) => { - return extra.name !== 'skip' && extra.name !== 'search'; - }) - .map((extra) => ({ - ...extra, - onSelect: onQueryParamChange, - options: extra.options.map((option) => ({ value: option, label: option })), - selected: extra.options.includes(queryParams[extra.name]) ? - [queryParams[extra.name]] - : - extra.isRequired ? - [extra.options[0]] - : - [] - })); - return requiredDropdowns.concat(extraDropdowns); - }, [addon, catalog, queryString]); - const items = React.useMemo(() => { - return Array(100).fill(null).map((_, index) => ({ - id: `tt${index}`, - type: 'movie', - name: `Stremio demo item ${index}`, - poster: `https://www.stremio.com/website/technology-hero.jpg`, - logo: `https://www.stremio.com/website/stremio-logo-small.png`, - posterShape: 'poster' - })); - }, []); - return [dropdowns, items]; + } + + const [addon, catalog] = state.ctx.content.addons.reduceRight((result, addon) => { + if (typeof addonId !== 'string' || addonId === addon.manifest.id) { + const catalog = addon.manifest.catalogs.find((catalog) => { + return (typeof catalogId !== 'string' || catalogId === catalog.id) && + catalog.type === type; // TODO && extraRequired.every(...); + }); + if (catalog) { + return [addon, catalog]; + } + } + + return result; + }, []); + if (catalog) { + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogFiltered', + args: { + base: addon.transportUrl, + path: { + resource: 'catalog', + type_name: type, + id: catalog.id, + extra: [] // TODO + } + } + } + }); + } else { + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogFiltered', + args: { + base: '', + path: { + resource: 'catalog', + type_name: type, + id: '', + extra: [] // TODO + } + } + } + }); + } + }, [urlParams, queryParams]); + return [selectInputs, []]; }; module.exports = useCatalog;