From 3548433a101d2917e66b35021be1455d5dae47c5 Mon Sep 17 00:00:00 2001 From: nitsua Date: Sat, 29 Aug 2020 11:41:03 -0400 Subject: [PATCH] New: Add runtime format option in Settings > UI so users can choose between a mins view and h/m view --- frontend/src/Movie/Details/MovieDetails.css | 8 +++-- frontend/src/Movie/Details/MovieDetails.js | 10 +++--- .../Movie/Details/MovieDetailsConnector.js | 6 ++-- .../src/Movie/Index/Table/MovieIndexRow.js | 8 +++-- .../src/Movie/Index/Table/MovieIndexTable.js | 7 +++-- .../Index/Table/MovieIndexTableConnector.js | 6 ++-- frontend/src/Settings/UI/UISettings.js | 31 +++++++++++++------ frontend/src/Utilities/Date/formatRuntime.js | 12 ++++--- .../Configuration/ConfigService.cs | 8 +++++ .../Configuration/IConfigService.cs | 2 ++ .../Configuration/MovieRuntimeFormatType.cs | 8 +++++ src/NzbDrone.Core/Localization/Core/en.json | 1 + src/Radarr.Api.V3/Config/UiConfigResource.cs | 5 +++ 13 files changed, 82 insertions(+), 30 deletions(-) create mode 100644 src/NzbDrone.Core/Configuration/MovieRuntimeFormatType.cs diff --git a/frontend/src/Movie/Details/MovieDetails.css b/frontend/src/Movie/Details/MovieDetails.css index f24bcf9a6..74180e7e8 100644 --- a/frontend/src/Movie/Details/MovieDetails.css +++ b/frontend/src/Movie/Details/MovieDetails.css @@ -118,7 +118,6 @@ } .links, -.tags, .rating, .year, .runtime { @@ -209,10 +208,13 @@ .certification, .links, - .tags, .rating, .year, .runtime { - margin-right: 10px; + margin-right: 9px; + } + + .details { + font-size: 19px; } } diff --git a/frontend/src/Movie/Details/MovieDetails.js b/frontend/src/Movie/Details/MovieDetails.js index 751a7e543..048e477a5 100644 --- a/frontend/src/Movie/Details/MovieDetails.js +++ b/frontend/src/Movie/Details/MovieDetails.js @@ -268,7 +268,8 @@ class MovieDetails extends Component { nextMovie, onMonitorTogglePress, onRefreshPress, - onSearchPress + onSearchPress, + movieRuntimeFormat } = this.props; const { @@ -426,7 +427,7 @@ class MovieDetails extends Component { { !!runtime && - {formatRuntime(runtime)} + {formatRuntime(runtime, movieRuntimeFormat)} } @@ -465,7 +466,7 @@ class MovieDetails extends Component { { !!tags.length && - + state.app.isSidebarVisible, - (titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions, isSidebarVisible) => { + (state) => state.settings.ui.item.movieRuntimeFormat, + (titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions, isSidebarVisible, movieRuntimeFormat) => { const sortedMovies = _.orderBy(allMovies, 'sortTitle'); const movieIndex = _.findIndex(sortedMovies, { titleSlug }); const movie = sortedMovies[movieIndex]; @@ -160,7 +161,8 @@ function createMapStateToProps() { previousMovie, nextMovie, isSmallScreen: dimensions.isSmallScreen, - isSidebarVisible + isSidebarVisible, + movieRuntimeFormat }; } ); diff --git a/frontend/src/Movie/Index/Table/MovieIndexRow.js b/frontend/src/Movie/Index/Table/MovieIndexRow.js index e5fae7080..b63ad5f4f 100644 --- a/frontend/src/Movie/Index/Table/MovieIndexRow.js +++ b/frontend/src/Movie/Index/Table/MovieIndexRow.js @@ -97,7 +97,8 @@ class MovieIndexRow extends Component { isSelected, onRefreshMoviePress, onSearchPress, - onSelectedChange + onSelectedChange, + movieRuntimeFormat } = this.props; const { @@ -253,7 +254,7 @@ class MovieIndexRow extends Component { key={name} className={styles[name]} > - {formatRuntime(runtime)} + {formatRuntime(runtime, movieRuntimeFormat)} ); } @@ -462,7 +463,8 @@ MovieIndexRow.propTypes = { onSelectedChange: PropTypes.func.isRequired, tmdbId: PropTypes.number.isRequired, imdbId: PropTypes.string, - youTubeTrailerId: PropTypes.string + youTubeTrailerId: PropTypes.string, + movieRuntimeFormat: PropTypes.string.isRequired }; MovieIndexRow.defaultProps = { diff --git a/frontend/src/Movie/Index/Table/MovieIndexTable.js b/frontend/src/Movie/Index/Table/MovieIndexTable.js index a8b409bff..9c2f6542c 100644 --- a/frontend/src/Movie/Index/Table/MovieIndexTable.js +++ b/frontend/src/Movie/Index/Table/MovieIndexTable.js @@ -49,7 +49,8 @@ class MovieIndexTable extends Component { columns, selectedState, onSelectedChange, - isMovieEditorActive + isMovieEditorActive, + movieRuntimeFormat } = this.props; const movie = items[rowIndex]; @@ -68,6 +69,7 @@ class MovieIndexTable extends Component { isSelected={selectedState[movie.id]} onSelectedChange={onSelectedChange} isMovieEditorActive={isMovieEditorActive} + movieRuntimeFormat={movieRuntimeFormat} /> ); @@ -135,7 +137,8 @@ MovieIndexTable.propTypes = { selectedState: PropTypes.object.isRequired, onSelectedChange: PropTypes.func.isRequired, onSelectAllChange: PropTypes.func.isRequired, - isMovieEditorActive: PropTypes.bool.isRequired + isMovieEditorActive: PropTypes.bool.isRequired, + movieRuntimeFormat: PropTypes.string.isRequired }; export default MovieIndexTable; diff --git a/frontend/src/Movie/Index/Table/MovieIndexTableConnector.js b/frontend/src/Movie/Index/Table/MovieIndexTableConnector.js index f13c4a8c8..1ba04366c 100644 --- a/frontend/src/Movie/Index/Table/MovieIndexTableConnector.js +++ b/frontend/src/Movie/Index/Table/MovieIndexTableConnector.js @@ -8,11 +8,13 @@ function createMapStateToProps() { (state) => state.app.dimensions, (state) => state.movieIndex.tableOptions, (state) => state.movieIndex.columns, - (dimensions, tableOptions, columns) => { + (state) => state.settings.ui.item.movieRuntimeFormat, + (dimensions, tableOptions, columns, movieRuntimeFormat) => { return { isSmallScreen: dimensions.isSmallScreen, showBanners: tableOptions.showBanners, - columns + columns, + movieRuntimeFormat }; } ); diff --git a/frontend/src/Settings/UI/UISettings.js b/frontend/src/Settings/UI/UISettings.js index 5526213a1..024c3d924 100644 --- a/frontend/src/Settings/UI/UISettings.js +++ b/frontend/src/Settings/UI/UISettings.js @@ -43,6 +43,11 @@ export const timeFormatOptions = [ { key: 'HH:mm', value: '17:00/17:30' } ]; +export const movieRuntimeFormatOptions = [ + { key: 'hoursMinutes', value: '1h 15m' }, + { key: 'minutes', value: '75 mins' } +]; + class UISettings extends Component { // @@ -111,9 +116,21 @@ class UISettings extends Component { -
+
+ + {translate('SettingsRuntimeFormat')} + + + +
+ +
{translate('SettingsShortDateFormat')} @@ -162,9 +179,7 @@ class UISettings extends Component {
-
+
{translate('SettingsEnableColorImpairedMode')}
-
+
{translate('SettingsUiLanguage')} 0) ? `${movieHours}h ` : '') + movieMinutes}m`; - - return formattedRuntime; + return `${((movieHours > 0) ? `${movieHours}h ` : '') + movieMinutes}m`; } export default formatRuntime; diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 122c43544..024acf5ff 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -5,6 +5,7 @@ using NLog; using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Http.Proxy; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Languages; using NzbDrone.Core.MediaFiles; @@ -336,6 +337,13 @@ public string CalendarWeekColumnHeader set { SetValue("CalendarWeekColumnHeader", value); } } + public MovieRuntimeFormatType MovieRuntimeFormat + { + get { return GetValueEnum("MovieRuntimeFormat", MovieRuntimeFormatType.HoursMinutes); } + + set { SetValue("MovieRuntimeFormat", value); } + } + public string ShortDateFormat { get { return GetValue("ShortDateFormat", "MMM D YYYY"); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index ed38e7a50..217f2452c 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using NzbDrone.Common.Http.Proxy; +using NzbDrone.Core.Configuration; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MetadataSource.SkyHook.Resource; using NzbDrone.Core.Security; @@ -68,6 +69,7 @@ public interface IConfigService //UI int FirstDayOfWeek { get; set; } string CalendarWeekColumnHeader { get; set; } + MovieRuntimeFormatType MovieRuntimeFormat { get; set; } string ShortDateFormat { get; set; } string LongDateFormat { get; set; } diff --git a/src/NzbDrone.Core/Configuration/MovieRuntimeFormatType.cs b/src/NzbDrone.Core/Configuration/MovieRuntimeFormatType.cs new file mode 100644 index 000000000..f95540727 --- /dev/null +++ b/src/NzbDrone.Core/Configuration/MovieRuntimeFormatType.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Core.Configuration +{ + public enum MovieRuntimeFormatType + { + HoursMinutes, + Minutes + } +} diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index c3c8a5a2d..faa165ef7 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -523,6 +523,7 @@ "SettingsRemotePathMappingLocalPathHelpText": "Path that Radarr should use to access the remote path locally", "SettingsRemotePathMappingRemotePath": "Remote Path", "SettingsRemotePathMappingRemotePathHelpText": "Root path to the directory that the Download Client accesses", + "SettingsRuntimeFormat": "Runtime Format", "SettingsShortDateFormat": "Short Date Format", "SettingsShowRelativeDates": "Show Relative Dates", "SettingsShowRelativeDatesHelpText": "Show relative (Today/Yesterday/etc) or absolute dates", diff --git a/src/Radarr.Api.V3/Config/UiConfigResource.cs b/src/Radarr.Api.V3/Config/UiConfigResource.cs index 723a5c13e..e84d20843 100644 --- a/src/Radarr.Api.V3/Config/UiConfigResource.cs +++ b/src/Radarr.Api.V3/Config/UiConfigResource.cs @@ -9,6 +9,9 @@ public class UiConfigResource : RestResource public int FirstDayOfWeek { get; set; } public string CalendarWeekColumnHeader { get; set; } + // Movies + public MovieRuntimeFormatType MovieRuntimeFormat { get; set; } + //Dates public string ShortDateFormat { get; set; } public string LongDateFormat { get; set; } @@ -28,6 +31,8 @@ public static UiConfigResource ToResource(IConfigService model) FirstDayOfWeek = model.FirstDayOfWeek, CalendarWeekColumnHeader = model.CalendarWeekColumnHeader, + MovieRuntimeFormat = model.MovieRuntimeFormat, + ShortDateFormat = model.ShortDateFormat, LongDateFormat = model.LongDateFormat, TimeFormat = model.TimeFormat,