diff --git a/package.json b/package.json index 20830d2..8b6efaa 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react-cookie": "^4.1.1", "react-dom": "^18.2.0", "react-redux": "^8.0.7", + "react-resize-detector": "^9.1.0", "react-router-dom": "^6.11.2", "react-scripts": "5.0.1", "sha1": "^1.1.1", @@ -48,4 +49,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/src/MainPage.js b/src/MainPage.js index 385c552..2be11b0 100644 --- a/src/MainPage.js +++ b/src/MainPage.js @@ -40,7 +40,7 @@ export default function () { dispatch(setList(list.result)); }); }, [accessToken, passportId]); - return
+ return
@@ -48,10 +48,11 @@ export default function () { - 2022-12-13 14:39_同传翻译 diff --git a/src/MainPage.module.css b/src/MainPage.module.css index b7bf5ff..ea01386 100644 --- a/src/MainPage.module.css +++ b/src/MainPage.module.css @@ -1,3 +1,7 @@ .title { background-color: burlywood; +} + +.mainBody { + background-color: #FAFAFA; } \ No newline at end of file diff --git a/src/PlayerBar.js b/src/PlayerBar.js index 8d6f5ce..321ea35 100644 --- a/src/PlayerBar.js +++ b/src/PlayerBar.js @@ -1,25 +1,101 @@ -import { Grid, MenuItem, Select, FormControl, InputLabel, Button } from "@mui/material" +import { MenuItem, Select, IconButton, Typography, Stack, Container } from "@mui/material" import styles from './PlayerBar.module.css'; +import { useSelector, useDispatch } from 'react-redux' +import { useEffect, useRef, useState, useCallback } from "react"; +import { useResizeDetector } from 'react-resize-detector'; +import pauseIcon from "./assets/play.png"; +import playIcon from "./assets/pause.png"; +import downloadIcon from "./assets/download.png"; +import { togglePauseState } from "./business/recorderSlice.js" +import Waveform from "./components/Waveform"; + +const durationFormat = (time) => { + if (isNaN(time)) return "00:00:00"; + time = parseInt(time); + let second = parseInt(time % 60); + let minute = parseInt((time / 60) % 60); + let hour = parseInt(time / 3600); + return hour.toString().padStart(2, '0') + ":" + minute.toString().padStart(2, '0') + ":" + second.toString().padStart(2, '0'); +} export default function () { - return - -
进度条
- - - 速度 - - - -
+ const dispatch = useDispatch(); + const [duration, setDuration] = useState("00:00:00"); + const [currentTime, setCurrentTime] = useState("00:00:00"); + const [canvasWidth, setCanvasWidth] = useState(0); + const currentIndex = useSelector(state => state.recorder.currentIndex); + const recordList = useSelector(state => state.recorder.list); + const currentBlob = useSelector(state => state.recorder.currentBlob); + const pause = useSelector(state => state.recorder.pause); + const player = useRef(null); + useEffect(() => { + player.current.url = currentBlob + console.log(player.current.url); + }, [currentBlob]); + + const toggleState = () => { + if (pause) { + player.current.play(); + } else { + player.current.pause(); + } + dispatch(togglePauseState()); + }; + + const onDurationChange = (event) => { + setDuration(durationFormat(player.current.duration)); + } + const onTimeUpdate = (event) => { + setCurrentTime(durationFormat(player.current.currentTime)); + } + + const onResize = useCallback((width, height) => { + setCanvasWidth(width - 90 - 60); + }, []); + + const { ref: playerBar } = useResizeDetector({ + onResize: onResize + }); + + return + + {recordList.length > 0 ? recordList.at(currentIndex).editName : ""} + + + + + +
+ + + + +
+ + + {currentTime} / {duration} + + +
} \ No newline at end of file diff --git a/src/PlayerBar.module.css b/src/PlayerBar.module.css index 7efc280..f69ba0a 100644 --- a/src/PlayerBar.module.css +++ b/src/PlayerBar.module.css @@ -1,3 +1,6 @@ .playerBar { display: flex; + background-color: #E6EAEC; + height: 70px; + width: 100%; } \ No newline at end of file diff --git a/src/RecordList.js b/src/RecordList.js index 147ce92..b853bb5 100644 --- a/src/RecordList.js +++ b/src/RecordList.js @@ -7,7 +7,7 @@ import ListItem from '@mui/material/ListItem'; import ListItemButton from '@mui/material/ListItemButton'; import ListItemText from '@mui/material/ListItemText'; import Toolbar from '@mui/material/Toolbar'; -import { setCurrentIndex, setCurrentLyric } from "./business/recorderSlice.js" +import { setCurrentIndex, setCurrentLyric, setCurrentBlob } from "./business/recorderSlice.js" import yzs from "./business/request.js"; const drawerWidth = 240; @@ -19,13 +19,17 @@ export default function () { const recordList = useSelector(state => state.recorder.list); const onSelected = (event, index) => { console.log("onSelected", index, recordList.at(index).transResultUrl) + dispatch(setCurrentIndex(index)); yzs.download(accessToken, recordList.at(index).transResultUrl).then( blob => blob.text() ).then(text => { console.log(text); - dispatch(setCurrentLyric(JSON.parse(text))); + let payload = recordList.at(index).type === 1 ? JSON.parse(text) : text; + dispatch(setCurrentLyric(payload)); + }); + yzs.download(accessToken, recordList.at(index).audioUrl).then(blob => { + dispatch(setCurrentBlob(URL.createObjectURL(blob))); }); - dispatch(setCurrentIndex(index)); } return state.recorder.currentLyric); + const currentIndex = useSelector(state => state.recorder.currentIndex); + const recordList = useSelector(state => state.recorder.list); - return
- {currentLyric.map((lyric, index) => { + + if (recordList.length === 0) return ; + + return + {recordList.at(currentIndex).type === 1 ? (typeof currentLyric === "object" ? currentLyric.map((lyric, index) => { return
{lyric.text} {lyric.translation}
- })} -
+ }) : ) :
{typeof currentLyric === "string" ? currentLyric : ""}
} + } \ No newline at end of file diff --git a/src/RecordLyrics.module.css b/src/RecordLyrics.module.css index 71c0761..13494e3 100644 --- a/src/RecordLyrics.module.css +++ b/src/RecordLyrics.module.css @@ -1,5 +1,7 @@ .lyricsBrowser { + margin-top: 16px; padding-bottom: 40px; + padding: 24px; } .lyricItem { diff --git a/src/assets/download.png b/src/assets/download.png new file mode 100644 index 0000000..832819a Binary files /dev/null and b/src/assets/download.png differ diff --git a/src/assets/pause.png b/src/assets/pause.png new file mode 100644 index 0000000..2fc8b5a Binary files /dev/null and b/src/assets/pause.png differ diff --git a/src/assets/play.png b/src/assets/play.png new file mode 100644 index 0000000..baf04ad Binary files /dev/null and b/src/assets/play.png differ diff --git a/src/business/recorderSlice.js b/src/business/recorderSlice.js index 054db87..b7a0dd1 100644 --- a/src/business/recorderSlice.js +++ b/src/business/recorderSlice.js @@ -6,21 +6,30 @@ export const recorderSlice = createSlice({ list: [], currentIndex: 0, currentLyric: [], + currentBlob: {}, + pause: true, }, reducers: { setList: (state, action) => { state.list = action.payload; }, setCurrentIndex: (state, action) => { + state.pause = true; state.currentIndex = action.payload; }, setCurrentLyric: (state, action) => { state.currentLyric = action.payload; - } + }, + setCurrentBlob: (state, action) => { + state.currentBlob = action.payload; + }, + togglePauseState: (state) => { + state.pause = !state.pause; + }, } }) // Action creators are generated for each case reducer function -export const { setCurrentIndex, setList, setCurrentLyric } = recorderSlice.actions +export const { setCurrentIndex, setList, setCurrentLyric, setCurrentBlob, togglePauseState } = recorderSlice.actions export default recorderSlice.reducer \ No newline at end of file diff --git a/src/components/Waveform.js b/src/components/Waveform.js new file mode 100644 index 0000000..4885d71 --- /dev/null +++ b/src/components/Waveform.js @@ -0,0 +1,159 @@ +import { useEffect, useRef, useState, useCallback } from "react"; +import useSetTrackProgress from "./useSetTrackProgress.js" +import { useResizeDetector } from 'react-resize-detector'; + +const pointWidth = 2; +const pointMargin = 3; + +const trackDuration = 60; //