[frontend] Refactor JSInterop and state saving in Virtualscroller

This commit is contained in:
Lilian 2024-07-22 21:06:17 +02:00
parent ba42e19beb
commit aa3a3b6787
No known key found for this signature in database
3 changed files with 53 additions and 26 deletions

View file

@ -4,6 +4,7 @@ using Iceshrimp.Shared.Schemas.Web;
using Ljbc1994.Blazor.IntersectionObserver; using Ljbc1994.Blazor.IntersectionObserver;
using Ljbc1994.Blazor.IntersectionObserver.API; using Ljbc1994.Blazor.IntersectionObserver.API;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.JSInterop; using Microsoft.JSInterop;
namespace Iceshrimp.Frontend.Components; namespace Iceshrimp.Frontend.Components;
@ -14,6 +15,7 @@ public partial class VirtualScroller : IAsyncDisposable
[Inject] private IJSRuntime Js { get; set; } = null!; [Inject] private IJSRuntime Js { get; set; } = null!;
[Inject] private StateService StateService { get; set; } = null!; [Inject] private StateService StateService { get; set; } = null!;
[Inject] private MessageService MessageService { get; set; } = null!; [Inject] private MessageService MessageService { get; set; } = null!;
[Inject] private NavigationManager Navigation { get; set; } = null!;
[Parameter] [EditorRequired] public required List<NoteResponse> NoteResponseList { get; set; } [Parameter] [EditorRequired] public required List<NoteResponse> NoteResponseList { get; set; }
[Parameter] [EditorRequired] public required Func<Task<bool>> ReachedEnd { get; set; } [Parameter] [EditorRequired] public required Func<Task<bool>> ReachedEnd { get; set; }
[Parameter] [EditorRequired] public required EventCallback ReachedStart { get; set; } [Parameter] [EditorRequired] public required EventCallback ReachedStart { get; set; }
@ -31,6 +33,7 @@ public partial class VirtualScroller : IAsyncDisposable
private bool _loadingTop = false; private bool _loadingTop = false;
private bool _loadingBottom = false; private bool _loadingBottom = false;
private bool _setScroll = false; private bool _setScroll = false;
private IDisposable? _locationChangeHandlerDisposable;
private ElementReference Ref private ElementReference Ref
{ {
@ -38,17 +41,20 @@ public partial class VirtualScroller : IAsyncDisposable
} }
private bool _interlock = false; private bool _interlock = false;
private IJSObjectReference Module { get; set; } = null!; private IJSInProcessObjectReference Module { get; set; } = null!;
private void InitialRender(string? id) private void InitialRender(string? id)
{ {
State.RenderedList = NoteResponseList.Count < _count ? NoteResponseList : NoteResponseList.GetRange(0, _count); State.RenderedList = NoteResponseList.Count < _count ? NoteResponseList : NoteResponseList.GetRange(0, _count);
} }
public async ValueTask DisposeAsync() public ValueTask DisposeAsync()
{ {
await SaveState(); // SaveState();
State.Dispose();
_locationChangeHandlerDisposable?.Dispose();
MessageService.AnyNoteDeleted -= OnNoteDeleted; MessageService.AnyNoteDeleted -= OnNoteDeleted;
return ValueTask.CompletedTask;
} }
private async Task LoadOlder() private async Task LoadOlder()
@ -75,17 +81,17 @@ public partial class VirtualScroller : IAsyncDisposable
StateHasChanged(); StateHasChanged();
} }
private async Task SaveState() private void SaveState()
{ {
await GetScrollTop(); GetScrollY(); // ^-^ grblll mrrp
StateService.VirtualScroller.SetState("home", State); StateService.VirtualScroller.SetState("home", State);
} }
private async Task RemoveAbove(int amount) private void RemoveAbove(int amount)
{ {
for (var i = 0; i < amount; i++) for (var i = 0; i < amount; i++)
{ {
var height = await Module.InvokeAsync<int>("GetHeight", _refs[i]); var height = Module.Invoke<int>("GetHeight", _refs[i]);
State.PadTop += height; State.PadTop += height;
State.Height[State.RenderedList[i].Id] = height; State.Height[State.RenderedList[i].Id] = height;
} }
@ -116,7 +122,7 @@ public partial class VirtualScroller : IAsyncDisposable
if (State.PadBottom > 0) State.PadBottom -= heightChange; if (State.PadBottom > 0) State.PadBottom -= heightChange;
State.RenderedList.AddRange(a); State.RenderedList.AddRange(a);
await RemoveAbove(UpdateCount); RemoveAbove(UpdateCount);
_interlock = false; _interlock = false;
StateHasChanged(); StateHasChanged();
} }
@ -124,13 +130,13 @@ public partial class VirtualScroller : IAsyncDisposable
await OvrscrlObsvBottom.Observe(_padBotRef); await OvrscrlObsvBottom.Observe(_padBotRef);
} }
private async Task Up(int updateCount) private async ValueTask Up(int updateCount)
{ {
if (OvrscrlObsvTop is null) throw new Exception("Tried to use observer that does not exist"); if (OvrscrlObsvTop is null) throw new Exception("Tried to use observer that does not exist");
await OvrscrlObsvTop.Disconnect(); await OvrscrlObsvTop.Disconnect();
for (var i = 0; i < updateCount; i++) for (var i = 0; i < updateCount; i++)
{ {
var height = await Module.InvokeAsync<int>("GetHeight", _refs[i]); var height = Module.Invoke<int>("GetHeight", _refs[i]);
State.PadBottom += height; State.PadBottom += height;
State.Height[State.RenderedList[i].Id] = height; State.Height[State.RenderedList[i].Id] = height;
} }
@ -217,15 +223,15 @@ public partial class VirtualScroller : IAsyncDisposable
} }
} }
private async Task GetScrollTop() private void GetScrollY()
{ {
var scrollTop = await Module.InvokeAsync<float>("GetScrollTop", _scroller); var scrollTop = Module.Invoke<float>("GetScrollY");
State.ScrollTop = scrollTop; State.ScrollTop = scrollTop;
} }
private async Task SetScrollTop() private void SetScrollY()
{ {
await Module.InvokeVoidAsync("SetScrollTop", State.ScrollTop, _scroller); Module.InvokeVoid("SetScrollY", State.ScrollTop);
} }
private void OnNoteDeleted(object? _, NoteResponse note) private void OnNoteDeleted(object? _, NoteResponse note)
@ -234,10 +240,17 @@ public partial class VirtualScroller : IAsyncDisposable
StateHasChanged(); StateHasChanged();
} }
private ValueTask LocationChangeHandler(LocationChangingContext arg)
{
SaveState();
return ValueTask.CompletedTask;
}
protected override void OnInitialized() protected override void OnInitialized()
{ {
State = StateService.VirtualScroller.CreateStateObject(); State = StateService.VirtualScroller.CreateStateObject();
MessageService.AnyNoteDeleted += OnNoteDeleted; MessageService.AnyNoteDeleted += OnNoteDeleted;
_locationChangeHandlerDisposable = Navigation.RegisterLocationChangingHandler(LocationChangeHandler);
try try
{ {
var virtualScrollerState = StateService.VirtualScroller.GetState("home"); var virtualScrollerState = StateService.VirtualScroller.GetState("home");
@ -259,13 +272,13 @@ public partial class VirtualScroller : IAsyncDisposable
{ {
if (firstRender) if (firstRender)
{ {
Module = await Js.InvokeAsync<IJSObjectReference>("import", "./Components/VirtualScroller.razor.js"); Module = (IJSInProcessObjectReference) await Js.InvokeAsync<IJSObjectReference>("import", "./Components/VirtualScroller.razor.js");
await SetupObservers(); await SetupObservers();
} }
if (_setScroll) if (_setScroll)
{ {
await SetScrollTop(); SetScrollY();
_setScroll = false; _setScroll = false;
} }
} }

View file

@ -2,12 +2,26 @@ export function GetHeight(ref) {
if (ref != null) { if (ref != null) {
return ref.scrollHeight; return ref.scrollHeight;
} else { } else {
console.log("invalid ref")
return 0; return 0;
} }
} }
export function GetScrollTop(ref) { export function GetScrollTop(ref) {
if (ref != null) {
return ref.scrollTop; return ref.scrollTop;
} else {
console.log("invalid ref")
return 0;
}
}
export function GetScrollY(){
return window.scrollY;
}
export function SetScrollY(number){
window.scroll(window.scrollX, number);
} }
export function SetScrollTop(number, ref) { export function SetScrollTop(number, ref) {

View file

@ -37,7 +37,7 @@ internal class VirtualScrollerState : IDisposable
public int PadTop = 0; public int PadTop = 0;
public List<NoteResponse> RenderedList = []; public List<NoteResponse> RenderedList = [];
public float ScrollTop = 0; public float ScrollTop = 0;
private MessageService _messageService; private readonly MessageService _messageService;
private void OnNoteChanged(object? _, NoteResponse note) private void OnNoteChanged(object? _, NoteResponse note)
{ {