diff --git a/next.config.ts b/next.config.ts index 29d246d6..6f02c9d8 100644 --- a/next.config.ts +++ b/next.config.ts @@ -19,7 +19,6 @@ const nextConfig: NextConfig = { }, ]; }, - }; export default nextConfig; diff --git a/public/mp3-logo.png b/public/mp3-logo.png new file mode 100644 index 00000000..97b75edf Binary files /dev/null and b/public/mp3-logo.png differ diff --git a/src/app/darmasaba/(pages)/musik/lib/nextPrev.ts b/src/app/darmasaba/(pages)/musik/lib/nextPrev.ts new file mode 100644 index 00000000..632de027 --- /dev/null +++ b/src/app/darmasaba/(pages)/musik/lib/nextPrev.ts @@ -0,0 +1,32 @@ +export function getNextIndex( + currentIndex: number, + total: number, + isShuffle: boolean +) { + if (total === 0) return -1; + + if (isShuffle) { + return Math.floor(Math.random() * total); + } + + return (currentIndex + 1) % total; +} + +export function getPrevIndex( + currentIndex: number, + total: number, + isShuffle: boolean +) { + if (total === 0) return -1; + + if (isShuffle) { + return Math.floor(Math.random() * total); + } + + return currentIndex - 1 < 0 ? total - 1 : currentIndex - 1; +} + +//pakai di ui + +// const next = getNextIndex(currentSongIndex, filteredMusik.length, isShuffle); +// playSong(next); \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/musik/lib/playPause.ts b/src/app/darmasaba/(pages)/musik/lib/playPause.ts new file mode 100644 index 00000000..b09b482a --- /dev/null +++ b/src/app/darmasaba/(pages)/musik/lib/playPause.ts @@ -0,0 +1,24 @@ +import { RefObject } from "react"; + +export function togglePlayPause( + audioRef: RefObject, + isPlaying: boolean, + setIsPlaying: (v: boolean) => void +) { + if (!audioRef.current) return; + + if (isPlaying) { + audioRef.current.pause(); + setIsPlaying(false); + } else { + audioRef.current + .play() + .then(() => setIsPlaying(true)) + .catch(console.error); + } +} + +// pakai di ui +// onClick={() => +// togglePlayPause(audioRef, isPlaying, setIsPlaying) +// } \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/musik/lib/repeat.ts b/src/app/darmasaba/(pages)/musik/lib/repeat.ts new file mode 100644 index 00000000..3a745f96 --- /dev/null +++ b/src/app/darmasaba/(pages)/musik/lib/repeat.ts @@ -0,0 +1,22 @@ +import { RefObject } from "react"; + +export function handleRepeatOrNext( + audioRef: RefObject, + isRepeat: boolean, + playNext: () => void +) { + if (!audioRef.current) return; + + if (isRepeat) { + audioRef.current.currentTime = 0; + audioRef.current.play(); + } else { + playNext(); + } +} + +//dipakai di ui + +// onEnded={() => +// handleRepeatOrNext(audioRef, isRepeat, playNext) +// } \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/musik/lib/seek.ts b/src/app/darmasaba/(pages)/musik/lib/seek.ts new file mode 100644 index 00000000..eca6ac81 --- /dev/null +++ b/src/app/darmasaba/(pages)/musik/lib/seek.ts @@ -0,0 +1,25 @@ +export function seekTo( + audioRef: React.RefObject, + time: number +) { + if (!audioRef.current) return; + audioRef.current.currentTime = time; +} + + +// import { RefObject } from "react"; + +// export function seekTo( +// audioRef: RefObject, +// time: number, +// setCurrentTime: (v: number) => void +// ) { +// if (!audioRef.current) return; + +// audioRef.current.currentTime = time; +// setCurrentTime(time); +// } + +// //pakai di ui + +// // onChange={(v) => seekTo(audioRef, v, setCurrentTime)} diff --git a/src/app/darmasaba/(pages)/musik/lib/shuffle.ts b/src/app/darmasaba/(pages)/musik/lib/shuffle.ts new file mode 100644 index 00000000..acb866d2 --- /dev/null +++ b/src/app/darmasaba/(pages)/musik/lib/shuffle.ts @@ -0,0 +1,6 @@ +export function toggleShuffle( + isShuffle: boolean, + setIsShuffle: (v: boolean) => void +) { + setIsShuffle(!isShuffle); +} \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/musik/lib/volume.ts b/src/app/darmasaba/(pages)/musik/lib/volume.ts new file mode 100644 index 00000000..431686f8 --- /dev/null +++ b/src/app/darmasaba/(pages)/musik/lib/volume.ts @@ -0,0 +1,29 @@ +import { RefObject } from "react"; + +export function setAudioVolume( + audioRef: RefObject, + volume: number, + setVolume: (v: number) => void, + setIsMuted: (v: boolean) => void +) { + if (!audioRef.current) return; + + audioRef.current.volume = volume / 100; + setVolume(volume); + + if (volume > 0) { + setIsMuted(false); + } +} + +export function toggleMute( + audioRef: RefObject, + isMuted: boolean, + setIsMuted: (v: boolean) => void +) { + if (!audioRef.current) return; + + const muted = !isMuted; + audioRef.current.muted = muted; + setIsMuted(muted); +} \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx b/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx index 6368caf8..8556c9a3 100644 --- a/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx +++ b/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx @@ -1,9 +1,14 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import { ActionIcon, Avatar, Badge, Box, Card, Flex, Grid, Group, Paper, ScrollArea, Slider, Stack, Text, TextInput } from '@mantine/core'; import { IconArrowsShuffle, IconPlayerPauseFilled, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerSkipForwardFilled, IconRepeat, IconRepeatOff, IconSearch, IconVolume, IconVolumeOff, IconX } from '@tabler/icons-react'; import { useEffect, useRef, useState } from 'react'; import BackButton from '../../desa/layanan/_com/BackButto'; +import { togglePlayPause } from '../lib/playPause'; +import { getNextIndex, getPrevIndex } from '../lib/nextPrev'; +import { handleRepeatOrNext } from '../lib/repeat'; +import { seekTo } from '../lib/seek'; +import { toggleShuffle } from '../lib/shuffle'; +import { setAudioVolume, toggleMute as toggleMuteUtil } from '../lib/volume'; interface MusicFile { id: string; @@ -39,9 +44,8 @@ const MusicPlayer = () => { const [musikData, setMusikData] = useState([]); const [loading, setLoading] = useState(true); const [currentSongIndex, setCurrentSongIndex] = useState(-1); - + const [isSeeking, setIsSeeking] = useState(false); const audioRef = useRef(null); - const progressInterval = useRef(null); // Fetch musik data from API useEffect(() => { @@ -71,30 +75,30 @@ const MusicPlayer = () => { (musik.genre && musik.genre.toLowerCase().includes(search.toLowerCase())) ); - const currentSong = currentSongIndex >= 0 && currentSongIndex < filteredMusik.length - ? filteredMusik[currentSongIndex] + const currentSong = currentSongIndex >= 0 && currentSongIndex < filteredMusik.length + ? filteredMusik[currentSongIndex] : null; - // Update progress bar - useEffect(() => { - if (isPlaying && audioRef.current) { - progressInterval.current = window.setInterval(() => { - if (audioRef.current) { - setCurrentTime(Math.floor(audioRef.current.currentTime)); - } - }, 1000); - } else { - if (progressInterval.current) { - clearInterval(progressInterval.current); - } - } + // // Update progress bar + // useEffect(() => { + // if (isPlaying && audioRef.current) { + // progressInterval.current = window.setInterval(() => { + // if (audioRef.current) { + // setCurrentTime(Math.floor(audioRef.current.currentTime)); + // } + // }, 1000); + // } else { + // if (progressInterval.current) { + // clearInterval(progressInterval.current); + // } + // } - return () => { - if (progressInterval.current) { - clearInterval(progressInterval.current); - } - }; - }, [isPlaying]); + // return () => { + // if (progressInterval.current) { + // clearInterval(progressInterval.current); + // } + // }; + // }, [isPlaying]); // Update duration when song changes useEffect(() => { @@ -110,7 +114,7 @@ const MusicPlayer = () => { }); } } - }, [currentSongIndex]); + }, [currentSongIndex, currentSong, isPlaying]); const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60); @@ -120,84 +124,64 @@ const MusicPlayer = () => { const playSong = (index: number) => { if (index < 0 || index >= filteredMusik.length) return; - + setCurrentSongIndex(index); setIsPlaying(true); }; const handleSongEnd = () => { - if (isRepeat) { - if (audioRef.current) { - audioRef.current.currentTime = 0; - audioRef.current.play(); - } - } else { - // Play next song + const playNext = () => { let nextIndex: number; if (isShuffle) { nextIndex = Math.floor(Math.random() * filteredMusik.length); } else { nextIndex = (currentSongIndex + 1) % filteredMusik.length; } - + if (filteredMusik.length > 1) { playSong(nextIndex); } else { setIsPlaying(false); setCurrentTime(0); } - } + }; + + handleRepeatOrNext(audioRef, isRepeat, playNext); }; const handleSeek = (value: number) => { - setCurrentTime(value); - if (audioRef.current) { - audioRef.current.currentTime = value; - } + seekTo(audioRef, value); }; const toggleMute = () => { - const newMuted = !isMuted; - setIsMuted(newMuted); - if (audioRef.current) { - audioRef.current.muted = newMuted; - } + toggleMuteUtil(audioRef, isMuted, setIsMuted); }; const handleVolumeChange = (val: number) => { - setVolume(val); - if (audioRef.current) { - audioRef.current.volume = val / 100; - } - if (val > 0 && isMuted) { - setIsMuted(false); - } + setAudioVolume(audioRef, val, setVolume, setIsMuted); }; const skipBack = () => { - if (audioRef.current) { - audioRef.current.currentTime = Math.max(0, audioRef.current.currentTime - 10); + const prevIndex = getPrevIndex(currentSongIndex, filteredMusik.length, isShuffle); + if (prevIndex >= 0) { + playSong(prevIndex); } }; const skipForward = () => { - if (audioRef.current) { - audioRef.current.currentTime = Math.min(duration, audioRef.current.currentTime + 10); + const nextIndex = getNextIndex(currentSongIndex, filteredMusik.length, isShuffle); + if (nextIndex >= 0) { + playSong(nextIndex); } }; - const togglePlayPause = () => { + const toggleShuffleHandler = () => { + toggleShuffle(isShuffle, setIsShuffle); + }; + + const togglePlayPauseHandler = () => { if (!currentSong) return; - - if (isPlaying) { - audioRef.current?.pause(); - setIsPlaying(false); - } else { - audioRef.current?.play().catch(err => { - console.error('Error playing audio:', err); - }); - setIsPlaying(true); - } + togglePlayPause(audioRef, isPlaying, setIsPlaying); }; if (loading) { @@ -217,13 +201,16 @@ const MusicPlayer = () => {