diff --git a/package-lock.json b/package-lock.json index 7bd2bd6ea..1f87bbd55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "react-i18next": "^15.1.3", "react-is": "18.3.1", "spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", - "stremio-translations": "github:Stremio/stremio-translations#f666d9a97cafa5aa150878b5c51a2896b5f4f1b2", + "stremio-translations": "github:Stremio/stremio-translations#a0f50634202f748a57907b645d2cd92fbaa479dd", "url": "0.11.4", "use-long-press": "^3.2.0" }, @@ -13372,8 +13372,9 @@ }, "node_modules/stremio-translations": { "version": "1.44.9", - "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#f666d9a97cafa5aa150878b5c51a2896b5f4f1b2", - "integrity": "sha512-SzaIGUMqQuMAq58sI9L/RKSs5O4eF8VKPMqnWFddBSg/tZOU9xuNYqjRPKT07cp8MRfzzGQmCKMByozTYfjdIA==" + "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#a0f50634202f748a57907b645d2cd92fbaa479dd", + "integrity": "sha512-JJpd1JJet3T6/VTNdZ2NZ7uvHJ4zkuyqo5BnTcDGqLVNO/OpicGqKhZjE4WGSgmuhsfPBU8T0ICCfzKu2xpvKg==", + "license": "MIT" }, "node_modules/string_decoder": { "version": "1.1.1", diff --git a/package.json b/package.json index d1709095e..8a4665615 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "react-i18next": "^15.1.3", "react-is": "18.3.1", "spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", - "stremio-translations": "github:Stremio/stremio-translations#f666d9a97cafa5aa150878b5c51a2896b5f4f1b2", + "stremio-translations": "github:Stremio/stremio-translations#a0f50634202f748a57907b645d2cd92fbaa479dd", "url": "0.11.4", "use-long-press": "^3.2.0" }, diff --git a/src/routes/Player/AudioMenu/AudioMenu.less b/src/routes/Player/AudioMenu/AudioMenu.less new file mode 100644 index 000000000..1887a1e7c --- /dev/null +++ b/src/routes/Player/AudioMenu/AudioMenu.less @@ -0,0 +1,60 @@ +.audio-menu { + display: flex; + flex-direction: row; + + .container { + flex: none; + align-self: stretch; + display: flex; + flex-direction: column; + width: 16rem; + + .header { + flex: none; + align-self: stretch; + padding: 1.5rem 2rem; + font-weight: 700; + color: var(--primary-foreground-color); + } + + .list { + flex: 1; + align-self: stretch; + overflow-y: auto; + padding: 0 1rem; + padding-bottom: 0.5rem; + + .option { + display: flex; + flex-direction: row; + align-items: center; + height: 3.5rem; + padding: 0 1.5rem; + margin-bottom: 0.5rem; + border-radius: var(--border-radius); + + &:global(.selected), &:hover { + background-color: var(--overlay-color); + } + + .label { + flex: 1; + max-height: 2.4em; + font-size: 1.1rem; + color: var(--primary-foreground-color); + text-wrap: nowrap; + text-overflow: ellipsis; + } + + .icon { + flex: none; + width: 0.5rem; + height: 0.5rem; + border-radius: 100%; + margin-left: 1rem; + background-color: var(--secondary-accent-color); + } + } + } + } +} \ No newline at end of file diff --git a/src/routes/Player/AudioMenu/AudioMenu.tsx b/src/routes/Player/AudioMenu/AudioMenu.tsx new file mode 100644 index 000000000..71bdb68ed --- /dev/null +++ b/src/routes/Player/AudioMenu/AudioMenu.tsx @@ -0,0 +1,66 @@ +import React, { MouseEvent, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import classNames from 'classnames'; +import { Button, languageNames } from 'stremio/common'; +import styles from './AudioMenu.less'; + +type Props = { + className: string, + selectedAudioTrackId: string | null, + audioTracks: AudioTrack[], + onAudioTrackSelected: (id: string) => void, +}; + +const AudioMenu = ({ className, selectedAudioTrackId, audioTracks, onAudioTrackSelected }: Props) => { + const { t } = useTranslation(); + + const onAudioTrackClick = useCallback(({ currentTarget }: MouseEvent) => { + const id = currentTarget.getAttribute('data-id')!; + onAudioTrackSelected && onAudioTrackSelected(id); + }, [onAudioTrackSelected]); + + const onMouseDown = (event: MouseEvent) => { + // @ts-expect-error: Property 'audioMenuClosePrevented' does not exist on type 'MouseEvent'. + event.nativeEvent.audioMenuClosePrevented = true; + }; + + return ( +
+
+
+ { t('AUDIO_TRACKS') } +
+
+ { + audioTracks.map(({ id, label, lang }, index) => ( + + )) + } +
+
+
+ ); +}; + +export default AudioMenu; diff --git a/src/routes/Player/AudioMenu/index.ts b/src/routes/Player/AudioMenu/index.ts new file mode 100644 index 000000000..265490872 --- /dev/null +++ b/src/routes/Player/AudioMenu/index.ts @@ -0,0 +1,2 @@ +import AudioMenu from './AudioMenu'; +export default AudioMenu; diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index 1d1330539..a5fe1adf9 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -35,6 +35,7 @@ const ControlBar = ({ onVolumeChangeRequested, onSeekRequested, onToggleSubtitlesMenu, + onToggleAudioMenu, onToggleSpeedMenu, onToggleSideDrawer, onToggleOptionsMenu, @@ -47,6 +48,9 @@ const ControlBar = ({ const onSubtitlesButtonMouseDown = React.useCallback((event) => { event.nativeEvent.subtitlesMenuClosePrevented = true; }, []); + const onAudioButtonMouseDown = React.useCallback((event) => { + event.nativeEvent.audioMenuClosePrevented = true; + }, []); const onSpeedButtonMouseDown = React.useCallback((event) => { event.nativeEvent.speedMenuClosePrevented = true; }, []); @@ -150,9 +154,12 @@ const ControlBar = ({ - + { metaItem?.content?.videos?.length > 0 ? - ))} - - - : - null - }
{ t('PLAYER_SUBTITLES_LANGUAGES') }
@@ -312,16 +286,8 @@ SubtitlesMenu.propTypes = { extraSubtitlesOffset: PropTypes.number, extraSubtitlesDelay: PropTypes.number, extraSubtitlesSize: PropTypes.number, - audioTracks: PropTypes.arrayOf(PropTypes.shape({ - id: PropTypes.string.isRequired, - lang: PropTypes.string.isRequired, - origin: PropTypes.string.isRequired, - label: PropTypes.string.isRequired - })), - selectedAudioTrackId: PropTypes.string, onSubtitlesTrackSelected: PropTypes.func, onExtraSubtitlesTrackSelected: PropTypes.func, - onAudioTrackSelected: PropTypes.func, onSubtitlesOffsetChanged: PropTypes.func, onSubtitlesSizeChanged: PropTypes.func, onExtraSubtitlesOffsetChanged: PropTypes.func, diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 275028038..407a4c172 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -627,6 +627,14 @@ const Settings = () => { S
+
+
+
{ t('SETTINGS_SHORTCUT_MENU_AUDIO') }
+
+
+ A +
+
{ t('SETTINGS_SHORTCUT_MENU_INFO') }
diff --git a/src/types/types.d.ts b/src/types/types.d.ts index 8b7a627b6..8f6d55730 100644 --- a/src/types/types.d.ts +++ b/src/types/types.d.ts @@ -61,3 +61,10 @@ type Catalog = { installed?: boolean, deepLinks?: D, }; + +type AudioTrack = { + id: string, + label: string, + lang: string, + origin: string, +};