Browse Source

improve schedule editor performance (#1240)

* rename

* async cleanup

* use autocomplete fields in schedule items editor
pull/1242/head
Jason Dove 2 years ago committed by GitHub
parent
commit
24f7544c9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 2
      ErsatzTV.Application/Filler/Queries/GetAllFillerPresetsHandler.cs
  3. 2
      ErsatzTV.Application/MediaCollections/Queries/GetAllCollectionsHandler.cs
  4. 2
      ErsatzTV.Application/MediaCollections/Queries/GetAllMultiCollectionsHandler.cs
  5. 2
      ErsatzTV.Application/MediaCollections/Queries/GetAllSmartCollectionsHandler.cs
  6. 5
      ErsatzTV.Application/Search/Queries/SearchArtists.cs
  7. 45
      ErsatzTV.Application/Search/Queries/SearchArtistsHandler.cs
  8. 5
      ErsatzTV.Application/Search/Queries/SearchCollections.cs
  9. 29
      ErsatzTV.Application/Search/Queries/SearchCollectionsHandler.cs
  10. 5
      ErsatzTV.Application/Search/Queries/SearchMultiCollections.cs
  11. 29
      ErsatzTV.Application/Search/Queries/SearchMultiCollectionsHandler.cs
  12. 5
      ErsatzTV.Application/Search/Queries/SearchSmartCollections.cs
  13. 29
      ErsatzTV.Application/Search/Queries/SearchSmartCollectionsHandler.cs
  14. 5
      ErsatzTV.Application/Search/Queries/SearchTelevisionSeasons.cs
  15. 46
      ErsatzTV.Application/Search/Queries/SearchTelevisionSeasonsHandler.cs
  16. 5
      ErsatzTV.Application/Search/Queries/SearchTelevisionShows.cs
  17. 39
      ErsatzTV.Application/Search/Queries/SearchTelevisionShowsHandler.cs
  18. 228
      ErsatzTV/Pages/ScheduleItemsEditor.razor

2
CHANGELOG.md

@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Remove duplicate items from smart collections before scheduling
- i.e. shows no longer need to be filtered out if search results also include episodes
- Certain multi-collection scenarios may still include duplicates across multiple collections
- Use autocomplete fields for collection searching in schedule items editor
- This greatly improves the editor performance
## [0.7.7-beta] - 2023-04-07
### Added

2
ErsatzTV.Application/Filler/Queries/GetAllFillerPresetsHandler.cs

@ -15,7 +15,7 @@ public class GetAllFillerPresetsHandler : IRequestHandler<GetAllFillerPresets, L @@ -15,7 +15,7 @@ public class GetAllFillerPresetsHandler : IRequestHandler<GetAllFillerPresets, L
GetAllFillerPresets request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.FillerPresets.ToListAsync(cancellationToken)
.Map(presets => presets.Map(ProjectToViewModel).ToList());
}

2
ErsatzTV.Application/MediaCollections/Queries/GetAllCollectionsHandler.cs

@ -15,7 +15,7 @@ public class GetAllCollectionsHandler : IRequestHandler<GetAllCollections, List< @@ -15,7 +15,7 @@ public class GetAllCollectionsHandler : IRequestHandler<GetAllCollections, List<
GetAllCollections request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Collections
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

2
ErsatzTV.Application/MediaCollections/Queries/GetAllMultiCollectionsHandler.cs

@ -15,7 +15,7 @@ public class GetAllMultiCollectionsHandler : IRequestHandler<GetAllMultiCollecti @@ -15,7 +15,7 @@ public class GetAllMultiCollectionsHandler : IRequestHandler<GetAllMultiCollecti
GetAllMultiCollections request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.MultiCollections
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

2
ErsatzTV.Application/MediaCollections/Queries/GetAllSmartCollectionsHandler.cs

@ -15,7 +15,7 @@ public class GetAllSmartCollectionsHandler : IRequestHandler<GetAllSmartCollecti @@ -15,7 +15,7 @@ public class GetAllSmartCollectionsHandler : IRequestHandler<GetAllSmartCollecti
GetAllSmartCollections request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.SmartCollections
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

5
ErsatzTV.Application/Search/Queries/SearchArtists.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
using ErsatzTV.Application.MediaItems;
namespace ErsatzTV.Application.Search;
public record SearchArtists(string Query) : IRequest<List<NamedMediaItemViewModel>>;

