elseifplayer/src/components/player/Player.jsx
2021-02-28 18:41:09 +05:00

120 lines
2.6 KiB
JavaScript

import { h } from 'preact'
import { useState, useEffect } from 'preact/hooks'
import {
compressToUTF16 as encode,
decompressFromUTF16 as decode
} from 'lz-string'
import CheapGlkOte from 'cheap-glkote'
import TextBuffer from './TextBuffer'
import InputBox from './InputBox'
import './player.css'
const INITIAL_STATUS = {
stage: 'loading',
details: 'Preparing...'
}
const runMachine = ({ Engine, file, handlers }) => {
console.log('runMachine')
const vm = new Engine()
const { glkInterface, sendFn } = CheapGlkOte(handlers)
vm.prepare(file, glkInterface)
vm.start()
return { sendFn, instance: vm }
}
const Handlers = ({
setStatus,
setCurrentWindow,
setInputType,
setInbox
}) => ({
onInit: _ => setStatus({ stage: 'ready' }),
/* */
onUpdateWindows: windows => {
setCurrentWindow(windows
.filter(x => x.type === 'buffer')
.slice(-1)[0])
},
onUpdateInputs: setInputType,
onUpdateContent: setInbox,
onDisable: _ => setInputType(null),
/* */
onFileNameRequest: (tosave, usage, _, setFileName) => {
setFileName({
usage,
filename: tosave ? 'save' : 'load'
})
},
onFileRead: ({ filename }) => {
if (filename === 'save') return null
const lsName = prompt('Enter the name of the saved file:')
const record = localStorage.getItem(`save-${lsName}`)
return decode(record)
},
onFileWrite: ({ filename }, content) => {
const lsName = prompt('Select a name for the saved file:')
const record = encode(content)
localStorage.setItem(`save-${lsName}`, record)
},
/* */
onExit: _ => setInputType(null)
})
export default function ({ vmParts: { file, engine } }) {
const [status, setStatus] = useState(INITIAL_STATUS)
const [currentWindow, setCurrentWindow] = useState(null)
const [inputType, setInputType] = useState(null)
const [inbox, setInbox] = useState([])
const [vm, setVm] = useState(null)
const [sendMessage, setSendMessage] = useState(null)
useEffect(() => {
const handlers = Handlers({
setStatus,
setCurrentWindow,
setInputType,
setInbox
})
const vm = runMachine({
Engine: engine,
file,
handlers
})
setVm(vm)
}, [file, engine])
useEffect(() => {
setSendMessage(_ => vm
? vm.sendFn
: null)
}, [vm])
return status.stage !== 'ready'
? (<div>{status.details}</div>)
: (
<section className='ifplayer'>
<TextBuffer {...{
inbox,
currentWindow
}} />
<InputBox {...{
currentWindow,
inputType,
sendMessage
}} />
</section>)
}