playing.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
  2. import React, {useState, useEffect} from 'react';
  3. import {faVolumeDown, faVolumeUp, faRandom, faStepBackward, faStopCircle, faStepForward, faPlayCircle, faRepeat} from '@fortawesome/free-solid-svg-icons'
  4. import { store } from '../store/store';
  5. import {actionPlayerRandom, actionFullPlay, actionFullPause, actionFullSetVolume, actionPrevTrack, actionNextTrack, actionSetRepeat, actionSetRandom} from '../store/playerReducer';
  6. import {Provider, connect} from 'react-redux';
  7. import { audio } from './Tracks';
  8. import img_album from '../images/default_album.gif';
  9. import {Nav, Tab, Tabs} from "react-bootstrap";
  10. function msToTime(duration) {
  11. let hours,minutes,seconds;
  12. hours = Math.floor(duration / 3600);
  13. minutes = Math.floor((duration - 3600 * hours) / 60);
  14. seconds = Math.floor((duration - 3600 * hours - 60 * minutes) % 60);
  15. hours = (hours < 10) ? "0" + hours : hours;
  16. minutes = (minutes < 10) ? "0" + minutes : minutes;
  17. seconds = (seconds < 10) ? "0" + seconds : seconds;
  18. return minutes + ":" + seconds;
  19. }
  20. export let NowPlayingPlayer = (props) => {
  21. const [volume, setVolume] = useState(20);
  22. const [newCurrent, setNewCurrent] = useState(0)
  23. useEffect(() => {
  24. if (props.currentTime) audio.currentTime = newCurrent
  25. }, [newCurrent]);
  26. let album_photo = (props.track?.album?.photo) ? `http://player-api/storage/albums/${props.track?.album?.photo}` : img_album
  27. const [key, setKey] = useState('home');
  28. return(
  29. <div className="player col-xxl-3 col-lg-5 ">
  30. <div className="wrapper ">
  31. <Tabs
  32. id="fill-tab-example"
  33. activeKey={key}
  34. onSelect={(k) => setKey(k)}
  35. className="mb-3 justify-content-center text-white"
  36. tabClassName="btn-dark"
  37. fill
  38. >
  39. <Tab className="text-white bg-dark" tabClassName="text-white bg-dark" eventKey="home" title="Player">
  40. <div className="flex-column justify-content-center align-items-center d-flex">
  41. <div className="details w-100">
  42. <div className="now-playing"></div>
  43. <div className="track-art" style={{backgroundImage:`url(${album_photo})`}} ></div>
  44. {/*<div className="track-name">{props.track?.name|| 'Track Name' }</div>*/}
  45. <div className="track-name w-100 text-center">
  46. <div className='line w-75'>
  47. <div className='second w-100'>
  48. <span className="w-100">
  49. {props.track?.name|| 'Track Name' }
  50. </span>
  51. </div>
  52. </div>
  53. </div>
  54. <div className="now-playing">{props.track?.id3?.artist || 'Artist' }</div>
  55. </div>
  56. <div className="slider-container duration">
  57. <div className="d-flex align-items-end justify-content-between">
  58. <div className="slider-container d-flex flex-column w-75 pe-2" >
  59. <div className="d-flex justify-content-between">
  60. <span className="text-secondary">{props.currentTime ?
  61. `0${((props.currentTime - props.currentTime % 60) / 60 % 60).toFixed() !== 'NaN' ?
  62. ((props.currentTime - props.currentTime % 60) / 60 % 60).toFixed() : '0'}:${(props.currentTime % 60).toFixed() > 9 ?
  63. '' : '0'}${(props.currentTime % 60).toFixed() !== 'NaN' ? (props.currentTime % 60).toFixed() : '0'}` : '--:--'}
  64. </span>
  65. <span className="text-secondary">{props.track?.id3?.time || (msToTime(props.duration) !== 'NaN:NaN'? msToTime(props.duration) : '00:00')}</span>
  66. </div>
  67. <input type='range' min={0} max={props.duration} className="seek-slider w-100 cursor-pointer"
  68. value={props.currentTime || 0} onChange={(e) => setNewCurrent(e.target.value)}
  69. onMouseUp={() => store.dispatch(actionFullPlay())} onMouseDown={() => store.dispatch(actionFullPause())}/>
  70. </div>
  71. <div className="slider-container d-flex flex-column w-25" >
  72. <div className="d-flex justify-content-between">
  73. <FontAwesomeIcon icon={faVolumeDown} className="text-secondary"/><FontAwesomeIcon icon={faVolumeUp} className="text-secondary"/>
  74. </div>
  75. <input type='range' min={1} max='99' value={volume} className="volume-slider cursor-pointer"
  76. onChange={(e) => {
  77. setVolume(e.target.value);
  78. if (store.getState()?.player?.track) store.dispatch(actionFullSetVolume(volume)) }}/>
  79. </div>
  80. </div>
  81. </div>
  82. <div className="buttons">
  83. <div className="random-track">
  84. <FontAwesomeIcon icon={faRandom} className={props.random === 1 ? 'fa-2x text-white-50 cursor-pointer' : 'fa-2x text-primary cursor-pointer'}
  85. onClick={() => {
  86. props.random === 1 ? store.dispatch(actionSetRandom(2)) : store.dispatch(actionSetRandom(1))
  87. store.dispatch(actionPlayerRandom());
  88. }}/>
  89. </div>
  90. <div className="prev-track">
  91. <FontAwesomeIcon icon={faStepBackward} className='fa-2x cursor-pointer'
  92. onClick={ () => store.dispatch(actionPrevTrack(props.track))}/>
  93. </div>
  94. <div className="play-track">
  95. <FontAwesomeIcon icon={(!props.isPlaying) ? faPlayCircle : faStopCircle} className='fa-5x cursor-pointer'
  96. onClick={() => {
  97. if(store.getState()?.player?.isPlaying === true) {
  98. store.dispatch(actionFullPause());
  99. } else{
  100. store.dispatch(actionFullPlay());
  101. }
  102. }}/>
  103. </div>
  104. <div className="next-track">
  105. <FontAwesomeIcon icon={faStepForward} className='fa-2x cursor-pointer' onClick={() => {
  106. store.dispatch(actionNextTrack({track: props.track, end:'false'}));
  107. }}/>
  108. </div>
  109. <div className="random-track">
  110. <FontAwesomeIcon icon={faRepeat} className={props.repeat === 1 ? 'fa-2x text-white-50 cursor-pointer' : 'fa-2x text-primary cursor-pointer'}
  111. onClick={() => (props.repeat === 1 ? store.dispatch(actionSetRepeat(2)) : store.dispatch(actionSetRepeat(1)))}/>
  112. </div>
  113. </div>
  114. </div>
  115. </Tab>
  116. <Tab className="text-white bg-dark" tabClassName="text-white bg-dark" eventKey="profile" title="Queue">
  117. asdasd
  118. </Tab>
  119. </Tabs>
  120. </div>
  121. </div>)
  122. }
  123. export const СNowPlayingPlayer = connect(state => ({track: state.player?.track || [],
  124. duration: state.player?.duration || '00:00',
  125. isPlaying: state.player?.isPlaying || false,
  126. currentTime: state.player?.currentTime || '00:00',
  127. repeat: state.player?.repeat || 1,
  128. random: state.player?.random || 1}) )(NowPlayingPlayer);