mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
improve BackgroundMediaPlayer
This commit is contained in:
parent
8a53daa3fa
commit
dedbe3d368
@ -1,123 +1,49 @@
|
||||
import React from "react"
|
||||
import Ticker from "react-ticker"
|
||||
import { FastAverageColor } from "fast-average-color"
|
||||
import * as antd from "antd"
|
||||
import classnames from "classnames"
|
||||
import { Icons } from "components/Icons"
|
||||
import Marquee from "react-fast-marquee"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const useEventBus = (events) => {
|
||||
const registerEvents = () => {
|
||||
for (const [event, handler] of Object.entries(events)) {
|
||||
app.eventBus.on(event, handler)
|
||||
}
|
||||
function RGBStringToValues(rgbString) {
|
||||
if (!rgbString) {
|
||||
return [0, 0, 0]
|
||||
}
|
||||
|
||||
const unregisterEvents = () => {
|
||||
for (const [event, handler] of Object.entries(events)) {
|
||||
app.eventBus.off(event, handler)
|
||||
}
|
||||
}
|
||||
const rgb = rgbString.replace("rgb(", "").replace(")", "").split(",").map((v) => parseInt(v))
|
||||
|
||||
React.useEffect(() => {
|
||||
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>
|
||||
return [rgb[0], rgb[1], rgb[2]]
|
||||
}
|
||||
|
||||
export default class BackgroundMediaPlayer extends React.Component {
|
||||
state = {
|
||||
thumbnailAnalysis: null,
|
||||
thumbnailAnalysis: app.cores.player.getState("coverColorAnalysis"),
|
||||
currentPlaying: app.cores.player.getState("currentAudioManifest"),
|
||||
plabackState: app.cores.player.getState("playbackStatus") ?? "stopped",
|
||||
expanded: false,
|
||||
}
|
||||
|
||||
events = {
|
||||
"player.coverColorAnalysis.update": (data) => {
|
||||
this.setState({
|
||||
thumbnailAnalysis: data
|
||||
})
|
||||
},
|
||||
"player.current.update": (data) => {
|
||||
this.calculateAverageCoverColor()
|
||||
|
||||
this.setState({
|
||||
currentPlaying: data
|
||||
})
|
||||
},
|
||||
"player.playback.update": (data) => {
|
||||
this.updateBackgroundItem()
|
||||
|
||||
"player.status.update": (data) => {
|
||||
this.setState({
|
||||
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()
|
||||
}
|
||||
|
||||
calculateAverageCoverColor = async () => {
|
||||
if (this.state.currentPlaying) {
|
||||
const color = await fac.getColorAsync(this.state.currentPlaying.thumbnail)
|
||||
|
||||
this.setState({
|
||||
thumbnailAnalysis: color
|
||||
})
|
||||
|
||||
this.updateBackgroundItem(color)
|
||||
toogleExpand = (to) => {
|
||||
if (typeof to !== "boolean") {
|
||||
to = !this.state.expanded
|
||||
}
|
||||
}
|
||||
|
||||
updateBackgroundItem = (analysis) => {
|
||||
app.SidebarController.updateBackgroundItem(undefined, {
|
||||
icon: <Icons.MdMusicNote />,
|
||||
style: {
|
||||
backgroundColor: analysis?.hex ?? this.state.thumbnailAnalysis?.hex,
|
||||
}
|
||||
this.setState({
|
||||
expanded: to
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount = async () => {
|
||||
this.calculateAverageCoverColor()
|
||||
|
||||
for (const [event, handler] of Object.entries(this.events)) {
|
||||
app.eventBus.on(event, handler)
|
||||
}
|
||||
@ -161,24 +74,113 @@ export default class BackgroundMediaPlayer extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div
|
||||
className="background_media_player"
|
||||
onClick={this.onClickMinimize}
|
||||
return <li
|
||||
className={classnames(
|
||||
"background_media_player",
|
||||
{
|
||||
["lightBackground"]: this.state.thumbnailAnalysis?.isLight,
|
||||
["expanded"]: this.state.expanded,
|
||||
}
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: this.state.thumbnailAnalysis?.rgba,
|
||||
"--averageColorValues": this.state.thumbnailAnalysis?.rgba,
|
||||
}}
|
||||
>
|
||||
{
|
||||
this.state.currentPlaying && <div
|
||||
<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(
|
||||
"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}
|
||||
</h4>
|
||||
{
|
||||
this.state.plabackState === "playing" ? <Icons.MdMusicNote /> : <Icons.MdPause />
|
||||
}
|
||||
</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>
|
||||
}
|
||||
}
|
@ -1,36 +1,223 @@
|
||||
.background_media_player {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
|
||||
padding: 10px;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
border-radius: 12px;
|
||||
|
||||
transition: all 150ms ease-in-out;
|
||||
|
||||
.background_media_player__title {
|
||||
overflow: hidden;
|
||||
line-height: 40px;
|
||||
|
||||
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 {
|
||||
color: var(--text-color-black);
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
.background_media_player__controls {
|
||||
color: var(--text-color-black);
|
||||
|
||||
overflow: hidden;
|
||||
.ant-btn {
|
||||
color: var(--text-color-black);
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
svg {
|
||||
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);
|
||||
}
|
||||
|
||||
&.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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user