Skip to content

Commit

Permalink
[feat] Add a dynamic image option to the fullscreen player (#526)
Browse files Browse the repository at this point in the history
* Add an option for a dynamic background image in the fullscreen player

* Center the background image and fix some more bugs

* More cleaning up the background image

* Add option for customizable blur amount

* Fix missing translation key for image blur

* Fix dynamic image shifting when player is opened

* Hide image blur size config if dynamic background is disabled

---------

Co-authored-by: Jeff <[email protected]>
  • Loading branch information
iiPythonx and jeffvli authored Mar 5, 2024
1 parent a45e7f2 commit d52d913
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@
"fullscreenPlayer": {
"config": {
"dynamicBackground": "dynamic background",
"dynamicImageBlur": "image blur size",
"dynamicIsImage": "enable background image",
"followCurrentLyric": "follow current lyric",
"lyricAlignment": "lyric alignment",
"lyricGap": "lyric gap",
Expand Down
78 changes: 70 additions & 8 deletions src/renderer/features/player/components/full-screen-player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,33 @@ const ResponsiveContainer = styled.div`
}
`;

const BackgroundImageOverlay = styled.div`
interface BackgroundImageOverlayProps {
$blur: number;
}

const BackgroundImageOverlay = styled.div<BackgroundImageOverlayProps>`
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
background: var(--bg-header-overlay);
backdrop-filter: blur(${({ $blur }) => $blur}rem);
`;

const mainBackground = 'var(--main-bg)';

const Controls = () => {
const { t } = useTranslation();
const { dynamicBackground, expanded, opacity, useImageAspectRatio } =
useFullScreenPlayerStore();
const {
dynamicBackground,
dynamicImageBlur,
dynamicIsImage,
expanded,
opacity,
useImageAspectRatio,
} = useFullScreenPlayerStore();
const { setStore } = useFullScreenPlayerStoreActions();
const { setSettings } = useSettingsStoreActions();
const lyricConfig = useLyricsSettings();
Expand Down Expand Up @@ -141,6 +154,45 @@ const Controls = () => {
/>
</Option.Control>
</Option>
{dynamicBackground && (
<Option>
<Option.Label>
{t('page.fullscreenPlayer.config.dynamicIsImage', {
postProcess: 'sentenceCase',
})}
</Option.Label>
<Option.Control>
<Switch
defaultChecked={dynamicIsImage}
onChange={(e) =>
setStore({
dynamicIsImage: e.target.checked,
})
}
/>
</Option.Control>
</Option>
)}
{dynamicBackground && dynamicIsImage && (
<Option>
<Option.Label>
{t('page.fullscreenPlayer.config.dynamicImageBlur', {
postProcess: 'sentenceCase',
})}
</Option.Label>
<Option.Control>
<Slider
defaultValue={dynamicImageBlur}
label={(e) => `${e} rem`}
max={6}
min={0}
step={0.5}
w="100%"
onChangeEnd={(e) => setStore({ dynamicImageBlur: Number(e) })}
/>
</Option.Control>
</Option>
)}
{dynamicBackground && (
<Option>
<Option.Label>
Expand Down Expand Up @@ -368,9 +420,13 @@ const containerVariants: Variants = {
};
},
open: (custom) => {
const { dynamicBackground, background, windowBarStyle } = custom;
const { background, backgroundImage, dynamicBackground, windowBarStyle } = custom;
return {
background: dynamicBackground ? background : 'var(--main-bg)',
background: dynamicBackground ? backgroundImage : mainBackground,
backgroundColor: dynamicBackground ? background : mainBackground,
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
height:
windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS
? 'calc(100vh - 120px)'
Expand All @@ -394,7 +450,7 @@ const containerVariants: Variants = {
};

export const FullScreenPlayer = () => {
const { dynamicBackground } = useFullScreenPlayerStore();
const { dynamicBackground, dynamicImageBlur, dynamicIsImage } = useFullScreenPlayerStore();
const { setStore } = useFullScreenPlayerStoreActions();
const { windowBarStyle } = useWindowSettings();

Expand All @@ -416,17 +472,23 @@ export const FullScreenPlayer = () => {
srcLoaded: true,
});

const imageUrl = currentSong?.imageUrl;
const backgroundImage =
imageUrl && dynamicIsImage
? `url("${imageUrl.replace(/size=\d+/g, 'size=500')}`
: mainBackground;

return (
<Container
animate="open"
custom={{ background, dynamicBackground, windowBarStyle }}
custom={{ background, backgroundImage, dynamicBackground, windowBarStyle }}
exit="closed"
initial="closed"
transition={{ duration: 2 }}
variants={containerVariants}
>
<Controls />
{dynamicBackground && <BackgroundImageOverlay />}
{dynamicBackground && <BackgroundImageOverlay $blur={dynamicImageBlur} />}
<ResponsiveContainer>
<FullScreenPlayerImage />
<FullScreenPlayerQueue />
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/store/full-screen-player.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { immer } from 'zustand/middleware/immer';
interface FullScreenPlayerState {
activeTab: string | 'queue' | 'related' | 'lyrics';
dynamicBackground?: boolean;
dynamicImageBlur: number;
dynamicIsImage?: boolean;
expanded: boolean;
opacity: number;
useImageAspectRatio: boolean;
Expand All @@ -28,6 +30,8 @@ export const useFullScreenPlayerStore = create<FullScreenPlayerSlice>()(
},
activeTab: 'queue',
dynamicBackground: true,
dynamicImageBlur: 1.5,
dynamicIsImage: false,
expanded: false,
opacity: 60,
useImageAspectRatio: false,
Expand Down

0 comments on commit d52d913

Please sign in to comment.