mark as watched implemented

This commit is contained in:
nklhrstv 2022-05-27 12:08:02 +03:00
parent 9d649b194a
commit 6d8bb2e152
2 changed files with 177 additions and 62 deletions

View file

@ -3,12 +3,37 @@
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const { useServices } = require('stremio/services');
const { useRouteFocused } = require('stremio-router');
const Icon = require('@stremio/stremio-icons/dom');
const { Button, Image } = require('stremio/common');
const { Button, Image, Popup, useBinaryState } = require('stremio/common');
const VideoPlaceholder = require('./VideoPlaceholder');
const styles = require('./styles');
const Video = ({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, deepLinks, ...props }) => {
const { core } = useServices();
const routeFocused = useRouteFocused();
const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false);
const popupLabelOnContextMenu = React.useCallback((event) => {
if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) {
toggleMenu();
event.nativeEvent.preventDefault();
}
}, [toggleMenu]);
const popupMenuOnContextMenu = React.useCallback((event) => {
event.nativeEvent.togglePopupPrevented = true;
}, []);
const toggleWatchedOnClick = React.useCallback((event) => {
event.preventDefault();
closeMenu();
core.transport.dispatch({
action: 'MetaDetails',
args: {
action: 'MarkAsWatched',
args: [id, !watched]
}
});
}, [id, watched]);
const href = React.useMemo(() => {
return deepLinks ?
typeof deepLinks.player === 'string' ?
@ -21,74 +46,115 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w
:
null;
}, [deepLinks]);
return (
<Button href={href} {...props} className={classnames(className, styles['video-container'])} title={title}>
{
typeof thumbnail === 'string' && thumbnail.length > 0 ?
<div className={styles['thumbnail-container']}>
<Image
className={styles['thumbnail']}
src={thumbnail}
alt={' '}
renderFallback={() => (
<Icon
className={styles['placeholder-icon']}
icon={'ic_broken_link'}
/>
)}
/>
const renderLabel = React.useMemo(() => function renderLabel({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, children, ...props }) {
return (
<Button {...props} className={classnames(className, styles['video-container'])} title={title}>
{
typeof thumbnail === 'string' && thumbnail.length > 0 ?
<div className={styles['thumbnail-container']}>
<Image
className={styles['thumbnail']}
src={thumbnail}
alt={' '}
renderFallback={() => (
<Icon
className={styles['placeholder-icon']}
icon={'ic_broken_link'}
/>
)}
/>
</div>
:
null
}
<div className={styles['info-container']}>
<div className={styles['title-container']}>
{episode !== null && !isNaN(episode) ? `${episode}. ` : null}
{typeof title === 'string' && title.length > 0 ? title : id}
</div>
:
null
}
<div className={styles['info-container']}>
<div className={styles['title-container']}>
{episode !== null && !isNaN(episode) ? `${episode}. ` : null}
{typeof title === 'string' && title.length > 0 ? title : id}
</div>
<div className={styles['flex-row-container']}>
{
released instanceof Date && !isNaN(released.getTime()) ?
<div className={styles['released-container']}>
{released.toLocaleString(undefined, { year: '2-digit', month: 'short', day: 'numeric' })}
</div>
:
scheduled ?
<div className={styles['released-container']} title={'To be announced'}>
TBA
</div>
:
null
}
<div className={styles['upcoming-watched-container']}>
<div className={styles['flex-row-container']}>
{
upcoming ?
<div className={styles['upcoming-container']}>
<div className={styles['flag-label']}>Upcoming</div>
released instanceof Date && !isNaN(released.getTime()) ?
<div className={styles['released-container']}>
{released.toLocaleString(undefined, { year: '2-digit', month: 'short', day: 'numeric' })}
</div>
:
null
}
{
watched ?
<div className={styles['watched-container']}>
<div className={styles['flag-label']}>Watched</div>
</div>
:
null
scheduled ?
<div className={styles['released-container']} title={'To be announced'}>
TBA
</div>
:
null
}
<div className={styles['upcoming-watched-container']}>
{
upcoming ?
<div className={styles['upcoming-container']}>
<div className={styles['flag-label']}>Upcoming</div>
</div>
:
null
}
{
watched ?
<div className={styles['watched-container']}>
<div className={styles['flag-label']}>Watched</div>
</div>
:
null
}
</div>
</div>
</div>
{
progress !== null && !isNaN(progress) && progress > 0 ?
<div className={styles['progress-bar-container']}>
<div className={styles['progress-bar']} style={{ width: `${Math.min(progress, 1) * 100}%` }} />
</div>
:
null
}
{children}
</Button>
);
}, []);
const renderMenu = React.useMemo(() => function renderMenu() {
return (
<div className={styles['context-menu-content']} onContextMenu={popupMenuOnContextMenu}>
<Button className={styles['context-menu-option-container']} title={'Watch'}>
<div className={styles['context-menu-option-label']}>Watch</div>
</Button>
<Button className={styles['context-menu-option-container']} title={watched ? 'Mark as non-watched' : 'Mark as watched'} onClick={toggleWatchedOnClick}>
<div className={styles['context-menu-option-label']}>{watched ? 'Mark as non-watched' : 'Mark as watched'}</div>
</Button>
</div>
{
progress !== null && !isNaN(progress) && progress > 0 ?
<div className={styles['progress-bar-container']}>
<div className={styles['progress-bar']} style={{ width: `${Math.min(progress, 1) * 100}%` }} />
</div>
:
null
}
</Button>
);
}, [watched, toggleWatchedOnClick]);
React.useEffect(() => {
if (!routeFocused) {
closeMenu();
}
}, [routeFocused]);
return (
<Popup
className={className}
id={id}
title={title}
thumbnail={thumbnail}
episode={episode}
released={released}
upcoming={upcoming}
watched={watched}
progress={progress}
scheduled={scheduled}
href={href}
{...props}
onContextMenu={popupLabelOnContextMenu}
open={menuOpen}
onCloseRequest={closeMenu}
renderLabel={renderLabel}
renderMenu={renderMenu}
/>
);
};

View file

@ -2,13 +2,21 @@
@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less';
:import('~stremio/common/Popup/styles.less') {
context-menu-container: menu-container;
menu-direction-top-left: menu-direction-top-left;
menu-direction-bottom-left: menu-direction-bottom-left;
menu-direction-top-right: menu-direction-top-right;
menu-direction-bottom-right: menu-direction-bottom-right;
}
.video-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 0.5rem 1rem;
&:hover, &:focus {
&:hover, &:focus, &:global(.active) {
background-color: @color-background;
}
@ -119,4 +127,45 @@
background-color: @color-primaryvariant1;
}
}
.context-menu-container {
max-width: calc(90% - 1.5rem);
&.menu-direction-top-left, &.menu-direction-bottom-left {
right: 1.5rem;
}
&.menu-direction-top-right, &.menu-direction-bottom-right {
left: 1.5rem;
}
&.menu-direction-top-left, &.menu-direction-top-right {
bottom: 90%;
}
&.menu-direction-bottom-left, &.menu-direction-bottom-right {
top: 90%;
}
.context-menu-content {
background-color: @color-background-dark1;
.context-menu-option-container {
display: flex;
flex-direction: row;
align-items: center;
padding: 0.5rem 1rem;
&:hover, &:focus {
background-color: @color-background;
}
.context-menu-option-label {
font-size: 1rem;
max-height: 2.4em;
color: @color-surface-light5-90;
}
}
}
}
}