diff options
Diffstat (limited to 'Pages/Gallery.razor')
| -rw-r--r-- | Pages/Gallery.razor | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/Pages/Gallery.razor b/Pages/Gallery.razor new file mode 100644 index 0000000..762ef7f --- /dev/null +++ b/Pages/Gallery.razor @@ -0,0 +1,149 @@ +@page "/" +@page "/Gallery" +@inject IDbContextFactory<HBContext> dbFactory +@inject ITagService tagService +@inject ISearchService searchService +@inject IUserService userService +@inject IJSRuntime jsRuntime +@implements IDisposable +@attribute [Authorize] + +<PageTitle>@Title</PageTitle> + +@if(Ingest && !userService.UserSessionState.ShowNsfw) { + <div id="ingest-warning"> + <p><center>Ingest feed is not available unless NSFW mode is enabled!</center></p> + <p><center><i>You must enable NSFW mode to continue...</i></center></p> + </div> +} + +<div style="padding:var(--size-default-gap);"> + @foreach(var media in displayMedia) { + // Precalculate thumbnail size to help the browser + // lay out the images during initial page load + int width = (int) media.CurrentUploadedFile.Width! * 200 / (int) media.CurrentUploadedFile.Height!; + <a href="/ViewMedia?m=@(media.Guid)"> + <img src="/media/thumb/@(media.Guid)?h=200" width=@width height="200"/> + </a> + } +</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")] + public string? Query { get; set; } + + [Parameter] + [SupplyParameterFromQuery] + public bool Ingest { get; set; } = false; + + public const int PageSize = 50; + + private string Title { + get { + if(Query is null) + return Ingest ? "Ingest Feed" : "Gallery"; + else + return "Search Results"; + } + } + + private List<Media> displayMedia; + private Media[] queryResult; + private IEnumerator<Media> mediaEnumerator; + + protected override void OnInitialized() => + userService.UserSessionState.OnStateChange += 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(); + + if(Query is not null) { + queryResult = searchService.Search(Query) + .OrderByDescending(m => m.ObjectId) + .ToArray(); + } else { + queryResult = db.Media + .Include(m => m.Tags) + .Include(m => m.CurrentUploadedFile) + .OrderByDescending(m => m.ObjectId) + .ToArray(); + } + + mediaEnumerator = FilterMedia(queryResult).GetEnumerator(); + + displayMedia = new(); + + 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(); + + while(true) { + bool success = enumerator.MoveNext(); + if(!success) + break; + Media? m = enumerator.Current; + + if(!userService.UserSessionState.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(UserSessionState userSessionState) { + await InvokeAsync(() => { + LoadMedia(); + StateHasChanged(); + }); + } + + public void Dispose() { + mediaEnumerator.Dispose(); + userService.UserSessionState.OnStateChange -= ShowNsfwChanged; + } +} |
