Browse Source

Add configurable pagination defaults and settings

pull/2742/head
Jon Crall 7 months ago
parent
commit
47a9ac58a6
  1. 6
      ErsatzTV.Application/Configuration/Commands/UpdatePaginationSettings.cs
  2. 29
      ErsatzTV.Application/Configuration/Commands/UpdatePaginationSettingsHandler.cs
  3. 6
      ErsatzTV.Application/Configuration/PaginationSettingsViewModel.cs
  4. 3
      ErsatzTV.Application/Configuration/Queries/GetPaginationSettings.cs
  5. 28
      ErsatzTV.Application/Configuration/Queries/GetPaginationSettingsHandler.cs
  6. 9
      ErsatzTV.Application/Filler/Queries/GetPagedFillerPresetsHandler.cs
  7. 6
      ErsatzTV.Application/Logs/Queries/GetRecentLogEntriesHandler.cs
  8. 5
      ErsatzTV.Application/MediaCards/Queries/GetMusicVideoCardsHandler.cs
  9. 5
      ErsatzTV.Application/MediaCards/Queries/GetTelevisionEpisodeCardsHandler.cs
  10. 7
      ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs
  11. 9
      ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs
  12. 9
      ErsatzTV.Application/MediaCollections/Queries/GetPagedMultiCollectionsHandler.cs
  13. 9
      ErsatzTV.Application/MediaCollections/Queries/GetPagedRerunCollectionsHandler.cs
  14. 9
      ErsatzTV.Application/MediaCollections/Queries/GetPagedSmartCollectionsHandler.cs
  15. 9
      ErsatzTV.Application/MediaCollections/Queries/GetPagedTraktListsHandler.cs
  16. 7
      ErsatzTV.Application/Playouts/Queries/GetBlockPlayoutHistoryHandler.cs
  17. 7
      ErsatzTV.Application/Playouts/Queries/GetFuturePlayoutItemsByIdHandler.cs
  18. 9
      ErsatzTV.Application/Playouts/Queries/GetPagedPlayoutsHandler.cs
  19. 9
      ErsatzTV.Application/ProgramSchedules/Queries/GetPagedProgramSchedulesHandler.cs
  20. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexArtistsHandler.cs
  21. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodesHandler.cs
  22. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexImagesHandler.cs
  23. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexMoviesHandler.cs
  24. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideosHandler.cs
  25. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs
  26. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexRemoteStreamsHandler.cs
  27. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasonsHandler.cs
  28. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexShowsHandler.cs
  29. 7
      ErsatzTV.Application/Search/Queries/QuerySearchIndexSongsHandler.cs
  30. 34
      ErsatzTV.Core.Tests/PaginationOptionsTests.cs
  31. 1
      ErsatzTV.Core/Domain/ConfigElementKey.cs
  32. 22
      ErsatzTV.Core/PaginationOptions.cs
  33. 14
      ErsatzTV/Extensions/PaginationExtensions.cs
  34. 4
      ErsatzTV/Pages/Artist.razor
  35. 3
      ErsatzTV/Pages/ArtistList.razor
  36. 3
      ErsatzTV/Pages/EpisodeList.razor
  37. 3
      ErsatzTV/Pages/ImageList.razor
  38. 4
      ErsatzTV/Pages/MovieList.razor
  39. 5
      ErsatzTV/Pages/MultiSelectBase.cs
  40. 3
      ErsatzTV/Pages/MusicVideoList.razor
  41. 3
      ErsatzTV/Pages/OtherVideoList.razor
  42. 3
      ErsatzTV/Pages/RemoteStreamList.razor
  43. 70
      ErsatzTV/Pages/Settings/PaginationSettings.razor
  44. 3
      ErsatzTV/Pages/SongList.razor
  45. 5
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  46. 6
      ErsatzTV/Pages/TelevisionSeasonList.razor
  47. 3
      ErsatzTV/Pages/TelevisionSeasonSearchResults.razor
  48. 3
      ErsatzTV/Pages/TelevisionShowList.razor
  49. 1
      ErsatzTV/Shared/MainLayout.razor

