Fixed type definition of SongCursorInfos fixed 'race conditions' in asset generation service removed hard coded cursor infos fixed tsc looking to build folders

This commit is contained in:
Clément Le Bihan
2023-11-06 12:00:16 +01:00
parent 4a5658c4ca
commit f1662ca18b
7 changed files with 127 additions and 8499 deletions

View File

@@ -157,12 +157,6 @@ export async function generateSongAssets(
eval(`import("cross-blob")`).then((module) => {
Blob = module.default;
});
try {
let e = require("canvas")
console.log(e, "pass");
} catch (e) {
console.log(e);
}
debug("" + sampleDir + " " + imageDir + " " + imageFormat);
if (!mode) {

View File

@@ -5,12 +5,24 @@ import { generateSongAssets } from "src/assetsgenerator/generateImages_browserle
@Injectable()
export class SongService {
constructor(private prisma: PrismaService) {}
// number is the song id
private readonly assetCreationTasks: Map<number, Promise<void>>;
constructor(private prisma: PrismaService) {
this.assetCreationTasks = new Map();
}
async createAssets(mxlPath: string, songId: number): Promise<void> {
if (this.assetCreationTasks.has(songId)) {
await this.assetCreationTasks.get(songId);
this.assetCreationTasks.delete(songId);
return;
}
// mxlPath can the path to an archive to an xml file or the path to the xml file directly
// const generateSongAssets = (await import("src/assetsgenerator/generateImages_browserless.mjs")).default;
return generateSongAssets(songId, mxlPath, "/data/cache/songs", "svg");
this.assetCreationTasks.set(
songId,
generateSongAssets(songId, mxlPath, "/data/cache/songs", "svg"),
);
return await this.assetCreationTasks.get(songId);
}
async songByArtist(data: number): Promise<Song[]> {

File diff suppressed because it is too large Load Diff

View File

@@ -16,8 +16,9 @@ export type ParitionMagicProps = {
};
const getSVGURL = (songID: number) => {
// return 'https://cdn.discordapp.com/attachments/717080637038788731/1162519992722530354/Short.mxl_1.svg?ex=653c3c1c&is=6529c71c&hm=1788e4abe532f4a2af8c24cae6dadcfde369eaf58322f051ecd1d9110d8b699a&';
return 'https://cdn.discordapp.com/attachments/717080637038788731/1161704545785757816/4.svg?ex=653944ab&is=6526cfab&hm=2416ee2cb414cc42fa9de8af58b8db544479d35f13393d76f02e8d9fe27aff45&';
return API.getPartitionSvgUrl(songID);
return 'https://cdn.discordapp.com/attachments/717080637038788731/1162519992722530354/Short.mxl_1.svg?ex=653c3c1c&is=6529c71c&hm=1788e4abe532f4a2af8c24cae6dadcfde369eaf58322f051ecd1d9110d8b699a&';
// return 'https://cdn.discordapp.com/attachments/717080637038788731/1161704545785757816/4.svg?ex=653944ab&is=6526cfab&hm=2416ee2cb414cc42fa9de8af58b8db544479d35f13393d76f02e8d9fe27aff45&';
};
const SVGContainer = ({
@@ -96,7 +97,7 @@ const PartitionMagic = ({ songID, onEndReached, onError, onReady }: ParitionMagi
}
}, [isLoading, isError]);
const transitionDuration = 75;
const transitionDuration = 200;
getCursorToPlay(
data?.cursors ?? [],
@@ -144,6 +145,7 @@ const PartitionMagic = ({ songID, onEndReached, onError, onReady }: ParitionMagi
left: `${partitionOffset.value * 100}%`,
}}
>
{!isLoading && !isError && (
<ImageBackground
source={{ uri: getSVGURL(songID) }}
onLoad={onReady}
@@ -153,6 +155,7 @@ const PartitionMagic = ({ songID, onEndReached, onError, onReady }: ParitionMagi
position: 'relative',
}}
/>
)}
</Animated.View>
<Animated.View
style={{

View File

@@ -13,12 +13,15 @@ export const SongCursorInfosValidator = yup.object({
height: yup.number().required(),
timestamp: yup.number().required(),
timing: yup.number().required(),
note: yup
.object({
note: yup.number().required(),
gain: yup.number().required(),
duration: yup.number().required(),
})
notes: yup
.array()
.of(
yup.object({
note: yup.number().required(),
gain: yup.number().required(),
duration: yup.number().required(),
})
)
.required(),
})
)
@@ -39,11 +42,11 @@ export const SongCursorInfosHandler: ResponseHandler<
height: cursor.height,
timestamp: cursor.timestamp,
timing: cursor.timing,
note: {
note: cursor.note.note,
gain: cursor.note.gain,
duration: cursor.note.duration,
},
notes: cursor.notes.map((n) => ({
note: n.note,
gain: n.gain,
duration: n.duration,
})),
})),
}),
};
@@ -55,11 +58,11 @@ export interface CursorInfoItem {
height: number;
timestamp: number;
timing: number;
note: {
notes: {
note: number;
gain: number;
duration: number;
};
}[];
}
export interface SongCursorInfos {

View File

@@ -112,6 +112,8 @@
"metro.config.js",
"jest.config.js",
"app.config.ts",
"*/*.test.tsx"
"*/*.test.tsx",
"web-build",
"dist",
]
}

