diff --git a/package-lock.json b/package-lock.json index 940c6220d..d2315a5e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "stremio", - "version": "5.0.0-beta.16", + "version": "5.0.0-beta.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stremio", - "version": "5.0.0-beta.16", + "version": "5.0.0-beta.17", "license": "gpl-2.0", "dependencies": { "@babel/runtime": "7.26.0", "@sentry/browser": "8.42.0", "@stremio/stremio-colors": "5.2.0", - "@stremio/stremio-core-web": "0.48.4", + "@stremio/stremio-core-web": "0.48.5", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.53", "a-color-picker": "1.2.1", @@ -3371,9 +3371,9 @@ "integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==" }, "node_modules/@stremio/stremio-core-web": { - "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==", + "version": "0.48.5", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.5.tgz", + "integrity": "sha512-oDTNBrv8zZi1VGbeV+1Bm6CliI2rF23ERdJpz+gv8EnbFjRIo78WIsoS0yO0EOg8HHXYsFytPq5+c0+YlxmBlA==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" diff --git a/package.json b/package.json index 111c8149d..423518889 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stremio", "displayName": "Stremio", - "version": "5.0.0-beta.16", + "version": "5.0.0-beta.17", "author": "Smart Code OOD", "private": true, "license": "gpl-2.0", @@ -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.4", + "@stremio/stremio-core-web": "0.48.5", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.53", "a-color-picker": "1.2.1", diff --git a/src/App/App.js b/src/App/App.js index 906200d64..6dc2d6e0b 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -10,6 +10,7 @@ const { FileDropProvider, PlatformProvider, ToastProvider, TooltipProvider, CONS const ServicesToaster = require('./ServicesToaster'); const DeepLinkHandler = require('./DeepLinkHandler'); const SearchParamsHandler = require('./SearchParamsHandler'); +const { default: UpdaterBanner } = require('./UpdaterBanner'); const ErrorDialog = require('./ErrorDialog'); const withProtectedRoutes = require('./withProtectedRoutes'); const routerViewsConfig = require('./routerViewsConfig'); @@ -169,6 +170,7 @@ const App = () => { + { + const { t } = useTranslation(); + const { shell } = useServices(); + const shellTransport = useShell(); + const [visible, show, hide] = useBinaryState(false); + + const onInstallClick = () => { + shellTransport.send('autoupdater-notif-clicked'); + }; + + useEffect(() => { + shell.transport && shell.transport.on('autoupdater-show-notif', show); + + return () => { + shell.transport && shell.transport.off('autoupdater-show-notif', show); + }; + }, []); + + return ( +
+ +
+
+ { t('UPDATER_TITLE') } +
+ + +
+
+
+ ); +}; + +export default UpdaterBanner; diff --git a/src/App/UpdaterBanner/index.ts b/src/App/UpdaterBanner/index.ts new file mode 100644 index 000000000..e4306ecb2 --- /dev/null +++ b/src/App/UpdaterBanner/index.ts @@ -0,0 +1,2 @@ +import UpdaterBanner from './UpdaterBanner'; +export default UpdaterBanner; diff --git a/src/App/styles.less b/src/App/styles.less index 884af4572..77ba398f1 100644 --- a/src/App/styles.less +++ b/src/App/styles.less @@ -23,8 +23,8 @@ // HTML sizes @html-width: ~"calc(max(var(--small-viewport-width), var(--dynamic-viewport-width)))"; @html-height: ~"calc(max(var(--small-viewport-height), var(--dynamic-viewport-height)))"; -@html-standalone-width: ~"calc(max(100%, var(--large-viewport-width)))"; -@html-standalone-height: ~"calc(max(100%, var(--large-viewport-height)))"; +@html-standalone-width: ~"calc(max(100%, var(--small-viewport-width)))"; +@html-standalone-height: ~"calc(max(100%, var(--small-viewport-height)))"; // Safe area insets @safe-area-inset-top: env(safe-area-inset-top, 0rem); @@ -64,7 +64,6 @@ --modal-background-color: rgba(15, 13, 32, 1); --outer-glow: 0px 0px 15px rgba(123, 91, 245, 0.37); --border-radius: 0.75rem; - --calculated-bottom-safe-inset: @calculated-bottom-safe-inset; --top-overlay-size: @top-overlay-size; --bottom-overlay-size: @bottom-overlay-size; --overlap-size: @overlap-size; @@ -99,6 +98,10 @@ @supports (height: 100lvh) and (height: 100svh) { --viewport-height-diff: calc(100lvh - 100svh); } + + @media (display-mode: standalone) { + --safe-area-inset-bottom: @calculated-bottom-safe-inset; + } } * { @@ -174,7 +177,7 @@ html { position: absolute; top: calc(1.2 * var(--horizontal-nav-bar-size) + var(--safe-area-inset-top)); right: var(--safe-area-inset-right); - bottom: calc(1.2 * var(--horizontal-nav-bar-size) + var(--calculated-bottom-safe-inset, 0rem)); + bottom: calc(1.2 * var(--horizontal-nav-bar-size) + var(--safe-area-inset-bottom, 0rem)); left: auto; z-index: 1; padding: 0 calc(0.5 * var(--horizontal-nav-bar-size)); @@ -217,6 +220,14 @@ html { } } + .updater-banner-container { + z-index: 1; + position: absolute; + left: 0; + right: 0; + bottom: 0; + } + .router { width: 100%; height: 100%; diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 41e74b24f..2212303e4 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -1,6 +1,6 @@ import React, { createContext, useContext } from 'react'; import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS'; -import useShell from './useShell'; +import useShell from 'stremio/common/useShell'; import { name, isMobile } from './device'; interface PlatformContext { diff --git a/src/common/animations.less b/src/common/animations.less index c7a30d2fb..91dbe386d 100644 --- a/src/common/animations.less +++ b/src/common/animations.less @@ -69,6 +69,19 @@ transform: translateX(100%); } +.slide-up-enter { + transform: translateY(100%); +} + +.slide-up-active { + transform: translateY(0%); + transition: transform 0.3s cubic-bezier(0.32, 0, 0.67, 0); +} + +.slide-up-exit { + transform: translateY(100%); +} + @keyframes fade-in-no-motion { 0% { opacity: 0; diff --git a/src/common/index.js b/src/common/index.js index 35f93e8f2..4acf8b056 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -20,6 +20,7 @@ const useModelState = require('./useModelState'); const useNotifications = require('./useNotifications'); const useOnScrollToBottom = require('./useOnScrollToBottom'); const useProfile = require('./useProfile'); +const { default: useShell } = require('./useShell'); const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); const useTranslate = require('./useTranslate'); @@ -50,6 +51,7 @@ module.exports = { useNotifications, useOnScrollToBottom, useProfile, + useShell, useStreamingServer, useTorrent, useTranslate, diff --git a/src/common/screen-sizes.less b/src/common/screen-sizes.less index a4a37437a..493c899dc 100644 --- a/src/common/screen-sizes.less +++ b/src/common/screen-sizes.less @@ -21,5 +21,5 @@ @small-phone-portrait: ~"screen and (max-width: @{small-phone-landscape-size}) and (max-height: @{small-phone-portrait-size}) and (orientation: portrait)"; @phone-landscape: ~"screen and (max-width: @{phone-portrait-size}) and (max-height: @{phone-landscape-size}) and (orientation: landscape)"; -@phone-portrait: ~"screen and (max-width: @{phone-portrait-size}) and (max-height: @{phone-portrait-size}) and (orientation: portrait)"; +@phone-portrait: ~"screen and (max-width: @{phone-landscape-size}) and (max-height: @{phone-portrait-size}) and (orientation: portrait)"; diff --git a/src/common/Platform/useShell.ts b/src/common/useShell.ts similarity index 100% rename from src/common/Platform/useShell.ts rename to src/common/useShell.ts diff --git a/src/components/BottomSheet/BottomSheet.less b/src/components/BottomSheet/BottomSheet.less index 6428e5081..f7e3315e1 100644 --- a/src/components/BottomSheet/BottomSheet.less +++ b/src/components/BottomSheet/BottomSheet.less @@ -101,7 +101,7 @@ @media only screen and (orientation: landscape) { .bottom-sheet { .container { - max-width: 90%; + max-width: calc(90% - var(--safe-area-inset-left) - var(--safe-area-inset-right)); } } } \ No newline at end of file diff --git a/src/components/ColorInput/ColorInput.js b/src/components/ColorInput/ColorInput.js index 88e9189ef..afa411f63 100644 --- a/src/components/ColorInput/ColorInput.js +++ b/src/components/ColorInput/ColorInput.js @@ -5,7 +5,8 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const AColorPicker = require('a-color-picker'); const { useTranslation } = require('react-i18next'); -const { Button, ModalDialog } = require('stremio/components'); +const { Button } = require('stremio/components'); +const ModalDialog = require('stremio/components/ModalDialog'); const useBinaryState = require('stremio/common/useBinaryState'); const ColorPicker = require('./ColorPicker'); const styles = require('./styles'); diff --git a/src/components/MainNavBars/MainNavBars.less b/src/components/MainNavBars/MainNavBars.less index 2ee57b505..a5495bc69 100644 --- a/src/components/MainNavBars/MainNavBars.less +++ b/src/components/MainNavBars/MainNavBars.less @@ -6,9 +6,9 @@ position: relative; z-index: 0; overflow: clip; - margin-left: env(safe-area-inset-left, 0px); - margin-right: env(safe-area-inset-right, 0px); - width: calc(100% - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)); + margin-left: var(--safe-area-inset-left); + margin-right: var(--safe-area-inset-right); + width: calc(100% - var(--safe-area-inset-left) - var(--safe-area-inset-right)); height: 100%; .horizontal-nav-bar { @@ -22,14 +22,14 @@ .vertical-nav-bar { position: absolute; top: var(--horizontal-nav-bar-size); - bottom: var(--calculated-bottom-safe-inset); + bottom: 0; left: 0; z-index: 1; } .nav-content-container { position: absolute; - padding-top: calc(var(--horizontal-nav-bar-size) + env(safe-area-inset-top, 0px)); + padding-top: calc(var(--horizontal-nav-bar-size) + var(--safe-area-inset-top)); top: 0; right: 0; bottom: 0; diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less index 37152eb8f..6a057d292 100644 --- a/src/routes/Addons/styles.less +++ b/src/routes/Addons/styles.less @@ -22,7 +22,7 @@ } .addons-container { - height: 100%; + height: calc(100% - var(--safe-area-inset-bottom)); background-color: transparent; .addons-content { diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index a9ed6b553..9e721edf2 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -4,12 +4,12 @@ const React = require('react'); const classnames = require('classnames'); const debounce = require('lodash.debounce'); const { useTranslation } = require('react-i18next'); -const { useStreamingServer, useNotifications, withCoreSuspender, getVisibleChildrenRange } = require('stremio/common'); +const { useStreamingServer, useNotifications, withCoreSuspender, getVisibleChildrenRange, useProfile } = require('stremio/common'); const { ContinueWatchingItem, EventModal, MainNavBars, MetaItem, MetaRow } = require('stremio/components'); -const StreamingServerWarning = require('./StreamingServerWarning'); const useBoard = require('./useBoard'); const useContinueWatchingPreview = require('./useContinueWatchingPreview'); const styles = require('./styles'); +const { default: StreamingServerWarning } = require('./StreamingServerWarning'); const THRESHOLD = 5; @@ -19,8 +19,15 @@ const Board = () => { const continueWatchingPreview = useContinueWatchingPreview(); const [board, loadBoardRows] = useBoard(); const notifications = useNotifications(); + const profile = useProfile(); const boardCatalogsOffset = continueWatchingPreview.items.length > 0 ? 1 : 0; const scrollContainerRef = React.useRef(); + const streamingServerWarningDismissed = React.useMemo(() => { + return streamingServer.settings !== null && streamingServer.settings.type === 'Ready' || ( + !isNaN(profile.settings.streamingServerWarningDismissed.getTime()) && + profile.settings.streamingServerWarningDismissed.getTime() > Date.now() + ); + }, [profile.settings, streamingServer.settings]); const onVisibleRangeChange = React.useCallback(() => { const range = getVisibleChildrenRange(scrollContainerRef.current); if (range === null) { @@ -95,7 +102,7 @@ const Board = () => { { - streamingServer.settings !== null && streamingServer.settings.type === 'Err' ? + !streamingServerWarningDismissed ? : null diff --git a/src/routes/Board/StreamingServerWarning/StreamingServerWarning.js b/src/routes/Board/StreamingServerWarning/StreamingServerWarning.js deleted file mode 100644 index 61a70dff3..000000000 --- a/src/routes/Board/StreamingServerWarning/StreamingServerWarning.js +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const { useServices } = require('stremio/services'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const { useTranslation } = require('react-i18next'); -const { Button } = require('stremio/components'); -const useProfile = require('stremio/common/useProfile'); -const { withCoreSuspender } = require('stremio/common/CoreSuspender'); -const styles = require('./styles'); - -const StreamingServerWarning = ({ className }) => { - const { t } = useTranslation(); - const { core } = useServices(); - const profile = useProfile(); - const onLaterClick = React.useCallback(() => { - const streamingServerWarningDismissed = new Date(); - streamingServerWarningDismissed.setMonth(streamingServerWarningDismissed.getMonth() + 1); - core.transport.dispatch({ - action: 'Ctx', - args: { - action: 'UpdateSettings', - args: { - ...profile.settings, - streamingServerWarningDismissed - } - } - }); - }, [profile.settings]); - const onDismissClick = React.useCallback(() => { - const streamingServerWarningDismissed = new Date(); - streamingServerWarningDismissed.setFullYear(streamingServerWarningDismissed.getFullYear() + 50); - core.transport.dispatch({ - action: 'Ctx', - args: { - action: 'UpdateSettings', - args: { - ...profile.settings, - streamingServerWarningDismissed - } - } - }); - }, [profile.settings]); - - if (!isNaN(profile.settings.streamingServerWarningDismissed.getTime()) && - profile.settings.streamingServerWarningDismissed.getTime() > Date.now()) { - return null; - } - - return ( -
-
{ t('SETTINGS_SERVER_UNAVAILABLE') }
- - - - - -
- ); -}; - -StreamingServerWarning.propTypes = { - className: PropTypes.string -}; - -module.exports = withCoreSuspender(StreamingServerWarning); diff --git a/src/routes/Board/StreamingServerWarning/StreamingServerWarning.less b/src/routes/Board/StreamingServerWarning/StreamingServerWarning.less new file mode 100644 index 000000000..233e06c07 --- /dev/null +++ b/src/routes/Board/StreamingServerWarning/StreamingServerWarning.less @@ -0,0 +1,61 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; +@import (reference) '~stremio/common/screen-sizes.less'; + +.warning-container { + display: flex; + flex-direction: row; + align-items: center; + padding: 1rem; + background-color: @color-accent5-dark3; + border-radius: 0.5rem; + box-shadow: 0rem 0.25rem 1rem rgba(0, 0, 0, 0.48), 0rem 0.5rem 3rem rgba(0, 0, 0, 0.64); + + .warning-statement { + flex: 1; + font-size: 1.2rem; + max-height: 2.4em; + color: @color-surface-light5-90; + } + + .actions { + display: flex; + gap: 1rem; + + .action { + flex: none; + padding: 0.5rem 1rem; + color: @color-surface-light5-90; + background-color: rgba(0, 0, 0, 0.24); + border-radius: var(--border-radius); + + &:first-child { + margin-left: 0; + } + + .label { + font-size: 1.2rem; + color: @color-surface-light5-90; + } + + &:hover { + .label { + text-decoration: underline; + } + } + } + } +} + +@media only screen and (max-width: @minimum) { + .warning-container { + flex-direction: column; + text-align: center; + padding: 1rem 0.5rem; + + .actions { + justify-content: space-around; + } + } +} diff --git a/src/routes/Board/StreamingServerWarning/StreamingServerWarning.tsx b/src/routes/Board/StreamingServerWarning/StreamingServerWarning.tsx new file mode 100644 index 000000000..7c9872c8b --- /dev/null +++ b/src/routes/Board/StreamingServerWarning/StreamingServerWarning.tsx @@ -0,0 +1,101 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import classnames from 'classnames'; +import { useServices } from 'stremio/services'; +import { Button } from 'stremio/components'; +import useProfile from 'stremio/common/useProfile'; +import { withCoreSuspender } from 'stremio/common/CoreSuspender'; +import styles from './StreamingServerWarning.less'; + +type Props = { + className?: string; +}; + +const StreamingServerWarning = ({ className }: Props) => { + const { t } = useTranslation(); + const { core } = useServices(); + const profile = useProfile(); + + const createDismissalDate = (months: number, years = 0): Date => { + const dismissalDate = new Date(); + + if (months) { + dismissalDate.setMonth(dismissalDate.getMonth() + months); + } + if (years) { + dismissalDate.setFullYear(dismissalDate.getFullYear() + years); + } + + return dismissalDate; + }; + + const updateSettings = useCallback((streamingServerWarningDismissed: Date) => { + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'UpdateSettings', + args: { + ...profile.settings, + streamingServerWarningDismissed + } + } + }); + }, [profile.settings]); + + const onLater = useCallback(() => { + updateSettings(createDismissalDate(1)); + }, [updateSettings]); + + const onDismiss = useCallback(() => { + updateSettings(createDismissalDate(0, 50)); + }, [updateSettings]); + + return ( +
+
+ {t('SETTINGS_SERVER_UNAVAILABLE')} +
+
+ + + + + +
+
+ ); +}; + +export default withCoreSuspender(StreamingServerWarning); diff --git a/src/routes/Board/StreamingServerWarning/index.js b/src/routes/Board/StreamingServerWarning/index.js deleted file mode 100644 index 6e3f26596..000000000 --- a/src/routes/Board/StreamingServerWarning/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const StreamingServerWarning = require('./StreamingServerWarning'); - -module.exports = StreamingServerWarning; diff --git a/src/routes/Board/StreamingServerWarning/index.ts b/src/routes/Board/StreamingServerWarning/index.ts new file mode 100644 index 000000000..f623704a5 --- /dev/null +++ b/src/routes/Board/StreamingServerWarning/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import StreamingServerWarning from './StreamingServerWarning'; + +export default StreamingServerWarning; diff --git a/src/routes/Board/StreamingServerWarning/styles.less b/src/routes/Board/StreamingServerWarning/styles.less deleted file mode 100644 index 42ab6bb4b..000000000 --- a/src/routes/Board/StreamingServerWarning/styles.less +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; - -.warning-container { - display: flex; - flex-direction: row; - align-items: center; - padding: 1rem; - background-color: @color-accent5-dark3; - - .warning-statement { - flex: 1; - margin-right: 1rem; - font-size: 1.2rem; - max-height: 2.4em; - color: @color-surface-light5-90; - } - - .warning-button { - flex: none; - margin-left: 1rem; - color: @color-surface-light5-90; - - &:first-child { - margin-left: 0; - } - - &:hover { - .warning-label { - text-decoration: underline; - } - } - - .warning-label { - font-size: 1.2rem; - max-height: 1.2em; - color: @color-surface-light5-90; - } - } - - .warning-button:hover { - text-decoration: underline; - } -} - -@media only screen and (max-width: 500px) { - .warning-container { - display: block; - height: auto !important; - text-align: center; - .warning-statement { - margin-bottom: 0.5rem; - margin-right: 0; - } - .warning-button { - display: inline-block; - } - } -} diff --git a/src/routes/Board/styles.less b/src/routes/Board/styles.less index 403e75869..ac6b08e59 100644 --- a/src/routes/Board/styles.less +++ b/src/routes/Board/styles.less @@ -13,7 +13,7 @@ .board-container { width: 100%; - height: 100%; + height: calc(100% - var(--safe-area-inset-bottom)); display: flex; flex-direction: column; @@ -36,9 +36,10 @@ } .board-warning-container { - flex: none; - align-self: stretch; - margin-bottom: var(--calculated-bottom-safe-inset, 0rem); + position: absolute; + bottom: calc(var(--safe-area-inset-bottom) + 0.5rem); + left: calc(var(--safe-area-inset-left) + 0.5rem); + right: calc(var(--safe-area-inset-right) + 0.5rem); } } @@ -216,12 +217,16 @@ } .board-warning-container { - position: absolute; - left: 0; - right: 0; - bottom: calc(var(--vertical-nav-bar-size) + var(--calculated-bottom-safe-inset, 0rem)); - height: 4rem; - margin-bottom: 0rem; + bottom: calc(var(--vertical-nav-bar-size) + 0.5rem); + height: 7rem; + } + } +} + +@media @phone-landscape { + .board-container { + .board-warning-container { + left: calc(var(--safe-area-inset-left) + var(--vertical-nav-bar-size) + 0.5rem); } } } \ No newline at end of file diff --git a/src/routes/Calendar/Calendar.less b/src/routes/Calendar/Calendar.less index b606fa2aa..4763353f1 100644 --- a/src/routes/Calendar/Calendar.less +++ b/src/routes/Calendar/Calendar.less @@ -3,8 +3,7 @@ @import (reference) '~stremio/common/screen-sizes.less'; .calendar { - width: 100%; - height: 100%; + height: calc(100% - var(--safe-area-inset-bottom)); background-color: transparent; .content { diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 05f03baf0..62e3adaee 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -17,7 +17,7 @@ } .discover-container { - height: 100%; + height: calc(100% - var(--safe-area-inset-bottom)); background-color: transparent; .discover-content { diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less index 6719932e1..2bdbc13ec 100644 --- a/src/routes/Library/styles.less +++ b/src/routes/Library/styles.less @@ -13,7 +13,7 @@ } .library-container { - height: 100%; + height: calc(100% - var(--safe-area-inset-bottom)); background-color: transparent; .library-content { diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 768b8d40a..41f81b386 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -181,12 +181,17 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const renderMenu = React.useMemo(() => function renderMenu() { return (
+
+ {description} +
{ streamLink && } diff --git a/src/routes/MetaDetails/StreamsList/Stream/styles.less b/src/routes/MetaDetails/StreamsList/Stream/styles.less index 0461c77ee..06720a879 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/styles.less +++ b/src/routes/MetaDetails/StreamsList/Stream/styles.less @@ -111,12 +111,29 @@ background-color: var(--secondary-accent-color); } + .menu-icon { + flex: none; + width: 1.7rem; + height: 1.7rem; + margin-right: 1rem; + color: var(--color-placeholder); + } + .context-menu-container { max-width: calc(90% - 1.5rem); z-index: 2; .context-menu-content { --spatial-navigation-contain: contain; + + .context-menu-title { + font-size: 0.9rem; + padding: 1rem 1.5rem; + font-weight: 100; + border-bottom: 1px solid var(--color-placeholder); + color: var(--primary-foreground-color); + white-space: break-spaces; + } .context-menu-option-container { display: flex; @@ -131,8 +148,9 @@ .context-menu-option-label { font-size: 1rem; - font-weight: 500; - color:var(--primary-foreground-color); + font-weight: 300; + color: var(--primary-foreground-color); + text-transform: capitalize; } } } diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index e1d18bab6..bcb5cb015 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -9,7 +9,7 @@ const { Button, Image, Multiselect } = require('stremio/components'); const { useServices } = require('stremio/services'); const Stream = require('./Stream'); const styles = require('./styles'); -const { usePlatform } = require('stremio/common'); +const { usePlatform, useProfile } = require('stremio/common'); const ALL_ADDONS_KEY = 'ALL'; @@ -17,17 +17,21 @@ const StreamsList = ({ className, video, ...props }) => { const { t } = useTranslation(); const { core } = useServices(); const platform = usePlatform(); + const profile = useProfile(); const streamsContainerRef = React.useRef(null); const [selectedAddon, setSelectedAddon] = React.useState(ALL_ADDONS_KEY); const onAddonSelected = React.useCallback((event) => { streamsContainerRef.current.scrollTo({ top: 0, left: 0, behavior: platform.name === 'ios' ? 'smooth' : 'instant' }); setSelectedAddon(event.value); }, [platform]); + const showInstallAddonsButton = React.useMemo(() => { + return !profile || profile.auth === null || profile.auth?.user?.isNewUser === true; + }, [profile]); const backButtonOnClick = React.useCallback(() => { if (video.deepLinks && typeof video.deepLinks.metaDetailsVideos === 'string') { window.location.replace(video.deepLinks.metaDetailsVideos + ( typeof video.season === 'number' ? - `?${new URLSearchParams({'season': video.season})}` + `?${new URLSearchParams({ 'season': video.season })}` : null )); @@ -126,6 +130,15 @@ const StreamsList = ({ className, video, ...props }) => {
{'
{t('NO_STREAM')}
+ { + showInstallAddonsButton ? + + : + null + }
: filteredStreams.length === 0 ? @@ -161,13 +174,18 @@ const StreamsList = ({ className, video, ...props }) => { onClick={stream.onClick} /> ))} + { + showInstallAddonsButton ? + + : + null + }
} - ); }; diff --git a/src/routes/MetaDetails/StreamsList/styles.less b/src/routes/MetaDetails/StreamsList/styles.less index c49cedf95..0f9ab2a0a 100644 --- a/src/routes/MetaDetails/StreamsList/styles.less +++ b/src/routes/MetaDetails/StreamsList/styles.less @@ -19,7 +19,7 @@ display: flex; flex-direction: column; align-items: center; - padding: 1rem 1rem 0; + padding: 1rem; overflow-y: auto; .image { @@ -144,11 +144,12 @@ flex-direction: row; align-items: center; justify-content: center; - margin: 1rem; - padding: 1.5rem 1rem; - border-radius: var(--border-radius); background-color: var(--secondary-accent-color); - border-radius: 3rem; + height: 4rem; + padding: 0 2rem; + margin: 1rem auto; + max-width: 50%; + border-radius: 2rem; &:hover { outline: var(--focus-outline-size) solid var(--secondary-accent-color); @@ -165,7 +166,7 @@ .label { flex: 0 1 auto; - font-size: 1.5rem; + font-size: 1rem; font-weight: 700; max-height: 3.6em; text-align: center; diff --git a/src/routes/MetaDetails/styles.less b/src/routes/MetaDetails/styles.less index 3e2fb1602..82740275b 100644 --- a/src/routes/MetaDetails/styles.less +++ b/src/routes/MetaDetails/styles.less @@ -52,7 +52,7 @@ flex-direction: row; margin-top: calc(var(--top-overlay-size) * -1); padding-top: var(--top-overlay-size); - padding-bottom: var(--calculated-bottom-safe-inset, 0rem); + padding-bottom: var(--safe-area-inset-bottom, 0rem); .vertical-nav-bar { flex: none; } diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index 0fa6de1a4..745e2bd49 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -138,6 +138,7 @@ const ControlBar = ({
diff --git a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js index 420f4ba41..a65ebfe9c 100644 --- a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js +++ b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js @@ -8,7 +8,7 @@ const { useRouteFocused } = require('stremio-router'); const { Slider } = require('stremio/components'); const styles = require('./styles'); -const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { +const VolumeSlider = ({ className, volume, onVolumeChangeRequested, muted }) => { const disabled = volume === null || isNaN(volume); const routeFocused = useRouteFocused(); const [slidingVolume, setSlidingVolume] = React.useState(null); @@ -45,7 +45,9 @@ const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { className={classnames(className, styles['volume-slider'], { 'active': slidingVolume !== null })} value={ !disabled ? - slidingVolume !== null ? slidingVolume : volume + !muted ? + slidingVolume !== null ? slidingVolume : volume + : 0 : 100 } @@ -61,7 +63,8 @@ const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { VolumeSlider.propTypes = { className: PropTypes.string, volume: PropTypes.number, - onVolumeChangeRequested: PropTypes.func + onVolumeChangeRequested: PropTypes.func, + muted: PropTypes.bool, }; module.exports = VolumeSlider; diff --git a/src/routes/Player/NextVideoPopup/NextVideoPopup.js b/src/routes/Player/NextVideoPopup/NextVideoPopup.js index e772f4639..8b400bfe2 100644 --- a/src/routes/Player/NextVideoPopup/NextVideoPopup.js +++ b/src/routes/Player/NextVideoPopup/NextVideoPopup.js @@ -76,14 +76,6 @@ const NextVideoPopup = ({ className, metaItem, nextVideo, onDismiss, onNextVideo : null } - { - nextVideo !== null && typeof nextVideo.overview === 'string' ? -
- { nextVideo.overview } -
- : - null - }
@@ -717,6 +723,23 @@ const Settings = () => { : null } + { + typeof shell?.transport?.props?.shellVersion === 'string' ? +
+
+
+ Shell Version +
+
+
+
+ { shell.transport.props.shellVersion } +
+
+
+ : + null + }
diff --git a/src/routes/Settings/styles.less b/src/routes/Settings/styles.less index 7cdd0b7d4..de37d17c2 100644 --- a/src/routes/Settings/styles.less +++ b/src/routes/Settings/styles.less @@ -13,7 +13,7 @@ } .settings-container { - height: 100%; + height: calc(100% - var(--safe-area-inset-bottom)); width: 100%; background-color: transparent; diff --git a/src/types/models/Ctx.d.ts b/src/types/models/Ctx.d.ts index ffb5d7f0a..a86fd60fa 100644 --- a/src/types/models/Ctx.d.ts +++ b/src/types/models/Ctx.d.ts @@ -9,6 +9,7 @@ type Auth = { created_at: number, expires_in: number, }, + isNewUser: boolean, }, }; diff --git a/webpack.config.js b/webpack.config.js index b23ee4c15..36f6b6e50 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -163,7 +163,7 @@ module.exports = (env, argv) => ({ exclude: /node_modules/, type: 'asset/resource', generator: { - filename: `${COMMIT_HASH}/images/[name][ext][query]` + filename: 'images/[name][ext][query]' } }, { @@ -231,9 +231,9 @@ module.exports = (env, argv) => ({ }), new CopyWebpackPlugin({ patterns: [ - { from: 'favicons', to: `${COMMIT_HASH}/favicons` }, - { from: 'images', to: `${COMMIT_HASH}/images` }, - { from: 'screenshots/*.webp', to: `${COMMIT_HASH}` }, + { from: 'favicons', to: 'favicons' }, + { from: 'images', to: 'images' }, + { from: 'screenshots/*.webp', to: './' }, ] }), new MiniCssExtractPlugin({ @@ -243,8 +243,8 @@ module.exports = (env, argv) => ({ template: './src/index.html', inject: false, scriptLoading: 'blocking', - faviconsPath: `${COMMIT_HASH}/favicons`, - imagesPath: `${COMMIT_HASH}/images`, + faviconsPath: 'favicons', + imagesPath: 'images', }), new WebpackPwaManifest({ name: 'Stremio Web', @@ -261,33 +261,33 @@ module.exports = (env, argv) => ({ icons: [ { src: 'images/icon.png', - destination: `${COMMIT_HASH}/images`, + destination: 'icons', sizes: [196, 512], - purpose: 'any', - ios: true, + purpose: 'any' }, { src: 'images/maskable_icon.png', - destination: `${COMMIT_HASH}/images`, + destination: 'maskable_icons', sizes: [196, 512], purpose: 'maskable', + ios: true }, { src: 'favicons/favicon.ico', - destination: `${COMMIT_HASH}/favicons`, + destination: 'favicons', sizes: [256], } ], screenshots : [ { - src: `${COMMIT_HASH}/screenshots/board_wide.webp`, + src: 'screenshots/board_wide.webp', sizes: '1440x900', type: 'image/webp', form_factor: 'wide', label: 'Homescreen of Stremio' }, { - src: `${COMMIT_HASH}/screenshots/board_narrow.webp`, + src: 'screenshots/board_narrow.webp', sizes: '414x896', type: 'image/webp', form_factor: 'narrow',