bold words

This commit is contained in:
2025-09-03 15:41:09 +02:00
parent a516f260d1
commit 8f1c062b33
+92 -3
View File
@@ -77,6 +77,22 @@ const MusicDetails = () => {
const player = useAudioPlayer(songUrl ? { uri: songUrl } : undefined);
// Karaoke aligned words (from timestamps)
const alignedWords = useMemo(() => {
try {
const idx = Number(project?.songIndex) || 0;
const ts = project?.musicTimestamps?.[idx];
const arr = Array.isArray(ts?.alignedWords) ? ts.alignedWords : [];
return arr.map((w) => ({
word: String(w?.word ?? ""),
startS: Number(w?.startS ?? 0),
endS: Number(w?.endS ?? 0),
}));
} catch (e) {
return [];
}
}, [project?.musicTimestamps, project?.songIndex]);
// Reset counters when the track changes
useEffect(() => {
listenedMsRef.current = 0;
@@ -189,10 +205,65 @@ const MusicDetails = () => {
}
const c = project?.lyrics?.couplet;
const r = project?.lyrics?.refrain;
const parts = [c ? `[Couplet]\n${c}` : null, r ? `[Refrain]\n${r}` : null].filter(Boolean);
const parts = [
c ? `[Couplet]\n${c}` : null,
r ? `[Refrain]\n${r}` : null,
].filter(Boolean);
return parts.length ? parts.join("\n\n") : "";
}, [project]);
// Current time in seconds for highlighting
const currentTimeS = useMemo(
() => Math.max(0, (progressInfo.pos || 0) / 1000),
[progressInfo.pos]
);
// Render full lyrics with the currently sung word highlighted
const renderKaraokeFullLyrics = () => {
if (!alignedWords?.length) return null;
const spans = [];
for (let i = 0; i < alignedWords.length; i++) {
const w = alignedWords[i];
const text = String(w.word || "");
// Highlight all words that already started (and keep them lit)
const isHighlighted = currentTimeS >= (w.startS || 0);
// split by newline to preserve line breaks
const parts = text.split(/(\n+)/);
parts.forEach((p, j) => {
if (/^\n+$/.test(p)) {
spans.push(<Text key={`br-${i}-${j}`}>{"\n"}</Text>);
} else if (p.length > 0) {
spans.push(
<Text
key={`w-${i}-${j}`}
style={
isHighlighted ? styles.karaokeWordActive : styles.karaokeWord
}
>
{p}
</Text>
);
}
});
// Add space between words when no newline
if (!/\n/.test(text) && i < alignedWords.length - 1) {
spans.push(
<Text key={`sp-${i}`} style={styles.karaokeWord}>
{" "}
</Text>
);
}
}
return (
<Text style={styles.karaokeContainer} selectable>
{spans}
</Text>
);
};
return (
<Page
headerType="NAVIGATION"
@@ -346,8 +417,10 @@ const MusicDetails = () => {
</View>
</View>
)}
{description?.length > 0 && (
<View style={{ marginTop: 30, gap: 20 }}>
{alignedWords?.length ? (
renderKaraokeFullLyrics()
) : description?.length > 0 ? (
<Text
style={{
fontSize: 16,
@@ -357,8 +430,8 @@ const MusicDetails = () => {
>
{description}
</Text>
) : null}
</View>
)}
</ScrollView>
</Page>
);
@@ -385,4 +458,20 @@ const styles = StyleSheet.create({
color: Palette.white,
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
},
karaokeContainer: {
fontSize: 16,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
lineHeight: 24,
},
karaokeWord: {
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
},
karaokeWordActive: {
color: Palette.white,
fontFamily: FONT_FAMILY.InterBold,
fontStyle: "italic",
fontWeight: "bold",
},
});