playing.js 8.8 KB

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