Savinvadim1312 / SpotifyClone

MIT License
133 stars 75 forks source link

how to make the user play all the song in the album when they click the pause button in Album Screen #2

Open sir-george2500 opened 3 years ago

sir-george2500 commented 3 years ago

Hi dear hoping you help me on this one and also a big thank you for turning in to my question I am working on a musical app I am using react-native and aws has my backend tools my problem is I have a album and I will like to play the whole album I mean all the song in the album if the user hit the album play button , below is my code for the db schema and the album button and the player Widget ...

Here is the code for the albumHeader

import React from 'react';
import { View, Text, Image } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { Album } from '../../types';
import styles from './styles';

export type AlbumHeaderProp = {
    album: Album;
}

const AlbumHeader = (props: AlbumHeaderProp) => {

    const { album } = props;
    return (
        <View style={styles.container}>
            <Image source={{ uri: album.imageUri }} style={styles.image} />
            <Text style={styles.name}>{album.name}</Text>

            <View style={styles.creatorContainer}>
                <Text style={styles.creator}>By {album.by}</Text>
                <Text style={styles.likes}>{album.numberOfLikes} Likes</Text>
            </View>
// This area is the play button I am talking about 
            <TouchableOpacity>
                <View style={styles.button}>
                    <Text style={styles.buttonText}>Play</Text>
                </View>
            </TouchableOpacity>

        </View>
    )
}

export default AlbumHeader;

Here is the SongListIem file

import React, { useContext } from 'react';
import { Text, Image, View, TouchableWithoutFeedback, TouchableOpacity } from 'react-native';

import styles from './styles';
import { Song } from "../../types";
import { AppContext } from '../../AppContext';

export type SongListItemProps = {

    song: Song

}

const SongListItem = (props: SongListItemProps) => {
    const { song } = props;

    const { setSongId, songId } = useContext(AppContext);

    const onPlay = () => {

        setSongId(song.id);

    }

    return (
        <TouchableOpacity onPress={onPlay}>
            <View style={styles.container}>
                <Image source={{ uri: song.imageUri }} style={styles.image} />
                <View style={styles.rightContainer}>
                    <Text style={styles.title}>{song.title}</Text>
                    <Text style={styles.artist}>{song.artist}</Text>
                </View>

            </View>
        </TouchableOpacity>
    )
}

export default SongListItem;

Here is the player Widget

import React, { useContext, useEffect, useState } from 'react';
import { Text, Image, View, TouchableOpacity } from 'react-native';
import { AntDesign, FontAwesome } from "@expo/vector-icons";
import { API, graphqlOperation } from 'aws-amplify';

import styles from './styles';
import { Song } from "../../types";
import { Sound } from "expo-av/build/Audio/Sound";

import { AppContext } from '../../AppContext';
import { getSong } from "../../src/graphql/queries";

const PlayerWidget = () => {

    const { songId } = useContext(AppContext);

    const [song, setSong] = useState(null);
    const [sound, setSound] = useState<Sound | null>(null);
    const [isPlaying, setIsPlaying] = useState<boolean>(true);
    const [duration, setDuration] = useState<number | null>(null);
    const [position, setPosition] = useState<number | null>(null);

    useEffect(() => {
        const fetchSong = async () => {
            try {
                const data = await API.graphql(graphqlOperation(getSong, { id: songId }))
                setSong(data.data.getSong);
            } catch (e) {
                console.log(e);
            }
        }

        fetchSong();
    }, [songId]);

    if (song?.artist.length > 10) {
        song.artist = song.artist.substring(0, 6) + "...";
    }

    if (song?.title.length > 8) {
        song.title = song.title.substring(0, 5) + "...";
    }

    const onPlaybackStatusUpdate = (status) => {
        setIsPlaying(status.isPlaying);
        setDuration(status.durationMillis);
        setPosition(status.positionMillis);
    }

    const playCurrentSong = async () => {
        if (sound) {
            await sound.unloadAsync();
        }

        const { sound: newSound } = await Sound.createAsync(
            { uri: song.uri },
            { shouldPlay: isPlaying },
            onPlaybackStatusUpdate
        )

        setSound(newSound)
    }

    useEffect(() => {
        if (song) {
            playCurrentSong();
        }
    }, [song])

    const onPlayPausePress = async () => {
        if (!sound) {
            return;
        }
        if (isPlaying) {
            await sound.pauseAsync();
        }
        else {
            await sound.playAsync();
        }
    }

    const getProgress = () => {
        if (sound === null || duration === null || position === null) {
            return 0;
        }

        return (position / duration) * 100;
    }

    if (!song) {
        return null;
    }

    return (
        <View style={styles.container}>
            <View style={[styles.progress, { width: `${getProgress()}%` }]} />
            <View style={styles.row}>
                <Image source={{ uri: song.imageUri }} style={styles.image} />
                <View style={styles.rightContainer}>
                    <View style={styles.nameContainer}>
                        <Text style={styles.title}>{song.title}</Text>
                        <Text style={styles.artist}>{song.artist}</Text>
                    </View>

                    <View style={styles.iconsContainer}>
                        <AntDesign name="hearto" size={30} color={"white"} />
                        <TouchableOpacity onPress={onPlayPausePress}>
                            <FontAwesome name={isPlaying ? 'pause' : 'play'} size={30} color={"white"} />
                        </TouchableOpacity>
                    </View>
                </View>
            </View>
        </View>
    )
}

