mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
Merge branch 'development' of github.com:Stremio/stremio-web into mobile
This commit is contained in:
commit
211f478e8a
12 changed files with 121 additions and 34 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -1833,9 +1833,9 @@
|
|||
"integrity": "sha512-yT3No1gIWKLV2BhQIeSgG94EzXxmEqXJLulO+pFpziqWNUbmmEKeE+nRvW5wtoIK4SLy+v0bLd0b6HBH3KFfWw=="
|
||||
},
|
||||
"@stremio/stremio-core-web": {
|
||||
"version": "0.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.35.0.tgz",
|
||||
"integrity": "sha512-MN5Mb+5yYV5MQXjzeShqJJeRXc4QLoLP/6TbE6ay6kq8PQ8bT7BreFiFVJunICVo/OmXjYNS3CiJhM5q1J4xZw==",
|
||||
"version": "0.36.0",
|
||||
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.36.0.tgz",
|
||||
"integrity": "sha512-A63yB+Pml/c6jtK4l5r7aacZ2Jm+ofaj60MfVCZfzSE4csBPMuoROYx6TM6nI6NU8iUDTcIU+OYoWcMfaT7v7A==",
|
||||
"requires": {
|
||||
"@babel/runtime": "7.15.4"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"@babel/runtime": "7.16.0",
|
||||
"@sentry/browser": "6.13.3",
|
||||
"@stremio/stremio-colors": "4.0.1",
|
||||
"@stremio/stremio-core-web": "0.35.0",
|
||||
"@stremio/stremio-core-web": "0.36.0",
|
||||
"@stremio/stremio-icons": "3.0.5",
|
||||
"@stremio/stremio-video": "0.0.19-rc.1",
|
||||
"a-color-picker": "1.2.1",
|
||||
|
|
|
|||
30
src/common/getVisibleChildrenRange.js
Normal file
30
src/common/getVisibleChildrenRange.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (C) 2017-2022 Smart code 203358507
|
||||
|
||||
const isChildVisible = (container, element, threshold) => {
|
||||
const elementTop = element.offsetTop;
|
||||
const elementBottom = element.offsetTop + element.clientHeight;
|
||||
const containerTop = container.scrollTop - threshold;
|
||||
const containerBottom = container.scrollTop + container.clientHeight + threshold;
|
||||
return (elementTop >= containerTop && elementBottom <= containerBottom) ||
|
||||
(elementTop < containerTop && containerTop < elementBottom) ||
|
||||
(elementTop < containerBottom && containerBottom < elementBottom);
|
||||
};
|
||||
|
||||
const getVisibleChildrenRange = (container, threshold) => {
|
||||
return Array.from(container.children).reduce((result, child, index) => {
|
||||
if (isChildVisible(container, child, threshold)) {
|
||||
if (result === null) {
|
||||
result = {
|
||||
start: index,
|
||||
end: index
|
||||
};
|
||||
} else {
|
||||
result.end = index;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, null);
|
||||
};
|
||||
|
||||
module.exports = getVisibleChildrenRange;
|
||||
|
|
@ -24,6 +24,7 @@ const TextInput = require('./TextInput');
|
|||
const { ToastProvider, useToast } = require('./Toast');
|
||||
const comparatorWithPriorities = require('./comparatorWithPriorities');
|
||||
const CONSTANTS = require('./CONSTANTS');
|
||||
const getVisibleChildrenRange = require('./getVisibleChildrenRange');
|
||||
const languageNames = require('./languageNames');
|
||||
const routesRegexp = require('./routesRegexp');
|
||||
const sanitizeLocationPath = require('./sanitizeLocationPath');
|
||||
|
|
@ -65,6 +66,7 @@ module.exports = {
|
|||
useToast,
|
||||
comparatorWithPriorities,
|
||||
CONSTANTS,
|
||||
getVisibleChildrenRange,
|
||||
languageNames,
|
||||
routesRegexp,
|
||||
sanitizeLocationPath,
|
||||
|
|
|
|||
|
|
@ -2,20 +2,43 @@
|
|||
|
||||
const React = require('react');
|
||||
const classnames = require('classnames');
|
||||
const { MainNavBars, MetaRow, LibItem, MetaItem, StreamingServerWarning, useProfile, useStreamingServer } = require('stremio/common');
|
||||
const debounce = require('lodash.debounce');
|
||||
const { MainNavBars, MetaRow, LibItem, MetaItem, StreamingServerWarning, useProfile, useStreamingServer, getVisibleChildrenRange } = require('stremio/common');
|
||||
const useBoard = require('./useBoard');
|
||||
const useContinueWatchingPreview = require('./useContinueWatchingPreview');
|
||||
const styles = require('./styles');
|
||||
|
||||
const THRESHOLD = 300;
|
||||
|
||||
const Board = () => {
|
||||
const board = useBoard();
|
||||
const profile = useProfile();
|
||||
const streamingServer = useStreamingServer();
|
||||
const continueWatchingPreview = useContinueWatchingPreview();
|
||||
const [board, loadBoardRows] = useBoard();
|
||||
const boardCatalogsOffset = continueWatchingPreview.libraryItems.length > 0 ? 1 : 0;
|
||||
const scrollContainerRef = React.useRef();
|
||||
const onVisibleRangeChange = React.useCallback(() => {
|
||||
const range = getVisibleChildrenRange(scrollContainerRef.current, THRESHOLD);
|
||||
if (range === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const start = Math.max(0, range.start - boardCatalogsOffset);
|
||||
const end = range.end - boardCatalogsOffset;
|
||||
if (end < start) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadBoardRows({ start, end });
|
||||
}, [boardCatalogsOffset]);
|
||||
const onScroll = React.useCallback(debounce(onVisibleRangeChange, 250), [onVisibleRangeChange]);
|
||||
React.useLayoutEffect(() => {
|
||||
onVisibleRangeChange();
|
||||
}, [board.catalogs, onVisibleRangeChange]);
|
||||
return (
|
||||
<div className={styles['board-container']}>
|
||||
<MainNavBars className={styles['board-content-container']} route={'board'}>
|
||||
<div className={styles['board-content']}>
|
||||
<div ref={scrollContainerRef} className={styles['board-content']} onScroll={onScroll}>
|
||||
{
|
||||
continueWatchingPreview.libraryItems.length > 0 ?
|
||||
<MetaRow
|
||||
|
|
@ -29,7 +52,7 @@ const Board = () => {
|
|||
null
|
||||
}
|
||||
{board.catalogs.map((catalog, index) => {
|
||||
switch (catalog.content.type) {
|
||||
switch (catalog.content?.type) {
|
||||
case 'Ready': {
|
||||
return (
|
||||
<MetaRow
|
||||
|
|
@ -53,7 +76,7 @@ const Board = () => {
|
|||
/>
|
||||
);
|
||||
}
|
||||
case 'Loading': {
|
||||
default: {
|
||||
return (
|
||||
<MetaRow.Placeholder
|
||||
key={index}
|
||||
|
|
|
|||
|
|
@ -28,15 +28,7 @@
|
|||
overflow-y: auto;
|
||||
|
||||
.board-row {
|
||||
margin: 4rem 2rem;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (C) 2017-2022 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const init = () => ({
|
||||
|
|
@ -9,6 +10,7 @@ const init = () => ({
|
|||
});
|
||||
|
||||
const useBoard = () => {
|
||||
const { core } = useServices();
|
||||
const action = React.useMemo(() => ({
|
||||
action: 'Load',
|
||||
args: {
|
||||
|
|
@ -16,7 +18,17 @@ const useBoard = () => {
|
|||
args: { extra: [] }
|
||||
}
|
||||
}), []);
|
||||
return useModelState({ model: 'board', timeout: 1500, action, init });
|
||||
const loadRange = React.useCallback((range) => {
|
||||
core.transport.dispatch({
|
||||
action: 'CatalogsWithExtra',
|
||||
args: {
|
||||
action: 'LoadRange',
|
||||
args: range
|
||||
}
|
||||
}, 'board');
|
||||
}, []);
|
||||
const board = useModelState({ model: 'board', timeout: 1500, action, init });
|
||||
return [board, loadRange];
|
||||
};
|
||||
|
||||
module.exports = useBoard;
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@
|
|||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const debounce = require('lodash.debounce');
|
||||
const Icon = require('@stremio/stremio-icons/dom');
|
||||
const { Image, MainNavBars, MetaRow, MetaItem, useDeepEqualMemo } = require('stremio/common');
|
||||
const { Image, MainNavBars, MetaRow, MetaItem, useDeepEqualMemo, getVisibleChildrenRange } = require('stremio/common');
|
||||
const useSearch = require('./useSearch');
|
||||
const styles = require('./styles');
|
||||
|
||||
const THRESHOLD = 100;
|
||||
|
||||
const Search = ({ queryParams }) => {
|
||||
const search = useSearch(queryParams);
|
||||
const [search, loadSearchRows] = useSearch(queryParams);
|
||||
const query = useDeepEqualMemo(() => {
|
||||
return search.selected !== null ?
|
||||
search.selected.extra.reduceRight((query, [name, value]) => {
|
||||
|
|
@ -22,9 +25,26 @@ const Search = ({ queryParams }) => {
|
|||
:
|
||||
null;
|
||||
}, [search.selected]);
|
||||
const scrollContainerRef = React.useRef();
|
||||
const onVisibleRangeChange = React.useCallback(() => {
|
||||
if (search.catalogs.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const range = getVisibleChildrenRange(scrollContainerRef.current, THRESHOLD);
|
||||
if (range === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadSearchRows(range);
|
||||
}, [search.catalogs]);
|
||||
const onScroll = React.useCallback(debounce(onVisibleRangeChange, 250), [onVisibleRangeChange]);
|
||||
React.useLayoutEffect(() => {
|
||||
onVisibleRangeChange();
|
||||
}, [search.catalogs, onVisibleRangeChange]);
|
||||
return (
|
||||
<MainNavBars className={styles['search-container']} route={'search'} query={query}>
|
||||
<div className={styles['search-content']}>
|
||||
<div ref={scrollContainerRef} className={styles['search-content']} onScroll={onScroll}>
|
||||
{
|
||||
query === null ?
|
||||
<div className={styles['search-hints-container']}>
|
||||
|
|
@ -49,7 +69,7 @@ const Search = ({ queryParams }) => {
|
|||
</div>
|
||||
:
|
||||
search.catalogs.map((catalog, index) => {
|
||||
switch (catalog.content.type) {
|
||||
switch (catalog.content?.type) {
|
||||
case 'Ready': {
|
||||
return (
|
||||
<MetaRow
|
||||
|
|
@ -73,7 +93,7 @@ const Search = ({ queryParams }) => {
|
|||
/>
|
||||
);
|
||||
}
|
||||
case 'Loading': {
|
||||
default: {
|
||||
return (
|
||||
<MetaRow.Placeholder
|
||||
key={index}
|
||||
|
|
|
|||
|
|
@ -22,15 +22,7 @@
|
|||
overflow-y: auto;
|
||||
|
||||
.search-row {
|
||||
margin: 4rem 2rem;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.search-hints-container {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,17 @@ const useSearch = (queryParams) => {
|
|||
};
|
||||
}
|
||||
}, [queryParams]);
|
||||
return useModelState({ model: 'search', action, init });
|
||||
const loadRange = React.useCallback((range) => {
|
||||
core.transport.dispatch({
|
||||
action: 'CatalogsWithExtra',
|
||||
args: {
|
||||
action: 'LoadRange',
|
||||
args: range
|
||||
}
|
||||
}, 'search');
|
||||
}, []);
|
||||
const search = useModelState({ model: 'search', action, init });
|
||||
return [search, loadRange];
|
||||
};
|
||||
|
||||
module.exports = useSearch;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@ function ChromecastTransport() {
|
|||
this.off = function(name, listener) {
|
||||
events.off(name, listener);
|
||||
};
|
||||
this.removeAllListeners = function() {
|
||||
events.removeAllListeners();
|
||||
};
|
||||
this.getCastState = function() {
|
||||
return cast.framework.CastContext.getInstance().getCastState();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ function CoreTransport() {
|
|||
this.off = function(name, listener) {
|
||||
events.off(name, listener);
|
||||
};
|
||||
this.removeAllListeners = function() {
|
||||
events.removeAllListeners();
|
||||
};
|
||||
this.getState = function(field) {
|
||||
return get_state(field);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue