improve BackgroundMediaPlayer

This commit is contained in:
SrGooglo 2023-04-04 23:51:31 +00:00
parent 8a53daa3fa
commit dedbe3d368
2 changed files with 326 additions and 137 deletions

View File

@ -1,123 +1,49 @@
import React from "react" import React from "react"
import Ticker from "react-ticker" import * as antd from "antd"
import { FastAverageColor } from "fast-average-color"
import classnames from "classnames" import classnames from "classnames"
import { Icons } from "components/Icons" import { Icons } from "components/Icons"
import Marquee from "react-fast-marquee"
import "./index.less" import "./index.less"
const useEventBus = (events) => { function RGBStringToValues(rgbString) {
const registerEvents = () => { if (!rgbString) {
for (const [event, handler] of Object.entries(events)) { return [0, 0, 0]
app.eventBus.on(event, handler)
}
} }
const unregisterEvents = () => { const rgb = rgbString.replace("rgb(", "").replace(")", "").split(",").map((v) => parseInt(v))
for (const [event, handler] of Object.entries(events)) {
app.eventBus.off(event, handler)
}
}
React.useEffect(() => { return [rgb[0], rgb[1], rgb[2]]
registerEvents()
return () => {
unregisterEvents()
}
}, [])
}
const fac = new FastAverageColor()
const bruh = (props) => {
const [thumbnailAnalysis, setThumbnailAnalysis] = React.useState("#000000")
const [currentPlaying, setCurrentPlaying] = React.useState(app.cores.player.getState("currentAudioManifest"))
const [plabackState, setPlaybackState] = React.useState(app.cores.player.getState("playbackStatus") ?? "stopped")
const onClickMinimize = () => {
app.cores.player.minimize()
}
const calculateAverageCoverColor = async () => {
if (currentPlaying) {
const color = await fac.getColorAsync(currentPlaying.thumbnail)
setThumbnailAnalysis(color)
updateBackgroundItem(color)
}
}
const updateBackgroundItem = () => {
app.SidebarController.updateBackgroundItem(undefined, {
icon: <Icons.MdMusicNote />,
style: {
backgroundColor: thumbnailAnalysis?.hex
}
})
}
useEventBus({
"player.current.update": (data) => {
console.log("player.current.update", data)
setCurrentPlaying(data)
updateBackgroundItem()
},
"player.playback.update": (data) => {
setPlaybackState(data)
updateBackgroundItem()
}
})
React.useEffect(() => {
calculateAverageCoverColor()
}, [currentPlaying])
React.useEffect(() => {
}, [])
return <div
className="background_media_player"
onClick={onClickMinimize}
>
{
currentPlaying && <div
className={classnames(
"background_media_player__title",
{
["lightBackground"]: thumbnailAnalysis.isLight,
}
)}
>
<h4>
{currentPlaying.title} - {currentPlaying.artist}
</h4>
</div>
}
</div>
} }
export default class BackgroundMediaPlayer extends React.Component { export default class BackgroundMediaPlayer extends React.Component {
state = { state = {
thumbnailAnalysis: null, thumbnailAnalysis: app.cores.player.getState("coverColorAnalysis"),
currentPlaying: app.cores.player.getState("currentAudioManifest"), currentPlaying: app.cores.player.getState("currentAudioManifest"),
plabackState: app.cores.player.getState("playbackStatus") ?? "stopped", plabackState: app.cores.player.getState("playbackStatus") ?? "stopped",
expanded: false,
} }
events = { events = {
"player.coverColorAnalysis.update": (data) => {
this.setState({
thumbnailAnalysis: data
})
},
"player.current.update": (data) => { "player.current.update": (data) => {
this.calculateAverageCoverColor()
this.setState({ this.setState({
currentPlaying: data currentPlaying: data
}) })
}, },
"player.playback.update": (data) => { "player.status.update": (data) => {
this.updateBackgroundItem()
this.setState({ this.setState({
plabackState: data plabackState: data
}) })
},
"sidebar.expanded": (to) => {
if (!to) {
this.toogleExpand(false)
}
} }
} }
@ -125,30 +51,17 @@ export default class BackgroundMediaPlayer extends React.Component {
app.cores.player.minimize() app.cores.player.minimize()
} }
calculateAverageCoverColor = async () => { toogleExpand = (to) => {
if (this.state.currentPlaying) { if (typeof to !== "boolean") {
const color = await fac.getColorAsync(this.state.currentPlaying.thumbnail) to = !this.state.expanded
this.setState({
thumbnailAnalysis: color
})
this.updateBackgroundItem(color)
} }
}
updateBackgroundItem = (analysis) => { this.setState({
app.SidebarController.updateBackgroundItem(undefined, { expanded: to
icon: <Icons.MdMusicNote />,
style: {
backgroundColor: analysis?.hex ?? this.state.thumbnailAnalysis?.hex,
}
}) })
} }
componentDidMount = async () => { componentDidMount = async () => {
this.calculateAverageCoverColor()
for (const [event, handler] of Object.entries(this.events)) { for (const [event, handler] of Object.entries(this.events)) {
app.eventBus.on(event, handler) app.eventBus.on(event, handler)
} }
@ -161,24 +74,113 @@ export default class BackgroundMediaPlayer extends React.Component {
} }
render() { render() {
return <div return <li
className="background_media_player" className={classnames(
onClick={this.onClickMinimize} "background_media_player",
{
["lightBackground"]: this.state.thumbnailAnalysis?.isLight,
["expanded"]: this.state.expanded,
}
)}
style={{
backgroundColor: this.state.thumbnailAnalysis?.rgba,
"--averageColorValues": this.state.thumbnailAnalysis?.rgba,
}}
> >
{ <div
this.state.currentPlaying && <div className="background_media_player__background"
style={{
backgroundImage: `url(${this.state.currentPlaying?.thumbnail})`
}}
/>
<div
className="background_media_player__row"
onClick={this.toogleExpand}
>
<div
id="sidebar_item_icon"
className={classnames( className={classnames(
"background_media_player__title", "background_media_player__icon",
{ {
["lightBackground"]: this.state.thumbnailAnalysis?.isLight, ["bounce"]: this.state.plabackState === "playing",
} }
)} )}
> >
<h4> {
{this.state.currentPlaying?.title} - {this.state.currentPlaying?.artist} this.state.plabackState === "playing" ? <Icons.MdMusicNote /> : <Icons.MdPause />
</h4> }
</div> </div>
}
</div> <div
id="sidebar_item_content"
className="background_media_player__title"
>
{
!this.state.expanded && <Marquee
gradientColor={RGBStringToValues(this.state.thumbnailAnalysis?.rgb)}
gradientWidth={20}
play={this.state.plabackState !== "stopped"}
>
<h4>
{
this.state.plabackState === "stopped" ? "Nothing is playing" : (this.state.currentPlaying?.title ?? "Untitled")
}
</h4>
</Marquee>
}
{
this.state.expanded && <h4>
<Icons.MdAlbum />
{
this.state.plabackState === "stopped" ? "Nothing is playing" : (this.state.currentPlaying?.title ?? "Untitled")
}
</h4>
}
</div>
</div>
<div
className={classnames(
"background_media_player__row",
"background_media_player__controls",
{
["hidden"]: !this.state.expanded,
}
)}
>
<antd.Button
size="small"
shape="rounded"
type="ghost"
icon={<Icons.ChevronLeft />}
onClick={app.cores.player.playback.previous}
/>
<antd.Button
size="small"
type="ghost"
shape="circle"
icon={this.state.plabackState === "playing" ? <Icons.MdPause /> : <Icons.MdPlayArrow />}
onClick={app.cores.player.playback.toogle}
/>
<antd.Button
size="small"
shape="rounded"
type="ghost"
icon={<Icons.ChevronRight />}
onClick={app.cores.player.playback.next}
/>
<antd.Button
size="small"
shape="rounded"
type="ghost"
icon={<Icons.Minimize />}
onClick={this.onClickMinimize}
/>
</div>
</li>
} }
} }