View File

@@ -1,7 +1,16 @@
/* eslint-disable no-mixed-spaces-and-tabs */
import { StackActions } from '@react-navigation/native';
import React, { useEffect, useRef, useState, createContext, useReducer } from 'react';
import { SafeAreaView, Platform, Animated } from 'react-native';
import { SafeAreaView, Platform } from 'react-native';
import Animated, {
BounceIn,
useSharedValue,
withTiming,
Easing,
useAnimatedStyle,
withSequence,
withDelay,
} from 'react-native-reanimated';
import * as ScreenOrientation from 'expo-screen-orientation';
import {
Box,
@@ -15,6 +24,7 @@ import {
Icon,
HStack,
Image,
PresenceTransition,
} from 'native-base';
import IconButton from '../components/IconButton';
import { Ionicons } from '@expo/vector-icons';
@@ -79,6 +89,27 @@ export const PianoCC = createContext<PianoCanvasContext>({
messages: [],
});
const infoCardInfos = [
{
icon: <Ionicons name="timer-outline" size={18} color="#6075F9" />,
label: 'Last Score',
id: 'lastScore',
value: 60,
},
{
icon: <Ionicons name="trophy-outline" size={18} color="#6075F9" />,
label: 'Best Score',
id: 'bestScore',
value: 60,
},
{
icon: <Ionicons name="bar-chart-outline" size={18} color="#6075F9" />,
label: 'Level',
id: 'level',
value: 3,
},
] as const;
const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
const accessToken = useSelector((state: RootState) => state.user.accessToken);
const navigation = useNavigation();
@@ -92,7 +123,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
const [time, setTime] = useState(0);
const [partitionRendered, setPartitionRendered] = useState(false); // Used to know when partitionview can render
const [score, setScore] = useState(0); // Between 0 and 100
const fadeAnim = useRef(new Animated.Value(0)).current;
// const fadeAnim = useRef(new Animated.Value(0)).current;
const musixml = useQuery(
transformQuery(API.getSongMusicXML(songId), (data) => new TextDecoder().decode(data)),
{ staleTime: Infinity }
@@ -108,27 +139,14 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
},
[]
);
const infoCardInfos = [
{
icon: <Ionicons name="timer-outline" size={18} color="#6075F9" />,
label: 'Last Score',
id: 'lastScore',
value: 60,
},
{
icon: <Ionicons name="trophy-outline" size={18} color="#6075F9" />,
label: 'Best Score',
id: 'bestScore',
value: 60,
},
{
icon: <Ionicons name="bar-chart-outline" size={18} color="#6075F9" />,
label: 'Level',
id: 'level',
value: 3,
},
] as const;
const [streak, setStreak] = useState(0);
const scoreMessageScale = useSharedValue(0);
// this style should bounce in on enter and fade away
const scoreMsgStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scoreMessageScale.value }],
};
});
const onPause = () => {
stopwatch.pause();
@@ -234,7 +252,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
type: 'noteTiming',
data: NoteTiming.Missed,
});
messageColor = 'black';
messageColor = 'white';
} else if (data.type == 'timing' || data.type == 'duration') {
formattedMessage = translate(data[data.type]);
switch (data[data.type]) {
@@ -324,12 +342,19 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
}, []);
useEffect(() => {
if (lastScoreMessage) {
fadeAnim.setValue(1);
Animated.timing(fadeAnim, {
toValue: 0,
duration: 3000,
useNativeDriver: true,
}).start();
scoreMessageScale.value = withSequence(
withTiming(1, {
duration: 400,
easing: Easing.elastic(3),
}),
withDelay(
700,
withTiming(0, {
duration: 300,
easing: Easing.out(Easing.cubic),
})
)
);
}
}, [lastScoreMessage]);
useEffect(() => {
@@ -408,20 +433,24 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
<View>
<Text fontSize={24}>{score}</Text>
</View>
<View
style={{
display: 'flex',
flexDirection: 'row',
gap: 7,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text fontSize={20}>Cool</Text>
<Text fontSize={15} bold>
x1
</Text>
</View>
<Animated.View style={[scoreMsgStyle]}>
<View
style={{
display: 'flex',
flexDirection: 'row',
gap: 7,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text fontSize={20} color={'white'}>
{lastScoreMessage?.content}
</Text>
<Text fontSize={15} bold>
{streak > 0 && `x${streak}`}
</Text>
</View>
</Animated.View>
</View>
<View
style={{
@@ -531,7 +560,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
.padStart(2, '0')}`}
</Text>
<StarProgress
value={60}
value={score}
max={100}
starSteps={[50, 75, 90]}
style={{
@@ -541,7 +570,6 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
marginBottom: 10,
}}
/>
<Text>2:30</Text>
</View>
<View
style={{