pinyindct-open/src/App.tsx

210 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useState } from 'react'
import './App.css'
import Form from 'react-bootstrap/Form';
import { Badge, Button, ListGroup } from 'react-bootstrap';
import { initials, finales, syllables, tones } from './data';
import { getRandomTones, isEnabled, toggle } from './utils';
import { Found, Syllable, Tone } from './types';
import { strings } from './strings';
const defaultFoundState:Found = {
allfinales: false,
allInitiales: false,
finales: [],
initiales: [],
syllables: [],
toneS: [],
randomTones: []
}
enum Status {params, plaing, plaied, showlist}
function App() {
const [ count, setCount ] = useState(10)
const [ pause, setPause ] = useState(3)
const [ found, setFound ] = useState(defaultFoundState)
const onchangepause = (e: React.ChangeEvent<HTMLInputElement> ) => setPause( Number(e.target.value) )
const onchangecount = (e: React.ChangeEvent<HTMLInputElement> ) => {
setCount( Number(e.target.value) )
refreshRandomTones()
}
//---------------- to found state
const toggleAllInitiales = () => {
let toggled = found.allInitiales ? [] : initials
let foundSyllables:Syllable[] = syllables.filter( syl =>
toggled.includes(syl.initiale) && found.finales.includes(syl.finale) )
let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) )
let foundRandomTones = getRandomTones( foundTones, count )
setFound({...found,
allInitiales: !found.allInitiales,
initiales: toggled,
syllables: foundSyllables,
toneS: foundTones,
randomTones: foundRandomTones
})
}
const toggleInitialsState = (caption: string) => {
let toggled = toggle(found.initiales,caption)
let foundSyllables:Syllable[] = syllables.filter( syl =>
toggled.includes(syl.initiale) && found.finales.includes(syl.finale) )
let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) )
let foundRandomTones = getRandomTones( foundTones, count )
setFound({...found,
initiales: toggled,
syllables: foundSyllables,
toneS: foundTones,
randomTones: foundRandomTones
})
}
const toggleAllFinales = () => {
let toggled = found.allfinales ? [] : finales.map( f => f.finale)
let foundSyllables:Syllable[] = syllables.filter ( syl =>
found.initiales.includes( syl.initiale) && toggled.includes( syl.finale ) )
let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) )
let foundRandomTones = getRandomTones( foundTones, count )
setFound({...found,
allfinales: !found.allfinales,
finales: toggled,
syllables: foundSyllables,
toneS: foundTones,
randomTones: foundRandomTones
})
}
const toggleFinalsState = (caption: string) => {
let toggled = toggle(found.finales,caption)
let foundSyllables:Syllable[] = syllables.filter ( syl =>
found.initiales.includes( syl.initiale) && toggled.includes( syl.finale ) )
let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) )
let foundRandomTones = getRandomTones( foundTones, count )
setFound({...found,
finales: toggled,
syllables: foundSyllables,
toneS: foundTones,
randomTones: foundRandomTones
})
}
const isFound = ():boolean => found.syllables.length > 0
const [plaingNo, setPlaingNo ] = useState(0)
// ---- опять по новой
const [ status, setStatus ] = useState(Status.params)
const beginDictation = (): void => {
refreshRandomTones()
console.debug(found.randomTones)
playDictation2(found.randomTones)
}
const playDictation2 = (randomTones: Tone[]) => {
if ( randomTones.length == 0 ) return
let audios:HTMLAudioElement[] = []
randomTones.forEach(element => {
audios = [...audios, new Audio(`/src/assets/audio/${element.tone}.mp3`) ]
});
console.debug(audios)
if ( audios.length == 0 ) return
for(let x=0; x<audios.length-1;x++)
{
audios[x].onended = () => setTimeout( () => {
let pno = x+2
setPlaingNo(pno)
audios[x+1].play()
}, 1000*pause ) ;
}
audios[audios.length-1].onended = () => setStatus(Status.plaied)
setStatus(Status.plaing)
setPlaingNo(1)
audios[0].play()
}
const renderRandomTones2 = () => {
return found.randomTones.map( (ton, i) => { return <span key={i}><Badge bg="success" pill>{ton.caption}</Badge>{' '}</span> })
}
const refresh = () => {
refreshRandomTones()
setStatus(Status.params)
}
const refreshRandomTones = () => {
let foundRandomTones = getRandomTones( found.toneS, count )
setFound({...found,
randomTones: foundRandomTones
})
}
return (
<>
<h1>Диктант pīnyīn</h1>
<ListGroup>
<ListGroup.Item disabled={status != Status.params}>
<h2>{strings.selectInitiales}</h2>
<Button variant={found.allInitiales ? "primary" : "outline-primary"}
onClick= {()=>toggleAllInitiales()}>
{found.allInitiales ? strings.unselectAll : strings.selectAll}
</Button>
{initials.map( (text, i) => <Button variant={isEnabled(found.initiales, text) ? "primary" : "outline-primary"}
key={i} onClick={()=>toggleInitialsState(text)}>
{text}
</Button>
)}
</ListGroup.Item>
<ListGroup.Item disabled={status != Status.params}>
<h2>{strings.selectFinales}</h2>
<Button variant={found.allfinales ? "success" : "outline-success"}
onClick= {toggleAllFinales}>
{found.allfinales ? strings.unselectAll : strings.selectAll}
</Button>
{finales.map( (fin, i) => <Button variant={isEnabled(found.finales, fin.finale) ? "success" : "outline-success"}
key={i} onClick={()=>toggleFinalsState(fin.finale)}>
{fin.caption}
</Button>
)}
</ListGroup.Item>
<ListGroup.Item disabled={status != Status.params}>
<h2>{strings.params}</h2>
<Form.Label>Количество слогов {count}</Form.Label>
<Form.Range value={count} min={5} max={50} step={5} onChange={onchangecount}/>
<Form.Label>Пауза между слогами {pause} секунд</Form.Label>
<Form.Range value={pause} min={1} max={10} step={1} onChange={onchangepause}/>
</ListGroup.Item>
<ListGroup.Item>
{ status == Status.params &&
<>
Выбрано {found.initiales.length} инициалей, {found.finales.length} финалей, найдено {found.syllables.length} слогов, { found.toneS.length } тонов ,
<br/>
<Button variant={isFound() ? "success" : "secondary"} size="lg" onClick={()=>beginDictation()} disabled={!isFound()}>
{isFound() ? "Начать диктант!" : "Выберите инициали и финали" }
</Button>
</>
}
{
status == Status.plaing &&
<h1>Воспроизводится...{plaingNo}</h1>
}
{
status == Status.plaied &&
<Button variant="success" onClick={()=>setStatus(Status.showlist)}>Показать слоги</Button>
}
{
status == Status.showlist &&
<>
<div>{renderRandomTones2()}</div>
<br/>
<Button variant="success" onClick={()=>refresh()}>В начало</Button>
</>
}
</ListGroup.Item>
</ListGroup>
</>
)
}
export default App