45
ErsatzTV.Application/Search/Queries/SearchArtistsHandler.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
using Dapper;
using ErsatzTV.Application.MediaItems;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Search;
public class SearchArtistsHandler : IRequestHandler<SearchArtists, List<NamedMediaItemViewModel>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SearchArtistsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<NamedMediaItemViewModel>> Handle(SearchArtists request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Connection.QueryAsync<Artist>(
@"SELECT Artist.Id, AM.Title FROM Artist
INNER JOIN ArtistMetadata AM on AM.ArtistId = Artist.Id
WHERE AM.Title LIKE @Title
ORDER BY AM.Title
LIMIT 10
COLLATE NOCASE",
new { Title = $"%{request.Query}%" })
.Map(list => list.Bind(a => ToNamedMediaItem(a)).ToList());
}
private static Option<NamedMediaItemViewModel> ToNamedMediaItem(Artist artist)
{
if (string.IsNullOrWhiteSpace(artist.Title))
{
return Option<NamedMediaItemViewModel>.None;
}
return new NamedMediaItemViewModel(artist.Id, artist.Title);
}
public record Artist(int Id, string Title)
{
public Artist() : this(default, default)
{
}
}
}

5
ErsatzTV.Application/Search/Queries/SearchCollections.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
using ErsatzTV.Application.MediaCollections;
namespace ErsatzTV.Application.Search;
public record SearchCollections(string Query) : IRequest<List<MediaCollectionViewModel>>;

29
ErsatzTV.Application/Search/Queries/SearchCollectionsHandler.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
namespace ErsatzTV.Application.Search;
public class SearchCollectionsHandler : IRequestHandler<SearchCollections, List<MediaCollectionViewModel>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SearchCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<MediaCollectionViewModel>> Handle(SearchCollections request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Collections.FromSqlRaw(
@"SELECT * FROM Collection
WHERE Name LIKE {0}
ORDER BY Name
LIMIT 10
COLLATE NOCASE",
$"%{request.Query}%")
.AsNoTracking()
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());
}
}

5
ErsatzTV.Application/Search/Queries/SearchMultiCollections.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
using ErsatzTV.Application.MediaCollections;
namespace ErsatzTV.Application.Search;
public record SearchMultiCollections(string Query) : IRequest<List<MultiCollectionViewModel>>;

29
ErsatzTV.Application/Search/Queries/SearchMultiCollectionsHandler.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
namespace ErsatzTV.Application.Search;
public class SearchMultiCollectionsHandler : IRequestHandler<SearchMultiCollections, List<MultiCollectionViewModel>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SearchMultiCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<MultiCollectionViewModel>> Handle(SearchMultiCollections request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.MultiCollections.FromSqlRaw(
@"SELECT * FROM MultiCollection
WHERE Name LIKE {0}
ORDER BY Name
LIMIT 10
COLLATE NOCASE",
$"%{request.Query}%")
.AsNoTracking()
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());
}
}

5
ErsatzTV.Application/Search/Queries/SearchSmartCollections.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
using ErsatzTV.Application.MediaCollections;
namespace ErsatzTV.Application.Search;
public record SearchSmartCollections(string Query) : IRequest<List<SmartCollectionViewModel>>;

29
ErsatzTV.Application/Search/Queries/SearchSmartCollectionsHandler.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
namespace ErsatzTV.Application.Search;
public class SearchSmartCollectionsHandler : IRequestHandler<SearchSmartCollections, List<SmartCollectionViewModel>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SearchSmartCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<SmartCollectionViewModel>> Handle(SearchSmartCollections request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.SmartCollections.FromSqlRaw(
@"SELECT * FROM SmartCollection
WHERE Name LIKE {0}
ORDER BY Name
LIMIT 10
COLLATE NOCASE",
$"%{request.Query}%")
.AsNoTracking()
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());
}
}

5
ErsatzTV.Application/Search/Queries/SearchTelevisionSeasons.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
using ErsatzTV.Application.MediaItems;
namespace ErsatzTV.Application.Search;
public record SearchTelevisionSeasons(string Query) : IRequest<List<NamedMediaItemViewModel>>;

