From 04af60ad0cd937639cf5e1a0a8d023d9c1eea152 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 18 Mar 2024 16:01:12 +0100 Subject: [PATCH] snes settings --- .../js/components/snes/SettingsDialog.js | 41 +++++ resources/js/components/snes/SettingsForm.js | 161 ++++++++++++++++++ .../twitch-bot/GuessingGameAutoTracking.js | 11 ++ resources/js/hooks/snes.js | 30 +++- resources/js/i18n/de.js | 7 + resources/js/i18n/en.js | 7 + 6 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 resources/js/components/snes/SettingsDialog.js create mode 100644 resources/js/components/snes/SettingsForm.js diff --git a/resources/js/components/snes/SettingsDialog.js b/resources/js/components/snes/SettingsDialog.js new file mode 100644 index 0000000..0f47d8f --- /dev/null +++ b/resources/js/components/snes/SettingsDialog.js @@ -0,0 +1,41 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { Modal } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import SettingsForm from './SettingsForm'; + +const SettingsDialog = ({ + deviceList, + onHide, + onSubmit, + settings, + show, +}) => { + const { t } = useTranslation(); + + return + + + {t('snes.settings')} + + + + ; +}; + +SettingsDialog.propTypes = { + deviceList: PropTypes.arrayOf(PropTypes.string), + onHide: PropTypes.func, + onSubmit: PropTypes.func, + settings: PropTypes.shape({ + }), + show: PropTypes.bool, +}; + +export default SettingsDialog; diff --git a/resources/js/components/snes/SettingsForm.js b/resources/js/components/snes/SettingsForm.js new file mode 100644 index 0000000..7e05108 --- /dev/null +++ b/resources/js/components/snes/SettingsForm.js @@ -0,0 +1,161 @@ +import { withFormik } from 'formik'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { Button, Col, Form, Modal, Row } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import yup from '../../schema/yup'; + +const SettingsForm = ({ + deviceList, + errors, + handleBlur, + handleChange, + handleSubmit, + onCancel, + settings, + touched, + values, +}) => { + const { t } = useTranslation(); + + return
+ + + + {t('snes.proto')} + + + + + {touched.proto && errors.proto ? + + {t(errors.proto)} + + : null} + + + {t('snes.host')} + + {touched.host && errors.host ? + + {t(errors.host)} + + : null} + + + {t('snes.port')} + + {touched.port && errors.port ? + + {t(errors.port)} + + : null} + + + {t('snes.device')} + + + {settings.device && !deviceList.includes(settings.device) ? + + : null} + {deviceList.map(device => + + )} + + {touched.device && errors.device ? + + {t(errors.device)} + + : null} + + + + + {onCancel ? + + : null} + + +
; +}; + +SettingsForm.propTypes = { + deviceList: PropTypes.arrayOf(PropTypes.string), + errors: PropTypes.shape({ + device: PropTypes.string, + host: PropTypes.string, + port: PropTypes.string, + proto: PropTypes.string, + }), + handleBlur: PropTypes.func, + handleChange: PropTypes.func, + handleSubmit: PropTypes.func, + onCancel: PropTypes.func, + settings: PropTypes.shape({ + device: PropTypes.string, + host: PropTypes.string, + port: PropTypes.number, + proto: PropTypes.string, + }), + touched: PropTypes.shape({ + device: PropTypes.bool, + host: PropTypes.bool, + port: PropTypes.bool, + proto: PropTypes.bool, + }), + values: PropTypes.shape({ + device: PropTypes.string, + host: PropTypes.string, + port: PropTypes.number, + proto: PropTypes.string, + }), +}; + +export default withFormik({ + displayName: 'SettingsForm', + enableReinitialize: true, + handleSubmit: async (values, actions) => { + const { onSubmit } = actions.props; + onSubmit(values); + }, + mapPropsToValues: ({ settings }) => settings, + validationSchema: yup.object().shape({ + device: yup.string(), + host: yup.string(), + port: yup.number().min(1).max(65665), + proto: yup.string(), + }), +})(SettingsForm); diff --git a/resources/js/components/twitch-bot/GuessingGameAutoTracking.js b/resources/js/components/twitch-bot/GuessingGameAutoTracking.js index fae142c..093e121 100644 --- a/resources/js/components/twitch-bot/GuessingGameAutoTracking.js +++ b/resources/js/components/twitch-bot/GuessingGameAutoTracking.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { Button } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import Icon from '../common/Icon'; @@ -90,6 +91,7 @@ const GuessingGameAutoTracking = ({ onSolve, onStart, onStop }) => { const { disable: disableSNES, enable: enableSNES, + openSettings, sock, status, } = useSNES(); @@ -329,6 +331,15 @@ const GuessingGameAutoTracking = ({ onSolve, onStart, onStop }) => { title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device })} /> : null} + React.useContext(context); export const SNESProvider = ({ children }) => { const [enabled, setEnabled] = React.useState(false); + const [showSettingsDialog, setShowSettingsDialog] = React.useState(false); const sock = React.useRef(null); @@ -104,6 +106,23 @@ export const SNESProvider = ({ children }) => { }); }, []); + const openSettings = React.useCallback(() => { + setShowSettingsDialog(true); + }, []); + + const closeSettings = React.useCallback(() => { + setShowSettingsDialog(false); + }, []); + + const saveSettings = React.useCallback((values) => { + setSettings(s => { + const newSettings = { ...s, ...values }; + localStorage.setItem('snes.settings', JSON.stringify(newSettings)); + return newSettings; + }); + setShowSettingsDialog(false); + }, []); + React.useEffect(() => { const savedSettings = localStorage.getItem('snes.settings'); if (savedSettings) { @@ -112,11 +131,18 @@ export const SNESProvider = ({ children }) => { }, []); const value = React.useMemo(() => { - return { disable, enable, enabled, settings, sock, status }; - }, [disable, enable, enabled, settings, sock, status]); + return { disable, enable, enabled, openSettings, settings, sock, status }; + }, [disable, enable, enabled, openSettings, settings, sock, status]); return {children} + ; }; diff --git a/resources/js/i18n/de.js b/resources/js/i18n/de.js index 0f20e4e..b8442dc 100644 --- a/resources/js/i18n/de.js +++ b/resources/js/i18n/de.js @@ -447,6 +447,13 @@ export default { search: { noResults: 'Keine Treffer', }, + snes: { + device: 'Bevorzugtes Gerät', + host: 'Host', + port: 'Port', + proto: 'Protokoll', + settings: 'SNES Einstellungen', + }, techniques: { description: 'Tutorials für The Legend of Zelda: A Link to the Past Randomizer', heading: 'Techniken', diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js index 4852f14..c5efdf4 100644 --- a/resources/js/i18n/en.js +++ b/resources/js/i18n/en.js @@ -447,6 +447,13 @@ export default { search: { noResults: 'No results', }, + snes: { + device: 'Preferred device', + host: 'Host', + port: 'Port', + proto: 'Protocol', + settings: 'SNES Settings', + }, techniques: { description: 'Tutorials for The Legend of Zelda: A Link to the Past Randomizer', heading: 'Techniques', -- 2.39.2