From 09c1c4f04cb8c833d7185568f165997908713bff Mon Sep 17 00:00:00 2001 From: unclekingpin <125216544+unclekingpin@users.noreply.github.com> Date: Tue, 18 Jul 2023 01:36:49 +0300 Subject: [PATCH 01/25] use github ref_name for all branches --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 59bcd5ee2..ba8e878a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,5 +24,5 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./build - destination_dir: ${{ github.ref_name != 'development' && github.ref_name || '' }} + destination_dir: ${{ github.ref_name }} allow_empty_commit: true From 5a7c3f0a9de05baac78135667cacdc6a7c96b20b Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 18 Jul 2023 22:45:52 +0200 Subject: [PATCH 02/25] fix(Video): context menu was not working on Firefox --- src/routes/MetaDetails/VideosList/Video/Video.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 6ce900537..a8092790a 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -24,13 +24,6 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w const popupLabelOnContextMenu = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { event.preventDefault(); - if (event.nativeEvent.pointerType === 'mouse') { - toggleMenu(); - } - } - }, [toggleMenu]); - const popupLabelOnLongPress = React.useCallback((event) => { - if (event.nativeEvent.pointerType !== 'mouse' && !event.nativeEvent.togglePopupPrevented) { toggleMenu(); } }, [toggleMenu]); @@ -173,7 +166,6 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w href={href} {...props} onClick={popupLabelOnClick} - onLongPress={popupLabelOnLongPress} onContextMenu={popupLabelOnContextMenu} open={menuOpen} onCloseRequest={closeMenu} From 0201627a43d1f4ff34af01d9bb0b0afa1c289257 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Wed, 19 Jul 2023 15:26:31 +0100 Subject: [PATCH 03/25] use event.nativeEvent.button to detect right click --- src/routes/MetaDetails/VideosList/Video/Video.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index a8092790a..7df1ec26a 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -24,6 +24,13 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w const popupLabelOnContextMenu = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { event.preventDefault(); + if (event.nativeEvent.pointerType === 'mouse' || event.nativeEvent.button === 2) { + toggleMenu(); + } + } + }, [toggleMenu]); + const popupLabelOnLongPress = React.useCallback((event) => { + if (event.nativeEvent.pointerType !== 'mouse' && !event.nativeEvent.togglePopupPrevented) { toggleMenu(); } }, [toggleMenu]); @@ -167,6 +174,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w {...props} onClick={popupLabelOnClick} onContextMenu={popupLabelOnContextMenu} + onLongPress={popupLabelOnLongPress} open={menuOpen} onCloseRequest={closeMenu} renderLabel={renderLabel} From b9f45b33927d7a5fa0ed03681cb8a60b5701b694 Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Wed, 19 Jul 2023 08:19:47 -0700 Subject: [PATCH 04/25] Empty-Commit From e62c1e68f1294973730eed3b415527023d87f38e Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Wed, 19 Jul 2023 08:25:51 -0700 Subject: [PATCH 05/25] Empty-Commit From 61a8088a89a8e4a8c9b6d77ec2935416b2c642c1 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Thu, 20 Jul 2023 13:42:00 +0100 Subject: [PATCH 06/25] fix contextMenu trigger for mobile devices --- src/routes/MetaDetails/VideosList/Video/Video.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 7df1ec26a..27338d404 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -24,7 +24,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w const popupLabelOnContextMenu = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { event.preventDefault(); - if (event.nativeEvent.pointerType === 'mouse' || event.nativeEvent.button === 2) { + if (event.nativeEvent.pointerType === 'mouse' || (event.nativeEvent.button === 2 && event.nativeEvent.button === 0)) { toggleMenu(); } } @@ -173,6 +173,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w href={href} {...props} onClick={popupLabelOnClick} + onLongPress={popupLabelOnLongPress} onContextMenu={popupLabelOnContextMenu} onLongPress={popupLabelOnLongPress} open={menuOpen} From d25db6ebde8334dc6acbe113795301d35ae8ed95 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Thu, 20 Jul 2023 14:04:26 +0100 Subject: [PATCH 07/25] disable pointer events for background images --- src/routes/MetaDetails/styles.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/MetaDetails/styles.less b/src/routes/MetaDetails/styles.less index db51e4a2d..a906c7a99 100644 --- a/src/routes/MetaDetails/styles.less +++ b/src/routes/MetaDetails/styles.less @@ -57,6 +57,7 @@ } .background-image { + pointer-events: none; display: block; width: 100%; height: 100%; From 903715fb244aced20e16edf97a6d53bd83cf3298 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Thu, 20 Jul 2023 14:32:21 +0100 Subject: [PATCH 08/25] fix typo --- src/routes/MetaDetails/VideosList/Video/Video.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 27338d404..8006ed132 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -24,7 +24,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w const popupLabelOnContextMenu = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { event.preventDefault(); - if (event.nativeEvent.pointerType === 'mouse' || (event.nativeEvent.button === 2 && event.nativeEvent.button === 0)) { + if (event.nativeEvent.pointerType === 'mouse' || (event.nativeEvent.button === 2 && event.nativeEvent.buttons === 0)) { toggleMenu(); } } From 02879d369fa48e9cfb4aea237c7fe653ed7d3ce4 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Thu, 20 Jul 2023 14:34:59 +0100 Subject: [PATCH 09/25] fix duplicate on longpress --- src/routes/MetaDetails/VideosList/Video/Video.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 8006ed132..62abb78bf 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -175,7 +175,6 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w onClick={popupLabelOnClick} onLongPress={popupLabelOnLongPress} onContextMenu={popupLabelOnContextMenu} - onLongPress={popupLabelOnLongPress} open={menuOpen} onCloseRequest={closeMenu} renderLabel={renderLabel} From 3b1ccd378e633362b92ac5c378cd5850d605c657 Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Thu, 20 Jul 2023 14:12:30 -0700 Subject: [PATCH 10/25] prevent authenticated user to access the Intro route --- src/App/App.js | 7 +++-- src/App/withProtectedRoutes.js | 20 ++++++++++++ src/router/Router/Router.js | 56 ++++++++++++++++++---------------- 3 files changed, 55 insertions(+), 28 deletions(-) create mode 100644 src/App/withProtectedRoutes.js diff --git a/src/App/App.js b/src/App/App.js index 77a4b5824..f0752dc3f 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -6,13 +6,16 @@ const { useTranslation } = require('react-i18next'); const { Router } = require('stremio-router'); const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider } = require('stremio/services'); const { NotFound } = require('stremio/routes'); -const { ToastProvider, CONSTANTS } = require('stremio/common'); +const { ToastProvider, CONSTANTS, withCoreSuspender } = require('stremio/common'); const ServicesToaster = require('./ServicesToaster'); const DeepLinkHandler = require('./DeepLinkHandler'); const ErrorDialog = require('./ErrorDialog'); +const withProtectedRoutes = require('./withProtectedRoutes'); const routerViewsConfig = require('./routerViewsConfig'); const styles = require('./styles'); +const RouterWithProtectedRoutes = withCoreSuspender(withProtectedRoutes(Router)); + const App = () => { const { i18n } = useTranslation(); const onPathNotMatch = React.useCallback(() => { @@ -152,7 +155,7 @@ const App = () => { - { + return function withProtectedRoutes(props) { + const profile = useProfile(); + const onRouteChange = React.useCallback((routeConfig) => { + if (profile.auth !== null && routeConfig.component === Intro) { + window.location.replace('#/'); + return true; + } + }, [profile]); + return ( + + ); + } +}; + +module.exports = withProtectedRoutes; diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index d442827c8..db4c9e957 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -11,7 +11,7 @@ const Route = require('../Route'); const routeConfigForPath = require('./routeConfigForPath'); const urlParamsForPath = require('./urlParamsForPath'); -const Router = ({ className, onPathNotMatch, ...props }) => { +const Router = ({ className, onPathNotMatch, onRouteChange, ...props }) => { const viewsConfig = React.useMemo(() => props.viewsConfig, []); const [views, setViews] = React.useState(() => { return Array(viewsConfig.length).fill(null); @@ -42,37 +42,40 @@ const Router = ({ className, onPathNotMatch, ...props }) => { const urlParams = urlParamsForPath(routeConfig, typeof pathname === 'string' ? pathname : ''); const routeViewIndex = viewsConfig.findIndex((vc) => vc.includes(routeConfig)); const routeIndex = viewsConfig[routeViewIndex].findIndex((rc) => rc === routeConfig); - setViews((views) => { - return views - .slice(0, viewsConfig.length) - .map((view, index) => { - if (index < routeViewIndex) { - return view; - } else if (index === routeViewIndex) { - return { - key: `${routeViewIndex}${routeIndex}`, - component: routeConfig.component, - urlParams: view !== null && isEqual(view.urlParams, urlParams) ? - view.urlParams - : - urlParams, - queryParams: view !== null && isEqual(Array.from(view.queryParams.entries()), Array.from(queryParams.entries())) ? - view.queryParams - : - queryParams - }; - } else { - return null; - } - }); - }); + const handled = typeof onRouteChange === 'function' && onRouteChange(routeConfig, urlParams, queryParams); + if (!handled) { + setViews((views) => { + return views + .slice(0, viewsConfig.length) + .map((view, index) => { + if (index < routeViewIndex) { + return view; + } else if (index === routeViewIndex) { + return { + key: `${routeViewIndex}${routeIndex}`, + component: routeConfig.component, + urlParams: view !== null && isEqual(view.urlParams, urlParams) ? + view.urlParams + : + urlParams, + queryParams: view !== null && isEqual(Array.from(view.queryParams.entries()), Array.from(queryParams.entries())) ? + view.queryParams + : + queryParams + }; + } else { + return null; + } + }); + }); + } }; window.addEventListener('hashchange', onLocationHashChange); onLocationHashChange(); return () => { window.removeEventListener('hashchange', onLocationHashChange); }; - }, [onPathNotMatch]); + }, [onPathNotMatch, onRouteChange]); return (
{ @@ -93,6 +96,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => { Router.propTypes = { className: PropTypes.string, onPathNotMatch: PropTypes.func, + onRouteChange: PropTypes.func, viewsConfig: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.exact({ regexp: PropTypes.instanceOf(RegExp).isRequired, urlParamsNames: PropTypes.arrayOf(PropTypes.string).isRequired, From 427da7909d1cb24e115bd89378327a3009670ca0 Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Thu, 20 Jul 2023 14:15:05 -0700 Subject: [PATCH 11/25] added copyright header --- src/App/withProtectedRoutes.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/App/withProtectedRoutes.js b/src/App/withProtectedRoutes.js index 1127a01d8..7883334a9 100644 --- a/src/App/withProtectedRoutes.js +++ b/src/App/withProtectedRoutes.js @@ -1,3 +1,5 @@ +// Copyright (C) 2017-2023 Smart code 203358507 + const React = require('react'); const { Intro } = require('stremio/routes'); const { useProfile } = require('stremio/common'); From c354f91d3859c3dd453b2deae8b732b0f27b426a Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Thu, 20 Jul 2023 14:17:26 -0700 Subject: [PATCH 12/25] fix lint --- src/App/withProtectedRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App/withProtectedRoutes.js b/src/App/withProtectedRoutes.js index 7883334a9..bfd775d89 100644 --- a/src/App/withProtectedRoutes.js +++ b/src/App/withProtectedRoutes.js @@ -16,7 +16,7 @@ const withProtectedRoutes = (Component) => { return ( ); - } + }; }; module.exports = withProtectedRoutes; From 1d259137ee97b0b99c420da357a255a6c9904610 Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Thu, 20 Jul 2023 14:39:41 -0700 Subject: [PATCH 13/25] adapt login/logout to the new flow --- src/App/App.js | 4 ++++ .../NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js | 2 +- src/routes/Intro/Intro.js | 6 ------ src/routes/Settings/Settings.js | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index f0752dc3f..6aac8b950 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -97,6 +97,10 @@ const App = () => { React.useEffect(() => { const onCoreEvent = ({ event, args }) => { switch (event) { + case 'UserLoggedOut': { + window.location = '#/intro'; + break; + } case 'SettingsUpdated': { if (args && args.settings && typeof args.settings.interfaceLanguage === 'string') { i18n.changeLanguage(args.settings.interfaceLanguage); diff --git a/src/common/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js b/src/common/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js index 64cc16efe..459e39ee2 100644 --- a/src/common/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js +++ b/src/common/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js @@ -53,7 +53,7 @@ const NavMenuContent = ({ onClick }) => {
{profile.auth === null ? t('ANONYMOUS_USER') : profile.auth.user.email}
-
diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 11da3a39a..92dc3db5d 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -144,12 +144,6 @@ const Intro = ({ queryParams }) => { dispatch({ type: 'error', error: 'You must accept the Terms of Service' }); return; } - core.transport.dispatch({ - action: 'Ctx', - args: { - action: 'Logout' - } - }); window.location = '#/'; }, [state.termsAccepted]); const signup = React.useCallback(() => { diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 9a001594b..cd3c8bab1 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -223,7 +223,7 @@ const Settings = () => { { profile.auth !== null ? - : @@ -237,7 +237,7 @@ const Settings = () => { { profile.auth === null ?
-
From dc85e938bd8905412da22e978f34b242ac989bb2 Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Thu, 20 Jul 2023 15:19:29 -0700 Subject: [PATCH 14/25] navigate to intro when the state actually changes --- src/App/App.js | 4 ---- src/App/withProtectedRoutes.js | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index 6aac8b950..f0752dc3f 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -97,10 +97,6 @@ const App = () => { React.useEffect(() => { const onCoreEvent = ({ event, args }) => { switch (event) { - case 'UserLoggedOut': { - window.location = '#/intro'; - break; - } case 'SettingsUpdated': { if (args && args.settings && typeof args.settings.interfaceLanguage === 'string') { i18n.changeLanguage(args.settings.interfaceLanguage); diff --git a/src/App/withProtectedRoutes.js b/src/App/withProtectedRoutes.js index bfd775d89..5532a08aa 100644 --- a/src/App/withProtectedRoutes.js +++ b/src/App/withProtectedRoutes.js @@ -7,6 +7,13 @@ const { useProfile } = require('stremio/common'); const withProtectedRoutes = (Component) => { return function withProtectedRoutes(props) { const profile = useProfile(); + const previousProfileRef = React.useRef(null); + React.useEffect(() => { + if (previousProfileRef.current?.auth !== null && profile.auth === null) { + window.location = '#/intro'; + } + previousProfileRef.current = profile; + }, [profile]) const onRouteChange = React.useCallback((routeConfig) => { if (profile.auth !== null && routeConfig.component === Intro) { window.location.replace('#/'); From 2c6c2adb74f91816e2877d882890755cd695f855 Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Thu, 20 Jul 2023 15:22:16 -0700 Subject: [PATCH 15/25] fix lint --- src/App/withProtectedRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App/withProtectedRoutes.js b/src/App/withProtectedRoutes.js index 5532a08aa..ac9e8737b 100644 --- a/src/App/withProtectedRoutes.js +++ b/src/App/withProtectedRoutes.js @@ -13,7 +13,7 @@ const withProtectedRoutes = (Component) => { window.location = '#/intro'; } previousProfileRef.current = profile; - }, [profile]) + }, [profile]); const onRouteChange = React.useCallback((routeConfig) => { if (profile.auth !== null && routeConfig.component === Intro) { window.location.replace('#/'); From 32caea1b9ec592aa69bb12715d33fe7666c32b9c Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 21 Jul 2023 01:56:06 +0200 Subject: [PATCH 16/25] fix(Video): issue on firefox desktop linux --- src/routes/MetaDetails/VideosList/Video/Video.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 62abb78bf..fd252d5ce 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -15,18 +15,17 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w const { core } = useServices(); const routeFocused = useRouteFocused(); const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false); - const popupLabelOnClick = React.useCallback((event) => { - if (!event.nativeEvent.togglePopupPrevented && event.nativeEvent.ctrlKey) { - event.preventDefault(); - toggleMenu(); + const popupLabelOnMouseUp = React.useCallback((event) => { + if (!event.nativeEvent.togglePopupPrevented) { + if (event.nativeEvent.ctrlKey || event.nativeEvent.button === 2) { + event.preventDefault(); + toggleMenu(); + } } }, []); const popupLabelOnContextMenu = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { event.preventDefault(); - if (event.nativeEvent.pointerType === 'mouse' || (event.nativeEvent.button === 2 && event.nativeEvent.buttons === 0)) { - toggleMenu(); - } } }, [toggleMenu]); const popupLabelOnLongPress = React.useCallback((event) => { @@ -172,7 +171,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w scheduled={scheduled} href={href} {...props} - onClick={popupLabelOnClick} + onMouseUp={popupLabelOnMouseUp} onLongPress={popupLabelOnLongPress} onContextMenu={popupLabelOnContextMenu} open={menuOpen} From d89bd422203e4bf07a095d819fd3b6a7d365d540 Mon Sep 17 00:00:00 2001 From: unclekingpin Date: Fri, 21 Jul 2023 12:51:56 -0700 Subject: [PATCH 17/25] fix comparison between null and undefined --- src/App/withProtectedRoutes.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/App/withProtectedRoutes.js b/src/App/withProtectedRoutes.js index ac9e8737b..a16e0c0c7 100644 --- a/src/App/withProtectedRoutes.js +++ b/src/App/withProtectedRoutes.js @@ -7,12 +7,12 @@ const { useProfile } = require('stremio/common'); const withProtectedRoutes = (Component) => { return function withProtectedRoutes(props) { const profile = useProfile(); - const previousProfileRef = React.useRef(null); + const previousAuthRef = React.useRef(profile.auth); React.useEffect(() => { - if (previousProfileRef.current?.auth !== null && profile.auth === null) { + if (previousAuthRef.current !== null && profile.auth === null) { window.location = '#/intro'; } - previousProfileRef.current = profile; + previousAuthRef.current = profile.auth; }, [profile]); const onRouteChange = React.useCallback((routeConfig) => { if (profile.auth !== null && routeConfig.component === Intro) { From a81303e5ef9fbb89eb33e8195a21249b657672bb Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 31 Jul 2023 20:09:23 +0200 Subject: [PATCH 18/25] feat: add notification counter on library items --- src/App/App.js | 6 +++++ src/common/LibItem/LibItem.js | 7 ++++++ src/common/MetaItem/MetaItem.js | 15 +++++++++++- src/common/MetaItem/styles.less | 39 ++++++++++++++++++++++++++++++++ src/common/index.js | 2 ++ src/common/useNotifications.d.ts | 2 ++ src/common/useNotifications.js | 11 +++++++++ src/types/models/Ctx.d.ts | 13 +++++++++++ 8 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/common/useNotifications.d.ts create mode 100644 src/common/useNotifications.js diff --git a/src/App/App.js b/src/App/App.js index f0752dc3f..be59767b7 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -129,6 +129,12 @@ const App = () => { action: 'SyncLibraryWithAPI' } }); + services.core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'PullNotifications' + } + }); }; if (services.core.active) { onWindowFocus(); diff --git a/src/common/LibItem/LibItem.js b/src/common/LibItem/LibItem.js index 8cc174266..cb64efdaa 100644 --- a/src/common/LibItem/LibItem.js +++ b/src/common/LibItem/LibItem.js @@ -4,6 +4,7 @@ const React = require('react'); const { useServices } = require('stremio/services'); const PropTypes = require('prop-types'); const MetaItem = require('stremio/common/MetaItem'); +const useNotifications = require('stremio/common/useNotifications'); const { t } = require('i18next'); const OPTIONS = [ @@ -15,6 +16,11 @@ const OPTIONS = [ const LibItem = ({ _id, removable, ...props }) => { const { core } = useServices(); + const notifications = useNotifications(); + const newVideos = React.useMemo(() => { + const count = notifications.items?.[_id]?.length ?? 0; + return Math.min(Math.max(count, 0), 99); + }, [_id, notifications.items]); const options = React.useMemo(() => { return OPTIONS .filter(({ value }) => { @@ -91,6 +97,7 @@ const LibItem = ({ _id, removable, ...props }) => { return ( diff --git a/src/common/MetaItem/MetaItem.js b/src/common/MetaItem/MetaItem.js index 39a140cd3..d0c12df92 100644 --- a/src/common/MetaItem/MetaItem.js +++ b/src/common/MetaItem/MetaItem.js @@ -13,7 +13,7 @@ const useBinaryState = require('stremio/common/useBinaryState'); const { ICON_FOR_TYPE } = require('stremio/common/CONSTANTS'); const styles = require('./styles'); -const MetaItem = React.memo(({ className, type, name, poster, posterShape, playIcon, progress, options, deepLinks, dataset, optionOnSelect, ...props }) => { +const MetaItem = React.memo(({ className, type, name, poster, posterShape, playIcon, progress, newVideos, options, deepLinks, dataset, optionOnSelect, ...props }) => { const [menuOpen, onMenuOpen, onMenuClose] = useBinaryState(false); const href = React.useMemo(() => { return deepLinks ? @@ -89,6 +89,18 @@ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playI : null } + { + newVideos > 0 ? +
+
+
+
+ +{newVideos} +
+
+ : + null + }
{ (typeof name === 'string' && name.length > 0) || (Array.isArray(options) && options.length > 0) ? @@ -129,6 +141,7 @@ MetaItem.propTypes = { posterShape: PropTypes.oneOf(['poster', 'landscape', 'square']), playIcon: PropTypes.bool, progress: PropTypes.number, + newVideos: PropTypes.number, options: PropTypes.array, deepLinks: PropTypes.shape({ metaDetailsVideos: PropTypes.string, diff --git a/src/common/MetaItem/styles.less b/src/common/MetaItem/styles.less index 17ee1f8cf..75f09b555 100644 --- a/src/common/MetaItem/styles.less +++ b/src/common/MetaItem/styles.less @@ -118,6 +118,45 @@ background-color: @color-primaryvariant1; } } + + .new-videos { + z-index: -1; + position: absolute; + top: 0; + right: 0; + overflow: visible; + + .layer { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + height: 1.6rem; + width: 2.75rem; + border-radius: 0.25rem; + font-size: 1rem; + font-weight: 600; + color: @color-background-dark2-90; + + &:nth-child(1) { + top: 0.5rem; + right: 0.5rem; + background-color: @color-surface-light5-40; + } + + &:nth-child(2) { + top: 0.75rem; + right: 0.75rem; + background-color: @color-surface-light5-60; + } + + &:nth-child(3) { + top: 1rem; + right: 1rem; + background-color: @color-surface-light5; + } + } + } } .title-bar-container { diff --git a/src/common/index.js b/src/common/index.js index 9dbc551a6..f267be575 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -36,6 +36,7 @@ const useBinaryState = require('./useBinaryState'); const useFullscreen = require('./useFullscreen'); const useLiveRef = require('./useLiveRef'); const useModelState = require('./useModelState'); +const useNotifications = require('./useNotifications'); const useOnScrollToBottom = require('./useOnScrollToBottom'); const useProfile = require('./useProfile'); const useStreamingServer = require('./useStreamingServer'); @@ -83,6 +84,7 @@ module.exports = { useFullscreen, useLiveRef, useModelState, + useNotifications, useOnScrollToBottom, useProfile, useStreamingServer, diff --git a/src/common/useNotifications.d.ts b/src/common/useNotifications.d.ts new file mode 100644 index 000000000..7a6943654 --- /dev/null +++ b/src/common/useNotifications.d.ts @@ -0,0 +1,2 @@ +declare const useNotifcations: () => Notifications; +export = useNotifcations; \ No newline at end of file diff --git a/src/common/useNotifications.js b/src/common/useNotifications.js new file mode 100644 index 000000000..b0b7e7858 --- /dev/null +++ b/src/common/useNotifications.js @@ -0,0 +1,11 @@ +// Copyright (C) 2017-2023 Smart code 203358507 + +const useModelState = require('stremio/common/useModelState'); + +const map = (ctx) => ctx.notifications; + +const useNotifications = () => { + return useModelState({ model: 'ctx', map }); +}; + +module.exports = useNotifications; diff --git a/src/types/models/Ctx.d.ts b/src/types/models/Ctx.d.ts index 83fe66c84..367f83d9b 100644 --- a/src/types/models/Ctx.d.ts +++ b/src/types/models/Ctx.d.ts @@ -42,6 +42,19 @@ type Profile = { settings: Settings, }; +type VideoNotification = { + meta_id: string, + video_id: string, + video: Video, +}; + +type Notifications = { + uid: string, + created: string, + items: Record, +}; + type Ctx = { profile: Profile, + notifications: Notifications, }; \ No newline at end of file From 064550a828e0c3649a0fc73e08fbea7a50a86ac3 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 1 Aug 2023 11:15:03 +0200 Subject: [PATCH 19/25] chore: update stremio-core-web --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 12f0161d0..482af7ef4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.44.18", + "@stremio/stremio-core-web": "0.44.20", "@stremio/stremio-icons": "4.0.0", "@stremio/stremio-video": "0.0.24", "a-color-picker": "1.2.1", @@ -2703,9 +2703,9 @@ "integrity": "sha512-Dt3PYmy1DZ473QNs99KYXVWQPHtpIl37VUY0+gCEvvuCqE1fRrZIJtZ9KbysUKonvO7WwdQDztgcW0iGoc1dEA==" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.44.18", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.18.tgz", - "integrity": "sha512-g89XSIfLIsvN+FIscvBP9t5ywLP1uhGT9jED97e37ScXKCVedOL9ibnn1DJIeUj8U+ezJdbHFx4zWpnMfJdU2A==", + "version": "0.44.20", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.20.tgz", + "integrity": "sha512-dcqs9svqe9iQHDIyIr7ML42H5Oa2GNjIy3Ngp/TSMPd0UIQ/kJ4ZU/qoZk17r/McI20FEzYIdGFdCcif7c/n9g==", "dependencies": { "@babel/runtime": "7.16.0" } @@ -16804,9 +16804,9 @@ "integrity": "sha512-Dt3PYmy1DZ473QNs99KYXVWQPHtpIl37VUY0+gCEvvuCqE1fRrZIJtZ9KbysUKonvO7WwdQDztgcW0iGoc1dEA==" }, "@stremio/stremio-core-web": { - "version": "0.44.18", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.18.tgz", - "integrity": "sha512-g89XSIfLIsvN+FIscvBP9t5ywLP1uhGT9jED97e37ScXKCVedOL9ibnn1DJIeUj8U+ezJdbHFx4zWpnMfJdU2A==", + "version": "0.44.20", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.20.tgz", + "integrity": "sha512-dcqs9svqe9iQHDIyIr7ML42H5Oa2GNjIy3Ngp/TSMPd0UIQ/kJ4ZU/qoZk17r/McI20FEzYIdGFdCcif7c/n9g==", "requires": { "@babel/runtime": "7.16.0" } diff --git a/package.json b/package.json index a6b2a9a28..0f3efc6c6 100755 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.44.18", + "@stremio/stremio-core-web": "0.44.20", "@stremio/stremio-icons": "4.0.0", "@stremio/stremio-video": "0.0.24", "a-color-picker": "1.2.1", From e6d9477caeca0d069a9e16a71047f4c7065b6836 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 1 Aug 2023 13:15:20 +0200 Subject: [PATCH 20/25] refactor(types): update Ctx notification type --- src/types/models/Ctx.d.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/types/models/Ctx.d.ts b/src/types/models/Ctx.d.ts index 367f83d9b..d8a2828c7 100644 --- a/src/types/models/Ctx.d.ts +++ b/src/types/models/Ctx.d.ts @@ -42,16 +42,10 @@ type Profile = { settings: Settings, }; -type VideoNotification = { - meta_id: string, - video_id: string, - video: Video, -}; - type Notifications = { uid: string, created: string, - items: Record, + items: Record, }; type Ctx = { From acb38b0e58ca1488cc4b99b1c954c56686617c5a Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 2 Aug 2023 16:14:17 +0200 Subject: [PATCH 21/25] feat: add notifications toggle on details --- src/routes/MetaDetails/MetaDetails.js | 13 ++++++++++++ .../VideosList/SeasonsBar/styles.less | 1 - .../MetaDetails/VideosList/VideosList.js | 20 +++++++++++++++---- src/routes/MetaDetails/VideosList/styles.less | 14 +++++++++++++ src/types/models/MetaDetails.d.ts | 1 + 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index a61a82ee0..a30800835 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -61,6 +61,17 @@ const MetaDetails = ({ urlParams, queryParams }) => { } }); }, [metaDetails]); + const toggleNotifications = React.useCallback(() => { + if (metaDetails.libraryItem) { + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'ToggleLibraryItemNotifications', + args: [metaDetails.libraryItem._id, !metaDetails.libraryItem.state.noNotif], + } + }); + } + }, [metaDetails.libraryItem]); const seasonOnSelect = React.useCallback((event) => { setSeason(event.value); }, [setSeason]); @@ -156,8 +167,10 @@ const MetaDetails = ({ urlParams, queryParams }) => { : null diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less b/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less index 4c044ea15..42326acfc 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less @@ -13,7 +13,6 @@ display: flex; flex-direction: row; justify-content: space-between; - padding: 1rem; overflow: visible; .prev-season-button, .next-season-button { diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index b1928eba8..e344c6480 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -4,13 +4,15 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { t } = require('i18next'); -const Image = require('stremio/common/Image'); -const SearchBar = require('stremio/common/SearchBar'); +const { Image, SearchBar, Checkbox } = require('stremio/common'); const SeasonsBar = require('./SeasonsBar'); const Video = require('./Video'); const styles = require('./styles'); -const VideosList = ({ className, metaItem, season, seasonOnSelect }) => { +const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, toggleNotifications }) => { + const showNotificationsToggle = React.useMemo(() => { + return metaItem?.content?.content?.inLibrary && metaItem?.content?.content?.videos?.length; + }, [metaItem]); const videos = React.useMemo(() => { return metaItem && metaItem.content.type === 'Ready' ? metaItem.content.content.videos @@ -80,6 +82,14 @@ const VideosList = ({ className, metaItem, season, seasonOnSelect }) => {
: + { + showNotificationsToggle && libraryItem ? + + {t('DETAIL_RECEIVE_NOTIF_SERIES')} + + : + null + } { seasons.length > 0 ? { VideosList.propTypes = { className: PropTypes.string, metaItem: PropTypes.object, + libraryItem: PropTypes.object, season: PropTypes.number, - seasonOnSelect: PropTypes.func + seasonOnSelect: PropTypes.func, + toggleNotifications: PropTypes.func, }; module.exports = VideosList; diff --git a/src/routes/MetaDetails/VideosList/styles.less b/src/routes/MetaDetails/VideosList/styles.less index 4a1cc37ef..103d8c139 100644 --- a/src/routes/MetaDetails/VideosList/styles.less +++ b/src/routes/MetaDetails/VideosList/styles.less @@ -6,6 +6,7 @@ .videos-list-container { display: flex; flex-direction: column; + padding-top: 0.5rem; .message-container { flex: 1; @@ -35,9 +36,22 @@ } } + .notifications-checkbox { + flex: none; + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 1rem; + height: 3rem; + padding: 0 1.5rem; + color: @color-surface-light5-90; + } + .seasons-bar { flex: none; align-self: stretch; + margin: 0.5rem 1rem 1rem 1rem; } .search-bar { diff --git a/src/types/models/MetaDetails.d.ts b/src/types/models/MetaDetails.d.ts index 4b18a3612..efa7efc33 100644 --- a/src/types/models/MetaDetails.d.ts +++ b/src/types/models/MetaDetails.d.ts @@ -14,6 +14,7 @@ type MetaDetails = { addon: Addon, content: Loadable, } | null, + libraryItem: LibraryItem | null, selected: { metaPath: ResourceRequestPath, streamPath: ResourceRequestPath, From 59e3540bc2e530c9ebd5746e4ce9c4bfb999fd2d Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 10 Aug 2023 11:38:54 +0200 Subject: [PATCH 22/25] refactor(LibItem): dispatch DismissNotificationItem on dismiss --- src/common/LibItem/LibItem.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/common/LibItem/LibItem.js b/src/common/LibItem/LibItem.js index cb64efdaa..431359071 100644 --- a/src/common/LibItem/LibItem.js +++ b/src/common/LibItem/LibItem.js @@ -74,6 +74,13 @@ const LibItem = ({ _id, removable, ...props }) => { args: _id } }); + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'DismissNotificationItem', + args: _id + } + }); } break; From 7e2e178286b179e0dbec8b3e9295795f537251eb Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 10 Aug 2023 14:55:24 +0300 Subject: [PATCH 23/25] fix: Board has now it's own items instead of LibraryItem Signed-off-by: Lachezar Lechev --- src/routes/Board/Board.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index c8043b0a2..64afb7900 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -16,7 +16,7 @@ const Board = () => { const streamingServer = useStreamingServer(); const continueWatchingPreview = useContinueWatchingPreview(); const [board, loadBoardRows] = useBoard(); - const boardCatalogsOffset = continueWatchingPreview.libraryItems.length > 0 ? 1 : 0; + const boardCatalogsOffset = continueWatchingPreview.items.length > 0 ? 1 : 0; const scrollContainerRef = React.useRef(); const onVisibleRangeChange = React.useCallback(() => { const range = getVisibleChildrenRange(scrollContainerRef.current); @@ -41,11 +41,11 @@ const Board = () => {
{ - continueWatchingPreview.libraryItems.length > 0 ? + continueWatchingPreview.items.length > 0 ? From df05ead29106db277a924f3efbbc2fff9a21f475 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 11 Aug 2023 08:55:00 +0300 Subject: [PATCH 24/25] chore: add NotificationItem for Notifications Signed-off-by: Lachezar Lechev --- src/types/models/Ctx.d.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/types/models/Ctx.d.ts b/src/types/models/Ctx.d.ts index d8a2828c7..fd3cb2766 100644 --- a/src/types/models/Ctx.d.ts +++ b/src/types/models/Ctx.d.ts @@ -45,9 +45,15 @@ type Profile = { type Notifications = { uid: string, created: string, - items: Record, + items: Record, }; +type NotificationItem = { + metaId: string, + videoId: string, + videoReleased: string, +} + type Ctx = { profile: Profile, notifications: Notifications, From 86da6b925f0c2fe69a258b4b917d4655b4331ad6 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 14 Aug 2023 13:56:14 +0200 Subject: [PATCH 25/25] chore: update stremio-core-web --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 482af7ef4..9579d9c06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.44.20", + "@stremio/stremio-core-web": "0.44.21", "@stremio/stremio-icons": "4.0.0", "@stremio/stremio-video": "0.0.24", "a-color-picker": "1.2.1", @@ -2703,9 +2703,9 @@ "integrity": "sha512-Dt3PYmy1DZ473QNs99KYXVWQPHtpIl37VUY0+gCEvvuCqE1fRrZIJtZ9KbysUKonvO7WwdQDztgcW0iGoc1dEA==" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.44.20", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.20.tgz", - "integrity": "sha512-dcqs9svqe9iQHDIyIr7ML42H5Oa2GNjIy3Ngp/TSMPd0UIQ/kJ4ZU/qoZk17r/McI20FEzYIdGFdCcif7c/n9g==", + "version": "0.44.21", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.21.tgz", + "integrity": "sha512-xVCE9A/ZWLJ8un1x6VYSDY4fYclxq4rV98UIgUcc9SZlleHOoB92kqy5TIXhQ6v+Ym9EX9OU2uLBv+d2fi6KHA==", "dependencies": { "@babel/runtime": "7.16.0" } @@ -16804,9 +16804,9 @@ "integrity": "sha512-Dt3PYmy1DZ473QNs99KYXVWQPHtpIl37VUY0+gCEvvuCqE1fRrZIJtZ9KbysUKonvO7WwdQDztgcW0iGoc1dEA==" }, "@stremio/stremio-core-web": { - "version": "0.44.20", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.20.tgz", - "integrity": "sha512-dcqs9svqe9iQHDIyIr7ML42H5Oa2GNjIy3Ngp/TSMPd0UIQ/kJ4ZU/qoZk17r/McI20FEzYIdGFdCcif7c/n9g==", + "version": "0.44.21", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.44.21.tgz", + "integrity": "sha512-xVCE9A/ZWLJ8un1x6VYSDY4fYclxq4rV98UIgUcc9SZlleHOoB92kqy5TIXhQ6v+Ym9EX9OU2uLBv+d2fi6KHA==", "requires": { "@babel/runtime": "7.16.0" } diff --git a/package.json b/package.json index 0f3efc6c6..dfa055820 100755 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.44.20", + "@stremio/stremio-core-web": "0.44.21", "@stremio/stremio-icons": "4.0.0", "@stremio/stremio-video": "0.0.24", "a-color-picker": "1.2.1",