6
ErsatzTV.Application/Configuration/Commands/UpdatePaginationSettings.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
using ErsatzTV.Core;
using LanguageExt;
namespace ErsatzTV.Application.Configuration;
public record UpdatePaginationSettings(PaginationSettingsViewModel Settings) : IRequest<Either<BaseError, Unit>>;

29
ErsatzTV.Application/Configuration/Commands/UpdatePaginationSettingsHandler.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using System.Globalization;
using LanguageExt;
namespace ErsatzTV.Application.Configuration;
public class UpdatePaginationSettingsHandler : IRequestHandler<UpdatePaginationSettings, Either<BaseError, Unit>>
{
private readonly IConfigElementRepository _configElementRepository;
public UpdatePaginationSettingsHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public async Task<Either<BaseError, Unit>> Handle(
UpdatePaginationSettings request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.Settings.DefaultPageSize);
await _configElementRepository.Upsert(
ConfigElementKey.PagesDefaultPageSize,
pageSize.ToString(CultureInfo.InvariantCulture),
cancellationToken);
return Unit.Default;
}
}

6
ErsatzTV.Application/Configuration/PaginationSettingsViewModel.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
namespace ErsatzTV.Application.Configuration;
public class PaginationSettingsViewModel
{
public int DefaultPageSize { get; set; }
}

3
ErsatzTV.Application/Configuration/Queries/GetPaginationSettings.cs

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Configuration;
public record GetPaginationSettings : IRequest<PaginationSettingsViewModel>;

28
ErsatzTV.Application/Configuration/Queries/GetPaginationSettingsHandler.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
namespace ErsatzTV.Application.Configuration;
public class GetPaginationSettingsHandler : IRequestHandler<GetPaginationSettings, PaginationSettingsViewModel>
{
private readonly IConfigElementRepository _configElementRepository;
public GetPaginationSettingsHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public async Task<PaginationSettingsViewModel> Handle(
GetPaginationSettings request,
CancellationToken cancellationToken)
{
Option<ConfigElement> maybeElement = await _configElementRepository.GetConfigElement(
ConfigElementKey.PagesDefaultPageSize,
cancellationToken);
int defaultPageSize = PaginationOptions.NormalizePageSize(
maybeElement.Bind<int?>(element => int.TryParse(element.Value, out int value) ? value : null));
return new PaginationSettingsViewModel { DefaultPageSize = defaultPageSize };
}
}

9
ErsatzTV.Application/Filler/Queries/GetPagedFillerPresetsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Core;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.Filler.Mapper;
@ -15,13 +16,15 @@ public class GetPagedFillerPresetsHandler : IRequestHandler<GetPagedFillerPreset @@ -15,13 +16,15 @@ public class GetPagedFillerPresetsHandler : IRequestHandler<GetPagedFillerPreset
GetPagedFillerPresets request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.FillerPresets.CountAsync(cancellationToken);
List<FillerPresetViewModel> page = await dbContext.FillerPresets
.AsNoTracking()
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

6
ErsatzTV.Application/Logs/Queries/GetRecentLogEntriesHandler.cs

@ -14,6 +14,8 @@ public class GetRecentLogEntriesHandler : IRequestHandler<GetRecentLogEntries, P @@ -14,6 +14,8 @@ public class GetRecentLogEntriesHandler : IRequestHandler<GetRecentLogEntries, P
GetRecentLogEntries request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
// get most recent file
string logFileName = _localFileSystem.ListFiles(FileSystemLayout.LogsFolder)
.OrderDescending()
@ -41,8 +43,8 @@ public class GetRecentLogEntriesHandler : IRequestHandler<GetRecentLogEntries, P @@ -41,8 +43,8 @@ public class GetRecentLogEntriesHandler : IRequestHandler<GetRecentLogEntries, P
() => entries.OrderByDescending(le => le.Timestamp));
var page = ordered
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToList();
return new PagedLogEntriesViewModel(count, page).AsTask();

5
ErsatzTV.Application/MediaCards/Queries/GetMusicVideoCardsHandler.cs

