@@ -57,22 +64,6 @@ const AddonPrompt = ({ className, id, name, logo, description, types, catalogs,
:
null
}
- {
- Array.isArray(catalogs) && catalogs.length > 0 ?
-
- :
- null
- }
{
!official ?
@@ -85,19 +76,16 @@ const AddonPrompt = ({ className, id, name, logo, description, types, catalogs,
);
};
-AddonPrompt.propTypes = {
+AddonDetails.propTypes = {
className: PropTypes.string,
id: PropTypes.string,
name: PropTypes.string,
+ version: PropTypes.string,
logo: PropTypes.string,
description: PropTypes.string,
types: PropTypes.arrayOf(PropTypes.string),
- catalogs: PropTypes.arrayOf(PropTypes.shape({
- name: PropTypes.string
- })),
- version: PropTypes.string,
transportUrl: PropTypes.string,
- official: PropTypes.bool
+ official: PropTypes.bool,
};
-module.exports = AddonPrompt;
+module.exports = AddonDetails;
diff --git a/src/common/AddonDetailsModal/AddonDetails/index.js b/src/common/AddonDetailsModal/AddonDetails/index.js
new file mode 100644
index 000000000..03cf009c7
--- /dev/null
+++ b/src/common/AddonDetailsModal/AddonDetails/index.js
@@ -0,0 +1,3 @@
+const AddonDetails = require('./AddonDetails');
+
+module.exports = AddonDetails;
diff --git a/src/common/AddonDetailsModal/AddonDetails/styles.less b/src/common/AddonDetailsModal/AddonDetails/styles.less
new file mode 100644
index 000000000..2d69af547
--- /dev/null
+++ b/src/common/AddonDetailsModal/AddonDetails/styles.less
@@ -0,0 +1,48 @@
+.addon-details-container {
+ .title-container {
+ .logo, .icon {
+ float: left;
+ width: 5rem;
+ height: 5rem;
+ margin-right: 1rem;
+ padding: 0.5rem;
+ background-color: var(--color-backgrounddarker);
+ }
+
+ .logo {
+ object-fit: contain;
+ object-position: center;
+ }
+
+ .icon {
+ fill: var(--color-surfacelighter);
+ }
+
+ .name {
+ font-size: 2.4rem;
+ font-weight: 300;
+ line-height: 5rem;
+ }
+ }
+
+ .section-container {
+ margin-top: 1rem;
+
+ .section-header {
+ font-size: 1.2rem;
+ }
+
+ .section-label {
+ font-size: 1.2rem;
+ font-weight: 300;
+
+ &.transport-url-label {
+ user-select: text;
+ }
+
+ &.disclaimer-label {
+ font-style: italic;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/common/AddonDetailsModal/AddonDetailsModal.js b/src/common/AddonDetailsModal/AddonDetailsModal.js
new file mode 100644
index 000000000..fd20da40f
--- /dev/null
+++ b/src/common/AddonDetailsModal/AddonDetailsModal.js
@@ -0,0 +1,121 @@
+const React = require('react');
+const PropTypes = require('prop-types');
+const ModalDialog = require('stremio/common/ModalDialog');
+const { useServices } = require('stremio/services');
+const AddonDetails = require('./AddonDetails');
+const useAddonDetails = require('./useAddonDetails');
+const styles = require('./styles');
+
+const AddonDetailsModal = ({ transportUrl, onCloseRequest }) => {
+ const { core } = useServices();
+ const addonDetails = useAddonDetails(transportUrl);
+ const modalButtons = React.useMemo(() => {
+ if (addonDetails.descriptor === null || addonDetails.descriptor.content.type !== 'Ready') {
+ return null;
+ }
+
+ const cancelOnClick = (event) => {
+ if (typeof onCloseRequest === 'function') {
+ onCloseRequest({
+ type: 'cancel',
+ reactEvent: event,
+ nativeEvent: event.nativeEvent
+ });
+ }
+ };
+ const installOnClick = (event) => {
+ core.dispatch({
+ action: 'AddonOp',
+ args: {
+ addonOp: 'Install',
+ args: addonDetails.descriptor.content.content
+ }
+ });
+ if (typeof onCloseRequest === 'function') {
+ onCloseRequest({
+ type: 'install',
+ reactEvent: event,
+ nativeEvent: event.nativeEvent
+ });
+ }
+ };
+ const uninstallOnClick = (event) => {
+ core.dispatch({
+ action: 'AddonOp',
+ args: {
+ addonOp: 'Uninstall',
+ args: {
+ transport_url: addonDetails.descriptor.content.content.transportUrl
+ }
+ }
+ });
+ if (typeof onCloseRequest === 'function') {
+ onCloseRequest({
+ type: 'uninstall',
+ reactEvent: event,
+ nativeEvent: event.nativeEvent
+ });
+ }
+ };
+ return [
+ {
+ className: styles['cancel-button'],
+ label: 'Cancel',
+ props: {
+ onClick: cancelOnClick
+ }
+ },
+ addonDetails.descriptor.content.content.installed ?
+ {
+ className: styles['uninstall-button'],
+ label: 'Uninstall',
+ props: {
+ onClick: uninstallOnClick
+ }
+ }
+ :
+ {
+
+ className: styles['install-button'],
+ label: 'Install',
+ props: {
+ onClick: installOnClick
+ }
+ }
+ ];
+ }, [addonDetails, onCloseRequest]);
+ return (
+
+ {
+ addonDetails.descriptor === null || addonDetails.descriptor.content.type === 'Loading' ?
+
+ Loading addon manifest from {transportUrl}
+
+ :
+ addonDetails.descriptor.content.type === 'Err' ?
+
+ Failed to get addon manifest from {transportUrl}
+
+ :
+
+ }
+
+ );
+};
+
+AddonDetailsModal.propTypes = {
+ transportUrl: PropTypes.string,
+ onCloseRequest: PropTypes.func
+};
+
+module.exports = AddonDetailsModal;
diff --git a/src/common/AddonDetailsModal/index.js b/src/common/AddonDetailsModal/index.js
new file mode 100644
index 000000000..b2d5f6838
--- /dev/null
+++ b/src/common/AddonDetailsModal/index.js
@@ -0,0 +1,3 @@
+const AddonDetailsModal = require('./AddonDetailsModal');
+
+module.exports = AddonDetailsModal;
diff --git a/src/common/AddonDetailsModal/styles.less b/src/common/AddonDetailsModal/styles.less
new file mode 100644
index 000000000..146dc9a2f
--- /dev/null
+++ b/src/common/AddonDetailsModal/styles.less
@@ -0,0 +1,34 @@
+:import('~stremio/common/ModalDialog/styles.less') {
+ label: label;
+}
+
+.addon-details-modal-container {
+ .addon-details-container, .addon-details-message-container {
+ width: 60rem;
+ max-width: 100%;
+ }
+
+ .install-button, .uninstall-button, .cancel-button {
+ .label {
+ font-size: 1.2rem;
+ font-weight: 500;
+ }
+ }
+
+ .cancel-button, .uninstall-button {
+ background-color: transparent;
+ outline-width: var(--focus-outline-size);
+ outline-offset: calc(-1 * var(--focus-outline-size));
+ outline-color: var(--color-surfacedarker);
+ outline-style: solid;
+
+ &:hover, &:focus {
+ filter: none;
+ background: var(--color-surfacelight);
+ }
+
+ .label {
+ color: var(--color-surfacedarker);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/routes/Addons/useAddonDetails.js b/src/common/AddonDetailsModal/useAddonDetails.js
similarity index 69%
rename from src/routes/Addons/useAddonDetails.js
rename to src/common/AddonDetailsModal/useAddonDetails.js
index afa45eceb..71b9c2a9d 100644
--- a/src/routes/Addons/useAddonDetails.js
+++ b/src/common/AddonDetailsModal/useAddonDetails.js
@@ -1,5 +1,5 @@
const React = require('react');
-const { useModelState } = require('stremio/common');
+const useModelState = require('stremio/common/useModelState');
const initAddonDetailsState = () => ({
descriptor: null
@@ -11,7 +11,10 @@ const mapAddonDetailsStateWithCtx = (addonDetails, ctx) => {
...addonDetails.descriptor,
content: {
...addonDetails.descriptor.content,
- installed: ctx.content.addons.some((addon) => addon.transportUrl === addonDetails.descriptor.transport_url),
+ content: {
+ ...addonDetails.descriptor.content.content,
+ installed: ctx.content.addons.some((addon) => addon.transportUrl === addonDetails.descriptor.transportUrl),
+ }
}
}
:
@@ -19,15 +22,15 @@ const mapAddonDetailsStateWithCtx = (addonDetails, ctx) => {
return { descriptor };
};
-const useAddonDetails = (queryParams) => {
+const useAddonDetails = (transportUrl) => {
const loadAddonDetailsAction = React.useMemo(() => {
- if (queryParams.has('addon')) {
+ if (typeof transportUrl === 'string') {
return {
action: 'Load',
args: {
load: 'AddonDetails',
args: {
- transport_url: queryParams.get('addon')
+ transport_url: transportUrl
}
}
};
@@ -36,7 +39,7 @@ const useAddonDetails = (queryParams) => {
action: 'Unload'
};
}
- }, [queryParams]);
+ }, [transportUrl]);
return useModelState({
model: 'addon_details',
action: loadAddonDetailsAction,
diff --git a/src/common/MainNavBar/MainNavBar.js b/src/common/MainNavBar/MainNavBar.js
index 507f8d229..e3ce70436 100644
--- a/src/common/MainNavBar/MainNavBar.js
+++ b/src/common/MainNavBar/MainNavBar.js
@@ -3,15 +3,17 @@ const PropTypes = require('prop-types');
const NavBar = require('stremio/common/NavBar');
const TABS = [
- { label: 'Board', icon: 'ic_board', href: '#/' },
- { label: 'Discover', icon: 'ic_discover', href: '#/discover' },
- { label: 'Library', icon: 'ic_library', href: '#/library' }
+ { route: 'board', label: 'Board', icon: 'ic_board', href: '#/' },
+ { route: 'discover', label: 'Discover', icon: 'ic_discover', href: '#/discover' },
+ { route: 'library', label: 'Library', icon: 'ic_library', href: '#/library' }
];
-const MainNavBar = React.memo(({ className }) => {
+const MainNavBar = React.memo(({ className, route, query }) => {
return (
{
MainNavBar.displayName = 'MainNavBar';
MainNavBar.propTypes = {
- className: PropTypes.string
+ className: PropTypes.string,
+ route: PropTypes.string,
+ query: PropTypes.string
};
module.exports = MainNavBar;
diff --git a/src/common/NavBar/NavBar.js b/src/common/NavBar/NavBar.js
index 92663af21..0e946f3c4 100644
--- a/src/common/NavBar/NavBar.js
+++ b/src/common/NavBar/NavBar.js
@@ -9,7 +9,7 @@ const NotificationsMenu = require('./NotificationsMenu');
const NavMenu = require('./NavMenu');
const styles = require('./styles');
-const NavBar = React.memo(({ className, backButton, tabs, title, searchBar, addonsButton, fullscreenButton, notificationsMenu, navMenu }) => {
+const NavBar = React.memo(({ className, route, query, backButton, tabs, title, searchBar, addonsButton, fullscreenButton, notificationsMenu, navMenu }) => {
const backButtonOnClick = React.useCallback(() => {
window.history.back();
}, []);
@@ -28,14 +28,15 @@ const NavBar = React.memo(({ className, backButton, tabs, title, searchBar, addo
}
{
Array.isArray(tabs) && tabs.length > 0 ?
- tabs.slice(0, 4).map(({ href = '', icon = '', label = '', onClick }) => (
+ tabs.slice(0, 4).map((tab, index) => (
))
:
@@ -45,7 +46,7 @@ const NavBar = React.memo(({ className, backButton, tabs, title, searchBar, addo
searchBar ?
-
+
:
@@ -83,10 +84,13 @@ NavBar.displayName = 'NavBar';
NavBar.propTypes = {
className: PropTypes.string,
+ route: PropTypes.string,
+ query: PropTypes.string,
backButton: PropTypes.bool,
tabs: PropTypes.arrayOf(PropTypes.shape({
- icon: PropTypes.string,
+ route: PropTypes.string,
label: PropTypes.string,
+ icon: PropTypes.string,
href: PropTypes.string,
onClick: PropTypes.func
})),
diff --git a/src/common/NavBar/NavTabButton/NavTabButton.js b/src/common/NavBar/NavTabButton/NavTabButton.js
index 3af4bd7fb..7a525b868 100644
--- a/src/common/NavBar/NavTabButton/NavTabButton.js
+++ b/src/common/NavBar/NavTabButton/NavTabButton.js
@@ -3,25 +3,11 @@ const PropTypes = require('prop-types');
const classnames = require('classnames');
const Icon = require('stremio-icons/dom');
const Button = require('stremio/common/Button');
-const routesRegexp = require('stremio/common/routesRegexp');
-const useRouteActive = require('stremio/common/useRouteActive');
const styles = require('./styles');
-const NavTabButton = ({ className, icon, label, href, onClick }) => {
- const routeRegexp = React.useMemo(() => {
- if (typeof href === 'string' && href.startsWith('#')) {
- for (const { regexp } of Object.values(routesRegexp)) {
- if (href.slice(1).match(regexp)) {
- return regexp;
- }
- }
- }
-
- return null;
- }, [href]);
- const routeActive = useRouteActive(routeRegexp);
+const NavTabButton = ({ className, icon, label, href, selected, onClick }) => {
return (
-
);
};
Addons.propTypes = {
urlParams: PropTypes.exact({
- addonTransportUrl: PropTypes.string,
+ transportUrl: PropTypes.string,
catalogId: PropTypes.string,
type: PropTypes.string
}),
diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js
index 57be65b45..cd0fae6f9 100644
--- a/src/routes/Addons/useAddons.js
+++ b/src/routes/Addons/useAddons.js
@@ -55,13 +55,13 @@ const onNewAddonsState = (addons) => {
const useAddons = (urlParams) => {
const { core } = useServices();
const loadAddonsAction = React.useMemo(() => {
- if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') {
+ if (typeof urlParams.transportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') {
return {
action: 'Load',
args: {
load: 'CatalogFiltered',
args: {
- base: urlParams.addonTransportUrl,
+ base: urlParams.transportUrl,
path: {
resource: 'addon_catalog',
type_name: urlParams.type,
diff --git a/src/routes/Addons/useSelectableInputs.js b/src/routes/Addons/useSelectableInputs.js
index 1b1c4dd15..4db24b058 100644
--- a/src/routes/Addons/useSelectableInputs.js
+++ b/src/routes/Addons/useSelectableInputs.js
@@ -1,10 +1,10 @@
const React = require('react');
const navigateWithLoadRequest = (load_request) => {
- const addonTransportUrl = encodeURIComponent(load_request.base);
+ const transportUrl = encodeURIComponent(load_request.base);
const catalogId = encodeURIComponent(load_request.path.id);
const type = encodeURIComponent(load_request.path.type_name);
- window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}`);
+ window.location.replace(`#/addons/${transportUrl}/${catalogId}/${type}`);
};
const equalWithouExtra = (request1, request2) => {
diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js
index 47f293f45..6209f077a 100644
--- a/src/routes/Board/Board.js
+++ b/src/routes/Board/Board.js
@@ -11,7 +11,7 @@ const Board = () => {
const [options, optionOnSelect] = useItemOptions();
return (