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
129
130
|
@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 id="canary" style="height:1px;"></div>
</div>
}
<script suppress-error="BL9992">
function registerScrollObserver(dotNetObject) {
var scrollObserver = new IntersectionObserver(
async (e) => {
if(e[0].isIntersecting) {
await dotNetObject.invokeMethodAsync('LoadMedia', false);
}
},
{
root: document.getElementById('content'),
threshold: 0
});
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;
}
|