import React, { useState, useRef, useEffect } from 'react'; import { AppMode, Language } from '../types'; import { MessageCircle, Mic2, BookOpen, Headphones, ScanText, Languages, Palette, Play, Square, Loader2, Sparkles, Home } from 'lucide-react'; import { translations } from '../utils/localization'; import { geminiService, decodeAudioData } from '../services/geminiService'; interface HomeViewProps { language: Language; onNavigate: (mode: AppMode) => void; } const PHRASES = [ { ja: "継続は力なり", reading: "Keizoku wa chikara nari", en: "Perseverance is power.", zh: "坚持就是力量。" }, { ja: "一期一会", reading: "Ichigo ichie", en: "Treasure every meeting, for it will never recur.", zh: "一期一会 (珍惜每次相遇)。" }, { ja: "千里の道も一歩から", reading: "Senri no michi mo ippo kara", en: "A journey of a thousand miles begins with a single step.", zh: "千里之行,始于足下。" }, { ja: "七転び八起き", reading: "Nanakorobi yaoki", en: "Fall seven times, stand up eight.", zh: "七颠八起 (百折不挠)。" }, { ja: "知らぬが仏", reading: "Shiranu ga hotoke", en: "Ignorance is bliss.", zh: "不知者是佛 (眼不见为净)。" }, { ja: "花鳥風月", reading: "Kachou fuugetsu", en: "Experience the beauties of nature.", zh: "花鸟风月 (大自然的美景)。" }, { ja: "以心伝心", reading: "Ishin denshin", en: "Telepathy / Tacit understanding.", zh: "以心传心 (心领神会)。" } ]; const HomeView: React.FC = ({ language, onNavigate }) => { const t = translations[language].home; const tNav = translations[language].nav; const [phrase, setPhrase] = useState(PHRASES[0]); const [isPlaying, setIsPlaying] = useState(false); const [isLoadingAudio, setIsLoadingAudio] = useState(false); const audioContextRef = useRef(null); const audioSourceRef = useRef(null); useEffect(() => { // Select phrase based on day of year to change daily const dayOfYear = Math.floor((Date.now() - new Date(new Date().getFullYear(), 0, 0).getTime()) / 86400000); setPhrase(PHRASES[dayOfYear % PHRASES.length]); }, []); useEffect(() => { return () => { if (audioSourceRef.current) audioSourceRef.current.stop(); }; }, []); const playAudio = async () => { if (isPlaying) { if (audioSourceRef.current) audioSourceRef.current.stop(); setIsPlaying(false); return; } setIsLoadingAudio(true); try { const audioBase64 = await geminiService.generateSpeech(phrase.ja); if (audioBase64) { if (!audioContextRef.current) { audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)(); } const ctx = audioContextRef.current; if (ctx.state === 'suspended') await ctx.resume(); const buffer = await decodeAudioData(audioBase64, ctx); const source = ctx.createBufferSource(); source.buffer = buffer; source.connect(ctx.destination); source.onended = () => setIsPlaying(false); source.start(); audioSourceRef.current = source; setIsPlaying(true); } } catch (e) { console.error("Audio playback failed", e); } finally { setIsLoadingAudio(false); } }; const features = [ { mode: AppMode.CHAT, title: t.features.chatTitle, desc: t.features.chatDesc, icon: MessageCircle, color: 'text-indigo-500', bg: 'bg-indigo-50 border-indigo-100' }, { mode: AppMode.READING, title: t.features.readingTitle, desc: t.features.readingDesc, icon: BookOpen, color: 'text-emerald-500', bg: 'bg-emerald-50 border-emerald-100' }, { mode: AppMode.LISTENING, title: t.features.listeningTitle, desc: t.features.listeningDesc, icon: Headphones, color: 'text-sky-500', bg: 'bg-sky-50 border-sky-100' }, { mode: AppMode.SPEAKING, title: t.features.speakingTitle, desc: t.features.speakingDesc, icon: Mic2, color: 'text-orange-500', bg: 'bg-orange-50 border-orange-100' }, { mode: AppMode.TRANSLATION, title: t.features.toolsTitle, desc: t.features.toolsDesc, icon: Languages, color: 'text-blue-500', bg: 'bg-blue-50 border-blue-100' }, { mode: AppMode.CREATIVE, title: t.features.creativeTitle, desc: t.features.creativeDesc, icon: Palette, color: 'text-purple-500', bg: 'bg-purple-50 border-purple-100' }, ]; return (
{/* Header */}

{t.welcome}

{t.subtitle}

{/* Daily Phrase Card */}

{t.dailyPhrase}

{phrase.ja}

{phrase.reading}

{language === 'zh' ? phrase.zh : phrase.en}

{/* Features Grid */}
{features.map((feat, idx) => ( ))}
); }; export default HomeView;