1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-20 01:42:35 +01:00

New: Improve status label and progress bar style for deleted movies

Closes #7127
This commit is contained in:
Bogdan 2024-08-15 23:34:56 +03:00
parent fa1d6ad109
commit 9ad6b3a611
19 changed files with 146 additions and 75 deletions

View File

@ -285,6 +285,7 @@ class AddNewMovieSearchResult extends Component {
{
isExistingMovie && isSmallScreen &&
<MovieStatusLabel
status={status}
hasMovieFiles={hasMovieFile}
monitored={monitored}
isAvailable={isAvailable}

View File

@ -3,10 +3,10 @@ import moment from 'moment';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import CalendarEventQueueDetails from 'Calendar/Events/CalendarEventQueueDetails';
import getStatusStyle from 'Calendar/getStatusStyle';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import { icons, kinds } from 'Helpers/Props';
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
import translate from 'Utilities/String/translate';
import styles from './AgendaEvent.css';
@ -82,7 +82,7 @@ class AgendaEvent extends Component {
startTime = moment(startTime);
const downloading = !!(queueItem || grabbed);
const isMonitored = monitored;
const statusStyle = getStatusStyle(null, isMonitored, hasFile, isAvailable, 'style', downloading);
const statusStyle = getStatusStyle(hasFile, downloading, isMonitored, isAvailable);
const joinedGenres = genres.slice(0, 2).join(', ');
const link = `/movie/${titleSlug}`;

View File

@ -2,10 +2,10 @@ import classNames from 'classnames';
import moment from 'moment';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import getStatusStyle from 'Calendar/getStatusStyle';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import { icons, kinds } from 'Helpers/Props';
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
import translate from 'Utilities/String/translate';
import CalendarEventQueueDetails from './CalendarEventQueueDetails';
import styles from './CalendarEvent.css';
@ -39,7 +39,7 @@ class CalendarEvent extends Component {
const isDownloading = !!(queueItem || grabbed);
const isMonitored = monitored;
const statusStyle = getStatusStyle(null, isMonitored, hasFile, isAvailable, 'style', isDownloading);
const statusStyle = getStatusStyle(hasFile, isDownloading, isMonitored, isAvailable);
const joinedGenres = genres.slice(0, 2).join(', ');
const link = `/movie/${titleSlug}`;
const eventType = [];

View File

@ -0,0 +1,25 @@
function getStatusStyle(hasFile, downloading, isMonitored, isAvailable) {
if (downloading) {
return 'queue';
}
if (hasFile && isMonitored) {
return 'downloaded';
}
if (hasFile && !isMonitored) {
return 'unmonitored';
}
if (isAvailable && isMonitored) {
return 'missingMonitored';
}
if (!isMonitored) {
return 'missingUnmonitored';
}
return 'continuing';
}
export default getStatusStyle;

View File

@ -2,7 +2,7 @@ import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
import getProgressBarKind from 'Utilities/Movie/getProgressBarKind';
import translate from 'Utilities/String/translate';
import styles from './CollectionMovieLabel.css';
@ -45,7 +45,7 @@ class CollectionMovieLabel extends Component {
<div
className={classNames(
styles.movieStatus,
styles[getStatusStyle(status, monitored, hasFile, isAvailable, 'kinds')]
styles[getProgressBarKind(status, monitored, hasFile, isAvailable)]
)}
>
{

View File

@ -8,7 +8,7 @@
cursor: default;
}
.title {
.name {
margin-bottom: 2px;
color: var(--helpTextColor);
font-size: 10px;

View File

@ -4,9 +4,9 @@ interface CssExports {
'label': string;
'large': string;
'medium': string;
'name': string;
'outline': string;
'small': string;
'title': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@ -7,7 +7,7 @@ import styles from './InfoLabel.css';
function InfoLabel(props) {
const {
className,
title,
name,
kind,
size,
outline,
@ -25,8 +25,8 @@ function InfoLabel(props) {
)}
{...otherProps}
>
<div className={styles.title}>
{title}
<div className={styles.name}>
{name}
</div>
<div>
{children}
@ -37,7 +37,7 @@ function InfoLabel(props) {
InfoLabel.propTypes = {
className: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
kind: PropTypes.oneOf(kinds.all).isRequired,
size: PropTypes.oneOf(sizes.all).isRequired,
outline: PropTypes.bool.isRequired,

View File

@ -21,6 +21,10 @@
background-color: var(--darkGray);
}
&.inverse {
background-color: var(--inverseLabelColor);
}
&.primary {
background-color: var(--primaryColor);
}
@ -61,10 +65,18 @@
.frontTextContainer {
z-index: 1;
color: var(--progressBarFrontTextColor);
&.inverse {
color: var(--inverseLabelTextColor);
}
}
.backTextContainer {
color: var(--progressBarBackTextColor);
&.inverse {
color: var(--inverseLabelTextColor);
}
}
.backTextContainer,

View File

@ -9,6 +9,7 @@ interface CssExports {
'frontText': string;
'frontTextContainer': string;
'info': string;
'inverse': string;
'large': string;
'medium': string;
'primary': string;

View File

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
import { kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './ProgressBar.css';
function ProgressBar(props) {
@ -57,7 +58,7 @@ function ProgressBar(props) {
enableColorImpairedMode && 'colorImpaired'
)}
role="meter"
aria-label={`Progress Bar at ${progress.toFixed(0)}%`}
aria-label={translate('ProgressBarProgress', { progress: progress.toFixed(0) })}
aria-valuenow={progress.toFixed(0)}
aria-valuemin="0"
aria-valuemax="100"

View File

@ -24,6 +24,7 @@ import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import DeleteMovieModal from 'Movie/Delete/DeleteMovieModal';
import EditMovieModalConnector from 'Movie/Edit/EditMovieModalConnector';
import getMovieStatusDetails from 'Movie/getMovieStatusDetails';
import MovieHistoryModal from 'Movie/History/MovieHistoryModal';
import MoviePoster from 'Movie/MoviePoster';
import MovieInteractiveSearchModalConnector from 'Movie/Search/MovieInteractiveSearchModalConnector';
@ -246,6 +247,7 @@ class MovieDetails extends Component {
genres,
collection,
overview,
status,
youTubeTrailerId,
isAvailable,
images,
@ -283,6 +285,8 @@ class MovieDetails extends Component {
titleWidth
} = this.state;
const statusDetails = getMovieStatusDetails(status);
const fanartUrl = getFanartUrl(images);
const marqueeWidth = isSmallScreen ? titleWidth : (titleWidth - 150);
@ -524,7 +528,7 @@ class MovieDetails extends Component {
<div className={styles.detailsLabels}>
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('Path')}
name={translate('Path')}
size={sizes.LARGE}
>
<span className={styles.path}>
@ -534,12 +538,14 @@ class MovieDetails extends Component {
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('Status')}
name={translate('Status')}
title={statusDetails.message}
kind={kinds.DELETE}
size={sizes.LARGE}
>
<span className={styles.statusName}>
<MovieStatusLabel
status={status}
hasMovieFiles={hasMovieFiles}
monitored={monitored}
isAvailable={isAvailable}
@ -550,7 +556,7 @@ class MovieDetails extends Component {
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('QualityProfile')}
name={translate('QualityProfile')}
size={sizes.LARGE}
>
<span className={styles.qualityProfileName}>
@ -564,7 +570,7 @@ class MovieDetails extends Component {
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('Size')}
name={translate('Size')}
size={sizes.LARGE}
>
<span className={styles.sizeOnDisk}>
@ -576,7 +582,7 @@ class MovieDetails extends Component {
collection ?
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('Collection')}
name={translate('Collection')}
size={sizes.LARGE}
>
<div className={styles.collection}>
@ -592,7 +598,7 @@ class MovieDetails extends Component {
originalLanguage?.name && !isSmallScreen ?
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('OriginalLanguage')}
name={translate('OriginalLanguage')}
size={sizes.LARGE}
>
<span className={styles.originalLanguage}>
@ -606,7 +612,7 @@ class MovieDetails extends Component {
studio && !isSmallScreen ?
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('Studio')}
name={translate('Studio')}
size={sizes.LARGE}
>
<span className={styles.studio}>
@ -620,7 +626,7 @@ class MovieDetails extends Component {
genres.length && !isSmallScreen ?
<InfoLabel
className={styles.detailsInfoLabel}
title={translate('Genres')}
name={translate('Genres')}
size={sizes.LARGE}
>
<span className={styles.genres}>

View File

@ -27,3 +27,9 @@
padding-left: 2px;
border-left: 4px solid var(--warningColor);
}
.deleted {
padding-left: 2px;
border-left: 4px solid var(--inverseLabelColor);
color: var(--dangerColor);
}

View File

@ -3,6 +3,7 @@
interface CssExports {
'availNotMonitored': string;
'continuing': string;
'deleted': string;
'ended': string;
'missingMonitored': string;
'missingUnmonitored': string;

View File

@ -7,7 +7,7 @@ import firstCharToUpper from 'Utilities/String/firstCharToUpper';
import translate from 'Utilities/String/translate';
import styles from './MovieStatusLabel.css';
function getMovieStatus(hasFile, isMonitored, isAvailable, queueItem = false) {
function getMovieStatus(status, hasFile, isMonitored, isAvailable, queueItem = false) {
if (queueItem) {
const queueStatus = queueItem.status;
const queueState = queueItem.trackedDownloadStatus;
@ -26,6 +26,10 @@ function getMovieStatus(hasFile, isMonitored, isAvailable, queueItem = false) {
return 'ended';
}
if (status === 'deleted') {
return 'deleted';
}
if (isAvailable && !isMonitored && !hasFile) {
return 'missingUnmonitored';
}
@ -39,6 +43,7 @@ function getMovieStatus(hasFile, isMonitored, isAvailable, queueItem = false) {
function MovieStatusLabel(props) {
const {
status,
hasMovieFiles,
monitored,
isAvailable,
@ -47,17 +52,15 @@ function MovieStatusLabel(props) {
colorImpairedMode
} = props;
let status = getMovieStatus(hasMovieFiles, monitored, isAvailable, queueItem);
let statusClass = status;
let movieStatus = getMovieStatus(status, hasMovieFiles, monitored, isAvailable, queueItem);
let statusClass = movieStatus;
if (status === 'availNotMonitored' || status === 'ended') {
status = 'downloaded';
}
if (status === 'missingMonitored' || status === 'missingUnmonitored') {
status = 'missing';
}
if (status === 'continuing') {
status = 'notAvailable';
if (movieStatus === 'availNotMonitored' || movieStatus === 'ended') {
movieStatus = 'downloaded';
} else if (movieStatus === 'missingMonitored' || movieStatus === 'missingUnmonitored') {
movieStatus = 'missing';
} else if (movieStatus === 'continuing') {
movieStatus = 'notAvailable';
}
if (queueItem) {
@ -83,6 +86,9 @@ function MovieStatusLabel(props) {
case 'missingUnmonitored':
kind = kinds.WARNING;
break;
case 'deleted':
kind = kinds.INVERSE;
break;
default:
}
@ -92,7 +98,7 @@ function MovieStatusLabel(props) {
size={sizes.LARGE}
colorImpairedMode={colorImpairedMode}
>
{translate(firstCharToUpper(status))}
{translate(firstCharToUpper(movieStatus))}
</Label>
);
}
@ -101,12 +107,13 @@ function MovieStatusLabel(props) {
<span
className={styles[statusClass]}
>
{translate(firstCharToUpper(status))}
{translate(firstCharToUpper(movieStatus))}
</span>
);
}
MovieStatusLabel.propTypes = {
status: PropTypes.string.isRequired,
hasMovieFiles: PropTypes.bool.isRequired,
monitored: PropTypes.bool.isRequired,
isAvailable: PropTypes.bool.isRequired,
@ -115,4 +122,9 @@ MovieStatusLabel.propTypes = {
colorImpairedMode: PropTypes.bool
};
MovieStatusLabel.defaultProps = {
useLabel: false,
colorImpairedMode: false
};
export default MovieStatusLabel;

View File

@ -5,8 +5,9 @@ import { sizes } from 'Helpers/Props';
import createMovieQueueItemsDetailsSelector, {
MovieQueueDetails,
} from 'Movie/Index/createMovieQueueDetailsSelector';
import { MovieStatus } from 'Movie/Movie';
import { MovieFile } from 'MovieFile/MovieFile';
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
import getProgressBarKind from 'Utilities/Movie/getProgressBarKind';
import translate from 'Utilities/String/translate';
import styles from './MovieIndexProgressBar.css';
@ -14,7 +15,7 @@ interface MovieIndexProgressBarProps {
movieId: number;
movieFile: MovieFile;
monitored: boolean;
status: string;
status: MovieStatus;
hasFile: boolean;
isAvailable: boolean;
width: number;
@ -44,20 +45,14 @@ function MovieIndexProgressBar(props: MovieIndexProgressBarProps) {
const progress = 100;
const queueStatusText =
queueDetails.count > 0 ? translate('Downloading') : null;
let movieStatus = status === 'released' && hasFile ? 'downloaded' : status;
if (movieStatus === 'deleted') {
movieStatus = translate('Missing');
if (hasFile) {
movieStatus = movieFile?.quality?.quality.name ?? translate('Downloaded');
}
} else if (hasFile) {
let movieStatus = translate('NotAvailable');
if (hasFile) {
movieStatus = movieFile?.quality?.quality.name ?? translate('Downloaded');
} else if (status === 'deleted') {
movieStatus = translate('Deleted');
} else if (isAvailable && !hasFile) {
movieStatus = translate('Missing');
} else {
movieStatus = translate('NotAvailable');
}
const attachedClassName = bottomRadius
@ -70,12 +65,11 @@ function MovieIndexProgressBar(props: MovieIndexProgressBarProps) {
className={styles.progressBar}
containerClassName={containerClassName}
progress={progress}
kind={getStatusStyle(
kind={getProgressBarKind(
status,
monitored,
hasFile,
isAvailable,
'kinds',
queueDetails.count > 0
)}
size={detailedProgressBar ? sizes.MEDIUM : sizes.SMALL}

View File

@ -0,0 +1,38 @@
import { kinds } from 'Helpers/Props';
import { MovieStatus } from 'Movie/Movie';
function getProgressBarKind(
status: MovieStatus,
monitored: boolean,
hasFile: boolean,
isAvailable: boolean,
isDownloading: boolean = false
) {
if (isDownloading) {
return kinds.PURPLE;
}
if (hasFile && monitored) {
return kinds.SUCCESS;
}
if (hasFile && !monitored) {
return kinds.DEFAULT;
}
if (status === 'deleted') {
return kinds.INVERSE;
}
if (isAvailable && monitored) {
return kinds.DANGER;
}
if (!monitored) {
return kinds.WARNING;
}
return kinds.PRIMARY;
}
export default getProgressBarKind;

View File

@ -1,27 +0,0 @@
import { kinds } from 'Helpers/Props';
function getStatusStyle(status, monitored, hasFile, isAvailable, returnType, queue = false) {
if (queue) {
return returnType === 'kinds' ? kinds.QUEUE : 'queue';
}
if (hasFile && monitored) {
return returnType === 'kinds' ? kinds.SUCCESS : 'downloaded';
}
if (hasFile && !monitored) {
return returnType === 'kinds' ? kinds.DEFAULT : 'unmonitored';
}
if (isAvailable && monitored) {
return returnType === 'kinds' ? kinds.DANGER : 'missingMonitored';
}
if (!monitored) {
return returnType === 'kinds' ? kinds.WARNING : 'missingUnmonitored';
}
return returnType === 'kinds' ? kinds.PRIMARY : 'continuing';
}
export default getStatusStyle;

View File

@ -1306,6 +1306,7 @@
"Profiles": "Profiles",
"ProfilesSettingsSummary": "Quality, Language, Delay and Release profiles",
"Progress": "Progress",
"ProgressBarProgress": "Progress Bar at {progress}%",
"Proper": "Proper",
"Protocol": "Protocol",
"ProtocolHelpText": "Choose which protocol(s) to use and which one is preferred when choosing between otherwise equal releases",