From 773e6f0e3f77b1a5a86d4d14308b3c08f7e65c70 Mon Sep 17 00:00:00 2001
From: chris
Date: Tue, 6 Oct 2026 15:25:41 -0400
Subject: [PATCH] Feed: show everyone you follow
The feed only listed people who had played something, so following
someone who hadn't connected a service yet looked like it did nothing.
Under the feed, a "Following" row now shows everyone else you follow,
linking to their profiles, and the empty message says why it's empty.
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
---
apps/mobile/src/app/(tabs)/index.tsx | 42 +++++++++++++++++++++++++---
apps/web/src/app/globals.css | 5 ++++
apps/web/src/app/page.tsx | 35 ++++++++++++++++++++---
3 files changed, 74 insertions(+), 8 deletions(-)
diff --git a/apps/mobile/src/app/(tabs)/index.tsx b/apps/mobile/src/app/(tabs)/index.tsx
index 37422b2..a493a51 100644
--- a/apps/mobile/src/app/(tabs)/index.tsx
+++ b/apps/mobile/src/app/(tabs)/index.tsx
@@ -1,11 +1,12 @@
import { router } from 'expo-router';
import { useEffect, useState } from 'react';
-import { RefreshControl, StyleSheet, Text, View } from 'react-native';
+import { Pressable, RefreshControl, ScrollView, StyleSheet, Text, View } from 'react-native';
import Animated, { FadeInDown, LinearTransition } from 'react-native-reanimated';
import { SafeAreaView } from 'react-native-safe-area-context';
import useSWR from 'swr';
-import { sortFeed, type ConnectionDTO, type FeedItemDTO, type ProfileDTO } from '@musicshare/shared';
+import { sortFeed, type ConnectionDTO, type FeedItemDTO, type FollowListDTO, type ProfileDTO } from '@musicshare/shared';
import { AmbientBackground } from '@/components/AmbientBackground';
+import { Avatar } from '@/components/Avatar';
import { NowPlayingCard } from '@/components/NowPlayingCard';
import { RelinkReminder } from '@/components/RelinkReminder';
import { SharingControls } from '@/components/SharingControls';
@@ -24,6 +25,10 @@ export default function FeedScreen() {
const { data: feed, mutate, isLoading } = useSWR('/feed');
// Your own profile, for the "You" card. Loading it also marks you as watched, so your updates arrive quickly.
const { data: mine, mutate: mutateMine } = useSWR(me ? `/users/${me.username}` : null);
+ // Everyone you follow; the feed only has the ones who've played something.
+ const { data: following, mutate: mutateFollowing } = useSWR(me ? `/users/${me.username}/following` : null);
+ const inFeed = new Set(feed?.map((n) => n.user.id));
+ const quiet = following?.users.filter((u) => !inFeed.has(u.id)) ?? [];
const [refreshing, setRefreshing] = useState(false);
const reader = useReader();
@@ -67,7 +72,7 @@ export default function FeedScreen() {
const refresh = async () => {
setRefreshing(true);
- await Promise.all([mutate(), mutateMine()]).catch(() => {});
+ await Promise.all([mutate(), mutateMine(), mutateFollowing()]).catch(() => {});
setRefreshing(false);
};
@@ -115,11 +120,37 @@ export default function FeedScreen() {
ListEmptyComponent={
isLoading ? null : (
- Nothing yet. Follow some friends and their music will show up here live.
+
+ {following?.users.length
+ ? 'Nobody you follow has played anything yet. Their music will show up here live.'
+ : 'Nothing yet. Follow some friends and their music will show up here live.'}
+
)
}
+ ListFooterComponent={
+ quiet.length > 0 ? (
+
+ FOLLOWING · NOTHING PLAYED YET
+
+ {quiet.map((u) => (
+ router.push(`/u/${u.username}`)} style={styles.quietPerson} accessibilityLabel={u.displayName ?? u.username}>
+
+
+ {u.displayName ?? u.username}
+
+
+ ))}
+ {following?.nextCursor && me && (
+ router.push(`/u/${me.username}/following`)} style={[styles.quietPerson, { justifyContent: 'center' }]}>
+ See all
+
+ )}
+
+
+ ) : null
+ }
renderItem={({ item, index }) => (
('/feed', fetcher);
// Your own profile, for the "You" card. Loading it also marks you as watched, so your updates arrive quickly.
const { data: mine, mutate: mutateMine } = useSWR(me ? `/users/${me.username}` : null, fetcher);
+ // Everyone you follow; the feed only has the ones who've played something.
+ const { data: following } = useSWR(me ? `/users/${me.username}/following` : null, fetcher);
+ const inFeed = new Set(feed?.map((n) => n.user.id));
+ const quiet = following?.users.filter((u) => !inFeed.has(u.id)) ?? [];
useRealtime(true, (msg) => {
if (msg.type !== 'now_playing') return;
@@ -69,9 +74,12 @@ function Feed() {
Pick your streaming service in Settings so songs open in the right app.
)}
- {feed?.length === 0 && (
-
Nothing yet. Follow some friends and their music will show up here live.