Skip to content

Commit

Permalink
resize, nicer scroll, better actions
Browse files Browse the repository at this point in the history
  • Loading branch information
kgarner7 committed Nov 6, 2023
1 parent 8ba25f2 commit 1f20cd7
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 103 deletions.
1 change: 1 addition & 0 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@
"lyricFetchProvider_description": "select the providers to fetch lyrics from. the order of the providers is the order in which they will be queried",
"lyricOffset": "lyric offset (ms)",
"lyricOffset_description": "offset the lyric by the specified amount of milliseconds",
"lyricWdith": "lyric overlay width",
"minimizeToTray": "minimize to tray",
"minimizeToTray_description": "minimize the application to the system tray",
"minimumScrobblePercentage": "minimum scrobble duration (percentage)",
Expand Down
170 changes: 108 additions & 62 deletions src/renderer/features/lyrics/lyrics-actions.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { Box, Group } from '@mantine/core';
import { Box, Grid, Group } from '@mantine/core';
import isElectron from 'is-electron';
import { useTranslation } from 'react-i18next';
import { RiAddFill, RiSubtractFill } from 'react-icons/ri';
import { LyricsOverride } from '/@/renderer/api/types';
import { Button, NumberInput, Tooltip } from '/@/renderer/components';
import { openLyricSearchModal } from '/@/renderer/features/lyrics/components/lyrics-search-form';
import {
useAppStoreActions,
useCurrentSong,
useLyricsSettings,
useLyricsStore,
useSettingsStore,
useSettingsStoreActions,
} from '/@/renderer/store';
import { useCallback } from 'react';

