[frontend] Refactor JSInterop and state saving in Virtualscroller
This commit is contained in:
parent
ba42e19beb
commit
aa3a3b6787
3 changed files with 53 additions and 26 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue