1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
@page "/"
@page "/Gallery"
@inject ITagService tagService
@inject IFeedService feedService
@inject IUserService userService
@inject IJSRuntime jsRuntime
@implements IDisposable
@attribute [Authorize]
<PageTitle>@Title</PageTitle>
@if(Ingest && !userService.UserSessionState.ShowNsfw) {
<div id="feed-error">
<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>
} else if(TagId is not null && Query is not null) {
<div id="feed-error">
<p><center>Invalid query parameters! Both a search query and</center></p>
<p><center>a tag ID have been specified!</center></p>
</div>
} else {
<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('LoadMedia', false);
}
},
{ threshold: [1] });
scrollObserver.observe(document.getElementById("canary"));
}
</script>
@code {
[Parameter]
[SupplyParameterFromQuery(Name = "t")]
public Guid? TagId { get; set; }
[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;
protected override void OnInitialized() =>
userService.UserSessionState.OnStateChange += ShowNsfwChanged;
protected override void OnParametersSet() => LoadMedia(true);
protected override void OnAfterRender(bool firstRender) {
if(firstRender)
jsRuntime.InvokeVoidAsync(
"registerScrollObserver",
DotNetObjectReference.Create(this));
}
[JSInvokable("LoadMedia")]
public void LoadMedia(bool initial = false) {
Media? key = displayMedia?.Any() ?? false && !initial ? displayMedia.Last() : null;
if(initial)
displayMedia = new();
if(TagId is not null && Query is null) {
displayMedia!.AddRange(feedService.LoadChunk(
selectIngest: Ingest,
includeNsfw: userService.UserSessionState.ShowNsfw,
tagId: (Guid) TagId!,
key: key,
count: PageSize));
} else if(Query is not null && TagId is null) {
displayMedia!.AddRange(feedService.LoadChunk(
selectIngest: Ingest,
includeNsfw: userService.UserSessionState.ShowNsfw,
query: string.IsNullOrWhiteSpace(Query) ? null : Query,
key: key,
count: PageSize));
} else {
displayMedia!.AddRange(feedService.LoadChunk(
selectIngest: Ingest,
includeNsfw: userService.UserSessionState.ShowNsfw,
key: key,
count: PageSize));
}
StateHasChanged();
}
private async void ShowNsfwChanged(UserSessionState userSessionState) {
await InvokeAsync(() => {
LoadMedia(true);
});
}
public void Dispose() =>
userService.UserSessionState.OnStateChange -= ShowNsfwChanged;
}
|