@inherits LocalizableComponentBase
@* The feed page's tabs, one per kind of feed, scrolling sideways on narrow screens. Groups adds a choice of the
persona's communities and circles, Lists a choice of its lists (made and filled on /lists), Tag the hashtag being
read, with its week and a button to follow it (its public posts then come home). The stats icon shows how the current feed was
read; the buttons on the right open the composer and, on narrow screens, the globe. *@
@foreach (var type in Types)
{
}
@Localizer["Post"]
@if (Filter.TimelineType is TimelineType.Groups)
{
@if (Groups.Count == 0)
{
@Localizer["This persona is in no community or circle yet."]
}
else
{
@foreach (var group in Groups)
{
@(group.IsCommunity ? "◎" : "◉") @(group.Name ?? group.UserName)
}
}
}
else if (Filter.TimelineType is TimelineType.Lists)
{
@if (Lists.Count == 0)
{
@Localizer["This persona has no list yet."]
}
else
{
@foreach (var list in Lists)
{
@list.Title
}
}
@Localizer["Manage lists"]
}
else if (Filter.TimelineType is TimelineType.Tag)
{
#@Filter.Tag
@if (tag is not null)
{
@Localizer["{0} posts this week, {1} people today", tag.WeekUses, tag.TodayAccounts]
@(tag.Following == true ? Localizer["Stop following #{0}", tag.Name] : Localizer["Follow #{0}", tag.Name])
}
}
@code {
[Parameter, EditorRequired] public FeedFilter Filter { get; set; }
[Parameter] public List Groups { get; set; } = [];
[Parameter] public List Lists { get; set; } = [];
[Parameter] public IEnumerable Stats { get; set; } = [];
[Parameter] public bool IsComposing { get; set; }
[Parameter] public EventCallback OnCompose { get; set; }
/// Raised after Filter changed (tab, group or globe).
[Parameter] public EventCallback OnChanged { get; set; }
static readonly TimelineType[] Always =
[
TimelineType.Home, TimelineType.Local, TimelineType.Federation, TimelineType.Nearby, TimelineType.Groups, TimelineType.Direct,
TimelineType.Notifications, TimelineType.Favourites, TimelineType.Bookmarks, TimelineType.Lists
];
List Types => Filter.Tag is { Length: > 0 } ? [.. Always, TimelineType.Tag] : [.. Always];
int ActiveIndex => Types.IndexOf(Filter.TimelineType);
ViewGroup SelectedGroup => Groups.FirstOrDefault(g => g.Id == Filter.GroupId);
[Inject] DiscoveryService DiscoveryService { get; set; }
Tag tag;
string loadedTag;
bool isFollowing;
protected override void OnInitialized() => IsLoading = false;
// the hashtag being read: its week and whether the persona follows it, read again when it changes
protected override async Task OnParametersSetAsync()
{
var wanted = Filter.TimelineType is TimelineType.Tag ? Filter.Tag : null;
if (wanted == loadedTag)
return;
loadedTag = wanted;
tag = wanted is { Length: > 0 } ? await DiscoveryService.Tag(wanted) : null;
}
async Task ToggleTagFollow()
{
isFollowing = true;
var result = await DiscoveryService.FollowTag(tag.Name, tag.Following != true);
isFollowing = false;
if (result.IsInvalid)
{
Toast.AddResponseError(result);
return;
}
tag = (Tag)result.Data;
Toast.AddResponseSuccess(tag.Following == true ? Localizer["Following #{0}: its public posts come home.", tag.Name] : Localizer["No longer following #{0}.", tag.Name]);
}
string TabName(TimelineType type) => type switch
{
TimelineType.Federation => Localizer["Federated"],
TimelineType.Tag => "#" + Filter.Tag,
_ => Localizer[type.ToString()]
};
async Task Select(int index)
{
Filter.TimelineType = Types[index];
if (Filter.TimelineType is TimelineType.Groups && SelectedGroup is null)
Filter.GroupId = Groups.FirstOrDefault()?.Id;
if (Filter.TimelineType is TimelineType.Lists && Lists.All(l => l.Id != Filter.ListId))
Filter.ListId = Lists.FirstOrDefault()?.Id;
await OnChanged.InvokeAsync(Filter);
}
async Task SelectList(string listId)
{
Filter.ListId = listId;
await OnChanged.InvokeAsync(Filter);
}
async Task SelectGroup(string groupId)
{
Filter.GroupId = groupId;
await OnChanged.InvokeAsync(Filter);
}
async Task ToggleGlobe()
{
Filter.ShowGlobe = !Filter.ShowGlobe;
await OnChanged.InvokeAsync(Filter);
}
}