diff --git a/packages/app/src/components/Music/PlaylistView/list.jsx b/packages/app/src/components/Music/PlaylistView/list.jsx
index 9fcfe14d..58dd0561 100644
--- a/packages/app/src/components/Music/PlaylistView/list.jsx
+++ b/packages/app/src/components/Music/PlaylistView/list.jsx
@@ -1,9 +1,10 @@
-import React from "react"
import * as antd from "antd"
import classnames from "classnames"
-import { WithPlayerContext } from "@contexts/WithPlayerContext"
-import { Context as PlaylistContext } from "@contexts/WithPlaylistContext"
+import {
+ WithPlayerContext,
+ usePlayerStateContext,
+} from "@contexts/WithPlayerContext"
import LoadMore from "@components/LoadMore"
import { Icons } from "@components/Icons"
@@ -24,6 +25,8 @@ const TrackList = ({
hasMore,
noHeader = false,
}) => {
+ const [{ track_manifest, playback_status }] = usePlayerStateContext()
+
const showListHeader = !noHeader && (tracks.length > 0 || searchResults)
if (!searchResults && tracks.length === 0) {
@@ -62,7 +65,7 @@ const TrackList = ({
key={item._id}
order={item._id} // Consider using index if order matters
track={item}
- onPlay={() => onTrackClick(item)}
+ onPlay={onTrackClick}
changeState={(update) =>
onTrackStateChange(item._id, update)
}
@@ -76,19 +79,19 @@ const TrackList = ({
onBottom={onLoadMore}
hasMore={hasMore}
>
-
- {tracks.map((item, index) => (
- onTrackClick(item)}
- changeState={(update) =>
- onTrackStateChange(item._id, update)
- }
- />
- ))}
-
+ {tracks.map((item, index) => (
+
+ ))}
)}
diff --git a/packages/app/src/components/Music/Track/index.jsx b/packages/app/src/components/Music/Track/index.jsx
index 439e65d7..179879b3 100755
--- a/packages/app/src/components/Music/Track/index.jsx
+++ b/packages/app/src/components/Music/Track/index.jsx
@@ -2,14 +2,13 @@ import React from "react"
import * as antd from "antd"
import classnames from "classnames"
-import RGBStringToValues from "@utils/rgbToValues"
-
import ImageViewer from "@components/ImageViewer"
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 "./index.less"
@@ -22,128 +21,18 @@ function secondsToIsoTime(seconds) {
.padStart(2, "0")}`
}
-const handlers = {
- 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 Track = React.memo((props) => {
const playlist_ctx = React.useContext(PlaylistContext)
const [moreMenuOpened, setMoreMenuOpened] = React.useState(false)
+ const [liked, setLiked] = React.useState(props.track.liked)
- const isCurrent = track_manifest?._id === props.track._id
- const isPlaying = isCurrent && playback_status === "playing"
+ const trackDuration = React.useMemo(() => {
+ return props.track?.metadata?.duration ?? props.track?.duration
+ }, [props.track])
- const handleClickPlayBtn = () => {
- if (typeof props.onPlay === "function") {
- 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: ,
- label: "Like",
- },
- {
- key: "share",
- icon: ,
- label: "Share",
- disabled: true,
- },
- {
- key: "add_to_playlist",
- icon: ,
- label: "Add to playlist",
- disabled: true,
- },
- {
- type: "divider",
- },
- {
- key: "add_to_queue",
- icon: ,
- label: "Add to queue",
- },
- {
- key: "play_next",
- icon: ,
- label: "Play next",
- },
- ]
+ const menuItems = React.useMemo(() => {
+ const items = [...MenuItemsBase]
if (props.track.liked) {
items[0] = {
@@ -170,22 +59,68 @@ const Track = (props) => {
return items
}, [props.track])
- const trackDuration =
- props.track?.metadata?.duration ?? props.track?.duration
+ const handleClickPlayBtn = React.useCallback(() => {
+ 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 (
@@ -204,7 +139,7 @@ const Track = (props) => {
type="primary"
shape="circle"
icon={
- isPlaying ? (
+ props.isPlaying ? (
) : (
@@ -212,14 +147,6 @@ const Track = (props) => {
}
onClick={handleClickPlayBtn}
/>
-
- {/* {props.track?.metadata?.duration && (
-
- {secondsToIsoTime(
- props.track.metadata.duration,
- )}
-
- )} */}
)}
@@ -267,7 +194,7 @@ const Track = (props) => {
{
)
-}
+})
+
+Track.displayName = "Track"
export default Track
diff --git a/packages/app/src/components/Music/Track/menuHandlers.js b/packages/app/src/components/Music/Track/menuHandlers.js
new file mode 100644
index 00000000..5dd7ede3
--- /dev/null
+++ b/packages/app/src/components/Music/Track/menuHandlers.js
@@ -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)
+ },
+}
diff --git a/packages/app/src/components/Music/Track/menuItems.jsx b/packages/app/src/components/Music/Track/menuItems.jsx
new file mode 100644
index 00000000..1a53cc2e
--- /dev/null
+++ b/packages/app/src/components/Music/Track/menuItems.jsx
@@ -0,0 +1,42 @@
+import { Icons } from "@components/Icons"
+
+export default [
+ {
+ key: "like",
+ icon: ,
+ label: "Like",
+ },
+ {
+ key: "share",
+ icon: ,
+ label: "Share",
+ disabled: true,
+ },
+ {
+ key: "add_to_playlist",
+ icon: ,
+ label: "Add to playlist",
+ disabled: true,
+ },
+ {
+ type: "divider",
+ },
+ {
+ key: "add_to_queue",
+ icon: ,
+ label: "Add to queue",
+ },
+ {
+ key: "play_next",
+ icon: ,
+ label: "Play next",
+ },
+ {
+ type: "divider",
+ },
+ {
+ key: "copy_id",
+ icon: ,
+ label: "Copy ID",
+ },
+]