diff --git a/src/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs b/src/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs index d31edcac6..1cff8601f 100644 --- a/src/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs +++ b/src/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs @@ -41,7 +41,8 @@ namespace NzbDrone.Api.Test.MappingTests [TestCase(typeof(ParsedEpisodeInfo), typeof(ReleaseResource))] [TestCase(typeof(DownloadDecision), typeof(ReleaseResource))] [TestCase(typeof(Core.History.History), typeof(HistoryResource))] - [TestCase(typeof(Quality), typeof(QualityResource))] + [TestCase(typeof(QualityProfile), typeof(QualityProfileResource))] + [TestCase(typeof(QualityProfileItem), typeof(QualityProfileItemResource))] [TestCase(typeof(Log), typeof(LogResource))] [TestCase(typeof(Command), typeof(CommandResource))] public void matching_fields(Type modelType, Type resourceType) @@ -109,7 +110,8 @@ namespace NzbDrone.Api.Test.MappingTests { var profileResource = new QualityProfileResource { - Allowed = Builder.CreateListOfSize(1).Build().ToList(), + Cutoff = Quality.WEBDL1080p, + Items = new List { new QualityProfileItemResource { Quality = Quality.WEBDL1080p, Allowed = true } } }; diff --git a/src/NzbDrone.Api/Qualities/QualityProfileModule.cs b/src/NzbDrone.Api/Qualities/QualityProfileModule.cs index 250bddd08..395d67803 100644 --- a/src/NzbDrone.Api/Qualities/QualityProfileModule.cs +++ b/src/NzbDrone.Api/Qualities/QualityProfileModule.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Api.Qualities SharedValidator.RuleFor(c => c.Name).NotEmpty(); SharedValidator.RuleFor(c => c.Cutoff).NotNull(); - SharedValidator.RuleFor(c => c.Allowed).NotEmpty(); + SharedValidator.RuleFor(c => c.Items).NotEmpty(); GetResourceAll = GetAll; @@ -48,46 +48,23 @@ namespace NzbDrone.Api.Qualities private void Update(QualityProfileResource resource) { var model = _qualityProfileService.Get(resource.Id); + model.Name = resource.Name; model.Cutoff = (Quality)resource.Cutoff.Id; - model.Allowed = resource.Allowed.Select(p => (Quality)p.Id).ToList(); + model.Items = resource.Items.InjectTo>(); _qualityProfileService.Update(model); } private QualityProfileResource GetById(int id) { - return MapToResource(_qualityProfileService.Get(id)); + return _qualityProfileService.Get(id).InjectTo(); } private List GetAll() { - var profiles = _qualityProfileService.All().Select(MapToResource).ToList(); + var profiles = _qualityProfileService.All().InjectTo>(); return profiles; } - - private QualityProfileResource MapToResource(QualityProfile profile) - { - return new QualityProfileResource - { - Cutoff = MapToResource(_qualityDefinitionService.Get(profile.Cutoff)), - Available = _qualityDefinitionService.All() - .Where(c => !profile.Allowed.Any(q => c.Quality == q)) - .Select(MapToResource).ToList(), - Allowed = profile.Allowed.Select(_qualityDefinitionService.Get).Select(MapToResource).ToList(), - Name = profile.Name, - Id = profile.Id - }; - } - - private QualityResource MapToResource(QualityDefinition config) - { - return new QualityResource - { - Id = config.Quality.Id, - Name = config.Quality.Name, - Weight = config.Weight - }; - } } } \ No newline at end of file diff --git a/src/NzbDrone.Api/Qualities/QualityProfileResource.cs b/src/NzbDrone.Api/Qualities/QualityProfileResource.cs index 73ba94268..dbeff0fa0 100644 --- a/src/NzbDrone.Api/Qualities/QualityProfileResource.cs +++ b/src/NzbDrone.Api/Qualities/QualityProfileResource.cs @@ -1,21 +1,20 @@ using System; using System.Collections.Generic; using NzbDrone.Api.REST; +using NzbDrone.Core.Qualities; namespace NzbDrone.Api.Qualities { public class QualityProfileResource : RestResource { public String Name { get; set; } - public QualityResource Cutoff { get; set; } - public List Available { get; set; } - public List Allowed { get; set; } + public Quality Cutoff { get; set; } + public List Items { get; set; } } - public class QualityResource : RestResource + public class QualityProfileItemResource : RestResource { - public String Name { get; set; } - - public Int32 Weight { get; set; } + public Quality Quality { get; set; } + public bool Allowed { get; set; } } } \ No newline at end of file diff --git a/src/NzbDrone.Api/Qualities/QualityProfileSchemaModule.cs b/src/NzbDrone.Api/Qualities/QualityProfileSchemaModule.cs index e4e23ca02..64caeefab 100644 --- a/src/NzbDrone.Api/Qualities/QualityProfileSchemaModule.cs +++ b/src/NzbDrone.Api/Qualities/QualityProfileSchemaModule.cs @@ -19,34 +19,16 @@ namespace NzbDrone.Api.Qualities private List GetAll() { + var items = _qualityDefinitionService.All() + .OrderBy(v => v.Weight) + .Select(v => new QualityProfileItem { Quality = v.Quality, Allowed = false }) + .ToList(); + var profile = new QualityProfile(); profile.Cutoff = Quality.Unknown; - profile.Allowed = new List(); - - return new List { QualityToResource(profile) }; - } - - private QualityProfileResource QualityToResource(QualityProfile profile) - { - return new QualityProfileResource - { - Cutoff = QualityToResource(_qualityDefinitionService.Get(profile.Cutoff)), - Available = _qualityDefinitionService.All().Select(QualityToResource).ToList(), - Allowed = profile.Allowed.Select(_qualityDefinitionService.Get).Select(QualityToResource).ToList(), - Name = profile.Name, - Id = profile.Id - }; - } + profile.Items = items; - - private QualityResource QualityToResource(QualityDefinition config) - { - return new QualityResource - { - Id = config.Quality.Id, - Name = config.Quality.Name, - Weight = config.Weight - }; + return new List { profile.InjectTo() }; } } } \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs index be1f420da..861d39d32 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs @@ -13,35 +13,35 @@ namespace NzbDrone.Core.Test.DecisionEngineTests [Test] public void should_return_true_if_current_episode_is_less_than_cutoff() { - Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }, + Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() }, new QualityModel(Quality.DVD, true)).Should().BeTrue(); } [Test] public void should_return_false_if_current_episode_is_equal_to_cutoff() { - Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }, + Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() }, new QualityModel(Quality.HDTV720p, true)).Should().BeFalse(); } [Test] public void should_return_false_if_current_episode_is_greater_than_cutoff() { - Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }, + Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() }, new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse(); } [Test] public void should_return_true_when_new_episode_is_proper_but_existing_is_not() { - Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }, + Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() }, new QualityModel(Quality.HDTV720p, false), new QualityModel(Quality.HDTV720p, true)).Should().BeTrue(); } [Test] public void should_return_false_if_cutoff_is_met_and_quality_is_higher() { - Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }, + Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() }, new QualityModel(Quality.HDTV720p, true), new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse(); } } diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs index 36d7db629..4013271c9 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs @@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests }; _fakeSeries = Builder.CreateNew() - .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); _parseResultMulti = new RemoteEpisode @@ -130,7 +130,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests [Test] public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing() { - _fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }; + _fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p, Items = Qualities.QualityFixture.GetDefaultQualities() }; _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, false); _upgradableQuality = new QualityModel(Quality.WEBDL1080p, false); diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/NotInQueueSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/NotInQueueSpecificationFixture.cs index 59361c70f..baa24d5b4 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/NotInQueueSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/NotInQueueSpecificationFixture.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests public void Setup() { _series = Builder.CreateNew() - .With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); _episode = Builder.CreateNew() diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs index fb5ddde76..d8d46f3c0 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs @@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests public void should_allow_if_quality_is_defined_in_profile(Quality qualityType) { remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; - remoteEpisode.Series.QualityProfile.Value.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; + remoteEpisode.Series.QualityProfile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p); Subject.IsSatisfiedBy(remoteEpisode, null).Should().BeTrue(); } @@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType) { remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; - remoteEpisode.Series.QualityProfile.Value.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; + remoteEpisode.Series.QualityProfile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p); Subject.IsSatisfiedBy(remoteEpisode, null).Should().BeFalse(); } diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/QualityUpgradeSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/QualityUpgradeSpecificationFixture.cs index d3385c23b..e91771776 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/QualityUpgradeSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/QualityUpgradeSpecificationFixture.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { GivenAutoDownloadPropers(true); - var qualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }; + var qualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }; Subject.IsUpgradable(qualityProfile, new QualityModel(current, currentProper), new QualityModel(newQuality, newProper)) .Should().Be(expected); @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { GivenAutoDownloadPropers(false); - var qualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }; + var qualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }; Subject.IsUpgradable(qualityProfile, new QualityModel(Quality.DVD, true), new QualityModel(Quality.DVD, false)) .Should().BeFalse(); diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs index 9135f0a75..c9e03d256 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests var doubleEpisodeList = new List { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = _secondFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } }; var fakeSeries = Builder.CreateNew() - .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); _parseResultMulti = new RemoteEpisode diff --git a/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/DownloadApprovedFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/DownloadApprovedFixture.cs index 65ad262a1..0563db94e 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/DownloadApprovedFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/DownloadApprovedFixture.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests remoteEpisode.Release.PublishDate = DateTime.UtcNow; remoteEpisode.Series = Builder.CreateNew() - .With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); return remoteEpisode; diff --git a/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/GetQualifiedReportsFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/GetQualifiedReportsFixture.cs index 0036a8bcb..4c8aafaa4 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/GetQualifiedReportsFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadApprovedReportsTests/GetQualifiedReportsFixture.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests remoteEpisode.Release.Size = size; remoteEpisode.Series = Builder.CreateNew() - .With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); return remoteEpisode; diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs index 0e2bc1053..dcd8a12dc 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs @@ -65,7 +65,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport _videoFiles = new List { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi" }; _series = Builder.CreateNew() - .With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); _quality = new QualityModel(Quality.DVD); diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs index f189f049b..a0bff8424 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications { _series = Builder.CreateNew() .With(s => s.SeriesType = SeriesTypes.Standard) - .With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); _localEpisode = new LocalEpisode diff --git a/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs index 55789f9b8..59aa51f1c 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.MediaFiles _approvedDecisions = new List(); var series = Builder.CreateNew() - .With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() }) + .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); var episodes = Builder.CreateListOfSize(5) diff --git a/src/NzbDrone.Core.Test/Qualities/QualityFixture.cs b/src/NzbDrone.Core.Test/Qualities/QualityFixture.cs index bffb0f5be..ddab8f19b 100644 --- a/src/NzbDrone.Core.Test/Qualities/QualityFixture.cs +++ b/src/NzbDrone.Core.Test/Qualities/QualityFixture.cs @@ -44,9 +44,9 @@ namespace NzbDrone.Core.Test.Qualities i.Should().Be(expected); } - public static List GetDefaultQualities() + public static List GetDefaultQualities(params Quality[] allowed) { - return new List + var qualities = new List { Quality.SDTV, Quality.WEBDL480p, @@ -59,6 +59,16 @@ namespace NzbDrone.Core.Test.Qualities Quality.WEBDL1080p, Quality.Bluray1080p }; + + if (allowed.Length == 0) + allowed = qualities.ToArray(); + + var items = qualities + .Except(allowed) + .Concat(allowed) + .Select(v => new QualityProfileItem { Quality = v, Allowed = allowed.Contains(v) }).ToList(); + + return items; } } } diff --git a/src/NzbDrone.Core.Test/Qualities/QualityModelComparerFixture.cs b/src/NzbDrone.Core.Test/Qualities/QualityModelComparerFixture.cs index 416962658..187455abb 100644 --- a/src/NzbDrone.Core.Test/Qualities/QualityModelComparerFixture.cs +++ b/src/NzbDrone.Core.Test/Qualities/QualityModelComparerFixture.cs @@ -15,12 +15,12 @@ namespace NzbDrone.Core.Test.Qualities private void GivenDefaultQualityProfile() { - Subject = new QualityModelComparer(new QualityProfile { Allowed = QualityFixture.GetDefaultQualities() }); + Subject = new QualityModelComparer(new QualityProfile { Items = QualityFixture.GetDefaultQualities() }); } private void GivenCustomQualityProfile() { - Subject = new QualityModelComparer(new QualityProfile { Allowed = new List { Quality.Bluray720p, Quality.DVD } }); + Subject = new QualityModelComparer(new QualityProfile { Items = QualityFixture.GetDefaultQualities(Quality.Bluray720p, Quality.DVD) }); } [Test] @@ -87,31 +87,5 @@ namespace NzbDrone.Core.Test.Qualities compare.Should().BeGreaterThan(0); } - - [Test] - public void Icomparer_missing_custom_order() - { - GivenCustomQualityProfile(); - - var first = new QualityModel(Quality.Bluray720p, true); - var second = new QualityModel(Quality.Bluray1080p, true); - - var compare = Subject.Compare(first, second); - - compare.Should().BeGreaterThan(0); - } - - [Test] - public void Icomparer_missing_both_custom_order() - { - GivenCustomQualityProfile(); - - var first = new QualityModel(Quality.SDTV, true); - var second = new QualityModel(Quality.Bluray1080p, true); - - var compare = Subject.Compare(first, second); - - compare.Should().Be(0); - } } } diff --git a/src/NzbDrone.Core.Test/Qualities/QualityProfileRepositoryFixture.cs b/src/NzbDrone.Core.Test/Qualities/QualityProfileRepositoryFixture.cs index f13c59f3d..10b8ece92 100644 --- a/src/NzbDrone.Core.Test/Qualities/QualityProfileRepositoryFixture.cs +++ b/src/NzbDrone.Core.Test/Qualities/QualityProfileRepositoryFixture.cs @@ -14,13 +14,7 @@ namespace NzbDrone.Core.Test.Qualities { var profile = new QualityProfile { - Allowed = new List - { - Quality.Bluray1080p, - Quality.DVD, - Quality.HDTV720p - }, - + Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p), Cutoff = Quality.Bluray1080p, Name = "TestProfile" }; @@ -29,8 +23,8 @@ namespace NzbDrone.Core.Test.Qualities StoredModel.Name.Should().Be(profile.Name); StoredModel.Cutoff.Should().Be(profile.Cutoff); - - StoredModel.Allowed.Should().BeEquivalentTo(profile.Allowed); + + StoredModel.Items.Should().Equal(profile.Items, (a,b) => a.Quality == b.Quality && a.Allowed == b.Allowed); } diff --git a/src/NzbDrone.Core.Test/TvTests/SeriesRepositoryTests/QualityProfileRepositoryFixture.cs b/src/NzbDrone.Core.Test/TvTests/SeriesRepositoryTests/QualityProfileRepositoryFixture.cs index 4829e3417..0685ccc0f 100644 --- a/src/NzbDrone.Core.Test/TvTests/SeriesRepositoryTests/QualityProfileRepositoryFixture.cs +++ b/src/NzbDrone.Core.Test/TvTests/SeriesRepositoryTests/QualityProfileRepositoryFixture.cs @@ -17,12 +17,7 @@ namespace NzbDrone.Core.Test.TvTests.SeriesRepositoryTests { var profile = new QualityProfile { - Allowed = new List - { - Quality.Bluray1080p, - Quality.DVD, - Quality.HDTV720p - }, + Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p), Cutoff = Quality.Bluray1080p, Name = "TestProfile" diff --git a/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs b/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs index e144d4cf4..e7591f3ee 100644 --- a/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs +++ b/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs @@ -2,11 +2,33 @@ using Marr.Data.Converters; using Marr.Data.Mapping; using NzbDrone.Common.Serializer; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; namespace NzbDrone.Core.Datastore.Converters { public class EmbeddedDocumentConverter : IConverter { + private readonly JsonSerializerSettings SerializerSetting; + + public EmbeddedDocumentConverter(params JsonConverter[] converters) + { + SerializerSetting = new JsonSerializerSettings + { + DateTimeZoneHandling = DateTimeZoneHandling.Utc, + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.Indented, + DefaultValueHandling = DefaultValueHandling.Include, + ContractResolver = new CamelCasePropertyNamesContractResolver() + }; + + SerializerSetting.Converters.Add(new StringEnumConverter { CamelCaseText = true }); + SerializerSetting.Converters.Add(new VersionConverter()); + foreach (var converter in converters) + SerializerSetting.Converters.Add(converter); + } + public virtual object FromDB(ConverterContext context) { if (context.DbValue == DBNull.Value) @@ -20,8 +42,7 @@ namespace NzbDrone.Core.Datastore.Converters { return null; } - - return Json.Deserialize(stringValue, context.ColumnMap.FieldType); + return JsonConvert.DeserializeObject(stringValue, context.ColumnMap.FieldType, SerializerSetting); } public object FromDB(ColumnMap map, object dbValue) @@ -33,7 +54,7 @@ namespace NzbDrone.Core.Datastore.Converters { if (clrValue == null) return null; - return clrValue.ToJson(); + return JsonConvert.SerializeObject(clrValue, SerializerSetting); } public Type DbType diff --git a/src/NzbDrone.Core/Datastore/Converters/QualityIntConverter.cs b/src/NzbDrone.Core/Datastore/Converters/QualityIntConverter.cs index ea5dfd59f..ad07994c5 100644 --- a/src/NzbDrone.Core/Datastore/Converters/QualityIntConverter.cs +++ b/src/NzbDrone.Core/Datastore/Converters/QualityIntConverter.cs @@ -4,10 +4,11 @@ using Marr.Data.Mapping; using NzbDrone.Core.Qualities; using System.Collections.Generic; using NzbDrone.Common.Serializer; +using Newtonsoft.Json; namespace NzbDrone.Core.Datastore.Converters { - public class QualityIntConverter : IConverter + public class QualityIntConverter : JsonConverter, IConverter { public object FromDB(ConverterContext context) { @@ -46,5 +47,23 @@ namespace NzbDrone.Core.Datastore.Converters return typeof(int); } } + + #region JsonConverter + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Quality); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var item = reader.Value; + return (Quality)Convert.ToInt32(item); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(ToDB(value)); + } + #endregion } } \ No newline at end of file diff --git a/src/NzbDrone.Core/Datastore/Converters/QualityListConverter.cs b/src/NzbDrone.Core/Datastore/Converters/QualityListConverter.cs deleted file mode 100644 index c0c58d8f5..000000000 --- a/src/NzbDrone.Core/Datastore/Converters/QualityListConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using Marr.Data.Converters; -using Marr.Data.Mapping; -using NzbDrone.Core.Qualities; -using System.Collections.Generic; -using NzbDrone.Common.Serializer; - -namespace NzbDrone.Core.Datastore.Converters -{ - public class QualityListConverter : IConverter - { - public object FromDB(ConverterContext context) - { - if (context.DbValue == DBNull.Value) - { - return DBNull.Value; - } - - var val = Convert.ToString(context.DbValue); - - var qualityList = Json.Deserialize>(val).ConvertAll(Quality.FindById); - - return qualityList; - } - - public object FromDB(ColumnMap map, object dbValue) - { - return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue }); - } - - public object ToDB(object clrValue) - { - if (clrValue == DBNull.Value) return null; - - var qualityList = clrValue as List; - - if (qualityList == null) - { - throw new InvalidOperationException("Can only store a list of qualities in this database column."); - } - - var intList = qualityList.ConvertAll(v => v.Id); - - return intList.ToJson(); - } - - public Type DbType - { - get { return typeof(string); } - } - } -} diff --git a/src/NzbDrone.Core/Datastore/Converters/QualityModelConverter.cs b/src/NzbDrone.Core/Datastore/Converters/QualityModelConverter.cs deleted file mode 100644 index 8e2917dcc..000000000 --- a/src/NzbDrone.Core/Datastore/Converters/QualityModelConverter.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using Marr.Data.Converters; -using Marr.Data.Mapping; -using NzbDrone.Core.Qualities; -using System.Collections.Generic; -using NzbDrone.Common.Serializer; - -namespace NzbDrone.Core.Datastore.Converters -{ - public class QualityModelConverter : IConverter - { - public object FromDB(ConverterContext context) - { - if (context.DbValue == DBNull.Value) - { - return new QualityModel(); - } - - var val = Convert.ToString(context.DbValue); - - var jsonObject = Json.Deserialize>(val); - - return new QualityModel((Quality)Convert.ToInt32(jsonObject["id"]), Convert.ToBoolean(jsonObject["proper"])); - } - - public object FromDB(ColumnMap map, object dbValue) - { - return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue }); - } - - public object ToDB(object clrValue) - { - if (clrValue == DBNull.Value) - clrValue = new QualityModel(); - - var qualityModel = clrValue as QualityModel; - - if (qualityModel == null) - { - throw new InvalidOperationException("Can only store a QualityModel in this database column."); - } - - var jsonObject = new Dictionary(); - jsonObject["id"] = (int)qualityModel.Quality; - jsonObject["proper"] = qualityModel.Proper; - - return jsonObject.ToJson(); - } - - public Type DbType - { - get { return typeof(string); } - } - } -} diff --git a/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs b/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs index c29490f66..35f9dbbb9 100644 --- a/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs +++ b/src/NzbDrone.Core/Datastore/Migration/036_update_with_quality_converters.cs @@ -6,6 +6,7 @@ using System; using NzbDrone.Common.Serializer; using NzbDrone.Core.Qualities; using System.Collections.Generic; +using NzbDrone.Core.Datastore.Converters; namespace NzbDrone.Core.Datastore.Migration { @@ -14,6 +15,8 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { + Alter.Table("QualityProfiles").AddColumn("Items").AsString().Nullable(); + Execute.WithConnection(ConvertQualityProfiles); Execute.WithConnection(ConvertQualityModels); @@ -21,7 +24,7 @@ namespace NzbDrone.Core.Datastore.Migration private void ConvertQualityProfiles(IDbConnection conn, IDbTransaction tran) { - var qualityListConverter = new NzbDrone.Core.Datastore.Converters.QualityListConverter(); + var qualityProfileItemConverter = new EmbeddedDocumentConverter(new QualityIntConverter()); // Convert 'Allowed' column in QualityProfiles from Json List to Json List (int = Quality) using (IDbCommand qualityProfileCmd = conn.CreateCommand()) @@ -36,13 +39,15 @@ namespace NzbDrone.Core.Datastore.Migration var allowedJson = qualityProfileReader.GetString(1); var allowed = Json.Deserialize>(allowedJson); - - var allowedNewJson = qualityListConverter.ToDB(allowed); + + var items = Quality.DefaultQualityDefinitions.OrderBy(v => v.Weight).Select(v => new QualityProfileItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) }).ToList(); + + var allowedNewJson = qualityProfileItemConverter.ToDB(items); using (IDbCommand updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE QualityProfiles SET Allowed = ? WHERE Id = ?"; + updateCmd.CommandText = "UPDATE QualityProfiles SET Items = ? WHERE Id = ?"; updateCmd.AddParameter(allowedNewJson); updateCmd.AddParameter(id); @@ -63,7 +68,7 @@ namespace NzbDrone.Core.Datastore.Migration private void ConvertQualityModel(IDbConnection conn, IDbTransaction tran, string tableName) { - var qualityModelConverter = new NzbDrone.Core.Datastore.Converters.QualityModelConverter(); + var qualityModelConverter = new EmbeddedDocumentConverter(new QualityIntConverter()); using (IDbCommand qualityModelCmd = conn.CreateCommand()) { diff --git a/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs b/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs index 1020dca2c..c036ee4ba 100644 --- a/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs +++ b/src/NzbDrone.Core/Datastore/Migration/037_add_configurable_qualities.cs @@ -14,6 +14,9 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { + SqLiteAlter.DropColumns("QualityProfiles", new[] { "Allowed" }); + Alter.Column("Items").OnTable("QualityProfiles").AsString().NotNullable(); + Create.TableForModel("QualityDefinitions") .WithColumn("Quality").AsInt32().Unique() .WithColumn("Title").AsString().Unique() diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index f164e925d..f97514f16 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -81,8 +81,8 @@ namespace NzbDrone.Core.Datastore MapRepository.Instance.RegisterTypeConverter(typeof(Boolean), new BooleanIntConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(Enum), new EnumIntConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(Quality), new QualityIntConverter()); - MapRepository.Instance.RegisterTypeConverter(typeof(List), new QualityListConverter()); - MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new QualityModelConverter()); + MapRepository.Instance.RegisterTypeConverter(typeof(List), new EmbeddedDocumentConverter(new QualityIntConverter())); + MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new EmbeddedDocumentConverter(new QualityIntConverter())); MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary), new EmbeddedDocumentConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(List), new EmbeddedDocumentConverter()); } diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs index 40c0a3ad0..b4bcc1f83 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) { _logger.Trace("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality); - if (!subject.Series.QualityProfile.Value.Allowed.Contains(subject.ParsedEpisodeInfo.Quality.Quality)) + if (!subject.Series.QualityProfile.Value.Items.Exists(v => v.Allowed && v.Quality == subject.ParsedEpisodeInfo.Quality.Quality)) { _logger.Trace("Quality {0} rejected by Series' quality profile", subject.ParsedEpisodeInfo.Quality); return false; diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index b93b226a2..635d2bfd3 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -145,8 +145,6 @@ - - @@ -461,6 +459,7 @@ + diff --git a/src/NzbDrone.Core/Qualities/Quality.cs b/src/NzbDrone.Core/Qualities/Quality.cs index 656e522da..673abc5f7 100644 --- a/src/NzbDrone.Core/Qualities/Quality.cs +++ b/src/NzbDrone.Core/Qualities/Quality.cs @@ -68,7 +68,7 @@ namespace NzbDrone.Core.Qualities public static Quality WEBDL480p { get { return new Quality(8, "WEBDL-480p"); } } public static Quality HDTV1080p { get { return new Quality(9, "HDTV-1080p"); } } public static Quality RAWHD { get { return new Quality(10, "Raw-HD"); } } - public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p"); } } + //public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p"); } } public static List All { diff --git a/src/NzbDrone.Core/Qualities/QualityModelComparer.cs b/src/NzbDrone.Core/Qualities/QualityModelComparer.cs index 2859059af..bb66dcd7f 100644 --- a/src/NzbDrone.Core/Qualities/QualityModelComparer.cs +++ b/src/NzbDrone.Core/Qualities/QualityModelComparer.cs @@ -14,15 +14,15 @@ namespace NzbDrone.Core.Qualities public QualityModelComparer(QualityProfile qualityProfile) { Ensure.That(qualityProfile, () => qualityProfile).IsNotNull(); - Ensure.That(qualityProfile.Allowed, () => qualityProfile.Allowed).HasItems(); + Ensure.That(qualityProfile.Items, () => qualityProfile.Items).HasItems(); _qualityProfile = qualityProfile; } public int Compare(Quality left, Quality right) { - int leftIndex = _qualityProfile.Allowed.IndexOf(left); - int rightIndex = _qualityProfile.Allowed.IndexOf(right); + int leftIndex = _qualityProfile.Items.FindIndex(v => v.Quality == left); + int rightIndex = _qualityProfile.Items.FindIndex(v => v.Quality == right); return leftIndex.CompareTo(rightIndex); } @@ -36,32 +36,5 @@ namespace NzbDrone.Core.Qualities return result; } - /* - public string GetName(Quality quality) - { - QualityDefinition qualityDefinition = _qualityDefinitionService.Get(quality); - - return qualityDefinition.Name; - } - - public string GetName(QualityModel quality) - { - QualityDefinition qualityDefinition = _qualityDefinitionService.Get(quality.Quality); - - if (quality.Proper) - return qualityDefinition.Name + " Proper"; - else - return qualityDefinition.Name; - } - - public string GetSceneName(QualityModel quality) - { - QualityDefinition qualityDefinition = _qualityDefinitionService.Get(quality.Quality); - - if (quality.Proper) - return qualityDefinition.SceneName + " PROPER"; - else - return qualityDefinition.SceneName; - }*/ } } diff --git a/src/NzbDrone.Core/Qualities/QualityProfile.cs b/src/NzbDrone.Core/Qualities/QualityProfile.cs index 892983ecd..b578d1962 100644 --- a/src/NzbDrone.Core/Qualities/QualityProfile.cs +++ b/src/NzbDrone.Core/Qualities/QualityProfile.cs @@ -6,7 +6,7 @@ namespace NzbDrone.Core.Qualities public class QualityProfile : ModelBase { public string Name { get; set; } - public List Allowed { get; set; } public Quality Cutoff { get; set; } + public List Items { get; set; } } } \ No newline at end of file diff --git a/src/NzbDrone.Core/Qualities/QualityProfileItem.cs b/src/NzbDrone.Core/Qualities/QualityProfileItem.cs new file mode 100644 index 000000000..9d7d839d2 --- /dev/null +++ b/src/NzbDrone.Core/Qualities/QualityProfileItem.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.Qualities +{ + public class QualityProfileItem : IEmbeddedDocument + { + public Quality Quality { get; set; } + public bool Allowed { get; set; } + } +} diff --git a/src/NzbDrone.Core/Qualities/QualityProfileService.cs b/src/NzbDrone.Core/Qualities/QualityProfileService.cs index 82baaaa39..13b18afad 100644 --- a/src/NzbDrone.Core/Qualities/QualityProfileService.cs +++ b/src/NzbDrone.Core/Qualities/QualityProfileService.cs @@ -60,68 +60,46 @@ namespace NzbDrone.Core.Qualities return _qualityProfileRepository.Get(id); } + private QualityProfile AddDefaultQualityProfile(string name, Quality cutoff, params Quality[] allowed) + { + var items = Quality.DefaultQualityDefinitions + .OrderBy(v => v.Weight) + .Select(v => new QualityProfileItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) }) + .ToList(); + + var qualityProfile = new QualityProfile { Name = name, Cutoff = cutoff, Items = items }; + + return Add(qualityProfile); + } + public void Handle(ApplicationStartedEvent message) { if (All().Any()) return; _logger.Info("Setting up default quality profiles"); - var sd = new QualityProfile - { - Name = "SD", - Allowed = new List - { - Quality.SDTV, - Quality.WEBDL480p, - Quality.DVD - }, - Cutoff = Quality.SDTV - }; - - var hd720p = new QualityProfile - { - Name = "HD 720p", - Allowed = new List - { - Quality.HDTV720p, - Quality.WEBDL720p, - Quality.Bluray720p - }, - Cutoff = Quality.HDTV720p - }; - - - var hd1080p = new QualityProfile - { - Name = "HD 1080p", - Allowed = new List - { - Quality.HDTV1080p, - Quality.WEBDL1080p, - Quality.Bluray1080p - }, - Cutoff = Quality.HDTV1080p - }; - - var hdAll = new QualityProfile - { - Name = "HD - All", - Allowed = new List - { - Quality.HDTV720p, - Quality.WEBDL720p, - Quality.Bluray720p, - Quality.HDTV1080p, - Quality.WEBDL1080p, - Quality.Bluray1080p - }, - Cutoff = Quality.HDTV720p - }; - - Add(sd); - Add(hd720p); - Add(hd1080p); - Add(hdAll); + AddDefaultQualityProfile("SD", Quality.SDTV, + Quality.SDTV, + Quality.WEBDL480p, + Quality.DVD); + + AddDefaultQualityProfile("HD-720p", Quality.HDTV720p, + Quality.HDTV720p, + Quality.WEBDL720p, + Quality.Bluray720p); + + AddDefaultQualityProfile("HD-1080p", Quality.HDTV1080p, + Quality.HDTV1080p, + Quality.WEBDL1080p, + Quality.Bluray1080p); + + AddDefaultQualityProfile("HD - All", Quality.HDTV720p, + Quality.HDTV720p, + Quality.HDTV1080p, + Quality.WEBDL720p, + Quality.WEBDL1080p, + Quality.Bluray720p, + Quality.Bluray1080p); } } } \ No newline at end of file diff --git a/src/UI/JsLibraries/backbone.collectionview.js b/src/UI/JsLibraries/backbone.collectionview.js index 170871ec4..29ec982ff 100644 --- a/src/UI/JsLibraries/backbone.collectionview.js +++ b/src/UI/JsLibraries/backbone.collectionview.js @@ -875,7 +875,7 @@ { if( _.contains( this.selectedItems, clickedItemId ) ) this.setSelectedModels( _.without( this.selectedItems, clickedItemId ), { by : "cid" } ); - else this.setSelectedModels( _.union( this.selectedItems, clickedItemId ), { by : "cid" } ); + else this.setSelectedModels( _.union( this.selectedItems, [ clickedItemId ] ), { by : "cid" } ); } else this.setSelectedModels( [ clickedItemId ], { by : "cid" } ); diff --git a/src/UI/Settings/Quality/Profile/AllowedLabeler.js b/src/UI/Settings/Quality/Profile/AllowedLabeler.js index fed162e17..ab09626e9 100644 --- a/src/UI/Settings/Quality/Profile/AllowedLabeler.js +++ b/src/UI/Settings/Quality/Profile/AllowedLabeler.js @@ -7,13 +7,14 @@ define( Handlebars.registerHelper('allowedLabeler', function () { var ret = ''; var cutoff = this.cutoff; - _.each(this.allowed, function (allowed) { - if (allowed.id === cutoff.id) { - ret += '' + allowed.name + ' '; - } - - else { - ret += '' + allowed.name + ' '; + _.each(this.items, function (item) { + if (item.allowed) { + if (item.quality.id === cutoff.id) { + ret += '' + item.quality.name + ' '; + } + else { + ret += '' + item.quality.name + ' '; + } } }); diff --git a/src/UI/Settings/Quality/Profile/EditQualityProfileItemViewTemplate.html b/src/UI/Settings/Quality/Profile/EditQualityProfileItemViewTemplate.html index 520c95246..f118c528b 100644 --- a/src/UI/Settings/Quality/Profile/EditQualityProfileItemViewTemplate.html +++ b/src/UI/Settings/Quality/Profile/EditQualityProfileItemViewTemplate.html @@ -1,4 +1,3 @@ - -{{name}} + +{{quality.name}} - diff --git a/src/UI/Settings/Quality/Profile/EditQualityProfileView.js b/src/UI/Settings/Quality/Profile/EditQualityProfileView.js index 139bb5de2..49e571939 100644 --- a/src/UI/Settings/Quality/Profile/EditQualityProfileView.js +++ b/src/UI/Settings/Quality/Profile/EditQualityProfileView.js @@ -15,7 +15,6 @@ define( template: 'Settings/Quality/Profile/EditQualityProfileViewTemplate', ui: { - available: '.x-available-list', allowed : '.x-allowed-list', cutoff : '.x-cutoff' }, @@ -26,101 +25,62 @@ define( initialize: function (options) { this.profileCollection = options.profileCollection; - - this.availableCollection = new Backbone.Collection(this.model.get('available')); - this.availableCollection.comparator = function (model) { return -model.get('weight'); }; - this.availableCollection.sort(); - - this.allowedCollection = new Backbone.Collection(this.model.get('allowed')); - this.allowedCollection.comparator = function (model) { return -model.get('weight'); }; - this.allowedCollection.sort(); - this.allowedCollection.comparator = undefined; + + this.allowedCollection = new Backbone.Collection(_.toArray(this.model.get('items')).reverse()); }, - onRender: function() { - var listViewAvailable = new BackboneSortableCollectionView({ - el : this.ui.available, - modelView : EditQualityProfileItemView, - selectable: false, - sortable : false, - collection: this.availableCollection - }); - - var listViewAllowed = new BackboneSortableCollectionView({ - el : this.ui.allowed, - modelView : EditQualityProfileItemView, - selectable: false, - sortable : true, + onRender: function() { + var MyCollectionView = BackboneSortableCollectionView.extend({ + events : { + // Backbone.CollectionView used mousedown for the click event, which interferes with the sortable. + "click li, td" : "_listItem_onMousedown", + "dblclick li, td" : "_listItem_onDoubleClick", + "click" : "_listBackground_onClick", + "click ul.collection-list, table.collection-list" : "_listBackground_onClick", + "keydown" : "_onKeydown" + } + }); + var listViewAllowed = new MyCollectionView({ + el : this.ui.allowed, + modelView : EditQualityProfileItemView, + selectable : true, + selectMultiple : true, + clickToSelect : true, + clickToToggle : true, + sortable : true, sortableOptions : { handle: '.x-drag-handle' }, collection : this.allowedCollection }); - listViewAvailable.render(); + listViewAllowed.setSelectedModels(this.allowedCollection.filter(function(item) { return item.get('allowed') === true; })); + listViewAllowed.render(); - this.listenTo(listViewAvailable, 'doubleClick', this._moveQuality); - this.listenTo(listViewAllowed, 'doubleClick', this._moveQuality); - - this.listenTo(listViewAvailable, 'moveClicked', this._moveQuality); - this.listenTo(listViewAllowed, 'moveClicked', this._moveQuality); - + this.listenTo(listViewAllowed, 'selectionChanged', this._selectionChanged); this.listenTo(listViewAllowed, 'sortStop', this._updateModel); }, - - _moveQuality: function (event) { - - var quality; - var qualityId = event.get('id'); + + _selectionChanged: function(newSelectedModels, oldSelectedModels) { + var addedModels = _.difference(newSelectedModels, oldSelectedModels); + var removeModels = _.difference(oldSelectedModels, newSelectedModels); - if (this.availableCollection.get(qualityId)) { - quality = this.availableCollection.get(qualityId); - var idealIndex = 0; - var idealMismatches = 1000; - // Insert it at the best possible spot. - for (var i = 0; i <= this.allowedCollection.length; i++) { - var mismatches = 0; - for (var j = 0; j < i; j++) { - if (this.allowedCollection.at(j).get('weight') < quality.get('weight')) - mismatches++; - } - for (j = i; j < this.allowedCollection.length; j++) { - if (this.allowedCollection.at(j).get('weight') > quality.get('weight')) - mismatches++; - } - if (mismatches <= idealMismatches) { - idealIndex = i; - idealMismatches = mismatches; - } - } - - this.availableCollection.remove(quality); - this.allowedCollection.add(quality, {at: idealIndex}); - } - else if (this.allowedCollection.get(qualityId)) { - quality = this.allowedCollection.get(qualityId); - - this.allowedCollection.remove(quality); - this.availableCollection.add(quality); - } - else { - throw 'couldnt find quality id ' + qualityId; - } + _.each(removeModels, function(item) { item.set('allowed', false); }); + _.each(addedModels, function(item) { item.set('allowed', true); }); this._updateModel(); }, _updateModel: function() { - this.model.set('available', this.availableCollection.toJSON().reverse()); - this.model.set('allowed', this.allowedCollection.toJSON().reverse()); + this.model.set('items', this.allowedCollection.toJSON().reverse()); this.render(); }, _saveQualityProfile: function () { var self = this; - var cutoff = _.findWhere(this.model.get('allowed'), { id: parseInt(this.ui.cutoff.val(), 10)}); + var cutoff = _.findWhere(_.pluck(this.model.get('items'), 'quality'), { id: parseInt(self.ui.cutoff.val(), 10)}); this.model.set('cutoff', cutoff); var promise = this.model.save(); diff --git a/src/UI/Settings/Quality/Profile/EditQualityProfileViewTemplate.html b/src/UI/Settings/Quality/Profile/EditQualityProfileViewTemplate.html index e905b9b4c..5603f9221 100644 --- a/src/UI/Settings/Quality/Profile/EditQualityProfileViewTemplate.html +++ b/src/UI/Settings/Quality/Profile/EditQualityProfileViewTemplate.html @@ -18,8 +18,10 @@
@@ -30,11 +32,6 @@
-

Available

-
    -
-
-

Allowed diff --git a/src/UI/Settings/Quality/quality.less b/src/UI/Settings/Quality/quality.less index de383c735..9a5b65cd9 100644 --- a/src/UI/Settings/Quality/quality.less +++ b/src/UI/Settings/Quality/quality.less @@ -36,7 +36,7 @@ } } -ul.available-list, ul.allowed-list { +ul.allowed-list { .user-select(none); min-height: 100px; @@ -52,51 +52,41 @@ ul.available-list, ul.allowed-list { border: 1px solid #AAA; border-radius: 4px; /* may need vendor varients */ background: #FAFAFA; - cursor: default; + cursor: pointer; - &:hover { - border-color: #888; - background: #EEE; + .quality-label { + color: #CCC; } - - .drag-handle, .move-left-handle, .move-right-handle { - opacity: 0.0; + .drag-handle, .select-handle { + opacity: 0.2; line-height: 20px; cursor: pointer; } - - .move-handle { + + .drag-handle:hover { + opacity: 1.0; cursor: pointer; } } -} - -ul.available-list li { - .move-right-handle { - opacity: 0.2; - } - - .drag-handle { - display: none; - } - - &:hover .move-right-handle { - opacity: 1.0; - } -} - -ul.allowed-list li { - .drag-handle, .move-left-handle { - opacity: 0.2; - } - .drag-handle:hover { - opacity: 1.0; - cursor: pointer; + li.selected { + .select-handle { + opacity: 1.0; + cursor: pointer; + } + + .quality-label { + color: #444; + } } - &:hover .move-left-handle { - opacity: 1.0; + li:hover { + border-color: #888; + background: #EEE; + + .select-handle { + opacity: 0.5; + } } }