Browse Source

add multiple mode to schedule items (#2163)

pull/2164/head
Jason Dove 4 weeks ago committed by GitHub
parent
commit
54be3761dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 7
      CHANGELOG.md
  2. 1
      ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs
  3. 1
      ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs
  4. 14
      ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs
  5. 1
      ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs
  6. 1
      ErsatzTV.Application/ProgramSchedules/Mapper.cs
  7. 8
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs
  8. 4
      ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs
  9. 1
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerMultipleTests.cs
  10. 17
      ErsatzTV.Core/Domain/MultipleMode.cs
  11. 2
      ErsatzTV.Core/Domain/ProgramScheduleItemMultiple.cs
  12. 33
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerMultiple.cs
  13. 5920
      ErsatzTV.Infrastructure.MySql/Migrations/20250718133418_Add_ProgramScheduleItemMultipleMode.Designer.cs
  14. 31
      ErsatzTV.Infrastructure.MySql/Migrations/20250718133418_Add_ProgramScheduleItemMultipleMode.cs
  15. 3
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  16. 5759
      ErsatzTV.Infrastructure.Sqlite/Migrations/20250718133309_Add_ProgramScheduleItemMultipleMode.Designer.cs
  17. 31
      ErsatzTV.Infrastructure.Sqlite/Migrations/20250718133309_Add_ProgramScheduleItemMultipleMode.cs
  18. 3
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  19. 2
      ErsatzTV/Pages/Artist.razor
  20. 58
      ErsatzTV/Pages/ScheduleItemsEditor.razor
  21. 2
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  22. 2
      ErsatzTV/Pages/TelevisionSeasonList.razor
  23. 5
      ErsatzTV/Validators/ProgramScheduleItemEditViewModelValidator.cs
  24. 2
      ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

7
CHANGELOG.md

@ -106,10 +106,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -106,10 +106,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Split main `Settings` page into multiple pages
- Update UI layout on all pages to be less cramped and to work better on mobile
- Add CPU and Video Controller info to `Troubleshooting` > `General` output
- Expand special zero-count case for `Multiple` playout mode with playlists
- This configuration will automatically maintain the multiple count so that it is equal to the number of items in each playlist item
- This configuration should be used if you want to play every media item in a playlist item exactly once before advancing
- Enable write-ahead logging (WAL) mode on SQLite databases
- Add `Multiple Mode` option to schedule items editor and remove support for count values of zero
- `Count`: same behavior as before, requires a number of media items to play and will always schedule the same number
- `Collection Size`: similar to count of zero before, will play all media items from the collection before continuing to the next schedule item
- `Playlist Item Size`: will play all media items from the current playlist item before continuing to the next schedule item
### Fixed
- Fix QSV acceleration in docker with older Intel devices

1
ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs

@ -18,6 +18,7 @@ public record AddProgramScheduleItem( @@ -18,6 +18,7 @@ public record AddProgramScheduleItem(
int? PlaylistId,
PlaybackOrder PlaybackOrder,
FillWithGroupMode FillWithGroupMode,
MultipleMode MultipleMode,
int? MultipleCount,
TimeSpan? PlayoutDuration,
TailMode TailMode,

1
ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs

@ -16,6 +16,7 @@ public interface IProgramScheduleItemRequest @@ -16,6 +16,7 @@ public interface IProgramScheduleItemRequest
PlayoutMode PlayoutMode { get; }
PlaybackOrder PlaybackOrder { get; }
FillWithGroupMode FillWithGroupMode { get; }
MultipleMode MultipleMode { get; }
int? MultipleCount { get; }
TimeSpan? PlayoutDuration { get; }
TailMode TailMode { get; }

14
ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs

@ -71,10 +71,17 @@ public abstract class ProgramScheduleItemCommandBase @@ -71,10 +71,17 @@ public abstract class ProgramScheduleItemCommandBase
case PlayoutMode.One:
break;
case PlayoutMode.Multiple:
if (item.MultipleCount.GetValueOrDefault() < 0)
if (item.MultipleMode is MultipleMode.PlaylistItemSize &&
item.CollectionType is not ProgramScheduleItemCollectionType.Playlist)
{
return BaseError.New(
"[MultipleCount] must be greater than or equal to 0 for playout mode 'multiple'");
"[MultipleMode] cannot be [PlaylistItemSize] when collection is not a playlist");
}
if (item.MultipleMode is MultipleMode.Count && item.MultipleCount.GetValueOrDefault() < 1)
{
return BaseError.New(
"[MultipleCount] must be greater than 0 for playout mode 'multiple / count'");
}
break;
@ -248,7 +255,8 @@ public abstract class ProgramScheduleItemCommandBase @@ -248,7 +255,8 @@ public abstract class ProgramScheduleItemCommandBase
PlaylistId = item.PlaylistId,
PlaybackOrder = item.PlaybackOrder,
FillWithGroupMode = item.FillWithGroupMode,
Count = item.MultipleCount.GetValueOrDefault(),
MultipleMode = item.MultipleMode,
Count = item.MultipleMode is MultipleMode.Count ? item.MultipleCount.GetValueOrDefault() : 0,
CustomTitle = item.CustomTitle,
GuideMode = item.GuideMode,
PreRollFillerId = item.PreRollFillerId,

1
ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs

@ -18,6 +18,7 @@ public record ReplaceProgramScheduleItem( @@ -18,6 +18,7 @@ public record ReplaceProgramScheduleItem(
int? PlaylistId,
PlaybackOrder PlaybackOrder,
FillWithGroupMode FillWithGroupMode,
MultipleMode MultipleMode,
int? MultipleCount,
TimeSpan? PlayoutDuration,
TailMode TailMode,

1
ErsatzTV.Application/ProgramSchedules/Mapper.cs

@ -155,6 +155,7 @@ internal static class Mapper @@ -155,6 +155,7 @@ internal static class Mapper
},
multiple.PlaybackOrder,
multiple.FillWithGroupMode,
multiple.MultipleMode,
multiple.Count,
multiple.CustomTitle,
multiple.GuideMode,

8
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs

@ -23,6 +23,7 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode @@ -23,6 +23,7 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
NamedMediaItemViewModel mediaItem,
PlaybackOrder playbackOrder,
FillWithGroupMode fillWithGroupMode,
MultipleMode multipleMode,
int count,
string customTitle,
GuideMode guideMode,
@ -61,8 +62,13 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode @@ -61,8 +62,13 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
preferredAudioLanguageCode,
preferredAudioTitle,
preferredSubtitleLanguageCode,
subtitleMode) =>
subtitleMode)
{
MultipleMode = multipleMode;
Count = count;
}
public MultipleMode MultipleMode { get; set; }
public int Count { get; }
}

