diff options
| -rw-r--r-- | Pages/Gallery.razor | 103 |
1 files changed, 78 insertions, 25 deletions
diff --git a/Pages/Gallery.razor b/Pages/Gallery.razor index 669ac28..241bed0 100644 --- a/Pages/Gallery.razor +++ b/Pages/Gallery.razor @@ -4,12 +4,13 @@ @inject ITagService tagService @inject ISearchService searchService @inject IUserService userService +@inject IJSRuntime jsRuntime @implements IDisposable <PageTitle>@Title</PageTitle> <div style="padding:var(--size-default-gap);"> - @foreach(var media in Media) { + @foreach(var media in displayMedia) { // Precalculate thumbnail size to help the browser // lay out the images during initial page load int width = media.Width * 200 / media.Height; @@ -19,6 +20,21 @@ } </div> +<div id="canary"/> + +<script suppress-error="BL9992"> + function registerScrollObserver(dotNetObject) { + var scrollObserver = new IntersectionObserver( + async (e) => { + if(e[0].isIntersecting) { + await dotNetObject.invokeMethodAsync('LoadMore'); + } + }, + { threshold: [1] }); + scrollObserver.observe(document.getElementById("canary")); + } +</script> + @code { [Parameter] [SupplyParameterFromQuery(Name = "q")] @@ -28,6 +44,8 @@ [SupplyParameterFromQuery] public bool Ingest { get; set; } = false; + public const int PageSize = 50; + private string Title { get { if(Query is null) @@ -37,42 +55,75 @@ } } - private Media[] Media; + private List<Media> displayMedia; + private Media[] queryResult; + private IEnumerator<Media> mediaEnumerator; protected override void OnInitialized() => userService.ShowNsfwChanged += ShowNsfwChanged; protected override void OnParametersSet() => LoadMedia(); + protected override void OnAfterRender(bool firstRender) { + if(firstRender) + jsRuntime.InvokeVoidAsync( + "registerScrollObserver", + DotNetObjectReference.Create(this)); + } + private void LoadMedia() { using var db = dbFactory.CreateDbContext(); - IEnumerable<Media> media = db.Media - .Include(m => m.Tags) - .OrderByDescending(m => m.ObjectId) - .ToArray(); + if(Query is not null) { + queryResult = searchService.Search(Query) + .OrderByDescending(m => m.ObjectId) + .ToArray(); + } else { + queryResult = db.Media + .Include(m => m.Tags) + .OrderByDescending(m => m.ObjectId) + .ToArray(); + } - if(Query is not null) - media = searchService.Search(Query) - .OrderByDescending(m => m.ObjectId); + mediaEnumerator = FilterMedia(queryResult).GetEnumerator(); - if(Ingest) - media = media - .AsEnumerable() - .Where(m => m.IsIngest); + displayMedia = new(); - // Filter both NSFW AND ingest images if we're not showing NSFW - if(!userService.ShowNsfw) { - var nsfwTags = tagService.TagsThatImply(HBContext.NsfwTag) - .Select(td => td.ObjectId) - .ToArray(); - media = media - .AsEnumerable() - .Where(m => !m.Tags.Select(t => t.TagDefinitionId).Intersect(nsfwTags).Any()) - .Where(m => !m.IsIngest); - } + LoadMore(); + } + + [JSInvokable("LoadMore")] + public void LoadMore() { + for(int i = 0; i < PageSize; i++) { + if(!mediaEnumerator.MoveNext()) + break; + displayMedia.Add(mediaEnumerator.Current); + } + StateHasChanged(); + } + + private IEnumerable<Media> FilterMedia(IEnumerable<Media> media) { + var nsfwTags = tagService.TagsThatImply(HBContext.NsfwTag) + .Select(td => td.ObjectId) + .ToArray(); + + using var enumerator = media.GetEnumerator(); - Media = media.ToArray(); + while(true) { + bool success = enumerator.MoveNext(); + if(!success) + break; + Media? m = enumerator.Current; + + if(!userService.ShowNsfw) + if(m.Tags.Select(t => t.TagDefinitionId).Intersect(nsfwTags).Any() || m.IsIngest) + continue; + + if(m.IsIngest != Ingest) + continue; + + yield return m; + } } private async void ShowNsfwChanged(object? sender, bool showNsfw) { @@ -82,6 +133,8 @@ }); } - public void Dispose() => + public void Dispose() { + mediaEnumerator.Dispose(); userService.ShowNsfwChanged -= ShowNsfwChanged; + } } |
