Show your own now-playing at the top of the feed
The feed only listed people you follow, so with no follows it looked like nothing was being picked up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { router } from 'expo-router';
|
||||
import { useState } from 'react';
|
||||
import { FlatList, RefreshControl, StyleSheet, View } from 'react-native';
|
||||
import { FlatList, RefreshControl, StyleSheet, Text, View } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import useSWR from 'swr';
|
||||
import { sortFeed, type FeedItemDTO } from '@musicshare/shared';
|
||||
import { sortFeed, type FeedItemDTO, type ProfileDTO } from '@musicshare/shared';
|
||||
import { NowPlayingCard } from '@/components/NowPlayingCard';
|
||||
import { Body, Button, Card, Title } from '@/components/ui';
|
||||
import { api } from '@/lib/api';
|
||||
@@ -15,10 +15,16 @@ import { colors, space } from '@/lib/theme';
|
||||
export default function FeedScreen() {
|
||||
const { me } = useSession();
|
||||
const { data: feed, mutate, isLoading } = useSWR<FeedItemDTO[]>('/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<ProfileDTO>(me ? `/users/${me.username}` : null);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
useRealtime(true, (msg) => {
|
||||
if (msg.type !== 'now_playing' || msg.data.user.id === me?.id) return;
|
||||
if (msg.type !== 'now_playing') return;
|
||||
if (msg.data.user.id === me?.id) {
|
||||
if (mine) mutateMine({ ...mine, nowPlaying: msg.data }, { revalidate: false });
|
||||
return;
|
||||
}
|
||||
mutate(
|
||||
(current = []) => {
|
||||
const existing = current.find((n) => n.user.id === msg.data.user.id);
|
||||
@@ -42,7 +48,7 @@ export default function FeedScreen() {
|
||||
|
||||
const refresh = async () => {
|
||||
setRefreshing(true);
|
||||
await mutate().catch(() => {});
|
||||
await Promise.all([mutate(), mutateMine()]).catch(() => {});
|
||||
setRefreshing(false);
|
||||
};
|
||||
|
||||
@@ -55,6 +61,12 @@ export default function FeedScreen() {
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={refresh} tintColor={colors.muted} />}
|
||||
ListHeaderComponent={
|
||||
<View style={styles.header}>
|
||||
{mine?.nowPlaying && (
|
||||
<View style={{ gap: space.sm }}>
|
||||
<Text style={styles.sectionLabel}>YOU</Text>
|
||||
<NowPlayingCard np={mine.nowPlaying} preferred={me?.preferredService} showUser={false} />
|
||||
</View>
|
||||
)}
|
||||
<Title>Friends listening</Title>
|
||||
{!me?.preferredService && (
|
||||
<Card>
|
||||
@@ -89,4 +101,5 @@ const styles = StyleSheet.create({
|
||||
safe: { flex: 1, backgroundColor: colors.bg },
|
||||
list: { padding: space.lg, gap: space.md, paddingBottom: space.xl * 3 },
|
||||
header: { gap: space.md, marginBottom: space.xs },
|
||||
sectionLabel: { color: colors.muted, fontSize: 12, fontWeight: '700', letterSpacing: 0.8 },
|
||||
});
|
||||
|
||||
@@ -41,6 +41,7 @@ input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); ou
|
||||
.muted { color: var(--muted); }
|
||||
.error { color: var(--danger); margin: 0; }
|
||||
.notice { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 0.75rem 1rem; margin: 0; }
|
||||
.section-label { margin: 0; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
|
||||
.narrow { max-width: 420px; margin: 2rem auto; }
|
||||
|
||||
.nav {
|
||||
@@ -109,6 +110,15 @@ input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); ou
|
||||
.search-results li { padding: 0.35rem 0.4rem; }
|
||||
.result { display: flex; gap: 0.6rem; align-items: center; background: none; border: 0; color: inherit; font: inherit; cursor: pointer; width: 100%; text-align: left; padding: 0; }
|
||||
.result:hover { color: var(--accent); }
|
||||
.recent { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
|
||||
.recent-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.45rem 0; text-decoration: none; border-radius: 8px; }
|
||||
a.recent-row:hover .recent-title { color: var(--accent); }
|
||||
.recent li + li { border-top: 1px solid var(--border); }
|
||||
.recent-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
|
||||
.recent-text > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.recent-title { font-weight: 600; }
|
||||
.recent-time { font-size: 0.8rem; white-space: nowrap; }
|
||||
.artwork-sm.artwork-empty { display: grid; place-items: center; background: var(--surface-2); color: var(--muted); }
|
||||
.picked { display: flex; gap: 0.75rem; align-items: center; }
|
||||
|
||||
.connections { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.5rem; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import Link from 'next/link';
|
||||
import useSWR from 'swr';
|
||||
import { sortFeed, type FeedItemDTO } from '@musicshare/shared';
|
||||
import { sortFeed, type FeedItemDTO, type ProfileDTO } from '@musicshare/shared';
|
||||
import { NowPlayingCard } from '@/components/NowPlayingCard';
|
||||
import { UserSearch } from '@/components/UserSearch';
|
||||
import { api, fetcher, useMe } from '@/lib/api';
|
||||
@@ -18,9 +18,15 @@ export default function Home() {
|
||||
function Feed() {
|
||||
const { me } = useMe();
|
||||
const { data: feed, mutate } = useSWR<FeedItemDTO[]>('/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<ProfileDTO>(me ? `/users/${me.username}` : null, fetcher);
|
||||
|
||||
useRealtime(true, (msg) => {
|
||||
if (msg.type !== 'now_playing' || msg.data.user.id === me?.id) return;
|
||||
if (msg.type !== 'now_playing') return;
|
||||
if (msg.data.user.id === me?.id) {
|
||||
if (mine) mutateMine({ ...mine, nowPlaying: msg.data }, { revalidate: false });
|
||||
return;
|
||||
}
|
||||
mutate(
|
||||
(current = []) => {
|
||||
const existing = current.find((n) => n.user.id === msg.data.user.id);
|
||||
@@ -47,6 +53,12 @@ function Feed() {
|
||||
return (
|
||||
<div className="stack">
|
||||
<UserSearch />
|
||||
{mine?.nowPlaying && (
|
||||
<section className="stack">
|
||||
<h2 className="section-label">You</h2>
|
||||
<NowPlayingCard np={mine.nowPlaying} preferred={me?.preferredService} showUser={false} />
|
||||
</section>
|
||||
)}
|
||||
<h1>Friends listening</h1>
|
||||
{!me?.preferredService && (
|
||||
<p className="notice">
|
||||
|
||||
Reference in New Issue
Block a user