4
ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs

@ -1503,7 +1503,7 @@ public class PlayoutBuilderTests @@ -1503,7 +1503,7 @@ public class PlayoutBuilderTests
}
[Test]
public async Task Auto_Zero_MultipleCount()
public async Task Multiple_Mode_Collection_Size()
{
var collectionOne = new Collection
{
@ -1543,6 +1543,7 @@ public class PlayoutBuilderTests @@ -1543,6 +1543,7 @@ public class PlayoutBuilderTests
CollectionId = collectionOne.Id,
StartTime = null,
Count = 0,
MultipleMode = MultipleMode.CollectionSize,
PlaybackOrder = PlaybackOrder.Chronological
},
new ProgramScheduleItemMultiple
@ -1553,6 +1554,7 @@ public class PlayoutBuilderTests @@ -1553,6 +1554,7 @@ public class PlayoutBuilderTests
CollectionId = collectionTwo.Id,
StartTime = null,
Count = 0,
MultipleMode = MultipleMode.CollectionSize,
PlaybackOrder = PlaybackOrder.Chronological
}
};

1
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerMultipleTests.cs

@ -33,6 +33,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase @@ -33,6 +33,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
TailFiller = null,
FallbackFiller = null,
Count = 0,
MultipleMode = MultipleMode.CollectionSize,
CustomTitle = "CustomTitle"
};

