Fixed Movie Details Tweaks

Fixes #4124
pull/2/head
Qstick 5 years ago
parent b7cf6f49d0
commit f073f0c35c

@ -0,0 +1,179 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
const FPS = 20;
const STEP = 1;
const TIMEOUT = 1 / FPS * 1000;
class Marquee extends Component {
static propTypes = {
text: PropTypes.string,
hoverToStop: PropTypes.bool,
loop: PropTypes.bool,
className: PropTypes.string
};
static defaultProps = {
text: '',
hoverToStop: true,
loop: false
};
state = {
animatedWidth: 0,
overflowWidth: 0,
direction: 0
};
componentDidMount() {
this.measureText();
if (this.props.hoverToStop) {
this.startAnimation();
}
}
componentWillReceiveProps(nextProps) {
if (this.props.text.length !== nextProps.text.length) {
clearTimeout(this.marqueeTimer);
this.setState({ animatedWidth: 0, direction: 0 });
}
}
componentDidUpdate() {
this.measureText();
if (this.props.hoverToStop) {
this.startAnimation();
}
}
componentWillUnmount() {
clearTimeout(this.marqueeTimer);
}
onHandleMouseEnter = () => {
if (this.props.hoverToStop) {
clearTimeout(this.marqueeTimer);
} else if (this.state.overflowWidth > 0) {
this.startAnimation();
}
}
onHandleMouseLeave = () => {
if (this.props.hoverToStop && this.state.overflowWidth > 0) {
this.startAnimation();
} else {
clearTimeout(this.marqueeTimer);
this.setState({ animatedWidth: 0 });
}
}
startAnimation = () => {
clearTimeout(this.marqueeTimer);
const isLeading = this.state.animatedWidth === 0;
const timeout = isLeading ? 0 : TIMEOUT;
const animate = () => {
const { overflowWidth } = this.state;
let animatedWidth = this.state.animatedWidth;
let direction = this.state.direction;
if (direction === 0) {
animatedWidth = this.state.animatedWidth + STEP;
} else {
animatedWidth = this.state.animatedWidth - STEP;
}
const isRoundOver = animatedWidth < 0;
const endOfText = animatedWidth > overflowWidth;
if (endOfText) {
direction = direction === 1;
}
if (isRoundOver) {
if (this.props.loop) {
direction = direction === 0;
} else {
return;
}
}
this.setState({ animatedWidth, direction });
this.marqueeTimer = setTimeout(animate, TIMEOUT);
};
this.marqueeTimer = setTimeout(animate, timeout);
}
measureText = () => {
const container = this.container;
const node = this.text;
if (container && node) {
const containerWidth = container.offsetWidth;
const textWidth = node.offsetWidth;
const overflowWidth = textWidth - containerWidth;
if (overflowWidth !== this.state.overflowWidth) {
this.setState({ overflowWidth });
}
}
}
render() {
const style = {
position: 'relative',
right: this.state.animatedWidth,
whiteSpace: 'nowrap'
};
if (this.state.overflowWidth < 0) {
return (
<div
ref={(el) => {
this.container = el;
}}
className={`ui-marquee ${this.props.className}`}
style={{ overflow: 'hidden' }}
>
<span
ref={(el) => {
this.text = el;
}}
style={style}
title={this.props.text}
>
{this.props.text}
</span>
</div>
);
}
return (
<div
ref={(el) => {
this.container = el;
}}
className={`ui-marquee ${this.props.className}`.trim()}
style={{ overflow: 'hidden' }}
onMouseEnter={this.onHandleMouseEnter}
onMouseLeave={this.onHandleMouseLeave}
>
<span
ref={(el) => {
this.text = el;
}}
style={style}
title={this.props.text}
>
{this.props.text}
</span>
</div>
);
}
}
export default Marquee;

