From 854979b35946027fcc7c51d8e63a2c036b2ef6b5 Mon Sep 17 00:00:00 2001 From: Lilian Date: Sun, 21 Jul 2024 22:27:32 +0200 Subject: [PATCH] [frontend] Refactor MessageSvc to implement note deletion (ISH-404) --- .../Components/Note/Note.razor.cs | 8 ++- .../Components/RecursiveNote.razor | 7 ++- .../Core/Services/MessageService.cs | 60 +++++++++++++++---- .../StateServicePatterns/TimelineState.cs | 18 ++++-- Iceshrimp.Frontend/Pages/SingleNote.razor | 5 +- 5 files changed, 74 insertions(+), 24 deletions(-) diff --git a/Iceshrimp.Frontend/Components/Note/Note.razor.cs b/Iceshrimp.Frontend/Components/Note/Note.razor.cs index 39b93467..fadcca7b 100644 --- a/Iceshrimp.Frontend/Components/Note/Note.razor.cs +++ b/Iceshrimp.Frontend/Components/Note/Note.razor.cs @@ -14,7 +14,8 @@ public partial class Note : IDisposable [Parameter] [EditorRequired] public required NoteResponse NoteResponse { get; set; } [Parameter] public bool Indented { get; set; } - private bool _shouldRender = false; + private bool _shouldRender = false; + private IDisposable _noteChangedHandler = null!; public void React(EmojiResponse emoji) { @@ -122,7 +123,7 @@ public partial class Note : IDisposable protected override void OnInitialized() { - MessageSvc.Register(NoteResponse.Id, OnNoteChanged); + _noteChangedHandler = MessageSvc.Register(NoteResponse.Id, OnNoteChanged, MessageService.Type.Updated); } public void Reply() @@ -176,10 +177,11 @@ public partial class Note : IDisposable public async Task Delete() { await ApiService.Notes.DeleteNote(NoteResponse.Id); + await MessageSvc.DeleteNote(NoteResponse); } public void Dispose() { - MessageSvc.Unregister(NoteResponse.Id, OnNoteChanged); + _noteChangedHandler.Dispose(); } } \ No newline at end of file diff --git a/Iceshrimp.Frontend/Components/RecursiveNote.razor b/Iceshrimp.Frontend/Components/RecursiveNote.razor index e1acce90..9189ed32 100644 --- a/Iceshrimp.Frontend/Components/RecursiveNote.razor +++ b/Iceshrimp.Frontend/Components/RecursiveNote.razor @@ -65,11 +65,12 @@ [Parameter] [EditorRequired] public required NoteResponse Note { get; set; } [Parameter] [EditorRequired] public required int Depth { get; set; } [Parameter] [EditorRequired] public required int MaxDepth { get; set; } - private bool _indented = false; + private bool _indented = false; + private IDisposable _noteChangedHandler = null!; protected override void OnInitialized() { - MessageService.Register(Note.Id, OnNoteChanged); + _noteChangedHandler = MessageService.Register(Note.Id, OnNoteChanged, MessageService.Type.Updated); if (Depth > 0 || Note.Descendants?.Count > 0) { _indented = true; @@ -99,6 +100,6 @@ public void Dispose() { - MessageService.Unregister(Note.Id, OnNoteChanged); + _noteChangedHandler.Dispose(); } } \ No newline at end of file diff --git a/Iceshrimp.Frontend/Core/Services/MessageService.cs b/Iceshrimp.Frontend/Core/Services/MessageService.cs index e66caa8a..19b24d76 100644 --- a/Iceshrimp.Frontend/Core/Services/MessageService.cs +++ b/Iceshrimp.Frontend/Core/Services/MessageService.cs @@ -4,28 +4,39 @@ namespace Iceshrimp.Frontend.Core.Services; internal class MessageService { - public event EventHandler? AnyNoteChanged; + public event EventHandler? AnyNoteChanged; + public event EventHandler? AnyNoteDeleted; - public Dictionary> NoteChangedHandlers = new(); + private readonly Dictionary<(string, Type), EventHandler> _noteChangedHandlers = new(); - public void Register(string id, EventHandler func) + + public enum Type { - if (NoteChangedHandlers.ContainsKey(id)) + Updated, + Deleted + } + public NoteMessageHandler Register(string id, EventHandler func, Type type) + { + var tuple = (id, type); + if (_noteChangedHandlers.ContainsKey(tuple)) { - NoteChangedHandlers[id] += func; + _noteChangedHandlers[tuple] += func; } else { - NoteChangedHandlers.Add(id, func); + _noteChangedHandlers.Add(tuple, func); } + + return new NoteMessageHandler(func, id, type, this); } - public void Unregister(string id, EventHandler func) + private void Unregister(string id, EventHandler func, Type type) { - if (NoteChangedHandlers.ContainsKey(id)) + var tuple = (id, type); + if (_noteChangedHandlers.ContainsKey(tuple)) { #pragma warning disable CS8601 - NoteChangedHandlers[id] -= func; + _noteChangedHandlers[tuple] -= func; #pragma warning restore CS8601 } else @@ -33,11 +44,40 @@ internal class MessageService throw new ArgumentException("Tried to unregister from callback that doesn't exist"); } } + + public class NoteMessageHandler : IDisposable + { + private readonly EventHandler _handler; + private readonly string _id; + private readonly Type _type; + private readonly MessageService _messageService; + + public NoteMessageHandler(EventHandler handler, string id, Type type, MessageService messageService) + { + _handler = handler; + _id = id; + _type = type; + _messageService = messageService; + } + + public void Dispose() + { + _messageService.Unregister(_id, _handler, _type); + } + } public Task UpdateNote(NoteResponse note) { AnyNoteChanged?.Invoke(this, note); - NoteChangedHandlers.TryGetValue(note.Id, out var xHandler); + _noteChangedHandlers.TryGetValue((note.Id, Type.Updated), out var xHandler); + xHandler?.Invoke(this, note); + return Task.CompletedTask; + } + + public Task DeleteNote(NoteResponse note) + { + AnyNoteDeleted?.Invoke(this, note); + _noteChangedHandlers.TryGetValue((note.Id, Type.Deleted), out var xHandler); xHandler?.Invoke(this, note); return Task.CompletedTask; } diff --git a/Iceshrimp.Frontend/Core/Services/StateServicePatterns/TimelineState.cs b/Iceshrimp.Frontend/Core/Services/StateServicePatterns/TimelineState.cs index dce4b4cb..d5713aaf 100644 --- a/Iceshrimp.Frontend/Core/Services/StateServicePatterns/TimelineState.cs +++ b/Iceshrimp.Frontend/Core/Services/StateServicePatterns/TimelineState.cs @@ -35,12 +35,12 @@ internal class TimelineState : IDisposable [SetsRequiredMembers] public TimelineState(List timeline, string? maxId, string? minId, MessageService messageService) { - MaxId = maxId; - MinId = minId; - Timeline = timeline; - MessageService = messageService; + MaxId = maxId; + MinId = minId; + Timeline = timeline; + MessageService = messageService; MessageService.AnyNoteChanged += OnNoteChanged; - + MessageService.AnyNoteDeleted += OnNoteDeleted; } private void OnNoteChanged(object? _, NoteResponse note) @@ -48,12 +48,18 @@ internal class TimelineState : IDisposable var i = Timeline.FindIndex(p => p.Id == note.Id); if (i >= 0) { - Timeline[i].Liked = note.Liked; + Timeline[i] = note; } } + private void OnNoteDeleted(object? _, NoteResponse note) + { + Timeline.Remove(note); + } + public void Dispose() { MessageService.AnyNoteChanged -= OnNoteChanged; + MessageService.AnyNoteDeleted -= OnNoteDeleted; } } \ No newline at end of file diff --git a/Iceshrimp.Frontend/Pages/SingleNote.razor b/Iceshrimp.Frontend/Pages/SingleNote.razor index 943a01ad..b1952d03 100644 --- a/Iceshrimp.Frontend/Pages/SingleNote.razor +++ b/Iceshrimp.Frontend/Pages/SingleNote.razor @@ -62,6 +62,7 @@ else private int _depth = 20; private ElementReference Scroller { get; set; } private IDisposable? _locationChangingHandlerDisposable; + private IDisposable? _noteChangedHandler; protected override async Task OnParametersSetAsync() { @@ -88,7 +89,7 @@ else protected override void OnInitialized() { - if (NoteId != null) MessageService.Register(NoteId, OnNoteChanged); + if (NoteId != null) _noteChangedHandler = MessageService.Register(NoteId, OnNoteChanged, MessageService.Type.Updated); _locationChangingHandlerDisposable = Navigation.RegisterLocationChangingHandler(LocationChangeHandler); } @@ -142,7 +143,7 @@ else public void Dispose() { - if (NoteId != null) MessageService.Unregister(NoteId, OnNoteChanged); + if (_noteChangedHandler != null) _noteChangedHandler.Dispose(); SaveState(); _locationChangingHandlerDisposable?.Dispose(); }