Lists: made on /lists, read as a tab of the feed
A persona's lists (PrivaPub's /api/v1/lists): made, renamed, given a replies policy and made exclusive on /lists, filled from the accounts it follows (accounts/search?following=true), and read as the feed's Lists tab. A followed account's profile has a Lists menu to put it in or take it out. ListService does the calls; the e2e tests check each step against PrivaPub's own answer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
011bafb6af
commit
e2491de16e
18 files changed
+914
-9
No files matched your search
@@ -56,6 +56,30 @@
|
||||
@FollowLabel
|
||||
</DButton>
|
||||
}
|
||||
@if (relationship?.Following == true)
|
||||
{
|
||||
<DDropdown @bind-IsOpen="isListMenuOpen" Align="DDropdownAlign.End" TriggerClass="btn btn-sm"
|
||||
ContentClass="mt-2 flex flex-col gap-2 p-3 rounded-box w-64 bg-base-100 neo-raised neo-xs z-20" title="@Localizer["Lists"]">
|
||||
<Trigger>
|
||||
<i class="ion-md-list"></i><span>@Localizer["Lists"]</span>
|
||||
</Trigger>
|
||||
<ChildContent>
|
||||
@if (allLists.Count == 0)
|
||||
{
|
||||
<p class="text-xs opacity-70">@Localizer["This persona has no list yet."]</p>
|
||||
}
|
||||
@foreach (var list in allLists)
|
||||
{
|
||||
<label class="label text-sm" data-list-id="@list.Id">
|
||||
<input type="checkbox" class="checkbox checkbox-sm" checked="@inLists.Contains(list.Id)" disabled="@(IsDefaultDisabled || isActing)"
|
||||
@onchange="@((ChangeEventArgs e) => SetListMember(list, e.Value is true))" />
|
||||
<span class="truncate">@list.Title</span>
|
||||
</label>
|
||||
}
|
||||
<a class="btn btn-xs" href="lists"><i class="ion-md-create"></i><span>@Localizer["Manage lists"]</span></a>
|
||||
</ChildContent>
|
||||
</DDropdown>
|
||||
}
|
||||
<DButton Size="DSize.Sm" Disabled="@(IsDefaultDisabled || isActing || relationship is null)"
|
||||
OnClick="@(() => Do(relationship?.Muting == true ? AccountAction.Unmute : AccountAction.Mute))">
|
||||
<i class="@(relationship?.Muting == true ? "ion-md-eye" : "ion-md-eye-off")"></i>
|
||||
@@ -140,6 +164,7 @@
|
||||
|
||||
@code {
|
||||
[Inject] AccountService AccountService { get; set; }
|
||||
[Inject] ListService ListService { get; set; }
|
||||
[Inject] InstanceService InstanceService { get; set; }
|
||||
[Inject] ILocalStorageService LocalStorage { get; set; }
|
||||
[Inject] IJSRuntime JS { get; set; }
|
||||
@@ -155,6 +180,9 @@
|
||||
string loadedPersonaId;
|
||||
bool isActing;
|
||||
bool isLoadingMore;
|
||||
bool isListMenuOpen;
|
||||
List<MastodonList> allLists = [];
|
||||
HashSet<string> inLists = [];
|
||||
|
||||
bool IsOwn => account is not null && account.Id == CascadingState.PersonaId;
|
||||
|
||||
@@ -197,12 +225,44 @@
|
||||
return;
|
||||
}
|
||||
relationship = account.Id == CascadingState.PersonaId ? null : await AccountService.Relationship(account.Id);
|
||||
await LoadLists();
|
||||
posts = [];
|
||||
maxId = null;
|
||||
IsLoading = false;
|
||||
await LoadPage();
|
||||
}
|
||||
|
||||
/// <summary>The persona's lists and which of them hold the account, for an account the persona follows.</summary>
|
||||
async Task LoadLists()
|
||||
{
|
||||
if (relationship?.Following != true)
|
||||
{
|
||||
allLists = [];
|
||||
inLists = [];
|
||||
return;
|
||||
}
|
||||
allLists = await ListService.All();
|
||||
inLists = [.. (await ListService.Of(account.Id)).Select(l => l.Id)];
|
||||
}
|
||||
|
||||
async Task SetListMember(MastodonList list, bool member)
|
||||
{
|
||||
isActing = true;
|
||||
var result = await ListService.SetMember(list.Id, account.Id, member);
|
||||
isActing = false;
|
||||
if (result.IsInvalid)
|
||||
{
|
||||
Toast.AddResponseError(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (member)
|
||||
inLists.Add(list.Id);
|
||||
else
|
||||
inLists.Remove(list.Id);
|
||||
Toast.AddResponseSuccess(member ? Localizer["{0} added to {1}.", account.Name, list.Title] : Localizer["{0} removed from {1}.", account.Name, list.Title]);
|
||||
}
|
||||
|
||||
async Task LoadPage()
|
||||
{
|
||||
isLoadingMore = true;
|
||||
@@ -247,6 +307,8 @@
|
||||
}
|
||||
|
||||
relationship = (Relationship)result.Data ?? relationship;
|
||||
if (action is AccountAction.Follow or AccountAction.Unfollow)
|
||||
await LoadLists();
|
||||
Toast.AddResponseSuccess(action switch
|
||||
{
|
||||
AccountAction.Follow when relationship?.Requested == true => Localizer["Asked {0} to accept you.", account.Name],
|
||||
|
||||
Reference in new issue
Block a user