export default PlayerWidget;

Here is the AppContext

import React from 'react';

const context = {
    songId: null,
    setSongId: (id: string) => {

    }
}

export const AppContext = React.createContext(context);

This one is a bit boring but if you need the Schema here is it

/* tslint:disable */
/* eslint-disable */
// this is an auto generated file. This will be overwritten

export const getAlbumCategory = /* GraphQL */ `
  query GetAlbumCategory($id: ID!) {
    getAlbumCategory(id: $id) {
      id
      title
      albums {
        items {
          id
          name
          by
          numberOfLikes
          imageUri
          artistsHeadline
          albumCategoryId
          createdAt
          updatedAt
        }
        nextToken
      }
      createdAt
      updatedAt
    }
  }
`;
export const listAlbumCategorys = /* GraphQL */ `
  query ListAlbumCategorys(
    $filter: ModelAlbumCategoryFilterInput
    $limit: Int
    $nextToken: String
  ) {
    listAlbumCategorys(filter: $filter, limit: $limit, nextToken: $nextToken) {
      items {
        id
        title
        albums {
          items{
            id
            imageUri
            artistsHeadline
          }
        }
        createdAt
        updatedAt
      }
      nextToken
    }
  }
`;
export const getAlbum = /* GraphQL */ `
  query GetAlbum($id: ID!) {
    getAlbum(id: $id) {
      id
      name
      by
      numberOfLikes
      imageUri
      artistsHeadline
      songs {
        items {
          id
          imageUri
          uri
          title
          artist
          albumId
          createdAt
          updatedAt
        }
        nextToken
      }
      albumCategoryId
      albumCategory {
        id
        title
        albums {
          nextToken
        }
        createdAt
        updatedAt
      }
      createdAt
      updatedAt
    }
  }
`;
export const listAlbums = /* GraphQL */ `
  query ListAlbums(
    $filter: ModelAlbumFilterInput
    $limit: Int
    $nextToken: String
  ) {
    listAlbums(filter: $filter, limit: $limit, nextToken: $nextToken) {
      items {
        id
        name
        by
        numberOfLikes
        imageUri
        artistsHeadline
        songs {
          nextToken
        }
        albumCategoryId
        albumCategory {
          id
          title
          createdAt
          updatedAt
        }
        createdAt
        updatedAt
      }
      nextToken
    }
  }
`;
export const getSong = /* GraphQL */ `
  query GetSong($id: ID!) {
    getSong(id: $id) {
      id
      imageUri
      uri
      title
      artist
      albumId
      album {
        id
        name
        by
        numberOfLikes
        imageUri
        artistsHeadline
        songs {
          nextToken
        }
        albumCategoryId
        albumCategory {
          id
          title
          createdAt
          updatedAt
        }
        createdAt
        updatedAt
      }
      createdAt
      updatedAt
    }
  }
`;
export const listSongs = /* GraphQL */ `
  query ListSongs(
    $filter: ModelSongFilterInput
    $limit: Int
    $nextToken: String
  ) {
    listSongs(filter: $filter, limit: $limit, nextToken: $nextToken) {
      items {
        id
        imageUri
        uri
        title
        artist
        albumId
        album {
          id
          name
          by
          numberOfLikes
          imageUri
          artistsHeadline
          albumCategoryId
          createdAt
          updatedAt
        }
        createdAt
        updatedAt
      }
      nextToken
    }
  }
`;
siviwexakaza commented 2 years ago

Working on a similar thing, will probably put up a PR soon