@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Emby; @@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.MediaCards;
@ -31,10 +32,12 @@ public class GetMusicVideoCardsHandler : IRequestHandler<GetMusicVideoCards, Mus @@ -31,10 +32,12 @@ public class GetMusicVideoCardsHandler : IRequestHandler<GetMusicVideoCards, Mus
GetMusicVideoCards request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
int count = await _musicVideoRepository.GetMusicVideoCount(request.ArtistId);
List<MusicVideoMetadata> musicVideos = await _musicVideoRepository
.GetPagedMusicVideos(request.ArtistId, request.PageNumber, request.PageSize);
.GetPagedMusicVideos(request.ArtistId, request.PageNumber, pageSize);
var results = new List<MusicVideoCardViewModel>();

5
ErsatzTV.Application/MediaCards/Queries/GetTelevisionEpisodeCardsHandler.cs

@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Emby; @@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.MediaCards;
@ -35,6 +36,8 @@ public class @@ -35,6 +36,8 @@ public class
GetTelevisionEpisodeCards request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
int count = await _televisionRepository.GetEpisodeCount(request.TelevisionSeasonId);
Option<JellyfinMediaSource> maybeJellyfin = await _mediaSourceRepository.GetAllJellyfin(cancellationToken)
@ -44,7 +47,7 @@ public class @@ -44,7 +47,7 @@ public class
.Map(list => list.HeadOrNone());
List<EpisodeMetadata> episodes = await _televisionRepository
.GetPagedEpisodes(request.TelevisionSeasonId, request.PageNumber, request.PageSize);
.GetPagedEpisodes(request.TelevisionSeasonId, request.PageNumber, pageSize);
var results = new List<TelevisionEpisodeCardViewModel>();
foreach (EpisodeMetadata episodeMetadata in episodes)

7
ErsatzTV.Application/MediaCards/Queries/GetTelevisionSeasonCardsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using static ErsatzTV.Application.MediaCards.Mapper;
@ -23,6 +24,8 @@ public class @@ -23,6 +24,8 @@ public class
GetTelevisionSeasonCards request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
int count = await _televisionRepository.GetSeasonCount(request.TelevisionShowId);
Option<JellyfinMediaSource> maybeJellyfin = await _mediaSourceRepository.GetAllJellyfin(cancellationToken)
@ -32,7 +35,7 @@ public class @@ -32,7 +35,7 @@ public class
.Map(list => list.HeadOrNone());
List<TelevisionSeasonCardViewModel> results = await _televisionRepository
.GetPagedSeasons(request.TelevisionShowId, request.PageNumber, request.PageSize, cancellationToken)
.GetPagedSeasons(request.TelevisionShowId, request.PageNumber, pageSize, cancellationToken)
.Map(list => list.Map(s => ProjectToViewModel(s, maybeJellyfin, maybeEmby)).ToList());
return new TelevisionSeasonCardResultsViewModel(count, results, null);

9
ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -12,6 +13,8 @@ public class GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFa @@ -12,6 +13,8 @@ public class GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFa
GetPagedCollections request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.Collections.CountAsync(cancellationToken);
@ -26,8 +29,8 @@ public class GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFa @@ -26,8 +29,8 @@ public class GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFa
List<MediaCollectionViewModel> page = await query
.OrderBy(c => EF.Functions.Collate(c.Name, TvContext.CaseInsensitiveCollation))
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

9
ErsatzTV.Application/MediaCollections/Queries/GetPagedMultiCollectionsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -12,6 +13,8 @@ public class GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -12,6 +13,8 @@ public class GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbCont
GetPagedMultiCollections request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.MultiCollections.CountAsync(cancellationToken);
@ -26,8 +29,8 @@ public class GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -26,8 +29,8 @@ public class GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbCont
List<MultiCollectionViewModel> page = await query
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.Include(mc => mc.MultiCollectionItems)
.ThenInclude(i => i.Collection)
.ToListAsync(cancellationToken)

