using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ErsatzTV.Application.MediaCards; using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaCollections.Commands; using ErsatzTV.Core; using ErsatzTV.Shared; using LanguageExt; using LanguageExt.UnsafeValueAccess; using MediatR; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.Logging; using MudBlazor; using static LanguageExt.Prelude; using Unit = LanguageExt.Unit; namespace ErsatzTV.Pages { public class MultiSelectBase : FragmentNavigationBase { private readonly System.Collections.Generic.HashSet _selectedItems; private Option _recentlySelected; public MultiSelectBase() { _recentlySelected = None; _selectedItems = new System.Collections.Generic.HashSet(); } [Inject] protected IDialogService Dialog { get; set; } [Inject] protected ISnackbar Snackbar { get; set; } [Inject] protected ILogger Logger { get; set; } [Inject] protected IMediator Mediator { get; set; } protected bool IsSelected(MediaCardViewModel card) => _selectedItems.Contains(card); protected bool IsSelectMode() => _selectedItems.Any(); protected string SelectionLabel() => $"{_selectedItems.Count} {(_selectedItems.Count == 1 ? "Item" : "Items")} Selected"; protected void ClearSelection() { _selectedItems.Clear(); _recentlySelected = None; } protected virtual Task RefreshData() => Task.CompletedTask; protected void SelectClicked( Func> getSortedItems, MediaCardViewModel card, MouseEventArgs e) { if (_selectedItems.Contains(card)) { _selectedItems.Remove(card); } else { if (e.ShiftKey && _recentlySelected.IsSome) { List sorted = getSortedItems(); int start = sorted.IndexOf(_recentlySelected.ValueUnsafe()); int finish = sorted.IndexOf(card); if (start > finish) { int temp = start; start = finish; finish = temp; } for (int i = start; i < finish; i++) { _selectedItems.Add(sorted[i]); } } _recentlySelected = card; _selectedItems.Add(card); } } protected Task AddSelectionToCollection() => AddItemsToCollection( _selectedItems.OfType().Map(m => m.MovieId).ToList(), _selectedItems.OfType().Map(s => s.TelevisionShowId).ToList(), _selectedItems.OfType().Map(e => e.EpisodeId).ToList(), _selectedItems.OfType().Map(a => a.ArtistId).ToList(), _selectedItems.OfType().Map(mv => mv.MusicVideoId).ToList()); protected async Task AddItemsToCollection( List movieIds, List showIds, List episodeIds, List artistIds, List musicVideoIds, string entityName = "selected items") { int count = movieIds.Count + showIds.Count + episodeIds.Count + artistIds.Count + musicVideoIds.Count; var parameters = new DialogParameters { { "EntityType", count.ToString() }, { "EntityName", entityName } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = Dialog.Show("Add To Collection", parameters, options); DialogResult result = await dialog.Result; if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) { var request = new AddItemsToCollection( collection.Id, movieIds, showIds, episodeIds, artistIds, musicVideoIds); Either addResult = await Mediator.Send(request); addResult.Match( Left: error => { Snackbar.Add($"Unexpected error adding items to collection: {error.Value}"); Logger.LogError("Unexpected error adding items to collection: {Error}", error.Value); }, Right: _ => { Snackbar.Add( $"Added {count} items to collection {collection.Name}", Severity.Success); ClearSelection(); }); } } protected async Task RemoveSelectionFromCollection(int collectionId) { var parameters = new DialogParameters { { "EntityType", _selectedItems.Count.ToString() }, { "EntityName", "selected items" } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = Dialog.Show( "Remove From Collection", parameters, options); DialogResult result = await dialog.Result; if (!result.Cancelled) { var itemIds = _selectedItems.Map(vm => vm.MediaItemId).ToList(); await Mediator.Send( new RemoveItemsFromCollection(collectionId) { MediaItemIds = itemIds }); await RefreshData(); ClearSelection(); } } } }