17
ErsatzTV.Core/Domain/MultipleMode.cs

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
namespace ErsatzTV.Core.Domain;
public enum MultipleMode
{
// static integer count
Count = 0,
// current size of the collection
CollectionSize = 1,
// current size of the playlist item
PlaylistItemSize = 2,
// from one item (not a multi-episode) to however many multi-episodes are linked together
// is this limited to chronological and season/episode?
MultiEpisodeSize = 3
}

2
ErsatzTV.Core/Domain/ProgramScheduleItemMultiple.cs

@ -2,5 +2,7 @@ @@ -2,5 +2,7 @@
public class ProgramScheduleItemMultiple : ProgramScheduleItem
{
public MultipleMode MultipleMode { get; set; }
public int Count { get; set; }
}

33
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerMultiple.cs

@ -42,22 +42,25 @@ public class PlayoutModeSchedulerMultiple : PlayoutModeSchedulerBase<ProgramSche @@ -42,22 +42,25 @@ public class PlayoutModeSchedulerMultiple : PlayoutModeSchedulerBase<ProgramSche
if (nextState.MultipleRemaining == 0)
{
// playlist count of zero means play all media items in the current playlist item
if (contentEnumerator is PlaylistEnumerator { CurrentEnumeratorPlayAll: true } playlistEnumerator)
switch (scheduleItem.MultipleMode)
{
nextState = nextState with
{
MultipleRemaining = playlistEnumerator
.ChildEnumerators[playlistEnumerator.EnumeratorIndex]
.Enumerator.Count
};
}
else
{
nextState = nextState with
{
MultipleRemaining = _collectionItemCount[CollectionKey.ForScheduleItem(scheduleItem)]
};
case MultipleMode.CollectionSize:
nextState = nextState with
{
MultipleRemaining = _collectionItemCount[CollectionKey.ForScheduleItem(scheduleItem)]
};
break;
case MultipleMode.PlaylistItemSize:
if (contentEnumerator is PlaylistEnumerator { CurrentEnumeratorPlayAll: true } playlistEnumerator)
{
nextState = nextState with
{
MultipleRemaining = playlistEnumerator
.ChildEnumerators[playlistEnumerator.EnumeratorIndex]
.Enumerator.Count
};
}
break;
}
}

5920
ErsatzTV.Infrastructure.MySql/Migrations/20250718133418_Add_ProgramScheduleItemMultipleMode.Designer.cs generated

File diff suppressed because it is too large Load Diff

31
ErsatzTV.Infrastructure.MySql/Migrations/20250718133418_Add_ProgramScheduleItemMultipleMode.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.MySql.Migrations
{
/// <inheritdoc />
public partial class Add_ProgramScheduleItemMultipleMode : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "MultipleMode",
table: "ProgramScheduleMultipleItem",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.Sql(@"UPDATE `ProgramScheduleMultipleItem` SET `MultipleMode` = 1 WHERE `Count` = 0");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MultipleMode",
table: "ProgramScheduleMultipleItem");
}
}
}

3
ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs

@ -3488,6 +3488,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -3488,6 +3488,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("MultipleMode")
.HasColumnType("int");
b.ToTable("ProgramScheduleMultipleItem", (string)null);
});

5759
ErsatzTV.Infrastructure.Sqlite/Migrations/20250718133309_Add_ProgramScheduleItemMultipleMode.Designer.cs generated

File diff suppressed because it is too large Load Diff

