更新至 v0.6.0_20251125 版本

This commit is contained in:
2025-11-25 22:31:59 +08:00
parent b53183e931
commit 66fa85e474
6 changed files with 274 additions and 43 deletions

View File

@@ -1,10 +1,8 @@
import React, { useState, useRef, useEffect } from 'react';
import { Language, ListeningLesson, ListeningLessonRecord, ReadingDifficulty, ChatMessage, Role, MessageType } from '../types';
import { geminiService, decodeAudioData } from '../services/geminiService';
import { processAndDownloadAudio } from '../utils/audioUtils';
import { Headphones, Loader2, Send, Eye, EyeOff, List, HelpCircle, ChevronLeft, History, Trash2, X, PanelRightClose, PanelRightOpen, Volume2, Square, Play, Pause, CheckCircle, AlertCircle, FileText, MessageCircle, Download, RotateCcw } from 'lucide-react';
import { Headphones, Loader2, Send, Eye, EyeOff, List, HelpCircle, ChevronLeft, History, Trash2, X, PanelRightClose, PanelRightOpen, Volume2, Square, Play, Pause, CheckCircle, AlertCircle, FileText, MessageCircle, Download, RotateCcw, Copy, Check } from 'lucide-react';
import { translations } from '../utils/localization';
import ChatBubble from '../components/ChatBubble';
@@ -17,6 +15,28 @@ interface ListeningViewProps {
onDeleteHistoryItem: (id: string) => void;
}
// Internal Copy Button Component
const CopyButton: React.FC<{ text: string; label?: string }> = ({ text, label }) => {
const [copied, setCopied] = useState(false);
const handleCopy = (e: React.MouseEvent) => {
e.stopPropagation();
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<button
onClick={handleCopy}
className="p-1.5 rounded-lg text-slate-400 hover:bg-slate-100 hover:text-slate-600 transition-colors flex items-center gap-1"
title={label || "Copy"}
>
{copied ? <Check size={16} className="text-emerald-500" /> : <Copy size={16} />}
</button>
);
};
const ListeningView: React.FC<ListeningViewProps> = ({ language, history, onSaveToHistory, onUpdateHistory, onClearHistory, onDeleteHistoryItem }) => {
const t = translations[language].listening;
const tCommon = translations[language].common;
@@ -603,15 +623,21 @@ const ListeningView: React.FC<ListeningViewProps> = ({ language, history, onSave
{/* Script Reveal */}
{showScript && (
<div className="animate-fade-in-up">
<div className="bg-white p-6 md:p-8 rounded-2xl border border-slate-200 shadow-sm mb-6">
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider mb-4">{t.scriptTitle}</h4>
<div className="bg-white p-6 md:p-8 rounded-2xl border border-slate-200 shadow-sm mb-6 relative">
<div className="flex items-center justify-between mb-4">
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider">{t.scriptTitle}</h4>
<CopyButton text={lesson.script || ''} label={tCommon.copy} />
</div>
<p className="text-lg md:text-xl leading-loose font-serif text-slate-800 whitespace-pre-wrap">
{lesson.script || <span className="text-red-400 italic">{t.scriptMissing}</span>}
</p>
</div>
<div className="bg-slate-50 p-6 rounded-2xl border border-slate-200 mb-6">
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider mb-2">{translations[language].reading.translationLabel}</h4>
<div className="bg-slate-50 p-6 rounded-2xl border border-slate-200 mb-6 relative">
<div className="flex items-center justify-between mb-2">
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider">{translations[language].reading.translationLabel}</h4>
<CopyButton text={lesson.translation || ''} label={tCommon.copy} />
</div>
<p className="text-slate-700 leading-relaxed">{lesson.translation}</p>
</div>