View File

@ -1,36 +1,223 @@
.background_media_player { .background_media_player {
overflow: hidden; position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%; width: 100%;
height: 40px;
padding: 10px;
overflow: hidden;
border-radius: 12px;
transition: all 150ms ease-in-out; transition: all 150ms ease-in-out;
.background_media_player__title { line-height: 40px;
overflow: hidden;
white-space: nowrap; color: var(--text-color-white);
width: 100%; background-repeat: no-repeat;
background-size: cover;
&.expanded {
height: 120px;
.background_media_player__background {
opacity: 0.4;
}
.background_media_player__icon {
width: 0;
opacity: 0;
}
.background_media_player__title {
padding: 10px 0;
h4 {
word-break: break-all;
word-wrap: break-word;
white-space: break-spaces;
font-size: 1rem;
}
}
.background_media_player__controls {
margin-top: 10px;
background-color: var(--text-color-white);
}
}
&.lightBackground {
color: var(--text-color-black);
.background_media_player__icon {
svg {
color: var(--text-color-black);
}
}
.background_media_player__title {
color: var(--text-color-black);
&.lightBackground {
h4 { h4 {
color: var(--text-color-black); color: var(--text-color-black);
} }
} }
h4 { .background_media_player__controls {
font-size: 1rem; color: var(--text-color-black);
font-weight: 600;
overflow: hidden; .ant-btn {
color: var(--text-color-black);
text-overflow: ellipsis; svg {
white-space: nowrap; color: var(--text-color-black);
}
}
}
}
font-family: "Space Grotesk", sans-serif; .background_media_player__background {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 12px;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
transition: all 150ms ease-in-out;
opacity: 0;
}
.background_media_player__row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
z-index: 350;
width: 100%;
&.hidden {
pointer-events: none;
opacity: 0;
height: 0;
}
}
.background_media_player__icon {
svg {
margin-right: 0 !important;
color: var(--text-color-white); color: var(--text-color-white);
} }
&.bounce {
animation: bounce 1s infinite;
}
}
.background_media_player__title {
max-height: 67px;
transition: all 150ms ease-in-out;
color: var(--text-color-white);
width: 100%;
overflow: hidden;
h4 {
line-height: 20px;
font-size: 0.8rem;
font-weight: 600;
margin: 0 0 0 10px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-family: "Space Grotesk", sans-serif;
color: var(--text-color-white);
}
.marquee-container {
width: 100%;
.overlay {
width: 100%;
}
}
}
.background_media_player__controls {
display: flex;
flex-direction: row;
align-self: flex-end;
align-items: center;
justify-content: space-evenly;
width: 100%;
color: var(--text-color-white);
background-color: var(--text-color-black);
border-radius: 12px;
opacity: 0.5;
.ant-btn {
color: var(--text-color-black);
background-color: transparent;
svg {
color: var(--text-color-black);
}
}
}
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-5px);
}
60% {
transform: translateY(-3px);
} }
} }