mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-05-18 11:01:48 +00:00
Merge branch 'development' of https://github.com/Stremio/stremio-web into refactor/shortcuts-logic
This commit is contained in:
commit
145a498101
10 changed files with 49 additions and 25 deletions
|
|
@ -17,7 +17,7 @@
|
||||||
"@babel/runtime": "7.29.2",
|
"@babel/runtime": "7.29.2",
|
||||||
"@sentry/browser": "8.42.0",
|
"@sentry/browser": "8.42.0",
|
||||||
"@stremio/stremio-colors": "5.2.0",
|
"@stremio/stremio-colors": "5.2.0",
|
||||||
"@stremio/stremio-core-web": "0.56.4",
|
"@stremio/stremio-core-web": "0.57.0",
|
||||||
"@stremio/stremio-icons": "5.10.0",
|
"@stremio/stremio-icons": "5.10.0",
|
||||||
"@stremio/stremio-video": "0.0.78",
|
"@stremio/stremio-video": "0.0.78",
|
||||||
"a-color-picker": "1.2.1",
|
"a-color-picker": "1.2.1",
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ importers:
|
||||||
specifier: 5.2.0
|
specifier: 5.2.0
|
||||||
version: 5.2.0
|
version: 5.2.0
|
||||||
'@stremio/stremio-core-web':
|
'@stremio/stremio-core-web':
|
||||||
specifier: 0.56.4
|
specifier: 0.57.0
|
||||||
version: 0.56.4
|
version: 0.57.0
|
||||||
'@stremio/stremio-icons':
|
'@stremio/stremio-icons':
|
||||||
specifier: 5.10.0
|
specifier: 5.10.0
|
||||||
version: 5.10.0
|
version: 5.10.0
|
||||||
|
|
@ -1394,8 +1394,8 @@ packages:
|
||||||
'@stremio/stremio-colors@5.2.0':
|
'@stremio/stremio-colors@5.2.0':
|
||||||
resolution: {integrity: sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==}
|
resolution: {integrity: sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==}
|
||||||
|
|
||||||
'@stremio/stremio-core-web@0.56.4':
|
'@stremio/stremio-core-web@0.57.0':
|
||||||
resolution: {integrity: sha512-tFAMYgKrJ1bkvHRMpxDykM/844sDjgRPFk6FLhjQiwh01OHIyEgDqGo/NgwFM+CuMR4mW676SDvwNHkK0Xqg3w==}
|
resolution: {integrity: sha512-go8GZwGm6MFfjez6J/T1HrGNY2330EU3VoVinDYR0rE331aay6fenViLyCYLE829FTebW2eglrmc7MdHjmhqSA==}
|
||||||
|
|
||||||
'@stremio/stremio-icons@5.10.0':
|
'@stremio/stremio-icons@5.10.0':
|
||||||
resolution: {integrity: sha512-Zw/vGC3D2yeQfk8xv/tfMJTDvbCPOI91tBg4XpR2+EgbZSX8Xvm7Vz457PIhFPhTAwdOPHp0VX0M3gzjbt0zOg==}
|
resolution: {integrity: sha512-Zw/vGC3D2yeQfk8xv/tfMJTDvbCPOI91tBg4XpR2+EgbZSX8Xvm7Vz457PIhFPhTAwdOPHp0VX0M3gzjbt0zOg==}
|
||||||
|
|
@ -6444,7 +6444,7 @@ snapshots:
|
||||||
|
|
||||||
'@stremio/stremio-colors@5.2.0': {}
|
'@stremio/stremio-colors@5.2.0': {}
|
||||||
|
|
||||||
'@stremio/stremio-core-web@0.56.4':
|
'@stremio/stremio-core-web@0.57.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.24.1
|
'@babel/runtime': 7.24.1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export type FullscreenContextValue = readonly [
|
||||||
requestFullscreen: () => Promise<void> | void,
|
requestFullscreen: () => Promise<void> | void,
|
||||||
exitFullscreen: () => void,
|
exitFullscreen: () => void,
|
||||||
toggleFullscreen: () => void,
|
toggleFullscreen: () => void,
|
||||||
|
supported: boolean,
|
||||||
];
|
];
|
||||||
|
|
||||||
const FullscreenContext = createContext<FullscreenContextValue | null>(null);
|
const FullscreenContext = createContext<FullscreenContextValue | null>(null);
|
||||||
|
|
|
||||||
|
|
@ -79,9 +79,11 @@ const FullscreenProvider = ({ children }: Props) => {
|
||||||
};
|
};
|
||||||
}, [shell, toggleFullscreen, exitFullscreen, escExitFullscreen]);
|
}, [shell, toggleFullscreen, exitFullscreen, escExitFullscreen]);
|
||||||
|
|
||||||
|
const supported = shell.active || document.fullscreenEnabled === true;
|
||||||
|
|
||||||
const value = useMemo<FullscreenContextValue>(
|
const value = useMemo<FullscreenContextValue>(
|
||||||
() => [fullscreen, requestFullscreen, exitFullscreen, toggleFullscreen],
|
() => [fullscreen, requestFullscreen, exitFullscreen, toggleFullscreen, supported],
|
||||||
[fullscreen, requestFullscreen, exitFullscreen, toggleFullscreen]
|
[fullscreen, requestFullscreen, exitFullscreen, toggleFullscreen, supported]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,6 @@
|
||||||
"label": "SETTINGS_SHORTCUT_NAVIGATE_HISTORY",
|
"label": "SETTINGS_SHORTCUT_NAVIGATE_HISTORY",
|
||||||
"combos": [["Backspace"], ["Ctrl", "Backspace"]]
|
"combos": [["Backspace"], ["Ctrl", "Backspace"]]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "exit",
|
|
||||||
"label": "SETTINGS_SHORTCUT_EXIT_BACK",
|
|
||||||
"combos": [["Backspace"]]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "fullscreen",
|
"name": "fullscreen",
|
||||||
"label": "SETTINGS_SHORTCUT_FULLSCREEN",
|
"label": "SETTINGS_SHORTCUT_FULLSCREEN",
|
||||||
|
|
@ -128,6 +123,11 @@
|
||||||
"name": "playNext",
|
"name": "playNext",
|
||||||
"label": "SETTINGS_SHORTCUT_PLAY_NEXT",
|
"label": "SETTINGS_SHORTCUT_PLAY_NEXT",
|
||||||
"combos": [["Shift", "N"]]
|
"combos": [["Shift", "N"]]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "exit",
|
||||||
|
"label": "SETTINGS_SHORTCUT_EXIT_BACK",
|
||||||
|
"combos": [["Escape"]]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ const classnames = require('classnames');
|
||||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||||
const { Button, Image } = require('stremio/components');
|
const { Button, Image } = require('stremio/components');
|
||||||
const { useFullscreen } = require('stremio/common/Fullscreen');
|
const { useFullscreen } = require('stremio/common/Fullscreen');
|
||||||
const usePWA = require('stremio/common/usePWA');
|
|
||||||
const { useHorizontalNavGamepadNavigation } = require('stremio/services/GamepadNavigation');
|
const { useHorizontalNavGamepadNavigation } = require('stremio/services/GamepadNavigation');
|
||||||
const SearchBar = require('./SearchBar');
|
const SearchBar = require('./SearchBar');
|
||||||
const NavMenu = require('./NavMenu');
|
const NavMenu = require('./NavMenu');
|
||||||
|
|
@ -17,8 +16,7 @@ const HorizontalNavBar = React.memo(({ className, route, query, title, backButto
|
||||||
const backButtonOnClick = React.useCallback(() => {
|
const backButtonOnClick = React.useCallback(() => {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
}, []);
|
}, []);
|
||||||
const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen();
|
const [fullscreen, requestFullscreen, exitFullscreen, , supported] = useFullscreen();
|
||||||
const [isIOSPWA] = usePWA();
|
|
||||||
const renderNavMenuLabel = React.useCallback(({ ref, className, onClick, children, }) => (
|
const renderNavMenuLabel = React.useCallback(({ ref, className, onClick, children, }) => (
|
||||||
<Button ref={ref} className={classnames(className, styles['button-container'], styles['menu-button-container'])} tabIndex={-1} onClick={onClick}>
|
<Button ref={ref} className={classnames(className, styles['button-container'], styles['menu-button-container'])} tabIndex={-1} onClick={onClick}>
|
||||||
<Icon className={styles['icon']} name={'person-outline'} />
|
<Icon className={styles['icon']} name={'person-outline'} />
|
||||||
|
|
@ -64,7 +62,7 @@ const HorizontalNavBar = React.memo(({ className, route, query, title, backButto
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
!isIOSPWA && fullscreenButton ?
|
supported && fullscreenButton ?
|
||||||
<Button className={styles['button-container']} title={fullscreen ? t('EXIT_FULLSCREEN') : t('ENTER_FULLSCREEN')} tabIndex={-1} onClick={fullscreen ? exitFullscreen : requestFullscreen}>
|
<Button className={styles['button-container']} title={fullscreen ? t('EXIT_FULLSCREEN') : t('ENTER_FULLSCREEN')} tabIndex={-1} onClick={fullscreen ? exitFullscreen : requestFullscreen}>
|
||||||
<Icon className={styles['icon']} name={fullscreen ? 'minimize' : 'maximize'} />
|
<Icon className={styles['icon']} name={fullscreen ? 'minimize' : 'maximize'} />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ const NavMenuContent = ({ onClick }) => {
|
||||||
const streamingServer = useStreamingServer();
|
const streamingServer = useStreamingServer();
|
||||||
const { handlePlayUrl } = usePlayUrl();
|
const { handlePlayUrl } = usePlayUrl();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen();
|
const [fullscreen, requestFullscreen, exitFullscreen, , supported] = useFullscreen();
|
||||||
const [isIOSPWA, isAndroidPWA] = usePWA();
|
const [, isAndroidPWA] = usePWA();
|
||||||
const streamingServerWarningDismissed = React.useMemo(() => {
|
const streamingServerWarningDismissed = React.useMemo(() => {
|
||||||
return streamingServer.settings !== null && streamingServer.settings.type === 'Ready' || (
|
return streamingServer.settings !== null && streamingServer.settings.type === 'Ready' || (
|
||||||
!isNaN(profile.settings.streamingServerWarningDismissed.getTime()) &&
|
!isNaN(profile.settings.streamingServerWarningDismissed.getTime()) &&
|
||||||
|
|
@ -79,7 +79,7 @@ const NavMenuContent = ({ onClick }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
!isIOSPWA && !isAndroidPWA ?
|
supported && !isAndroidPWA ?
|
||||||
<div className={styles['nav-menu-section']}>
|
<div className={styles['nav-menu-section']}>
|
||||||
<Button className={styles['nav-menu-option-container']} title={fullscreen ? t('EXIT_FULLSCREEN') : t('ENTER_FULLSCREEN')} onClick={fullscreen ? exitFullscreen : requestFullscreen}>
|
<Button className={styles['nav-menu-option-container']} title={fullscreen ? t('EXIT_FULLSCREEN') : t('ENTER_FULLSCREEN')} onClick={fullscreen ? exitFullscreen : requestFullscreen}>
|
||||||
<Icon className={styles['icon']} name={fullscreen ? 'minimize' : 'maximize'} />
|
<Icon className={styles['icon']} name={fullscreen ? 'minimize' : 'maximize'} />
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@
|
||||||
action-buttons-container: action-buttons-container;
|
action-buttons-container: action-buttons-container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:import('~stremio/components/MultiselectMenu/Dropdown/Dropdown.less') {
|
||||||
|
dropdown: dropdown;
|
||||||
|
open: open;
|
||||||
|
}
|
||||||
|
|
||||||
@padding: 1rem;
|
@padding: 1rem;
|
||||||
|
|
||||||
.side-drawer {
|
.side-drawer {
|
||||||
|
|
@ -69,6 +74,7 @@
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
padding: @padding;
|
padding: @padding;
|
||||||
|
min-height: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
.side-drawer-meta-preview {
|
.side-drawer-meta-preview {
|
||||||
|
|
@ -89,8 +95,11 @@
|
||||||
flex: 2;
|
flex: 2;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
|
||||||
.videos {
|
.videos {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -109,6 +118,14 @@
|
||||||
@media @phone-landscape {
|
@media @phone-landscape {
|
||||||
.side-drawer {
|
.side-drawer {
|
||||||
max-width: 50dvw;
|
max-width: 50dvw;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
max-height: 40dvh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown.open {
|
||||||
|
max-height: calc(3rem * 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright (C) 2017-2024 Smart code 203358507
|
// Copyright (C) 2017-2024 Smart code 203358507
|
||||||
|
|
||||||
import React, { useMemo, useCallback, useState, forwardRef, memo } from 'react';
|
import React, { useMemo, useCallback, useState, useRef, forwardRef, memo } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Icon from '@stremio/stremio-icons/react';
|
import Icon from '@stremio/stremio-icons/react';
|
||||||
import { useCore } from 'stremio/core';
|
import { useCore } from 'stremio/core';
|
||||||
|
|
@ -22,6 +22,7 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
|
||||||
const core = useCore();
|
const core = useCore();
|
||||||
const [season, setSeason] = useState<number>(seriesInfo?.season);
|
const [season, setSeason] = useState<number>(seriesInfo?.season);
|
||||||
const [selectedVideoId, setSelectedVideoId] = useState<string | null>(null);
|
const [selectedVideoId, setSelectedVideoId] = useState<string | null>(null);
|
||||||
|
const videosRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const metaItem = useMemo(() => {
|
const metaItem = useMemo(() => {
|
||||||
return seriesInfo ?
|
return seriesInfo ?
|
||||||
|
|
@ -47,8 +48,9 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
|
||||||
.sort((a, b) => (a || Number.MAX_SAFE_INTEGER) - (b || Number.MAX_SAFE_INTEGER));
|
.sort((a, b) => (a || Number.MAX_SAFE_INTEGER) - (b || Number.MAX_SAFE_INTEGER));
|
||||||
}, [props.metaItem.videos]);
|
}, [props.metaItem.videos]);
|
||||||
|
|
||||||
const seasonOnSelect = useCallback((event: { value: string }) => {
|
const seasonOnSelect = useCallback((event: { value: string | number }) => {
|
||||||
setSeason(parseInt(event.value));
|
setSeason(parseInt(String(event.value), 10));
|
||||||
|
videosRef.current?.scrollTo({ top: 0, left: 0 });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const seasonWatched = React.useMemo(() => {
|
const seasonWatched = React.useMemo(() => {
|
||||||
|
|
@ -109,7 +111,7 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
|
||||||
seasons={seasons}
|
seasons={seasons}
|
||||||
onSelect={seasonOnSelect}
|
onSelect={seasonOnSelect}
|
||||||
/>
|
/>
|
||||||
<div className={styles['videos']}>
|
<div ref={videosRef} className={styles['videos']}>
|
||||||
{videos.map((video, index) => (
|
{videos.map((video, index) => (
|
||||||
<Video
|
<Video
|
||||||
key={index}
|
key={index}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ html:not(.active-slider-within) {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.nav-bar-layer {
|
&.nav-bar-layer {
|
||||||
|
left: var(--safe-area-inset-left);
|
||||||
|
right: var(--safe-area-inset-right);
|
||||||
bottom: initial;
|
bottom: initial;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|
@ -95,9 +97,11 @@ html:not(.active-slider-within) {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.control-bar-layer {
|
&.control-bar-layer {
|
||||||
|
left: var(--safe-area-inset-left);
|
||||||
|
right: var(--safe-area-inset-right);
|
||||||
top: initial;
|
top: initial;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: calc(0.5rem + var(--safe-area-inset-bottom));
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue