diff --git a/src/App.tsx b/src/App.tsx index ada75ef..8819e9f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,103 +1,29 @@ 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 { initials, finales } from './data'; +import { BtnColor, Tone } from './types'; import { strings } from './strings'; - -const defaultFoundState:Found = { - allfinales: false, - allInitiales: false, - finales: [], - initiales: [], - syllables: [], - toneS: [], - randomTones: [] -} +import { useStateContext } from './store'; +import { Params } from './params'; +import { ActionType, ToggleType } from './reducer'; +import { ButtonSet } from './buttons'; enum Status {params, plaing, plaied, showlist} function App() { + + const { state, dispatch } = useStateContext(); - const [ count, setCount ] = useState(10) - const [ pause, setPause ] = useState(3) - - const [ found, setFound ] = useState(defaultFoundState) - - const onchangepause = (e: React.ChangeEvent ) => setPause( Number(e.target.value) ) - const onchangecount = (e: React.ChangeEvent ) => { - 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 isFound = ():boolean => state.foundSyllables!.length > 0 const [plaingNo, setPlaingNo ] = useState(0) -// ---- опять по новой const [ status, setStatus ] = useState(Status.params) const beginDictation = (): void => { - refreshRandomTones() - console.debug(found.randomTones) - playDictation2(found.randomTones) + dispatch({ type: ActionType.refreshPlayList }) + playDictation2(state.randomTones!) } const playDictation2 = (randomTones: Tone[]) => { @@ -114,7 +40,7 @@ const playDictation2 = (randomTones: Tone[]) => { let pno = x+2 setPlaingNo(pno) audios[x+1].play() - }, 1000*pause ) ; + }, 1000*state.sylPause! ) ; } audios[audios.length-1].onended = () => setStatus(Status.plaied) setStatus(Status.plaing) @@ -123,60 +49,36 @@ const playDictation2 = (randomTones: Tone[]) => { } const renderRandomTones2 = () => { - return found.randomTones.map( (ton, i) => { return {ton.caption}{' '} }) + return state.randomTones!.map( (ton, i) => { return {ton.caption}{' '} }) } const refresh = () => { - refreshRandomTones() + dispatch({ type: ActionType.refreshPlayList }) setStatus(Status.params) } -const refreshRandomTones = () => { - let foundRandomTones = getRandomTones( found.toneS, count ) - setFound({...found, - randomTones: foundRandomTones - }) - } - return ( - <> + <>

Диктант pīnyīn

{strings.selectInitiales}

- - {initials.map( (text, i) => - )} +
+

{strings.selectFinales}

- - {finales.map( (fin, i) => - )} +
+

{strings.params}

- Количество слогов {count} - - Пауза между слогами {pause} секунд - -
+ + { status == Status.params && <> - Выбрано {found.initiales.length} инициалей, {found.finales.length} финалей, найдено {found.syllables.length} слогов, { found.toneS.length } тонов , + Выбрано {state.initiales!.length} инициалей, {state.finales!.length} финалей, найдено {state.foundSyllables!.length} слогов, { state.foundTones!.length } тонов ,
+ { source.map( (part, i) => + )} + +} \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 91445de..d114f17 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,9 +3,12 @@ import ReactDOM from 'react-dom/client' import App from './App.tsx' import './index.css' import 'bootstrap/dist/css/bootstrap.min.css'; +import { StateProvider } from './store.js'; ReactDOM.createRoot(document.getElementById('root')!).render( - + + + , ) diff --git a/src/params.tsx b/src/params.tsx new file mode 100644 index 0000000..49a9789 --- /dev/null +++ b/src/params.tsx @@ -0,0 +1,24 @@ +import { ReactElement } from "react"; +import { useStateContext } from "./store"; +import { Form } from "react-bootstrap"; +import { ActionType } from "./reducer"; +import { strings } from "./strings"; + +export const Params = (): ReactElement => { + + const { state, dispatch } = useStateContext(); + + const pausedispatcher = (e: React.ChangeEvent) => + dispatch({ type: ActionType.setPause, payload: Number(e.target.value)}) + const countdispatcher = (e: React.ChangeEvent) => + dispatch({ type: ActionType.setCount, payload: Number(e.target.value)}) + + return <> +

{strings.params}

+ Количество слогов {state.sylCount} + + Пауза между слогами {state.sylPause} секунд + + + +} \ No newline at end of file diff --git a/src/reducer.ts b/src/reducer.ts index e9dbf53..c0171d5 100644 --- a/src/reducer.ts +++ b/src/reducer.ts @@ -1,23 +1,88 @@ -import { Found } from "./types"; +import { finales, initials, tones } from "./data"; +import { IState } from "./store"; +import { SylPart, Syllable, Tone } from "./types"; +import { GetSyllablesByInitAndFin, getRandomArray, toggle } from "./utils"; export enum ActionType { - toggleInitiale, toggleFinale, toggleAllInitiales, toggleAllFinales + toggleOne, toggleAll, refreshPlayList, setPause, setCount } -export type Action = { type: ActionType } | { type: ActionType }; +export enum ToggleType { init, fin } +export type TogglePayload = { type: ToggleType, part: SylPart } -export const reducer = (state:Found, action:Action):Found => { +export type Action = { type: ActionType, payload?: any }; + +const ProceedAllInitials = (state: IState):{ allInitiales:boolean, initiales: SylPart[], foundSyllables:Syllable[], foundTones: Tone[]} => +{ + let toggled = state.allInitiales ? [] as SylPart[] : initials + let foundSyllables:Syllable[] = GetSyllablesByInitAndFin( toggled, state.finales ) + let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) ) + return { + allInitiales: !state.allInitiales, + initiales: toggled, + foundSyllables: foundSyllables, + foundTones: foundTones + } +} + +const ProceedAllFinales = (state: IState):{ allfinales:boolean, finales: SylPart[], foundSyllables:Syllable[], foundTones: Tone[]} => +{ + let toggled = state.allfinales ? [] as SylPart[] : finales + let foundSyllables:Syllable[] = GetSyllablesByInitAndFin( state.initiales, toggled ) + let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) ) + return { + allfinales: !state.allfinales, + finales: toggled, + foundSyllables: foundSyllables, + foundTones: foundTones + } +} + + +const ProceedInitiale = (state: IState, index: SylPart):{ initiales: SylPart[], foundSyllables:Syllable[], foundTones: Tone[]} => +{ + let toggled = toggle(state.initiales,index) + let foundSyllables:Syllable[] = GetSyllablesByInitAndFin( toggled, state.finales ) + let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) ) + return { + initiales: toggled, + foundSyllables: foundSyllables, + foundTones: foundTones + } +} + +const ProceedFinale = (state: IState, index: SylPart):{ finales: SylPart[], foundSyllables:Syllable[], foundTones: Tone[]} => +{ + let toggled = toggle(state.finales,index) + let foundSyllables:Syllable[] = GetSyllablesByInitAndFin( state.initiales , toggled ) + let foundTones = tones.filter( t => foundSyllables.some( syl => syl.tones.some( st => st===t.tone) ) ) + return { + finales: toggled, + foundSyllables: foundSyllables, + foundTones: foundTones + } +} + +export const reducer = (state:IState, action:Action):IState => { switch (action.type) { + case ActionType.setPause: return { ...state, sylPause: action.payload as number } + case ActionType.setCount: return { ...state, sylCount: action.payload as number } + case ActionType.refreshPlayList: return { ...state, randomTones: getRandomArray( state.foundTones, state.sylCount! ) } + + case ActionType.toggleAll: { + if (action.payload as ToggleType === ToggleType.init) return { ...state, ...ProceedAllInitials(state) } + if (action.payload as ToggleType === ToggleType.fin) return { ...state, ...ProceedAllFinales(state) } + return state + } + + case ActionType.toggleOne: { + if ( (action.payload as TogglePayload).type === ToggleType.init) + return { ...state, ...ProceedInitiale(state, (action.payload as TogglePayload).part ) } + if ( (action.payload as TogglePayload).type === ToggleType.fin) + return { ...state, ...ProceedFinale(state, (action.payload as TogglePayload).part ) } + return state + } + default: return state } -} - -export const defaultState:Found = { - allfinales: false, - allInitiales: false, - finales: [], - initiales: [], - syllables: [], - toneS: [], - randomTones: [] - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/store.tsx b/src/store.tsx index 27f6153..db96114 100644 --- a/src/store.tsx +++ b/src/store.tsx @@ -1,17 +1,54 @@ import { Context, createContext, Dispatch, ReactElement, useContext, useReducer } from "react"; -import { reducer, defaultState, Action } from "./reducer" -import { Found } from "./types"; +import { reducer, Action, ToggleType } from "./reducer" +import { Syllable, SylPart, Tone } from "./types"; +import { isEnabled } from "./utils"; -export interface IStore { - state: Found - dispatch?: Dispatch +export interface IState { + sylCount: number, + sylPause: number, + initiales: SylPart[], + finales: SylPart[], + allInitiales: boolean, + allfinales: boolean, + foundSyllables: Syllable[], + foundTones: Tone[], + randomTones: Tone[], + allEnabled: (type: ToggleType) => false, + isEnabled: (type: ToggleType, index: string) => false } -export const AppContext:Context = createContext({ state: defaultState, dispatch: () => null }) +export interface IStore { + state: Partial + dispatch: Dispatch +} + +export const defaultState:Object = { + sylCount: 10, + sylPause: 3, + allfinales: false, + allInitiales: false, + finales: [] as SylPart[], + initiales: [] as SylPart[], + foundSyllables: [], + foundTones: [], + randomTones: [], + allEnabled: function(type: ToggleType) { + if ( type === ToggleType.init ) return (this as IState).allInitiales + if ( type === ToggleType.fin ) return (this as IState).allfinales + return false + }, + isEnabled: function(type: ToggleType, index: string) { + if ( type === ToggleType.init ) return isEnabled((this as IState).initiales!, index) + if ( type === ToggleType.fin ) return isEnabled((this as IState).finales!, index) + return false + } + } + +export const AppContext:Context = createContext({ state: defaultState as IState, dispatch: () => null }) export const useStateContext = () => useContext(AppContext); export const StateProvider = ({ children }: { children: ReactElement }) => { - const [state, dispatch] = useReducer(reducer, defaultState); + const [state, dispatch] = useReducer(reducer, defaultState as IState); return } \ No newline at end of file