Add remaining lyric actions functionality
This commit is contained in:
parent
aaa1b5f63a
commit
e56350c1c2
5 changed files with 60 additions and 99 deletions
|
@ -1,32 +0,0 @@
|
|||
import { RiCloseFill } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import { Button } from '/@/renderer/components';
|
||||
|
||||
const LyricClearButton = styled(Button)`
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
z-index: 999;
|
||||
bottom: 6vh;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
bottom: 3vh;
|
||||
}
|
||||
`;
|
||||
|
||||
interface LyricSkipProps {
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
}
|
||||
|
||||
export const LyricSkip = ({ onClick }: LyricSkipProps) => {
|
||||
return (
|
||||
<LyricClearButton
|
||||
leftIcon={<RiCloseFill />}
|
||||
size="xl"
|
||||
tooltip={{ label: 'Remove incorrect lyrics', position: 'top' }}
|
||||
variant="default"
|
||||
onClick={onClick}
|
||||
>
|
||||
Clear
|
||||
</LyricClearButton>
|
||||
);
|
||||
};
|
|
@ -2,14 +2,31 @@ import { RiAddFill, RiSubtractFill } from 'react-icons/ri';
|
|||
import { LyricsOverride } from '/@/renderer/api/types';
|
||||
import { Button, NumberInput } from '/@/renderer/components';
|
||||
import { openLyricSearchModal } from '/@/renderer/features/lyrics/components/lyrics-search-form';
|
||||
import { useCurrentSong } from '/@/renderer/store';
|
||||
import {
|
||||
useCurrentSong,
|
||||
useLyricsSettings,
|
||||
useSettingsStore,
|
||||
useSettingsStoreActions,
|
||||
} from '/@/renderer/store';
|
||||
|
||||
interface LyricsActionsProps {
|
||||
onSearchOverride?: (params: LyricsOverride) => void;
|
||||
onRemoveLyric: () => void;
|
||||
onSearchOverride: (params: LyricsOverride) => void;
|
||||
}
|
||||
|
||||
export const LyricsActions = ({ onSearchOverride }: LyricsActionsProps) => {
|
||||
export const LyricsActions = ({ onRemoveLyric, onSearchOverride }: LyricsActionsProps) => {
|
||||
const currentSong = useCurrentSong();
|
||||
const { setSettings } = useSettingsStoreActions();
|
||||
const { delayMs } = useLyricsSettings();
|
||||
|
||||
const handleLyricOffset = (e: number) => {
|
||||
setSettings({
|
||||
lyrics: {
|
||||
...useSettingsStore.getState().lyrics,
|
||||
delayMs: e,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -27,30 +44,30 @@ export const LyricsActions = ({ onSearchOverride }: LyricsActionsProps) => {
|
|||
Search
|
||||
</Button>
|
||||
<Button
|
||||
tooltip={{ label: 'Decrease offset', openDelay: 500 }}
|
||||
aria-label="Decrease lyric offset"
|
||||
variant="subtle"
|
||||
onClick={() => handleLyricOffset(delayMs - 50)}
|
||||
>
|
||||
<RiSubtractFill />
|
||||
</Button>
|
||||
<NumberInput
|
||||
aria-label="Lyric offset"
|
||||
styles={{ input: { textAlign: 'center' } }}
|
||||
value={delayMs || 0}
|
||||
width={55}
|
||||
onChange={handleLyricOffset}
|
||||
/>
|
||||
<Button
|
||||
tooltip={{ label: 'Increase offset', openDelay: 500 }}
|
||||
aria-label="Increase lyric offset"
|
||||
variant="subtle"
|
||||
onClick={() => handleLyricOffset(delayMs + 50)}
|
||||
>
|
||||
<RiAddFill />
|
||||
</Button>
|
||||
<Button
|
||||
uppercase
|
||||
variant="subtle"
|
||||
onClick={() =>
|
||||
openLyricSearchModal({
|
||||
artist: currentSong?.artistName,
|
||||
name: currentSong?.name,
|
||||
})
|
||||
}
|
||||
onClick={onRemoveLyric}
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
|
|
|
@ -9,7 +9,7 @@ import { SynchronizedLyrics } from './synchronized-lyrics';
|
|||
import { ScrollArea, Spinner, TextTitle } from '/@/renderer/components';
|
||||
import { ErrorFallback } from '/@/renderer/features/action-required';
|
||||
import { UnsynchronizedLyrics } from '/@/renderer/features/lyrics/unsynchronized-lyrics';
|
||||
import { getServerById, useCurrentSong } from '/@/renderer/store';
|
||||
import { getServerById, useCurrentSong, usePlayerStore } from '/@/renderer/store';
|
||||
import {
|
||||
FullLyricsMetadata,
|
||||
LyricsOverride,
|
||||
|
@ -20,7 +20,7 @@ import { LyricsActions } from '/@/renderer/features/lyrics/lyrics-actions';
|
|||
|
||||
const ActionsContainer = styled.div`
|
||||
position: absolute;
|
||||
bottom: 4rem;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
|
@ -42,6 +42,7 @@ const ActionsContainer = styled.div`
|
|||
|
||||
const LyricsContainer = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
@ -67,6 +68,7 @@ const ScrollContainer = styled(motion(ScrollArea))`
|
|||
);
|
||||
|
||||
&.mantine-ScrollArea-root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
@ -154,16 +156,16 @@ export const Lyrics = () => {
|
|||
|
||||
return (
|
||||
<ErrorBoundary FallbackComponent={ErrorFallback}>
|
||||
{isLoadingLyrics ? (
|
||||
<Spinner
|
||||
container
|
||||
size={25}
|
||||
/>
|
||||
) : (
|
||||
<AnimatePresence mode="sync">
|
||||
<LyricsContainer>
|
||||
<LyricsContainer>
|
||||
{isLoadingLyrics ? (
|
||||
<Spinner
|
||||
container
|
||||
size={25}
|
||||
/>
|
||||
) : (
|
||||
<AnimatePresence mode="sync">
|
||||
{!data?.lyrics || clear ? (
|
||||
<Center>
|
||||
<Center w="100%">
|
||||
<Group>
|
||||
<RiInformationFill size="2rem" />
|
||||
<TextTitle
|
||||
|
@ -182,25 +184,21 @@ export const Lyrics = () => {
|
|||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
{isSynchronizedLyrics ? (
|
||||
<SynchronizedLyrics
|
||||
{...lyricsMetadata}
|
||||
onRemoveLyric={() => setClear(true)}
|
||||
/>
|
||||
<SynchronizedLyrics {...lyricsMetadata} />
|
||||
) : (
|
||||
<UnsynchronizedLyrics
|
||||
{...(lyricsMetadata as UnsynchronizedLyricMetadata)}
|
||||
onRemoveLyric={() => setClear(true)}
|
||||
/>
|
||||
<UnsynchronizedLyrics {...(lyricsMetadata as UnsynchronizedLyricMetadata)} />
|
||||
)}
|
||||
</ScrollContainer>
|
||||
)}
|
||||
|
||||
<ActionsContainer>
|
||||
<LyricsActions onSearchOverride={handleOnSearchOverride} />
|
||||
</ActionsContainer>
|
||||
</LyricsContainer>
|
||||
</AnimatePresence>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
)}
|
||||
<ActionsContainer>
|
||||
<LyricsActions
|
||||
onRemoveLyric={() => setClear(true)}
|
||||
onSearchOverride={handleOnSearchOverride}
|
||||
/>
|
||||
</ActionsContainer>
|
||||
</LyricsContainer>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,6 @@ import isElectron from 'is-electron';
|
|||
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
||||
import { FullLyricsMetadata, SynchronizedLyricsArray } from '/@/renderer/api/types';
|
||||
import styled from 'styled-components';
|
||||
import { LyricSkip } from '/@/renderer/features/lyrics/lyric-skip';
|
||||
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
|
||||
|
@ -22,14 +21,12 @@ const SynchronizedLyricsContainer = styled.div`
|
|||
|
||||
interface SynchronizedLyricsProps extends Omit<FullLyricsMetadata, 'lyrics'> {
|
||||
lyrics: SynchronizedLyricsArray;
|
||||
onRemoveLyric: () => void;
|
||||
}
|
||||
|
||||
export const SynchronizedLyrics = ({
|
||||
artist,
|
||||
lyrics,
|
||||
name,
|
||||
onRemoveLyric,
|
||||
remote,
|
||||
source,
|
||||
}: SynchronizedLyricsProps) => {
|
||||
|
@ -146,16 +143,6 @@ export const SynchronizedLyrics = ({
|
|||
}
|
||||
}, []);
|
||||
|
||||
const removeLyric = useCallback(() => {
|
||||
onRemoveLyric();
|
||||
|
||||
if (lyricTimer.current) {
|
||||
clearTimeout(lyricTimer.current);
|
||||
}
|
||||
|
||||
timerEpoch.current += 1;
|
||||
}, [onRemoveLyric]);
|
||||
|
||||
useEffect(() => {
|
||||
// Copy the follow settings into a ref that can be accessed in the timeout
|
||||
followRef.current = settings.follow;
|
||||
|
@ -276,13 +263,10 @@ export const SynchronizedLyrics = ({
|
|||
/>
|
||||
)}
|
||||
{remote && (
|
||||
<>
|
||||
<LyricLine
|
||||
className="lyric-credit"
|
||||
text={`(Matched as ${artist} by ${name})`}
|
||||
/>
|
||||
<LyricSkip onClick={removeLyric} />
|
||||
</>
|
||||
<LyricLine
|
||||
className="lyric-credit"
|
||||
text={`(Matched as ${artist} by ${name})`}
|
||||
/>
|
||||
)}
|
||||
{lyrics.map(([, text], idx) => (
|
||||
<LyricLine
|
||||
|
|
|
@ -2,11 +2,9 @@ import { useMemo } from 'react';
|
|||
import styled from 'styled-components';
|
||||
import { LyricLine } from '/@/renderer/features/lyrics/lyric-line';
|
||||
import { FullLyricsMetadata } from '/@/renderer/api/types';
|
||||
import { LyricSkip } from '/@/renderer/features/lyrics/lyric-skip';
|
||||
|
||||
interface UnsynchronizedLyricsProps extends Omit<FullLyricsMetadata, 'lyrics'> {
|
||||
lyrics: string;
|
||||
onRemoveLyric: () => void;
|
||||
}
|
||||
|
||||
const UnsynchronizedLyricsContainer = styled.div`
|
||||
|
@ -17,7 +15,6 @@ export const UnsynchronizedLyrics = ({
|
|||
artist,
|
||||
lyrics,
|
||||
name,
|
||||
onRemoveLyric,
|
||||
remote,
|
||||
source,
|
||||
}: UnsynchronizedLyricsProps) => {
|
||||
|
@ -34,13 +31,10 @@ export const UnsynchronizedLyrics = ({
|
|||
/>
|
||||
)}
|
||||
{remote && (
|
||||
<>
|
||||
<LyricLine
|
||||
className="lyric-credit"
|
||||
text={`(Matched as ${artist} by ${name})`}
|
||||
/>
|
||||
<LyricSkip onClick={onRemoveLyric} />
|
||||
</>
|
||||
<LyricLine
|
||||
className="lyric-credit"
|
||||
text={`(Matched as ${artist} by ${name})`}
|
||||
/>
|
||||
)}
|
||||
{lines.map((text, idx) => (
|
||||
<LyricLine
|
||||
|
|
Reference in a new issue