mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
subtitles picker adapted to latest changes in common
This commit is contained in:
parent
ae4bfda554
commit
671873aeb3
2 changed files with 109 additions and 188 deletions
|
|
@ -3,13 +3,16 @@ const PropTypes = require('prop-types');
|
|||
const classnames = require('classnames');
|
||||
const Icon = require('stremio-icons/dom');
|
||||
const { Modal } = require('stremio-router');
|
||||
const { ColorPicker } = require('stremio/common');
|
||||
const { ColorInput } = require('stremio/common');
|
||||
const styles = require('./styles');
|
||||
|
||||
const ORIGIN_PRIORITIES = Object.freeze({
|
||||
'LOCAL': 1,
|
||||
'EMBEDDED': 2
|
||||
});
|
||||
const LANGUAGE_PRIORITIES = Object.freeze({
|
||||
'English': 1
|
||||
});
|
||||
const SUBTITLES_SIZE_LABELS = Object.freeze({
|
||||
1: '75%',
|
||||
2: '100%',
|
||||
|
|
@ -27,13 +30,9 @@ const comparatorWithPriorities = (priorities) => {
|
|||
if (!isNaN(valueB)) return 1;
|
||||
return a - b;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const NumberInput = ({ value, label, delta, onChange }) => {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['number-input-container']}>
|
||||
<div className={styles['number-input-button']} data-value={value - delta} onClick={onChange}>
|
||||
|
|
@ -47,100 +46,55 @@ const NumberInput = ({ value, label, delta, onChange }) => {
|
|||
);
|
||||
};
|
||||
|
||||
const SubtitlesColorPicker = ({ label, value, onChange }) => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const onOpen = () => setOpen(true);
|
||||
const onClose = () => setOpen(false);
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={styles['color-picker-button-container']}>
|
||||
<div style={{ backgroundColor: value }} className={styles['color-picker-indicator']} onClick={onOpen} />
|
||||
<div className={styles['color-picker-label']}>{label}</div>
|
||||
</div>
|
||||
{
|
||||
open ?
|
||||
<Modal>
|
||||
<div className={styles['color-picker-modal-container']} onClick={onClose}>
|
||||
<ColorPicker className={styles['color-picker-container']} value={value} onChange={onChange} />
|
||||
</div>
|
||||
</Modal>
|
||||
:
|
||||
null
|
||||
}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
class SubtitlesPicker extends React.Component {
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return nextProps.className !== this.props.className ||
|
||||
nextProps.subtitlesTracks !== this.props.subtitlesTracks ||
|
||||
nextProps.selectedSubtitlesTrackId !== this.props.selectedSubtitlesTrackId ||
|
||||
nextProps.subtitlesSize !== this.props.subtitlesSize ||
|
||||
nextProps.subtitlesDelay !== this.props.subtitlesDelay ||
|
||||
nextProps.subtitlesTextColor !== this.props.subtitlesTextColor ||
|
||||
nextProps.subtitlesBackgroundColor !== this.props.subtitlesBackgroundColor ||
|
||||
nextProps.subtitlesOutlineColor !== this.props.subtitlesOutlineColor;
|
||||
}
|
||||
|
||||
toggleSubtitleEnabled = () => {
|
||||
const selectedSubtitlesTrackId = this.props.selectedSubtitlesTrackId === null && this.props.subtitlesTracks.length > 0 ?
|
||||
this.props.subtitlesTracks[0].id
|
||||
const SubtitlesPicker = (props) => {
|
||||
const toggleSubtitleEnabled = React.useCallback(() => {
|
||||
const selectedSubtitlesTrackId = props.selectedSubtitlesTrackId === null && props.subtitlesTracks.length > 0 ?
|
||||
props.subtitlesTracks[0].id
|
||||
:
|
||||
null;
|
||||
this.props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: selectedSubtitlesTrackId });
|
||||
}
|
||||
|
||||
labelOnClick = (event) => {
|
||||
const subtitleTrack = this.props.subtitlesTracks.find(({ label, origin }) => {
|
||||
props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: selectedSubtitlesTrackId });
|
||||
}, [props.selectedSubtitlesTrackId, props.subtitlesTracks, props.dispatch]);
|
||||
const labelOnClick = React.useCallback((event) => {
|
||||
const subtitleTrack = props.subtitlesTracks.find(({ label, origin }) => {
|
||||
return label === event.currentTarget.dataset.label &&
|
||||
origin === event.currentTarget.dataset.origin;
|
||||
});
|
||||
if (subtitleTrack) {
|
||||
this.props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: subtitleTrack.id });
|
||||
props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: subtitleTrack.id });
|
||||
}
|
||||
}
|
||||
|
||||
variantOnClick = (event) => {
|
||||
this.props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: event.currentTarget.dataset.trackId });
|
||||
}
|
||||
|
||||
setsubtitlesSize = (event) => {
|
||||
this.props.dispatch({ propName: 'subtitlesSize', propValue: event.currentTarget.dataset.value });
|
||||
}
|
||||
|
||||
setSubtitlesDelay = (event) => {
|
||||
this.props.dispatch({ propName: 'subtitlesDelay', propValue: event.currentTarget.dataset.value });
|
||||
}
|
||||
|
||||
setSubtitlesTextColor = (color) => {
|
||||
this.props.dispatch({ propName: 'subtitlesTextColor', propValue: color });
|
||||
}
|
||||
|
||||
setSubtitlesBackgroundColor = (color) => {
|
||||
this.props.dispatch({ propName: 'subtitlesBackgroundColor', propValue: color });
|
||||
}
|
||||
|
||||
setSubtitlesOutlineColor = (color) => {
|
||||
this.props.dispatch({ propName: 'subtitlesOutlineColor', propValue: color });
|
||||
}
|
||||
|
||||
renderToggleButton({ selectedTrack }) {
|
||||
return (
|
||||
<div className={styles['toggle-button-container']} onClick={this.toggleSubtitleEnabled}>
|
||||
}, [props.subtitlesTracks, props.dispatch]);
|
||||
const variantOnClick = React.useCallback((event) => {
|
||||
props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: event.currentTarget.dataset.trackId });
|
||||
}, [props.dispatch]);
|
||||
const setsubtitlesSize = React.useCallback((event) => {
|
||||
props.dispatch({ propName: 'subtitlesSize', propValue: event.currentTarget.dataset.value });
|
||||
}, [props.dispatch]);
|
||||
const setSubtitlesDelay = React.useCallback((event) => {
|
||||
props.dispatch({ propName: 'subtitlesDelay', propValue: event.currentTarget.dataset.value });
|
||||
}, [props.dispatch]);
|
||||
const setSubtitlesTextColor = React.useCallback((event) => {
|
||||
props.dispatch({ propName: 'subtitlesTextColor', propValue: event.nativeEvent.value });
|
||||
}, [props.dispatch]);
|
||||
const setSubtitlesBackgroundColor = React.useCallback((color) => {
|
||||
props.dispatch({ propName: 'subtitlesBackgroundColor', propValue: color });
|
||||
}, [props.dispatch]);
|
||||
const setSubtitlesOutlineColor = React.useCallback((color) => {
|
||||
props.dispatch({ propName: 'subtitlesOutlineColor', propValue: color });
|
||||
}, [props.dispatch]);
|
||||
const selectedTrack = props.subtitlesTracks.find(({ id }) => id === props.selectedSubtitlesTrackId);
|
||||
const groupedTracks = props.subtitlesTracks.reduce((result, track) => {
|
||||
result[track.origin] = result[track.origin] || {};
|
||||
result[track.origin][track.label] = result[track.origin][track.label] || [];
|
||||
result[track.origin][track.label].push(track);
|
||||
return result;
|
||||
}, {});
|
||||
return (
|
||||
<div className={classnames(props.className, styles['subtitles-picker-container'])}>
|
||||
<div className={styles['toggle-button-container']} onClick={toggleSubtitleEnabled}>
|
||||
<div className={styles['toggle-label']}>ON</div>
|
||||
<div className={styles['toggle-label']}>OFF</div>
|
||||
<div className={classnames(styles['toggle-thumb'], { [styles['on']]: !!selectedTrack })} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderLabelsList({ groupedTracks, selectedTrack }) {
|
||||
return (
|
||||
<div className={styles['labels-list-container']}>
|
||||
{
|
||||
Object.keys(groupedTracks)
|
||||
|
|
@ -150,13 +104,13 @@ class SubtitlesPicker extends React.Component {
|
|||
<div className={styles['track-origin']}>{origin}</div>
|
||||
{
|
||||
Object.keys(groupedTracks[origin])
|
||||
.sort(comparatorWithPriorities(this.props.languagePriorities))
|
||||
.sort(comparatorWithPriorities(LANGUAGE_PRIORITIES))
|
||||
.map((label) => {
|
||||
const selected = selectedTrack && selectedTrack.label === label && selectedTrack.origin === origin;
|
||||
return (
|
||||
<div key={label}
|
||||
className={classnames(styles['language-label'], { [styles['selected']]: selected })}
|
||||
onClick={this.labelOnClick}
|
||||
onClick={labelOnClick}
|
||||
data-label={label}
|
||||
data-origin={origin}
|
||||
children={label}
|
||||
|
|
@ -168,115 +122,83 @@ class SubtitlesPicker extends React.Component {
|
|||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderVariantsList({ groupedTracks, selectedTrack }) {
|
||||
if (groupedTracks[selectedTrack.origin][selectedTrack.label].length <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['variants-container']}>
|
||||
{
|
||||
groupedTracks[selectedTrack.origin][selectedTrack.label].map((track, index) => (
|
||||
<div key={track.id}
|
||||
className={classnames(styles['variant-button'], { [styles['selected']]: track.id === selectedTrack.id })}
|
||||
title={track.id}
|
||||
onClick={this.variantOnClick}
|
||||
data-track-id={track.id}
|
||||
children={index + 1}
|
||||
{
|
||||
!selectedTrack ?
|
||||
<div className={styles['preferences-container']}>
|
||||
<div className={styles['subtitles-disabled-label']}>Subtitles are disabled</div>
|
||||
</div>
|
||||
:
|
||||
<div className={styles['preferences-container']}>
|
||||
<div className={styles['preferences-title']}>Preferences</div>
|
||||
{
|
||||
groupedTracks[selectedTrack.origin][selectedTrack.label].length > 1 ?
|
||||
<div className={styles['variants-container']}>
|
||||
{
|
||||
groupedTracks[selectedTrack.origin][selectedTrack.label].map((track, index) => (
|
||||
<div key={track.id}
|
||||
className={classnames(styles['variant-button'], { [styles['selected']]: track.id === selectedTrack.id })}
|
||||
title={track.id}
|
||||
onClick={variantOnClick}
|
||||
data-track-id={track.id}
|
||||
children={index + 1}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
:
|
||||
null
|
||||
}
|
||||
<div className={styles['color-picker-button-container']}>
|
||||
<ColorInput
|
||||
className={styles['color-picker-indicator']}
|
||||
value={props.subtitlesTextColor}
|
||||
onChange={setSubtitlesTextColor}
|
||||
/>
|
||||
<div className={styles['color-picker-label']}>Text color</div>
|
||||
</div>
|
||||
{/* <SubtitlesColorPicker
|
||||
label={'Background color'}
|
||||
value={props.subtitlesBackgroundColor}
|
||||
onChange={setSubtitlesBackgroundColor}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderPreferences({ groupedTracks, selectedTrack }) {
|
||||
if (!selectedTrack) {
|
||||
return (
|
||||
<div className={styles['preferences-container']}>
|
||||
<div className={styles['subtitles-disabled-label']}>Subtitles are disabled</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['preferences-container']}>
|
||||
<div className={styles['preferences-title']}>Preferences</div>
|
||||
{this.renderVariantsList({ groupedTracks, selectedTrack })}
|
||||
<SubtitlesColorPicker
|
||||
label={'Text color'}
|
||||
value={this.props.subtitlesTextColor}
|
||||
onChange={this.setSubtitlesTextColor}
|
||||
/>
|
||||
<SubtitlesColorPicker
|
||||
label={'Background color'}
|
||||
value={this.props.subtitlesBackgroundColor}
|
||||
onChange={this.setSubtitlesBackgroundColor}
|
||||
/>
|
||||
<SubtitlesColorPicker
|
||||
label={'Outline color'}
|
||||
value={this.props.subtitlesOutlineColor}
|
||||
onChange={this.setSubtitlesOutlineColor}
|
||||
/>
|
||||
<NumberInput
|
||||
label={SUBTITLES_SIZE_LABELS[this.props.subtitlesSize]}
|
||||
value={this.props.subtitlesSize}
|
||||
delta={1}
|
||||
onChange={this.setsubtitlesSize}
|
||||
/>
|
||||
<NumberInput
|
||||
label={`${(this.props.subtitlesDelay / 1000).toFixed(2)}s`}
|
||||
value={this.props.subtitlesDelay}
|
||||
delta={100}
|
||||
onChange={this.setSubtitlesDelay}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const selectedTrack = this.props.subtitlesTracks.find(({ id }) => id === this.props.selectedSubtitlesTrackId);
|
||||
const groupedTracks = this.props.subtitlesTracks.reduce((result, track) => {
|
||||
result[track.origin] = result[track.origin] || {};
|
||||
result[track.origin][track.label] = result[track.origin][track.label] || [];
|
||||
result[track.origin][track.label].push(track);
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
return (
|
||||
<div className={classnames(this.props.className, styles['subtitles-picker-container'])}>
|
||||
{this.renderToggleButton({ selectedTrack })}
|
||||
{this.renderLabelsList({ groupedTracks, selectedTrack })}
|
||||
{this.renderPreferences({ groupedTracks, selectedTrack })}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
<SubtitlesColorPicker
|
||||
label={'Outline color'}
|
||||
value={props.subtitlesOutlineColor}
|
||||
onChange={setSubtitlesOutlineColor}
|
||||
/> */}
|
||||
<NumberInput
|
||||
label={SUBTITLES_SIZE_LABELS[props.subtitlesSize]}
|
||||
value={props.subtitlesSize}
|
||||
delta={1}
|
||||
onChange={setsubtitlesSize}
|
||||
/>
|
||||
<NumberInput
|
||||
label={`${(props.subtitlesDelay / 1000).toFixed(2)}s`}
|
||||
value={props.subtitlesDelay}
|
||||
delta={100}
|
||||
onChange={setSubtitlesDelay}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
SubtitlesPicker.propTypes = {
|
||||
className: PropTypes.string,
|
||||
languagePriorities: PropTypes.objectOf(PropTypes.number).isRequired,
|
||||
languagePriorities: PropTypes.objectOf(PropTypes.number),
|
||||
subtitlesTracks: PropTypes.arrayOf(PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
origin: PropTypes.string.isRequired
|
||||
})).isRequired,
|
||||
})),
|
||||
selectedSubtitlesTrackId: PropTypes.string,
|
||||
subtitlesSize: PropTypes.number,
|
||||
subtitlesDelay: PropTypes.number,
|
||||
subtitlesTextColor: PropTypes.string,
|
||||
subtitlesBackgroundColor: PropTypes.string,
|
||||
subtitlesOutlineColor: PropTypes.string,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
};
|
||||
SubtitlesPicker.defaultProps = {
|
||||
subtitlesTracks: Object.freeze([]),
|
||||
languagePriorities: Object.freeze({
|
||||
English: 1
|
||||
})
|
||||
dispatch: PropTypes.func
|
||||
};
|
||||
|
||||
module.exports = SubtitlesPicker;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
.subtitles-picker-container {
|
||||
width: calc(var(--subtitles-picker-button-size) * 14);
|
||||
height: calc(var(--subtitles-picker-button-size) * 9);
|
||||
--subtitles-picker-button-size: 2.5rem;
|
||||
font-size: calc(var(--subtitles-picker-button-size) * 0.45);
|
||||
padding: calc(var(--subtitles-picker-button-size) * 0.3);
|
||||
gap: calc(var(--subtitles-picker-button-size) * 0.3);
|
||||
|
|
|
|||
Loading…
Reference in a new issue