Front; Song Lobby: Cpaters, Scores and layout

This commit is contained in:
Arthi-chaud
2022-09-04 16:06:05 +02:00
parent 62f1576a70
commit f6a0acb991
5 changed files with 854 additions and 707 deletions
+11 -11
View File
@@ -59,7 +59,7 @@ export default class API {
static async getSong(songId: number): Promise<Song> { static async getSong(songId: number): Promise<Song> {
return delay(1).then(() => ({ return delay(1).then(() => ({
title: "Song", title: "Song",
description: "A song", description: "A very very very very very very very very very very very very very very very very very very very very very very very very good song",
album: "Album", album: "Album",
metrics: {}, metrics: {},
id: songId id: songId
@@ -72,16 +72,16 @@ export default class API {
* @param songId the id to find the song * @param songId the id to find the song
*/ */
static async getSongChapters(songId: number): Promise<Chapter[]> { static async getSongChapters(songId: number): Promise<Chapter[]> {
return [{ return [1, 2, 3, 4, 5].map((value) => ({
start: 0, start: 100 * (value - 1),
end: 100, end: 100 * value,
songId: songId, songId: songId,
name: "Chapter", name: `Chapter ${value}`,
type: "chorus", type: "chorus",
key_aspect: "rhythm", key_aspect: "rhythm",
difficulty: 1, difficulty: value,
id: 1 id: value * 10
}]; }));
} }
/** /**
@@ -89,11 +89,11 @@ export default class API {
* @param songId the id to find the song * @param songId the id to find the song
*/ */
static async getSongHistory(songId: number): Promise<SongHistory[]> { static async getSongHistory(songId: number): Promise<SongHistory[]> {
return [{ return [6, 1, 2, 3, 4, 5].map((value) => ({
songId: songId, songId: songId,
userId: 1, userId: 1,
score: 2 score: value
}]; }));
} }
/** /**
+6
View File
@@ -2,10 +2,16 @@ export const en = {
welcome: 'Welcome to Chromacase', welcome: 'Welcome to Chromacase',
signoutBtn: 'Sign out', signoutBtn: 'Sign out',
signinBtn: 'Sign in', signinBtn: 'Sign in',
playBtn: 'Play',
level: 'Level',
chapters: 'Chapters'
}; };
export const fr: typeof en = { export const fr: typeof en = {
welcome: 'Bienvenue sur Chromacase', welcome: 'Bienvenue sur Chromacase',
signoutBtn: 'Se déconnecter', signoutBtn: 'Se déconnecter',
signinBtn: 'Se connecter', signinBtn: 'Se connecter',
playBtn: 'Jouer',
level: 'Niveau',
chapters: 'Chapitres'
}; };
+6 -5
View File
@@ -16,14 +16,16 @@
"@react-navigation/native": "^6.0.11", "@react-navigation/native": "^6.0.11",
"@react-navigation/native-stack": "^6.7.0", "@react-navigation/native-stack": "^6.7.0",
"@reduxjs/toolkit": "^1.8.3", "@reduxjs/toolkit": "^1.8.3",
"@tanstack/react-query": "^4.2.3",
"@types/jest": "^28.1.4", "@types/jest": "^28.1.4",
"@types/react": "^18.0.8", "@types/react-dom": "^18.0.6",
"@types/react-query": "^1.2.9", "@types/react-query": "^1.2.9",
"@types/react-test-renderer": "^18.0.0", "@types/react-test-renderer": "^18.0.0",
"expo": "~45.0.0", "expo": "~45.0.0",
"expo-asset": "^8.6.1", "expo-asset": "^8.6.1",
"expo-dev-client": "~1.0.0", "expo-dev-client": "~1.0.0",
"expo-status-bar": "~1.3.0", "expo-status-bar": "~1.3.0",
"format-duration": "^2.0.0",
"i18next": "^21.8.16", "i18next": "^21.8.16",
"jest": "^26.6.3", "jest": "^26.6.3",
"jest-expo": "^45.0.1", "jest-expo": "^45.0.1",
@@ -31,19 +33,18 @@
"react-dom": "17.0.2", "react-dom": "17.0.2",
"react-i18next": "^11.18.3", "react-i18next": "^11.18.3",
"react-native": "0.68.2", "react-native": "0.68.2",
"react-native-paper": "^4.12.2", "react-native-paper": "^4.12.4",
"react-native-safe-area-context": "4.2.4", "react-native-safe-area-context": "4.2.4",
"react-native-screens": "~3.11.1", "react-native-screens": "~3.11.1",
"react-native-testing-library": "^6.0.0", "react-native-testing-library": "^6.0.0",
"react-native-web": "0.17.7", "react-native-web": "0.17.7",
"react-query": "^4.0.0",
"react-redux": "^8.0.2" "react-redux": "^8.0.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9", "@babel/core": "^7.12.9",
"@testing-library/react-native": "^11.0.0", "@testing-library/react-native": "^11.0.0",
"@types/react": "~17.0.21", "@types/react": "^18.0.18",
"@types/react-native": "~0.66.13", "@types/react-native": "^0.69.6",
"react-test-renderer": "17.0.2", "react-test-renderer": "17.0.2",
"typescript": "~4.3.5" "typescript": "~4.3.5"
}, },
+52 -12
View File
@@ -1,11 +1,13 @@
import { useRoute } from "@react-navigation/native"; import { useRoute } from "@react-navigation/native";
import { Image, View } from "react-native" import { Image, View } from "react-native"
import { Surface, Text } from "react-native-paper"; import { Button, Divider, IconButton, List, Surface, Text } from "react-native-paper";
import API from "../API"; import API from "../API";
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import LoadingComponent from "../components/loading"; import LoadingComponent from "../components/loading";
import React, { useEffect } from "react"; import React, { useEffect, useState } from "react";
import logo from '../assets/cover.png'; import logo from '../assets/cover.png';
import { translate } from "../i18n/i18n";
import formatDuration from "format-duration";
interface SongLobbyProps { interface SongLobbyProps {
// The unique identifier to find a song // The unique identifier to find a song
@@ -15,27 +17,65 @@ interface SongLobbyProps {
const SongLobbyView = () => { const SongLobbyView = () => {
const route = useRoute(); const route = useRoute();
const props: SongLobbyProps = route.params as any; const props: SongLobbyProps = route.params as any;
const { isLoading, data } = useQuery(['song', props.songId], () => API.getSong(props.songId)); const songQuery = useQuery(['song', props.songId], () => API.getSong(props.songId));
useEffect(() => {}, [isLoading]); const chaptersQuery = useQuery(['song', props.songId, 'chapters'], () => API.getSongChapters(props.songId));
if (isLoading) const scoresQuery = useQuery(['song', props.songId, 'scores'], () => API.getSongHistory(props.songId));
const [chaptersOpen, setChaptersOpen] = useState(false);
useEffect(() => {
if (chaptersOpen && !chaptersQuery.data)
chaptersQuery.refetch();
}, [chaptersOpen]);
useEffect(() => {}, [songQuery.isLoading]);
if (songQuery.isLoading || scoresQuery.isLoading)
return <View style={{ flexGrow: 1, justifyContent: 'center' }}> return <View style={{ flexGrow: 1, justifyContent: 'center' }}>
<LoadingComponent/> <LoadingComponent/>
</View> </View>
return ( return (
<View style={{ padding: 30 }}> <View style={{ padding: 30, flexDirection: 'column' }}>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row'}}>
<View style={{ flex: 3 }}> <View style={{ flex: 3 }}>
<Surface style={{ aspectRatio: 1, zIndex: 0 }}> <Surface style={{ aspectRatio: 1, zIndex: 0 }}>
<Image source={logo} style={{ height: '100%', width: undefined, resizeMode: 'contain' }}/> <Image source={logo} style={{ height: '100%', width: undefined, resizeMode: 'contain' }}/>
</Surface> </Surface>
</View> </View>
<View style={{ flex: 3, padding: 10 }}> <View style={{ flex: 0.5 }}/>
<Text>{data.title}</Text> <View style={{ flex: 3, padding: 10, flexDirection: 'column', justifyContent: 'space-between' }}>
<Text></Text> <View>
<Text style={{ fontWeight: 'bold', fontSize: 25 }}>{songQuery.data!.title}</Text>
<Text>{'3:20'} - {translate('level')} { chaptersQuery.data!.reduce((a, b) => a + b.difficulty, 0) / chaptersQuery.data!.length }</Text>
</View>
<Button icon="play" mode="contained" labelStyle={{ color: 'white' }} contentStyle={{ flexDirection: 'row-reverse' }}>
{ translate('playBtn') }
</Button>
</View> </View>
</View> </View>
<View style={{ paddingVertical: 10 }}/> <View style={{ flexDirection: 'row', justifyContent: 'space-between', padding: 30}}>
<Text>{data.description}</Text> <View style={{ flexDirection: 'column', alignItems: 'center' }}>
<Text style={{ fontWeight: 'bold', fontSize: 15 }}>Best Score</Text>
<Text>{scoresQuery.data!.sort()[0]?.score}</Text>
</View>
<View style={{ flexDirection: 'column', alignItems: 'center' }}>
<Text style={{ fontWeight: 'bold', fontSize: 15}}>Last Score</Text>
<Text>{scoresQuery.data!.slice(-1)[0]!.score}</Text>
</View>
</View>
<Text style={{ paddingBottom: 10 }}>{songQuery.data!.description}</Text>
<List.Accordion
title={translate('chapters')}
expanded={chaptersOpen}
onPress={() => setChaptersOpen(!chaptersOpen)}>
{ chaptersQuery.isLoading && <LoadingComponent/>}
{ !chaptersQuery.isLoading && chaptersQuery.data!.map((chapter) =>
<>
<List.Item
key={chapter.id}
title={chapter.name}
description={`Level ${chapter.difficulty} - ${formatDuration((chapter.end - chapter.start) * 1000)}`}
/>
<Divider />
</>
)}
</List.Accordion>
</View> </View>
) )
} }
+779 -679
View File
File diff suppressed because it is too large Load Diff