From 936e9b3485442578f20d6926e99964305239c472 Mon Sep 17 00:00:00 2001 From: GreenWizard2015 Date: Mon, 15 Jan 2024 12:29:27 +0000 Subject: [PATCH] better HoldToPour --- ui/src/components/HoldToPour.js | 90 +++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/ui/src/components/HoldToPour.js b/ui/src/components/HoldToPour.js index 2471575..4266962 100644 --- a/ui/src/components/HoldToPour.js +++ b/ui/src/components/HoldToPour.js @@ -1,40 +1,90 @@ import React, { useState, useEffect } from 'react'; import { connect } from 'react-redux'; -import { Container } from 'react-bootstrap'; +import { Container, Form } from 'react-bootstrap'; import { useWaterPumpAPI } from '../contexts/WaterPumpAPIContext'; import { startPump, stopPump } from '../store/slices/SystemStatus.js'; -export function HoldToPourComponent({ startPump, stopPump }) { - const pouringTime = 1500; - const api = useWaterPumpAPI().API; +export function HoldToPourComponent({ startPump, stopPump, interval }) { const [isPouring, setIsPouring] = useState(false); + const [clickToPour, setClickToPour] = useState(false); + // continuously pour water while the button is pressed + const lastPouringTime = React.useRef(0); + const onTick = React.useCallback( + async () => { + if(Date.now() < lastPouringTime.current) return; + try { + lastPouringTime.current = Number.MAX_SAFE_INTEGER; // prevent concurrent calls + await startPump(); + lastPouringTime.current = Date.now() + interval; + } catch(e) { + lastPouringTime.current = 0; // run again on next tick + } + }, + [startPump, interval] + ); useEffect(() => { - if (!isPouring) return; - - const tid = setInterval(() => { - startPump({ api, pouringTime }); - }, pouringTime - 500); - - return () => { - clearInterval(tid); - stopPump({ api }); - }; - }, [isPouring, api, startPump, stopPump]); + if(!isPouring) { + lastPouringTime.current = 0; + stopPump(); + return; + } + // tick every 100ms + const tid = setInterval(onTick, 100); + return () => { clearInterval(tid); } + }, [onTick, isPouring, stopPump, lastPouringTime]); const handlePress = () => { setIsPouring(true); }; const handleRelease = () => { setIsPouring(false); }; - + const handleCheckboxChange = e => { setClickToPour(e.target.checked); }; + const handleToggle = () => { setIsPouring(!isPouring); }; + // FIX: onMouseDown/onMouseUp is not working on mobile return ( - + Hold to pour button + + + Click to pour (dangerous) + + } /> ); } +// Helper wrapper to simplify the code in the component +function HoldToPourComponent_withExtras({ pouringTime, startPump, stopPump }) { + const api = useWaterPumpAPI().API; + + const _startPump = React.useCallback( + async () => { await startPump({ api, pouringTime }); }, + [api, startPump, pouringTime] + ); + const _stopPump = React.useCallback( + async () => { await stopPump({ api }); }, + [api, stopPump] + ); + // a bit smaller than the actual pouring time, to prevent the pump from stopping + // which could damage the pump + const interval = Math.max(Math.round(pouringTime - 500), 100); + return ( + + ); +}; + export default connect( - state => ({}), + state => ({ pouringTime: state.UI.pouringTime }), { startPump, stopPump } -)(HoldToPourComponent); \ No newline at end of file +)(HoldToPourComponent_withExtras); \ No newline at end of file