interface LyricsActionsProps {
onRemoveLyric: () => void;
Expand All @@ -26,7 +29,9 @@ export const LyricsActions = ({
const { t } = useTranslation();
const currentSong = useCurrentSong();
const { setSettings } = useSettingsStoreActions();
const { setLyrics } = useAppStoreActions();
const { delayMs, sources } = useLyricsSettings();
const { open, width } = useLyricsStore();

const handleLyricOffset = (e: number) => {
setSettings({
Expand All @@ -37,79 +42,120 @@ export const LyricsActions = ({
});
};

const setWidth = useCallback(
(newWidth: number) => {
setLyrics({ open, width: newWidth });
},
[open, setLyrics],
);

const isActionsDisabled = !currentSong;
const isDesktop = isElectron();

return (
<Box style={{ position: 'relative', width: '100%' }}>
<Group position="center">
<Grid
grow
justify="center"
>
{true && (
<Grid.Col span="content">
<Tooltip
label={t('setting.lyricWdith', { postProcess: 'sentenceCase' })}
openDelay={500}
>
<NumberInput
aria-label="Lyric offset"
max={1000}
min={400}
rightSection="px"
styles={{ input: { textAlign: 'center' } }}
value={width}
w={100}
onBlur={(e) => setWidth(Number(e.currentTarget.value))}
/>
</Tooltip>
</Grid.Col>
)}
{isDesktop && sources.length ? (
<Button
uppercase
disabled={isActionsDisabled}
variant="subtle"
onClick={() =>
openLyricSearchModal({
artist: currentSong?.artistName,
name: currentSong?.name,
onSearchOverride,
})
}
>
{t('common.search', { postProcess: 'titleCase' })}
</Button>
<Grid.Col span="content">
<Button
fullWidth
uppercase
disabled={isActionsDisabled}
variant="subtle"
onClick={() =>
openLyricSearchModal({
artist: currentSong?.artistName,
name: currentSong?.name,
onSearchOverride,
})
}
>
{t('common.search', { postProcess: 'titleCase' })}
</Button>
</Grid.Col>
) : null}
<Button
aria-label="Decrease lyric offset"
variant="subtle"
onClick={() => handleLyricOffset(delayMs - 50)}
>
<RiSubtractFill />
</Button>
<Tooltip
label={t('setting.lyricOffset', { postProcess: 'sentenceCase' })}
openDelay={500}
>
<NumberInput
aria-label="Lyric offset"
styles={{ input: { textAlign: 'center' } }}
value={delayMs || 0}
width={55}
onChange={handleLyricOffset}
/>
</Tooltip>
<Button
aria-label="Increase lyric offset"
variant="subtle"
onClick={() => handleLyricOffset(delayMs + 50)}
>
<RiAddFill />
</Button>
<Grid.Col span="content">
<Group>
<Button
aria-label="Decrease lyric offset"
variant="subtle"
onClick={() => handleLyricOffset(delayMs - 50)}
>
<RiSubtractFill />
</Button>
<Tooltip
label={t('setting.lyricOffset', { postProcess: 'sentenceCase' })}
openDelay={500}
>
<NumberInput
aria-label="Lyric offset"
styles={{ input: { textAlign: 'center' } }}
value={delayMs || 0}
width={75}
onChange={handleLyricOffset}
/>
</Tooltip>
<Button
aria-label="Increase lyric offset"
variant="subtle"
onClick={() => handleLyricOffset(delayMs + 50)}
>
<RiAddFill />
</Button>
</Group>
</Grid.Col>

{isDesktop && sources.length ? (
<Button
uppercase
disabled={isActionsDisabled}
variant="subtle"
onClick={onResetLyric}
>
{t('common.reset', { postProcess: 'sentenceCase' })}
</Button>
<Grid.Col span="content">
<Button
fullWidth
uppercase
disabled={isActionsDisabled}
variant="subtle"
onClick={onResetLyric}
>
{t('common.reset', { postProcess: 'sentenceCase' })}
</Button>
</Grid.Col>
) : null}
</Group>

<Box style={{ position: 'absolute', right: 0, top: 0 }}>
{isDesktop && sources.length ? (
<Button
uppercase
color="red"
disabled={isActionsDisabled}
variant="subtle"
onClick={onRemoveLyric}
>
{t('common.clear', { postProcess: 'sentenceCase' })}
</Button>
<Grid.Col span="content">
<Button
fullWidth
uppercase
color="red"
disabled={isActionsDisabled}
variant="subtle"
onClick={onRemoveLyric}
>
{t('common.clear', { postProcess: 'sentenceCase' })}
</Button>
</Grid.Col>
) : null}
</Box>
</Grid>
</Box>
);
};
9 changes: 7 additions & 2 deletions src/renderer/features/lyrics/synchronized-lyrics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ export const SynchronizedLyrics = ({
currentLyric.classList.add('active');

if (followRef.current) {
doc?.scroll({ behavior: 'smooth', top: offsetTop });
// Have smooth scrolling for line-by-line, instant for large jumps
const behavior =
Math.abs(doc.scrollTop - offsetTop) > 8 * settings.fontSize
? 'instant'
: 'smooth';
doc?.scroll({ behavior, top: offsetTop });
}

if (index !== lyricRef.current!.length - 1) {
Expand All @@ -178,7 +183,7 @@ export const SynchronizedLyrics = ({
}, nextTime - timeInMs - elapsed);
}
},
[],
[settings.fontSize],
);

useEffect(() => {
Expand Down
77 changes: 39 additions & 38 deletions src/renderer/layouts/default-layout/lyrics-overlay.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AnimatePresence, Variants, motion, useDragControls } from 'framer-motion';
import { useMemo, useRef } from 'react';
import { useMemo, useRef, useState } from 'react';
import { Variants, motion, useDragControls } from 'framer-motion';
import { Lyrics } from '/@/renderer/features/lyrics/lyrics';
import styled from 'styled-components';
import { Platform } from '/@/renderer/types';
Expand All @@ -21,6 +21,9 @@ export const LyricsOverlay = () => {
const dragControls = useDragControls();
const constraintsRef = useRef(null);
const { open, width } = useLyricsStore();
const lyricRef = useRef<HTMLDivElement>(null);

const [x, setX] = useState((document.body.clientWidth - width) / 2);

const variants: Variants = useMemo(
() => ({
Expand All @@ -29,14 +32,14 @@ export const LyricsOverlay = () => {
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
left: 'calc(50vw - 225px)',
position: 'absolute',
top: '75px',
transition: {
duration: 0.4,
ease: 'anticipate',
},
width,
x,
}),
open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
Expand All @@ -45,47 +48,45 @@ export const LyricsOverlay = () => {
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
transition: {
damping: 10,
delay: 0,
duration: 0.4,
ease: 'anticipate',
mass: 0.5,
},
width,
x,
zIndex: 121,
}),
}),
[width],
[width, x],
);

return (
<AnimatePresence
key="lyric-drawer"
presenceAffectsLayout
initial={false}
mode="sync"
>
{open && (
<LyricsContainer ref={constraintsRef}>
<LyricsDrawer
key="lyric-drawer"
dragListener
animate="open"
drag="x"
dragConstraints={constraintsRef}
dragControls={dragControls}
dragElastic={0}
dragMomentum={false}
exit="closed"
id="drawer-lyric"
initial="closed"
variants={variants}
>
<Lyrics />
</LyricsDrawer>
</LyricsContainer>
)}
</AnimatePresence>
open && (
<LyricsContainer
// This key is here to force rerender when lyric width changes. Otherwise
// the constraints are not updated properly
key={width}
ref={constraintsRef}
>
<LyricsDrawer
key="lyric-drawer"
ref={lyricRef}
dragListener
animate="open"
drag="x"
dragConstraints={constraintsRef}
dragControls={dragControls}
dragElastic={0}
dragMomentum={false}
exit="closed"
id="drawer-lyric"
initial="closed"
variants={variants}
onDragEnd={() => {
// bodge to save the current position, so that on resize
// window does not snap back to 0
setX(lyricRef.current!.getBoundingClientRect().x);
}}
>
<Lyrics />
</LyricsDrawer>
</LyricsContainer>
)
);
};
2 changes: 1 addition & 1 deletion src/renderer/store/app.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const useAppStore = create<AppSlice>()(
isReorderingQueue: false,
lyrics: {
open: false,
width: 450,
width: 525,
},
platform: Platform.WINDOWS,
sidebar: {
Expand Down

0 comments on commit 1f20cd7

Please sign in to comment.