mirror of
https://github.com/ragestudio/comty.git
synced 2025-07-08 16:54:15 +00:00
Refactor Track menu logic into separate handlers and items files
This commit is contained in:
parent
d1b58d19fc
commit
843405dd15
@ -1,9 +1,10 @@
|
|||||||
import React from "react"
|
|
||||||
import * as antd from "antd"
|
import * as antd from "antd"
|
||||||
import classnames from "classnames"
|
import classnames from "classnames"
|
||||||
|
|
||||||
import { WithPlayerContext } from "@contexts/WithPlayerContext"
|
import {
|
||||||
import { Context as PlaylistContext } from "@contexts/WithPlaylistContext"
|
WithPlayerContext,
|
||||||
|
usePlayerStateContext,
|
||||||
|
} from "@contexts/WithPlayerContext"
|
||||||
|
|
||||||
import LoadMore from "@components/LoadMore"
|
import LoadMore from "@components/LoadMore"
|
||||||
import { Icons } from "@components/Icons"
|
import { Icons } from "@components/Icons"
|
||||||
@ -24,6 +25,8 @@ const TrackList = ({
|
|||||||
hasMore,
|
hasMore,
|
||||||
noHeader = false,
|
noHeader = false,
|
||||||
}) => {
|
}) => {
|
||||||
|
const [{ track_manifest, playback_status }] = usePlayerStateContext()
|
||||||
|
|
||||||
const showListHeader = !noHeader && (tracks.length > 0 || searchResults)
|
const showListHeader = !noHeader && (tracks.length > 0 || searchResults)
|
||||||
|
|
||||||
if (!searchResults && tracks.length === 0) {
|
if (!searchResults && tracks.length === 0) {
|
||||||
@ -62,7 +65,7 @@ const TrackList = ({
|
|||||||
key={item._id}
|
key={item._id}
|
||||||
order={item._id} // Consider using index if order matters
|
order={item._id} // Consider using index if order matters
|
||||||
track={item}
|
track={item}
|
||||||
onPlay={() => onTrackClick(item)}
|
onPlay={onTrackClick}
|
||||||
changeState={(update) =>
|
changeState={(update) =>
|
||||||
onTrackStateChange(item._id, update)
|
onTrackStateChange(item._id, update)
|
||||||
}
|
}
|
||||||
@ -76,19 +79,19 @@ const TrackList = ({
|
|||||||
onBottom={onLoadMore}
|
onBottom={onLoadMore}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
>
|
>
|
||||||
<WithPlayerContext>
|
{tracks.map((item, index) => (
|
||||||
{tracks.map((item, index) => (
|
<MusicTrack
|
||||||
<MusicTrack
|
key={item._id}
|
||||||
key={item._id} // Use unique ID for key
|
order={index + 1}
|
||||||
order={index + 1}
|
track={item}
|
||||||
track={item}
|
onPlay={onTrackClick}
|
||||||
onPlay={() => onTrackClick(item)}
|
isCurrent={item._id === track_manifest?._id}
|
||||||
changeState={(update) =>
|
isPlaying={
|
||||||
onTrackStateChange(item._id, update)
|
item._id === track_manifest?._id &&
|
||||||
}
|
playback_status === "playing"
|
||||||
/>
|
}
|
||||||
))}
|
/>
|
||||||
</WithPlayerContext>
|
))}
|
||||||
</LoadMore>
|
</LoadMore>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,14 +2,13 @@ import React from "react"
|
|||||||
import * as antd from "antd"
|
import * as antd from "antd"
|
||||||
import classnames from "classnames"
|
import classnames from "classnames"
|
||||||
|
|
||||||
import RGBStringToValues from "@utils/rgbToValues"
|
|
||||||
|
|
||||||
import ImageViewer from "@components/ImageViewer"
|
import ImageViewer from "@components/ImageViewer"
|
||||||
import { Icons } from "@components/Icons"
|
import { Icons } from "@components/Icons"
|
||||||
|
|
||||||
import MusicModel from "@models/music"
|
import MenuItemsBase from "./menuItems"
|
||||||
|
import MenuHandlers from "./menuHandlers"
|
||||||
|
|
||||||
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
|
import RGBStringToValues from "@utils/rgbToValues"
|
||||||
import { Context as PlaylistContext } from "@contexts/WithPlaylistContext"
|
import { Context as PlaylistContext } from "@contexts/WithPlaylistContext"
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
@ -22,128 +21,18 @@ function secondsToIsoTime(seconds) {
|
|||||||
.padStart(2, "0")}`
|
.padStart(2, "0")}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlers = {
|
const Track = React.memo((props) => {
|
||||||
like: async (ctx, track) => {
|
|
||||||
await MusicModel.toggleItemFavourite("track", track._id, true)
|
|
||||||
|
|
||||||
ctx.changeState({
|
|
||||||
liked: true,
|
|
||||||
})
|
|
||||||
ctx.closeMenu()
|
|
||||||
},
|
|
||||||
unlike: async (ctx, track) => {
|
|
||||||
await MusicModel.toggleItemFavourite("track", track._id, false)
|
|
||||||
|
|
||||||
ctx.changeState({
|
|
||||||
liked: false,
|
|
||||||
})
|
|
||||||
ctx.closeMenu()
|
|
||||||
},
|
|
||||||
add_to_playlist: async (ctx, track) => {},
|
|
||||||
add_to_queue: async (ctx, track) => {
|
|
||||||
await app.cores.player.queue.add(track)
|
|
||||||
},
|
|
||||||
play_next: async (ctx, track) => {
|
|
||||||
await app.cores.player.queue.add(track, { next: true })
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const Track = (props) => {
|
|
||||||
const [{ loading, track_manifest, playback_status }] =
|
|
||||||
usePlayerStateContext()
|
|
||||||
|
|
||||||
const playlist_ctx = React.useContext(PlaylistContext)
|
const playlist_ctx = React.useContext(PlaylistContext)
|
||||||
|
|
||||||
const [moreMenuOpened, setMoreMenuOpened] = React.useState(false)
|
const [moreMenuOpened, setMoreMenuOpened] = React.useState(false)
|
||||||
|
const [liked, setLiked] = React.useState(props.track.liked)
|
||||||
|
|
||||||
const isCurrent = track_manifest?._id === props.track._id
|
const trackDuration = React.useMemo(() => {
|
||||||
const isPlaying = isCurrent && playback_status === "playing"
|
return props.track?.metadata?.duration ?? props.track?.duration
|
||||||
|
}, [props.track])
|
||||||
|
|
||||||
const handleClickPlayBtn = () => {
|
const menuItems = React.useMemo(() => {
|
||||||
if (typeof props.onPlay === "function") {
|
const items = [...MenuItemsBase]
|
||||||
return props.onPlay(props.track)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof props.onClickPlayBtn === "function") {
|
|
||||||
props.onClickPlayBtn(props.track)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isCurrent) {
|
|
||||||
app.cores.player.start(props.track)
|
|
||||||
} else {
|
|
||||||
app.cores.player.playback.toggle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOnClickItem = React.useCallback(() => {
|
|
||||||
if (props.onClick) {
|
|
||||||
props.onClick(props.track)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app.isMobile) {
|
|
||||||
handleClickPlayBtn()
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleMoreMenuOpen = React.useCallback(() => {
|
|
||||||
if (app.isMobile) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return setMoreMenuOpened((prev) => {
|
|
||||||
return !prev
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleMoreMenuItemClick = React.useCallback((e) => {
|
|
||||||
const { key } = e
|
|
||||||
|
|
||||||
if (typeof handlers[key] === "function") {
|
|
||||||
return handlers[key](
|
|
||||||
{
|
|
||||||
closeMenu: () => {
|
|
||||||
setMoreMenuOpened(false)
|
|
||||||
},
|
|
||||||
changeState: props.changeState,
|
|
||||||
},
|
|
||||||
props.track,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const moreMenuItems = React.useMemo(() => {
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
key: "like",
|
|
||||||
icon: <Icons.MdFavorite />,
|
|
||||||
label: "Like",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "share",
|
|
||||||
icon: <Icons.MdShare />,
|
|
||||||
label: "Share",
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "add_to_playlist",
|
|
||||||
icon: <Icons.MdPlaylistAdd />,
|
|
||||||
label: "Add to playlist",
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "divider",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "add_to_queue",
|
|
||||||
icon: <Icons.MdQueueMusic />,
|
|
||||||
label: "Add to queue",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "play_next",
|
|
||||||
icon: <Icons.MdSkipNext />,
|
|
||||||
label: "Play next",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
if (props.track.liked) {
|
if (props.track.liked) {
|
||||||
items[0] = {
|
items[0] = {
|
||||||
@ -170,22 +59,68 @@ const Track = (props) => {
|
|||||||
return items
|
return items
|
||||||
}, [props.track])
|
}, [props.track])
|
||||||
|
|
||||||
const trackDuration =
|
const handleClickPlayBtn = React.useCallback(() => {
|
||||||
props.track?.metadata?.duration ?? props.track?.duration
|
if (typeof props.onPlay === "function") {
|
||||||
|
return props.onPlay(props.track)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof props.onClickPlayBtn === "function") {
|
||||||
|
props.onClickPlayBtn(props.track)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.isCurrent) {
|
||||||
|
app.cores.player.start(props.track)
|
||||||
|
} else {
|
||||||
|
app.cores.player.playback.toggle()
|
||||||
|
}
|
||||||
|
}, [props.isCurrent])
|
||||||
|
|
||||||
|
const handleOnClickItem = React.useCallback(() => {
|
||||||
|
if (props.onClick) {
|
||||||
|
props.onClick(props.track)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app.isMobile) {
|
||||||
|
handleClickPlayBtn()
|
||||||
|
}
|
||||||
|
}, [props.track])
|
||||||
|
|
||||||
|
const handleMoreMenuOpen = React.useCallback(() => {
|
||||||
|
if (app.isMobile) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return setMoreMenuOpened((prev) => {
|
||||||
|
return !prev
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleMoreMenuItemClick = React.useCallback(
|
||||||
|
(e) => {
|
||||||
|
const { key } = e
|
||||||
|
|
||||||
|
if (typeof MenuHandlers[key] === "function") {
|
||||||
|
return MenuHandlers[key](
|
||||||
|
{
|
||||||
|
close: () => {
|
||||||
|
setMoreMenuOpened(false)
|
||||||
|
},
|
||||||
|
setLiked: setLiked,
|
||||||
|
},
|
||||||
|
props.track,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[props.track],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id={props.track._id}
|
id={props.track._id}
|
||||||
className={classnames("music-track", {
|
className={classnames("music-track", {
|
||||||
["current"]: isCurrent,
|
["current"]: props.isCurrent,
|
||||||
["playing"]: isPlaying,
|
["playing"]: props.isPlaying,
|
||||||
["loading"]: isCurrent && loading,
|
|
||||||
})}
|
})}
|
||||||
style={{
|
|
||||||
"--cover_average-color": RGBStringToValues(
|
|
||||||
track_manifest?.cover_analysis?.rgb,
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="music-track_background" />
|
<div className="music-track_background" />
|
||||||
|
|
||||||
@ -204,7 +139,7 @@ const Track = (props) => {
|
|||||||
type="primary"
|
type="primary"
|
||||||
shape="circle"
|
shape="circle"
|
||||||
icon={
|
icon={
|
||||||
isPlaying ? (
|
props.isPlaying ? (
|
||||||
<Icons.MdPause />
|
<Icons.MdPause />
|
||||||
) : (
|
) : (
|
||||||
<Icons.MdPlayArrow />
|
<Icons.MdPlayArrow />
|
||||||
@ -212,14 +147,6 @@ const Track = (props) => {
|
|||||||
}
|
}
|
||||||
onClick={handleClickPlayBtn}
|
onClick={handleClickPlayBtn}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* {props.track?.metadata?.duration && (
|
|
||||||
<div className="music-track_play_duration">
|
|
||||||
{secondsToIsoTime(
|
|
||||||
props.track.metadata.duration,
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -267,7 +194,7 @@ const Track = (props) => {
|
|||||||
|
|
||||||
<antd.Dropdown
|
<antd.Dropdown
|
||||||
menu={{
|
menu={{
|
||||||
items: moreMenuItems,
|
items: menuItems,
|
||||||
onClick: handleMoreMenuItemClick,
|
onClick: handleMoreMenuItemClick,
|
||||||
}}
|
}}
|
||||||
onOpenChange={handleMoreMenuOpen}
|
onOpenChange={handleMoreMenuOpen}
|
||||||
@ -281,6 +208,8 @@ const Track = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
Track.displayName = "Track"
|
||||||
|
|
||||||
export default Track
|
export default Track
|
||||||
|
31
packages/app/src/components/Music/Track/menuHandlers.js
Normal file
31
packages/app/src/components/Music/Track/menuHandlers.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import MusicModel from "@models/music"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
like: async (ctx, track) => {
|
||||||
|
await MusicModel.toggleItemFavourite("track", track._id, true)
|
||||||
|
|
||||||
|
ctx.changeState({
|
||||||
|
liked: true,
|
||||||
|
})
|
||||||
|
ctx.close()
|
||||||
|
},
|
||||||
|
unlike: async (ctx, track) => {
|
||||||
|
await MusicModel.toggleItemFavourite("track", track._id, false)
|
||||||
|
|
||||||
|
ctx.changeState({
|
||||||
|
liked: false,
|
||||||
|
})
|
||||||
|
ctx.close()
|
||||||
|
},
|
||||||
|
add_to_playlist: async (ctx, track) => {},
|
||||||
|
add_to_queue: async (ctx, track) => {
|
||||||
|
await app.cores.player.queue.add(track)
|
||||||
|
},
|
||||||
|
play_next: async (ctx, track) => {
|
||||||
|
await app.cores.player.queue.add(track, { next: true })
|
||||||
|
},
|
||||||
|
copy_id: (ctx, track) => {
|
||||||
|
console.log("copy_id", track)
|
||||||
|
navigator.clipboard.writeText(track._id)
|
||||||
|
},
|
||||||
|
}
|
42
packages/app/src/components/Music/Track/menuItems.jsx
Normal file
42
packages/app/src/components/Music/Track/menuItems.jsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Icons } from "@components/Icons"
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
key: "like",
|
||||||
|
icon: <Icons.MdFavorite />,
|
||||||
|
label: "Like",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "share",
|
||||||
|
icon: <Icons.MdShare />,
|
||||||
|
label: "Share",
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "add_to_playlist",
|
||||||
|
icon: <Icons.MdPlaylistAdd />,
|
||||||
|
label: "Add to playlist",
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "divider",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "add_to_queue",
|
||||||
|
icon: <Icons.MdQueueMusic />,
|
||||||
|
label: "Add to queue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "play_next",
|
||||||
|
icon: <Icons.MdSkipNext />,
|
||||||
|
label: "Play next",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "divider",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "copy_id",
|
||||||
|
icon: <Icons.MdLink />,
|
||||||
|
label: "Copy ID",
|
||||||
|
},
|
||||||
|
]
|
Loading…
x
Reference in New Issue
Block a user