mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-18 14:27:51 +00:00
feat: adicionando controles de texto
This commit is contained in:
parent
dd9e2f4dd3
commit
51b8fb4088
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { ArrowLeft, ArrowRight, Volume2, Share2, ChevronDown, ChevronUp, Loader2, Pause, Play, Download, RefreshCw, Trash2, TextSelect } from 'lucide-react';
|
import { ArrowLeft, ArrowRight, Share2, ChevronDown, ChevronUp, Loader2, Download, RefreshCw, Trash2, Type } from 'lucide-react';
|
||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { supabase } from '../../lib/supabase';
|
import { supabase } from '../../lib/supabase';
|
||||||
import { AudioRecorder } from '../../components/story/AudioRecorder';
|
import { AudioRecorder } from '../../components/story/AudioRecorder';
|
||||||
@ -9,7 +9,7 @@ import { convertWebmToMp3 } from '../../utils/audioConverter';
|
|||||||
import * as Dialog from '@radix-ui/react-dialog';
|
import * as Dialog from '@radix-ui/react-dialog';
|
||||||
import { ExerciseSuggestions } from '../../components/learning/ExerciseSuggestions';
|
import { ExerciseSuggestions } from '../../components/learning/ExerciseSuggestions';
|
||||||
import { TextCaseToggle } from '../../components/ui/text-case-toggle';
|
import { TextCaseToggle } from '../../components/ui/text-case-toggle';
|
||||||
import { AdaptiveText, AdaptiveTitle, AdaptiveParagraph } from '../../components/ui/adaptive-text';
|
import { AdaptiveText } from '../../components/ui/adaptive-text';
|
||||||
import { useSession } from '../../hooks/useSession';
|
import { useSession } from '../../hooks/useSession';
|
||||||
import { useSyllables } from '../../features/syllables/hooks/useSyllables';
|
import { useSyllables } from '../../features/syllables/hooks/useSyllables';
|
||||||
import { useUppercasePreference } from '../../hooks/useUppercasePreference';
|
import { useUppercasePreference } from '../../hooks/useUppercasePreference';
|
||||||
@ -38,7 +38,6 @@ interface StoryRecording {
|
|||||||
|
|
||||||
function RecordingHistoryCard({ recording }: { recording: StoryRecording }) {
|
function RecordingHistoryCard({ recording }: { recording: StoryRecording }) {
|
||||||
const [isExpanded, setIsExpanded] = React.useState(false);
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
||||||
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
||||||
const [isAudioSupported, setIsAudioSupported] = React.useState(true);
|
const [isAudioSupported, setIsAudioSupported] = React.useState(true);
|
||||||
const audioRef = React.useRef<HTMLAudioElement | null>(null);
|
const audioRef = React.useRef<HTMLAudioElement | null>(null);
|
||||||
const [isConverting, setIsConverting] = React.useState(false);
|
const [isConverting, setIsConverting] = React.useState(false);
|
||||||
@ -74,15 +73,11 @@ function RecordingHistoryCard({ recording }: { recording: StoryRecording }) {
|
|||||||
readyState: audioElement.readyState,
|
readyState: audioElement.readyState,
|
||||||
src: audioElement.src
|
src: audioElement.src
|
||||||
});
|
});
|
||||||
setIsPlaying(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePlayPause = async () => {
|
const handlePlayPause = async () => {
|
||||||
if (audioRef.current) {
|
if (audioRef.current) {
|
||||||
try {
|
try {
|
||||||
if (isPlaying) {
|
|
||||||
audioRef.current.pause();
|
|
||||||
} else {
|
|
||||||
if (audioRef.current.ended) {
|
if (audioRef.current.ended) {
|
||||||
audioRef.current.currentTime = 0;
|
audioRef.current.currentTime = 0;
|
||||||
}
|
}
|
||||||
@ -101,14 +96,10 @@ function RecordingHistoryCard({ recording }: { recording: StoryRecording }) {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Erro ao reproduzir áudio:', error);
|
console.error('Erro ao reproduzir áudio:', error);
|
||||||
setIsPlaying(false);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
setIsPlaying(!isPlaying);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao manipular áudio:', error);
|
console.error('Erro ao manipular áudio:', error);
|
||||||
setIsPlaying(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -152,10 +143,11 @@ function RecordingHistoryCard({ recording }: { recording: StoryRecording }) {
|
|||||||
const audio = audioRef.current;
|
const audio = audioRef.current;
|
||||||
|
|
||||||
if (audio) {
|
if (audio) {
|
||||||
const handleEnded = () => setIsPlaying(false);
|
const handleEnded = () => {
|
||||||
|
console.log('Reprodução encerrada');
|
||||||
|
};
|
||||||
const handleError = (e: ErrorEvent) => {
|
const handleError = (e: ErrorEvent) => {
|
||||||
console.error('Erro no áudio:', e);
|
console.error('Erro no áudio:', e);
|
||||||
setIsPlaying(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
audio.addEventListener('ended', handleEnded);
|
audio.addEventListener('ended', handleEnded);
|
||||||
@ -238,17 +230,7 @@ function RecordingHistoryCard({ recording }: { recording: StoryRecording }) {
|
|||||||
disabled={!recording.audio_url && !mp3Url}
|
disabled={!recording.audio_url && !mp3Url}
|
||||||
className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
|
className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{isPlaying ? (
|
|
||||||
<>
|
|
||||||
<Pause className="h-5 w-5" />
|
|
||||||
Pausar
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Play className="h-5 w-5" />
|
|
||||||
{recording.audio_url || mp3Url ? 'Ouvir' : 'Carregando...'}
|
{recording.audio_url || mp3Url ? 'Ouvir' : 'Carregando...'}
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -394,7 +376,6 @@ export function StoryPage() {
|
|||||||
const [currentPage, setCurrentPage] = React.useState(0);
|
const [currentPage, setCurrentPage] = React.useState(0);
|
||||||
const [loading, setLoading] = React.useState(true);
|
const [loading, setLoading] = React.useState(true);
|
||||||
const [error, setError] = React.useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
||||||
const [recordings, setRecordings] = React.useState<StoryRecording[]>([]);
|
const [recordings, setRecordings] = React.useState<StoryRecording[]>([]);
|
||||||
const [loadingRecordings, setLoadingRecordings] = React.useState(true);
|
const [loadingRecordings, setLoadingRecordings] = React.useState(true);
|
||||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||||
@ -706,7 +687,7 @@ export function StoryPage() {
|
|||||||
onClick={toggleSyllables}
|
onClick={toggleSyllables}
|
||||||
className="flex items-center gap-2 px-3 py-1.5 rounded-lg transition-colors text-gray-600 hover:text-gray-900 hover:bg-gray-100 border border-gray-200"
|
className="flex items-center gap-2 px-3 py-1.5 rounded-lg transition-colors text-gray-600 hover:text-gray-900 hover:bg-gray-100 border border-gray-200"
|
||||||
>
|
>
|
||||||
<TextSelect className="h-4 w-4" />
|
<Type className="h-4 w-4" />
|
||||||
<span className="text-sm font-medium">
|
<span className="text-sm font-medium">
|
||||||
{isSyllablesEnabled ? 'Desativar Sílabas' : 'Ativar Sílabas'}
|
{isSyllablesEnabled ? 'Desativar Sílabas' : 'Ativar Sílabas'}
|
||||||
</span>
|
</span>
|
||||||
@ -814,8 +795,27 @@ export function StoryPage() {
|
|||||||
<h2 className="text-lg font-semibold text-gray-900">Gravação de Áudio</h2>
|
<h2 className="text-lg font-semibold text-gray-900">Gravação de Áudio</h2>
|
||||||
<AudioRecorder
|
<AudioRecorder
|
||||||
storyId={story.id}
|
storyId={story.id}
|
||||||
onRecordingComplete={(recording) => {
|
studentId={session?.user?.id || ''}
|
||||||
setRecordings(prev => [recording, ...prev]);
|
onAudioUploaded={(audioUrl) => {
|
||||||
|
const newRecording: StoryRecording = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
audio_url: audioUrl,
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
processed_at: null,
|
||||||
|
fluency_score: 0,
|
||||||
|
pronunciation_score: 0,
|
||||||
|
accuracy_score: 0,
|
||||||
|
comprehension_score: 0,
|
||||||
|
words_per_minute: 0,
|
||||||
|
pause_count: 0,
|
||||||
|
error_count: 0,
|
||||||
|
self_corrections: 0,
|
||||||
|
strengths: [],
|
||||||
|
improvements: [],
|
||||||
|
suggestions: '',
|
||||||
|
transcription: ''
|
||||||
|
};
|
||||||
|
setRecordings(prev => [newRecording, ...prev]);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user