9
ErsatzTV.Application/MediaCollections/Queries/GetPagedRerunCollectionsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -12,6 +13,8 @@ public class GetPagedRerunCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -12,6 +13,8 @@ public class GetPagedRerunCollectionsHandler(IDbContextFactory<TvContext> dbCont
GetPagedRerunCollections request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.RerunCollections.CountAsync(cancellationToken);
@ -26,8 +29,8 @@ public class GetPagedRerunCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -26,8 +29,8 @@ public class GetPagedRerunCollectionsHandler(IDbContextFactory<TvContext> dbCont
List<RerunCollectionViewModel> page = await query
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

9
ErsatzTV.Application/MediaCollections/Queries/GetPagedSmartCollectionsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -12,6 +13,8 @@ public class GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -12,6 +13,8 @@ public class GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbCont
GetPagedSmartCollections request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.SmartCollections.CountAsync(cancellationToken);
@ -26,8 +29,8 @@ public class GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbCont @@ -26,8 +29,8 @@ public class GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbCont
List<SmartCollectionViewModel> page = await query
.OrderBy(s => EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation))
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

9
ErsatzTV.Application/MediaCollections/Queries/GetPagedTraktListsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Core;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -15,13 +16,15 @@ public class GetPagedTraktListsHandler : IRequestHandler<GetPagedTraktLists, Pag @@ -15,13 +16,15 @@ public class GetPagedTraktListsHandler : IRequestHandler<GetPagedTraktLists, Pag
GetPagedTraktLists request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.TraktLists.CountAsync(cancellationToken);
List<TraktListViewModel> page = await dbContext.TraktLists
.AsNoTracking()
.OrderBy(f => EF.Functions.Collate(f.Name, TvContext.CaseInsensitiveCollation))
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.Include(l => l.Items)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

7
ErsatzTV.Application/Playouts/Queries/GetBlockPlayoutHistoryHandler.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
@ -11,6 +12,8 @@ public class GetBlockPlayoutHistoryHandler(IDbContextFactory<TvContext> dbContex @@ -11,6 +12,8 @@ public class GetBlockPlayoutHistoryHandler(IDbContextFactory<TvContext> dbContex
GetBlockPlayoutHistory request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
IQueryable<PlayoutHistory> query = dbContext.PlayoutHistory
@ -21,8 +24,8 @@ public class GetBlockPlayoutHistoryHandler(IDbContextFactory<TvContext> dbContex @@ -21,8 +24,8 @@ public class GetBlockPlayoutHistoryHandler(IDbContextFactory<TvContext> dbContex
List<PlayoutHistory> allHistory = await query
.OrderBy(ph => ph.Id)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken);
return new PagedPlayoutHistoryViewModel(totalCount, allHistory.Map(Mapper.ProjectToViewModel).ToList());

7
ErsatzTV.Application/Playouts/Queries/GetFuturePlayoutItemsByIdHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Globalization;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Infrastructure.Data;
@ -14,6 +15,8 @@ public class GetFuturePlayoutItemsByIdHandler(IDbContextFactory<TvContext> dbCon @@ -14,6 +15,8 @@ public class GetFuturePlayoutItemsByIdHandler(IDbContextFactory<TvContext> dbCon
GetFuturePlayoutItemsById request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
DateTime now = DateTimeOffset.Now.UtcDateTime;
@ -39,8 +42,8 @@ public class GetFuturePlayoutItemsByIdHandler(IDbContextFactory<TvContext> dbCon @@ -39,8 +42,8 @@ public class GetFuturePlayoutItemsByIdHandler(IDbContextFactory<TvContext> dbCon
List<PlayoutItemViewModel> page = await combined
.OrderBy(c => c.Start)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken)
.Bind(async pageOfCombined =>
{

9
ErsatzTV.Application/Playouts/Queries/GetPagedPlayoutsHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.Playouts.Mapper;
@ -12,6 +13,8 @@ public class GetPagedPlayoutsHandler(IDbContextFactory<TvContext> dbContextFacto @@ -12,6 +13,8 @@ public class GetPagedPlayoutsHandler(IDbContextFactory<TvContext> dbContextFacto
GetPagedPlayouts request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.Playouts.CountAsync(cancellationToken);
@ -31,8 +34,8 @@ public class GetPagedPlayoutsHandler(IDbContextFactory<TvContext> dbContextFacto @@ -31,8 +34,8 @@ public class GetPagedPlayoutsHandler(IDbContextFactory<TvContext> dbContextFacto
List<PlayoutNameViewModel> page = await query
.OrderBy(p => p.Channel.SortNumber)
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

9
ErsatzTV.Application/ProgramSchedules/Queries/GetPagedProgramSchedulesHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.ProgramSchedules.Mapper;
@ -12,6 +13,8 @@ public class GetPagedProgramSchedulesHandler(IDbContextFactory<TvContext> dbCont @@ -12,6 +13,8 @@ public class GetPagedProgramSchedulesHandler(IDbContextFactory<TvContext> dbCont
GetPagedProgramSchedules request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.ProgramSchedules.CountAsync(cancellationToken);
@ -26,8 +29,8 @@ public class GetPagedProgramSchedulesHandler(IDbContextFactory<TvContext> dbCont @@ -26,8 +29,8 @@ public class GetPagedProgramSchedulesHandler(IDbContextFactory<TvContext> dbCont
List<ProgramScheduleViewModel> page = await query
.OrderBy(s => EF.Functions.Collate(s.Name, TvContext.CaseInsensitiveCollation))
.Skip(request.PageNum * request.PageSize)
.Take(request.PageSize)
.Skip(request.PageNum * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToViewModel).ToList());

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexArtistsHandler.cs

@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -18,12 +19,14 @@ public class QuerySearchIndexArtistsHandler( @@ -18,12 +19,14 @@ public class QuerySearchIndexArtistsHandler(
QuerySearchIndexArtists request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodesHandler.cs

@ -11,6 +11,7 @@ using ErsatzTV.Core.Search; @@ -11,6 +11,7 @@ using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -30,12 +31,14 @@ public class @@ -30,12 +31,14 @@ public class
QuerySearchIndexEpisodes request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexImagesHandler.cs

@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -18,12 +19,14 @@ public class QuerySearchIndexImagesHandler( @@ -18,12 +19,14 @@ public class QuerySearchIndexImagesHandler(
QuerySearchIndexImages request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexMoviesHandler.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -19,12 +20,14 @@ public class QuerySearchIndexMoviesHandler( @@ -19,12 +20,14 @@ public class QuerySearchIndexMoviesHandler(
QuerySearchIndexMovies request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideosHandler.cs

@ -9,6 +9,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -9,6 +9,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -27,12 +28,14 @@ public class @@ -27,12 +28,14 @@ public class
QuerySearchIndexMusicVideos request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs

@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -19,12 +20,14 @@ public class @@ -19,12 +20,14 @@ public class
QuerySearchIndexOtherVideos request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexRemoteStreamsHandler.cs

@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -18,12 +19,14 @@ public class QuerySearchIndexRemoteStreamsHandler( @@ -18,12 +19,14 @@ public class QuerySearchIndexRemoteStreamsHandler(
QuerySearchIndexRemoteStreams request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasonsHandler.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -20,12 +21,14 @@ public class @@ -20,12 +21,14 @@ public class
QuerySearchIndexSeasons request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexShowsHandler.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -20,12 +21,14 @@ public class @@ -20,12 +21,14 @@ public class
QuerySearchIndexShows request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

7
ErsatzTV.Application/Search/Queries/QuerySearchIndexSongsHandler.cs

@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search; @@ -4,6 +4,7 @@ using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using ErsatzTV.Core;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@ -15,12 +16,14 @@ public class QuerySearchIndexSongsHandler(IClient client, ISearchIndex searchInd @@ -15,12 +16,14 @@ public class QuerySearchIndexSongsHandler(IClient client, ISearchIndex searchInd
QuerySearchIndexSongs request,
CancellationToken cancellationToken)
{
int pageSize = PaginationOptions.NormalizePageSize(request.PageSize);
SearchResult searchResult = await searchIndex.Search(
client,
request.Query,
string.Empty,
(request.PageNumber - 1) * request.PageSize,
request.PageSize,
(request.PageNumber - 1) * pageSize,
pageSize,
cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

34
ErsatzTV.Core.Tests/PaginationOptionsTests.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
using ErsatzTV.Core;
using FluentAssertions;
using NUnit.Framework;
namespace ErsatzTV.Core.Tests;
[TestFixture]
public class PaginationOptionsTests
{
[Test]
public void NormalizePageSize_Should_Default_For_Null()
{
PaginationOptions.NormalizePageSize(null).Should().Be(PaginationOptions.DefaultPageSize);
}
[TestCase(0)]
[TestCase(-1)]
public void NormalizePageSize_Should_Default_For_NonPositive(int input)
{
PaginationOptions.NormalizePageSize(input).Should().Be(PaginationOptions.DefaultPageSize);
}
[Test]
public void NormalizePageSize_Should_Accept_Positive()
{
PaginationOptions.NormalizePageSize(50).Should().Be(50);
}
[Test]
public void NormalizePageSize_Should_Clamp_To_Max()
{
PaginationOptions.NormalizePageSize(1000).Should().Be(PaginationOptions.MaxPageSize);
}
}

1
ErsatzTV.Core/Domain/ConfigElementKey.cs

@ -32,6 +32,7 @@ public class ConfigElementKey @@ -32,6 +32,7 @@ public class ConfigElementKey
public static ConfigElementKey HDHRTunerCount => new("hdhr.tuner_count");
public static ConfigElementKey HDHRUUID => new("hdhr.uuid");
public static ConfigElementKey PagesIsDarkMode => new("pages.is_dark_mode");
public static ConfigElementKey PagesDefaultPageSize => new("pages.default_page_size");
public static ConfigElementKey ChannelsPageSize => new("pages.channels.page_size");
public static ConfigElementKey ChannelsShowDisabled => new("pages.channels.show_disabled");
public static ConfigElementKey CollectionsPageSize => new("pages.collections.page_size");

22
ErsatzTV.Core/PaginationOptions.cs

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
using System;
namespace ErsatzTV.Core;
public static class PaginationOptions
{
public const int DefaultPageSize = 100;
public const int MaxPageSize = 500;
public static int NormalizePageSize(int? requested) =>
NormalizePageSize(requested, DefaultPageSize, MaxPageSize);
public static int NormalizePageSize(int? requested, int defaultSize, int maxSize)
{
if (requested is null || requested <= 0)
{
return defaultSize;
}
return Math.Clamp(requested.Value, 1, maxSize);
}
}

14
ErsatzTV/Extensions/PaginationExtensions.cs

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
using ErsatzTV.Application.Configuration;
using ErsatzTV.Core;
using MediatR;
namespace ErsatzTV.Extensions;
public static class PaginationExtensions
{
public static async Task<int> GetDefaultPageSize(this IMediator mediator, CancellationToken cancellationToken)
{
PaginationSettingsViewModel settings = await mediator.Send(new GetPaginationSettings(), cancellationToken);
return PaginationOptions.NormalizePageSize(settings.DefaultPageSize);
}
}

4
ErsatzTV/Pages/Artist.razor

@ -253,6 +253,7 @@ @@ -253,6 +253,7 @@
private List<string> _sortedGenres = [];
private List<string> _sortedStyles = [];
private List<string> _sortedMoods = [];
private int _pageSize = PaginationOptions.DefaultPageSize;
private MusicVideoCardResultsViewModel _musicVideos = new(0, [], new SearchPageMap([]));
public void Dispose()
@ -270,6 +271,7 @@ @@ -270,6 +271,7 @@
try
{
_pageSize = await Mediator.GetDefaultPageSize(token);
await Mediator.Send(new GetArtistById(ArtistId), token).IfSomeAsync(vm =>
{
_artist = vm;
@ -279,7 +281,7 @@ @@ -279,7 +281,7 @@
_sortedMoods = _artist.Moods.OrderBy(m => m).ToList();
});
_musicVideos = await Mediator.Send(new GetMusicVideoCards(ArtistId, 1, 100), token);
_musicVideos = await Mediator.Send(new GetMusicVideoCards(ArtistId, 1, _pageSize), token);
}
catch (OperationCanceledException)
{

3
ErsatzTV/Pages/ArtistList.razor

@ -45,7 +45,6 @@ @@ -45,7 +45,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -55,6 +54,8 @@ @@ -55,6 +54,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

3
ErsatzTV/Pages/EpisodeList.razor

@ -45,7 +45,6 @@ @@ -45,7 +45,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -55,6 +54,8 @@ @@ -55,6 +54,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

3
ErsatzTV/Pages/ImageList.razor

@ -45,7 +45,6 @@ @@ -45,7 +45,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -55,6 +54,8 @@ @@ -55,6 +54,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

4
ErsatzTV/Pages/MovieList.razor

@ -47,8 +47,6 @@ @@ -47,8 +47,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -66,6 +64,8 @@ @@ -66,6 +64,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

5
ErsatzTV/Pages/MultiSelectBase.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
using ErsatzTV.Application.MediaCards;
using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Core;
using ErsatzTV.Extensions;
using ErsatzTV.Shared;
using LanguageExt.UnsafeValueAccess;
using MediatR;
@ -14,6 +15,7 @@ namespace ErsatzTV.Pages; @@ -14,6 +15,7 @@ namespace ErsatzTV.Pages;
public class MultiSelectBase<T> : FragmentNavigationBase
{
private Option<MediaCardViewModel> _recentlySelected = None;
protected int PageSize { get; private set; } = PaginationOptions.DefaultPageSize;
[Inject]
protected IDialogService Dialog { get; set; }
@ -29,6 +31,9 @@ public class MultiSelectBase<T> : FragmentNavigationBase @@ -29,6 +31,9 @@ public class MultiSelectBase<T> : FragmentNavigationBase
protected System.Collections.Generic.HashSet<MediaCardViewModel> SelectedItems { get; } = [];
protected async Task InitializePageSize(CancellationToken cancellationToken) =>
PageSize = await Mediator.GetDefaultPageSize(cancellationToken);
protected bool IsSelected(MediaCardViewModel card) =>
SelectedItems.Contains(card);

3
ErsatzTV/Pages/MusicVideoList.razor

@ -45,7 +45,6 @@ @@ -45,7 +45,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -55,6 +54,8 @@ @@ -55,6 +54,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

3
ErsatzTV/Pages/OtherVideoList.razor

@ -45,7 +45,6 @@ @@ -45,7 +45,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -55,6 +54,8 @@ @@ -55,6 +54,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

3
ErsatzTV/Pages/RemoteStreamList.razor

@ -45,7 +45,6 @@ @@ -45,7 +45,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -55,6 +54,8 @@ @@ -55,6 +54,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

70
ErsatzTV/Pages/Settings/PaginationSettings.razor

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
@page "/settings/pagination"
@using ErsatzTV.Application.Configuration
@inject IMediator Mediator
@inject ISnackbar Snackbar
@inject ILogger<PaginationSettings> Logger
@implements IDisposable
<MudForm Style="max-height: 100%">
<MudPaper Square="true" Style="display: flex; height: 64px; min-height: 64px; width: 100%; z-index: 100; align-items: center">
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => SavePaginationSettings())" Class="ml-6" StartIcon="@Icons.Material.Filled.Save">Save Settings</MudButton>
</MudPaper>
<div class="d-flex flex-column" style="height: 100vh; overflow-x: auto">
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudText Typo="Typo.h5" Class="mb-2">Pagination</MudText>
<MudDivider Class="mb-6"/>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Items Per Page</MudText>
</div>
<MudSelect @bind-Value="_settings.DefaultPageSize">
<MudSelectItem Value="25">25</MudSelectItem>
<MudSelectItem Value="50">50</MudSelectItem>
<MudSelectItem Value="100">100</MudSelectItem>
<MudSelectItem Value="200">200</MudSelectItem>
<MudSelectItem Value="500">500</MudSelectItem>
</MudSelect>
</MudStack>
</MudContainer>
</div>
</MudForm>
@code {
private CancellationTokenSource _cts;
private PaginationSettingsViewModel _settings = new();
public void Dispose()
{
_cts?.Cancel();
_cts?.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_cts?.Cancel();
_cts?.Dispose();
_cts = new CancellationTokenSource();
var token = _cts.Token;
try
{
_settings = await Mediator.Send(new GetPaginationSettings(), token);
}
catch (OperationCanceledException)
{
// do nothing
}
}
private async Task SavePaginationSettings()
{
Either<BaseError, Unit> result = await Mediator.Send(new UpdatePaginationSettings(_settings), _cts.Token);
result.Match(
Left: error =>
{
Snackbar.Add(error.Value, Severity.Error);
Logger.LogError("Unexpected error saving pagination settings: {Error}", error.Value);
},
Right: _ => Snackbar.Add("Successfully saved pagination settings", Severity.Success));
}
}

3
ErsatzTV/Pages/SongList.razor

@ -45,7 +45,6 @@ @@ -45,7 +45,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -55,6 +54,8 @@ @@ -55,6 +54,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

5
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -188,7 +188,7 @@ @@ -188,7 +188,7 @@
private TelevisionSeasonViewModel _season;
private static int PageSize => 100;
private int _pageSize = PaginationOptions.DefaultPageSize;
private const int PageNumber = 1;
private TelevisionEpisodeCardResultsViewModel _data = new(0, new List<TelevisionEpisodeCardViewModel>(), null);
@ -223,8 +223,9 @@ @@ -223,8 +223,9 @@
try
{
_pageSize = await Mediator.GetDefaultPageSize(token);
await Mediator.Send(new GetTelevisionSeasonById(SeasonId), token).IfSomeAsync(vm => _season = vm);
_data = await Mediator.Send(new GetTelevisionEpisodeCards(SeasonId, PageNumber, PageSize), token);
_data = await Mediator.Send(new GetTelevisionEpisodeCards(SeasonId, PageNumber, _pageSize), token);
}
catch (OperationCanceledException)
{

6
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -189,7 +189,7 @@ @@ -189,7 +189,7 @@
private List<string> _sortedGenres = [];
private List<string> _sortedTags = [];
private static int PageSize => 100;
private int _pageSize = PaginationOptions.DefaultPageSize;
private const int PageNumber = 1;
private TelevisionSeasonCardResultsViewModel _data = new(0, [], null);
@ -209,6 +209,8 @@ @@ -209,6 +209,8 @@
try
{
_pageSize = await Mediator.GetDefaultPageSize(token);
Option<TelevisionShowViewModel> maybeShow = await Mediator.Send(new GetTelevisionShowById(ShowId), token);
foreach (TelevisionShowViewModel show in maybeShow)
{
@ -221,7 +223,7 @@ @@ -221,7 +223,7 @@
_sortedNetworks = _show.Networks.OrderBy(n => n).ToList();
}
_data = await Mediator.Send(new GetTelevisionSeasonCards(ShowId, PageNumber, PageSize), token);
_data = await Mediator.Send(new GetTelevisionSeasonCards(ShowId, PageNumber, _pageSize), token);
}
catch (OperationCanceledException)
{

3
ErsatzTV/Pages/TelevisionSeasonSearchResults.razor

@ -69,7 +69,6 @@ @@ -69,7 +69,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -79,6 +78,8 @@ @@ -79,6 +78,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

3
ErsatzTV/Pages/TelevisionShowList.razor

@ -46,7 +46,6 @@ @@ -46,7 +46,6 @@
}
@code {
private static int PageSize => 100;
[Parameter]
public int PageNumber { get; set; }
@ -65,6 +64,8 @@ @@ -65,6 +64,8 @@
protected override async Task OnParametersSetAsync()
{
await InitializePageSize(CancellationToken);
if (PageNumber == 0)
{
PageNumber = 1;

1
ErsatzTV/Shared/MainLayout.razor

@ -189,6 +189,7 @@ @@ -189,6 +189,7 @@
<MudNavLink Href="settings/hdhr">HDHomeRun</MudNavLink>
<MudNavLink Href="settings/scanner">Scanner</MudNavLink>
<MudNavLink Href="settings/playout">Playout</MudNavLink>
<MudNavLink Href="settings/pagination">Pagination</MudNavLink>
<MudNavLink Href="settings/xmltv">XMLTV</MudNavLink>
</MudNavGroup>
<MudNavGroup Expanded="true">

Loading…
Cancel
Save