[frontend] Make reply tree update when new replies are added (ISH-399)
This commit is contained in:
parent
6dbde914a3
commit
ee0ee919d6
3 changed files with 109 additions and 60 deletions
|
@ -10,45 +10,46 @@
|
||||||
@inject ComposeService ComposeService
|
@inject ComposeService ComposeService
|
||||||
@inject SessionService SessionService
|
@inject SessionService SessionService
|
||||||
@inject IStringLocalizer<Localization> Loc;
|
@inject IStringLocalizer<Localization> Loc;
|
||||||
@inject GlobalComponentSvc GlobalComponentSvc
|
@inject GlobalComponentSvc GlobalComponentSvc
|
||||||
|
@inject MessageService MessageService
|
||||||
<dialog class="dialog" @ref="Dialog">
|
<dialog class="dialog" @ref="Dialog">
|
||||||
<div class="compose">
|
<div class="compose">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<button @onclick="CloseDialog">
|
<button @onclick="CloseDialog">
|
||||||
<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"/>
|
||||||
<button @onclick="SendNote" class="post-btn">
|
<button @onclick="SendNote" class="post-btn">
|
||||||
@Loc["ComposePost"]<Icon Name="Icons.PaperPlaneRight"/>
|
@Loc["ComposePost"]<Icon Name="Icons.PaperPlaneRight"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
@if (ReplyOrQuote != null)
|
|
||||||
{
|
|
||||||
<div class="reply-or-quote">
|
|
||||||
<NoteComponent Note="ReplyOrQuote" AsQuote="true"/>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
@if (ReplyOrQuote != null)
|
||||||
@if (NoteDraft.Cw != null)
|
{
|
||||||
{
|
<div class="reply-or-quote">
|
||||||
<input @bind="NoteDraft.Cw" class="input cw-field" placeholder="Content Warning"/>
|
<NoteComponent Note="ReplyOrQuote" AsQuote="true"/>
|
||||||
<hr class="separator"/>
|
</div>
|
||||||
}
|
}
|
||||||
<textarea @ref="Textarea" @bind="NoteDraft.Text" class="textarea" placeholder="@TextPlaceholder" rows="5" cols="35" autofocus="autofocus"></textarea>
|
@if (NoteDraft.Cw != null)
|
||||||
<div class="footer">
|
{
|
||||||
<button class="footer-btn" @onclick="OpenUpload">
|
<input @bind="NoteDraft.Cw" class="input cw-field" placeholder="Content Warning"/>
|
||||||
<Icon Name="Icons.Upload" Size="1.3rem"></Icon>
|
<hr class="separator"/>
|
||||||
</button>
|
}
|
||||||
<button class="footer-btn" @onclick="ToggleCw">
|
<textarea @ref="Textarea" @bind="NoteDraft.Text" class="textarea" placeholder="@TextPlaceholder" rows="5" cols="35" autofocus="autofocus"></textarea>
|
||||||
<Icon Name="Icons.EyeSlash" Size="1.3rem"></Icon>
|
<div class="footer">
|
||||||
</button>
|
<button class="footer-btn" @onclick="OpenUpload">
|
||||||
<button @ref="EmojiButton" class="footer-btn positioned" @onclick="ToggleEmojiPicker">
|
<Icon Name="Icons.Upload" Size="1.3rem"></Icon>
|
||||||
<Icon Name="Icons.Smiley" Size="1.3rem"></Icon>
|
</button>
|
||||||
</button>
|
<button class="footer-btn" @onclick="ToggleCw">
|
||||||
<div class="file-input">
|
<Icon Name="Icons.EyeSlash" Size="1.3rem"></Icon>
|
||||||
<InputFile @ref="UploadInput" OnChange="Upload">Upload!</InputFile>
|
</button>
|
||||||
|
<button @ref="EmojiButton" class="footer-btn positioned" @onclick="ToggleEmojiPicker">
|
||||||
|
<Icon Name="Icons.Smiley" Size="1.3rem"></Icon>
|
||||||
|
</button>
|
||||||
|
<div class="file-input">
|
||||||
|
<InputFile @ref="UploadInput" OnChange="Upload">Upload!</InputFile>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div @onclick="CloseDialog" class="backdrop"></div>
|
||||||
<div @onclick="CloseDialog" class="backdrop"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
|
@ -70,12 +71,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!" }
|
|
||||||
};
|
|
||||||
|
|
||||||
RenderFragment DropdownIcon(NoteVisibility vis)
|
RenderFragment DropdownIcon(NoteVisibility vis)
|
||||||
{
|
{
|
||||||
|
@ -108,9 +104,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();
|
||||||
|
@ -203,14 +197,9 @@
|
||||||
|
|
||||||
private void ResetState()
|
private void ResetState()
|
||||||
{
|
{
|
||||||
ReplyOrQuote = null;
|
ReplyOrQuote = null;
|
||||||
Attachments = new List<DriveFileResponse>();
|
Attachments = new List<DriveFileResponse>();
|
||||||
NoteDraft = new NoteCreateRequest
|
NoteDraft = new NoteCreateRequest { Text = "", Visibility = NoteVisibility.Followers, Cw = null };
|
||||||
{
|
|
||||||
Text = "",
|
|
||||||
Visibility = NoteVisibility.Followers,
|
|
||||||
Cw = null
|
|
||||||
};
|
|
||||||
TextPlaceholder = AvailablePlaceholders["default"];
|
TextPlaceholder = AvailablePlaceholders["default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +216,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
await ApiService.Notes.CreateNote(NoteDraft);
|
await ApiService.Notes.CreateNote(NoteDraft);
|
||||||
|
if (ReplyOrQuote != null)
|
||||||
|
{
|
||||||
|
var res = await ApiService.Notes.GetNote(ReplyOrQuote.Id);
|
||||||
|
if (res != null) _ = MessageService.UpdateNote(res);
|
||||||
|
}
|
||||||
|
|
||||||
await CloseDialog();
|
await CloseDialog();
|
||||||
|
|
||||||
// FIXME: Implement timeline refresh and call it here.
|
// FIXME: Implement timeline refresh and call it here.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
@* 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.Shared.Schemas.Web
|
@using Iceshrimp.Shared.Schemas.Web
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject MessageService MessageService
|
||||||
|
@inject ApiService Api
|
||||||
|
@implements IDisposable
|
||||||
|
|
||||||
<div class="@(Depth > 0 ? "descendant" : "root-note")">
|
<div class="@(Depth > 0 ? "descendant" : "root-note")">
|
||||||
<div class="note-container">
|
<div class="note-container">
|
||||||
|
@ -44,13 +48,13 @@
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<RecursiveNote Note="note" Depth="Depth + 1"/>
|
<RecursiveNote Note="note" Depth="Depth + 1" MaxDepth="MaxDepth"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<RecursiveNote Note="note" Depth="Depth + 1"/>
|
<RecursiveNote Note="note" Depth="Depth + 1" MaxDepth="MaxDepth"/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,20 +62,43 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] [EditorRequired] public required NoteResponse Note { get; set; }
|
[Parameter] [EditorRequired] public required NoteResponse Note { get; set; }
|
||||||
[Parameter] [EditorRequired] public required int Depth { 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;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
|
MessageService.Register(Note.Id, OnNoteChanged);
|
||||||
if (Depth > 0 || Note.Descendants?.Count > 0)
|
if (Depth > 0 || Note.Descendants?.Count > 0)
|
||||||
{
|
{
|
||||||
_indented = true;
|
_indented = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnNoteChanged(object? _, NoteResponse note)
|
||||||
|
{
|
||||||
|
var __ = Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Refresh()
|
||||||
|
{
|
||||||
|
if (Depth < MaxDepth)
|
||||||
|
{
|
||||||
|
var res = await Api.Notes.GetNoteDescendants(Note.Id, MaxDepth - Depth);
|
||||||
|
Note.Descendants = res;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void OpenNote()
|
private void OpenNote()
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo($"/notes/{Note.Id}");
|
NavigationManager.NavigateTo($"/notes/{Note.Id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
MessageService.Unregister(Note.Id, OnNoteChanged);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,8 @@
|
||||||
@using Iceshrimp.Shared.Schemas.Web
|
@using Iceshrimp.Shared.Schemas.Web
|
||||||
@inject ApiService ApiService
|
@inject ApiService ApiService
|
||||||
@inject IJSRuntime Js
|
@inject IJSRuntime Js
|
||||||
|
@inject MessageService MessageService
|
||||||
|
@implements IDisposable
|
||||||
|
|
||||||
@if (_init)
|
@if (_init)
|
||||||
{
|
{
|
||||||
|
@ -28,7 +30,7 @@
|
||||||
<div class="descendants">
|
<div class="descendants">
|
||||||
@foreach (var element in Descendants)
|
@foreach (var element in Descendants)
|
||||||
{
|
{
|
||||||
<RecursiveNote Note="element" Depth="0"/>
|
<RecursiveNote Note="element" Depth="0" MaxDepth="_depth"/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -54,6 +56,7 @@ else
|
||||||
private ElementReference RootNoteRef { get; set; }
|
private ElementReference RootNoteRef { get; set; }
|
||||||
private bool _init;
|
private bool _init;
|
||||||
private bool _error;
|
private bool _error;
|
||||||
|
private int _depth = 20;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
|
@ -71,13 +74,31 @@ else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Descendants = await ApiService.Notes.GetNoteDescendants(NoteId, default);
|
Descendants = await ApiService.Notes.GetNoteDescendants(NoteId, _depth);
|
||||||
Ascendants = await ApiService.Notes.GetNoteAscendants(NoteId, default);
|
Ascendants = await ApiService.Notes.GetNoteAscendants(NoteId, default);
|
||||||
_init = true;
|
_init = true;
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
if (NoteId != null) MessageService.Register(NoteId, OnNoteChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNoteChanged(object? _, NoteResponse note)
|
||||||
|
{
|
||||||
|
var __ = Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Refresh()
|
||||||
|
{
|
||||||
|
if (NoteId == null) throw new InvalidOperationException("RefreshNote called under impossible circumstances");
|
||||||
|
Descendants = await ApiService.Notes.GetNoteDescendants(NoteId, default);
|
||||||
|
Ascendants = await ApiService.Notes.GetNoteAscendants(NoteId, default);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
|
@ -91,4 +112,9 @@ else
|
||||||
.InvokeVoidAsync("ScrollIntoView", RootNoteRef);
|
.InvokeVoidAsync("ScrollIntoView", RootNoteRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (NoteId != null) MessageService.Unregister(NoteId, OnNoteChanged);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue