From aa3a3b678774498d3d8c5489828594fd3c2c9320 Mon Sep 17 00:00:00 2001 From: Lilian Date: Mon, 22 Jul 2024 21:06:17 +0200 Subject: [PATCH] [frontend] Refactor JSInterop and state saving in Virtualscroller --- .../Components/VirtualScroller.razor.cs | 51 ++++++++++++------- .../Components/VirtualScroller.razor.js | 16 +++++- .../VirtualScrollerState.cs | 12 ++--- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/Iceshrimp.Frontend/Components/VirtualScroller.razor.cs b/Iceshrimp.Frontend/Components/VirtualScroller.razor.cs index c345822a..90c4d215 100644 --- a/Iceshrimp.Frontend/Components/VirtualScroller.razor.cs +++ b/Iceshrimp.Frontend/Components/VirtualScroller.razor.cs @@ -4,6 +4,7 @@ using Iceshrimp.Shared.Schemas.Web; using Ljbc1994.Blazor.IntersectionObserver; using Ljbc1994.Blazor.IntersectionObserver.API; using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Routing; using Microsoft.JSInterop; namespace Iceshrimp.Frontend.Components; @@ -14,6 +15,7 @@ public partial class VirtualScroller : IAsyncDisposable [Inject] private IJSRuntime Js { get; set; } = null!; [Inject] private StateService StateService { get; set; } = null!; [Inject] private MessageService MessageService { get; set; } = null!; + [Inject] private NavigationManager Navigation { get; set; } = null!; [Parameter] [EditorRequired] public required List NoteResponseList { get; set; } [Parameter] [EditorRequired] public required Func> ReachedEnd { 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 _loadingBottom = false; private bool _setScroll = false; + private IDisposable? _locationChangeHandlerDisposable; private ElementReference Ref { @@ -38,17 +41,20 @@ public partial class VirtualScroller : IAsyncDisposable } private bool _interlock = false; - private IJSObjectReference Module { get; set; } = null!; + private IJSInProcessObjectReference Module { get; set; } = null!; private void InitialRender(string? id) { 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; + return ValueTask.CompletedTask; } private async Task LoadOlder() @@ -75,17 +81,17 @@ public partial class VirtualScroller : IAsyncDisposable StateHasChanged(); } - private async Task SaveState() + private void SaveState() { - await GetScrollTop(); + GetScrollY(); // ^-^ grblll mrrp StateService.VirtualScroller.SetState("home", State); } - private async Task RemoveAbove(int amount) + private void RemoveAbove(int amount) { for (var i = 0; i < amount; i++) { - var height = await Module.InvokeAsync("GetHeight", _refs[i]); + var height = Module.Invoke("GetHeight", _refs[i]); State.PadTop += height; State.Height[State.RenderedList[i].Id] = height; } @@ -116,7 +122,7 @@ public partial class VirtualScroller : IAsyncDisposable if (State.PadBottom > 0) State.PadBottom -= heightChange; State.RenderedList.AddRange(a); - await RemoveAbove(UpdateCount); + RemoveAbove(UpdateCount); _interlock = false; StateHasChanged(); } @@ -124,13 +130,13 @@ public partial class VirtualScroller : IAsyncDisposable 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"); await OvrscrlObsvTop.Disconnect(); for (var i = 0; i < updateCount; i++) { - var height = await Module.InvokeAsync("GetHeight", _refs[i]); + var height = Module.Invoke("GetHeight", _refs[i]); State.PadBottom += height; State.Height[State.RenderedList[i].Id] = height; } @@ -217,27 +223,34 @@ public partial class VirtualScroller : IAsyncDisposable } } - private async Task GetScrollTop() + private void GetScrollY() { - var scrollTop = await Module.InvokeAsync("GetScrollTop", _scroller); + var scrollTop = Module.Invoke("GetScrollY"); 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) { State.RenderedList.Remove(note); StateHasChanged(); } + private ValueTask LocationChangeHandler(LocationChangingContext arg) + { + SaveState(); + return ValueTask.CompletedTask; + } + protected override void OnInitialized() { - State = StateService.VirtualScroller.CreateStateObject(); - MessageService.AnyNoteDeleted += OnNoteDeleted; + State = StateService.VirtualScroller.CreateStateObject(); + MessageService.AnyNoteDeleted += OnNoteDeleted; + _locationChangeHandlerDisposable = Navigation.RegisterLocationChangingHandler(LocationChangeHandler); try { var virtualScrollerState = StateService.VirtualScroller.GetState("home"); @@ -259,13 +272,13 @@ public partial class VirtualScroller : IAsyncDisposable { if (firstRender) { - Module = await Js.InvokeAsync("import", "./Components/VirtualScroller.razor.js"); + Module = (IJSInProcessObjectReference) await Js.InvokeAsync("import", "./Components/VirtualScroller.razor.js"); await SetupObservers(); } if (_setScroll) { - await SetScrollTop(); + SetScrollY(); _setScroll = false; } } diff --git a/Iceshrimp.Frontend/Components/VirtualScroller.razor.js b/Iceshrimp.Frontend/Components/VirtualScroller.razor.js index e373f91a..338f9958 100644 --- a/Iceshrimp.Frontend/Components/VirtualScroller.razor.js +++ b/Iceshrimp.Frontend/Components/VirtualScroller.razor.js @@ -2,12 +2,26 @@ export function GetHeight(ref) { if (ref != null) { return ref.scrollHeight; } else { + console.log("invalid ref") return 0; } } export function GetScrollTop(ref) { - return ref.scrollTop; + if (ref != null) { + 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) { diff --git a/Iceshrimp.Frontend/Core/Services/StateServicePatterns/VirtualScrollerState.cs b/Iceshrimp.Frontend/Core/Services/StateServicePatterns/VirtualScrollerState.cs index 7a13bf3a..225462f5 100644 --- a/Iceshrimp.Frontend/Core/Services/StateServicePatterns/VirtualScrollerState.cs +++ b/Iceshrimp.Frontend/Core/Services/StateServicePatterns/VirtualScrollerState.cs @@ -32,12 +32,12 @@ internal class VirtualScrollerState : IDisposable _messageService.AnyNoteDeleted += OnNoteDeleted; } - public Dictionary Height = new(); - public int PadBottom = 0; - public int PadTop = 0; - public List RenderedList = []; - public float ScrollTop = 0; - private MessageService _messageService; + public Dictionary Height = new(); + public int PadBottom = 0; + public int PadTop = 0; + public List RenderedList = []; + public float ScrollTop = 0; + private readonly MessageService _messageService; private void OnNoteChanged(object? _, NoteResponse note) {