From e3784651265477b8535f22ccf5eac07a78822c1a Mon Sep 17 00:00:00 2001 From: danis Date: Wed, 21 Jun 2023 08:21:34 +0200 Subject: [PATCH 01/28] components RowCustom & SongRow + artist banner --- back/src/song/song.controller.ts | 3 ++ front/components/RowCustom.tsx | 36 ++++++++++++++++ front/components/SongRow.tsx | 69 +++++++++++++++++++++++++++++++ front/views/ArtistDetailsView.tsx | 59 +++++++++++++++----------- 4 files changed, 144 insertions(+), 23 deletions(-) create mode 100644 front/components/RowCustom.tsx create mode 100644 front/components/SongRow.tsx diff --git a/back/src/song/song.controller.ts b/back/src/song/song.controller.ts index 63ac65e..5e69056 100644 --- a/back/src/song/song.controller.ts +++ b/back/src/song/song.controller.ts @@ -26,6 +26,7 @@ import { createReadStream, existsSync } from 'fs'; import { ApiTags, ApiUnauthorizedResponse } from '@nestjs/swagger'; import { HistoryService } from 'src/history/history.service'; import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'; +import { IsDefined } from 'class-validator'; @Controller('song') @ApiTags('song') @@ -107,6 +108,7 @@ export class SongController { @Query() filter: Prisma.SongWhereInput, @Query('skip', new DefaultValuePipe(0), ParseIntPipe) skip: number, @Query('take', new DefaultValuePipe(20), ParseIntPipe) take: number, + // @Query('artistId') artistId: number, ): Promise> { try { const ret = await this.songService.songs({ @@ -115,6 +117,7 @@ export class SongController { where: { ...filter, id: filter.id ? +filter.id : undefined, + // artistId: artistId ? +artistId : undefined, }, }); return new Plage(ret, req); diff --git a/front/components/RowCustom.tsx b/front/components/RowCustom.tsx new file mode 100644 index 0000000..f72cded --- /dev/null +++ b/front/components/RowCustom.tsx @@ -0,0 +1,36 @@ +import { useColorScheme } from "react-native"; +import { RootState, useSelector } from "../state/Store"; +import { Box, Pressable } from "native-base"; + +const RowCustom = ( + props: Parameters[0] & { onPress?: () => void } +) => { + const settings = useSelector((state: RootState) => state.settings.local); + const systemColorMode = useColorScheme(); + const colorScheme = settings.colorScheme; + + return ( + + {({ isHovered, isPressed }) => ( + + {props.children} + + )} + + ); +}; + +export default RowCustom; \ No newline at end of file diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx new file mode 100644 index 0000000..1924e86 --- /dev/null +++ b/front/components/SongRow.tsx @@ -0,0 +1,69 @@ +import { HStack, Image, Text } from "native-base"; +import Song, { SongWithArtist } from "../models/Song"; +import RowCustom from "./RowCustom"; +import TextButton from "./TextButton"; + + +type SongRowProps = { + song: Song | SongWithArtist; // TODO: remove Song + onPress: () => void; +}; + +const SongRow = ({ song, onPress }: SongRowProps) => { + return ( + + + {song.name} + + + {song.name} + + + {song.artistId ?? "artist"} + + + + + + ); +}; + +export default SongRow; \ No newline at end of file diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 4485263..a1358aa 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -1,40 +1,53 @@ -import { VStack, Text, Image, Heading, IconButton, Icon, Container } from 'native-base'; +import { VStack, Text, Box, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue } from 'native-base'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native'; import { useQuery } from 'react-query'; import LoadingComponent from '../components/Loading'; import API from '../API'; - -const handleFavorite = () => { - -}; +import Song from '../models/Song'; +import SongRow from '../components/SongRow'; +import { useNavigation } from '@react-navigation/native'; const ArtistDetailsView = ({ artistId }: any) => { const { isLoading, data: artistData, error } = useQuery(['artist', artistId], () => API.getArtist(artistId)); + const screenSize = useBreakpointValue({ base: "small", md: "big" }); + const isMobileView = screenSize == "small"; + let songData = [] as Song[]; + const navigation = useNavigation(); if (isLoading) { - return ; + return
; } return ( - - {artistData?.name} - - {artistData?.name} - } - onPress={() => handleFavorite()} - variant="unstyled" - _pressed={{ opacity: 0.6 }} - /> - - + + {artistData?.name} + + Abba + + {songData.map((comp, index) => ( + { + API.createSearchHistoryEntry(comp.name, "song", Date.now()); + navigation.navigate("Song", { songId: comp.id }); + }} + /> + )) + } + + + + ); }; From b2247e79ae1522ee188bf2ee9f82cb7479b70adc Mon Sep 17 00:00:00 2001 From: danis Date: Wed, 28 Jun 2023 09:11:49 +0200 Subject: [PATCH 02/28] having a bug with api :/ --- front/API.ts | 25 +++++++++++++++++++++++++ front/components/SongRow.tsx | 5 ++++- front/views/ArtistDetailsView.tsx | 17 +++++++++++++---- front/views/SearchView.tsx | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/front/API.ts b/front/API.ts index 4d2d3b7..05b8e7a 100644 --- a/front/API.ts +++ b/front/API.ts @@ -237,6 +237,31 @@ export default class API { ); } + /** + * @description retrieves songs from a specific artist + * @param artistId is the id of the artist that composed the songs aimed + * @param skip is how much songs do we skip before returning the list + * @param take is how much songs should be returned + * @returns a Promise of Songs type array + */ + public static async getSongsByArtist(artistId: number): Promise { + // let queryString = `/song?artisId=${artistId}`; + + // if (skip) { + // queryString = `${queryString}&skip=${skip}`; + // } + // if (take) { + // queryString = `${queryString}&take=${take}`; + // } + // return await API.fetch({ + // route: queryString, + // }); + + return API.fetch({ + route: `/song?artistId=${artistId}`, + }); + } + /** * Retrieve a song * @param songId the id to find the song diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index 1924e86..a122e40 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -20,6 +20,8 @@ const SongRow = ({ song, onPress }: SongRowProps) => { style={{ zIndex: 0, aspectRatio: 1, borderRadius: 5 }} source={{ uri: song.cover }} alt={song.name} + borderColor={'white'} + borderWidth={1} /> { flexShrink: 1, }} isTruncated - pl={10} + pl={5} maxW={"100%"} bold fontSize="md" @@ -59,6 +61,7 @@ const SongRow = ({ song, onPress }: SongRowProps) => { colorScheme="primary" variant={"outline"} size="sm" + mr={5} onPress={onPress} /> diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 178632c..e7ef854 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -7,15 +7,24 @@ import API from '../API'; import Song from '../models/Song'; import SongRow from '../components/SongRow'; import { useNavigation } from '@react-navigation/native'; +import { useEffect, useState } from 'react'; const ArtistDetailsView = ({ artistId }: any) => { - const { isLoading, data: artistData, error } = useQuery(['artist', artistId], () => API.getArtist(artistId)); + const { isLoading: isLoadingArtist, data: artistData, error: errorArtist } = useQuery(['artist', artistId], () => API.getArtist(artistId)); + // const { isLoading: isLoadingSongs, data: songData = [], error: errorSongs } = useQuery(['songs', artistId], () => API.getSongsByArtist(artistId)) const screenSize = useBreakpointValue({ base: "small", md: "big" }); const isMobileView = screenSize == "small"; - let songData = [] as Song[]; const navigation = useNavigation(); + const [merde, setMerde] = useState(null); - if (isLoading) { + useEffect(() => { + // Code to be executed when the component is focused + console.warn('Component focused!'); + setMerde(API.getSongsByArtist(112)); + // Call your function or perform any other actions here + }, []); + + if (isLoadingArtist) { return
; } @@ -33,7 +42,7 @@ const ArtistDetailsView = ({ artistId }: any) => { Abba - {songData.map((comp, index) => ( + {merde.map((comp, index) => ( ) => { const { isLoading: isLoadingSong, data: songData = [] } = useQuery( ['song', stringQuery], - () => API.searchSongs(stringQuery), + () => API.getSongsByArtist(112), { enabled: !!stringQuery } ); From 28716eeab25720e2b482219adbeece39034f56c9 Mon Sep 17 00:00:00 2001 From: danis Date: Wed, 5 Jul 2023 09:26:45 +0200 Subject: [PATCH 03/28] init genreDetailsView --- back/src/song/song.controller.ts | 6 ++++++ back/src/song/song.service.ts | 8 ++++++++ front/API.ts | 30 ++++++++++++++++++++++++++---- front/views/ArtistDetailsView.tsx | 20 ++++++-------------- front/views/GenreDetailsView.tsx | 14 ++++++++++++++ 5 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 front/views/GenreDetailsView.tsx diff --git a/back/src/song/song.controller.ts b/back/src/song/song.controller.ts index a80a31b..be725ed 100644 --- a/back/src/song/song.controller.ts +++ b/back/src/song/song.controller.ts @@ -146,4 +146,10 @@ export class SongController { songId: id, }); } + + @Get('/artist/:artistId') + async getSongByArtist(@Param('artistId', ParseIntPipe) artistId: number) { + const res = await this.songService.songByArtist(artistId) + return res; + } } diff --git a/back/src/song/song.service.ts b/back/src/song/song.service.ts index 4a7a285..de7aa02 100644 --- a/back/src/song/song.service.ts +++ b/back/src/song/song.service.ts @@ -6,6 +6,14 @@ import { PrismaService } from 'src/prisma/prisma.service'; export class SongService { constructor(private prisma: PrismaService) {} + async songByArtist(data: number): Promise { + return this.prisma.song.findMany({ + where: { + artistId: {equals: data}, + }, + }); + } + async createSong(data: Prisma.SongCreateInput): Promise { return this.prisma.song.create({ data, diff --git a/front/API.ts b/front/API.ts index b75cc0a..5e30e63 100644 --- a/front/API.ts +++ b/front/API.ts @@ -278,10 +278,32 @@ export default class API { * @param artistId is the id of the artist that composed the songs aimed * @returns a Promise of Songs type array */ - public static async getSongsByArtist(artistId: number): Promise { - return API.fetch({ - route: `/song?artistId=${artistId}`, - }); + public static getSongsByArtist(artistId: string): Query { + return { + key: ['songs', artistId], + exec: async () => { + const songs = await API.fetch({ + route: `/song/artist/${artistId}`, + }); + + // this is a dummy illustration, we will need to fetch the real one from the API + return songs.data.map( + // To be fixed with #168 + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (song: any) => + ({ + id: song.id as number, + name: song.name as string, + artistId: song.artistId as number, + albumId: song.albumId as number, + genreId: song.genreId as number, + details: song.difficulties, + cover: `${baseAPIUrl}/song/${song.id}/illustration`, + metrics: {}, + } as Song) + ); + }, + }; } /** diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 2e5e088..9b07677 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -10,25 +10,17 @@ import { Key, useEffect, useState } from 'react'; import { useNavigation } from '../Navigation'; const ArtistDetailsView = ({ artistId }: any) => { - const { isLoading, data: artistData, isError } = useQuery(API.getArtist(artistId)); - // const { isLoading: isLoadingSongs, data: songData = [], error: errorSongs } = useQuery(['songs', artistId], () => API.getSongsByArtist(artistId)) + const { isLoading: isLoadingArt, data: artistData, error: isErrorArt } = useQuery(API.getArtist(artistId)); + const { isLoading: isLoadingSong, data: songData = [], error: isErrorSong } = useQuery(API.getSongsByArtist(artistId)); const screenSize = useBreakpointValue({ base: "small", md: "big" }); const isMobileView = screenSize == "small"; const navigation = useNavigation(); - const [merde, setMerde] = useState(null); - useEffect(() => { - // Code to be executed when the component is focused - console.warn('Component focused!'); - setMerde(API.getSongsByArtist(112)); - // Call your function or perform any other actions here - }, []); - - if (isLoading) { + if (isLoadingArt) { return ; } - if (isError) { + if (isErrorArt) { navigation.navigate('Error'); } @@ -44,9 +36,9 @@ const ArtistDetailsView = ({ artistId }: any) => { resizeMode='cover' /> - Abba + {artistData?.name} - {merde.map((comp: Song | SongWithArtist, index: Key | null | undefined) => ( + {songData.map((comp: Song | SongWithArtist, index: Key | null | undefined) => ( { + return ( + + + + + + ); +} \ No newline at end of file From 87de52cae02922a84ca6627e825cec1bbed7fe5e Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Wed, 5 Jul 2023 14:18:31 +0100 Subject: [PATCH 04/28] Front: 'Get Song By Artist' Query: fix typings --- front/API.ts | 17 ++++++--- front/components/RowCustom.tsx | 20 +++++----- front/components/SongRow.tsx | 37 +++++++++--------- front/views/ArtistDetailsView.tsx | 62 ++++++++++++++----------------- 4 files changed, 67 insertions(+), 69 deletions(-) diff --git a/front/API.ts b/front/API.ts index 20f15cc..29b2c03 100644 --- a/front/API.ts +++ b/front/API.ts @@ -279,15 +279,22 @@ export default class API { }; } - /** + /** * @description retrieves songs from a specific artist * @param artistId is the id of the artist that composed the songs aimed * @returns a Promise of Songs type array */ - public static async getSongsByArtist(artistId: number): Promise { - return API.fetch({ - route: `/song?artistId=${artistId}`, - }); + public static getSongsByArtist(artistId: number): Query { + return { + key: ['artist', artistId, 'songs'], + exec: () => + API.fetch( + { + route: `/song?artistId=${artistId}`, + }, + { handler: PlageHandler(SongHandler) } + ).then(({ data }) => data), + }; } /** diff --git a/front/components/RowCustom.tsx b/front/components/RowCustom.tsx index f72cded..aa9d4e3 100644 --- a/front/components/RowCustom.tsx +++ b/front/components/RowCustom.tsx @@ -1,10 +1,8 @@ -import { useColorScheme } from "react-native"; -import { RootState, useSelector } from "../state/Store"; -import { Box, Pressable } from "native-base"; +import { useColorScheme } from 'react-native'; +import { RootState, useSelector } from '../state/Store'; +import { Box, Pressable } from 'native-base'; -const RowCustom = ( - props: Parameters[0] & { onPress?: () => void } -) => { +const RowCustom = (props: Parameters[0] & { onPress?: () => void }) => { const settings = useSelector((state: RootState) => state.settings.local); const systemColorMode = useColorScheme(); const colorScheme = settings.colorScheme; @@ -17,13 +15,13 @@ const RowCustom = ( py={3} my={1} bg={ - (colorScheme == "system" ? systemColorMode : colorScheme) == "dark" + (colorScheme == 'system' ? systemColorMode : colorScheme) == 'dark' ? isHovered || isPressed - ? "gray.800" + ? 'gray.800' : undefined : isHovered || isPressed - ? "coolGray.200" - : undefined + ? 'coolGray.200' + : undefined } > {props.children} @@ -33,4 +31,4 @@ const RowCustom = ( ); }; -export default RowCustom; \ No newline at end of file +export default RowCustom; diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index a122e40..4a61c83 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -1,8 +1,7 @@ -import { HStack, Image, Text } from "native-base"; -import Song, { SongWithArtist } from "../models/Song"; -import RowCustom from "./RowCustom"; -import TextButton from "./TextButton"; - +import { HStack, Image, Text } from 'native-base'; +import Song, { SongWithArtist } from '../models/Song'; +import RowCustom from './RowCustom'; +import TextButton from './TextButton'; type SongRowProps = { song: Song | SongWithArtist; // TODO: remove Song @@ -11,8 +10,8 @@ type SongRowProps = { const SongRow = ({ song, onPress }: SongRowProps) => { return ( - - + + { style={{ zIndex: 0, aspectRatio: 1, borderRadius: 5 }} source={{ uri: song.cover }} alt={song.name} - borderColor={'white'} - borderWidth={1} + borderColor={'white'} + borderWidth={1} /> @@ -39,7 +38,7 @@ const SongRow = ({ song, onPress }: SongRowProps) => { }} isTruncated pl={5} - maxW={"100%"} + maxW={'100%'} bold fontSize="md" > @@ -49,19 +48,19 @@ const SongRow = ({ song, onPress }: SongRowProps) => { style={{ flexShrink: 0, }} - fontSize={"sm"} + fontSize={'sm'} > - {song.artistId ?? "artist"} + {song.artistId ?? 'artist'} @@ -69,4 +68,4 @@ const SongRow = ({ song, onPress }: SongRowProps) => { ); }; -export default SongRow; \ No newline at end of file +export default SongRow; diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 2e5e088..3bc9a4b 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -1,62 +1,56 @@ -import { VStack, Text, Box, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue } from 'native-base'; -import { Ionicons } from '@expo/vector-icons'; +import { Box, Image, Heading, useBreakpointValue } from 'native-base'; import { SafeAreaView } from 'react-native'; import { useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import API from '../API'; import Song, { SongWithArtist } from '../models/Song'; import SongRow from '../components/SongRow'; -import { Key, useEffect, useState } from 'react'; -import { useNavigation } from '../Navigation'; +import { Key } from 'react'; +import { RouteProps, useNavigation } from '../Navigation'; -const ArtistDetailsView = ({ artistId }: any) => { - const { isLoading, data: artistData, isError } = useQuery(API.getArtist(artistId)); - // const { isLoading: isLoadingSongs, data: songData = [], error: errorSongs } = useQuery(['songs', artistId], () => API.getSongsByArtist(artistId)) - const screenSize = useBreakpointValue({ base: "small", md: "big" }); - const isMobileView = screenSize == "small"; +type ArtistDetailsViewProps = { + artistId: number; +}; + +const ArtistDetailsView = ({ artistId }: RouteProps) => { + const artistQuery = useQuery(API.getArtist(artistId)); + const songsQuery = useQuery(API.getSongsByArtist(artistId)); + const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); + const isMobileView = screenSize == 'small'; const navigation = useNavigation(); - const [merde, setMerde] = useState(null); - useEffect(() => { - // Code to be executed when the component is focused - console.warn('Component focused!'); - setMerde(API.getSongsByArtist(112)); - // Call your function or perform any other actions here - }, []); - - if (isLoading) { - return ; - } - - if (isError) { + if (artistQuery.isError || songsQuery.isError) { navigation.navigate('Error'); + return <>; + } + if (!artistQuery.data || songsQuery.data === undefined) { + return ; } return ( {artistData?.name} - Abba + Abba - {merde.map((comp: Song | SongWithArtist, index: Key | null | undefined) => ( + {songsQuery.data.map((comp: Song, index: Key | null | undefined) => ( { - API.createSearchHistoryEntry(comp.name, "song", Date.now()); - navigation.navigate("Song", { songId: comp.id }); + API.createSearchHistoryEntry(comp.name, 'song'); + navigation.navigate('Song', { songId: comp.id }); }} /> - )) - } + ))} From 3a09d10d3bdf683d9847bef86952f3104e99c833 Mon Sep 17 00:00:00 2001 From: danis Date: Sun, 9 Jul 2023 23:24:31 +0200 Subject: [PATCH 05/28] you miss 100% of the shots you dont take --- front/Navigation.tsx | 6 ++ front/components/SearchResult.tsx | 14 +-- front/views/ArtistDetailsView.tsx | 109 ++++++++++++++++++++-- front/views/GenreDetailsView.tsx | 145 ++++++++++++++++++++++++++++-- 4 files changed, 251 insertions(+), 23 deletions(-) diff --git a/front/Navigation.tsx b/front/Navigation.tsx index 011967b..fc64f15 100644 --- a/front/Navigation.tsx +++ b/front/Navigation.tsx @@ -28,6 +28,7 @@ import { Button, Center, VStack } from 'native-base'; import { unsetAccessToken } from './state/UserSlice'; import TextButton from './components/TextButton'; import ErrorView from './views/ErrorView'; +import GenreDetailsView from './views/GenreDetailsView'; // Util function to hide route props in URL const removeMe = () => ''; @@ -58,6 +59,11 @@ const protectedRoutes = () => options: { title: translate('artistFilter') }, link: '/artist/:artistId', }, + Genre: { + component: GenreDetailsView, + options: { title: translate('genreFilter')}, + link: '/genre/:genreId', + }, Score: { component: ScoreView, options: { title: translate('score'), headerLeft: null }, diff --git a/front/components/SearchResult.tsx b/front/components/SearchResult.tsx index 274cf54..aab02bf 100644 --- a/front/components/SearchResult.tsx +++ b/front/components/SearchResult.tsx @@ -252,13 +252,13 @@ const ArtistSearchComponent = (props: ItemSearchComponentProps) => { {artistData?.length ? ( ({ - image: API.getArtistIllustration(a.id), - name: a.name, - id: a.id, + content={artistData.slice(0, props.maxItems ?? artistData.length).map((artistData) => ({ + image: API.getArtistIllustration(artistData.id), + name: artistData.name, + id: artistData.id, onPress: () => { - API.createSearchHistoryEntry(a.name, 'artist'); - navigation.navigate('Artist', { artistId: a.id }); + API.createSearchHistoryEntry(artistData.name, 'artist'); + navigation.navigate('Artist', { artistId: artistData.id }); }, }))} cardComponent={ArtistCard} @@ -287,7 +287,7 @@ const GenreSearchComponent = (props: ItemSearchComponentProps) => { id: g.id, onPress: () => { API.createSearchHistoryEntry(g.name, 'genre'); - navigation.navigate('Home'); + navigation.navigate('Genre', {genreId: g.id}); }, }))} cardComponent={GenreCard} diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 9b07677..7baa1b4 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -1,4 +1,4 @@ -import { VStack, Text, Box, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue } from 'native-base'; +import { VStack, Text, Box, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue, ScrollView } from 'native-base'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native'; import { useQuery } from '../Queries'; @@ -9,6 +9,99 @@ import SongRow from '../components/SongRow'; import { Key, useEffect, useState } from 'react'; import { useNavigation } from '../Navigation'; +const songs: Song[] = [ + { + id: 1, + name: "Dancing Queen", + artistId: 1, + albumId: 1, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 2, + name: "Mamma Mia", + artistId: 1, + albumId: 1, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 3, + name: "Take a Chance on Me", + artistId: 1, + albumId: 2, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 4, + name: "Fernando", + artistId: 1, + albumId: 3, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 5, + name: "Waterloo", + artistId: 1, + albumId: 4, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 6, + name: "The Winner Takes It All", + artistId: 1, + albumId: 5, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 7, + name: "SOS", + artistId: 1, + albumId: 6, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 8, + name: "Knowing Me, Knowing You", + artistId: 1, + albumId: 7, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 9, + name: "Money, Money, Money", + artistId: 1, + albumId: 8, + genreId: 1, + cover: undefined, + details: undefined, + }, + { + id: 10, + name: "Gimme! Gimme! Gimme! (A Man After Midnight)", + artistId: 1, + albumId: 9, + genreId: 1, + cover: undefined, + details: undefined, + }, +]; + const ArtistDetailsView = ({ artistId }: any) => { const { isLoading: isLoadingArt, data: artistData, error: isErrorArt } = useQuery(API.getArtist(artistId)); const { isLoading: isLoadingSong, data: songData = [], error: isErrorSong } = useQuery(API.getSongsByArtist(artistId)); @@ -25,10 +118,10 @@ const ArtistDetailsView = ({ artistId }: any) => { } return ( - + {artistData?.name} { resizeMode='cover' /> - {artistData?.name} - - {songData.map((comp: Song | SongWithArtist, index: Key | null | undefined) => ( + {artistData?.name} + + {songs.map((comp: Song | SongWithArtist, index: Key | null | undefined) => ( { /> )) } - + - + ); }; diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index a4a78d0..4a8b3d8 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -1,14 +1,143 @@ import { SafeAreaView } from 'react-native'; -import { VStack, Text, Box, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue } from 'native-base'; +import { VStack, Text, Box, Flex, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue, ScrollView } from 'native-base'; +import { useQuery } from '../Queries'; +import { LoadingView } from '../components/Loading'; +import { useNavigation } from '../Navigation'; +import API from '../API'; +import Artist from '../models/Artist'; +const colorRange = [ + { + code: '#364fc7', + }, + { + code: '#5c940d', + }, + { + code: '#c92a2a', + }, + { + code: '#d6336c', + }, + { + code: '#20c997' + } +] +const rockArtists: Artist[] = [ + { + id: 1, + name: "Led Zeppelin", + picture: "https://picsum.photos/200", + }, + { + id: 2, + name: "Queen", + picture: "https://picsum.photos/200", + }, + { + id: 3, + name: "The Rolling Stones", + picture: "https://picsum.photos/200", + }, + { + id: 4, + name: "AC/DC", + picture: "https://picsum.photos/200", + }, + { + name: "Guns N' Roses", + id: 5, + picture: "https://picsum.photos/200", + }, +]; + +const rockSongs: Song[] = [ + { + id: 1, + name: "Stairway to Heaven", + artistId: 1, + albumId: 1, + genreId: 1, + cover: "https://picsum.photos/200", + details: { /* song details */ }, + }, + { + id: 2, + name: "Bohemian Rhapsody", + artistId: 2, + albumId: 2, + genreId: 1, + cover: "https://picsum.photos/200", + details: { /* song details */ }, + }, + { + id: 3, + name: "Paint It Black", + artistId: 3, + albumId: 3, + genreId: 1, + cover: "https://picsum.photos/200", + details: { /* song details */ }, + }, + { + id: 4, + name: "Highway to Hell", + artistId: 4, + albumId: 4, + genreId: 1, + cover: "https://picsum.photos/200", + details: { /* song details */ }, + }, + { + id: 5, + name: "Sweet Child o' Mine", + artistId: 5, + albumId: 5, + genreId: 1, + cover: "https://picsum.photos/200", + details: { /* song details */ }, + }, + // Add more songs as needed + ]; const GenreDetailsView = ({ genreId }: any) => { + // const { isLoading: isLoadingGenre, data: genreData, error: isErrorGenre } = useQuery(API.getArtist(genreId)); + const screenSize = useBreakpointValue({ base: "small", md: "big" }); + const isMobileView = screenSize == "small"; + const navigation = useNavigation(); + + // if (isLoadingGenre) { + // return ; + // } + + // if (isErrorGenre) { + // navigation.navigate('Error'); + // } + return ( - - - - - - ); -} \ No newline at end of file + + + + + + + + + + + +); +} + +export default GenreDetailsView; \ No newline at end of file From 373128ba5310d5d1d555109ee851ff4ffcd0c004 Mon Sep 17 00:00:00 2001 From: danis Date: Mon, 10 Jul 2023 23:12:37 +0200 Subject: [PATCH 06/28] broke my glasses --- front/components/SongRow.tsx | 6 +++--- front/views/GenreDetailsView.tsx | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index a122e40..bc2dff2 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -20,8 +20,8 @@ const SongRow = ({ song, onPress }: SongRowProps) => { style={{ zIndex: 0, aspectRatio: 1, borderRadius: 5 }} source={{ uri: song.cover }} alt={song.name} - borderColor={'white'} - borderWidth={1} + borderColor={'white'} + borderWidth={1} /> { colorScheme="primary" variant={"outline"} size="sm" - mr={5} + mr={5} onPress={onPress} /> diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 4a8b3d8..ba4f42c 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -5,6 +5,9 @@ import { LoadingView } from '../components/Loading'; import { useNavigation } from '../Navigation'; import API from '../API'; import Artist from '../models/Artist'; +import ArtistCard from '../components/ArtistCard'; +import CardGridCustom from '../components/CardGridCustom'; +import { translate } from '../i18n/i18n'; const colorRange = [ { @@ -121,7 +124,7 @@ const GenreDetailsView = ({ genreId }: any) => { size={'100%'} height={isMobileView ? 200 : 300} width={'100%'} - backgroundColor={'#20c997'} + backgroundColor={colorRange[Math.floor(Math.random() * 5)]?.code ?? '#364fc7'} /> { mt={4} > - + {rockArtists?.length ? ( + ({ + image: API.getArtistIllustration(artistData.id), + name: artistData.name, + id: artistData.id, + onPress: () => { + API.createSearchHistoryEntry(artistData.name, 'artist'); + navigation.navigate('Artist', { artistId: artistData.id }); + }, + }))} + cardComponent={ArtistCard} + /> + ) : ( + {translate('errNoResults')} + )} From bf09a25eb54ffaf580dc5facc674ad983cea5333 Mon Sep 17 00:00:00 2001 From: danis Date: Tue, 11 Jul 2023 10:06:55 +0200 Subject: [PATCH 07/28] linear gradient --- front/Theme.tsx | 6 ++++++ front/package.json | 5 +++-- front/views/ArtistDetailsView.tsx | 32 ++++++++++++++++++++++++++++--- front/views/GenreDetailsView.tsx | 8 +++++++- front/yarn.lock | 5 +++++ 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/front/Theme.tsx b/front/Theme.tsx index 6d7fc57..9c19074 100644 --- a/front/Theme.tsx +++ b/front/Theme.tsx @@ -4,9 +4,15 @@ import { useEffect } from 'react'; const ThemeProvider = ({ children }: { children: JSX.Element }) => { const colorScheme = useColorScheme(); + const config = { + dependencies: { + "linear-gradient": require("expo-linear-gradient").LinearGradient, + }, + }; return ( { return ( - + + + + {/* {artistData?.name} { height={isMobileView ? 200 : 300} width={'100%'} resizeMode='cover' - /> + /> */} {artistData?.name} @@ -144,7 +170,7 @@ const ArtistDetailsView = ({ artistId }: any) => { } - + {/* */} ); }; diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index ba4f42c..53700bf 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -124,7 +124,13 @@ const GenreDetailsView = ({ genreId }: any) => { size={'100%'} height={isMobileView ? 200 : 300} width={'100%'} - backgroundColor={colorRange[Math.floor(Math.random() * 5)]?.code ?? '#364fc7'} + // backgroundColor={colorRange[Math.floor(Math.random() * 5)]?.code ?? '#364fc7'} + bg={{ + linearGradient: { + colors: [colorRange[Math.floor(Math.random() * 5)]?.code ?? '#364fc7', 'black'], + start: [0, 0], + end: [0, 1], + },}} /> Date: Sat, 12 Aug 2023 10:43:02 +0200 Subject: [PATCH 08/28] basic genre details view --- front/API.ts | 20 ++++++++++++ front/i18n/Translations.ts | 3 ++ front/views/GenreDetailsView.tsx | 52 +------------------------------- 3 files changed, 24 insertions(+), 51 deletions(-) diff --git a/front/API.ts b/front/API.ts index 5e30e63..f3a893d 100644 --- a/front/API.ts +++ b/front/API.ts @@ -337,6 +337,16 @@ export default class API { return `${baseAPIUrl}/genre/${genreId}/illustration`; } + public static getGenre(genreId: number): Query { + return { + key: ['genre', genreId], + exec: () => + API.fetch({ + route: `/genre/${genreId}`, + }), + } + } + /** * Retrive a song's musicXML partition * @param songId the id to find the song @@ -490,6 +500,16 @@ export default class API { }; } + public static getFavorites(): Query { + return { + key: 'favorites', + exec: () => + API.fetch({ + route: '/search/songs/o', + }), + }; + } + /** * Retrieve the authenticated user's search history * @param skip number of entries skipped before returning diff --git a/front/i18n/Translations.ts b/front/i18n/Translations.ts index 014ed86..739c78d 100644 --- a/front/i18n/Translations.ts +++ b/front/i18n/Translations.ts @@ -42,6 +42,7 @@ export const en = { artistFilter: 'Artists', songsFilter: 'Songs', genreFilter: 'Genres', + favoriteFilter: 'Favorites', // profile page user: 'Profile', @@ -227,6 +228,7 @@ export const fr: typeof en = { artistFilter: 'Artistes', songsFilter: 'Morceaux', genreFilter: 'Genres', + favoriteFilter: 'Favoris', // Difficulty settings diffBtn: 'Difficulté', @@ -422,6 +424,7 @@ export const sp: typeof en = { artistFilter: 'Artistas', songsFilter: 'canciones', genreFilter: 'géneros', + favoriteFilter: 'Favorites', // Difficulty settings diffBtn: 'Dificultad', diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 53700bf..7e42e24 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -55,57 +55,8 @@ const rockArtists: Artist[] = [ }, ]; -const rockSongs: Song[] = [ - { - id: 1, - name: "Stairway to Heaven", - artistId: 1, - albumId: 1, - genreId: 1, - cover: "https://picsum.photos/200", - details: { /* song details */ }, - }, - { - id: 2, - name: "Bohemian Rhapsody", - artistId: 2, - albumId: 2, - genreId: 1, - cover: "https://picsum.photos/200", - details: { /* song details */ }, - }, - { - id: 3, - name: "Paint It Black", - artistId: 3, - albumId: 3, - genreId: 1, - cover: "https://picsum.photos/200", - details: { /* song details */ }, - }, - { - id: 4, - name: "Highway to Hell", - artistId: 4, - albumId: 4, - genreId: 1, - cover: "https://picsum.photos/200", - details: { /* song details */ }, - }, - { - id: 5, - name: "Sweet Child o' Mine", - artistId: 5, - albumId: 5, - genreId: 1, - cover: "https://picsum.photos/200", - details: { /* song details */ }, - }, - // Add more songs as needed - ]; - const GenreDetailsView = ({ genreId }: any) => { - // const { isLoading: isLoadingGenre, data: genreData, error: isErrorGenre } = useQuery(API.getArtist(genreId)); + const { isLoading: isLoadingGenre, data: genreData, error: isErrorGenre } = useQuery(API.getArtist(genreId)); const screenSize = useBreakpointValue({ base: "small", md: "big" }); const isMobileView = screenSize == "small"; const navigation = useNavigation(); @@ -124,7 +75,6 @@ const GenreDetailsView = ({ genreId }: any) => { size={'100%'} height={isMobileView ? 200 : 300} width={'100%'} - // backgroundColor={colorRange[Math.floor(Math.random() * 5)]?.code ?? '#364fc7'} bg={{ linearGradient: { colors: [colorRange[Math.floor(Math.random() * 5)]?.code ?? '#364fc7', 'black'], From 1255343b9774ebf51dedee9a5eaa11167077ba4b Mon Sep 17 00:00:00 2001 From: danis Date: Sat, 12 Aug 2023 11:16:22 +0200 Subject: [PATCH 09/28] artist view + moved components --- front/components/SearchBar.tsx | 9 +- front/components/SearchResult.tsx | 156 ++++++++++++++++++------------ front/components/SongRow.tsx | 14 ++- front/views/ArtistDetailsView.tsx | 54 +++++------ front/views/SearchView.tsx | 12 ++- 5 files changed, 146 insertions(+), 99 deletions(-) diff --git a/front/components/SearchBar.tsx b/front/components/SearchBar.tsx index b04cc97..9bb568e 100644 --- a/front/components/SearchBar.tsx +++ b/front/components/SearchBar.tsx @@ -5,7 +5,7 @@ import { translate } from '../i18n/i18n'; import { SearchContext } from '../views/SearchView'; import { debounce } from 'lodash'; -export type Filter = 'artist' | 'song' | 'genre' | 'all'; +export type Filter = 'artist' | 'song' | 'genre' | 'all' | 'favorite'; type FilterButton = { name: string; @@ -16,7 +16,7 @@ type FilterButton = { const SearchBar = () => { const { filter, updateFilter } = React.useContext(SearchContext); const { stringQuery, updateStringQuery } = React.useContext(SearchContext); - const [barText, updateBarText] = React.useState(stringQuery); + const [ barText, updateBarText ] = React.useState(stringQuery); const debouncedUpdateStringQuery = debounce(updateStringQuery, 500); @@ -42,6 +42,11 @@ const SearchBar = () => { callback: () => updateFilter('all'), id: 'all', }, + { + name: translate('favoriteFilter'), + callback: () => updateFilter('favorite'), + id: 'favorite', + }, { name: translate('artistFilter'), callback: () => updateFilter('artist'), diff --git a/front/components/SearchResult.tsx b/front/components/SearchResult.tsx index aab02bf..8dd037c 100644 --- a/front/components/SearchResult.tsx +++ b/front/components/SearchResult.tsx @@ -29,6 +29,8 @@ import SearchHistoryCard from './HistoryCard'; import Song, { SongWithArtist } from '../models/Song'; import { useNavigation } from '../Navigation'; import Artist from '../models/Artist'; +import SongRow from '../components/SongRow'; + const swaToSongCardProps = (song: SongWithArtist) => ({ songId: song.id, @@ -66,67 +68,67 @@ const RowCustom = (props: Parameters[0] & { onPress?: () => void }) ); }; -type SongRowProps = { - song: Song | SongWithArtist; // TODO: remove Song - onPress: () => void; -}; +// type SongRowProps = { +// song: Song | SongWithArtist; // TODO: remove Song +// onPress: () => void; +// }; -const SongRow = ({ song, onPress }: SongRowProps) => { - return ( - - - {song.name} - - - {song.name} - - - {song.artistId ?? 'artist'} - - - - - - ); -}; +// const SongRow = ({ song, onPress }: SongRowProps) => { +// return ( +// +// +// {song.name} +// +// +// {song.name} +// +// +// {song.artistId ?? 'artist'} +// +// +// +// +// +// ); +// }; SongRow.defaultProps = { onPress: () => {}, @@ -299,6 +301,35 @@ const GenreSearchComponent = (props: ItemSearchComponentProps) => { ); }; +const FavoriteSearchComponent = (props: SongsSearchComponentProps) => { + const { favoriteData } = React.useContext(SearchContext); + const navigation = useNavigation(); + + return ( + + + {translate('favoriteFilter')} + + + {favoriteData?.length ? ( + favoriteData.slice(0, props.maxRows).map((comp, index) => ( + { + API.createSearchHistoryEntry(comp.name, 'song'); + navigation.navigate('Song', { songId: comp.id }); + }} + /> + )) + ) : ( + {translate('errNoResults')} + )} + + + ) +} + const AllComponent = () => { const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); const isMobileView = screenSize == 'small'; @@ -344,6 +375,8 @@ const FilterSwitch = () => { return ; case 'genre': return ; + case 'favorite': + return ; default: return Something very bad happened: {currentFilter}; } @@ -351,7 +384,8 @@ const FilterSwitch = () => { export const SearchResultComponent = () => { const { stringQuery } = React.useContext(SearchContext); - const shouldOutput = !!stringQuery.trim(); + const { filter } = React.useContext(SearchContext); + const shouldOutput = !!stringQuery.trim() || filter == "favorite"; return shouldOutput ? ( diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index bc2dff2..17b60c0 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -1,15 +1,21 @@ -import { HStack, Image, Text } from "native-base"; +import { HStack, IconButton, Image, Text } from "native-base"; import Song, { SongWithArtist } from "../models/Song"; import RowCustom from "./RowCustom"; import TextButton from "./TextButton"; +import { MaterialIcons } from "@expo/vector-icons"; +import API from "../API"; type SongRowProps = { + liked: boolean; song: Song | SongWithArtist; // TODO: remove Song onPress: () => void; }; -const SongRow = ({ song, onPress }: SongRowProps) => { +const handleLikeButton = { +} + +const SongRow = ({ song, onPress, liked }: SongRowProps) => { return ( @@ -23,6 +29,10 @@ const SongRow = ({ song, onPress }: SongRowProps) => { borderColor={'white'} borderWidth={1} /> + { return ( - - - {/* - {artistData?.name} */} - - {artistData?.name} - - {songs.map((comp: Song | SongWithArtist, index: Key | null | undefined) => ( - { - API.createSearchHistoryEntry(comp.name, "song", Date.now()); - navigation.navigate("Song", { songId: comp.id }); - }} - /> - )) - } - - - {/* */} + style={{width : '100%', height: isMobileView ? 200 : 300}} + source={{uri : "https://picsum.photos/720"}}> + + + + {artistData?.name} + + {songs.map((comp: Song | SongWithArtist, index: Key | null | undefined) => ( + { + API.createSearchHistoryEntry(comp.name, "song", Date.now()); + navigation.navigate("Song", { songId: comp.id }); + }} + /> + )) + } + + ); }; diff --git a/front/views/SearchView.tsx b/front/views/SearchView.tsx index 108ff54..5c10e0e 100644 --- a/front/views/SearchView.tsx +++ b/front/views/SearchView.tsx @@ -12,13 +12,14 @@ import { ScrollView } from 'native-base'; import { RouteProps } from '../Navigation'; interface SearchContextType { - filter: 'artist' | 'song' | 'genre' | 'all'; - updateFilter: (newData: 'artist' | 'song' | 'genre' | 'all') => void; + filter: 'artist' | 'song' | 'genre' | 'all' | 'favorite'; + updateFilter: (newData: 'artist' | 'song' | 'genre' | 'all' | 'favorite') => void; stringQuery: string; updateStringQuery: (newData: string) => void; songData: Song[]; artistData: Artist[]; genreData: Genre[]; + favoriteData: Song[]; isLoadingSong: boolean; isLoadingArtist: boolean; isLoadingGenre: boolean; @@ -32,6 +33,7 @@ export const SearchContext = React.createContext({ songData: [], artistData: [], genreData: [], + favoriteData: [], isLoadingSong: false, isLoadingArtist: false, isLoadingGenre: false, @@ -60,6 +62,11 @@ const SearchView = (props: RouteProps) => { { enabled: !!stringQuery } ); + const { isLoading: isLoadingFavorite, data: favoriteData = [] } = useQuery( + API.getFavorites(), + { enabled: true } + ) + const updateFilter = (newData: Filter) => { // called when the filter is changed setFilter(newData); @@ -80,6 +87,7 @@ const SearchView = (props: RouteProps) => { songData, artistData, genreData, + favoriteData, isLoadingSong, isLoadingArtist, isLoadingGenre, From 1396fcb39c304784707c72a2b5ec9839c317ac95 Mon Sep 17 00:00:00 2001 From: danis Date: Mon, 4 Sep 2023 11:05:33 +0200 Subject: [PATCH 10/28] artist name fix --- front/views/ArtistDetailsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 3bc9a4b..56f3c06 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -39,7 +39,7 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => resizeMode="cover" /> - Abba + {artistQuery.data.name} {songsQuery.data.map((comp: Song, index: Key | null | undefined) => ( Date: Tue, 5 Sep 2023 09:33:31 +0200 Subject: [PATCH 11/28] actual data from db tho needs better design care --- back/src/song/song.controller.ts | 6 -- front/API.ts | 43 +++++++++++--- front/views/GenreDetailsView.tsx | 97 ++++++++++++-------------------- front/views/SearchView.tsx | 14 ++--- 4 files changed, 78 insertions(+), 82 deletions(-) diff --git a/back/src/song/song.controller.ts b/back/src/song/song.controller.ts index be725ed..a80a31b 100644 --- a/back/src/song/song.controller.ts +++ b/back/src/song/song.controller.ts @@ -146,10 +146,4 @@ export class SongController { songId: id, }); } - - @Get('/artist/:artistId') - async getSongByArtist(@Param('artistId', ParseIntPipe) artistId: number) { - const res = await this.songService.songByArtist(artistId) - return res; - } } diff --git a/front/API.ts b/front/API.ts index 25dd3dc..35c413c 100644 --- a/front/API.ts +++ b/front/API.ts @@ -297,6 +297,24 @@ export default class API { }; } + /** + * Retrieves all songs corresponding to the given genre ID + * @param genreId the id of the genre we're aiming + * @returns a promise of an array of Songs + */ + public static getSongsByGenre(genreId: number): Query { + return { + key: ['genre', genreId, 'songs'], + exec: () => + API.fetch( + { + route: `/song?genreId=${genreId}`, + }, + { handler: PlageHandler(SongHandler) } + ).then(({ data }) => data), + }; + } + /** * Retrive a song's midi partition * @param songId the id to find the song @@ -332,15 +350,22 @@ export default class API { return `${API.baseUrl}/genre/${genreId}/illustration`; } - // public static getGenre(genreId: number): Query { - // return { - // key: ['genre', genreId], - // exec: () => - // API.fetch({ - // route: `/genre/${genreId}`, - // }), - // } - // } + /** + * Retrieves a genre + * @param genreId the id of the aimed genre + */ + public static getGenre(genreId: number): Query { + return { + key: ['genre', genreId], + exec: () => + API.fetch( + { + route: `/genre/${genreId}`, + }, + { handler: GenreHandler } + ), + }; + } /** * Retrive a song's musicXML partition diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 7e42e24..1b62caa 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -2,72 +2,52 @@ import { SafeAreaView } from 'react-native'; import { VStack, Text, Box, Flex, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue, ScrollView } from 'native-base'; import { useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; -import { useNavigation } from '../Navigation'; +import { RouteProps, useNavigation } from '../Navigation'; import API from '../API'; import Artist from '../models/Artist'; import ArtistCard from '../components/ArtistCard'; import CardGridCustom from '../components/CardGridCustom'; import { translate } from '../i18n/i18n'; -const colorRange = [ - { - code: '#364fc7', - }, - { - code: '#5c940d', - }, - { - code: '#c92a2a', - }, - { - code: '#d6336c', - }, - { - code: '#20c997' - } -] +const colorRange = ['#364fc7', '#5c940d', '#c92a2a', '#d6336c', '#20c997']; +// { +// code: '#364fc7', +// }, +// { +// code: '#5c940d', +// }, +// { +// code: '#c92a2a', +// }, +// { +// code: '#d6336c', +// }, +// { +// code: '#20c997' +// } +// ] -const rockArtists: Artist[] = [ - { - id: 1, - name: "Led Zeppelin", - picture: "https://picsum.photos/200", - }, - { - id: 2, - name: "Queen", - picture: "https://picsum.photos/200", - }, - { - id: 3, - name: "The Rolling Stones", - picture: "https://picsum.photos/200", - }, - { - id: 4, - name: "AC/DC", - picture: "https://picsum.photos/200", - }, - { - name: "Guns N' Roses", - id: 5, - picture: "https://picsum.photos/200", - }, -]; +type GenreDetailsViewProps = { + genreId: number; +} -const GenreDetailsView = ({ genreId }: any) => { - const { isLoading: isLoadingGenre, data: genreData, error: isErrorGenre } = useQuery(API.getArtist(genreId)); +const rockArtists: any[] = []; + +const GenreDetailsView = ({ genreId }: RouteProps) => { + // const { isLoading: isLoadingGenre, data: genreData, error: isErrorGenre } = useQuery(API.getArtist(genreId)); + const genreQuery = useQuery(API.getGenre(genreId)) + const songsQuery = useQuery(API.getSongsByGenre(genreId)) const screenSize = useBreakpointValue({ base: "small", md: "big" }); const isMobileView = screenSize == "small"; const navigation = useNavigation(); - // if (isLoadingGenre) { - // return ; - // } - - // if (isErrorGenre) { - // navigation.navigate('Error'); - // } + if (genreQuery.isError || songsQuery.isError) { + navigation.navigate('Error'); + return <>; + } + if (!genreQuery.data || songsQuery.data === undefined) { + return ; + } return ( @@ -77,11 +57,12 @@ const GenreDetailsView = ({ genreId }: any) => { width={'100%'} bg={{ linearGradient: { - colors: [colorRange[Math.floor(Math.random() * 5)]?.code ?? '#364fc7', 'black'], + colors: [colorRange[Math.floor(Math.random() * 5)] ?? '#364fc7', 'black'], start: [0, 0], end: [0, 1], },}} /> + {genreQuery.data.name} { mt={4} > - {rockArtists?.length ? ( ({ + content={songsQuery.data.slice(0, songsQuery.data.length).map((artistData) => ({ image: API.getArtistIllustration(artistData.id), name: artistData.name, id: artistData.id, @@ -102,9 +82,6 @@ const GenreDetailsView = ({ genreId }: any) => { }))} cardComponent={ArtistCard} /> - ) : ( - {translate('errNoResults')} - )} diff --git a/front/views/SearchView.tsx b/front/views/SearchView.tsx index 5c10e0e..b3b84bf 100644 --- a/front/views/SearchView.tsx +++ b/front/views/SearchView.tsx @@ -19,7 +19,7 @@ interface SearchContextType { songData: Song[]; artistData: Artist[]; genreData: Genre[]; - favoriteData: Song[]; + // favoriteData: Song[]; isLoadingSong: boolean; isLoadingArtist: boolean; isLoadingGenre: boolean; @@ -33,7 +33,7 @@ export const SearchContext = React.createContext({ songData: [], artistData: [], genreData: [], - favoriteData: [], + // favoriteData: [], isLoadingSong: false, isLoadingArtist: false, isLoadingGenre: false, @@ -62,10 +62,10 @@ const SearchView = (props: RouteProps) => { { enabled: !!stringQuery } ); - const { isLoading: isLoadingFavorite, data: favoriteData = [] } = useQuery( - API.getFavorites(), - { enabled: true } - ) + // const { isLoading: isLoadingFavorite, data: favoriteData = [] } = useQuery( + // API.getFavorites(), + // { enabled: true } + // ) const updateFilter = (newData: Filter) => { // called when the filter is changed @@ -87,7 +87,7 @@ const SearchView = (props: RouteProps) => { songData, artistData, genreData, - favoriteData, + // favoriteData, isLoadingSong, isLoadingArtist, isLoadingGenre, From 539c35c90364884a1741d9202cf50a9fb12c0bd5 Mon Sep 17 00:00:00 2001 From: danis Date: Tue, 5 Sep 2023 09:36:11 +0200 Subject: [PATCH 12/28] song cards routing fix --- front/views/GenreDetailsView.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 1b62caa..e7bf15a 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -71,13 +71,13 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { > ({ - image: API.getArtistIllustration(artistData.id), - name: artistData.name, - id: artistData.id, + content={songsQuery.data.slice(0, songsQuery.data.length).map((songData) => ({ + image: API.getArtistIllustration(songData.id), + name: songData.name, + id: songData.id, onPress: () => { - API.createSearchHistoryEntry(artistData.name, 'artist'); - navigation.navigate('Artist', { artistId: artistData.id }); + API.createSearchHistoryEntry(songData.name, 'artist'); + navigation.navigate('Song', { songId: songData.id }); }, }))} cardComponent={ArtistCard} From c9d3ef88e7ecb22da79f8da121079e4cefca9391 Mon Sep 17 00:00:00 2001 From: danis Date: Tue, 5 Sep 2023 13:44:30 +0200 Subject: [PATCH 13/28] clean code + search history handler fix --- front/models/SearchHistory.ts | 2 +- front/views/GenreDetailsView.tsx | 24 ------------------------ 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/front/models/SearchHistory.ts b/front/models/SearchHistory.ts index 05c433b..779be6c 100644 --- a/front/models/SearchHistory.ts +++ b/front/models/SearchHistory.ts @@ -2,7 +2,7 @@ import Model, { ModelValidator } from './Model'; import * as yup from 'yup'; import ResponseHandler from './ResponseHandler'; -export const SearchType = ['song', 'artist', 'album'] as const; +export const SearchType = ['song', 'artist', 'album', 'genre'] as const; export type SearchType = (typeof SearchType)[number]; const SearchHistoryValidator = yup diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index e7bf15a..694b129 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -10,31 +10,12 @@ import CardGridCustom from '../components/CardGridCustom'; import { translate } from '../i18n/i18n'; const colorRange = ['#364fc7', '#5c940d', '#c92a2a', '#d6336c', '#20c997']; -// { -// code: '#364fc7', -// }, -// { -// code: '#5c940d', -// }, -// { -// code: '#c92a2a', -// }, -// { -// code: '#d6336c', -// }, -// { -// code: '#20c997' -// } -// ] type GenreDetailsViewProps = { genreId: number; } -const rockArtists: any[] = []; - const GenreDetailsView = ({ genreId }: RouteProps) => { - // const { isLoading: isLoadingGenre, data: genreData, error: isErrorGenre } = useQuery(API.getArtist(genreId)); const genreQuery = useQuery(API.getGenre(genreId)) const songsQuery = useQuery(API.getSongsByGenre(genreId)) const screenSize = useBreakpointValue({ base: "small", md: "big" }); @@ -69,7 +50,6 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { justifyContent={['flex-start']} mt={4} > - ({ image: API.getArtistIllustration(songData.id), @@ -82,10 +62,6 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { }))} cardComponent={ArtistCard} /> - - - - ); From 2f50f694f371794ca3d6662560f4e91752715f65 Mon Sep 17 00:00:00 2001 From: danis Date: Wed, 6 Sep 2023 15:57:38 +0200 Subject: [PATCH 14/28] clean code --- front/views/GenreDetailsView.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 694b129..f206199 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -1,6 +1,6 @@ import { SafeAreaView } from 'react-native'; import { VStack, Text, Box, Flex, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue, ScrollView } from 'native-base'; -import { useQuery } from '../Queries'; +import { useQueries, useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import { RouteProps, useNavigation } from '../Navigation'; import API from '../API'; @@ -8,6 +8,7 @@ import Artist from '../models/Artist'; import ArtistCard from '../components/ArtistCard'; import CardGridCustom from '../components/CardGridCustom'; import { translate } from '../i18n/i18n'; +import SongCard from '../components/SongCard'; const colorRange = ['#364fc7', '#5c940d', '#c92a2a', '#d6336c', '#20c997']; @@ -22,6 +23,7 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { const isMobileView = screenSize == "small"; const navigation = useNavigation(); + if (genreQuery.isError || songsQuery.isError) { navigation.navigate('Error'); return <>; @@ -51,16 +53,17 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { mt={4} > ({ - image: API.getArtistIllustration(songData.id), + content={songsQuery.data.map((songData) => ({ name: songData.name, - id: songData.id, + cover: songData.cover, + artistName: songData.artistId.toString(), + songId: songData.id, onPress: () => { - API.createSearchHistoryEntry(songData.name, 'artist'); + API.createSearchHistoryEntry(songData.name, 'song'); navigation.navigate('Song', { songId: songData.id }); }, }))} - cardComponent={ArtistCard} + cardComponent={SongCard} /> From 7e866f98269233c18c8e109f5241c51dbe18e496 Mon Sep 17 00:00:00 2001 From: danis Date: Wed, 6 Sep 2023 15:59:50 +0200 Subject: [PATCH 15/28] clean code III --- front/views/ArtistDetailsView.tsx | 5 +---- front/views/GenreDetailsView.tsx | 7 +------ 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 3fc9dbf..442e86f 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -1,7 +1,4 @@ -import { VStack, Text, Box, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue, ScrollView } from 'native-base'; -import { Ionicons } from '@expo/vector-icons'; -// import { Box, Image, Heading, useBreakpointValue } from 'native-base'; -import { SafeAreaView } from 'react-native'; +import { Box, Heading, useBreakpointValue, ScrollView } from 'native-base'; import { useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import API from '../API'; diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index f206199..aaea0be 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -1,13 +1,9 @@ -import { SafeAreaView } from 'react-native'; -import { VStack, Text, Box, Flex, Image, Heading, IconButton, Icon, Container, Center, useBreakpointValue, ScrollView } from 'native-base'; +import { Box, Flex, Heading, useBreakpointValue, ScrollView } from 'native-base'; import { useQueries, useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import { RouteProps, useNavigation } from '../Navigation'; import API from '../API'; -import Artist from '../models/Artist'; -import ArtistCard from '../components/ArtistCard'; import CardGridCustom from '../components/CardGridCustom'; -import { translate } from '../i18n/i18n'; import SongCard from '../components/SongCard'; const colorRange = ['#364fc7', '#5c940d', '#c92a2a', '#d6336c', '#20c997']; @@ -23,7 +19,6 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { const isMobileView = screenSize == "small"; const navigation = useNavigation(); - if (genreQuery.isError || songsQuery.isError) { navigation.navigate('Error'); return <>; From 852fbd5c8711c2466107231ad06aeedad0f8dbd7 Mon Sep 17 00:00:00 2001 From: danis Date: Wed, 6 Sep 2023 16:39:38 +0200 Subject: [PATCH 16/28] clean code IV --- front/views/SearchView.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/front/views/SearchView.tsx b/front/views/SearchView.tsx index b3b84bf..1de10fb 100644 --- a/front/views/SearchView.tsx +++ b/front/views/SearchView.tsx @@ -19,7 +19,6 @@ interface SearchContextType { songData: Song[]; artistData: Artist[]; genreData: Genre[]; - // favoriteData: Song[]; isLoadingSong: boolean; isLoadingArtist: boolean; isLoadingGenre: boolean; @@ -33,7 +32,6 @@ export const SearchContext = React.createContext({ songData: [], artistData: [], genreData: [], - // favoriteData: [], isLoadingSong: false, isLoadingArtist: false, isLoadingGenre: false, @@ -62,11 +60,6 @@ const SearchView = (props: RouteProps) => { { enabled: !!stringQuery } ); - // const { isLoading: isLoadingFavorite, data: favoriteData = [] } = useQuery( - // API.getFavorites(), - // { enabled: true } - // ) - const updateFilter = (newData: Filter) => { // called when the filter is changed setFilter(newData); @@ -87,7 +80,6 @@ const SearchView = (props: RouteProps) => { songData, artistData, genreData, - // favoriteData, isLoadingSong, isLoadingArtist, isLoadingGenre, From 6da96ed886f760d6c1ccb7792ea7798d220fb4ac Mon Sep 17 00:00:00 2001 From: danis Date: Wed, 6 Sep 2023 17:00:36 +0200 Subject: [PATCH 17/28] clean code V --- front/components/SearchBar.tsx | 5 -- front/components/SearchResult.tsx | 126 ------------------------------ front/components/SongRow.tsx | 11 +-- 3 files changed, 1 insertion(+), 141 deletions(-) diff --git a/front/components/SearchBar.tsx b/front/components/SearchBar.tsx index 9bb568e..3ef7d71 100644 --- a/front/components/SearchBar.tsx +++ b/front/components/SearchBar.tsx @@ -42,11 +42,6 @@ const SearchBar = () => { callback: () => updateFilter('all'), id: 'all', }, - { - name: translate('favoriteFilter'), - callback: () => updateFilter('favorite'), - id: 'favorite', - }, { name: translate('artistFilter'), callback: () => updateFilter('artist'), diff --git a/front/components/SearchResult.tsx b/front/components/SearchResult.tsx index 8dd037c..42d031a 100644 --- a/front/components/SearchResult.tsx +++ b/front/components/SearchResult.tsx @@ -39,101 +39,6 @@ const swaToSongCardProps = (song: SongWithArtist) => ({ cover: song.cover ?? 'https://picsum.photos/200', }); -const RowCustom = (props: Parameters[0] & { onPress?: () => void }) => { - const settings = useSelector((state: RootState) => state.settings.local); - const systemColorMode = useColorScheme(); - const colorScheme = settings.colorScheme; - - return ( - - {({ isHovered, isPressed }) => ( - - {props.children} - - )} - - ); -}; - -// type SongRowProps = { -// song: Song | SongWithArtist; // TODO: remove Song -// onPress: () => void; -// }; - -// const SongRow = ({ song, onPress }: SongRowProps) => { -// return ( -// -// -// {song.name} -// -// -// {song.name} -// -// -// {song.artistId ?? 'artist'} -// -// -// -// -// -// ); -// }; - -SongRow.defaultProps = { - onPress: () => {}, -}; - const HomeSearchComponent = () => { const { updateStringQuery } = React.useContext(SearchContext); const { isLoading: isLoadingHistory, data: historyData = [] } = useQuery( @@ -301,35 +206,6 @@ const GenreSearchComponent = (props: ItemSearchComponentProps) => { ); }; -const FavoriteSearchComponent = (props: SongsSearchComponentProps) => { - const { favoriteData } = React.useContext(SearchContext); - const navigation = useNavigation(); - - return ( - - - {translate('favoriteFilter')} - - - {favoriteData?.length ? ( - favoriteData.slice(0, props.maxRows).map((comp, index) => ( - { - API.createSearchHistoryEntry(comp.name, 'song'); - navigation.navigate('Song', { songId: comp.id }); - }} - /> - )) - ) : ( - {translate('errNoResults')} - )} - - - ) -} - const AllComponent = () => { const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); const isMobileView = screenSize == 'small'; @@ -375,8 +251,6 @@ const FilterSwitch = () => { return ; case 'genre': return ; - case 'favorite': - return ; default: return Something very bad happened: {currentFilter}; } diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index 57d1746..5ac3189 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -3,18 +3,13 @@ import Song, { SongWithArtist } from "../models/Song"; import RowCustom from "./RowCustom"; import TextButton from "./TextButton"; import { MaterialIcons } from "@expo/vector-icons"; -import API from "../API"; type SongRowProps = { - liked: boolean; song: Song | SongWithArtist; // TODO: remove Song onPress: () => void; }; -const handleLikeButton = { -} - -const SongRow = ({ song, onPress, liked }: SongRowProps) => { +const SongRow = ({ song, onPress }: SongRowProps) => { return ( @@ -28,10 +23,6 @@ const SongRow = ({ song, onPress, liked }: SongRowProps) => { borderColor={'white'} borderWidth={1} /> - Date: Wed, 6 Sep 2023 17:07:16 +0200 Subject: [PATCH 18/28] clean code VI --- front/views/ArtistDetailsView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 442e86f..7d2dae9 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -45,7 +45,6 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => { API.createSearchHistoryEntry(comp.name, 'song'); navigation.navigate('Song', { songId: comp.id }); From 16cd794e3b10271d83b60d1a1e33c5105900d1c8 Mon Sep 17 00:00:00 2001 From: danis Date: Thu, 7 Sep 2023 10:31:03 +0200 Subject: [PATCH 19/28] trial for artist name --- front/views/GenreDetailsView.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index aaea0be..9d75337 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -15,6 +15,12 @@ type GenreDetailsViewProps = { const GenreDetailsView = ({ genreId }: RouteProps) => { const genreQuery = useQuery(API.getGenre(genreId)) const songsQuery = useQuery(API.getSongsByGenre(genreId)) + const artistQueries = useQueries(songsQuery.data.map((song) => song.artistId).map((artistId) => API.getArtist(artistId))); + const songWithArtist = songsQuery.data.map((song) => ({ + ...song, + artist: artistQueries.find((query) => query.data.id == song.artistId) + })).filter((song) => song.artist !== undefined); + const screenSize = useBreakpointValue({ base: "small", md: "big" }); const isMobileView = screenSize == "small"; const navigation = useNavigation(); @@ -48,10 +54,10 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { mt={4} > ({ + content={songWithArtist.map((songData) => ({ name: songData.name, cover: songData.cover, - artistName: songData.artistId.toString(), + artistName: songData.artist.name, songId: songData.id, onPress: () => { API.createSearchHistoryEntry(songData.name, 'song'); From b1d0415ba00cdeec175af4a4e4742df7a7c73322 Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Thu, 7 Sep 2023 17:10:18 +0200 Subject: [PATCH 20/28] Front: Fix genre view --- front/views/GenreDetailsView.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 9d75337..a0ff410 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -15,10 +15,11 @@ type GenreDetailsViewProps = { const GenreDetailsView = ({ genreId }: RouteProps) => { const genreQuery = useQuery(API.getGenre(genreId)) const songsQuery = useQuery(API.getSongsByGenre(genreId)) - const artistQueries = useQueries(songsQuery.data.map((song) => song.artistId).map((artistId) => API.getArtist(artistId))); - const songWithArtist = songsQuery.data.map((song) => ({ + const artistQueries = useQueries(songsQuery.data?.map((song) => song.artistId).map((artistId) => API.getArtist(artistId)) ?? []); + // Here, .artist will always be defined + const songWithArtist = songsQuery?.data?.map((song) => ({ ...song, - artist: artistQueries.find((query) => query.data.id == song.artistId) + artist: artistQueries.find((query) => query.data?.id == song.artistId)?.data })).filter((song) => song.artist !== undefined); const screenSize = useBreakpointValue({ base: "small", md: "big" }); @@ -29,7 +30,7 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { navigation.navigate('Error'); return <>; } - if (!genreQuery.data || songsQuery.data === undefined) { + if (!genreQuery.data || songsQuery.data === undefined || songWithArtist === undefined) { return ; } @@ -57,7 +58,7 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { content={songWithArtist.map((songData) => ({ name: songData.name, cover: songData.cover, - artistName: songData.artist.name, + artistName: songData.artist!.name, songId: songData.id, onPress: () => { API.createSearchHistoryEntry(songData.name, 'song'); From b61968706dfd9f06455e87d30aded29f991be48d Mon Sep 17 00:00:00 2001 From: danis Date: Sat, 9 Sep 2023 14:25:03 +0200 Subject: [PATCH 21/28] fix PR I --- front/API.ts | 10 ---------- front/Theme.tsx | 12 ++++++------ front/components/SearchBar.tsx | 2 +- front/components/SearchResult.tsx | 2 +- front/views/ArtistDetailsView.tsx | 7 ++++--- front/views/GenreDetailsView.tsx | 5 +++-- 6 files changed, 15 insertions(+), 23 deletions(-) diff --git a/front/API.ts b/front/API.ts index 4ef5531..54ac0e5 100644 --- a/front/API.ts +++ b/front/API.ts @@ -542,16 +542,6 @@ export default class API { }; } - // public static getFavorites(): Query { - // return { - // key: 'favorites', - // exec: () => - // API.fetch({ - // route: '/search/songs/o', - // }), - // }; - // } - /** * Retrieve the authenticated user's search history * @param skip number of entries skipped before returning diff --git a/front/Theme.tsx b/front/Theme.tsx index 9c19074..b6e61ed 100644 --- a/front/Theme.tsx +++ b/front/Theme.tsx @@ -4,15 +4,15 @@ import { useEffect } from 'react'; const ThemeProvider = ({ children }: { children: JSX.Element }) => { const colorScheme = useColorScheme(); - const config = { - dependencies: { - "linear-gradient": require("expo-linear-gradient").LinearGradient, - }, - }; + const config = { + dependencies: { + "linear-gradient": require("expo-linear-gradient").LinearGradient, + }, + }; return ( { export const SearchResultComponent = () => { const { stringQuery } = React.useContext(SearchContext); const { filter } = React.useContext(SearchContext); - const shouldOutput = !!stringQuery.trim() || filter == "favorite"; + const shouldOutput = !!stringQuery.trim(); return shouldOutput ? ( diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 7d2dae9..a3ddfb7 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -1,4 +1,4 @@ -import { Box, Heading, useBreakpointValue, ScrollView } from 'native-base'; +import { Box, Heading, useBreakpointValue, ScrollView, useColorModeValue } from 'native-base'; import { useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import API from '../API'; @@ -17,6 +17,7 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => const artistQuery = useQuery(API.getArtist(artistId)); const songsQuery = useQuery(API.getSongsByArtist(artistId)); const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); + const fadeColor = useColorModeValue('#ffffff', '#000000'); const isMobileView = screenSize == 'small'; const navigation = useNavigation(); @@ -32,9 +33,9 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => + source={{uri : API.getArtistIllustration(artistQuery.data.id)}}> diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index a0ff410..5dd6e52 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -1,4 +1,4 @@ -import { Box, Flex, Heading, useBreakpointValue, ScrollView } from 'native-base'; +import { Box, Flex, Heading, useBreakpointValue, ScrollView, useColorModeValue } from 'native-base'; import { useQueries, useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import { RouteProps, useNavigation } from '../Navigation'; @@ -24,6 +24,7 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { const screenSize = useBreakpointValue({ base: "small", md: "big" }); const isMobileView = screenSize == "small"; + const fadeColor = useColorModeValue('#ffffff', '#000000'); const navigation = useNavigation(); if (genreQuery.isError || songsQuery.isError) { @@ -42,7 +43,7 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { width={'100%'} bg={{ linearGradient: { - colors: [colorRange[Math.floor(Math.random() * 5)] ?? '#364fc7', 'black'], + colors: [colorRange[Math.floor(Math.random() * 5)] ?? '#364fc7', fadeColor], start: [0, 0], end: [0, 1], },}} From 3ff523560b8897b7653ecc67e44fcfd0de2729fc Mon Sep 17 00:00:00 2001 From: danis Date: Sat, 9 Sep 2023 17:51:18 +0200 Subject: [PATCH 22/28] fix PR II --- front/views/ArtistDetailsView.tsx | 2 +- front/views/GenreDetailsView.tsx | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index a3ddfb7..eae2ee4 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -59,4 +59,4 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => ); }; -export default ArtistDetailsView; +export default ArtistDetailsView; \ No newline at end of file diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 5dd6e52..df3655b 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -5,8 +5,8 @@ import { RouteProps, useNavigation } from '../Navigation'; import API from '../API'; import CardGridCustom from '../components/CardGridCustom'; import SongCard from '../components/SongCard'; - -const colorRange = ['#364fc7', '#5c940d', '#c92a2a', '#d6336c', '#20c997']; +import { ImageBackground } from 'react-native'; +import { LinearGradient } from 'expo-linear-gradient'; type GenreDetailsViewProps = { genreId: number; @@ -37,17 +37,13 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { return ( - + + + {genreQuery.data.name} Date: Sat, 9 Sep 2023 17:52:22 +0200 Subject: [PATCH 23/28] fix PR III --- front/views/SearchView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/front/views/SearchView.tsx b/front/views/SearchView.tsx index 1de10fb..108ff54 100644 --- a/front/views/SearchView.tsx +++ b/front/views/SearchView.tsx @@ -12,8 +12,8 @@ import { ScrollView } from 'native-base'; import { RouteProps } from '../Navigation'; interface SearchContextType { - filter: 'artist' | 'song' | 'genre' | 'all' | 'favorite'; - updateFilter: (newData: 'artist' | 'song' | 'genre' | 'all' | 'favorite') => void; + filter: 'artist' | 'song' | 'genre' | 'all'; + updateFilter: (newData: 'artist' | 'song' | 'genre' | 'all') => void; stringQuery: string; updateStringQuery: (newData: string) => void; songData: Song[]; From a6d9cb3b409fb79667b8f0a505a75f8e7e9b47d2 Mon Sep 17 00:00:00 2001 From: danis Date: Sat, 9 Sep 2023 18:55:32 +0200 Subject: [PATCH 24/28] run prettier --- front/Navigation.tsx | 2 +- front/Theme.tsx | 2 +- front/components/SearchBar.tsx | 2 +- front/components/SearchResult.tsx | 23 +++++++++-------- front/components/SongRow.tsx | 10 +++---- front/i18n/Translations.ts | 6 ++--- front/views/ArtistDetailsView.tsx | 16 +++++++----- front/views/GenreDetailsView.tsx | 43 +++++++++++++++++++------------ 8 files changed, 59 insertions(+), 45 deletions(-) diff --git a/front/Navigation.tsx b/front/Navigation.tsx index f5fc58b..1e12973 100644 --- a/front/Navigation.tsx +++ b/front/Navigation.tsx @@ -62,7 +62,7 @@ const protectedRoutes = () => }, Genre: { component: GenreDetailsView, - options: { title: translate('genreFilter')}, + options: { title: translate('genreFilter') }, link: '/genre/:genreId', }, Score: { diff --git a/front/Theme.tsx b/front/Theme.tsx index b6e61ed..ab23d2d 100644 --- a/front/Theme.tsx +++ b/front/Theme.tsx @@ -6,7 +6,7 @@ const ThemeProvider = ({ children }: { children: JSX.Element }) => { const colorScheme = useColorScheme(); const config = { dependencies: { - "linear-gradient": require("expo-linear-gradient").LinearGradient, + 'linear-gradient': require('expo-linear-gradient').LinearGradient, }, }; diff --git a/front/components/SearchBar.tsx b/front/components/SearchBar.tsx index dc70c58..b04cc97 100644 --- a/front/components/SearchBar.tsx +++ b/front/components/SearchBar.tsx @@ -16,7 +16,7 @@ type FilterButton = { const SearchBar = () => { const { filter, updateFilter } = React.useContext(SearchContext); const { stringQuery, updateStringQuery } = React.useContext(SearchContext); - const [ barText, updateBarText ] = React.useState(stringQuery); + const [barText, updateBarText] = React.useState(stringQuery); const debouncedUpdateStringQuery = debounce(updateStringQuery, 500); diff --git a/front/components/SearchResult.tsx b/front/components/SearchResult.tsx index 962d916..85e371f 100644 --- a/front/components/SearchResult.tsx +++ b/front/components/SearchResult.tsx @@ -31,7 +31,6 @@ import { useNavigation } from '../Navigation'; import Artist from '../models/Artist'; import SongRow from '../components/SongRow'; - const swaToSongCardProps = (song: SongWithArtist) => ({ songId: song.id, name: song.name, @@ -159,15 +158,17 @@ const ArtistSearchComponent = (props: ItemSearchComponentProps) => { {artistData?.length ? ( ({ - image: API.getArtistIllustration(artistData.id), - name: artistData.name, - id: artistData.id, - onPress: () => { - API.createSearchHistoryEntry(artistData.name, 'artist'); - navigation.navigate('Artist', { artistId: artistData.id }); - }, - }))} + content={artistData + .slice(0, props.maxItems ?? artistData.length) + .map((artistData) => ({ + image: API.getArtistIllustration(artistData.id), + name: artistData.name, + id: artistData.id, + onPress: () => { + API.createSearchHistoryEntry(artistData.name, 'artist'); + navigation.navigate('Artist', { artistId: artistData.id }); + }, + }))} cardComponent={ArtistCard} /> ) : ( @@ -194,7 +195,7 @@ const GenreSearchComponent = (props: ItemSearchComponentProps) => { id: g.id, onPress: () => { API.createSearchHistoryEntry(g.name, 'genre'); - navigation.navigate('Genre', {genreId: g.id}); + navigation.navigate('Genre', { genreId: g.id }); }, }))} cardComponent={GenreCard} diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index 5ac3189..d88eaf6 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -1,8 +1,8 @@ -import { HStack, IconButton, Image, Text } from "native-base"; -import Song, { SongWithArtist } from "../models/Song"; -import RowCustom from "./RowCustom"; -import TextButton from "./TextButton"; -import { MaterialIcons } from "@expo/vector-icons"; +import { HStack, IconButton, Image, Text } from 'native-base'; +import Song, { SongWithArtist } from '../models/Song'; +import RowCustom from './RowCustom'; +import TextButton from './TextButton'; +import { MaterialIcons } from '@expo/vector-icons'; type SongRowProps = { song: Song | SongWithArtist; // TODO: remove Song diff --git a/front/i18n/Translations.ts b/front/i18n/Translations.ts index 040fe5c..07684ea 100644 --- a/front/i18n/Translations.ts +++ b/front/i18n/Translations.ts @@ -43,7 +43,7 @@ export const en = { artistFilter: 'Artists', songsFilter: 'Songs', genreFilter: 'Genres', - favoriteFilter: 'Favorites', + favoriteFilter: 'Favorites', // profile page user: 'Profile', @@ -232,7 +232,7 @@ export const fr: typeof en = { artistFilter: 'Artistes', songsFilter: 'Morceaux', genreFilter: 'Genres', - favoriteFilter: 'Favoris', + favoriteFilter: 'Favoris', // Difficulty settings diffBtn: 'Difficulté', @@ -430,7 +430,7 @@ export const sp: typeof en = { artistFilter: 'Artistas', songsFilter: 'canciones', genreFilter: 'géneros', - favoriteFilter: 'Favorites', + favoriteFilter: 'Favorites', // Difficulty settings diffBtn: 'Dificultad', diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index eae2ee4..555157e 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -32,14 +32,18 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => return ( - + + style={{ height: '100%', width: '100%' }} + /> - {artistQuery.data.name} + + {artistQuery.data.name} + {songsQuery.data.map((comp: Song, index: Key | null | undefined) => ( @@ -59,4 +63,4 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => ); }; -export default ArtistDetailsView; \ No newline at end of file +export default ArtistDetailsView; diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index df3655b..8ee28ee 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -10,20 +10,25 @@ import { LinearGradient } from 'expo-linear-gradient'; type GenreDetailsViewProps = { genreId: number; -} +}; const GenreDetailsView = ({ genreId }: RouteProps) => { - const genreQuery = useQuery(API.getGenre(genreId)) - const songsQuery = useQuery(API.getSongsByGenre(genreId)) - const artistQueries = useQueries(songsQuery.data?.map((song) => song.artistId).map((artistId) => API.getArtist(artistId)) ?? []); + const genreQuery = useQuery(API.getGenre(genreId)); + const songsQuery = useQuery(API.getSongsByGenre(genreId)); + const artistQueries = useQueries( + songsQuery.data?.map((song) => song.artistId).map((artistId) => API.getArtist(artistId)) ?? + [] + ); // Here, .artist will always be defined - const songWithArtist = songsQuery?.data?.map((song) => ({ - ...song, - artist: artistQueries.find((query) => query.data?.id == song.artistId)?.data - })).filter((song) => song.artist !== undefined); + const songWithArtist = songsQuery?.data + ?.map((song) => ({ + ...song, + artist: artistQueries.find((query) => query.data?.id == song.artistId)?.data, + })) + .filter((song) => song.artist !== undefined); - const screenSize = useBreakpointValue({ base: "small", md: "big" }); - const isMobileView = screenSize == "small"; + const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); + const isMobileView = screenSize == 'small'; const fadeColor = useColorModeValue('#ffffff', '#000000'); const navigation = useNavigation(); @@ -38,13 +43,17 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { return ( + style={{ width: '100%', height: isMobileView ? 200 : 300 }} + source={{ uri: API.getGenreIllustration(genreQuery.data.id) }} + > + style={{ height: '100%', width: '100%' }} + /> - {genreQuery.data.name} + + {genreQuery.data.name} + ) => { /> -); -} + ); +}; -export default GenreDetailsView; \ No newline at end of file +export default GenreDetailsView; From 64640eda55d3a8c0a3cb2d26832aca1aaac162ac Mon Sep 17 00:00:00 2001 From: danis Date: Sat, 9 Sep 2023 19:18:30 +0200 Subject: [PATCH 25/28] lints fix --- front/Theme.tsx | 6 ------ front/components/SearchResult.tsx | 8 +------- front/components/SongRow.tsx | 3 +-- front/views/ArtistDetailsView.tsx | 2 +- front/views/GenreDetailsView.tsx | 2 +- 5 files changed, 4 insertions(+), 17 deletions(-) diff --git a/front/Theme.tsx b/front/Theme.tsx index ab23d2d..6d7fc57 100644 --- a/front/Theme.tsx +++ b/front/Theme.tsx @@ -4,15 +4,9 @@ import { useEffect } from 'react'; const ThemeProvider = ({ children }: { children: JSX.Element }) => { const colorScheme = useColorScheme(); - const config = { - dependencies: { - 'linear-gradient': require('expo-linear-gradient').LinearGradient, - }, - }; return ( { export const SearchResultComponent = () => { const { stringQuery } = React.useContext(SearchContext); - const { filter } = React.useContext(SearchContext); const shouldOutput = !!stringQuery.trim(); return shouldOutput ? ( diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index d88eaf6..4a61c83 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -1,8 +1,7 @@ -import { HStack, IconButton, Image, Text } from 'native-base'; +import { HStack, Image, Text } from 'native-base'; import Song, { SongWithArtist } from '../models/Song'; import RowCustom from './RowCustom'; import TextButton from './TextButton'; -import { MaterialIcons } from '@expo/vector-icons'; type SongRowProps = { song: Song | SongWithArtist; // TODO: remove Song diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 555157e..e7a7b03 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -2,7 +2,7 @@ import { Box, Heading, useBreakpointValue, ScrollView, useColorModeValue } from import { useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import API from '../API'; -import Song, { SongWithArtist } from '../models/Song'; +import Song from '../models/Song'; import SongRow from '../components/SongRow'; import { Key } from 'react'; import { RouteProps, useNavigation } from '../Navigation'; diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 8ee28ee..8161f8c 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -1,4 +1,4 @@ -import { Box, Flex, Heading, useBreakpointValue, ScrollView, useColorModeValue } from 'native-base'; +import { Flex, Heading, useBreakpointValue, ScrollView, useColorModeValue } from 'native-base'; import { useQueries, useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import { RouteProps, useNavigation } from '../Navigation'; From 46ef0a7f1bf93fe77fea91e6fc5bc21c3f9ae00f Mon Sep 17 00:00:00 2001 From: danis Date: Tue, 12 Sep 2023 22:05:31 +0200 Subject: [PATCH 26/28] remove expo-linear-gradient --- front/package.json | 1 - front/views/ArtistDetailsView.tsx | 5 ----- front/views/GenreDetailsView.tsx | 5 ----- 3 files changed, 11 deletions(-) diff --git a/front/package.json b/front/package.json index cc75dac..f097628 100644 --- a/front/package.json +++ b/front/package.json @@ -34,7 +34,6 @@ "expo": "^47.0.8", "expo-asset": "~8.7.0", "expo-dev-client": "~2.0.1", - "expo-linear-gradient": "^12.3.0", "expo-image-picker": "~14.0.2", "expo-linking": "~3.3.1", "expo-screen-orientation": "~5.0.1", diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index e7a7b03..8a88062 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -7,7 +7,6 @@ import SongRow from '../components/SongRow'; import { Key } from 'react'; import { RouteProps, useNavigation } from '../Navigation'; import { ImageBackground } from 'react-native'; -import { LinearGradient } from 'expo-linear-gradient'; type ArtistDetailsViewProps = { artistId: number; @@ -35,10 +34,6 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => style={{ width: '100%', height: isMobileView ? 200 : 300 }} source={{ uri: API.getArtistIllustration(artistQuery.data.id) }} > - diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index 8161f8c..c9f4486 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -6,7 +6,6 @@ import API from '../API'; import CardGridCustom from '../components/CardGridCustom'; import SongCard from '../components/SongCard'; import { ImageBackground } from 'react-native'; -import { LinearGradient } from 'expo-linear-gradient'; type GenreDetailsViewProps = { genreId: number; @@ -46,10 +45,6 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { style={{ width: '100%', height: isMobileView ? 200 : 300 }} source={{ uri: API.getGenreIllustration(genreQuery.data.id) }} > - {genreQuery.data.name} From 1fefe7912da56a1870cb047b614b5242f6d212f8 Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Thu, 14 Sep 2023 11:37:50 +0200 Subject: [PATCH 27/28] Front: Run Pretty --- front/views/ArtistDetailsView.tsx | 3 +-- front/views/GenreDetailsView.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 8a88062..15026b1 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -33,8 +33,7 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => - + > {artistQuery.data.name} diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index c9f4486..d1d3990 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -44,8 +44,7 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { - + > {genreQuery.data.name} From 70ab56ce3a69da665a0ffba1a84f52d6fa82c47a Mon Sep 17 00:00:00 2001 From: Arthur Jamet Date: Thu, 14 Sep 2023 11:41:38 +0200 Subject: [PATCH 28/28] Front: Remove unused value --- front/views/ArtistDetailsView.tsx | 3 +-- front/views/GenreDetailsView.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/front/views/ArtistDetailsView.tsx b/front/views/ArtistDetailsView.tsx index 15026b1..61a0328 100644 --- a/front/views/ArtistDetailsView.tsx +++ b/front/views/ArtistDetailsView.tsx @@ -1,4 +1,4 @@ -import { Box, Heading, useBreakpointValue, ScrollView, useColorModeValue } from 'native-base'; +import { Box, Heading, useBreakpointValue, ScrollView } from 'native-base'; import { useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import API from '../API'; @@ -16,7 +16,6 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => const artistQuery = useQuery(API.getArtist(artistId)); const songsQuery = useQuery(API.getSongsByArtist(artistId)); const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); - const fadeColor = useColorModeValue('#ffffff', '#000000'); const isMobileView = screenSize == 'small'; const navigation = useNavigation(); diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index d1d3990..e9c632e 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -1,4 +1,4 @@ -import { Flex, Heading, useBreakpointValue, ScrollView, useColorModeValue } from 'native-base'; +import { Flex, Heading, useBreakpointValue, ScrollView } from 'native-base'; import { useQueries, useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import { RouteProps, useNavigation } from '../Navigation'; @@ -28,7 +28,6 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); const isMobileView = screenSize == 'small'; - const fadeColor = useColorModeValue('#ffffff', '#000000'); const navigation = useNavigation(); if (genreQuery.isError || songsQuery.isError) {