46
ErsatzTV.Application/Search/Queries/SearchTelevisionSeasonsHandler.cs

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
using Dapper;
using ErsatzTV.Application.MediaItems;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Search;
public class SearchTelevisionSeasonsHandler : IRequestHandler<SearchTelevisionSeasons, List<NamedMediaItemViewModel>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SearchTelevisionSeasonsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<NamedMediaItemViewModel>> Handle(SearchTelevisionSeasons request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Connection.QueryAsync<TelevisionSeason>(
@"SELECT Season.Id, SM2.Title, Season.SeasonNumber FROM Season
INNER JOIN SeasonMetadata SM on Season.Id = SM.SeasonId
INNER JOIN ShowMetadata SM2 on SM2.ShowId = Season.ShowId
WHERE (SM2.Title || ' ' || SM.Title) LIKE @Title
ORDER BY SM2.Title, Season.SeasonNumber
LIMIT 20
COLLATE NOCASE",
new { Title = $"%{request.Query}%" })
.Map(list => list.Map(ToNamedMediaItem).ToList());
}
private static NamedMediaItemViewModel ToNamedMediaItem(TelevisionSeason season) => new(
season.Id,
$"{ShowTitle(season)} ({SeasonTitle(season)})");
private static string ShowTitle(TelevisionSeason season) => $"{season.Title ?? "???"}";
private static string SeasonTitle(TelevisionSeason season) => season.SeasonNumber == 0
? "Specials"
: $"Season {season.SeasonNumber}";
public record TelevisionSeason(int Id, string Title, int SeasonNumber)
{
public TelevisionSeason() : this(default, default, default)
{
}
}
}

5
ErsatzTV.Application/Search/Queries/SearchTelevisionShows.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
using ErsatzTV.Application.MediaItems;
namespace ErsatzTV.Application.Search;
public record SearchTelevisionShows(string Query) : IRequest<List<NamedMediaItemViewModel>>;

39
ErsatzTV.Application/Search/Queries/SearchTelevisionShowsHandler.cs

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
using Dapper;
using ErsatzTV.Application.MediaItems;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Search;
public class SearchTelevisionShowsHandler : IRequestHandler<SearchTelevisionShows, List<NamedMediaItemViewModel>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SearchTelevisionShowsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<NamedMediaItemViewModel>> Handle(SearchTelevisionShows request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Connection.QueryAsync<TelevisionShow>(
@"SELECT Show.Id, SM.Title, SM.Year FROM Show
INNER JOIN ShowMetadata SM on SM.ShowId = Show.Id
WHERE (SM.Title || ' ' || SM.Year) LIKE @Title
ORDER BY SM.Title, SM.Year
LIMIT 10
COLLATE NOCASE",
new { Title = $"%{request.Query}%" })
.Map(list => list.Map(ToNamedMediaItem).ToList());
}
private static NamedMediaItemViewModel ToNamedMediaItem(TelevisionShow show) => new(
show.Id,
$"{show.Title} ({(show.Year.HasValue ? show.Year.Value.ToString() : "???")})");
public record TelevisionShow(int Id, string Title, int? Year)
{
public TelevisionShow() : this(default, default, default)
{
}
}
}

