@ -5,6 +5,7 @@
@@ -5,6 +5,7 @@
@using ErsatzTV.Extensions
@inherits MultiSelectBase<Search>
@inject NavigationManager NavigationManager
@inject PersistentComponentState ApplicationState
<MudPaper Square="true" Style="display: flex; height: 64px; left: 240px; padding: 0; position: fixed; right: 0; z-index: 100;">
<div style="display: flex; flex-direction: row; margin-bottom: auto; margin-top: auto; width: 100%" class="ml-6 mr-6">
@ -29,47 +30,47 @@
@@ -29,47 +30,47 @@
}
else
{
if (_movies?.Count > 0)
if (_movies?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#movies")" Style="margin-bottom: auto; margin-top: auto">@_movies.Count Movies</MudLink>
}
if (_shows?.Count > 0)
if (_shows?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#shows")" Style="margin-bottom: auto; margin-top: auto">@_shows.Count Shows</MudLink>
}
if (_seasons?.Count > 0)
if (_seasons?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#seasons")" Style="margin-bottom: auto; margin-top: auto">@_seasons.Count Seasons</MudLink>
}
if (_episodes?.Count > 0)
if (_episodes?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#episodes")" Style="margin-bottom: auto; margin-top: auto">@_episodes.Count Episodes</MudLink>
}
if (_artists?.Count > 0)
if (_artists?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#artists")" Style="margin-bottom: auto; margin-top: auto">@_artists.Count Artists</MudLink>
}
if (_musicVideos?.Count > 0)
if (_musicVideos?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#music_videos")" Style="margin-bottom: auto; margin-top: auto">@_musicVideos.Count Music Videos</MudLink>
}
if (_otherVideos?.Count > 0)
if (_otherVideos?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#other_videos")" Style="margin-bottom: auto; margin-top: auto">@_otherVideos.Count Other Videos</MudLink>
}
if (_songs?.Count > 0)
if (_songs?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#songs")" Style="margin-bottom: auto; margin-top: auto">@_songs.Count Songs</MudLink>
}
if (_images?.Count > 0)
if (_images?.Cards.C ount > 0)
{
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#images")" Style="margin-bottom: auto; margin-top: auto">@_images.Count Images</MudLink>
}
@ -93,7 +94,7 @@
@@ -93,7 +94,7 @@
</div>
</MudPaper>
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Style="margin-top: 96px">
@if (_movies?.Count > 0)
@if (_movies?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -121,7 +122,7 @@
@@ -121,7 +122,7 @@
</MudContainer>
}
@if (_shows?.Count > 0)
@if (_shows?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -149,7 +150,7 @@
@@ -149,7 +150,7 @@
</MudContainer>
}
@if (_seasons?.Count > 0)
@if (_seasons?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -177,7 +178,7 @@
@@ -177,7 +178,7 @@
</MudContainer>
}
@if (_episodes?.Count > 0)
@if (_episodes?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -206,7 +207,7 @@
@@ -206,7 +207,7 @@
</MudContainer>
}
@if (_artists?.Count > 0)
@if (_artists?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -235,7 +236,7 @@
@@ -235,7 +236,7 @@
</MudContainer>
}
@if (_musicVideos?.Count > 0)
@if (_musicVideos?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -264,7 +265,7 @@
@@ -264,7 +265,7 @@
</MudContainer>
}
@if (_otherVideos?.Count > 0)
@if (_otherVideos?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -293,7 +294,7 @@
@@ -293,7 +294,7 @@
</MudContainer>
}
@if (_songs?.Count > 0)
@if (_songs?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -322,7 +323,7 @@
@@ -322,7 +323,7 @@
</MudContainer>
}
@if (_images?.Count > 0)
@if (_images?.Cards.C ount > 0)
{
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4"
@ -353,6 +354,8 @@
@@ -353,6 +354,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private string _query;
private MovieCardResultsViewModel _movies;
private TelevisionShowCardResultsViewModel _shows;
@ -364,27 +367,102 @@
@@ -364,27 +367,102 @@
private ImageCardResultsViewModel _images;
private ArtistCardResultsViewModel _artists;
protected override Task OnInitializedAsync() => RefreshData();
private PersistingComponentStateSubscription _persistingSubscription;
protected override void Dispose(bool disposing)
{
if (disposing)
{
_persistingSubscription.Dispose();
_cts.Cancel();
_cts.Dispose();
}
base.Dispose(disposing);
}
protected override Task OnInitializedAsync()
{
_persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
return base.OnInitializedAsync();
}
private Task PersistData()
{
ApplicationState.PersistAsJson("_movies", _movies);
ApplicationState.PersistAsJson("_shows", _shows);
ApplicationState.PersistAsJson("_seasons", _seasons);
ApplicationState.PersistAsJson("_episodes", _episodes);
ApplicationState.PersistAsJson("_musicVideos", _musicVideos);
ApplicationState.PersistAsJson("_otherVideos", _otherVideos);
ApplicationState.PersistAsJson("_songs", _songs);
ApplicationState.PersistAsJson("_images", _images);
ApplicationState.PersistAsJson("_artists", _artists);
return Task.CompletedTask;
}
protected override async Task OnParametersSetAsync()
{
await RefreshData();
await InvokeAsync(StateHasChanged);
}
protected override async Task RefreshData()
{
_query = "state:FileNotFound";
if (!string.IsNullOrWhiteSpace(_query))
{
_movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50), CancellationToken);
_shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50), CancellationToken);
_seasons = await Mediator.Send(new QuerySearchIndexSeasons($"type:season AND ({_query})", 1, 50), CancellationToken);
_episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50), CancellationToken);
_musicVideos = await Mediator.Send(new QuerySearchIndexMusicVideos($"type:music_video AND ({_query})", 1, 50), CancellationToken);
_otherVideos = await Mediator.Send(new QuerySearchIndexOtherVideos($"type:other_video AND ({_query})", 1, 50), CancellationToken);
_songs = await Mediator.Send(new QuerySearchIndexSongs($"type:song AND ({_query})", 1, 50), CancellationToken);
_images = await Mediator.Send(new QuerySearchIndexImages($"type:image AND ({_query})", 1, 50), CancellationToken);
_artists = await Mediator.Send(new QuerySearchIndexArtists($"type:artist AND ({_query})", 1, 50), CancellationToken);
if (!ApplicationState.TryTakeFromJson("_movies", out _movies))
{
_movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_shows", out _shows))
{
_shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_seasons", out _seasons))
{
_seasons = await Mediator.Send(new QuerySearchIndexSeasons($"type:season AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_episodes", out _episodes))
{
_episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_musicVideos", out _musicVideos))
{
_musicVideos = await Mediator.Send(new QuerySearchIndexMusicVideos($"type:music_video AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_otherVideos", out _otherVideos))
{
_otherVideos = await Mediator.Send(new QuerySearchIndexOtherVideos($"type:other_video AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_songs", out _songs))
{
_songs = await Mediator.Send(new QuerySearchIndexSongs($"type:song AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_images", out _images))
{
_images = await Mediator.Send(new QuerySearchIndexImages($"type:image AND ({_query})", 1, 50), _cts.Token);
}
if (!ApplicationState.TryTakeFromJson("_artists", out _artists))
{
_artists = await Mediator.Send(new QuerySearchIndexArtists($"type:artist AND ({_query})", 1, 50), _cts.Token);
}
}
}
private bool IsNotEmpty =>
_movies?.Count > 0 || _shows?.Count > 0 || _seasons?.Count > 0 || _episodes?.Count > 0 || _musicVideos?.Count > 0 || _otherVideos?.Count > 0 || _songs?.Count > 0 || _artists?.Count > 0 || _images?.Count > 0;
_movies?.Cards.C ount > 0 || _shows?.Cards.C ount > 0 || _seasons?.Cards.C ount > 0 || _episodes?.Cards.C ount > 0 || _musicVideos?.Cards.C ount > 0 || _otherVideos?.Cards.C ount > 0 || _songs?.Cards.C ount > 0 || _artists?.Cards .Count > 0 || _images?.Cards .Count > 0;
private void SelectClicked(MediaCardViewModel card, MouseEventArgs e)
{
@ -558,7 +636,7 @@
@@ -558,7 +636,7 @@
.Append(imageIds)
.ToList());
Either<BaseError, Unit> addResult = await Mediator.Send(request, Cancellation Token);
Either<BaseError, Unit> addResult = await Mediator.Send(request, _cts. Token);
await addResult.Match(
Left: error =>
{
@ -628,11 +706,11 @@
@@ -628,11 +706,11 @@
var parameters = new DialogParameters { { "EntityType", entityType }, { "EntityName", entityName } };
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
IDialogReference dialog = Dialog.Show<DeleteFromDatabaseDialog>("Delete From Database", parameters, options);
IDialogReference dialog = await Dialog.ShowAsync <DeleteFromDatabaseDialog>("Delete From Database", parameters, options);
DialogResult result = await dialog.Result;
if (!result.Canceled)
if (result is not null && !result.Canceled)
{
await Mediator.Send(request, Cancellation Token);
await Mediator.Send(request, _cts. Token);
await RefreshData();
}
}
@ -645,12 +723,22 @@
@@ -645,12 +723,22 @@
var parameters = new DialogParameters { { "EntityType", count.ToString() }, { "EntityName", "missing items" } };
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
IDialogReference dialog = Dialog.Show<DeleteFromDatabaseDialog>("Delete From Database", parameters, options);
IDialogReference dialog = await Dialog.ShowAsync <DeleteFromDatabaseDialog>("Delete From Database", parameters, options);
DialogResult result = await dialog.Result;
if (!result.Canceled)
if (result is not null && !result.Canceled)
{
await Mediator.Send(new EmptyTrash(), CancellationToken);
await RefreshData();
Either<BaseError, Unit> emptyTrashResult = await Mediator.Send(new EmptyTrash(), _cts.Token);
foreach (BaseError error in emptyTrashResult.LeftToSeq())
{
Snackbar.Add(error.Value, Severity.Error);
Logger.LogError("Unexpected error emptying trash: {Error}", error.Value);
}
if (emptyTrashResult.IsRight)
{
await RefreshData();
await InvokeAsync(StateHasChanged);
}
}
}