mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-05-11 16:30:42 +00:00
Merge remote-tracking branch 'origin/development' into pr-1260
# Conflicts: # src/common/Fullscreen/FullscreenProvider.tsx
This commit is contained in:
commit
86d716187a
16 changed files with 102 additions and 188 deletions
|
|
@ -17,7 +17,7 @@
|
|||
"@babel/runtime": "7.29.2",
|
||||
"@sentry/browser": "8.42.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-video": "0.0.79",
|
||||
"a-color-picker": "1.2.1",
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
"react-i18next": "^15.7.4",
|
||||
"react-is": "18.3.1",
|
||||
"spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6",
|
||||
"stremio-translations": "github:Stremio/stremio-translations#d9cd2fb88268b365b14101452665de698f9c15e9",
|
||||
"stremio-translations": "github:Stremio/stremio-translations#c2d68dc590ac7d56f0df5e69a2144ba83e0d5ef0",
|
||||
"url": "0.11.4",
|
||||
"use-long-press": "^3.3.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ importers:
|
|||
specifier: 5.2.0
|
||||
version: 5.2.0
|
||||
'@stremio/stremio-core-web':
|
||||
specifier: 0.56.4
|
||||
version: 0.56.4
|
||||
specifier: 0.57.0
|
||||
version: 0.57.0
|
||||
'@stremio/stremio-icons':
|
||||
specifier: 5.10.0
|
||||
version: 5.10.0
|
||||
|
|
@ -90,8 +90,8 @@ importers:
|
|||
specifier: github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6
|
||||
version: https://codeload.github.com/Stremio/spatial-navigation/tar.gz/64871b1422466f5f45d24ebc8bbd315b2ebab6a6
|
||||
stremio-translations:
|
||||
specifier: github:Stremio/stremio-translations#d9cd2fb88268b365b14101452665de698f9c15e9
|
||||
version: https://codeload.github.com/Stremio/stremio-translations/tar.gz/d9cd2fb88268b365b14101452665de698f9c15e9
|
||||
specifier: github:Stremio/stremio-translations#c2d68dc590ac7d56f0df5e69a2144ba83e0d5ef0
|
||||
version: https://codeload.github.com/Stremio/stremio-translations/tar.gz/c2d68dc590ac7d56f0df5e69a2144ba83e0d5ef0
|
||||
url:
|
||||
specifier: 0.11.4
|
||||
version: 0.11.4
|
||||
|
|
@ -123,12 +123,12 @@ importers:
|
|||
'@types/lodash.throttle':
|
||||
specifier: ^4.1.9
|
||||
version: 4.1.9
|
||||
'@types/node':
|
||||
specifier: ^25.6.0
|
||||
version: 25.6.0
|
||||
'@types/magnet-uri':
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
'@types/node':
|
||||
specifier: ^25.6.0
|
||||
version: 25.6.0
|
||||
'@types/react':
|
||||
specifier: ^18.3.28
|
||||
version: 18.3.28
|
||||
|
|
@ -1394,8 +1394,8 @@ packages:
|
|||
'@stremio/stremio-colors@5.2.0':
|
||||
resolution: {integrity: sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==}
|
||||
|
||||
'@stremio/stremio-core-web@0.56.4':
|
||||
resolution: {integrity: sha512-tFAMYgKrJ1bkvHRMpxDykM/844sDjgRPFk6FLhjQiwh01OHIyEgDqGo/NgwFM+CuMR4mW676SDvwNHkK0Xqg3w==}
|
||||
'@stremio/stremio-core-web@0.57.0':
|
||||
resolution: {integrity: sha512-go8GZwGm6MFfjez6J/T1HrGNY2330EU3VoVinDYR0rE331aay6fenViLyCYLE829FTebW2eglrmc7MdHjmhqSA==}
|
||||
|
||||
'@stremio/stremio-icons@5.10.0':
|
||||
resolution: {integrity: sha512-Zw/vGC3D2yeQfk8xv/tfMJTDvbCPOI91tBg4XpR2+EgbZSX8Xvm7Vz457PIhFPhTAwdOPHp0VX0M3gzjbt0zOg==}
|
||||
|
|
@ -1497,9 +1497,6 @@ packages:
|
|||
'@types/mime@1.3.5':
|
||||
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
|
||||
|
||||
'@types/node-forge@1.3.14':
|
||||
resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==}
|
||||
|
||||
'@types/node@25.6.0':
|
||||
resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==}
|
||||
|
||||
|
|
@ -4424,8 +4421,8 @@ packages:
|
|||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/d9cd2fb88268b365b14101452665de698f9c15e9:
|
||||
resolution: {tarball: https://codeload.github.com/Stremio/stremio-translations/tar.gz/d9cd2fb88268b365b14101452665de698f9c15e9}
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/c2d68dc590ac7d56f0df5e69a2144ba83e0d5ef0:
|
||||
resolution: {tarball: https://codeload.github.com/Stremio/stremio-translations/tar.gz/c2d68dc590ac7d56f0df5e69a2144ba83e0d5ef0}
|
||||
version: 1.52.0
|
||||
|
||||
string-length@4.0.2:
|
||||
|
|
@ -6447,7 +6444,7 @@ snapshots:
|
|||
|
||||
'@stremio/stremio-colors@5.2.0': {}
|
||||
|
||||
'@stremio/stremio-core-web@0.56.4':
|
||||
'@stremio/stremio-core-web@0.57.0':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.1
|
||||
|
||||
|
|
@ -10003,7 +10000,7 @@ snapshots:
|
|||
es-errors: 1.3.0
|
||||
internal-slot: 1.1.0
|
||||
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/d9cd2fb88268b365b14101452665de698f9c15e9: {}
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/c2d68dc590ac7d56f0df5e69a2144ba83e0d5ef0: {}
|
||||
|
||||
string-length@4.0.2:
|
||||
dependencies:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const React = require('react');
|
|||
const { useTranslation } = require('react-i18next');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { Router } = require('stremio-router');
|
||||
const { Shell, Chromecast, KeyboardShortcuts, ServicesProvider, GamepadProvider } = require('stremio/services');
|
||||
const { Shell, Chromecast, ServicesProvider, GamepadProvider } = require('stremio/services');
|
||||
const { NotFound } = require('stremio/routes');
|
||||
const { FullscreenProvider, PlatformProvider, ToastProvider, TooltipProvider, ShortcutsProvider, CONSTANTS, useShell, useBinaryState, useProfile, withCoreSuspender, onFileDrop } = require('stremio/common');
|
||||
const ServicesToaster = require('./ServicesToaster');
|
||||
|
|
@ -33,13 +33,12 @@ const App = () => {
|
|||
return {
|
||||
shell: new Shell(),
|
||||
chromecast: new Chromecast(),
|
||||
keyboardShortcuts: new KeyboardShortcuts(),
|
||||
};
|
||||
}, []);
|
||||
const [shortcutModalOpen,, closeShortcutsModal, toggleShortcutModal] = useBinaryState(false);
|
||||
const [gamepadModalOpen,, closeGamepadModal, toggleGamepadModal] = useBinaryState(false);
|
||||
|
||||
const onShortcut = React.useCallback((name) => {
|
||||
const onShortcut = React.useCallback((name, combo, key) => {
|
||||
switch (name) {
|
||||
case 'shortcuts':
|
||||
toggleShortcutModal();
|
||||
|
|
@ -47,6 +46,18 @@ const App = () => {
|
|||
case 'gamepadGuide':
|
||||
toggleGamepadModal();
|
||||
break;
|
||||
case 'navigateSearch':
|
||||
window.location = '#/search';
|
||||
break;
|
||||
case 'navigateTabs': {
|
||||
const routes = ['', 'discover', 'library', 'calendar', 'addons', 'settings'];
|
||||
const index = key - 1;
|
||||
if (index in routes) window.location = `#/${routes[index]}`;
|
||||
break;
|
||||
}
|
||||
case 'navigateHistory':
|
||||
combo === 0 ? window.history.back() : window.history.forward();
|
||||
break;
|
||||
}
|
||||
}, [toggleShortcutModal, toggleGamepadModal]);
|
||||
|
||||
|
|
@ -90,12 +101,10 @@ const App = () => {
|
|||
services.chromecast.on('stateChanged', onChromecastStateChange);
|
||||
services.shell.start();
|
||||
services.chromecast.start();
|
||||
services.keyboardShortcuts.start();
|
||||
window.services = services;
|
||||
return () => {
|
||||
services.shell.stop();
|
||||
services.chromecast.stop();
|
||||
services.keyboardShortcuts.stop();
|
||||
services.chromecast.off('stateChanged', onChromecastStateChange);
|
||||
};
|
||||
}, []);
|
||||
|
|
|
|||
|
|
@ -11,16 +11,6 @@ type Props = {
|
|||
children: React.ReactNode,
|
||||
};
|
||||
|
||||
const isTextInputFocused = () => {
|
||||
const activeElement = document.activeElement;
|
||||
|
||||
return activeElement instanceof HTMLElement &&
|
||||
(activeElement.tagName === 'INPUT' ||
|
||||
activeElement.tagName === 'TEXTAREA' ||
|
||||
activeElement.tagName === 'SELECT' ||
|
||||
activeElement.isContentEditable);
|
||||
};
|
||||
|
||||
const hasWebkitFullscreen = typeof HTMLVideoElement !== 'undefined' &&
|
||||
typeof HTMLVideoElement.prototype.webkitEnterFullscreen === 'function';
|
||||
|
||||
|
|
@ -48,7 +38,11 @@ const FullscreenProvider = ({ children }: Props) => {
|
|||
if (shell.active) {
|
||||
shell.send('win-set-visibility', { fullscreen: true });
|
||||
} else if (document.fullscreenEnabled) {
|
||||
await document.documentElement.requestFullscreen();
|
||||
try {
|
||||
await document.documentElement.requestFullscreen();
|
||||
} catch (err) {
|
||||
console.error('Error enabling fullscreen', err);
|
||||
}
|
||||
} else if (videoElementRef.current && hasWebkitFullscreen) {
|
||||
(videoElementRef.current as any).webkitEnterFullscreen();
|
||||
}
|
||||
|
|
@ -68,12 +62,7 @@ const FullscreenProvider = ({ children }: Props) => {
|
|||
fullscreen ? exitFullscreen() : requestFullscreen();
|
||||
}, [fullscreen, exitFullscreen, requestFullscreen]);
|
||||
|
||||
const toggleFullscreenFromShortcut = useCallback(() => {
|
||||
if (isTextInputFocused()) return;
|
||||
toggleFullscreen();
|
||||
}, [toggleFullscreen]);
|
||||
|
||||
onShortcut('fullscreen', toggleFullscreenFromShortcut, [toggleFullscreenFromShortcut]);
|
||||
onShortcut('fullscreen', toggleFullscreen, [toggleFullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
const videoElement = videoElementRef.current;
|
||||
|
|
|
|||
|
|
@ -16,16 +16,26 @@ const ShortcutsContext = createContext<ShortcutsContext>({} as ShortcutsContext)
|
|||
|
||||
type Props = {
|
||||
children: JSX.Element,
|
||||
onShortcut: (name: ShortcutName) => void,
|
||||
onShortcut: (name: ShortcutName, combo: number, key: string) => void,
|
||||
};
|
||||
|
||||
const REPEAT_THROTTLE_MS = 130;
|
||||
|
||||
const isInputFocused = () => {
|
||||
const inputElements = ['INPUT', 'TEXTAREA', 'SELECT'];
|
||||
const activeElement = document.activeElement;
|
||||
|
||||
return activeElement instanceof HTMLElement &&
|
||||
(inputElements.includes(activeElement.tagName) || activeElement.isContentEditable);
|
||||
};
|
||||
|
||||
const ShortcutsProvider = ({ children, onShortcut }: Props) => {
|
||||
const listeners = useRef<Map<ShortcutName, Set<ShortcutListener>>>(new Map());
|
||||
const lastRepeatTime = useRef<Map<string, number>>(new Map());
|
||||
|
||||
const onKeyDown = useCallback(({ ctrlKey, shiftKey, altKey, metaKey, code, key, repeat }: KeyboardEvent) => {
|
||||
if (isInputFocused()) return;
|
||||
|
||||
if (repeat) {
|
||||
const now = Date.now();
|
||||
const last = lastRepeatTime.current.get(code) ?? 0;
|
||||
|
|
@ -43,7 +53,7 @@ const ShortcutsProvider = ({ children, onShortcut }: Props) => {
|
|||
const combo = combos.indexOf(keys);
|
||||
listeners.current.get(name)?.forEach((listener) => listener(combo));
|
||||
|
||||
onShortcut(name as ShortcutName);
|
||||
onShortcut(name as ShortcutName, combo, key);
|
||||
}
|
||||
}));
|
||||
}, [onShortcut]);
|
||||
|
|
|
|||
|
|
@ -13,16 +13,16 @@
|
|||
"label": "SETTINGS_SHORTCUT_GO_TO_SEARCH",
|
||||
"combos": [["0"]]
|
||||
},
|
||||
{
|
||||
"name": "navigateHistory",
|
||||
"label": "SETTINGS_SHORTCUT_NAVIGATE_HISTORY",
|
||||
"combos": [["Backspace"], ["Ctrl", "Backspace"]]
|
||||
},
|
||||
{
|
||||
"name": "fullscreen",
|
||||
"label": "SETTINGS_SHORTCUT_FULLSCREEN",
|
||||
"combos": [["F"]]
|
||||
},
|
||||
{
|
||||
"name": "exit",
|
||||
"label": "SETTINGS_SHORTCUT_EXIT_BACK",
|
||||
"combos": [["Backspace"]]
|
||||
},
|
||||
{
|
||||
"name": "shortcuts",
|
||||
"label": "SETTINGS_SHORTCUT_SHORTCUTS",
|
||||
|
|
@ -55,14 +55,9 @@
|
|||
"combos": [["ArrowLeft"], ["Shift", "ArrowLeft"]]
|
||||
},
|
||||
{
|
||||
"name": "volumeUp",
|
||||
"label": "SETTINGS_SHORTCUT_VOLUME_UP",
|
||||
"combos": [["ArrowUp"]]
|
||||
},
|
||||
{
|
||||
"name": "volumeDown",
|
||||
"label": "SETTINGS_SHORTCUT_VOLUME_DOWN",
|
||||
"combos": [["ArrowDown"]]
|
||||
"name": "volume",
|
||||
"label": "SETTINGS_SHORTCUT_VOLUME",
|
||||
"combos": [["ArrowUp"], ["ArrowDown"]]
|
||||
},
|
||||
{
|
||||
"name": "mute",
|
||||
|
|
@ -80,14 +75,9 @@
|
|||
"combos": [["G"], ["H"]]
|
||||
},
|
||||
{
|
||||
"name": "speedDown",
|
||||
"label": "SETTINGS_SHORTCUT_DECREASE_PLAYBACK_SPEED",
|
||||
"combos": [["["]]
|
||||
},
|
||||
{
|
||||
"name": "speedUp",
|
||||
"label": "SETTINGS_SHORTCUT_INCREASE_PLAYBACK_SPEED",
|
||||
"combos": [["]"]]
|
||||
"name": "speed",
|
||||
"label": "SETTINGS_SHORTCUT_PLAYBACK_SPEED",
|
||||
"combos": [["["], ["]"]]
|
||||
},
|
||||
{
|
||||
"name": "toggleSubtitles",
|
||||
|
|
@ -123,6 +113,11 @@
|
|||
"name": "playNext",
|
||||
"label": "SETTINGS_SHORTCUT_PLAY_NEXT",
|
||||
"combos": [["Shift", "N"]]
|
||||
},
|
||||
{
|
||||
"name": "exit",
|
||||
"label": "SETTINGS_SHORTCUT_EXIT_BACK",
|
||||
"combos": [["Escape"]]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
.combos {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
row-gap: 1rem;
|
||||
justify-content: end;
|
||||
overflow: visible;
|
||||
|
||||
.combo {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.shortcuts-group {
|
||||
flex: 1 1 0;
|
||||
position: relative;
|
||||
width: 30rem;
|
||||
width: 35rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
.shortcut {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 2rem;
|
||||
overflow: visible;
|
||||
|
|
@ -35,7 +35,6 @@
|
|||
position: relative;
|
||||
font-size: 1rem;
|
||||
color: var(--primary-foreground-color);
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -590,15 +590,10 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
video.state.muted === true ? onUnmuteRequested() : onMuteRequested();
|
||||
}, [video.state.muted], !menusOpen);
|
||||
|
||||
onShortcut('volumeUp', () => {
|
||||
onShortcut('volume', (combo) => {
|
||||
if (video.state.volume !== null) {
|
||||
onVolumeChangeRequested(Math.min(video.state.volume + 5, 200));
|
||||
}
|
||||
}, [video.state.volume], !menusOpen);
|
||||
|
||||
onShortcut('volumeDown', () => {
|
||||
if (video.state.volume !== null) {
|
||||
onVolumeChangeRequested(Math.max(video.state.volume - 5, 0));
|
||||
const volume = combo === 0 ? Math.min(video.state.volume + 5, 200) : Math.max(video.state.volume - 5, 0);
|
||||
onVolumeChangeRequested(volume);
|
||||
}
|
||||
}, [video.state.volume], !menusOpen);
|
||||
|
||||
|
|
@ -623,15 +618,10 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
}
|
||||
}, [video.state.playbackSpeed, toggleSpeedMenu]);
|
||||
|
||||
onShortcut('speedUp', () => {
|
||||
onShortcut('speed', (combo) => {
|
||||
if (video.state.playbackSpeed !== null) {
|
||||
onPlaybackSpeedChanged(Math.min(video.state.playbackSpeed + 0.25, 2));
|
||||
}
|
||||
}, [video.state.playbackSpeed, onPlaybackSpeedChanged], !menusOpen);
|
||||
|
||||
onShortcut('speedDown', () => {
|
||||
if (video.state.playbackSpeed !== null) {
|
||||
onPlaybackSpeedChanged(Math.max(video.state.playbackSpeed - 0.25, 0.25));
|
||||
const speed = combo === 0 ? Math.max(video.state.playbackSpeed - 0.25, 0.25) : Math.min(video.state.playbackSpeed + 0.25, 2);
|
||||
onPlaybackSpeedChanged(speed);
|
||||
}
|
||||
}, [video.state.playbackSpeed, onPlaybackSpeedChanged], !menusOpen);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@
|
|||
action-buttons-container: action-buttons-container;
|
||||
}
|
||||
|
||||
:import('~stremio/components/MultiselectMenu/Dropdown/Dropdown.less') {
|
||||
dropdown: dropdown;
|
||||
open: open;
|
||||
}
|
||||
|
||||
@padding: 1rem;
|
||||
|
||||
.side-drawer {
|
||||
|
|
@ -69,6 +74,7 @@
|
|||
|
||||
.info {
|
||||
padding: @padding;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
|
||||
.side-drawer-meta-preview {
|
||||
|
|
@ -89,8 +95,11 @@
|
|||
flex: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
|
||||
.videos {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
|
@ -109,6 +118,14 @@
|
|||
@media @phone-landscape {
|
||||
.side-drawer {
|
||||
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
|
||||
|
||||
import React, { useMemo, useCallback, useState, forwardRef, memo } from 'react';
|
||||
import React, { useMemo, useCallback, useState, useRef, forwardRef, memo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Icon from '@stremio/stremio-icons/react';
|
||||
import { useCore } from 'stremio/core';
|
||||
|
|
@ -22,6 +22,7 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
|
|||
const core = useCore();
|
||||
const [season, setSeason] = useState<number>(seriesInfo?.season);
|
||||
const [selectedVideoId, setSelectedVideoId] = useState<string | null>(null);
|
||||
const videosRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const metaItem = useMemo(() => {
|
||||
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));
|
||||
}, [props.metaItem.videos]);
|
||||
|
||||
const seasonOnSelect = useCallback((event: { value: string }) => {
|
||||
setSeason(parseInt(event.value));
|
||||
const seasonOnSelect = useCallback((event: { value: string | number }) => {
|
||||
setSeason(parseInt(String(event.value), 10));
|
||||
videosRef.current?.scrollTo({ top: 0, left: 0 });
|
||||
}, []);
|
||||
|
||||
const seasonWatched = React.useMemo(() => {
|
||||
|
|
@ -109,7 +111,7 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
|
|||
seasons={seasons}
|
||||
onSelect={seasonOnSelect}
|
||||
/>
|
||||
<div className={styles['videos']}>
|
||||
<div ref={videosRef} className={styles['videos']}>
|
||||
{videos.map((video, index) => (
|
||||
<Video
|
||||
key={index}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ html:not(.active-slider-within) {
|
|||
}
|
||||
|
||||
&.nav-bar-layer {
|
||||
left: var(--safe-area-inset-left);
|
||||
right: var(--safe-area-inset-right);
|
||||
bottom: initial;
|
||||
background: transparent;
|
||||
overflow: visible;
|
||||
|
|
@ -95,9 +97,11 @@ html:not(.active-slider-within) {
|
|||
}
|
||||
|
||||
&.control-bar-layer {
|
||||
left: var(--safe-area-inset-left);
|
||||
right: var(--safe-area-inset-right);
|
||||
top: initial;
|
||||
overflow: visible;
|
||||
padding-bottom: 0.5rem;
|
||||
padding-bottom: calc(0.5rem + var(--safe-area-inset-bottom));
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const EventEmitter = require('eventemitter3');
|
||||
|
||||
function KeyboardShortcuts() {
|
||||
let active = false;
|
||||
|
||||
const events = new EventEmitter();
|
||||
|
||||
function onKeyDown(event) {
|
||||
if (event.keyboardShortcutPrevented || event.target.tagName === 'INPUT' || event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.code) {
|
||||
case 'Digit0': {
|
||||
event.preventDefault();
|
||||
window.location = '#/search';
|
||||
break;
|
||||
}
|
||||
case 'Digit1': {
|
||||
event.preventDefault();
|
||||
window.location = '#/';
|
||||
break;
|
||||
}
|
||||
case 'Digit2': {
|
||||
event.preventDefault();
|
||||
window.location = '#/discover';
|
||||
break;
|
||||
}
|
||||
case 'Digit3': {
|
||||
event.preventDefault();
|
||||
window.location = '#/library';
|
||||
break;
|
||||
}
|
||||
case 'Digit4': {
|
||||
event.preventDefault();
|
||||
window.location = '#/calendar';
|
||||
break;
|
||||
}
|
||||
case 'Digit5': {
|
||||
event.preventDefault();
|
||||
window.location = '#/addons';
|
||||
break;
|
||||
}
|
||||
case 'Digit6': {
|
||||
event.preventDefault();
|
||||
window.location = '#/settings';
|
||||
break;
|
||||
}
|
||||
case 'Backspace': {
|
||||
event.preventDefault();
|
||||
if (event.ctrlKey) {
|
||||
window.history.forward();
|
||||
} else {
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
function onStateChanged() {
|
||||
events.emit('stateChanged');
|
||||
}
|
||||
|
||||
Object.defineProperties(this, {
|
||||
active: {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return active;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.start = function() {
|
||||
if (active) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', onKeyDown);
|
||||
active = true;
|
||||
onStateChanged();
|
||||
};
|
||||
this.stop = function() {
|
||||
window.removeEventListener('keydown', onKeyDown);
|
||||
active = false;
|
||||
onStateChanged();
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = KeyboardShortcuts;
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const KeyboardShortcuts = require('./KeyboardShortcuts');
|
||||
|
||||
module.exports = KeyboardShortcuts;
|
||||
1
src/services/ServicesContext/types.d.ts
vendored
1
src/services/ServicesContext/types.d.ts
vendored
|
|
@ -1,5 +1,4 @@
|
|||
type ServicesContext = {
|
||||
shell: any,
|
||||
chromecast: any,
|
||||
keyboardShortcuts: any,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const Chromecast = require('./Chromecast');
|
||||
const KeyboardShortcuts = require('./KeyboardShortcuts');
|
||||
const { ServicesProvider, useServices } = require('./ServicesContext');
|
||||
const { GamepadProvider, useGamepad } = require('./GamepadContext');
|
||||
const Shell = require('./Shell');
|
||||
|
||||
module.exports = {
|
||||
Chromecast,
|
||||
KeyboardShortcuts,
|
||||
ServicesProvider,
|
||||
useServices,
|
||||
Shell,
|
||||
|
|
|
|||
Loading…
Reference in a new issue