31
ErsatzTV.Infrastructure.Sqlite/Migrations/20250718133309_Add_ProgramScheduleItemMultipleMode.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
{
/// <inheritdoc />
public partial class Add_ProgramScheduleItemMultipleMode : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "MultipleMode",
table: "ProgramScheduleMultipleItem",
type: "INTEGER",
nullable: false,
defaultValue: 0);
migrationBuilder.Sql(@"UPDATE `ProgramScheduleMultipleItem` SET `MultipleMode` = 1 WHERE `Count` = 0");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MultipleMode",
table: "ProgramScheduleMultipleItem");
}
}
}

3
ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs

@ -3327,6 +3327,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -3327,6 +3327,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.Property<int>("Count")
.HasColumnType("INTEGER");
b.Property<int>("MultipleMode")
.HasColumnType("INTEGER");
b.ToTable("ProgramScheduleMultipleItem", (string)null);
});

2
ErsatzTV/Pages/Artist.razor

@ -286,7 +286,7 @@ @@ -286,7 +286,7 @@
DialogResult result = await dialog.Result;
if (result is { Canceled: false, Data: ProgramScheduleViewModel schedule })
{
await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, null, PlayoutMode.One, ProgramScheduleItemCollectionType.Artist, null, null, null, ArtistId, null, PlaybackOrder.Shuffle, FillWithGroupMode.None, null, null, TailMode.None, null, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, null, PlayoutMode.One, ProgramScheduleItemCollectionType.Artist, null, null, null, ArtistId, null, PlaybackOrder.Shuffle, FillWithGroupMode.None, MultipleMode.Count, null, null, TailMode.None, null, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
NavigationManager.NavigateTo($"schedules/{schedule.Id}/items");
}
}

58
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -21,9 +21,21 @@ @@ -21,9 +21,21 @@
{
string start = _selectedItem.StartType == StartType.Fixed ? _selectedItem.StartTime == null ? string.Empty : DateTime.Today.Add(_selectedItem.StartTime.Value).ToShortTimeString() : "Dynamic";
var mode = _selectedItem.PlayoutMode.ToString();
@if (_selectedItem.PlayoutMode == PlayoutMode.Multiple && _selectedItem.MultipleCount.HasValue)
@if (_selectedItem.PlayoutMode is PlayoutMode.Multiple)
{
mode += $" ({_selectedItem.MultipleCount})";
switch (_selectedItem.MultipleMode)
{
case MultipleMode.CollectionSize:
mode = "Collection Size";
break;
case MultipleMode.PlaylistItemSize:
mode = "Playlist Item Size";
break;
case MultipleMode.Count:
default:
mode += $" ({_selectedItem.MultipleCount})";
break;
}
}
var result = $"{_schedule.Name} ({start} - {_selectedItem.CollectionName} - {mode})";
@ -88,10 +100,25 @@ @@ -88,10 +100,25 @@
</MudTd>
<MudTd DataLabel="Playout Mode">
<MudText Typo="@Typo.body2">
@context.PlayoutMode
@if (context.PlayoutMode == PlayoutMode.Multiple && context.MultipleCount.HasValue)
@if (context.PlayoutMode is PlayoutMode.Multiple)
{
switch (context.MultipleMode)
{
case MultipleMode.CollectionSize:
@:Collection Size
break;
case MultipleMode.PlaylistItemSize:
@:Playlist Item Size
break;
case MultipleMode.Count:
default:
@($"Multiple ({context.MultipleCount})")
break;
}
}
else
{
@($" ({context.MultipleCount})")
@context.PlayoutMode
}
</MudText>
</MudTd>
@ -346,13 +373,29 @@ @@ -346,13 +373,29 @@
<MudSelectItem Value="PlayoutMode.Duration">Duration</MudSelectItem>
</MudSelect>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Multiple Mode</MudText>
</div>
<MudSelect @bind-Value="@_selectedItem.MultipleMode" For="@(() => _selectedItem.MultipleMode)">
<MudSelectItem Value="MultipleMode.Count">Count</MudSelectItem>
@if (_selectedItem.CollectionType is not ProgramScheduleItemCollectionType.Playlist)
{
<MudSelectItem Value="MultipleMode.CollectionSize">Collection Size</MudSelectItem>
}
else
{
<MudSelectItem Value="MultipleMode.PlaylistItemSize">Playlist Item Size</MudSelectItem>
}
</MudSelect>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Multiple Count</MudText>
</div>
<MudTextField @bind-Value="@_selectedItem.MultipleCount"
For="@(() => _selectedItem.MultipleCount)"
Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Multiple)"/>
Disabled="@(_selectedItem.PlayoutMode is not PlayoutMode.Multiple || _selectedItem.MultipleMode is not MultipleMode.Count)"/>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
@ -723,6 +766,7 @@ @@ -723,6 +766,7 @@
switch (item)
{
case ProgramScheduleItemMultipleViewModel multiple:
result.MultipleMode = multiple.MultipleMode;
result.MultipleCount = multiple.Count;
break;
case ProgramScheduleItemDurationViewModel duration:
@ -786,6 +830,7 @@ @@ -786,6 +830,7 @@
PreferredSubtitleLanguageCode = item.PreferredSubtitleLanguageCode,
SubtitleMode = item.SubtitleMode,
MultipleMode = item.MultipleMode,
MultipleCount = item.MultipleCount,
PlayoutDuration = item.PlayoutDuration,
TailMode = item.TailMode,
@ -841,6 +886,7 @@ @@ -841,6 +886,7 @@
item.Playlist?.Id,
item.PlaybackOrder,
item.FillWithGroupMode,
item.MultipleMode,
item.MultipleCount,
item.PlayoutDuration,
item.TailMode,

2
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -259,7 +259,7 @@ @@ -259,7 +259,7 @@
DialogResult result = await dialog.Result;
if (result is { Canceled: false, Data: ProgramScheduleViewModel schedule })
{
await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, null, null, SeasonId, null, PlaybackOrder.Shuffle, FillWithGroupMode.None, null, null, TailMode.None, null, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, null, null, SeasonId, null, PlaybackOrder.Shuffle, FillWithGroupMode.None, MultipleMode.Count, null, null, TailMode.None, null, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
NavigationManager.NavigateTo($"schedules/{schedule.Id}/items");
}
}

