diff --git a/package-lock.json b/package-lock.json index 0986d2e18..bca5effec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" }, diff --git a/package.json b/package.json index ad1a598d9..d40b607a4 100755 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/common/getVisibleChildrenRange.js b/src/common/getVisibleChildrenRange.js new file mode 100644 index 000000000..f389349e6 --- /dev/null +++ b/src/common/getVisibleChildrenRange.js @@ -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; diff --git a/src/common/index.js b/src/common/index.js index bcd66a99b..24868a2c7 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -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, diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index fef7ae766..2cbe193c9 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -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 (