mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
feat: watched on discover & details
This commit is contained in:
parent
536be36005
commit
6833bb719d
6 changed files with 156 additions and 16 deletions
74
src/components/DiscItem/DiscItem.js
Normal file
74
src/components/DiscItem/DiscItem.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const MetaItem = require('stremio/components/MetaItem');
|
||||
const { t } = require('i18next');
|
||||
|
||||
const DiscItem = ({ id, watched, selected, toggleWatched, ...props }) => {
|
||||
|
||||
const { core } = useServices();
|
||||
|
||||
const options = React.useMemo(() => {
|
||||
return [
|
||||
{ label: watched ? 'CTX_MARK_UNWATCHED' : 'CTX_MARK_WATCHED', value: 'watched' },
|
||||
].filter(({ value }) => {
|
||||
switch (value) {
|
||||
case 'watched':
|
||||
return props.deepLinks && (typeof props.deepLinks.metaDetailsVideos === 'string' || typeof props.deepLinks.metaDetailsStreams === 'string');
|
||||
}
|
||||
}).map((option) => ({
|
||||
...option,
|
||||
label: t(option.label)
|
||||
}));
|
||||
}, [id, props.deepLinks, watched]);
|
||||
|
||||
const optionOnSelect = React.useCallback((event) => {
|
||||
if (typeof props.optionOnSelect === 'function') {
|
||||
props.optionOnSelect(event);
|
||||
}
|
||||
|
||||
if (!event.nativeEvent.optionSelectPrevented) {
|
||||
switch (event.value) {
|
||||
case 'watched': {
|
||||
if (typeof id === 'string') {
|
||||
if (typeof toggleWatched === 'function') {
|
||||
toggleWatched();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [id, props.deepLinks, props.optionOnSelect]);
|
||||
|
||||
return (
|
||||
<MetaItem
|
||||
{...props}
|
||||
watched={watched}
|
||||
playname={selected}
|
||||
className={classnames({ 'selected': selected })}
|
||||
options={options}
|
||||
optionOnSelect={optionOnSelect}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
DiscItem.propTypes = {
|
||||
id: PropTypes.string,
|
||||
removable: PropTypes.bool,
|
||||
watched: PropTypes.bool,
|
||||
selected: PropTypes.bool,
|
||||
deepLinks: PropTypes.shape({
|
||||
metaDetailsVideos: PropTypes.string,
|
||||
metaDetailsStreams: PropTypes.string,
|
||||
player: PropTypes.string
|
||||
}),
|
||||
toggleWatched: PropTypes.func,
|
||||
optionOnSelect: PropTypes.func
|
||||
};
|
||||
|
||||
module.exports = DiscItem;
|
||||
5
src/components/DiscItem/index.js
Normal file
5
src/components/DiscItem/index.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const DiscItem = require('./DiscItem');
|
||||
|
||||
module.exports = DiscItem;
|
||||
|
|
@ -25,7 +25,7 @@ const ALLOWED_LINK_REDIRECTS = [
|
|||
routesRegexp.metadetails.regexp
|
||||
];
|
||||
|
||||
const MetaPreview = React.forwardRef(({ className, compact, name, logo, background, runtime, releaseInfo, released, description, deepLinks, links, trailerStreams, inLibrary, toggleInLibrary, ratingInfo }, ref) => {
|
||||
const MetaPreview = React.forwardRef(({ className, compact, name, logo, background, runtime, releaseInfo, released, description, deepLinks, links, trailerStreams, inLibrary, toggleInLibrary, watched, toggleWatched, ratingInfo }, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const [shareModalOpen, openShareModal, closeShareModal] = useBinaryState(false);
|
||||
const linksGroups = React.useMemo(() => {
|
||||
|
|
@ -221,6 +221,19 @@ const MetaPreview = React.forwardRef(({ className, compact, name, logo, backgrou
|
|||
:
|
||||
null
|
||||
}
|
||||
{
|
||||
typeof toggleWatched === 'function' ?
|
||||
<ActionButton
|
||||
className={styles['action-button']}
|
||||
icon={watched ? 'eye-off' : 'eye'}
|
||||
label={watched ? t('CTX_MARK_UNWATCHED') : t('CTX_MARK_WATCHED')}
|
||||
tooltip={compact}
|
||||
tabIndex={compact ? -1 : 0}
|
||||
onClick={toggleWatched}
|
||||
/>
|
||||
:
|
||||
null
|
||||
}
|
||||
{
|
||||
typeof showHref === 'string' && compact ?
|
||||
<ActionButton
|
||||
|
|
@ -298,6 +311,8 @@ MetaPreview.propTypes = {
|
|||
trailerStreams: PropTypes.array,
|
||||
inLibrary: PropTypes.bool,
|
||||
toggleInLibrary: PropTypes.func,
|
||||
watched: PropTypes.bool,
|
||||
toggleWatched: PropTypes.func,
|
||||
ratingInfo: PropTypes.object,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import EventModal from './EventModal';
|
|||
import HorizontalScroll from './HorizontalScroll';
|
||||
import Image from './Image';
|
||||
import LibItem from './LibItem';
|
||||
import DiscItem from './DiscItem';
|
||||
import MainNavBars from './MainNavBars';
|
||||
import MetaItem from './MetaItem';
|
||||
import MetaPreview from './MetaPreview';
|
||||
|
|
@ -45,6 +46,7 @@ export {
|
|||
HorizontalScroll,
|
||||
Image,
|
||||
LibItem,
|
||||
DiscItem,
|
||||
MainNavBars,
|
||||
MetaItem,
|
||||
MetaPreview,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const classnames = require('classnames');
|
|||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { CONSTANTS, useBinaryState, useOnScrollToBottom, withCoreSuspender } = require('stremio/common');
|
||||
const { AddonDetailsModal, Button, DelayedRenderer, Image, MainNavBars, MetaItem, MetaPreview, ModalDialog, MultiselectMenu } = require('stremio/components');
|
||||
const { AddonDetailsModal, Button, DelayedRenderer, Image, MainNavBars, DiscItem, MetaPreview, ModalDialog, MultiselectMenu } = require('stremio/components');
|
||||
const useDiscover = require('./useDiscover');
|
||||
const useSelectableInputs = require('./useSelectableInputs');
|
||||
const styles = require('./styles');
|
||||
|
|
@ -74,6 +74,32 @@ const Discover = ({ urlParams, queryParams }) => {
|
|||
}
|
||||
});
|
||||
}, [selectedMetaItem]);
|
||||
const toggleWatched = React.useCallback(() => {
|
||||
if (selectedMetaItem === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedMetaItem.inLibrary) {
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'AddToLibrary',
|
||||
args: selectedMetaItem
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'LibraryItemMarkAsWatched',
|
||||
args: {
|
||||
id: selectedMetaItem.id,
|
||||
is_watched: !selectedMetaItem.watched
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [selectedMetaItem]);
|
||||
const metaItemsOnFocusCapture = React.useCallback((event) => {
|
||||
if (event.target.dataset.index !== null && !isNaN(event.target.dataset.index)) {
|
||||
setSelectedMetaItemIndex(parseInt(event.target.dataset.index, 10));
|
||||
|
|
@ -157,20 +183,8 @@ const Discover = ({ urlParams, queryParams }) => {
|
|||
</div>
|
||||
:
|
||||
<div ref={metasContainerRef} className={classnames(styles['meta-items-container'], 'animation-fade-in')} onScroll={onScroll} onFocusCapture={metaItemsOnFocusCapture}>
|
||||
{discover.catalog.content.content.map((metaItem, index) => (
|
||||
<MetaItem
|
||||
key={index}
|
||||
className={classnames({ 'selected': selectedMetaItemIndex === index })}
|
||||
type={metaItem.type}
|
||||
name={metaItem.name}
|
||||
poster={metaItem.poster}
|
||||
posterShape={metaItem.posterShape}
|
||||
playname={selectedMetaItemIndex === index}
|
||||
deepLinks={metaItem.deepLinks}
|
||||
watched={metaItem.watched}
|
||||
data-index={index}
|
||||
onClick={metaItemOnClick}
|
||||
/>
|
||||
{discover.catalog.content.content.map((discItem, index) => (
|
||||
<DiscItem {...discItem} toggleWatched={toggleWatched} selected={selectedMetaItemIndex === index} key={index} data-index={index} onClick={metaItemOnClick} />
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
|
|
@ -193,6 +207,8 @@ const Discover = ({ urlParams, queryParams }) => {
|
|||
trailerStreams={selectedMetaItem.trailerStreams}
|
||||
inLibrary={selectedMetaItem.inLibrary}
|
||||
toggleInLibrary={selectedMetaItem.inLibrary ? removeFromLibrary : addToLibrary}
|
||||
watched={selectedMetaItem.watched}
|
||||
toggleWatched={toggleWatched}
|
||||
metaId={selectedMetaItem.id}
|
||||
like={selectedMetaItem.like}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -64,6 +64,32 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
}
|
||||
});
|
||||
}, [metaDetails]);
|
||||
const toggleWatched = React.useCallback(() => {
|
||||
if (metaDetails.metaItem.content.content === null || metaDetails.metaItem.content.type !== 'Ready') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!metaDetails.metaItem.content.content.inLibrary) {
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'AddToLibrary',
|
||||
args: metaDetails.metaItem.content.content
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'LibraryItemMarkAsWatched',
|
||||
args: {
|
||||
id: metaDetails.metaItem.content.content.id,
|
||||
is_watched: !metaDetails.metaItem.content.content.watched
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [metaDetails]);
|
||||
const toggleNotifications = React.useCallback(() => {
|
||||
if (metaDetails.libraryItem) {
|
||||
core.transport.dispatch({
|
||||
|
|
@ -168,6 +194,8 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
trailerStreams={metaDetails.metaItem.content.content.trailerStreams}
|
||||
inLibrary={metaDetails.metaItem.content.content.inLibrary}
|
||||
toggleInLibrary={metaDetails.metaItem.content.content.inLibrary ? removeFromLibrary : addToLibrary}
|
||||
watched={metaDetails.metaItem.content.content.watched}
|
||||
toggleWatched={toggleWatched}
|
||||
metaId={metaDetails.metaItem.content.content.id}
|
||||
ratingInfo={metaDetails.ratingInfo}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue