summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Pages/Gallery.razor103
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;
+ }
}