summaryrefslogtreecommitdiff
path: root/Pages/Gallery.razor
diff options
context:
space:
mode:
Diffstat (limited to 'Pages/Gallery.razor')
-rw-r--r--Pages/Gallery.razor149
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;
+ }
+}