refactor: Simplify AudioPlayer component by removing mobile detection logic and streamline download handling; enhance Home layout for better responsiveness
This commit is contained in:
@@ -12,35 +12,16 @@ interface AudioPlayerProps {
|
|||||||
jobId: number
|
jobId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMobileDevice = () => {
|
|
||||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
|
||||||
}
|
|
||||||
|
|
||||||
const AudioPlayer = memo(({ audioUrl, jobId }: AudioPlayerProps) => {
|
const AudioPlayer = memo(({ audioUrl, jobId }: AudioPlayerProps) => {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const [blobUrl, setBlobUrl] = useState<string>('')
|
const [blobUrl, setBlobUrl] = useState<string>('')
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [loadError, setLoadError] = useState<string | null>(null)
|
const [loadError, setLoadError] = useState<string | null>(null)
|
||||||
const [useMobileMode, setUseMobileMode] = useState(false)
|
|
||||||
const previousAudioUrlRef = useRef<string>('')
|
const previousAudioUrlRef = useRef<string>('')
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setUseMobileMode(isMobileDevice())
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!audioUrl || audioUrl === previousAudioUrlRef.current) return
|
if (!audioUrl || audioUrl === previousAudioUrlRef.current) return
|
||||||
|
|
||||||
if (useMobileMode) {
|
|
||||||
const token = localStorage.getItem('token')
|
|
||||||
const separator = audioUrl.includes('?') ? '&' : '?'
|
|
||||||
const urlWithToken = token ? `${audioUrl}${separator}token=${token}` : audioUrl
|
|
||||||
setBlobUrl(urlWithToken)
|
|
||||||
previousAudioUrlRef.current = audioUrl
|
|
||||||
setIsLoading(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let active = true
|
let active = true
|
||||||
const prevBlobUrl = blobUrl
|
const prevBlobUrl = blobUrl
|
||||||
|
|
||||||
@@ -76,7 +57,7 @@ const AudioPlayer = memo(({ audioUrl, jobId }: AudioPlayerProps) => {
|
|||||||
return () => {
|
return () => {
|
||||||
active = false
|
active = false
|
||||||
}
|
}
|
||||||
}, [audioUrl, useMobileMode])
|
}, [audioUrl, blobUrl, t])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
@@ -85,15 +66,11 @@ const AudioPlayer = memo(({ audioUrl, jobId }: AudioPlayerProps) => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleDownload = useCallback(() => {
|
const handleDownload = useCallback(() => {
|
||||||
if (useMobileMode) {
|
const link = document.createElement('a')
|
||||||
window.open(blobUrl || audioUrl, '_blank')
|
link.href = blobUrl || audioUrl
|
||||||
} else {
|
link.download = `tts-${jobId}-${Date.now()}.wav`
|
||||||
const link = document.createElement('a')
|
link.click()
|
||||||
link.href = blobUrl || audioUrl
|
}, [blobUrl, audioUrl, jobId])
|
||||||
link.download = `tts-${jobId}-${Date.now()}.wav`
|
|
||||||
link.click()
|
|
||||||
}
|
|
||||||
}, [blobUrl, audioUrl, jobId, useMobileMode])
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState, useRef, lazy, Suspense, useEffect } from 'react'
|
import { useState, useRef, lazy, Suspense, useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Navbar } from '@/components/Navbar'
|
import { Navbar } from '@/components/Navbar'
|
||||||
import { Card, CardContent, CardHeader } from '@/components/ui/card'
|
import { Card, CardContent } from '@/components/ui/card'
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||||
import { User, Palette, Copy } from 'lucide-react'
|
import { User, Palette, Copy } from 'lucide-react'
|
||||||
import type { CustomVoiceFormHandle } from '@/components/tts/CustomVoiceForm'
|
import type { CustomVoiceFormHandle } from '@/components/tts/CustomVoiceForm'
|
||||||
@@ -47,49 +47,47 @@ function Home() {
|
|||||||
onOpenChange={setSidebarOpen}
|
onOpenChange={setSidebarOpen}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<main className="flex-1 overflow-y-auto container mx-auto p-3 md:p-6 max-w-[800px] md:max-w-[700px]">
|
<main className="flex-1 overflow-y-auto flex items-start md:items-center justify-center">
|
||||||
<Card>
|
<div className="w-full container mx-auto p-3 md:p-6 max-w-[800px] md:max-w-[700px]">
|
||||||
<CardHeader>
|
<Tabs value={currentTab} onValueChange={setCurrentTab}>
|
||||||
<Tabs value={currentTab} onValueChange={setCurrentTab}>
|
<TabsList className="grid w-full grid-cols-3 h-9 mb-3">
|
||||||
<TabsList className="grid w-full grid-cols-3 h-9">
|
<TabsTrigger value="custom-voice" variant="default">
|
||||||
<TabsTrigger value="custom-voice" variant="default">
|
<User className="h-4 w-4 md:mr-2" />
|
||||||
<User className="h-4 w-4 md:mr-2" />
|
<span className="hidden md:inline">{t('customVoiceTab')}</span>
|
||||||
<span className="hidden md:inline">{t('customVoiceTab')}</span>
|
</TabsTrigger>
|
||||||
</TabsTrigger>
|
<TabsTrigger value="voice-design" variant="secondary">
|
||||||
<TabsTrigger value="voice-design" variant="secondary">
|
<Palette className="h-4 w-4 md:mr-2" />
|
||||||
<Palette className="h-4 w-4 md:mr-2" />
|
<span className="hidden md:inline">{t('voiceDesignTab')}</span>
|
||||||
<span className="hidden md:inline">{t('voiceDesignTab')}</span>
|
</TabsTrigger>
|
||||||
</TabsTrigger>
|
<TabsTrigger value="voice-clone" variant="outline">
|
||||||
<TabsTrigger value="voice-clone" variant="outline">
|
<Copy className="h-4 w-4 md:mr-2" />
|
||||||
<Copy className="h-4 w-4 md:mr-2" />
|
<span className="hidden md:inline">{t('voiceCloneTab')}</span>
|
||||||
<span className="hidden md:inline">{t('voiceCloneTab')}</span>
|
</TabsTrigger>
|
||||||
</TabsTrigger>
|
</TabsList>
|
||||||
</TabsList>
|
|
||||||
</Tabs>
|
|
||||||
</CardHeader>
|
|
||||||
|
|
||||||
<CardContent className="pt-0 px-3 md:px-6">
|
<Card>
|
||||||
<Tabs value={currentTab}>
|
<CardContent className="pt-6 px-3 md:px-6 pb-6">
|
||||||
<TabsContent value="custom-voice" className="mt-0">
|
<TabsContent value="custom-voice" className="mt-0">
|
||||||
<Suspense fallback={<FormSkeleton />}>
|
<Suspense fallback={<FormSkeleton />}>
|
||||||
<CustomVoiceForm ref={customVoiceFormRef} />
|
<CustomVoiceForm ref={customVoiceFormRef} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="voice-design" className="mt-0">
|
<TabsContent value="voice-design" className="mt-0">
|
||||||
<Suspense fallback={<FormSkeleton />}>
|
<Suspense fallback={<FormSkeleton />}>
|
||||||
<VoiceDesignForm ref={voiceDesignFormRef} />
|
<VoiceDesignForm ref={voiceDesignFormRef} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="voice-clone" className="mt-0">
|
<TabsContent value="voice-clone" className="mt-0">
|
||||||
<Suspense fallback={<FormSkeleton />}>
|
<Suspense fallback={<FormSkeleton />}>
|
||||||
<VoiceCloneForm />
|
<VoiceCloneForm />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</CardContent>
|
||||||
</CardContent>
|
</Card>
|
||||||
</Card>
|
</Tabs>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user