refactor(MetaPreview): usage of ratings

This commit is contained in:
Timothy Z. 2025-06-05 16:34:03 +03:00
parent beb873e34e
commit 38d5290d91
7 changed files with 99 additions and 31 deletions

View file

@ -8,9 +8,9 @@ const { Button } = require('stremio/components');
const styles = require('./styles');
const { Tooltip } = require('stremio/common/Tooltips');
const ActionButton = ({ className, icon, label, tooltip, ...props }) => {
const ActionButton = ({ className, icon, label, tooltip, showLabel = true, ...props }) => {
return (
<Button title={tooltip ? '' : label} {...props} className={classnames(className, styles['action-button-container'], { 'wide': typeof label === 'string' && !tooltip })}>
<Button title={tooltip ? '' : label} {...props} className={classnames(className, styles['action-button-container'], { 'wide': typeof label === 'string' && !tooltip && showLabel })}>
{
tooltip === true ?
<Tooltip label={label} position={'top'} />
@ -26,7 +26,7 @@ const ActionButton = ({ className, icon, label, tooltip, ...props }) => {
null
}
{
!tooltip && typeof label === 'string' && label.length > 0 ?
!tooltip && typeof label === 'string' && label.length > 0 && showLabel ?
<div className={styles['label-container']}>
<div className={styles['label']}>{label}</div>
</div>
@ -41,7 +41,8 @@ ActionButton.propTypes = {
className: PropTypes.string,
icon: PropTypes.string,
label: PropTypes.string,
tooltip: PropTypes.bool
tooltip: PropTypes.bool,
showLabel: PropTypes.bool
};
module.exports = ActionButton;

View file

@ -49,6 +49,40 @@
opacity: 0.9;
}
}
.active {
background-color: var(--primary-foreground-color);
opacity: 0.9;
.icon {
color: var(--primary-background-color);
}
}
&.rating-button {
&.active {
background-color: var(--primary-accent-color);
.icon {
color: var(--primary-foreground-color);
}
.label-container {
display: flex;
.label {
color: var(--primary-foreground-color);
opacity: 1;
}
}
}
&:not(.active) {
.label-container {
display: none;
}
}
}
}
@media @phone-landscape {

View file

@ -25,9 +25,9 @@ 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, metaDetails }, ref) => {
const MetaPreview = React.forwardRef(({ className, compact, name, logo, background, runtime, releaseInfo, released, description, deepLinks, links, trailerStreams, inLibrary, toggleInLibrary, metaId, like }, ref) => {
const { t } = useTranslation();
const { onLiked, onLoved } = useRating(metaDetails);
const { onLiked, onLoved, liked, loved } = useRating(metaId, like);
const [shareModalOpen, openShareModal, closeShareModal] = useBinaryState(false);
const linksGroups = React.useMemo(() => {
return Array.isArray(links) ?
@ -263,8 +263,12 @@ const MetaPreview = React.forwardRef(({ className, compact, name, logo, backgrou
{
!compact ?
<ActionButton
className={styles['action-button']}
icon={'volume-medium'}
className={classnames(styles['action-button'], styles['rating-button'], {
[styles['active']]: liked
})}
icon={'thumbs-up'}
label={t('LIKE')}
showLabel={liked}
tabIndex={compact ? -1 : 0}
onClick={onLiked}
tooltip={compact}
@ -275,8 +279,12 @@ const MetaPreview = React.forwardRef(({ className, compact, name, logo, backgrou
{
!compact ?
<ActionButton
className={styles['action-button']}
icon={'volume-high'}
className={classnames(styles['action-button'], styles['rating-button'], {
[styles['active']]: loved
})}
icon={'heart'}
label={t('LOVE')}
showLabel={loved}
tabIndex={compact ? -1 : 0}
onClick={onLoved}
tooltip={compact}
@ -314,7 +322,8 @@ MetaPreview.propTypes = {
trailerStreams: PropTypes.array,
inLibrary: PropTypes.bool,
toggleInLibrary: PropTypes.func,
metaDetails: PropTypes.object
metaId: PropTypes.string,
like: PropTypes.object,
};
module.exports = MetaPreview;

View file

@ -207,6 +207,26 @@
outline: none;
}
}
&.rating-button {
&.active {
width: auto;
padding: 0 2rem;
border-radius: 4rem;
background-color: var(--primary-accent-color);
&:hover, &:focus {
background-color: var(--primary-accent-color);
opacity: 0.8;
}
}
&:not(.active) {
&:hover, &:focus {
background-color: var(--overlay-color);
}
}
}
}
}
}

View file

@ -1,23 +1,15 @@
import { useMemo, useCallback } from 'react';
import { useServices } from 'stremio/services';
const useRating = (metaDetails: MetaDetails) => {
if (!metaDetails) {
return {
onLiked: () => {},
onLoved: () => {},
};
}
type Like = {
content: 'liked' | 'loved' | null;
type: 'Ready' | 'Loading' | 'Error';
};
const useRating = (metaId?: string, like?: Like) => {
const { core } = useServices();
const like = useMemo(() => {
return metaDetails.like?.type === 'Ready' ? metaDetails.like.content : null;
}, [metaDetails.like]);
const setRating = useCallback((status: LoadableError | null) => {
const metaId = metaDetails.metaItem?.content?.content?.id;
if (!metaId) return;
const setRating = useCallback((status: 'liked' | 'loved' | null) => {
core.transport.dispatch({
action: 'MetaDetails',
args: {
@ -28,20 +20,29 @@ const useRating = (metaDetails: MetaDetails) => {
},
},
});
}, [metaDetails.metaItem?.content?.content?.id]);
}, [core]);
const liked = useMemo(() => {
return like?.content === 'liked';
}, [like]);
const loved = useMemo(() => {
return like?.content === 'loved';
}, [like]);
const onLiked = useCallback(() => {
setRating(like === 'liked' ? null : 'liked');
setRating(like?.content === 'liked' ? null : 'liked');
}, [like, setRating]);
const onLoved = useCallback(() => {
setRating(like === 'loved' ? null : 'loved');
setRating(like?.content === 'loved' ? null : 'loved');
}, [like, setRating]);
return {
onLiked,
onLoved,
like,
liked,
loved,
};
};

View file

@ -191,6 +191,8 @@ const Discover = ({ urlParams, queryParams }) => {
trailerStreams={selectedMetaItem.trailerStreams}
inLibrary={selectedMetaItem.inLibrary}
toggleInLibrary={selectedMetaItem.inLibrary ? removeFromLibrary : addToLibrary}
metaId={selectedMetaItem.id}
like={selectedMetaItem.like}
/>
:
discover.catalog !== null && discover.catalog.content.type === 'Loading' ?

View file

@ -166,7 +166,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}
metaDetails={metaDetails}
metaId={metaDetails.metaItem.content.content.id}
like={metaDetails.like}
/>
</React.Fragment>
}