diff --git a/ErsatzTV.Application/Scheduling/Commands/UpdateDeco.cs b/ErsatzTV.Application/Scheduling/Commands/UpdateDeco.cs index 5c470fb7..d01b2da5 100644 --- a/ErsatzTV.Application/Scheduling/Commands/UpdateDeco.cs +++ b/ErsatzTV.Application/Scheduling/Commands/UpdateDeco.cs @@ -4,6 +4,15 @@ using ErsatzTV.Core.Domain.Scheduling; namespace ErsatzTV.Application.Scheduling; +public record UpdateDecoBreakContent( + int Id, + ProgramScheduleItemCollectionType CollectionType, + int? CollectionId, + int? MediaItemId, + int? MultiCollectionId, + int? SmartCollectionId, + DecoBreakPlacement Placement); + public record UpdateDeco( int DecoId, int DecoGroupId, @@ -23,5 +32,6 @@ public record UpdateDeco( int? DeadAirFallbackMediaItemId, int? DeadAirFallbackMultiCollectionId, int? DeadAirFallbackSmartCollectionId, - DecoMode BreakContentMode) + DecoMode BreakContentMode, + List BreakContent) : IRequest>; diff --git a/ErsatzTV.Application/Scheduling/Commands/UpdateDecoHandler.cs b/ErsatzTV.Application/Scheduling/Commands/UpdateDecoHandler.cs index 77fa7424..fcb0aaec 100644 --- a/ErsatzTV.Application/Scheduling/Commands/UpdateDecoHandler.cs +++ b/ErsatzTV.Application/Scheduling/Commands/UpdateDecoHandler.cs @@ -63,6 +63,43 @@ public class UpdateDecoHandler(IDbContextFactory dbContextFactory) // break content existing.BreakContentMode = request.BreakContentMode; + var toAdd = request.BreakContent.Filter(bc => bc.Id < 1).ToList(); + var toRemove = existing.BreakContent.Filter(bc => request.BreakContent.All(bc2 => bc2.Id != bc.Id)).ToList(); + var toUpdate = request.BreakContent.Except(toAdd).ToList(); + + foreach (DecoBreakContent remove in toRemove) + { + existing.BreakContent.Remove(remove); + } + + foreach (UpdateDecoBreakContent add in toAdd) + { + existing.BreakContent.Add( + new DecoBreakContent + { + CollectionType = add.CollectionType, + CollectionId = add.CollectionId, + MediaItemId = add.MediaItemId, + MultiCollectionId = add.MultiCollectionId, + SmartCollectionId = add.SmartCollectionId, + Placement = add.Placement + }); + } + + foreach (UpdateDecoBreakContent update in toUpdate) + { + Option maybeExisting = existing.BreakContent.Find(bc => bc.Id == update.Id); + foreach (DecoBreakContent bc in maybeExisting) + { + bc.CollectionType = update.CollectionType; + bc.CollectionId = update.CollectionId; + bc.MediaItemId = update.MediaItemId; + bc.MultiCollectionId = update.MultiCollectionId; + bc.SmartCollectionId = update.SmartCollectionId; + bc.Placement = update.Placement; + } + } + await dbContext.SaveChangesAsync(); return Mapper.ProjectToViewModel(existing); @@ -76,6 +113,7 @@ public class UpdateDecoHandler(IDbContextFactory dbContextFactory) TvContext dbContext, UpdateDeco request) => dbContext.Decos + .Include(d => d.BreakContent) .SelectOneAsync(d => d.Id, d => d.Id == request.DecoId) .Map(o => o.ToValidation("Deco does not exist")); diff --git a/ErsatzTV.Application/Scheduling/DecoBreakContentViewModel.cs b/ErsatzTV.Application/Scheduling/DecoBreakContentViewModel.cs new file mode 100644 index 00000000..d6a7525a --- /dev/null +++ b/ErsatzTV.Application/Scheduling/DecoBreakContentViewModel.cs @@ -0,0 +1,15 @@ +using ErsatzTV.Application.MediaCollections; +using ErsatzTV.Application.MediaItems; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Domain.Scheduling; + +namespace ErsatzTV.Application.Scheduling; + +public record DecoBreakContentViewModel( + int Id, + ProgramScheduleItemCollectionType CollectionType, + MediaCollectionViewModel Collection, + NamedMediaItemViewModel MediaItem, + MultiCollectionViewModel MultiCollection, + SmartCollectionViewModel SmartCollection, + DecoBreakPlacement Placement); diff --git a/ErsatzTV.Application/Scheduling/DecoViewModel.cs b/ErsatzTV.Application/Scheduling/DecoViewModel.cs index 995af399..6cdf1322 100644 --- a/ErsatzTV.Application/Scheduling/DecoViewModel.cs +++ b/ErsatzTV.Application/Scheduling/DecoViewModel.cs @@ -22,4 +22,5 @@ public record DecoViewModel( int? DeadAirFallbackMediaItemId, int? DeadAirFallbackMultiCollectionId, int? DeadAirFallbackSmartCollectionId, - DecoMode BreakContentMode); + DecoMode BreakContentMode, + List BreakContent); diff --git a/ErsatzTV.Application/Scheduling/Mapper.cs b/ErsatzTV.Application/Scheduling/Mapper.cs index 065db2fd..84898c9c 100644 --- a/ErsatzTV.Application/Scheduling/Mapper.cs +++ b/ErsatzTV.Application/Scheduling/Mapper.cs @@ -69,7 +69,18 @@ internal static class Mapper deco.DeadAirFallbackMediaItemId, deco.DeadAirFallbackMultiCollectionId, deco.DeadAirFallbackSmartCollectionId, - deco.BreakContentMode); + deco.BreakContentMode, + deco.BreakContent.Map(ProjectToViewModel).ToList()); + + internal static DecoBreakContentViewModel ProjectToViewModel(DecoBreakContent decoBreakContent) => + new( + decoBreakContent.Id, + decoBreakContent.CollectionType, + decoBreakContent.Collection is not null ? MediaCollections.Mapper.ProjectToViewModel(decoBreakContent.Collection) : null, + null, // not supporting show, season, artist, etc. yet + decoBreakContent.MultiCollection is not null ? MediaCollections.Mapper.ProjectToViewModel(decoBreakContent.MultiCollection) : null, + decoBreakContent.SmartCollection is not null ? MediaCollections.Mapper.ProjectToViewModel(decoBreakContent.SmartCollection) : null, + decoBreakContent.Placement); internal static DecoTemplateGroupViewModel ProjectToViewModel(DecoTemplateGroup decoTemplateGroup) => new(decoTemplateGroup.Id, decoTemplateGroup.Name, decoTemplateGroup.DecoTemplates.Count); diff --git a/ErsatzTV.Application/Scheduling/Queries/GetDecoByIdHandler.cs b/ErsatzTV.Application/Scheduling/Queries/GetDecoByIdHandler.cs index 0353c588..d1188235 100644 --- a/ErsatzTV.Application/Scheduling/Queries/GetDecoByIdHandler.cs +++ b/ErsatzTV.Application/Scheduling/Queries/GetDecoByIdHandler.cs @@ -11,6 +11,14 @@ public class GetDecoByIdHandler(IDbContextFactory dbContextFactory) { await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); return await dbContext.Decos + .Include(d => d.BreakContent) + .ThenInclude(bc => bc.Collection) + .Include(d => d.BreakContent) + .ThenInclude(bc => bc.MediaItem) + .Include(d => d.BreakContent) + .ThenInclude(bc => bc.MultiCollection) + .Include(d => d.BreakContent) + .ThenInclude(bc => bc.SmartCollection) .SelectOneAsync(b => b.Id, b => b.Id == request.DecoId) .MapT(Mapper.ProjectToViewModel); } diff --git a/ErsatzTV.Application/Scheduling/Queries/GetDecosByDecoGroupIdHandler.cs b/ErsatzTV.Application/Scheduling/Queries/GetDecosByDecoGroupIdHandler.cs index 038a0ab9..50f520f2 100644 --- a/ErsatzTV.Application/Scheduling/Queries/GetDecosByDecoGroupIdHandler.cs +++ b/ErsatzTV.Application/Scheduling/Queries/GetDecosByDecoGroupIdHandler.cs @@ -12,6 +12,7 @@ public class GetDecosByDecoGroupIdHandler(IDbContextFactory dbContext await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); List decos = await dbContext.Decos + .Include(d => d.BreakContent) .Filter(b => b.DecoGroupId == request.DecoGroupId) .AsNoTracking() .ToListAsync(cancellationToken); diff --git a/ErsatzTV/Pages/DecoEditor.razor b/ErsatzTV/Pages/DecoEditor.razor index af0ff372..75c50309 100644 --- a/ErsatzTV/Pages/DecoEditor.razor +++ b/ErsatzTV/Pages/DecoEditor.razor @@ -308,7 +308,7 @@ @@ -487,16 +487,27 @@ : null, BreakContentMode = deco.BreakContentMode, - BreakContent = [] + BreakContent = deco.BreakContent.Map(ProjectToEditViewModel).ToList() }; } } + private static DecoBreakContentEditViewModel ProjectToEditViewModel(DecoBreakContentViewModel vm) => + new() + { + Id = vm.Id, + CollectionType = vm.CollectionType, + Collection = vm.Collection, + MediaItem = vm.MediaItem, + MultiCollection = vm.MultiCollection, + SmartCollection = vm.SmartCollection, + Placement = vm.Placement + }; + private void AddBreakContent() { var item = new DecoBreakContentEditViewModel { - Index = _deco.BreakContent.Map(i => i.Index).DefaultIfEmpty().Max() + 1, CollectionType = ProgramScheduleItemCollectionType.Collection, Collection = null, Placement = DecoBreakPlacement.BlockStart @@ -512,6 +523,10 @@ private async Task SaveChanges() { + var breakContent = _deco.BreakContent + .Map(vm => new UpdateDecoBreakContent(vm.Id, vm.CollectionType, vm.Collection?.Id, vm.MediaItem?.MediaItemId, vm.MultiCollection?.Id, vm.SmartCollection?.Id, vm.Placement)) + .ToList(); + var request = new UpdateDeco( Id, _deco.DecoGroupId, @@ -531,7 +546,8 @@ _deco.DeadAirFallbackMediaItem?.MediaItemId, _deco.DeadAirFallbackMultiCollection?.Id, _deco.DeadAirFallbackSmartCollection?.Id, - _deco.BreakContentMode); + _deco.BreakContentMode, + breakContent); Seq errorMessages = await Mediator .Send(request, _cts.Token) diff --git a/ErsatzTV/ViewModels/DecoBreakContentEditViewModel.cs b/ErsatzTV/ViewModels/DecoBreakContentEditViewModel.cs index cc4e65de..aa94b3ff 100644 --- a/ErsatzTV/ViewModels/DecoBreakContentEditViewModel.cs +++ b/ErsatzTV/ViewModels/DecoBreakContentEditViewModel.cs @@ -13,7 +13,6 @@ public class DecoBreakContentEditViewModel : INotifyPropertyChanged private ProgramScheduleItemCollectionType _collectionType; public int Id { get; set; } - public int Index { get; set; } public ProgramScheduleItemCollectionType CollectionType {