mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
Merge pull request #595 from Stremio/refactor/library-infinite-scroll
Library infinite scroll
This commit is contained in:
commit
d6238014dd
4 changed files with 31 additions and 58 deletions
|
|
@ -5,11 +5,13 @@ const PropTypes = require('prop-types');
|
|||
const classnames = require('classnames');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const NotFound = require('stremio/routes/NotFound');
|
||||
const { Button, DelayedRenderer, Multiselect, MainNavBars, LibItem, Image, ModalDialog, PaginationInput, useProfile, useNotifications, routesRegexp, useBinaryState, withCoreSuspender } = require('stremio/common');
|
||||
const { Button, DelayedRenderer, Multiselect, MainNavBars, LibItem, Image, ModalDialog, useProfile, useNotifications, routesRegexp, useOnScrollToBottom, useBinaryState, withCoreSuspender } = require('stremio/common');
|
||||
const useLibrary = require('./useLibrary');
|
||||
const useSelectableInputs = require('./useSelectableInputs');
|
||||
const styles = require('./styles');
|
||||
|
||||
const SCROLL_TO_BOTTOM_TRESHOLD = 400;
|
||||
|
||||
function withModel(Library) {
|
||||
const withModel = ({ urlParams, queryParams }) => {
|
||||
const model = React.useMemo(() => {
|
||||
|
|
@ -46,9 +48,21 @@ function withModel(Library) {
|
|||
const Library = ({ model, urlParams, queryParams }) => {
|
||||
const profile = useProfile();
|
||||
const notifications = useNotifications();
|
||||
const library = useLibrary(model, urlParams, queryParams);
|
||||
const [typeSelect, sortSelect, paginationInput] = useSelectableInputs(library);
|
||||
const [library, loadNextPage] = useLibrary(model, urlParams, queryParams);
|
||||
const [typeSelect, sortSelect, hasNextPage] = useSelectableInputs(library);
|
||||
const [inputsModalOpen, openInputsModal, closeInputsModal] = useBinaryState(false);
|
||||
const scrollContainerRef = React.useRef(null);
|
||||
const onScrollToBottom = React.useCallback(() => {
|
||||
if (hasNextPage) {
|
||||
loadNextPage();
|
||||
}
|
||||
}, [hasNextPage, loadNextPage]);
|
||||
const onScroll = useOnScrollToBottom(onScrollToBottom, SCROLL_TO_BOTTOM_TRESHOLD);
|
||||
React.useLayoutEffect(() => {
|
||||
if (profile.auth !== null && library.selected && library.selected.request.page === 1) {
|
||||
scrollContainerRef.current.scrollTop = 0;
|
||||
}
|
||||
}, [profile.auth, library.selected]);
|
||||
return (
|
||||
<MainNavBars className={styles['library-container']} route={model}>
|
||||
<div className={styles['library-content']}>
|
||||
|
|
@ -58,12 +72,6 @@ const Library = ({ model, urlParams, queryParams }) => {
|
|||
<Multiselect {...typeSelect} className={styles['select-input-container']} />
|
||||
<Multiselect {...sortSelect} className={styles['select-input-container']} />
|
||||
<div className={styles['spacing']} />
|
||||
{
|
||||
paginationInput !== null ?
|
||||
<PaginationInput {...paginationInput} className={styles['pagination-input']} />
|
||||
:
|
||||
null
|
||||
}
|
||||
<Button className={styles['filter-container']} title={'All filters'} onClick={openInputsModal}>
|
||||
<Icon className={styles['filter-icon']} name={'filters'} />
|
||||
</Button>
|
||||
|
|
@ -107,7 +115,7 @@ const Library = ({ model, urlParams, queryParams }) => {
|
|||
<div className={styles['message-label']}>Empty {model === 'library' ? 'Library' : 'Continue Watching'}</div>
|
||||
</div>
|
||||
:
|
||||
<div className={classnames(styles['meta-items-container'], 'animation-fade-in')}>
|
||||
<div ref={scrollContainerRef} className={classnames(styles['meta-items-container'], 'animation-fade-in')} onScroll={onScroll}>
|
||||
{library.catalog.map((libItem, index) => (
|
||||
<LibItem {...libItem} notifications={notifications} removable={model === 'library'} key={index} />
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,6 @@
|
|||
multiselect-menu-container: menu-container;
|
||||
}
|
||||
|
||||
:import('~stremio/common/PaginationInput/styles.less') {
|
||||
pagination-prev-button-container: prev-button-container;
|
||||
pagination-next-button-container: next-button-container;
|
||||
pagination-button-icon: icon;
|
||||
pagination-label: label;
|
||||
}
|
||||
|
||||
:import('~stremio/common/ModalDialog/styles.less') {
|
||||
selectable-inputs-modal-container: modal-dialog-container;
|
||||
selectable-inputs-modal-content: modal-dialog-content;
|
||||
|
|
@ -75,26 +68,6 @@
|
|||
.spacing {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.pagination-input {
|
||||
flex: none;
|
||||
height: 3rem;
|
||||
margin-left: 1.5rem;
|
||||
|
||||
.pagination-prev-button-container, .pagination-next-button-container {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
|
||||
.pagination-button-icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-label {
|
||||
width: 3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-container {
|
||||
|
|
@ -277,10 +250,6 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.pagination-input {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,19 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const useLibrary = (model, urlParams, queryParams) => {
|
||||
const { core } = useServices();
|
||||
const loadNextPage = React.useCallback(() => {
|
||||
core.transport.dispatch({
|
||||
action: 'LibraryWithFilters',
|
||||
args: {
|
||||
action: 'LoadNextPage',
|
||||
}
|
||||
}, 'library');
|
||||
}, []);
|
||||
const action = React.useMemo(() => ({
|
||||
action: 'Load',
|
||||
args: {
|
||||
|
|
@ -12,12 +22,12 @@ const useLibrary = (model, urlParams, queryParams) => {
|
|||
request: {
|
||||
type: typeof urlParams.type === 'string' ? urlParams.type : null,
|
||||
sort: queryParams.has('sort') ? queryParams.get('sort') : undefined,
|
||||
page: queryParams.has('page') ? parseInt(queryParams.get('page'), 10) : undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}), [urlParams, queryParams]);
|
||||
return useModelState({ model, action });
|
||||
const library = useModelState({ model, action });
|
||||
return [library, loadNextPage];
|
||||
};
|
||||
|
||||
module.exports = useLibrary;
|
||||
|
|
|
|||
|
|
@ -32,21 +32,7 @@ const mapSelectableInputs = (library, t) => {
|
|||
window.location = event.value;
|
||||
}
|
||||
};
|
||||
const paginationInput = library.selectable.prevPage || library.selectable.nextPage ?
|
||||
{
|
||||
label: library.selected.request.page.toString(),
|
||||
onSelect: (event) => {
|
||||
if (event.value === 'prev' && library.selectable.prevPage) {
|
||||
window.location = library.selectable.prevPage.deepLinks.library;
|
||||
}
|
||||
if (event.value === 'next' && library.selectable.nextPage) {
|
||||
window.location = library.selectable.nextPage.deepLinks.library;
|
||||
}
|
||||
}
|
||||
}
|
||||
:
|
||||
null;
|
||||
return [typeSelect, sortSelect, paginationInput];
|
||||
return [typeSelect, sortSelect, library.selectable.nextPage];
|
||||
};
|
||||
|
||||
const useSelectableInputs = (library) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue