diff --git a/src/components/MetaPreview/Ratings/Ratings.less b/src/components/ActionsGroup/ActionsGroup.less
similarity index 96%
rename from src/components/MetaPreview/Ratings/Ratings.less
rename to src/components/ActionsGroup/ActionsGroup.less
index ffba0415b..09e903435 100644
--- a/src/components/MetaPreview/Ratings/Ratings.less
+++ b/src/components/ActionsGroup/ActionsGroup.less
@@ -8,7 +8,7 @@
@width-mobile: 3rem;
-.ratings-container {
+.group-container {
display: flex;
flex-direction: row;
align-items: center;
@@ -46,7 +46,7 @@
}
@media @phone-landscape {
- .ratings-container {
+ .group-container {
height: @height-mobile;
.icon-container {
diff --git a/src/components/ActionsGroup/ActionsGroup.tsx b/src/components/ActionsGroup/ActionsGroup.tsx
new file mode 100644
index 000000000..052f25016
--- /dev/null
+++ b/src/components/ActionsGroup/ActionsGroup.tsx
@@ -0,0 +1,45 @@
+// Copyright (C) 2017-2025 Smart code 203358507
+
+import classNames from 'classnames';
+import React from 'react';
+import Icon from '@stremio/stremio-icons/react';
+import { Tooltip } from 'stremio/common/Tooltips';
+import styles from './ActionsGroup.less';
+
+type Item = {
+ icon: string;
+ label?: string;
+ filled?: string;
+ disabled?: boolean;
+ className?: string;
+ onClick?: () => void;
+};
+
+type Props = {
+ items: Item[];
+ className?: string;
+};
+
+const ActionsGroup = ({ items, className }: Props) => {
+ return (
+
{
@@ -195,19 +208,6 @@ const MetaPreview = React.forwardRef(({ className, compact, name, logo, backgrou
}
- {
- typeof toggleInLibrary === 'function' ?
-
- :
- null
- }
{
typeof trailerHref === 'string' ?
+ : null
+ }
{
typeof showHref === 'string' && compact ?
:
null
@@ -298,6 +303,8 @@ MetaPreview.propTypes = {
trailerStreams: PropTypes.array,
inLibrary: PropTypes.bool,
toggleInLibrary: PropTypes.func,
+ watched: PropTypes.bool,
+ toggleWatched: PropTypes.func,
ratingInfo: PropTypes.object,
};
diff --git a/src/components/MetaPreview/Ratings/Ratings.tsx b/src/components/MetaPreview/Ratings/Ratings.tsx
index 6bef0cc6d..329ee4945 100644
--- a/src/components/MetaPreview/Ratings/Ratings.tsx
+++ b/src/components/MetaPreview/Ratings/Ratings.tsx
@@ -2,9 +2,7 @@
import React, { useMemo } from 'react';
import useRating from './useRating';
-import styles from './Ratings.less';
-import Icon from '@stremio/stremio-icons/react';
-import classNames from 'classnames';
+import { ActionsGroup } from 'stremio/components';
type Props = {
metaId?: string;
@@ -16,15 +14,21 @@ const Ratings = ({ ratingInfo, className }: Props) => {
const { onLiked, onLoved, liked, loved } = useRating(ratingInfo);
const disabled = useMemo(() => ratingInfo?.type !== 'Ready', [ratingInfo]);
+ const items = useMemo(() => [
+ {
+ icon: liked ? 'thumbs-up' : 'thumbs-up-outline',
+ disabled,
+ onClick: onLiked,
+ },
+ {
+ icon: loved ? 'heart' : 'heart-outline',
+ disabled,
+ onClick: onLoved,
+ },
+ ], [liked, loved, disabled]);
+
return (
-
+
);
};
diff --git a/src/components/MetaPreview/styles.less b/src/components/MetaPreview/styles.less
index 3fea95a5f..3b21c0ed6 100644
--- a/src/components/MetaPreview/styles.less
+++ b/src/components/MetaPreview/styles.less
@@ -32,7 +32,7 @@
.action-buttons-container {
justify-content: space-between;
- .action-button:not(:last-child) {
+ .action-button:not(:last-child), .group-container:not(:last-child) {
margin-right: 0;
}
}
@@ -207,11 +207,20 @@
}
}
}
- }
+
+ .group-container {
+ margin-bottom: 1rem;
- .ratings {
- margin-bottom: 1rem;
- margin-right: 1rem;
+ &:global(.wide) {
+ width: auto;
+ padding: 0 2rem;
+ border-radius: 4rem;
+ }
+
+ &:not(:last-child) {
+ margin-right: 1rem;
+ }
+ }
}
}
@@ -233,17 +242,13 @@
padding-top: 1.5rem;
gap: 0.5rem;
- .action-button {
+ .action-button, .group-container {
padding: 0 1.5rem !important;
margin-right: 0rem !important;
height: 3rem;
border-radius: 2rem;
}
}
-
- .ratings {
- margin-right: 0;
- }
}
}
@@ -272,6 +277,10 @@
&::-webkit-scrollbar {
display: none;
}
+
+ .action-button {
+ padding: 0 1rem !important;
+ }
}
}
diff --git a/src/components/index.ts b/src/components/index.ts
index a47c2c709..75400b0dd 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -30,6 +30,7 @@ import TextInput from './TextInput';
import Toggle from './Toggle';
import Transition from './Transition';
import Video from './Video';
+import ActionsGroup from './ActionsGroup';
export {
AddonDetailsModal,
@@ -65,4 +66,5 @@ export {
Toggle,
Transition,
Video,
+ ActionsGroup
};
diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js
index a28a86405..bcdbf5af9 100644
--- a/src/routes/Discover/Discover.js
+++ b/src/routes/Discover/Discover.js
@@ -10,6 +10,7 @@ const { CONSTANTS, useBinaryState, useOnScrollToBottom, withCoreSuspender } = re
const { AddonDetailsModal, Button, DelayedRenderer, Image, MainNavBars, MetaItem, MetaPreview, ModalDialog, MultiselectMenu } = require('stremio/components');
const useDiscover = require('./useDiscover');
const useSelectableInputs = require('./useSelectableInputs');
+const useMetaDetails = require('../MetaDetails/useMetaDetails');
const styles = require('./styles');
const SCROLL_TO_BOTTOM_THRESHOLD = 400;
@@ -23,6 +24,18 @@ const Discover = ({ urlParams, queryParams }) => {
const [addonModalOpen, openAddonModal, closeAddonModal] = useBinaryState(false);
const [selectedMetaItemIndex, setSelectedMetaItemIndex] = React.useState(0);
+ const { selectedMetaItem, metaDetailsParams } = React.useMemo(() => {
+ const item = discover.catalog?.content.type === 'Ready' &&
+ discover.catalog.content.content[selectedMetaItemIndex] || null;
+
+ return {
+ selectedMetaItem: item,
+ metaDetailsParams: item ? { type: item.type, id: item.id } : {}
+ };
+ }, [discover.catalog, selectedMetaItemIndex]);
+
+ useMetaDetails(metaDetailsParams);
+
const metasContainerRef = React.useRef();
const metaPreviewRef = React.useRef();
@@ -40,14 +53,6 @@ const Discover = ({ urlParams, queryParams }) => {
}
}
}, [hasNextPage, loadNextPage]);
- const selectedMetaItem = React.useMemo(() => {
- return discover.catalog !== null &&
- discover.catalog.content.type === 'Ready' &&
- discover.catalog.content.content[selectedMetaItemIndex] ?
- discover.catalog.content.content[selectedMetaItemIndex]
- :
- null;
- }, [discover.catalog, selectedMetaItemIndex]);
const addToLibrary = React.useCallback(() => {
if (selectedMetaItem === null) {
return;
@@ -74,6 +79,19 @@ const Discover = ({ urlParams, queryParams }) => {
}
});
}, [selectedMetaItem]);
+ const toggleWatched = React.useCallback(() => {
+ if (selectedMetaItem === null) {
+ return;
+ }
+
+ core.transport.dispatch({
+ action: 'MetaDetails',
+ args: {
+ action: 'MarkAsWatched',
+ args: !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));
@@ -193,6 +211,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}
/>
diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js
index 9f2279bd9..8376cdf2c 100644
--- a/src/routes/MetaDetails/MetaDetails.js
+++ b/src/routes/MetaDetails/MetaDetails.js
@@ -64,6 +64,19 @@ const MetaDetails = ({ urlParams, queryParams }) => {
}
});
}, [metaDetails]);
+ const toggleWatched = React.useCallback(() => {
+ if (metaDetails.metaItem === null || metaDetails.metaItem.content.type !== 'Ready') {
+ return;
+ }
+
+ core.transport.dispatch({
+ action: 'MetaDetails',
+ args: {
+ action: 'MarkAsWatched',
+ args: !metaDetails.metaItem.content.content.watched
+ }
+ });
+ }, [metaDetails]);
const toggleNotifications = React.useCallback(() => {
if (metaDetails.libraryItem) {
core.transport.dispatch({
@@ -172,6 +185,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}
/>