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", + }, +]