improve schedule editor performance (#1240)
* rename * async cleanup * use autocomplete fields in schedule items editor
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
|
||||
namespace ErsatzTV.Application.Search;
|
||||
|
||||
public record SearchArtists(string Query) : IRequest<List<NamedMediaItemViewModel>>;
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Application.Search;
|
||||
|
||||
public record SearchCollections(string Query) : IRequest<List<MediaCollectionViewModel>>;
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Application.Search;
|
||||
|
||||
public record SearchMultiCollections(string Query) : IRequest<List<MultiCollectionViewModel>>;
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Application.Search;
|
||||
|
||||
public record SearchSmartCollections(string Query) : IRequest<List<SmartCollectionViewModel>>;
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
|
||||
namespace ErsatzTV.Application.Search;
|
||||
|
||||
public record SearchTelevisionSeasons(string Query) : IRequest<List<NamedMediaItemViewModel>>;
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
|
||||
namespace ErsatzTV.Application.Search;
|
||||
|
||||
public record SearchTelevisionShows(string Query) : IRequest<List<NamedMediaItemViewModel>>;
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 @@
|
||||
</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 @@
|
||||
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 @@
|
||||
private async Task LoadScheduleItems()
|
||||
{
|
||||
// TODO: fix performance
|
||||
_mediaCollections = await _mediator.Send(new GetAllCollections(), _cts.Token)
|
||||
_fillerPresets = await Mediator.Send(new GetAllFillerPresets(), _cts.Token)
|
||||
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||
_multiCollections = await _mediator.Send(new GetAllMultiCollections(), _cts.Token)
|
||||
_watermarks = await Mediator.Send(new GetAllWatermarks(), _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)
|
||||
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
|
||||
_fillerPresets = await _mediator.Send(new GetAllFillerPresets(), _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
|
||||
@@ -404,6 +390,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)
|
||||
{
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user