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:
@@ -0,0 +1,72 @@
|
||||
import { useState } from 'react';
|
||||
import { Linking } from 'react-native';
|
||||
import { mutate } from 'swr';
|
||||
import { SERVICE_LABELS } from '@musicshare/shared';
|
||||
import { SignInError, signInWithService } from '@/lib/connect';
|
||||
import { Button } from '../ui';
|
||||
import { ErrorText, SetupActions, SetupHeader, type SetupProps } from './common';
|
||||
|
||||
type Provider = 'plex' | 'lastfm';
|
||||
|
||||
/**
|
||||
* Sign in to Plex, or to Last.fm for apps that can send plays there.
|
||||
* (Spotify has its own SpotifySetup: via Last.fm or ListenBrainz.)
|
||||
*/
|
||||
export function ServiceSignInSetup({
|
||||
service,
|
||||
appName,
|
||||
onDone,
|
||||
skipLabel,
|
||||
}: SetupProps & { service: Provider; appName?: string }) {
|
||||
const [done, setDone] = useState(false);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const run = async () => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
if ((await signInWithService(service)) === 'connected') {
|
||||
await mutate('/connections');
|
||||
setDone(true);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof SignInError ? err.message : `Couldn't connect ${SERVICE_LABELS[service]}. Try again.`);
|
||||
}
|
||||
setBusy(false);
|
||||
};
|
||||
|
||||
if (done) {
|
||||
return (
|
||||
<>
|
||||
<SetupHeader
|
||||
title="You're all set"
|
||||
subtitle={`Play something on ${appName ?? SERVICE_LABELS[service]} and your friends will see it.`}
|
||||
/>
|
||||
<SetupActions primary="Continue" onPrimary={onDone} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (service === 'lastfm') {
|
||||
return (
|
||||
<>
|
||||
<SetupHeader
|
||||
title="Connect Last.fm"
|
||||
subtitle={`${appName ?? 'Your app'} doesn’t let other iPhone apps see what’s playing. If it can send plays to Last.fm (TIDAL can, in its settings), sign in to Last.fm and we’ll share them.`}
|
||||
/>
|
||||
<ErrorText>{error}</ErrorText>
|
||||
<SetupActions primary="Sign in with Last.fm" loading={busy} onPrimary={run} onSkip={onDone} skipLabel={skipLabel} />
|
||||
<Button small title="New to Last.fm? Create an account" onPress={() => Linking.openURL('https://www.last.fm/join')} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SetupHeader title="Share what you’re playing" subtitle={`Sign in to ${SERVICE_LABELS[service]} and your friends see what you play.`} />
|
||||
<ErrorText>{error}</ErrorText>
|
||||
<SetupActions primary={`Connect ${SERVICE_LABELS[service]}`} loading={busy} onPrimary={run} onSkip={onDone} skipLabel={skipLabel} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user