2
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -251,7 +251,7 @@ @@ -251,7 +251,7 @@
DialogResult result = await dialog.Result;
if (result is { Canceled: false, Data: ProgramScheduleViewModel schedule })
{
await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, null, null, ShowId, null, PlaybackOrder.Shuffle, FillWithGroupMode.None, null, null, TailMode.None, null, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
await Mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, null, null, ShowId, null, PlaybackOrder.Shuffle, FillWithGroupMode.None, MultipleMode.Count, null, null, TailMode.None, null, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
NavigationManager.NavigateTo($"schedules/{schedule.Id}/items");
}
}

5
ErsatzTV/Validators/ProgramScheduleItemEditViewModelValidator.cs

@ -13,7 +13,10 @@ public class ProgramScheduleItemEditViewModelValidator : AbstractValidator<Progr @@ -13,7 +13,10 @@ public class ProgramScheduleItemEditViewModelValidator : AbstractValidator<Progr
() => RuleFor(i => i.StartTime).NotNull());
When(
i => i.PlayoutMode == PlayoutMode.Multiple,
() => RuleFor(i => i.MultipleCount).NotNull().GreaterThanOrEqualTo(0));
() =>
{
When(i => i.MultipleMode is MultipleMode.Count, () => RuleFor(i => i.MultipleCount).NotNull().GreaterThan(0));
});
When(
i => i.PlayoutMode == PlayoutMode.Duration,
() =>

2
ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

@ -104,6 +104,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged @@ -104,6 +104,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
public PlaybackOrder PlaybackOrder { get; set; }
public MultipleMode MultipleMode { get; set; }
public int? MultipleCount
{
get => PlayoutMode == PlayoutMode.Multiple ? _multipleCount : null;

Loading…
Cancel
Save