@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) {
@if (type is TimelineType.Notifications && UnreadNotifications > 0) { @UnreadNotifications } else if (type is TimelineType.Direct && UnreadConversations > 0) { @UnreadConversations }
}
@* a phone held sideways has no room for the banner: the globe opens full screen *@
@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) { } } } else if (Filter.TimelineType is TimelineType.Lists) {
@if (Lists.Count == 0) {

@Localizer["This persona has no list yet."]

} else { @foreach (var list in Lists) { } } @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; } = []; /// Groups of notifications newer than the persona's marker; a badge on the Notifications tab. [Parameter] public int UnreadNotifications { get; set; } /// How many of the newest direct conversations hold a message the persona has not read. [Parameter] public int UnreadConversations { get; set; } [Parameter] public IEnumerable Stats { get; set; } = []; [Parameter] public bool IsComposing { get; set; } [Parameter] public EventCallback OnCompose { get; set; } /// Opens the globe full screen (a phone held sideways, which has no room for its banner). [Parameter] public EventCallback OnGlobeFull { 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); } }