subtitles picker adapted to latest changes in common

This commit is contained in:
NikolaBorislavovHristov 2019-10-05 12:27:28 +03:00
parent ae4bfda554
commit 671873aeb3
2 changed files with 109 additions and 188 deletions

View file

@ -3,13 +3,16 @@ const PropTypes = require('prop-types');
const classnames = require('classnames'); const classnames = require('classnames');
const Icon = require('stremio-icons/dom'); const Icon = require('stremio-icons/dom');
const { Modal } = require('stremio-router'); const { Modal } = require('stremio-router');
const { ColorPicker } = require('stremio/common'); const { ColorInput } = require('stremio/common');
const styles = require('./styles'); const styles = require('./styles');
const ORIGIN_PRIORITIES = Object.freeze({ const ORIGIN_PRIORITIES = Object.freeze({
'LOCAL': 1, 'LOCAL': 1,
'EMBEDDED': 2 'EMBEDDED': 2
}); });
const LANGUAGE_PRIORITIES = Object.freeze({
'English': 1
});
const SUBTITLES_SIZE_LABELS = Object.freeze({ const SUBTITLES_SIZE_LABELS = Object.freeze({
1: '75%', 1: '75%',
2: '100%', 2: '100%',
@ -27,13 +30,9 @@ const comparatorWithPriorities = (priorities) => {
if (!isNaN(valueB)) return 1; if (!isNaN(valueB)) return 1;
return a - b; return a - b;
}; };
} };
const NumberInput = ({ value, label, delta, onChange }) => { const NumberInput = ({ value, label, delta, onChange }) => {
if (value === null) {
return null;
}
return ( return (
<div className={styles['number-input-container']}> <div className={styles['number-input-container']}>
<div className={styles['number-input-button']} data-value={value - delta} onClick={onChange}> <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 SubtitlesPicker = (props) => {
const [open, setOpen] = React.useState(false); const toggleSubtitleEnabled = React.useCallback(() => {
const onOpen = () => setOpen(true); const selectedSubtitlesTrackId = props.selectedSubtitlesTrackId === null && props.subtitlesTracks.length > 0 ?
const onClose = () => setOpen(false); props.subtitlesTracks[0].id
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
: :
null; null;
this.props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: selectedSubtitlesTrackId }); props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: selectedSubtitlesTrackId });
} }, [props.selectedSubtitlesTrackId, props.subtitlesTracks, props.dispatch]);
const labelOnClick = React.useCallback((event) => {
labelOnClick = (event) => { const subtitleTrack = props.subtitlesTracks.find(({ label, origin }) => {
const subtitleTrack = this.props.subtitlesTracks.find(({ label, origin }) => {
return label === event.currentTarget.dataset.label && return label === event.currentTarget.dataset.label &&
origin === event.currentTarget.dataset.origin; origin === event.currentTarget.dataset.origin;
}); });
if (subtitleTrack) { if (subtitleTrack) {
this.props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: subtitleTrack.id }); props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: subtitleTrack.id });
} }
} }, [props.subtitlesTracks, props.dispatch]);
const variantOnClick = React.useCallback((event) => {
variantOnClick = (event) => { props.dispatch({ propName: 'selectedSubtitlesTrackId', propValue: event.currentTarget.dataset.trackId });
this.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 });
setsubtitlesSize = (event) => { }, [props.dispatch]);
this.props.dispatch({ propName: 'subtitlesSize', propValue: event.currentTarget.dataset.value }); const setSubtitlesDelay = React.useCallback((event) => {
} props.dispatch({ propName: 'subtitlesDelay', propValue: event.currentTarget.dataset.value });
}, [props.dispatch]);
setSubtitlesDelay = (event) => { const setSubtitlesTextColor = React.useCallback((event) => {
this.props.dispatch({ propName: 'subtitlesDelay', propValue: event.currentTarget.dataset.value }); props.dispatch({ propName: 'subtitlesTextColor', propValue: event.nativeEvent.value });
} }, [props.dispatch]);
const setSubtitlesBackgroundColor = React.useCallback((color) => {
setSubtitlesTextColor = (color) => { props.dispatch({ propName: 'subtitlesBackgroundColor', propValue: color });
this.props.dispatch({ propName: 'subtitlesTextColor', propValue: color }); }, [props.dispatch]);
} const setSubtitlesOutlineColor = React.useCallback((color) => {
props.dispatch({ propName: 'subtitlesOutlineColor', propValue: color });
setSubtitlesBackgroundColor = (color) => { }, [props.dispatch]);
this.props.dispatch({ propName: 'subtitlesBackgroundColor', propValue: color }); const selectedTrack = props.subtitlesTracks.find(({ id }) => id === props.selectedSubtitlesTrackId);
} const groupedTracks = props.subtitlesTracks.reduce((result, track) => {
result[track.origin] = result[track.origin] || {};
setSubtitlesOutlineColor = (color) => { result[track.origin][track.label] = result[track.origin][track.label] || [];
this.props.dispatch({ propName: 'subtitlesOutlineColor', propValue: color }); result[track.origin][track.label].push(track);
} return result;
}, {});
renderToggleButton({ selectedTrack }) { return (
return ( <div className={classnames(props.className, styles['subtitles-picker-container'])}>
<div className={styles['toggle-button-container']} onClick={this.toggleSubtitleEnabled}> <div className={styles['toggle-button-container']} onClick={toggleSubtitleEnabled}>
<div className={styles['toggle-label']}>ON</div> <div className={styles['toggle-label']}>ON</div>
<div className={styles['toggle-label']}>OFF</div> <div className={styles['toggle-label']}>OFF</div>
<div className={classnames(styles['toggle-thumb'], { [styles['on']]: !!selectedTrack })} /> <div className={classnames(styles['toggle-thumb'], { [styles['on']]: !!selectedTrack })} />
</div> </div>
);
}
renderLabelsList({ groupedTracks, selectedTrack }) {
return (
<div className={styles['labels-list-container']}> <div className={styles['labels-list-container']}>
{ {
Object.keys(groupedTracks) Object.keys(groupedTracks)
@ -150,13 +104,13 @@ class SubtitlesPicker extends React.Component {
<div className={styles['track-origin']}>{origin}</div> <div className={styles['track-origin']}>{origin}</div>
{ {
Object.keys(groupedTracks[origin]) Object.keys(groupedTracks[origin])
.sort(comparatorWithPriorities(this.props.languagePriorities)) .sort(comparatorWithPriorities(LANGUAGE_PRIORITIES))
.map((label) => { .map((label) => {
const selected = selectedTrack && selectedTrack.label === label && selectedTrack.origin === origin; const selected = selectedTrack && selectedTrack.label === label && selectedTrack.origin === origin;
return ( return (
<div key={label} <div key={label}
className={classnames(styles['language-label'], { [styles['selected']]: selected })} className={classnames(styles['language-label'], { [styles['selected']]: selected })}
onClick={this.labelOnClick} onClick={labelOnClick}
data-label={label} data-label={label}
data-origin={origin} data-origin={origin}
children={label} children={label}
@ -168,115 +122,83 @@ class SubtitlesPicker extends React.Component {
)) ))
} }
</div> </div>
); {
} !selectedTrack ?
<div className={styles['preferences-container']}>
renderVariantsList({ groupedTracks, selectedTrack }) { <div className={styles['subtitles-disabled-label']}>Subtitles are disabled</div>
if (groupedTracks[selectedTrack.origin][selectedTrack.label].length <= 1) { </div>
return null; :
} <div className={styles['preferences-container']}>
<div className={styles['preferences-title']}>Preferences</div>
return ( {
<div className={styles['variants-container']}> groupedTracks[selectedTrack.origin][selectedTrack.label].length > 1 ?
{ <div className={styles['variants-container']}>
groupedTracks[selectedTrack.origin][selectedTrack.label].map((track, index) => ( {
<div key={track.id} groupedTracks[selectedTrack.origin][selectedTrack.label].map((track, index) => (
className={classnames(styles['variant-button'], { [styles['selected']]: track.id === selectedTrack.id })} <div key={track.id}
title={track.id} className={classnames(styles['variant-button'], { [styles['selected']]: track.id === selectedTrack.id })}
onClick={this.variantOnClick} title={track.id}
data-track-id={track.id} onClick={variantOnClick}
children={index + 1} 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}
/> />
)) <SubtitlesColorPicker
} label={'Outline color'}
</div> value={props.subtitlesOutlineColor}
); onChange={setSubtitlesOutlineColor}
} /> */}
<NumberInput
renderPreferences({ groupedTracks, selectedTrack }) { label={SUBTITLES_SIZE_LABELS[props.subtitlesSize]}
if (!selectedTrack) { value={props.subtitlesSize}
return ( delta={1}
<div className={styles['preferences-container']}> onChange={setsubtitlesSize}
<div className={styles['subtitles-disabled-label']}>Subtitles are disabled</div> />
</div> <NumberInput
); label={`${(props.subtitlesDelay / 1000).toFixed(2)}s`}
} value={props.subtitlesDelay}
delta={100}
return ( onChange={setSubtitlesDelay}
<div className={styles['preferences-container']}> />
<div className={styles['preferences-title']}>Preferences</div> </div>
{this.renderVariantsList({ groupedTracks, selectedTrack })} }
<SubtitlesColorPicker </div>
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>
);
}
}
SubtitlesPicker.propTypes = { SubtitlesPicker.propTypes = {
className: PropTypes.string, className: PropTypes.string,
languagePriorities: PropTypes.objectOf(PropTypes.number).isRequired, languagePriorities: PropTypes.objectOf(PropTypes.number),
subtitlesTracks: PropTypes.arrayOf(PropTypes.shape({ subtitlesTracks: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
origin: PropTypes.string.isRequired origin: PropTypes.string.isRequired
})).isRequired, })),
selectedSubtitlesTrackId: PropTypes.string, selectedSubtitlesTrackId: PropTypes.string,
subtitlesSize: PropTypes.number, subtitlesSize: PropTypes.number,
subtitlesDelay: PropTypes.number, subtitlesDelay: PropTypes.number,
subtitlesTextColor: PropTypes.string, subtitlesTextColor: PropTypes.string,
subtitlesBackgroundColor: PropTypes.string, subtitlesBackgroundColor: PropTypes.string,
subtitlesOutlineColor: PropTypes.string, subtitlesOutlineColor: PropTypes.string,
dispatch: PropTypes.func.isRequired dispatch: PropTypes.func
};
SubtitlesPicker.defaultProps = {
subtitlesTracks: Object.freeze([]),
languagePriorities: Object.freeze({
English: 1
})
}; };
module.exports = SubtitlesPicker; module.exports = SubtitlesPicker;

View file

@ -1,6 +1,5 @@
.subtitles-picker-container { .subtitles-picker-container {
width: calc(var(--subtitles-picker-button-size) * 14); --subtitles-picker-button-size: 2.5rem;
height: calc(var(--subtitles-picker-button-size) * 9);
font-size: calc(var(--subtitles-picker-button-size) * 0.45); font-size: calc(var(--subtitles-picker-button-size) * 0.45);
padding: calc(var(--subtitles-picker-button-size) * 0.3); padding: calc(var(--subtitles-picker-button-size) * 0.3);
gap: calc(var(--subtitles-picker-button-size) * 0.3); gap: calc(var(--subtitles-picker-button-size) * 0.3);