@ -66,7 +66,7 @@
.title { .title {
font-weight: 300; font-weight: 300;
font-size: 50px; font-size: 50px;
line-height: 50px; line-height: 60px;
} }
.toggleMonitoredContainer { .toggleMonitoredContainer {
@ -112,6 +112,7 @@
.details { .details {
margin-bottom: 8px; margin-bottom: 8px;
padding-left: 7px;
font-weight: 300; font-weight: 300;
font-size: 20px; font-size: 20px;
} }
@ -121,7 +122,7 @@
.rating, .rating,
.year, .year,
.runtime { .runtime {
margin-right: 15px; margin-right: 14px;
} }
.certification { .certification {
@ -156,6 +157,7 @@
.overview { .overview {
flex: 1 0 auto; flex: 1 0 auto;
margin-top: 8px; margin-top: 8px;
padding-left: 7px;
min-height: 0; min-height: 0;
font-size: $intermediateFontSize; font-size: $intermediateFontSize;
} }

@ -12,6 +12,7 @@ import HeartRating from 'Components/HeartRating';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import IconButton from 'Components/Link/IconButton'; import IconButton from 'Components/Link/IconButton';
import InfoLabel from 'Components/InfoLabel'; import InfoLabel from 'Components/InfoLabel';
import Marquee from 'Components/Marquee';
import MovieStatusLabel from './MovieStatusLabel'; import MovieStatusLabel from './MovieStatusLabel';
import Measure from 'Components/Measure'; import Measure from 'Components/Measure';
import MonitorToggleButton from 'Components/MonitorToggleButton'; import MonitorToggleButton from 'Components/MonitorToggleButton';
@ -35,7 +36,6 @@ import MovieHistoryTable from 'Movie/History/MovieHistoryTable';
import MovieTitlesTable from './Titles/MovieTitlesTable'; import MovieTitlesTable from './Titles/MovieTitlesTable';
import MovieCastPostersConnector from './Credits/Cast/MovieCastPostersConnector'; import MovieCastPostersConnector from './Credits/Cast/MovieCastPostersConnector';
import MovieCrewPostersConnector from './Credits/Crew/MovieCrewPostersConnector'; import MovieCrewPostersConnector from './Credits/Crew/MovieCrewPostersConnector';
import MovieAlternateTitles from './MovieAlternateTitles';
import MovieDetailsLinks from './MovieDetailsLinks'; import MovieDetailsLinks from './MovieDetailsLinks';
import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable'; import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable';
import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveSearchFilterMenuConnector'; import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveSearchFilterMenuConnector';
@ -78,7 +78,8 @@ class MovieDetails extends Component {
allCollapsed: false, allCollapsed: false,
expandedState: {}, expandedState: {},
selectedTabIndex: 0, selectedTabIndex: 0,
overviewHeight: 0 overviewHeight: 0,
titleWidth: 0
}; };
} }
@ -151,6 +152,10 @@ class MovieDetails extends Component {
this.setState({ overviewHeight: height }); this.setState({ overviewHeight: height });
} }
onTitleMeasure = ({ width }) => {
this.setState({ titleWidth: width });
}
// //
// Render // Render
@ -174,7 +179,6 @@ class MovieDetails extends Component {
youTubeTrailerId, youTubeTrailerId,
inCinemas, inCinemas,
images, images,
alternateTitles,
tags, tags,
isSaving, isSaving,
isRefreshing, isRefreshing,
@ -199,6 +203,7 @@ class MovieDetails extends Component {
isDeleteMovieModalOpen, isDeleteMovieModalOpen,
isInteractiveImportModalOpen, isInteractiveImportModalOpen,
overviewHeight, overviewHeight,
titleWidth,
selectedTabIndex selectedTabIndex
} = this.state; } = this.state;
@ -275,41 +280,43 @@ class MovieDetails extends Component {
/> />
<div className={styles.info}> <div className={styles.info}>
<div className={styles.titleRow}> <Measure onMeasure={this.onTitleMeasure}>
<div className={styles.titleContainer}> <div className={styles.titleRow}>
<div className={styles.toggleMonitoredContainer}> <div className={styles.titleContainer}>
<MonitorToggleButton <div className={styles.toggleMonitoredContainer}>
className={styles.monitorToggleButton} <MonitorToggleButton
monitored={monitored} className={styles.monitorToggleButton}
isSaving={isSaving} monitored={monitored}
size={40} isSaving={isSaving}
onPress={onMonitorTogglePress} size={40}
/> onPress={onMonitorTogglePress}
</div> />
</div>
<div className={styles.title}> <div className={styles.title} style={{ width: (titleWidth - 150) }}>
{title} <Marquee text={title} />
</div>
</div> </div>
</div>
<div className={styles.movieNavigationButtons}> <div className={styles.movieNavigationButtons}>
<IconButton <IconButton
className={styles.movieNavigationButton} className={styles.movieNavigationButton}
name={icons.ARROW_LEFT} name={icons.ARROW_LEFT}
size={30} size={30}
title={`Go to ${previousMovie.title}`} title={`Go to ${previousMovie.title}`}
to={`/movie/${previousMovie.titleSlug}`} to={`/movie/${previousMovie.titleSlug}`}
/> />
<IconButton <IconButton
className={styles.movieNavigationButton} className={styles.movieNavigationButton}
name={icons.ARROW_RIGHT} name={icons.ARROW_RIGHT}
size={30} size={30}
title={`Go to ${nextMovie.title}`} title={`Go to ${nextMovie.title}`}
to={`/movie/${nextMovie.titleSlug}`} to={`/movie/${nextMovie.titleSlug}`}
/> />
</div>
</div> </div>
</div> </Measure>
<div className={styles.details}> <div className={styles.details}>
<div> <div>
@ -453,7 +460,7 @@ class MovieDetails extends Component {
} }
{ {
!!studio && !!studio && !isSmallScreen &&
<InfoLabel <InfoLabel
className={styles.detailsInfoLabel} className={styles.detailsInfoLabel}
title="Studio" title="Studio"

Loading…
Cancel
Save