mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-04 10:02:40 +01:00
New: Swipe on Movie Details Page
This commit is contained in:
parent
a08648272c
commit
f37c7a9748
@ -202,7 +202,8 @@
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $breakpointLarge) {
|
||||
.poster {
|
||||
.poster,
|
||||
.movieNavigationButtons {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,20 @@ class MovieDetails extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('touchstart', this.onTouchStart);
|
||||
window.addEventListener('touchend', this.onTouchEnd);
|
||||
window.addEventListener('touchcancel', this.onTouchCancel);
|
||||
window.addEventListener('touchmove', this.onTouchMove);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('touchstart', this.onTouchStart);
|
||||
window.removeEventListener('touchend', this.onTouchEnd);
|
||||
window.removeEventListener('touchcancel', this.onTouchCancel);
|
||||
window.removeEventListener('touchmove', this.onTouchMove);
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
@ -156,6 +170,58 @@ class MovieDetails extends Component {
|
||||
this.setState({ titleWidth: width });
|
||||
}
|
||||
|
||||
onTouchStart = (event) => {
|
||||
const touches = event.touches;
|
||||
const touchStart = touches[0].pageX;
|
||||
const touchY = touches[0].pageY;
|
||||
|
||||
// Only change when swipe is on header, we need horizontal scroll on tables
|
||||
if (touchY > 470) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (touches.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
touchStart < 50 ||
|
||||
this.props.isSidebarVisible ||
|
||||
this.state.isEventModalOpen
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._touchStart = touchStart;
|
||||
}
|
||||
|
||||
onTouchEnd = (event) => {
|
||||
const touches = event.changedTouches;
|
||||
const currentTouch = touches[0].pageX;
|
||||
|
||||
if (!this._touchStart) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTouch > this._touchStart && currentTouch - this._touchStart > 100) {
|
||||
this.props.onGoToMovie(this.props.previousMovie.titleSlug);
|
||||
} else if (currentTouch < this._touchStart && this._touchStart - currentTouch > 100) {
|
||||
this.props.onGoToMovie(this.props.nextMovie.titleSlug);
|
||||
}
|
||||
|
||||
this._touchStart = null;
|
||||
}
|
||||
|
||||
onTouchCancel = (event) => {
|
||||
this._touchStart = null;
|
||||
}
|
||||
|
||||
onTouchMove = (event) => {
|
||||
if (!this._touchStart) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
@ -207,6 +273,8 @@ class MovieDetails extends Component {
|
||||
selectedTabIndex
|
||||
} = this.state;
|
||||
|
||||
const marqueeWidth = isSmallScreen ? titleWidth : (titleWidth - 150);
|
||||
|
||||
return (
|
||||
<PageContent title={title}>
|
||||
<PageToolbar>
|
||||
@ -293,7 +361,7 @@ class MovieDetails extends Component {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.title} style={{ width: (titleWidth - 150) }}>
|
||||
<div className={styles.title} style={{ width: marqueeWidth }}>
|
||||
<Marquee text={title} />
|
||||
</div>
|
||||
</div>
|
||||
@ -665,6 +733,7 @@ MovieDetails.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
isSmallScreen: PropTypes.bool.isRequired,
|
||||
isSidebarVisible: PropTypes.bool.isRequired,
|
||||
movieFilesError: PropTypes.object,
|
||||
movieCreditsError: PropTypes.object,
|
||||
extraFilesError: PropTypes.object,
|
||||
@ -673,7 +742,8 @@ MovieDetails.propTypes = {
|
||||
nextMovie: PropTypes.object.isRequired,
|
||||
onMonitorTogglePress: PropTypes.func.isRequired,
|
||||
onRefreshPress: PropTypes.func.isRequired,
|
||||
onSearchPress: PropTypes.func.isRequired
|
||||
onSearchPress: PropTypes.func.isRequired,
|
||||
onGoToMovie: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
MovieDetails.defaultProps = {
|
||||
|
@ -2,6 +2,7 @@ import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { push } from 'connected-react-router';
|
||||
import { createSelector } from 'reselect';
|
||||
import { findCommand, isCommandExecuting } from 'Utilities/Command';
|
||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||
@ -86,7 +87,8 @@ function createMapStateToProps() {
|
||||
createAllMoviesSelector(),
|
||||
createCommandsSelector(),
|
||||
createDimensionsSelector(),
|
||||
(titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions) => {
|
||||
(state) => state.app.isSidebarVisible,
|
||||
(titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions, isSidebarVisible) => {
|
||||
const sortedMovies = _.orderBy(allMovies, 'sortTitle');
|
||||
const movieIndex = _.findIndex(sortedMovies, { titleSlug });
|
||||
const movie = sortedMovies[movieIndex];
|
||||
@ -157,27 +159,59 @@ function createMapStateToProps() {
|
||||
sizeOnDisk,
|
||||
previousMovie,
|
||||
nextMovie,
|
||||
isSmallScreen: dimensions.isSmallScreen
|
||||
isSmallScreen: dimensions.isSmallScreen,
|
||||
isSidebarVisible
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchMovieFiles,
|
||||
clearMovieFiles,
|
||||
fetchMovieCredits,
|
||||
clearMovieCredits,
|
||||
fetchExtraFiles,
|
||||
clearExtraFiles,
|
||||
clearReleases,
|
||||
cancelFetchReleases,
|
||||
fetchNetImportSchema,
|
||||
toggleMovieMonitored,
|
||||
fetchQueueDetails,
|
||||
clearQueueDetails,
|
||||
executeCommand
|
||||
};
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
dispatchFetchMovieFiles({ movieId }) {
|
||||
dispatch(fetchMovieFiles({ movieId }));
|
||||
},
|
||||
dispatchClearMovieFiles() {
|
||||
dispatch(clearMovieFiles());
|
||||
},
|
||||
dispatchFetchMovieCredits({ movieId }) {
|
||||
dispatch(fetchMovieCredits({ movieId }));
|
||||
},
|
||||
dispatchClearMovieCredits() {
|
||||
dispatch(clearMovieCredits());
|
||||
},
|
||||
dispatchFetchExtraFiles({ movieId }) {
|
||||
dispatch(fetchExtraFiles({ movieId }));
|
||||
},
|
||||
dispatchClearExtraFiles() {
|
||||
dispatch(clearExtraFiles());
|
||||
},
|
||||
dispatchClearReleases() {
|
||||
dispatch(clearReleases());
|
||||
},
|
||||
dispatchCancelFetchReleases() {
|
||||
dispatch(cancelFetchReleases());
|
||||
},
|
||||
dispatchFetchQueueDetails({ movieId }) {
|
||||
dispatch(fetchQueueDetails({ movieId }));
|
||||
},
|
||||
dispatchClearQueueDetails() {
|
||||
dispatch(clearQueueDetails());
|
||||
},
|
||||
dispatchFetchNetImportSchema() {
|
||||
dispatch(fetchNetImportSchema());
|
||||
},
|
||||
dispatchToggleMovieMonitored(payload) {
|
||||
dispatch(toggleMovieMonitored(payload));
|
||||
},
|
||||
dispatchExecuteCommand(payload) {
|
||||
dispatch(executeCommand(payload));
|
||||
},
|
||||
onGoToMovie(titleSlug) {
|
||||
dispatch(push(`${window.Radarr.urlBase}/movie/${titleSlug}`));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class MovieDetailsConnector extends Component {
|
||||
|
||||
@ -227,41 +261,41 @@ class MovieDetailsConnector extends Component {
|
||||
populate = () => {
|
||||
const movieId = this.props.id;
|
||||
|
||||
this.props.fetchMovieFiles({ movieId });
|
||||
this.props.fetchExtraFiles({ movieId });
|
||||
this.props.fetchMovieCredits({ movieId });
|
||||
this.props.fetchQueueDetails({ movieId });
|
||||
this.props.fetchNetImportSchema();
|
||||
this.props.dispatchFetchMovieFiles({ movieId });
|
||||
this.props.dispatchFetchExtraFiles({ movieId });
|
||||
this.props.dispatchFetchMovieCredits({ movieId });
|
||||
this.props.dispatchFetchQueueDetails({ movieId });
|
||||
this.props.dispatchFetchNetImportSchema();
|
||||
}
|
||||
|
||||
unpopulate = () => {
|
||||
this.props.cancelFetchReleases();
|
||||
this.props.clearMovieFiles();
|
||||
this.props.clearExtraFiles();
|
||||
this.props.clearMovieCredits();
|
||||
this.props.clearQueueDetails();
|
||||
this.props.clearReleases();
|
||||
this.props.dispatchCancelFetchReleases();
|
||||
this.props.dispatchClearMovieFiles();
|
||||
this.props.dispatchClearExtraFiles();
|
||||
this.props.dispatchClearMovieCredits();
|
||||
this.props.dispatchClearQueueDetails();
|
||||
this.props.dispatchClearReleases();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onMonitorTogglePress = (monitored) => {
|
||||
this.props.toggleMovieMonitored({
|
||||
this.props.dispatchToggleMovieMonitored({
|
||||
movieId: this.props.id,
|
||||
monitored
|
||||
});
|
||||
}
|
||||
|
||||
onRefreshPress = () => {
|
||||
this.props.executeCommand({
|
||||
this.props.dispatchExecuteCommand({
|
||||
name: commandNames.REFRESH_MOVIE,
|
||||
movieId: this.props.id
|
||||
});
|
||||
}
|
||||
|
||||
onSearchPress = () => {
|
||||
this.props.executeCommand({
|
||||
this.props.dispatchExecuteCommand({
|
||||
name: commandNames.MOVIE_SEARCH,
|
||||
movieIds: [this.props.id]
|
||||
});
|
||||
@ -291,19 +325,20 @@ MovieDetailsConnector.propTypes = {
|
||||
isRenamingFiles: PropTypes.bool.isRequired,
|
||||
isRenamingMovie: PropTypes.bool.isRequired,
|
||||
isSmallScreen: PropTypes.bool.isRequired,
|
||||
fetchMovieFiles: PropTypes.func.isRequired,
|
||||
clearMovieFiles: PropTypes.func.isRequired,
|
||||
fetchExtraFiles: PropTypes.func.isRequired,
|
||||
clearExtraFiles: PropTypes.func.isRequired,
|
||||
fetchMovieCredits: PropTypes.func.isRequired,
|
||||
clearMovieCredits: PropTypes.func.isRequired,
|
||||
clearReleases: PropTypes.func.isRequired,
|
||||
cancelFetchReleases: PropTypes.func.isRequired,
|
||||
toggleMovieMonitored: PropTypes.func.isRequired,
|
||||
fetchQueueDetails: PropTypes.func.isRequired,
|
||||
clearQueueDetails: PropTypes.func.isRequired,
|
||||
fetchNetImportSchema: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired
|
||||
dispatchFetchMovieFiles: PropTypes.func.isRequired,
|
||||
dispatchClearMovieFiles: PropTypes.func.isRequired,
|
||||
dispatchFetchExtraFiles: PropTypes.func.isRequired,
|
||||
dispatchClearExtraFiles: PropTypes.func.isRequired,
|
||||
dispatchFetchMovieCredits: PropTypes.func.isRequired,
|
||||
dispatchClearMovieCredits: PropTypes.func.isRequired,
|
||||
dispatchClearReleases: PropTypes.func.isRequired,
|
||||
dispatchCancelFetchReleases: PropTypes.func.isRequired,
|
||||
dispatchToggleMovieMonitored: PropTypes.func.isRequired,
|
||||
dispatchFetchQueueDetails: PropTypes.func.isRequired,
|
||||
dispatchClearQueueDetails: PropTypes.func.isRequired,
|
||||
dispatchFetchNetImportSchema: PropTypes.func.isRequired,
|
||||
dispatchExecuteCommand: PropTypes.func.isRequired,
|
||||
onGoToMovie: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(MovieDetailsConnector);
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(MovieDetailsConnector);
|
||||
|
Loading…
Reference in New Issue
Block a user