Skip to content

Commit

Permalink
feat: slider and download
Browse files Browse the repository at this point in the history
  • Loading branch information
sandipndev committed Sep 22, 2024
1 parent 1ec8956 commit 8888210
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 8 deletions.
103 changes: 96 additions & 7 deletions frontend/app/details/[process-id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ type Props = {
const ProcessDetail: React.FC<Props> = ({ params }) => {
const processId = params["process-id"]

const { data } = useGetProcessQuery({
const { data, loading: processLoading } = useGetProcessQuery({
variables: {
id: processId,
},
pollInterval: 1000,
})
const [preloadingAudio, setPreloadingAudio] = useState(true)
const loading = processLoading && preloadingAudio

const [, setRenderCount] = useState(0)

const [currentSemitone, setCurrentSemitone] = useState(0)
const [isPlaying, setIsPlaying] = useState(false)
Expand Down Expand Up @@ -45,8 +49,10 @@ const ProcessDetail: React.FC<Props> = ({ params }) => {
audioRefs.current[semitone] = audio
}
})

setPreloadingAudio(true)
}
}, [data, processId])
}, [data, processId, setPreloadingAudio])

// Update currentTime when the audio is playing
useEffect(() => {
Expand Down Expand Up @@ -95,6 +101,50 @@ const ProcessDetail: React.FC<Props> = ({ params }) => {
}
}

useEffect(() => {
const audioRefsCurrent = audioRefs.current
return () => {
Object.values(audioRefsCurrent).forEach((audio) => {
audio.pause()
})
setIsPlaying(false)
}
}, [])

const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {
const audio = audioRefs.current[currentSemitone]
if (audio) {
const time = parseFloat(e.target.value)
audio.currentTime = time
setCurrentTime(time)
}
}

const handleDownload = () => {
const semitoneLabel =
currentSemitone >= 0 ? `+${currentSemitone}` : `${currentSemitone}`
const fileName =
currentSemitone === 0 ? `${processId}.mp3` : `${processId}_${semitoneLabel}_ST.mp3`
const fileUrl = `/media/${fileName}`

// Create a temporary anchor element to initiate download
const link = document.createElement("a")
link.href = fileUrl
link.download = `${data?.getProcess.name}_${semitoneLabel}.mp3`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}

useEffect(() => {
const i = setInterval(() => {
setRenderCount((prev) => (prev + 1) % 100)
}, 1000)
return () => clearInterval(i)
}, [])

if (loading) return <div>Loading...</div>

if (data?.getProcess.status !== "DONE")
return (
<>
Expand All @@ -106,40 +156,79 @@ const ProcessDetail: React.FC<Props> = ({ params }) => {
</>
)

const playingAudio = audioRefs.current[currentSemitone]
const playTime = (playingAudio && playingAudio.currentTime) || 0
const duration = (playingAudio && playingAudio.duration) || 0

return (
<div>
<div className="text-xl">{data?.getProcess.name}</div>
<div className="text-xl font-bold">{data?.getProcess.name}</div>
<div className="text-sm text-cyan-500">{data?.getProcess.youtubeUrl}</div>
<hr className="mt-6 border-zinc-700" />
<div className="mt-4">
<div>
<strong>Current Semitone: {currentSemitone}</strong>
<strong className="font-bold text-xl">
Current Semitone:{" "}
{currentSemitone > 0 ? `+${currentSemitone}` : currentSemitone}
</strong>
</div>
<div className="my-4">
<button
onClick={() => changeSemitone(-1)}
disabled={currentSemitone <= -10}
className="px-4 py-2 mr-2 bg-blue-500 text-white rounded disabled:opacity-50"
className="px-4 py-2 mr-2 bg-blue-500 hover:bg-blue-600 text-white rounded disabled:opacity-50"
>
-
</button>
<button
onClick={() => changeSemitone(1)}
disabled={currentSemitone >= 10}
className="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
className="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded disabled:opacity-50"
>
+
</button>
</div>
<div>
<button
onClick={handlePlayPause}
className="px-4 py-2 bg-green-500 text-white rounded"
className="px-4 py-2 bg-green-500 hover:bg-green-600 text-white rounded"
>
{isPlaying ? "Pause" : "Play"}
</button>
</div>
<div className="mt-8">
<input
type="range"
min="0"
max={duration}
value={playTime}
onChange={handleSeek}
className="w-full range-input"
/>
<div className="flex justify-between text-sm">
<span>{formatTime(playTime)}</span>
<span>{formatTime(duration)}</span>
</div>
</div>
<div className="mt-8">
<button
className="px-4 py-2 bg-slate-500 text-white rounded"
onClick={handleDownload}
>
Download
</button>
</div>
</div>
</div>
)
}

export default ProcessDetail

// Format time in mm:ss
const formatTime = (time: number) => {
if (isNaN(time)) return "0:00"
const minutes = Math.floor(time / 60)
const seconds = Math.floor(time % 60)
return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`
}
57 changes: 57 additions & 0 deletions frontend/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,60 @@
body {
background-color: var(--color-dark);
}

@layer components {
.range-input {
@apply w-full; /* Use Tailwind's width utility */
-webkit-appearance: none; /* Remove default styling */
appearance: none; /* Remove default styling */
background-color: transparent; /* Make the background transparent */
}

/* Track Styles */
.range-input::-webkit-slider-runnable-track {
@apply h-1 bg-zinc-500 rounded-full; /* Tailwind utilities for height, background color, and border radius */
}

.range-input::-moz-range-track {
@apply h-1 bg-zinc-500 rounded-full;
}

.range-input::-ms-track {
@apply h-1 bg-zinc-500 rounded-full;
}

/* Thumb Styles */
.range-input::-webkit-slider-thumb {
-webkit-appearance: none;
@apply h-4 w-4 bg-white rounded-full;
margin-top: -5px;
}

.range-input::-moz-range-thumb {
@apply h-4 w-4 bg-white rounded-full;
margin-top: -5px;
}

.range-input::-ms-thumb {
@apply h-4 w-4 bg-white rounded-full;
margin-top: -5px;
}

/* Focus Styles */
.range-input:focus {
outline: none;
}

/* Hover Effects */
.range-input:hover::-webkit-slider-runnable-track {
@apply bg-blue-600; /* Darken track on hover */
}

.range-input:hover::-moz-range-track {
@apply bg-blue-600;
}

.range-input:hover::-ms-track {
@apply bg-blue-600;
}
}
1 change: 1 addition & 0 deletions frontend/components/submit-process.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ gql`
getProcess(id: $id) {
id
name
youtubeUrl
status
}
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/lib/graphql/generated/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export type GetProcessQueryVariables = Exact<{
}>;


export type GetProcessQuery = { __typename?: 'Query', getProcess: { __typename?: 'Process', id: any, name: string, status: ProcessStatus } };
export type GetProcessQuery = { __typename?: 'Query', getProcess: { __typename?: 'Process', id: any, name: string, youtubeUrl: string, status: ProcessStatus } };


export const AllProcessesDocument = gql`
Expand Down Expand Up @@ -157,6 +157,7 @@ export const GetProcessDocument = gql`
getProcess(id: $id) {
id
name
youtubeUrl
status
}
}
Expand Down

0 comments on commit 8888210

Please sign in to comment.