diff --git a/package-lock.json b/package-lock.json index d6618f1b0..c0876ac29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.26.0", "@sentry/browser": "8.42.0", "@stremio/stremio-colors": "5.2.0", - "@stremio/stremio-core-web": "0.48.3", + "@stremio/stremio-core-web": "0.48.4", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.48", "a-color-picker": "1.2.1", @@ -3371,9 +3371,10 @@ "integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.48.3", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.3.tgz", - "integrity": "sha512-JL8pOLOEVACYG+33Dtp/mrB2/vuc7RoYZdxX1BQa5MPR8EzsODjpvL5uETmdxo/swgtMZyx2A6/e1B53eKA4oQ==", + "version": "0.48.4", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.4.tgz", + "integrity": "sha512-848OLm0dtP75aAlYhUB0KoOqwosJIj+ubB8/abuaAzH/N3dtxs40vu2AezmMpGjwR4V60rlOUkUZeWFvrUOjrw==", + "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index f79244edd..0b784890c 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@babel/runtime": "7.26.0", "@sentry/browser": "8.42.0", "@stremio/stremio-colors": "5.2.0", - "@stremio/stremio-core-web": "0.48.3", + "@stremio/stremio-core-web": "0.48.4", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.48", "a-color-picker": "1.2.1", diff --git a/src/routes/Addons/Addon/Addon.js b/src/routes/Addons/Addon/Addon.js index ae27dca51..cd00b7929 100644 --- a/src/routes/Addons/Addon/Addon.js +++ b/src/routes/Addons/Addon/Addon.js @@ -8,19 +8,43 @@ const { default: Icon } = require('@stremio/stremio-icons/react'); const { Button, Image } = require('stremio/common'); const styles = require('./styles'); -const Addon = ({ className, id, name, version, logo, description, types, behaviorHints, installed, onToggle, onConfigure, onShare, dataset }) => { +const Addon = ({ className, id, name, version, logo, description, types, behaviorHints, installed, onInstall, onUninstall, onConfigure, onOpen, onShare, dataset }) => { const { t } = useTranslation(); - const toggleButtonOnClick = React.useCallback((event) => { - if (typeof onToggle === 'function') { - onToggle({ - type: 'toggle', + const onInstallClick = React.useCallback((event) => { + event.stopPropagation(); + if (typeof onInstall === 'function') { + onInstall({ + type: 'install', nativeEvent: event.nativeEvent, reactEvent: event, dataset: dataset }); } - }, [onToggle, dataset]); + }, [onInstall, dataset]); + const onUninstallClick = React.useCallback((event) => { + event.stopPropagation(); + if (typeof onUninstall === 'function') { + onUninstall({ + type: 'uninstall', + nativeEvent: event.nativeEvent, + reactEvent: event, + dataset: dataset + }); + } + }, [onUninstall, dataset]); + const onOpenClick = React.useCallback((event) => { + event.stopPropagation(); + if (typeof onOpen === 'function') { + onOpen({ + type: 'open', + nativeEvent: event.nativeEvent, + reactEvent: event, + dataset: dataset + }); + } + }, [onOpen, dataset]); const configureButtonOnClick = React.useCallback((event) => { + event.stopPropagation(); if (typeof onConfigure === 'function') { onConfigure({ type: 'configure', @@ -31,6 +55,7 @@ const Addon = ({ className, id, name, version, logo, description, types, behavio } }, [onConfigure, dataset]); const shareButtonOnClick = React.useCallback((event) => { + event.stopPropagation(); if (typeof onShare === 'function') { onShare({ type: 'share', @@ -41,20 +66,15 @@ const Addon = ({ className, id, name, version, logo, description, types, behavio } }, [onShare, dataset]); const onKeyDown = React.useCallback((event) => { - if (event.key === 'Enter' && typeof onToggle === 'function') { - onToggle({ - type: 'toggle', - nativeEvent: event.nativeEvent, - reactEvent: event, - dataset: dataset - }); + if (event.key === 'Enter') { + onOpenClick(event); } - }, [onToggle, dataset]); + }, [onOpenClick]); const renderLogoFallback = React.useCallback(() => ( ), []); return ( - @@ -137,7 +157,10 @@ Addon.propTypes = { }), installed: PropTypes.bool, onToggle: PropTypes.func, + onInstall: PropTypes.func, + onUninstall: PropTypes.func, onConfigure: PropTypes.func, + onOpen: PropTypes.func, onShare: PropTypes.func, dataset: PropTypes.object }; diff --git a/src/routes/Addons/Addon/styles.less b/src/routes/Addons/Addon/styles.less index 26863df3f..a3bb4e174 100644 --- a/src/routes/Addons/Addon/styles.less +++ b/src/routes/Addons/Addon/styles.less @@ -8,9 +8,15 @@ flex-direction: row; align-items: flex-start; padding: 1.5rem; + border: 0.15rem solid transparent; border-radius: var(--border-radius); background-color: var(--overlay-color); - cursor: inherit; + transition: border-color 0.1s ease-out; + cursor: pointer; + + &:hover { + border-color: var(--overlay-color); + } .logo-container { flex: none; diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 1c410b819..b850e5088 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -6,6 +6,7 @@ const classnames = require('classnames'); const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { AddonDetailsModal, Button, Image, Multiselect, MainNavBars, TextInput, SearchBar, SharePrompt, ModalDialog, usePlatform, useBinaryState, withCoreSuspender } = require('stremio/common'); +const { useServices } = require('stremio/services'); const Addon = require('./Addon'); const useInstalledAddons = require('./useInstalledAddons'); const useRemoteAddons = require('./useRemoteAddons'); @@ -17,6 +18,7 @@ const { AddonPlaceholder } = require('./AddonPlaceholder'); const Addons = ({ urlParams, queryParams }) => { const { t } = useTranslation(); const platform = usePlatform(); + const { core } = useServices(); const installedAddons = useInstalledAddons(urlParams); const remoteAddons = useRemoteAddons(urlParams); const [addonDetailsTransportUrl, setAddonDetailsTransportUrl] = useAddonDetailsTransportUrl(urlParams, queryParams); @@ -57,12 +59,30 @@ const Addons = ({ urlParams, queryParams }) => { const onAddonShare = React.useCallback((event) => { setSharedAddon(event.dataset.addon); }, []); - const onAddonToggle = React.useCallback((event) => { - setAddonDetailsTransportUrl(event.dataset.addon.transportUrl); - }, [setAddonDetailsTransportUrl]); + const onAddonInstall = React.useCallback((event) => { + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'InstallAddon', + args: event.dataset.addon, + } + }); + }, []); + const onAddonUninstall = React.useCallback((event) => { + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'UninstallAddon', + args: event.dataset.addon, + } + }); + }, []); const onAddonConfigure = React.useCallback((event) => { platform.openExternal(event.dataset.addon.transportUrl.replace('manifest.json', 'configure')); }, []); + const onAddonOpen = React.useCallback((event) => { + setAddonDetailsTransportUrl(event.dataset.addon.transportUrl); + }, [setAddonDetailsTransportUrl]); const closeAddonDetails = React.useCallback(() => { setAddonDetailsTransportUrl(null); }, [setAddonDetailsTransportUrl]); @@ -135,8 +155,10 @@ const Addons = ({ urlParams, queryParams }) => { types={addon.manifest.types} behaviorHints={addon.manifest.behaviorHints} installed={addon.installed} - onToggle={onAddonToggle} + onInstall={onAddonInstall} + onUninstall={onAddonUninstall} onConfigure={onAddonConfigure} + onOpen={onAddonOpen} onShare={onAddonShare} dataset={{ addon }} /> @@ -173,8 +195,10 @@ const Addons = ({ urlParams, queryParams }) => { types={addon.manifest.types} behaviorHints={addon.manifest.behaviorHints} installed={addon.installed} - onToggle={onAddonToggle} + onInstall={onAddonInstall} + onUninstall={onAddonUninstall} onConfigure={onAddonConfigure} + onOpen={onAddonOpen} onShare={onAddonShare} dataset={{ addon }} />