parent
42f873b48c
commit
b59f0d961c
@ -1,8 +1,8 @@
|
|||||||
import {SafeAreaView, StyleSheet} from 'react-native';
|
import {SafeAreaView, StyleSheet} from 'react-native';
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import BottomTabNavigator from "@react-navigation/bottom-tabs/src/navigators/createBottomTabNavigator";
|
import NavigationBar from "./componente/Navigation/NavigationBar";
|
||||||
import NavigationBar from "./componente/NavigationBar";
|
|
||||||
import {Provider} from "react-redux";
|
import {Provider} from "react-redux";
|
||||||
|
|
||||||
import store from "./redux/store";
|
import store from "./redux/store";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
@ -0,0 +1,45 @@
|
|||||||
|
export class Album{
|
||||||
|
private _id: number;
|
||||||
|
private _name: string;
|
||||||
|
private _coverUrl: string
|
||||||
|
private _date: Date;
|
||||||
|
|
||||||
|
constructor(id: number, name: string, coverUrl: string, date: Date) {
|
||||||
|
this._id = id;
|
||||||
|
this._name = name;
|
||||||
|
this._coverUrl = coverUrl;
|
||||||
|
this._date = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id(): number {
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
set id(value: number) {
|
||||||
|
this._id = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
set name(value: string) {
|
||||||
|
this._name = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get coverUrl(): string {
|
||||||
|
return this._coverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
set coverUrl(value: string) {
|
||||||
|
this._coverUrl = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get date(): Date {
|
||||||
|
return this._date;
|
||||||
|
}
|
||||||
|
|
||||||
|
set date(value: Date) {
|
||||||
|
this._date = value;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import React from 'react';
|
||||||
|
import {View, Image, Text, StyleSheet} from 'react-native';
|
||||||
|
|
||||||
|
const AlbumCard = ({ album }) => {
|
||||||
|
console.log(album);
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Image source={{ uri: album.coverUrl }} style={styles.image}/>
|
||||||
|
<Text style={styles.name}>{album.name}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AlbumCard;
|
@ -0,0 +1,27 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {FlatList, ScrollView, StyleSheet, View} from "react-native";
|
||||||
|
import AlbumCard from "./AlbumCard";
|
||||||
|
|
||||||
|
const ArtistList = ({ALBUM_LIST}) => {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<FlatList
|
||||||
|
data={ALBUM_LIST}
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<AlbumCard album={item} />
|
||||||
|
)}
|
||||||
|
keyExtractor={(item) => item.name}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
height: 400,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ArtistList;
|
||||||
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
|||||||
import {createBottomTabNavigator} from "@react-navigation/bottom-tabs";
|
import {createBottomTabNavigator} from "@react-navigation/bottom-tabs";
|
||||||
import {NavigationContainer} from "@react-navigation/native";
|
import {NavigationContainer} from "@react-navigation/native";
|
||||||
import {AntDesign, Ionicons} from '@expo/vector-icons';
|
import {AntDesign, Ionicons} from '@expo/vector-icons';
|
||||||
import SettingsPage from "./SettingsPage";
|
import SettingsPage from "../SettingsPage";
|
||||||
import HomePage from "./HomePage";
|
import StackNavigationHomePage from "./StackNavigationHomePage";
|
||||||
import StackNavigation from "./StackNavigation";
|
import StackNavigationSearchPage from "./StackNavigationSearchPage";
|
||||||
|
|
||||||
export default function NavigationBar() {
|
export default function NavigationBar() {
|
||||||
const BottomTabNavigator = createBottomTabNavigator();
|
const BottomTabNavigator = createBottomTabNavigator();
|
||||||
return (
|
return (
|
||||||
<NavigationContainer >
|
<NavigationContainer >
|
||||||
<BottomTabNavigator.Navigator initialRouteName="HomeNav" screenOptions={{headerShown: false}}>
|
<BottomTabNavigator.Navigator initialRouteName="HomeNav" screenOptions={{headerShown: false}}>
|
||||||
<BottomTabNavigator.Screen name="HomeNav" component={StackNavigation} options={{
|
<BottomTabNavigator.Screen name="HomeNav" component={StackNavigationHomePage} options={{
|
||||||
title: 'Home',
|
title: 'Home',
|
||||||
tabBarIcon: () => (<AntDesign name="home" size={24} color="black" />)
|
tabBarIcon: () => (<AntDesign name="home" size={24} color="black" />)
|
||||||
}}/>
|
}}/>
|
||||||
|
<BottomTabNavigator.Screen name="Search" component={StackNavigationSearchPage} options={{
|
||||||
|
title: 'Search',
|
||||||
|
tabBarIcon: () => (<AntDesign name="search1" size={24} color="black" />)
|
||||||
|
}}/>
|
||||||
<BottomTabNavigator.Screen name="Settings" component={SettingsPage} options={{
|
<BottomTabNavigator.Screen name="Settings" component={SettingsPage} options={{
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
tabBarIcon: () => (<Ionicons name="settings-outline" size={24} color="black" />)
|
tabBarIcon: () => (<Ionicons name="settings-outline" size={24} color="black" />)
|
@ -1,15 +1,12 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {NavigationContainer} from "@react-navigation/native";
|
|
||||||
import {createStackNavigator} from "@react-navigation/stack";
|
import {createStackNavigator} from "@react-navigation/stack";
|
||||||
import SettingsPage from "./SettingsPage";
|
import HomePage from "../HomePage";
|
||||||
import HomePage from "./HomePage";
|
import ArtistePage from "../Artist/ArtistePage";
|
||||||
import ArtistePage from "./Artist/ArtistePage";
|
|
||||||
import NavigationBar from "./NavigationBar";
|
|
||||||
|
|
||||||
const Stack = createStackNavigator();
|
const Stack = createStackNavigator();
|
||||||
|
|
||||||
export default function StackNavigation() {
|
export default function StackNavigationHomePage() {
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator initialRouteName="Home">
|
<Stack.Navigator initialRouteName="Home">
|
||||||
<Stack.Screen name="Home" component={HomePage}/>
|
<Stack.Screen name="Home" component={HomePage}/>
|
@ -0,0 +1,17 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import React from "react";
|
||||||
|
import {createStackNavigator} from "@react-navigation/stack";
|
||||||
|
import HomePage from "../HomePage";
|
||||||
|
import ArtistePage from "../Artist/ArtistePage";
|
||||||
|
import SearchPage from "../SearchPage";
|
||||||
|
|
||||||
|
const Stack = createStackNavigator();
|
||||||
|
|
||||||
|
export default function StackNavigationSearchPage() {
|
||||||
|
return (
|
||||||
|
<Stack.Navigator initialRouteName="Home">
|
||||||
|
<Stack.Screen name="Search" component={SearchPage}/>
|
||||||
|
<Stack.Screen name="ArtistDetail" component={ArtistePage}/>
|
||||||
|
</Stack.Navigator>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { TextInput, TouchableOpacity, View, StyleSheet } from "react-native";
|
||||||
|
import { AntDesign } from "@expo/vector-icons";
|
||||||
|
import {searchArtists} from "../redux/actions/action";
|
||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
|
||||||
|
const SearchBar = () => {
|
||||||
|
const [searchText, setSearchText] = useState("");
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const handleSearch = () => {
|
||||||
|
console.log(searchText)
|
||||||
|
const loadArtist = async () => {
|
||||||
|
// @ts-ignore
|
||||||
|
await dispatch(searchArtists(searchText));
|
||||||
|
};
|
||||||
|
loadArtist();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<TextInput style={styles.input} value={searchText} onChangeText={setSearchText} placeholder="Search"/>
|
||||||
|
<TouchableOpacity onPress={handleSearch}>
|
||||||
|
<AntDesign name="search1" size={24} color="black" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
backgroundColor: "#FFFFFF",
|
||||||
|
borderRadius: 5,
|
||||||
|
margin: 10,
|
||||||
|
paddingHorizontal: 5,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
flex: 1,
|
||||||
|
fontSize: 18,
|
||||||
|
paddingVertical: 10,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default SearchBar;
|
@ -0,0 +1,18 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ArtistList from "./Artist/ArtistList";
|
||||||
|
import {View} from "react-native";
|
||||||
|
import SearchBar from "./SearchBar";
|
||||||
|
|
||||||
|
|
||||||
|
const SearchPage = ({ navigation }) => {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<SearchBar/>
|
||||||
|
<ArtistList navigation={navigation} type={"search"}/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchPage;
|
||||||
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
import {FETCH_ARTISTE,ACCESS_TOKEN} from '../constants';
|
|
||||||
import {Artist} from "../../Model/Artist";
|
|
||||||
|
|
||||||
|
|
||||||
export const setArtistList = (artistList: Artist[]) => {
|
|
||||||
return {
|
|
||||||
type: FETCH_ARTISTE,
|
|
||||||
payload: artistList,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getArtistList = (recherche) => {
|
|
||||||
return async dispatch => {
|
|
||||||
try{
|
|
||||||
const response = await fetch(`https://genius.com/api/search/artists?q=${encodeURIComponent(recherche)}`);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Network response was not ok');
|
|
||||||
}
|
|
||||||
|
|
||||||
const artistListJson = await response.json();
|
|
||||||
console.log(artistListJson);
|
|
||||||
|
|
||||||
|
|
||||||
/*artistListJson.response.hits.map((hit: any) =>
|
|
||||||
/*new Artist(hit.result.name, hit.result.image_url)*/
|
|
||||||
//console.log(hit)
|
|
||||||
//);
|
|
||||||
const artistList: Artist[] = artistListJson.response.sections[0].hits.map(hit => new Artist(hit.result.name, hit.result.image_url));
|
|
||||||
|
|
||||||
console.log(artistList);
|
|
||||||
|
|
||||||
|
|
||||||
dispatch(setArtistList(artistList));
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getArtistInfo = (idArtist) => {
|
|
||||||
return async dispatch => {
|
|
||||||
try{
|
|
||||||
const response = await fetch(`https://api.genius.com/artists/${idArtist}`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${ACCESS_TOKEN}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Network response was not ok');
|
|
||||||
}
|
|
||||||
|
|
||||||
const artistInfoJson = await response.json();
|
|
||||||
console.log(artistInfoJson);
|
|
||||||
|
|
||||||
|
|
||||||
/*const artistList: Artist[] = artistListJson.response.hits.map((hit: any) =>
|
|
||||||
new Artist(hit.result.primary_artist.name, hit.result.primary_artist.age)
|
|
||||||
);*/
|
|
||||||
|
|
||||||
|
|
||||||
//dispatch(setArtistList(artistList));
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,114 @@
|
|||||||
|
import {FETCH_ARTISTE_SEARCH,ACCESS_TOKEN} from '../constants';
|
||||||
|
import {Artist} from "../../Model/Artist";
|
||||||
|
import {Album} from "../../Model/Album";
|
||||||
|
|
||||||
|
|
||||||
|
export const setArtistList = (artistList: Artist[]) => {
|
||||||
|
return {
|
||||||
|
type: FETCH_ARTISTE_SEARCH,
|
||||||
|
payload: artistList,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const searchArtists = (recherche) => {
|
||||||
|
console.log("getArtistList");
|
||||||
|
return async dispatch => {
|
||||||
|
try{
|
||||||
|
const response = await fetch(`https://genius.com/api/search/artists?page=1&q=${encodeURIComponent(recherche)}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('[searchArtists] Network response was not ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
const artistListJson = await response.json();
|
||||||
|
console.log(artistListJson);
|
||||||
|
|
||||||
|
console.log("ici")
|
||||||
|
const artistList: Artist[] = artistListJson.response.sections[0].hits.map(hit =>
|
||||||
|
new Artist(hit.result.id, hit.result.name, hit.result.image_url,"")
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(setArtistList(artistList));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getArtistInfo = (artist) => {
|
||||||
|
console.log(artist._id)
|
||||||
|
return async dispatch => {
|
||||||
|
try{
|
||||||
|
const response = await fetch(`https://api.genius.com/artists/${artist._id}`, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${ACCESS_TOKEN}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.log(response);
|
||||||
|
throw new Error('[getArtistInfo] Network response was not ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
const artistInfoJson = await response.json();
|
||||||
|
artist.bio = artistInfoJson.response.artist.description.dom.children[0].children[0];
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSongByArtist = (artist) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try{
|
||||||
|
const response = await fetch(`https://api.genius.com/artists/${artist.id}/songs`, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${ACCESS_TOKEN}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.log(response);
|
||||||
|
throw new Error('[getSongByArtist] Network response was not ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
const artistSongsJson = await response.json();
|
||||||
|
console.log(artistSongsJson);
|
||||||
|
artistSongsJson.response.songs.map((hit: any) => console.log(hit));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getAlbumByArtist = (artist) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try{
|
||||||
|
const response = await fetch(`https://genius.com/api/artists/${artist.id}/albums`)
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.log(response);
|
||||||
|
throw new Error('[getAlbumByArtist] Network response was not ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
const artistAlbumJson = await response.json();
|
||||||
|
const albumList: Album[] = artistAlbumJson.response.albums.map((album: any) =>
|
||||||
|
new Album(album.id,
|
||||||
|
album.name,
|
||||||
|
album.cover_art_thumbnail_url,
|
||||||
|
// @ts-ignore
|
||||||
|
Date(album.release_date_components.day, album.release_date_components.month, album.release_date_components.year)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
artist.listAlbum = albumList;
|
||||||
|
console.log(artist.listAlbum);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
export const FETCH_ARTISTE = 'FETCH_ARTISTE';
|
|
||||||
|
|
||||||
export const ACCESS_TOKEN = 'nhmGn3gceDRH04YeeCqOSg1nD3cAXxIM_MOAOdh7lADuizSGEIuhAIT1dZ6hmkDU';
|
|
@ -0,0 +1,5 @@
|
|||||||
|
export const FETCH_ARTISTE = 'FETCH_ARTISTE';
|
||||||
|
export const FETCH_ARTISTE_SEARCH = 'FETCH_ARTISTE_SEARCH';
|
||||||
|
|
||||||
|
|
||||||
|
export const ACCESS_TOKEN = 'M0GAzZXbwqfifGOTxfB7lLmEWlRNadkFGV99E9SQCgirIX58kbcvEFYhu2WajbGH';
|
@ -1,14 +0,0 @@
|
|||||||
import {FETCH_ARTISTE} from '../constants';
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
artists: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function appReducer(state = initialState, action){
|
|
||||||
switch (action.type) {
|
|
||||||
case FETCH_ARTISTE:
|
|
||||||
return {...state, artists: action.payload};
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,19 @@
|
|||||||
|
import {FETCH_ARTISTE, FETCH_ARTISTE_SEARCH} from '../constants';
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
artists: [],
|
||||||
|
artistsSearch: []
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ReducerArtist(state = initialState, action){
|
||||||
|
switch (action.type) {
|
||||||
|
case FETCH_ARTISTE:
|
||||||
|
// @ts-ignore
|
||||||
|
return {...state, artists: action.payload};
|
||||||
|
case FETCH_ARTISTE_SEARCH:
|
||||||
|
return {...state, artistsSearch: action.payload};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +0,0 @@
|
|||||||
import {configureStore} from '@reduxjs/toolkit'
|
|
||||||
import appReducer from './reducers/reducer';
|
|
||||||
|
|
||||||
// Reference here all your application reducers
|
|
||||||
const reducer = {
|
|
||||||
appReducer: appReducer,
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const store = configureStore({
|
|
||||||
reducer,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export default store;
|
|
@ -0,0 +1,15 @@
|
|||||||
|
import {configureStore} from '@reduxjs/toolkit'
|
||||||
|
import ReducerArtist from './reducers/reducerArtist';
|
||||||
|
|
||||||
|
// Reference here all your application reducers
|
||||||
|
const reducer = {
|
||||||
|
ReducerArtist: ReducerArtist,
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = configureStore(
|
||||||
|
{
|
||||||
|
reducer,
|
||||||
|
middleware: (getDefaultMiddleware ) => getDefaultMiddleware({serializableCheck : false})
|
||||||
|
} );
|
||||||
|
|
||||||
|
export default store;
|
Loading…
Reference in new issue