228
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -2,17 +2,16 @@ @@ -2,17 +2,16 @@
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaItems
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.Television
@using ErsatzTV.Application.Watermarks
@using ErsatzTV.Application.Filler
@using System.Globalization
@using ErsatzTV.Core.Domain.Filler
@using ErsatzTV.Application.Artists
@using ErsatzTV.Application.Search
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<ScheduleItemsEditor> _logger
@inject ISnackbar _snackbar
@inject IMediator _mediator
@inject NavigationManager NavigationManager
@inject ILogger<ScheduleItemsEditor> Logger
@inject ISnackbar Snackbar
@inject IMediator Mediator
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudTable Hover="true" Items="_schedule.Items.OrderBy(i => i.Index)" Dense="true" @bind-SelectedItem="_selectedItem">
@ -104,82 +103,86 @@ @@ -104,82 +103,86 @@
</MudSelect>
<MudTimePicker Class="mt-3" Label="Start Time" @bind-Time="@_selectedItem.StartTime" For="@(() => _selectedItem.StartTime)" Disabled="@(_selectedItem.StartType == StartType.Dynamic)"/>
<MudSelect Class="mt-3" Label="Collection Type" @bind-Value="_selectedItem.CollectionType" For="@(() => _selectedItem.CollectionType)">
@foreach (ProgramScheduleItemCollectionType collectionType in Enum.GetValues<ProgramScheduleItemCollectionType>())
{
<MudSelectItem Value="@collectionType">@collectionType</MudSelectItem>
}
<MudSelectItem Value="ProgramScheduleItemCollectionType.Collection">Collection</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionShow">Television Show</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionSeason">Television Season</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.Artist">Artist</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.MultiCollection">Multi Collection</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.SmartCollection">Smart Collection</MudSelectItem>
</MudSelect>
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Collection)
{
<MudSelect Class="mt-3"
T="MediaCollectionViewModel"
Label="Collection"
@bind-value="_selectedItem.Collection">
@foreach (MediaCollectionViewModel collection in _mediaCollections)
{
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
}
</MudSelect>
<MudAutocomplete Class="mt-3" T="MediaCollectionViewModel" Label="Collection"
@bind-Value="_selectedItem.Collection" SearchFunc="@SearchCollections"
ToStringFunc="@(c=> c.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.MultiCollection)
{
<MudSelect Class="mt-3"
T="MultiCollectionViewModel"
Label="Multi Collection"
@bind-value="_selectedItem.MultiCollection">
@foreach (MultiCollectionViewModel collection in _multiCollections)
{
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
}
</MudSelect>
<MudAutocomplete Class="mt-3" T="MultiCollectionViewModel" Label="Multi Collection"
@bind-Value="_selectedItem.MultiCollection" SearchFunc="@SearchMultiCollections"
ToStringFunc="@(c=> c.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.SmartCollection)
{
<MudSelect Class="mt-3"
T="SmartCollectionViewModel"
Label="Smart Collection"
@bind-value="_selectedItem.SmartCollection">
@foreach (SmartCollectionViewModel collection in _smartCollections)
{
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
}
</MudSelect>
<MudAutocomplete Class="mt-3" T="SmartCollectionViewModel" Label="Smart Collection"
@bind-Value="_selectedItem.SmartCollection" SearchFunc="@SearchSmartCollections"
ToStringFunc="@(c=> c.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionShow)
{
<MudSelect Class="mt-3"
T="NamedMediaItemViewModel"
Label="Television Show"
@bind-value="_selectedItem.MediaItem">
@foreach (NamedMediaItemViewModel show in _televisionShows)
{
<MudSelectItem Value="@show">@show.Name</MudSelectItem>
}
</MudSelect>
<MudAutocomplete Class="mt-3" T="NamedMediaItemViewModel" Label="Television Show"
@bind-Value="_selectedItem.MediaItem" SearchFunc="@SearchTelevisionShows"
ToStringFunc="@(c=> c.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionSeason)
{
<MudSelect Class="mt-3"
T="NamedMediaItemViewModel"
Label="Television Season"
@bind-value="_selectedItem.MediaItem">
@foreach (NamedMediaItemViewModel season in _televisionSeasons)
{
<MudSelectItem Value="@season">@season.Name</MudSelectItem>
}
</MudSelect>
<MudAutocomplete Class="mt-3" T="NamedMediaItemViewModel" Label="Television Season"
@bind-Value="_selectedItem.MediaItem" SearchFunc="@SearchTelevisionSeasons"
ToStringFunc="@(c=> c.Name)" Placeholder="Type to search..."
MaxItems="20">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 20 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Artist)
{
<MudSelect Class="mt-3"
T="NamedMediaItemViewModel"
Label="Artist"
@bind-value="_selectedItem.MediaItem">
@foreach (NamedMediaItemViewModel artist in _artists)
{
<MudSelectItem Value="@artist">@artist.Name</MudSelectItem>
}
</MudSelect>
<MudAutocomplete Class="mt-3" T="NamedMediaItemViewModel" Label="Artist"
@bind-Value="_selectedItem.MediaItem" SearchFunc="@SearchArtists"
ToStringFunc="@(c=> c.Name)" Placeholder="Type to search..."
MaxItems="10">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
<MudSelect Class="mt-3" Label="Playback Order" @bind-Value="@_selectedItem.PlaybackOrder" For="@(() => _selectedItem.PlaybackOrder)">
@switch (_selectedItem.CollectionType)
@ -338,12 +341,6 @@ @@ -338,12 +341,6 @@
public int Id { get; set; }
private ProgramScheduleItemsEditViewModel _schedule;
private List<MediaCollectionViewModel> _mediaCollections;
private List<MultiCollectionViewModel> _multiCollections;
private List<SmartCollectionViewModel> _smartCollections;
private List<NamedMediaItemViewModel> _televisionShows;
private List<NamedMediaItemViewModel> _televisionSeasons;
private List<NamedMediaItemViewModel> _artists;
private List<FillerPresetViewModel> _fillerPresets;
private List<WatermarkViewModel> _watermarks;
private List<CultureInfo> _availableCultures;
@ -361,34 +358,23 @@ @@ -361,34 +358,23 @@
private async Task LoadScheduleItems()
{
// TODO: fix performance
_mediaCollections = await _mediator.Send(new GetAllCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_multiCollections = await _mediator.Send(new GetAllMultiCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_smartCollections = await _mediator.Send(new GetAllSmartCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_televisionShows = await _mediator.Send(new GetAllTelevisionShows(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_televisionSeasons = await _mediator.Send(new GetAllTelevisionSeasons(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_artists = await _mediator.Send(new GetAllArtists(), _cts.Token)
_fillerPresets = await Mediator.Send(new GetAllFillerPresets(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_fillerPresets = await _mediator.Send(new GetAllFillerPresets(), _cts.Token)
_watermarks = await Mediator.Send(new GetAllWatermarks(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_watermarks = await _mediator.Send(new GetAllWatermarks(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_availableCultures = await _mediator.Send(new GetAllLanguageCodes(), _cts.Token);
_availableCultures = await Mediator.Send(new GetAllLanguageCodes(), _cts.Token);
string name = string.Empty;
var shuffleScheduleItems = false;
Option<ProgramScheduleViewModel> maybeSchedule = await _mediator.Send(new GetProgramScheduleById(Id), _cts.Token);
Option<ProgramScheduleViewModel> maybeSchedule = await Mediator.Send(new GetProgramScheduleById(Id), _cts.Token);
foreach (ProgramScheduleViewModel schedule in maybeSchedule)
{
name = schedule.Name;
shuffleScheduleItems = schedule.ShuffleScheduleItems;
}
Option<IEnumerable<ProgramScheduleItemViewModel>> maybeResults = await _mediator.Send(new GetProgramScheduleItems(Id), _cts.Token);
Option<IEnumerable<ProgramScheduleItemViewModel>> maybeResults =
await Mediator.Send(new GetProgramScheduleItems(Id), _cts.Token);
foreach (IEnumerable<ProgramScheduleItemViewModel> items in maybeResults)
{
_schedule = new ProgramScheduleItemsEditViewModel
@ -405,6 +391,66 @@ @@ -405,6 +391,66 @@
}
}
private async Task<IEnumerable<MediaCollectionViewModel>> SearchCollections(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<MediaCollectionViewModel>();
}
return await Mediator.Send(new SearchCollections(value), _cts.Token);
}
private async Task<IEnumerable<MultiCollectionViewModel>> SearchMultiCollections(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<MultiCollectionViewModel>();
}
return await Mediator.Send(new SearchMultiCollections(value), _cts.Token);
}
private async Task<IEnumerable<SmartCollectionViewModel>> SearchSmartCollections(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<SmartCollectionViewModel>();
}
return await Mediator.Send(new SearchSmartCollections(value), _cts.Token);
}
private async Task<IEnumerable<NamedMediaItemViewModel>> SearchTelevisionShows(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<NamedMediaItemViewModel>();
}
return await Mediator.Send(new SearchTelevisionShows(value), _cts.Token);
}
private async Task<IEnumerable<NamedMediaItemViewModel>> SearchTelevisionSeasons(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<NamedMediaItemViewModel>();
}
return await Mediator.Send(new SearchTelevisionSeasons(value), _cts.Token);
}
private async Task<IEnumerable<NamedMediaItemViewModel>> SearchArtists(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<NamedMediaItemViewModel>();
}
return await Mediator.Send(new SearchArtists(value), _cts.Token);
}
private ProgramScheduleItemEditViewModel ProjectToEditViewModel(ProgramScheduleItemViewModel item)
{
var result = new ProgramScheduleItemEditViewModel
@ -512,15 +558,15 @@ @@ -512,15 +558,15 @@
item.PreferredSubtitleLanguageCode,
item.SubtitleMode)).ToList();
Seq<BaseError> errorMessages = await _mediator.Send(new ReplaceProgramScheduleItems(Id, items), _cts.Token).Map(e => e.LeftToSeq());
Seq<BaseError> errorMessages = await Mediator.Send(new ReplaceProgramScheduleItems(Id, items), _cts.Token).Map(e => e.LeftToSeq());
errorMessages.HeadOrNone().Match(
error =>
{
_snackbar.Add($"Unexpected error saving schedule: {error.Value}", Severity.Error);
_logger.LogError("Unexpected error saving schedule: {Error}", error.Value);
Snackbar.Add($"Unexpected error saving schedule: {error.Value}", Severity.Error);
Logger.LogError("Unexpected error saving schedule: {Error}", error.Value);
},
() => _navigationManager.NavigateTo("/schedules"));
() => NavigationManager.NavigateTo("/schedules"));
}
}
Loading…
Cancel
Save