diff --git a/.env b/.env index 5d987f52..6b567301 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -REACT_APP_DATABASE='http://localhost:3000/' +REACT_APP_DATABASE='http://localhost:3001/' REACT_APP_RECAPTCHA_SITE_KEY='6LcZ-kkqAAAAAFdmy2tD1gKFdjxb0D71w5VMaisr' \ No newline at end of file diff --git a/README.md b/README.md index 2722308a..2d661d05 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,6 @@ # PromoCursed +## Курсовая работа -ВАЖНАЯ ИНФОРМАЦИЯ!!! +### Описание -По какой-то причине при передаче объекта песни в CurrentTrack и получение свойств объекта в этом компонента -появляются ошибки. Их не было до какого-то момента, но я не успел к сроку выявить причины (я долго дебажил), -но результата это не принесло. До сих пор причины для меня остаются, к сожалению, загадкой... - -Что было добавлено/исправлено после очной демонстрации: - -1. Компоненты были раскиданы по папкам -2. Переименовал некоторые папки (например, API), -3. Добавил новые компоненты -4. Роутинг и страницы -5. Валидация форм - -Должен был добавить плеер с воспроизведением песен, но из-за ошибок, про которые я написал выше, не удалось. -Пришлось жестко передать объект песни прямо в коде компонента. \ No newline at end of file +Веб-приложение для прослушивания музыки. diff --git a/data.json b/data.json index 11f186e1..11360b0f 100644 --- a/data.json +++ b/data.json @@ -7,7 +7,7 @@ "band_name": "Nevroz", "albumid": "1", "album_name": "Album 1", - "source": "/src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3", + "source": "http://localhost:3001/songs_sources/nirvana.mp3", "cover": "https://cdn1.ozone.ru/s3/multimedia-t/6893834213.jpg", "playlists": [ "1", @@ -23,8 +23,8 @@ "band_name": "Nevroz", "albumid": "1", "album_name": "Album 1", - "source": "/src/songs/Blur_-_Song_2_47967381.mp3", - "cover": "https://cdn1.ozone.ru/s3/multimedia-t/6893834213.jpg", + "source": "http://localhost:3001/songs_sources/blur.mp3", + "cover": "https://lastfm.freetls.fastly.net/i/u/ar0/101e39a435244b05cbf9d3af6ddf8c74.jpg", "playlists": [ "2" ], @@ -38,7 +38,7 @@ "band_name": "noizemchik", "albumid": "2", "album_name": "Ругань из-за Стёпы", - "source": "/src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3", + "source": "http://localhost:3001/songs_sources/noizemc.mp3", "cover": "https://sun9-11.userapi.com/impg/yfCwuWXI6NkFVC2HvMlegM2qWLlenkeiiRyvNQ/jpH8m1wlLqs.jpg?size=604x604&quality=95&sign=60a1d1877b49631fb6078db88715fc88&c_uniq_tag=UKrig2vg02reyBH_ML0OKeqt5gm_2jpwEXD7NJBUXoQ&type=album" , "playlists": [ @@ -49,15 +49,15 @@ }, { "id": "4", - "song_name": "Crazy Frog", - "band_id": "3", + "song_name": "Хот вилз", + "band_id": "1", "band_name": "DSPD", - "albumid": "3", - "album_name": "Album 3", - "source": "/src/songs/DSPD_-_Crazy_Frog_75801748.mp3", + "albumid": "1", + "album_name": "Album 1", + "source": "http://localhost:3001/songs_sources/hotweelz.mp3", "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh", "playlists": [ - "2", "3" + "1", "2" ], "genreid": "1", "genre_name": "Rock" @@ -69,8 +69,8 @@ "band_name": "DSPD", "albumid": "3", "album_name": "Album 3", - "source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3", - "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh", + "source": "http://localhost:3001/songs_sources/kemstal.mp3", + "cover": "https://avatars.yandex.net/get-music-content/6058982/7e431a83.a.23910092-1/m1000x1000?webp=false", "playlists": [ "3" ], @@ -79,28 +79,29 @@ }, { "id": "6", - "song_name": "Smells Like Poop", - "band_id": "1", - "band_name": "Nevroz", - "albumid": "1", - "album_name": "Album 1", - "source": "/src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3", - "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh", + "song_name": "American Idiotus", + "band_id": "3", + "band_name": "Red Day", + "albumid": "3", + "album_name": "Album 3", + "source": "http://localhost:3001/songs_sources/greenday.mp3", + "cover": "https://avatars.yandex.net/get-music-content/32236/d3846188.a.1001691-1/m1000x1000?webp=false", "playlists": [ - "1", "2" + "2", "3" ], "genreid": "1", "genre_name": "Rock" + }, { "id": "7", - "song_name": "Song 3", + "song_name": "Ulyanofication'", "band_id": "1", - "band_name": "Nevroz", + "band_name": "Yellow Warm Russian Tomatoes", "albumid": "1", "album_name": "Album 1", - "source": "/src/songs/Blur_-_Song_2_47967381.mp3", - "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh", + "source": "http://localhost:3001/songs_sources/pepers.mp3", + "cover": "https://avatars.mds.yandex.net/i?id=8d01018aa8cac0da9845314da42e050ab8e61713-12569754-images-thumbs&n=13", "playlists": [ "2" ], @@ -109,13 +110,13 @@ }, { "id": "8", - "song_name": "Ругань из-за Стёпы", + "song_name": "СУМАСШЕДШИЙ ПОЕЗД!!!!", "band_id": "2", - "band_name": "noizemchik", + "band_name": "СТАРИНА ОЗЗИ ОЗБОРН (МУЗЫКА ДЬЯВОЛА)", "albumid": "2", "album_name": "Ругань из-за Стёпы", - "source": "/src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3", - "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh" + "source": "http://localhost:3001/songs_sources/ozzy.mp3", + "cover": "https://avatars.mds.yandex.net/i?id=95adb2fda305e542621b7d9757d70ddd_l-4937470-images-thumbs&n=13" , "playlists": [ "1", "3" @@ -125,13 +126,13 @@ }, { "id": "9", - "song_name": "Crazy Frog", + "song_name": "Downstairs to Heaven", "band_id": "3", - "band_name": "DSPD", + "band_name": "Эйси Диси", "albumid": "3", "album_name": "Album 3", - "source": "/src/songs/DSPD_-_Crazy_Frog_75801748.mp3", - "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh", + "source": "http://localhost:3001/songs_sources/acdc.mp3", + "cover": "https://avatars.mds.yandex.net/get-entity_search/509339/292583724/S600xU", "playlists": [ "2", "3" ], @@ -140,13 +141,13 @@ }, { "id": "10", - "song_name": "Кем я стал", + "song_name": "Ай воз мэйд фор лавин ю беби", "band_id": "3", - "band_name": "DSPD", + "band_name": "KISS", "albumid": "3", "album_name": "Album 3", - "source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3", - "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh", + "source": "http://localhost:3001/songs_sources/kiss.mp3", + "cover": "https://avatars.dzeninfra.ru/get-zen_doc/10073791/pub_64ab1cf9ec43747a7a73a3e0_64ab1d726ba4132c8f8b37b6/scale_1200", "playlists": [ "3" ], @@ -160,7 +161,7 @@ "band_name": "DSPD", "albumid": "3", "album_name": "Album 3", - "source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3", + "source": "http://localhost:3001/songs_sources/kemstal.mp3", "cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh", "playlists": [ "3" @@ -506,4 +507,4 @@ } ] -} \ No newline at end of file +} diff --git a/package.json b/package.json index 94425e82..07137a41 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ }, "scripts": { "start": "react-dotenv && set port=5000 && react-scripts start", - "json-server": "npx json-server data.json --port 3000", + "json-server": "npx json-server data.json --port 3001 --static ./public/songs_sources", "build": "react-dotenv && react-scripts build", "test": "react-dotenv && react-scripts test", "eject": "react-dotenv && react-scripts eject", diff --git a/public/songs_sources/acdc.mp3 b/public/songs_sources/acdc.mp3 new file mode 100644 index 00000000..ca7c75b1 Binary files /dev/null and b/public/songs_sources/acdc.mp3 differ diff --git a/src/songs/Blur_-_Song_2_47967381.mp3 b/public/songs_sources/blur.mp3 similarity index 100% rename from src/songs/Blur_-_Song_2_47967381.mp3 rename to public/songs_sources/blur.mp3 diff --git a/src/songs/DSPD_-_Crazy_Frog_75801748.mp3 b/public/songs_sources/crazyfrog.mp3 similarity index 100% rename from src/songs/DSPD_-_Crazy_Frog_75801748.mp3 rename to public/songs_sources/crazyfrog.mp3 diff --git a/public/songs_sources/greenday.mp3 b/public/songs_sources/greenday.mp3 new file mode 100644 index 00000000..2ca7e9b5 Binary files /dev/null and b/public/songs_sources/greenday.mp3 differ diff --git a/public/songs_sources/hotweelz.mp3 b/public/songs_sources/hotweelz.mp3 new file mode 100644 index 00000000..aa11dd3d Binary files /dev/null and b/public/songs_sources/hotweelz.mp3 differ diff --git a/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3 b/public/songs_sources/kemstal.mp3 similarity index 100% rename from src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3 rename to public/songs_sources/kemstal.mp3 diff --git a/public/songs_sources/kiss.mp3 b/public/songs_sources/kiss.mp3 new file mode 100644 index 00000000..619a8b62 Binary files /dev/null and b/public/songs_sources/kiss.mp3 differ diff --git a/src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3 b/public/songs_sources/nirvana.mp3 similarity index 100% rename from src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3 rename to public/songs_sources/nirvana.mp3 diff --git a/src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3 b/public/songs_sources/noizemc.mp3 similarity index 100% rename from src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3 rename to public/songs_sources/noizemc.mp3 diff --git a/public/songs_sources/ozzy.mp3 b/public/songs_sources/ozzy.mp3 new file mode 100644 index 00000000..dcfdc0c2 Binary files /dev/null and b/public/songs_sources/ozzy.mp3 differ diff --git a/public/songs_sources/pepers.mp3 b/public/songs_sources/pepers.mp3 new file mode 100644 index 00000000..0c61f58e Binary files /dev/null and b/public/songs_sources/pepers.mp3 differ diff --git a/src/API/api.ts b/src/API/api.ts index 6871a4d2..445ac4b4 100644 --- a/src/API/api.ts +++ b/src/API/api.ts @@ -27,7 +27,7 @@ export async function getSongs() { export async function getSong(id: string) { - return await axios.get(`${localhost}songs/` + id); + return await axios.get(`${localhost}songs/` + id); } diff --git a/src/App.css b/src/App.css index 9f6d1ad0..0f26451d 100644 --- a/src/App.css +++ b/src/App.css @@ -77,7 +77,12 @@ -webkit-box-shadow: 0px -26px 19px 0px rgba(34, 60, 80, 0.2); -moz-box-shadow: 0px -26px 19px 0px rgba(34, 60, 80, 0.2); box-shadow: 0px -26px 19px 0px rgba(34, 60, 80, 0.2); - + transform-origin: bottom center; + animation: fadeInAndMoveUp 0.2s ease-out forwards; +} +@keyframes fadeInAndMoveUp { + from { opacity: 0; transform: translateY(50px); } + to { opacity: 1; transform: translateY(0); } } .song-cover { @@ -92,20 +97,40 @@ .song-table-row { margin-top: 50px !important; margin-bottom: 50px !important; + padding: 30px !important; } - .song-table-row:hover { outline: #9d0000 solid 3px !important; - outline-offset: -1px !important; + outline-offset: -2px !important; + color: #7c0000 !important; + background-color: #fcfcfc !important; } +.song-table-row-active { + outline-offset: -2px !important; + + background-color: #e7e7e7 !important; +} + +.ant-table-tbody { + padding: 40 !important; +} +.ant-table-tbody > tr > td { + padding: 40 !important; +} .ant-table-cell { padding: 8px !important; } +.ant-table-tbody > tr { + padding-top: 20px !important; + padding-bottom: 20px !important; +} + + .ant-table-cell:nth-child(1) { - padding: 2px !important; + padding: 1px !important; } .play-song-button { @@ -142,6 +167,7 @@ color: grey; font-size: 30px !important; padding-right: 5px; + height: 30px; } .current-track-button { diff --git a/src/App.tsx b/src/App.tsx index 8f13210d..0af3f582 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,21 +7,29 @@ import { Loginpage } from './pages/Loginpage'; import { Registerpage } from './pages/Registerpage'; import { Profilepage } from './pages/Profilepage'; import { Layout } from './components/layoutComponents/Layout'; +import { CurrentSongProvider } from './contexts/SongContexts/SongContextProvider'; +import { PlayingProvider } from './contexts/SongContexts/PlayingProvider'; +import { VolumeProvider } from './contexts/VolumeContexts/VolumeProvider'; function App() { return ( - -
+
- - }> - } /> - } /> - } /> - - - + + + + + }> + } /> + } /> + } /> + + + + + +
diff --git a/src/components/layoutComponents/Layout.tsx b/src/components/layoutComponents/Layout.tsx index 4f78d97d..63c8134d 100644 --- a/src/components/layoutComponents/Layout.tsx +++ b/src/components/layoutComponents/Layout.tsx @@ -8,10 +8,16 @@ import { AdBlock } from './AdBlock'; import { Footer } from './Footer'; import { Header } from './Header'; import { MenuBlock } from './MenuBlock'; +import { useEffect, useRef } from 'react'; +import { usePlayingContext } from '../../contexts/SongContexts/PlayingProvider'; + export function Layout() { + return ( - <>
+ + <> +
diff --git a/src/components/layoutComponents/MenuBlock.tsx b/src/components/layoutComponents/MenuBlock.tsx index be5840ea..a0bc4dbe 100644 --- a/src/components/layoutComponents/MenuBlock.tsx +++ b/src/components/layoutComponents/MenuBlock.tsx @@ -17,6 +17,7 @@ interface MenuBlockProps { } export function MenuBlock({playlists, songs, albums, genres}: MenuBlockProps) { + const newSongsTab = { label: 'Новинки', key: 'New', @@ -39,7 +40,8 @@ export function MenuBlock({playlists, songs, albums, genres}: MenuBlockProps) { key: 'Recomendations', children: songs? : null }; - const tabs = [recTab, newSongsTab, chartTab, playlistsTab]; + const tabs = [recTab, newSongsTab, chartTab]; + return (
@@ -56,4 +58,4 @@ export function MenuBlock({playlists, songs, albums, genres}: MenuBlockProps) { ); -} +} \ No newline at end of file diff --git a/src/components/menuComponents/ChartSongsBlock.tsx b/src/components/menuComponents/ChartSongsBlock.tsx index 0dcfce43..3dae5b74 100644 --- a/src/components/menuComponents/ChartSongsBlock.tsx +++ b/src/components/menuComponents/ChartSongsBlock.tsx @@ -7,7 +7,7 @@ import { PlayCircleFilled, PlayCircleOutlined } from '@ant-design/icons'; import { getSongs } from '../../API/api'; import Title from 'antd/es/typography/Title'; import { GetColumns } from './Templates/songsTemplate'; -import { getColumnsWithNumber } from './Templates/numeredSongsTemplate'; +import { GetColumnsWithNumber } from './Templates/numeredSongsTemplate'; // Функция для генерации номеров строк const generateRowNumbers = (rows: any[]) => @@ -30,16 +30,19 @@ export function ChartSongsBlock() { return (
Чарт} - style={{ width: '100%', backgroundColor: 'transparent' }} + title={() => Чарт} + style={{ width: '100%', backgroundColor: 'transparent', overflowX: 'auto' }} className="songs-table menu-block" dataSource={numberedSongs} - columns={getColumnsWithNumber(numberedSongs)} + columns={GetColumnsWithNumber(numberedSongs)} showHeader={false} pagination={false} - rowClassName={() => 'song-table-row'} + rowClassName={() => 'song-table-row chart-row'} rowKey={(record) => record.id} + scroll={{ x: true }} /> ); }; + + diff --git a/src/components/menuComponents/NewSongsBlock.tsx b/src/components/menuComponents/NewSongsBlock.tsx index 75b15ada..b691f195 100644 --- a/src/components/menuComponents/NewSongsBlock.tsx +++ b/src/components/menuComponents/NewSongsBlock.tsx @@ -3,16 +3,21 @@ import { render } from '@testing-library/react'; import {ISong} from '../../models/IModels'; import axios from 'axios'; import { Table, Button, Empty } from 'antd'; -import { PlayCircleFilled, PlayCircleOutlined } from '@ant-design/icons'; +import { Loading3QuartersOutlined, PlayCircleFilled, PlayCircleOutlined } from '@ant-design/icons'; import { getSongs } from '../../API/api'; import Title from 'antd/es/typography/Title'; import { GetColumns } from './Templates/songsTemplate'; - +import { Spin } from "antd"; +import { useCurrentSongContext } from '../../contexts/SongContexts/SongContextProvider'; +import { usePlayingContext } from '../../contexts/SongContexts/PlayingProvider'; export function NewSongsBlock() { const [songs, setSongs] = useState([]); + const currentSongId = useCurrentSongContext(); + const isPlaying = usePlayingContext(); + const fetchData = async () => { const response = getSongs(); setSongs((await response).data); @@ -25,17 +30,20 @@ export function NewSongsBlock() { return (
-
Горячие новинки} - style={{width: '100%', backgroundColor: 'transparent'}} - className="songs-table menu-block" - dataSource={songs.map((s: ISong) => ({...s, play: ''}))} - columns={GetColumns(songs)} - showHeader={false} - pagination={false} - rowClassName={() => 'song-table-row'} - rowKey={(s: ISong) => s.id} - /> + } spinning={songs.length === 0}> +
Горячие новинки} + style={{width: '100%', backgroundColor: 'transparent'}} + className="songs-table menu-block" + dataSource={songs.map((s: ISong) => ({...s, play: ''}))} + columns={GetColumns(songs)} + showHeader={false} + pagination={false} + rowClassName={(record) => isPlaying ? (record.id === currentSongId.songId ? 'song-table-row-active' : 'song-table-row') : 'song-table-row'} + rowKey={(s: ISong) => s.id} + rowHoverable={false} + /> + ); -}; \ No newline at end of file +}; diff --git a/src/components/menuComponents/Templates/numeredSongsTemplate.tsx b/src/components/menuComponents/Templates/numeredSongsTemplate.tsx index d4503ab9..28ffd272 100644 --- a/src/components/menuComponents/Templates/numeredSongsTemplate.tsx +++ b/src/components/menuComponents/Templates/numeredSongsTemplate.tsx @@ -1,8 +1,18 @@ import { Button } from "antd"; import { ISong } from "../../../models/IModels"; -import PlayCircleFilled from "@ant-design/icons/lib/icons/PlayCircleFilled"; +import { useState } from "react"; +import { useCurrentSongContext } from "../../../contexts/SongContexts/SongContextProvider"; +import { usePlayingContext } from "../../../contexts/SongContexts/PlayingProvider"; -export function getColumnsWithNumber(songs: ISong[]) { +const useColumnsWithNumber = (songs: ISong[]) => { + + const {isPlaying, setIsPlaying} = usePlayingContext(); + const { songId, setSongId } = useCurrentSongContext(); + + const handlePlayClick = (songId: string) => { + setIsPlaying(!isPlaying); + setSongId(songId); + }; return [ { @@ -23,21 +33,23 @@ export function getColumnsWithNumber(songs: ISong[]) { width: 100, render: (text: string, song: ISong) => ( - - ), }, { title: '', dataIndex: 'song_name', key: 'song_name', - width: 350 + width: 400 }, { title: '', @@ -49,8 +61,12 @@ export function getColumnsWithNumber(songs: ISong[]) { title: '', dataIndex: 'album_name', key: 'album_name', - width: 400 + width: 350 } ] -} \ No newline at end of file +} + +export function GetColumnsWithNumber(songs: ISong[]) { + return useColumnsWithNumber(songs); +} diff --git a/src/components/menuComponents/Templates/songsTemplate.tsx b/src/components/menuComponents/Templates/songsTemplate.tsx index a9550814..83f550bd 100644 --- a/src/components/menuComponents/Templates/songsTemplate.tsx +++ b/src/components/menuComponents/Templates/songsTemplate.tsx @@ -1,15 +1,21 @@ import { Button } from "antd"; import { ISong } from "../../../models/IModels"; import { useState } from "react"; -import { PauseCircleFilled, PlayCircleFilled } from "@ant-design/icons"; +import { height } from "@mui/system"; +import { useCurrentSongContext } from "../../../contexts/SongContexts/SongContextProvider"; +import { usePlayingContext } from "../../../contexts/SongContexts/PlayingProvider"; -const useColumns = (songs: ISong[]) => { - const [isPlaying, setIsPlaying] = useState(false); +const useColumns = (songs: ISong[])=> { - const handlePlayClick = () => { + const {isPlaying, setIsPlaying} = usePlayingContext(); + const { songId, setSongId } = useCurrentSongContext(); + + const handlePlayClick = (songId: string) => { setIsPlaying(!isPlaying); + setSongId(songId); }; + return [ { title: 'Play', @@ -18,17 +24,19 @@ const useColumns = (songs: ISong[]) => { width: 100, render: (text: string, song: ISong) => ( - // Тут в дата-контент вставляется JSON коды иконок - - - ), }, { @@ -55,5 +63,4 @@ const useColumns = (songs: ISong[]) => { export function GetColumns(songs: ISong[]) { return useColumns(songs); -} - +} \ No newline at end of file diff --git a/src/components/songComponents/CurrentTrack.tsx b/src/components/songComponents/CurrentTrack.tsx index f089f49a..58db8165 100644 --- a/src/components/songComponents/CurrentTrack.tsx +++ b/src/components/songComponents/CurrentTrack.tsx @@ -1,73 +1,218 @@ -import React, { useEffect, useState } from 'react'; -import { Button, Col, Grid, Row, Table } from 'antd'; -import { BackwardFilled, FastForwardFilled, FastBackwardFilled, PlayCircleFilled, PlayCircleOutlined, StepBackwardFilled, StepForwardFilled, HeartOutlined, ShareAltOutlined, PauseCircleFilled, PauseCircleOutlined } from '@ant-design/icons'; +import React, { useEffect, useState, useRef } from 'react'; +import { Button, Col, Grid, Menu, Row, Slider, Space, Table } from 'antd'; +import { FastForwardFilled, FastBackwardFilled, PlayCircleOutlined, HeartOutlined, ShareAltOutlined, PauseCircleOutlined, SoundOutlined, MutedOutlined, SoundFilled } from '@ant-design/icons'; import { ISong, SongProps } from '../../models/IModels'; import styled from 'styled-components' -import useSound from 'use-sound'; +import { useCurrentSongContext } from '../../contexts/SongContexts/SongContextProvider'; +import { usePlayingContext } from '../../contexts/SongContexts/PlayingProvider'; +import Dropdown from 'antd/es/dropdown/dropdown'; +import Text from 'antd/es/typography/Text'; +import { useVolumeContext } from '../../contexts/VolumeContexts/VolumeProvider'; const Song = styled.div` - align-items: center; position: fixed; bottom: 0; - width: 75%;` + width: 100%; + display: flex; + justify-content: space-between; + padding: 0 0px; + box-sizing: border-box; + background-color: #fff; + + @media (max-width: 768px) { + padding: 0 10px; + flex-direction: column; + } +`; type CurrentSongProps = { song: ISong + songs: ISong[] } -export function CurrentTrack({ song }: CurrentSongProps) { - - const [isPlaying, setIsPlaying] = useState(false); - - const soundUrl = song?.source || ''; // Пустая строка в случае отсутствия source +const SongName = styled.span` + display: inline-block; + max-width: 200px; /* Максимальная ширина */ + white-space: nowrap; /* Предотвращает перенос слов на новую строку */ + overflow: hidden; /* Скрывает текст, выходящий за пределы контейнера */ + text-overflow: ellipsis; /* Добавляет точку-эллипсис */ + padding-right: 20px; /* Добавляем небольшой отступ справа для точки */ +`; - - - const [play, { pause, duration, sound }] = useSound(soundUrl, { volume: 0.5 }); +export function CurrentTrack({ song , songs}: CurrentSongProps) { - - const playingButton = () => { + const audioPlayer = useRef(null); + + const soundUrl = song?.source; + + const Playlist = songs; + + const {isPlaying, setIsPlaying} = usePlayingContext(); + + const { songId, setSongId } = useCurrentSongContext(); + + const { volumeValue: volume, setVolumeValue: setVolume } = useVolumeContext(); + + const [ elapsed, setElapsed] = useState(0); + + const [ duration, setDuration ] = useState(0); + + const [ muted, setMuted ] = useState(false); + + useEffect(() => { if (isPlaying) { - pause(); - setIsPlaying(false); - } else { - play(); - setIsPlaying(true); + audioPlayer.current?.play(); + } + else { + audioPlayer.current?.pause(); + } + }, [isPlaying]); + + const togglePlay = () => { + if (audioPlayer.current && audioPlayer.current.src) { + setIsPlaying(!isPlaying); + } + }; + + const prevTrack = () => { + if (parseInt(songId) > 0) { + const newId = (parseInt(songId) - 1).toString(); + setSongId(newId); + togglePlay(); + } + }; + + const nextTrack = () => { + if (parseInt(songId) < songs.length - 1) { + const newId = (parseInt(songId) + 1).toString(); + setSongId(newId); + togglePlay(); } }; useEffect(() => { if (song) { - play(); + audioPlayer.current?.play(); setIsPlaying(true); } }, [song]); + useEffect(() => { + if (audioPlayer.current) { + audioPlayer.current.muted = muted; + } + }, [muted]); + + useEffect(() => { + if (audioPlayer.current) { + audioPlayer.current.volume = volume / 100; + + if (isPlaying) { + setInterval(() => { + const duration = Math.floor(audioPlayer?.current?.duration ?? 0); + const currentTime = Math.floor(audioPlayer?.current?.currentTime ?? 0); + + setDuration(duration - currentTime); + setElapsed(currentTime); + + if (currentTime === duration) { + nextTrack(); + } + }, 100); + } + } + }, [volume, isPlaying]); + + const formatTime = (time: number) => { + if (time) { + const minutes = Math.floor(time / 60); + const seconds = Math.floor(time % 60); + return `${minutes}:${seconds < 10 ? `0${seconds}` : seconds}`; + } + return '0:00'; + }; + return ( -
- -
- - - - - - {song.cover} - - - {song.song_name} - {song.band_name} - - - - - - +