Skip to content

joules65/loudam---CODEQUEST-HACKATHON-SUBMISSION-DAVID-ACHIBIRI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 

Repository files navigation

LoudAM is a music streaming app that uses the Spotify for developers api documentation to pull and fetch preview music which runs on the expo app.

To Use the App on your device scan this qr Code: EXPOGO (1)

or use this link: https://expo.dev/preview/update?message=DONE&updateRuntimeVersion=1.0.0&createdAt=2024-09-28T18%3A44%3A43.581Z&slug=exp&projectId=d34cf299-c5bd-4e3b-9eaa-a79f0d825c58&group=dce5295d-b42f-4f00-bc2e-8d45ed47f368 https://github.com/user-attachments/assets/5d8db444-c8f1-439b-a43b-230858768b91

Player Component Documentation

Overview

The Player component is part of a music streaming application built using React Native. It allows users to play audio tracks, manage favorites, and provides a user interface for playback controls. The component utilizes the Expo AV library for audio playback and Apollo Client for managing GraphQL queries and mutations related to user favorites.

Features

Play and pause audio tracks.

Add or remove tracks from favorites.

Display track information including title, artist, and album artwork.

Update UI based on playback status.

Dependencies

react-native: For building the mobile application.

expo-av: For audio playback functionality.

@apollo/client: For GraphQL data management.

@expo/vector-icons: For iconography.

GraphQL Queries and Mutations

Insert Favorite Mutation

mutation MyMutation($userId: String!, $trackId: String!) { insertFavorites(userid: $userId, trackid: $trackId) { id trackid userid } }

Parameters:

userId: The ID of the user.

trackId: The ID of the track to be added to favorites.

Returns: The ID, track ID, and user ID of the newly inserted favorite.

Remove Favorite Mutation

mutation MyMutation($trackId: String!, $userId: String!) { deleteFavorites(trackid: $trackId, userid: $userId) { id } }

Parameters:

trackId: The ID of the track to be removed from favorites.

userId: The ID of the user.

Returns: The ID of the deleted favorite.

Is Favorite Query

query MyQuery($trackId: String!, $userId: String!) { favoritesByTrackidAndUserid(trackid: $trackId, userid: $userId) { id trackid userid } }

Parameters:

trackId: The ID of the track.

userId: The ID of the user.

Returns: An array of favorites matching the provided track ID and user ID.

Component Structure

Player Component

const Player = () => { // State variables const [sound, setSound] = useState(); const [isPlaying, setIsPlaying] = useState(false); const { track } = usePlayerContext();

// GraphQL mutations const [insertFavorite] = useMutation(insertFavoriteMutation); const [removeFavorite] = useMutation(removeFavoriteMutation);

// Query to check if the track is a favorite const { data, refetch } = useQuery(isFavoriteQuery, { variables: { userId: 'vadim', trackId: track?.id || '' }, }); const isLiked = data?.favoritesByTrackidAndUserid?.length > 0;

// Effect to play track when it changes useEffect(() => { playTrack(); }, [track]);

// Effect to unload sound when component unmounts useEffect(() => { return sound ? () => { console.log('Unloading Sound'); sound.unloadAsync(); } : undefined; }, [sound]);

// Function to play the selected track const playTrack = async () => { if (sound) { await sound.unloadAsync(); }

if (!track?.preview_url) {
  return;
}
const { sound: newSound } = await Audio.Sound.createAsync({
  uri: track.preview_url,
});

setSound(newSound);
newSound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
await newSound.playAsync();

};

// Function to handle playback status updates const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => { if (!status.isLoaded) { return; }

setIsPlaying(status.isPlaying);

};

// Function to toggle play/pause const onPlayPause = async () => { if (!sound) { return; } if (isPlaying) { await sound.pauseAsync(); } else { await sound.playAsync(); } };

// Function to like/unlike a track const onLike = async () => { if (!track) return; if (isLiked) { await removeFavorite({ variables: { userId: 'vadim', trackId: track.id }, }); } else { await insertFavorite({ variables: { userId: 'vadim', trackId: track.id }, }); } refetch(); };

// Render nothing if no track is available if (!track) { return null; }

const image = track.album.images?.[0];

return ( {image && <Image source={{ uri: image.url }} style={styles.image} />} <View style={{ flex: 1 }}> {track.name} {track.artists[0]?.name} <Ionicons onPress={onLike} name={isLiked ? 'heart' : 'heart-outline'} size={20} color={'white'} style={{ marginHorizontal: 10 }} /> <Ionicons onPress={onPlayPause} disabled={!track?.preview_url} name={isPlaying ? 'pause' : 'play'} size={22} color={track?.preview_url ? 'white' : 'gold'} /> ); };

Styles

const styles = StyleSheet.create({ container: { position: 'absolute', top: -75, width: '100%', height: 75, padding: 10, }, player: { backgroundColor: '#85C7F2', flex: 1, flexDirection: 'row', alignItems: 'center', borderRadius: 5, padding: 3, paddingRight: 15, }, title: { color: 'white', }, subtitle: { color: 'pink', fontSize: 12, }, image: { height: '100%', aspectRatio: 1, marginRight: 10, borderRadius: 5, }, });

Usage

To use the Player component, ensure that it is wrapped within a context provider that supplies the current track information via usePlayerContext. The component will automatically handle audio playback and favorite management based on user interactions.

Setup Instructions

Install the required dependencies:

npm install react-native expo-av @apollo/client @expo/vector-icons

Ensure that your GraphQL server is running and accessible.

Import and use the Player component in your application.

Challenges

Importing Stepzen in the terminal failed often. This was resolved by importing them manually in the files.

Coming Features

Lyric Statcard

Time duration for songs shown

Video Playback