mirror of https://github.com/ErsatzTV/ErsatzTV.git
32 changed files with 471 additions and 64 deletions
@ -0,0 +1,34 @@ |
|||||||
|
using ErsatzTV.Core.Domain; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
internal static class Mapper |
||||||
|
{ |
||||||
|
internal static TelevisionShowCardViewModel ProjectToViewModel(TelevisionShow televisionShow) => |
||||||
|
new( |
||||||
|
televisionShow.Id, |
||||||
|
televisionShow.Metadata.Title, |
||||||
|
televisionShow.Metadata.Year.ToString(), |
||||||
|
televisionShow.Metadata.SortTitle, |
||||||
|
televisionShow.Poster); |
||||||
|
|
||||||
|
internal static TelevisionSeasonCardViewModel ProjectToViewModel(TelevisionSeason televisionSeason) => |
||||||
|
new( |
||||||
|
televisionSeason.Id, |
||||||
|
GetSeasonName(televisionSeason.Number), |
||||||
|
string.Empty, |
||||||
|
GetSeasonName(televisionSeason.Number), |
||||||
|
televisionSeason.Poster); |
||||||
|
|
||||||
|
internal static MovieCardViewModel ProjectToViewModel(MovieMediaItem movie) => |
||||||
|
new( |
||||||
|
movie.Id, |
||||||
|
movie.Metadata.Title, |
||||||
|
movie.Metadata.Year.ToString(), |
||||||
|
movie.Metadata.SortTitle, |
||||||
|
movie.Poster); |
||||||
|
|
||||||
|
private static string GetSeasonName(int number) => |
||||||
|
number == 0 ? "Specials" : $"Season {number}"; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record MediaCardViewModel(string Title, string Subtitle, string SortTitle, string Poster); |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record MovieCardResultsViewModel(int Count, List<MovieCardViewModel> Cards); |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record MovieCardViewModel |
||||||
|
(int MovieId, string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel( |
||||||
|
Title, |
||||||
|
Subtitle, |
||||||
|
SortTitle, |
||||||
|
Poster) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
using MediatR; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards.Queries |
||||||
|
{ |
||||||
|
public record GetMovieCards(int PageNumber, int PageSize) : IRequest<MovieCardResultsViewModel>; |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ErsatzTV.Core.Interfaces.Repositories; |
||||||
|
using LanguageExt; |
||||||
|
using MediatR; |
||||||
|
using static ErsatzTV.Application.MediaCards.Mapper; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards.Queries |
||||||
|
{ |
||||||
|
public class |
||||||
|
GetMovieCardsHandler : IRequestHandler<GetMovieCards, MovieCardResultsViewModel> |
||||||
|
{ |
||||||
|
private readonly IMovieRepository _movieRepository; |
||||||
|
|
||||||
|
public GetMovieCardsHandler(IMovieRepository movieRepository) |
||||||
|
{ |
||||||
|
_movieRepository = movieRepository; |
||||||
|
} |
||||||
|
|
||||||
|
public async Task<MovieCardResultsViewModel> Handle( |
||||||
|
GetMovieCards request, |
||||||
|
CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
int count = await _movieRepository.GetMovieCount(); |
||||||
|
|
||||||
|
List<MovieCardViewModel> results = await _movieRepository |
||||||
|
.GetPagedMovies(request.PageNumber, request.PageSize) |
||||||
|
.Map(list => list.Map(ProjectToViewModel).ToList()); |
||||||
|
|
||||||
|
return new MovieCardResultsViewModel(count, results); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
using MediatR; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards.Queries |
||||||
|
{ |
||||||
|
public record GetTelevisionSeasonCards |
||||||
|
(int TelevisionShowId, int PageNumber, int PageSize) : IRequest<TelevisionSeasonCardResultsViewModel>; |
||||||
|
} |
||||||
@ -0,0 +1,34 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ErsatzTV.Core.Interfaces.Repositories; |
||||||
|
using LanguageExt; |
||||||
|
using MediatR; |
||||||
|
using static ErsatzTV.Application.MediaCards.Mapper; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards.Queries |
||||||
|
{ |
||||||
|
public class |
||||||
|
GetTelevisionSeasonCardsHandler : IRequestHandler<GetTelevisionSeasonCards, TelevisionSeasonCardResultsViewModel |
||||||
|
> |
||||||
|
{ |
||||||
|
private readonly ITelevisionRepository _televisionRepository; |
||||||
|
|
||||||
|
public GetTelevisionSeasonCardsHandler(ITelevisionRepository televisionRepository) => |
||||||
|
_televisionRepository = televisionRepository; |
||||||
|
|
||||||
|
public async Task<TelevisionSeasonCardResultsViewModel> Handle( |
||||||
|
GetTelevisionSeasonCards request, |
||||||
|
CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
int count = await _televisionRepository.GetSeasonCount(request.TelevisionShowId); |
||||||
|
|
||||||
|
List<TelevisionSeasonCardViewModel> results = await _televisionRepository |
||||||
|
.GetPagedSeasons(request.TelevisionShowId, request.PageNumber, request.PageSize) |
||||||
|
.Map(list => list.Map(ProjectToViewModel).ToList()); |
||||||
|
|
||||||
|
return new TelevisionSeasonCardResultsViewModel(count, results); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
using MediatR; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards.Queries |
||||||
|
{ |
||||||
|
public record GetTelevisionShowCards(int PageNumber, int PageSize) : IRequest<TelevisionShowCardResultsViewModel>; |
||||||
|
} |
||||||
@ -0,0 +1,33 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ErsatzTV.Core.Interfaces.Repositories; |
||||||
|
using LanguageExt; |
||||||
|
using MediatR; |
||||||
|
using static ErsatzTV.Application.MediaCards.Mapper; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards.Queries |
||||||
|
{ |
||||||
|
public class |
||||||
|
GetTelevisionShowCardsHandler : IRequestHandler<GetTelevisionShowCards, TelevisionShowCardResultsViewModel> |
||||||
|
{ |
||||||
|
private readonly ITelevisionRepository _televisionRepository; |
||||||
|
|
||||||
|
public GetTelevisionShowCardsHandler(ITelevisionRepository televisionRepository) => |
||||||
|
_televisionRepository = televisionRepository; |
||||||
|
|
||||||
|
public async Task<TelevisionShowCardResultsViewModel> Handle( |
||||||
|
GetTelevisionShowCards request, |
||||||
|
CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
int count = await _televisionRepository.GetShowCount(); |
||||||
|
|
||||||
|
List<TelevisionShowCardViewModel> results = await _televisionRepository |
||||||
|
.GetPagedShows(request.PageNumber, request.PageSize) |
||||||
|
.Map(list => list.Map(ProjectToViewModel).ToList()); |
||||||
|
|
||||||
|
return new TelevisionShowCardResultsViewModel(count, results); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record TelevisionEpisodeCardViewModel |
||||||
|
(string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel( |
||||||
|
Title, |
||||||
|
Subtitle, |
||||||
|
SortTitle, |
||||||
|
Poster) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record TelevisionSeasonCardResultsViewModel(int Count, List<TelevisionSeasonCardViewModel> Cards); |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record TelevisionSeasonCardViewModel |
||||||
|
(int TelevisionSeasonId, string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel( |
||||||
|
Title, |
||||||
|
Subtitle, |
||||||
|
SortTitle, |
||||||
|
Poster) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record TelevisionShowCardResultsViewModel(int Count, List<TelevisionShowCardViewModel> Cards); |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
namespace ErsatzTV.Application.MediaCards |
||||||
|
{ |
||||||
|
public record TelevisionShowCardViewModel |
||||||
|
(int TelevisionShowId, string Title, string Subtitle, string SortTitle, string Poster) : MediaCardViewModel( |
||||||
|
Title, |
||||||
|
Subtitle, |
||||||
|
SortTitle, |
||||||
|
Poster) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
@ -1,8 +1,8 @@ |
|||||||
using ErsatzTV.Core.Domain; |
using ErsatzTV.Core.AggregateModels; |
||||||
using MediatR; |
using MediatR; |
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaItems.Queries |
namespace ErsatzTV.Application.MediaItems.Queries |
||||||
{ |
{ |
||||||
public record GetAggregateMediaItems |
public record GetAggregateMediaItems |
||||||
(MediaType MediaType, int PageNumber, int PageSize) : IRequest<AggregateMediaItemResults>; |
(AggregateMediaItemType ItemType, int PageNumber, int PageSize) : IRequest<AggregateMediaItemResults>; |
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,10 @@ |
|||||||
|
namespace ErsatzTV.Core.AggregateModels |
||||||
|
{ |
||||||
|
public enum AggregateMediaItemType |
||||||
|
{ |
||||||
|
TelevisionShows, |
||||||
|
TelevisionSeasons, |
||||||
|
TelevisionEpisodes, |
||||||
|
Movies |
||||||
|
} |
||||||
|
} |
||||||
@ -1,8 +0,0 @@ |
|||||||
@page "/media/movies/items" |
|
||||||
@inject IMediator Mediator |
|
||||||
|
|
||||||
<MediaItemsGrid MediaType="@MediaType.Movie"/> |
|
||||||
|
|
||||||
@code { |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,8 +0,0 @@ |
|||||||
@page "/media/tv/items" |
|
||||||
@inject IMediator Mediator |
|
||||||
|
|
||||||
<MediaItemsGrid MediaType="@MediaType.TvShow"/> |
|
||||||
|
|
||||||
@code { |
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,28 @@ |
|||||||
|
@page "/media/tv/shows/{ShowId:int}" |
||||||
|
@using ErsatzTV.Application.MediaCards |
||||||
|
@using ErsatzTV.Application.MediaCards.Queries |
||||||
|
@inject IMediator Mediator |
||||||
|
|
||||||
|
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid"> |
||||||
|
@foreach (TelevisionSeasonCardViewModel card in _data.Cards) |
||||||
|
{ |
||||||
|
<MediaCard Data="@card" Link="@($"/media/tv/shows/{ShowId}/seasons/{card.TelevisionSeasonId}")" DataRefreshed="@(() => RefreshData())"/> |
||||||
|
} |
||||||
|
</MudContainer> |
||||||
|
|
||||||
|
@code { |
||||||
|
|
||||||
|
[Parameter] |
||||||
|
public int ShowId { get; set; } |
||||||
|
|
||||||
|
private int PageSize => 100; |
||||||
|
private int _pageNumber = 1; |
||||||
|
|
||||||
|
private TelevisionSeasonCardResultsViewModel _data; |
||||||
|
|
||||||
|
protected override Task OnParametersSetAsync() => RefreshData(); |
||||||
|
|
||||||
|
private async Task RefreshData() => |
||||||
|
_data = await Mediator.Send(new GetTelevisionSeasonCards(ShowId, _pageNumber, PageSize)); |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
@page "/media/tv/shows" |
||||||
|
@using ErsatzTV.Application.MediaCards |
||||||
|
@using ErsatzTV.Application.MediaCards.Queries |
||||||
|
@inject IMediator Mediator |
||||||
|
|
||||||
|
<MudContainer MaxWidth="MaxWidth.Small" Class="mb-6" Style="max-width: 300px"> |
||||||
|
<MudPaper Style="align-items: center; display: flex; justify-content: center;"> |
||||||
|
<MudIconButton Icon="@Icons.Material.Outlined.ChevronLeft" |
||||||
|
OnClick="@(() => PrevPage())" |
||||||
|
Disabled="@(_pageNumber <= 1)"> |
||||||
|
</MudIconButton> |
||||||
|
<MudText Style="flex-grow: 1" |
||||||
|
Align="Align.Center"> |
||||||
|
@Math.Min((_pageNumber - 1) * PageSize + 1, _data.Count)-@Math.Min(_data.Count, _pageNumber * PageSize) of @_data.Count |
||||||
|
</MudText> |
||||||
|
<MudIconButton Icon="@Icons.Material.Outlined.ChevronRight" |
||||||
|
OnClick="@(() => NextPage())" Disabled="@(_pageNumber * PageSize >= _data.Count)"> |
||||||
|
</MudIconButton> |
||||||
|
</MudPaper> |
||||||
|
</MudContainer> |
||||||
|
|
||||||
|
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid"> |
||||||
|
@foreach (TelevisionShowCardViewModel card in _data.Cards) |
||||||
|
{ |
||||||
|
<MediaCard Data="@card" Link="@($"/media/tv/shows/{card.TelevisionShowId}")" DataRefreshed="@(() => RefreshData())"/> |
||||||
|
} |
||||||
|
</MudContainer> |
||||||
|
|
||||||
|
@code { |
||||||
|
private int PageSize => 100; |
||||||
|
private int _pageNumber = 1; |
||||||
|
|
||||||
|
private TelevisionShowCardResultsViewModel _data; |
||||||
|
|
||||||
|
protected override Task OnParametersSetAsync() => RefreshData(); |
||||||
|
|
||||||
|
private async Task RefreshData() => |
||||||
|
_data = await Mediator.Send(new GetTelevisionShowCards(_pageNumber, PageSize)); |
||||||
|
|
||||||
|
private async Task PrevPage() |
||||||
|
{ |
||||||
|
_pageNumber -= 1; |
||||||
|
await RefreshData(); |
||||||
|
} |
||||||
|
|
||||||
|
private async Task NextPage() |
||||||
|
{ |
||||||
|
_pageNumber += 1; |
||||||
|
await RefreshData(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue