[frontend/components] Fix new descendants not showing up in single note view.
This commit is contained in:
parent
60f100385d
commit
e1e78a1052
6 changed files with 69 additions and 37 deletions
|
@ -2,6 +2,7 @@
|
||||||
@using Iceshrimp.Frontend.Components.Note
|
@using Iceshrimp.Frontend.Components.Note
|
||||||
@using Iceshrimp.Frontend.Core.Miscellaneous
|
@using Iceshrimp.Frontend.Core.Miscellaneous
|
||||||
@using Iceshrimp.Frontend.Core.Services
|
@using Iceshrimp.Frontend.Core.Services
|
||||||
|
@using Iceshrimp.Frontend.Core.Services.NoteStore
|
||||||
@using Iceshrimp.Frontend.Localization
|
@using Iceshrimp.Frontend.Localization
|
||||||
@using Iceshrimp.MfmSharp
|
@using Iceshrimp.MfmSharp
|
||||||
@using Iceshrimp.Shared.Schemas.Web
|
@using Iceshrimp.Shared.Schemas.Web
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
@inject GlobalComponentSvc GlobalComponentSvc
|
@inject GlobalComponentSvc GlobalComponentSvc
|
||||||
@inject MessageService MessageService
|
@inject MessageService MessageService
|
||||||
@inject SettingsService Settings;
|
@inject SettingsService Settings;
|
||||||
|
@inject NoteActions NoteActions;
|
||||||
<dialog @onkeydown="HandleKeyDown" class="dialog" @ref="Dialog">
|
<dialog @onkeydown="HandleKeyDown" class="dialog" @ref="Dialog">
|
||||||
<div class="compose">
|
<div class="compose">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
|
@ -23,7 +25,8 @@
|
||||||
<Icon Name="Icons.X"/>
|
<Icon Name="Icons.X"/>
|
||||||
</button>
|
</button>
|
||||||
<Dropdown TBind="NoteVisibility" Elements="@DropDownCreate()" @bind-Value="NoteDraft.Visibility"/>
|
<Dropdown TBind="NoteVisibility" Elements="@DropDownCreate()" @bind-Value="NoteDraft.Visibility"/>
|
||||||
<StateButton OnClick="SendNote" @ref="SendButton" ExtraClasses="post-btn" AriaLabel="post" Disabled="@(NoteLength - ((NoteDraft.Cw?.Length ?? 0) + NoteDraft.Text.Length) < 0)">
|
<StateButton OnClick="SendNote" @ref="SendButton" ExtraClasses="post-btn" AriaLabel="post"
|
||||||
|
Disabled="@(NoteLength - ((NoteDraft.Cw?.Length ?? 0) + NoteDraft.Text.Length) < 0)">
|
||||||
<Initial>
|
<Initial>
|
||||||
@Loc["ComposeNote"]<Icon Name="Icons.PaperPlaneRight"/>
|
@Loc["ComposeNote"]<Icon Name="Icons.PaperPlaneRight"/>
|
||||||
</Initial>
|
</Initial>
|
||||||
|
@ -50,7 +53,8 @@
|
||||||
aria-label="content warning"/>
|
aria-label="content warning"/>
|
||||||
<hr class="separator"/>
|
<hr class="separator"/>
|
||||||
}
|
}
|
||||||
<textarea @ref="Textarea" @bind="NoteDraft.Text" @bind:event="oninput" class="textarea" placeholder="@TextPlaceholder" rows="5"
|
<textarea @ref="Textarea" @bind="NoteDraft.Text" @bind:event="oninput" class="textarea"
|
||||||
|
placeholder="@TextPlaceholder" rows="5"
|
||||||
cols="35" autofocus="autofocus" aria-label="note text"></textarea>
|
cols="35" autofocus="autofocus" aria-label="note text"></textarea>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
@ -69,7 +73,8 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<span title="@Loc["Character limit"]" aria-label="character limit">@(NoteLength - ((NoteDraft.Cw?.Length ?? 0) + NoteDraft.Text.Length))</span>
|
<span title="@Loc["Character limit"]"
|
||||||
|
aria-label="character limit">@(NoteLength - ((NoteDraft.Cw?.Length ?? 0) + NoteDraft.Text.Length))</span>
|
||||||
<button class="btn" title="@Loc["Preview"]" @onclick="() => Preview = !Preview"
|
<button class="btn" title="@Loc["Preview"]" @onclick="() => Preview = !Preview"
|
||||||
aria-label="preview">
|
aria-label="preview">
|
||||||
<Icon Name="Icons.Binoculars" Size="1.3rem"></Icon>
|
<Icon Name="Icons.Binoculars" Size="1.3rem"></Icon>
|
||||||
|
@ -116,12 +121,7 @@
|
||||||
Cw = null
|
Cw = null
|
||||||
};
|
};
|
||||||
|
|
||||||
private Dictionary<string, string> AvailablePlaceholders { get; set; } = new()
|
private Dictionary<string, string> AvailablePlaceholders { get; set; } = new() { { "default", "What's on your mind?" }, { "reply", "Reply goes here!" }, { "quote", "Quote this post!" } };
|
||||||
{
|
|
||||||
{ "default", "What's on your mind?" },
|
|
||||||
{ "reply", "Reply goes here!" },
|
|
||||||
{ "quote", "Quote this post!" }
|
|
||||||
};
|
|
||||||
|
|
||||||
private async Task HandleKeyDown(KeyboardEventArgs e)
|
private async Task HandleKeyDown(KeyboardEventArgs e)
|
||||||
{
|
{
|
||||||
|
@ -162,9 +162,7 @@
|
||||||
new DropdownElement<NoteVisibility>
|
new DropdownElement<NoteVisibility>
|
||||||
{
|
{
|
||||||
#pragma warning disable BL0005 // Setting this outside the component is fine until this is reworked
|
#pragma warning disable BL0005 // Setting this outside the component is fine until this is reworked
|
||||||
Icon = DropdownIcon(vis),
|
Icon = DropdownIcon(vis), Content = DropdownContent(vis), Selection = vis
|
||||||
Content = DropdownContent(vis),
|
|
||||||
Selection = vis
|
|
||||||
#pragma warning restore BL0005
|
#pragma warning restore BL0005
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
@ -259,12 +257,7 @@
|
||||||
var settings = await Settings.GetUserSettingsAsync();
|
var settings = await Settings.GetUserSettingsAsync();
|
||||||
ReplyOrQuote = null;
|
ReplyOrQuote = null;
|
||||||
Attachments = new List<DriveFileResponse>();
|
Attachments = new List<DriveFileResponse>();
|
||||||
NoteDraft = new NoteCreateRequest
|
NoteDraft = new NoteCreateRequest { Text = "", Visibility = settings.DefaultNoteVisibility, Cw = null };
|
||||||
{
|
|
||||||
Text = "",
|
|
||||||
Visibility = settings.DefaultNoteVisibility,
|
|
||||||
Cw = null
|
|
||||||
};
|
|
||||||
TextPlaceholder = AvailablePlaceholders["default"];
|
TextPlaceholder = AvailablePlaceholders["default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,8 +288,7 @@
|
||||||
|
|
||||||
if (ReplyOrQuote != null)
|
if (ReplyOrQuote != null)
|
||||||
{
|
{
|
||||||
var res = await ApiService.Notes.GetNoteAsync(ReplyOrQuote.Id);
|
await NoteActions.RefetchNoteAsync(ReplyOrQuote);
|
||||||
if (res != null) _ = MessageService.UpdateNoteAsync(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SendButton.State = StateButton.StateEnum.Success;
|
SendButton.State = StateButton.StateEnum.Success;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
@* ReSharper disable once RedundantUsingDirective *@
|
@* ReSharper disable once RedundantUsingDirective *@
|
||||||
@using Iceshrimp.Frontend.Components.Note
|
@using Iceshrimp.Frontend.Components.Note
|
||||||
@using Iceshrimp.Frontend.Core.Services
|
@using Iceshrimp.Frontend.Core.Services
|
||||||
|
@using Iceshrimp.Frontend.Core.Services.NoteStore
|
||||||
@using Iceshrimp.Shared.Schemas.Web
|
@using Iceshrimp.Shared.Schemas.Web
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject MessageService MessageService
|
@inject MessageService MessageService
|
||||||
@inject ApiService Api
|
@inject ApiService Api
|
||||||
|
@inject RelatedStore Store
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
@if (_hidden == false)
|
@if (_hidden == false)
|
||||||
|
@ -69,12 +71,11 @@
|
||||||
[Parameter] [EditorRequired] public required int Depth { get; set; }
|
[Parameter] [EditorRequired] public required int Depth { get; set; }
|
||||||
[Parameter] [EditorRequired] public required int MaxDepth { get; set; }
|
[Parameter] [EditorRequired] public required int MaxDepth { get; set; }
|
||||||
private bool _indented = false;
|
private bool _indented = false;
|
||||||
private IDisposable _noteChangedHandler = null!;
|
|
||||||
private bool _hidden = false;
|
private bool _hidden = false;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
_noteChangedHandler = MessageService.Register(Note.Id, OnNoteChanged, MessageService.Type.Updated);
|
Store.NoteChanged += OnNoteChanged;
|
||||||
if (Depth > 0 || Note.Descendants?.Count > 0)
|
if (Depth > 0 || Note.Descendants?.Count > 0)
|
||||||
{
|
{
|
||||||
_indented = true;
|
_indented = true;
|
||||||
|
@ -89,16 +90,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNoteChanged(object? _, NoteResponse note)
|
private void OnNoteChanged(object? _, NoteResponse note)
|
||||||
|
{
|
||||||
|
if (note.Id == Note.Id)
|
||||||
{
|
{
|
||||||
var __ = Refresh();
|
var __ = Refresh();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Refresh()
|
private async Task Refresh()
|
||||||
{
|
{
|
||||||
if (Depth < MaxDepth)
|
if (Depth < MaxDepth)
|
||||||
{
|
{
|
||||||
var res = await Api.Notes.GetNoteDescendantsAsync(Note.Id, MaxDepth - Depth);
|
var res = await Store.GetDescendantsAsync(Note.Id, MaxDepth - Depth, true);
|
||||||
Note.Descendants = res;
|
if (res == null) return;
|
||||||
|
Note.Descendants = res.Select(p => p.Value).ToList();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +115,6 @@
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_noteChangedHandler.Dispose();
|
Store.NoteChanged -= OnNoteChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,6 +15,20 @@ internal class NoteActions(
|
||||||
stateSynchronizer.Broadcast(note);
|
stateSynchronizer.Broadcast(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task RefetchNoteAsync(NoteBase note)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var res = await api.Notes.GetNoteAsync(note.Id);
|
||||||
|
if (res == null) return;
|
||||||
|
Broadcast(res);
|
||||||
|
}
|
||||||
|
catch (ApiException e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Failed to fetch note.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ToggleLikeAsync(NoteBase note)
|
public async Task ToggleLikeAsync(NoteBase note)
|
||||||
{
|
{
|
||||||
if (note.Liked)
|
if (note.Liked)
|
||||||
|
|
|
@ -36,7 +36,6 @@ internal class RelatedStore : NoteMessageProvider, IDisposable
|
||||||
note.Attachments = noteResponse.Attachments;
|
note.Attachments = noteResponse.Attachments;
|
||||||
note.Reactions = noteResponse.Reactions;
|
note.Reactions = noteResponse.Reactions;
|
||||||
|
|
||||||
// container.Value.Notes[noteResponse.Id] = note;
|
|
||||||
NoteChangedHandlers.First(p => p.Key == note.Id).Value.Invoke(this, note);
|
NoteChangedHandlers.First(p => p.Key == note.Id).Value.Invoke(this, note);
|
||||||
NoteChanged?.Invoke(this, note);
|
NoteChanged?.Invoke(this, note);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +63,8 @@ internal class RelatedStore : NoteMessageProvider, IDisposable
|
||||||
input.Replies = updated.Replies;
|
input.Replies = updated.Replies;
|
||||||
input.Attachments = updated.Attachments;
|
input.Attachments = updated.Attachments;
|
||||||
input.Reactions = updated.Reactions;
|
input.Reactions = updated.Reactions;
|
||||||
NoteChangedHandlers.First(p => p.Key == input.Id).Value.Invoke(this, input);
|
var handler = NoteChangedHandlers.FirstOrDefault(p => p.Key == input.Id);
|
||||||
|
handler.Value?.Invoke(this, input);
|
||||||
NoteChanged?.Invoke(this, input);
|
NoteChanged?.Invoke(this, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,10 +82,14 @@ internal class RelatedStore : NoteMessageProvider, IDisposable
|
||||||
return await FetchAscendantsAsync(id, limit);
|
return await FetchAscendantsAsync(id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SortedList<string, NoteResponse>?> GetDescendantsAsync(string id, int? limit)
|
public async Task<SortedList<string, NoteResponse>?> GetDescendantsAsync(
|
||||||
|
string id, int? limit, bool refresh = false
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
if (refresh) return await FetchDescendantsAsync(id, limit);
|
||||||
var success = Descendants.TryGetValue(id, out var value);
|
var success = Descendants.TryGetValue(id, out var value);
|
||||||
if (success) return value?.Notes ?? throw new InvalidOperationException("Key somehow had no associated value.");
|
if (success)
|
||||||
|
return value?.Notes ?? throw new InvalidOperationException("Key somehow had no associated value.");
|
||||||
return await FetchDescendantsAsync(id, limit);
|
return await FetchDescendantsAsync(id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,8 @@ internal class TimelineStore : NoteMessageProvider, IAsyncDisposable, IStreaming
|
||||||
note.Attachments = changedNote.Attachments;
|
note.Attachments = changedNote.Attachments;
|
||||||
note.Reactions = changedNote.Reactions;
|
note.Reactions = changedNote.Reactions;
|
||||||
|
|
||||||
NoteChangedHandlers.First(p => p.Key == note.Id).Value.Invoke(this, note);
|
var handler = NoteChangedHandlers.FirstOrDefault(p => p.Key == note.Id);
|
||||||
|
handler.Value?.Invoke(this, note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,6 +218,7 @@
|
||||||
{
|
{
|
||||||
_locationChangingHandlerDisposable = Navigation.RegisterLocationChangingHandler(LocationChangeHandler);
|
_locationChangingHandlerDisposable = Navigation.RegisterLocationChangingHandler(LocationChangeHandler);
|
||||||
StateSynchronizer.NoteDeleted += OnNoteDeleted;
|
StateSynchronizer.NoteDeleted += OnNoteDeleted;
|
||||||
|
NoteStore.AnyNoteChanged += OnNoteChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNoteDeleted(object? _, NoteBase note)
|
private void OnNoteDeleted(object? _, NoteBase note)
|
||||||
|
@ -235,6 +236,20 @@
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnNoteChanged(object? _, NoteResponse note)
|
||||||
|
{
|
||||||
|
if (note.Id == NoteId)
|
||||||
|
{
|
||||||
|
var __ = Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Refresh()
|
||||||
|
{
|
||||||
|
if (NoteId != null) Descendants = await RelatedStore.GetDescendantsAsync(NoteId, _depth, true);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
private ValueTask LocationChangeHandler(LocationChangingContext arg)
|
private ValueTask LocationChangeHandler(LocationChangingContext arg)
|
||||||
{
|
{
|
||||||
|
@ -322,5 +337,6 @@
|
||||||
SaveState();
|
SaveState();
|
||||||
_locationChangingHandlerDisposable?.Dispose();
|
_locationChangingHandlerDisposable?.Dispose();
|
||||||
StateSynchronizer.NoteDeleted -= OnNoteDeleted;
|
StateSynchronizer.NoteDeleted -= OnNoteDeleted;
|
||||||
|
NoteStore.AnyNoteChanged -= OnNoteChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue