Mobile: redesign, onboarding, QR codes, logo, Spotify setup
- Redesign matching the web: album-art backdrops, Reanimated equalizer, spinning live ring, drifting ambient background, gradient buttons with spring press feedback and haptics, Space Grotesk headings, animated feed (enter + layout transitions); fix invisible tab labels - Four-step onboarding for new accounts: which app you listen with (sets where songs open), the matching share setup, find friends (search, scan, invite), and a featured song. Skippable; stored server-side - QR codes: My code (share link) and an in-app scanner (camera only, no microphone permission) - Spotify setup via Last.fm or ListenBrainz with guided linking; Android shares Spotify automatically through the phone reader - New logo as app icon, adaptive/monochrome icon and splash - app.config.ts allows cleartext only for local http:// test builds 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,11 @@
|
||||
import { router } from 'expo-router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FlatList, RefreshControl, StyleSheet, Text, View } from 'react-native';
|
||||
import { RefreshControl, 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 { AmbientBackground } from '@/components/AmbientBackground';
|
||||
import { NowPlayingCard } from '@/components/NowPlayingCard';
|
||||
import { RelinkReminder } from '@/components/RelinkReminder';
|
||||
import { SharingControls } from '@/components/SharingControls';
|
||||
@@ -71,7 +73,10 @@ export default function FeedScreen() {
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.safe} edges={['top']}>
|
||||
<FlatList
|
||||
<AmbientBackground />
|
||||
{/* Cards rise in on load and glide to new positions when someone pins or starts playing. */}
|
||||
<Animated.FlatList
|
||||
itemLayoutAnimation={LinearTransition.springify().damping(18)}
|
||||
data={feed ?? []}
|
||||
keyExtractor={(item) => item.user.id}
|
||||
contentContainerStyle={styles.list}
|
||||
@@ -115,13 +120,15 @@ export default function FeedScreen() {
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
renderItem={({ item }) => (
|
||||
<NowPlayingCard
|
||||
np={item}
|
||||
preferred={me?.preferredService}
|
||||
pinned={Boolean(item.pinnedAt)}
|
||||
onTogglePin={() => togglePin(item)}
|
||||
/>
|
||||
renderItem={({ item, index }) => (
|
||||
<Animated.View entering={FadeInDown.delay(Math.min(index, 8) * 60).springify().damping(16)}>
|
||||
<NowPlayingCard
|
||||
np={item}
|
||||
preferred={me?.preferredService}
|
||||
pinned={Boolean(item.pinnedAt)}
|
||||
onTogglePin={() => togglePin(item)}
|
||||
/>
|
||||
</Animated.View>
|
||||
)}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
|
||||
Reference in New Issue
Block a user