Skip to content

Commit

Permalink
better HoldToPour
Browse files Browse the repository at this point in the history
  • Loading branch information
GreenWizard2015 committed Jan 15, 2024
1 parent f9ae6cc commit 936e9b3
Showing 1 changed file with 70 additions and 20 deletions.
90 changes: 70 additions & 20 deletions ui/src/components/HoldToPour.js
Original file line number Diff line number Diff line change
@@ -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 (
<Container className="d-flex justify-content-center mt-3">
<Container className="d-flex flex-column align-items-center mt-3">
<img src="valve.png" className='hold-to-pour-image' alt="Hold to pour button"
draggable="false" onMouseDown={handlePress} onMouseUp={handleRelease}
draggable="false"
onMouseDown={clickToPour ? null : handlePress}
onMouseUp={clickToPour ? null : handleRelease}
onClick={clickToPour ? handleToggle : null}
/>

<Form.Check
type="checkbox"
checked={clickToPour} onChange={handleCheckboxChange}
label={
<span style={{ color: 'red', fontSize: '1.5rem' }}>
Click to pour (<b>dangerous</b>)
</span>
}
/>
</Container>
);
}

// 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 (
<HoldToPourComponent
startPump={_startPump} stopPump={_stopPump}
interval={interval}
/>
);
};

export default connect(
state => ({}),
state => ({ pouringTime: state.UI.pouringTime }),
{ startPump, stopPump }
)(HoldToPourComponent);
)(HoldToPourComponent_withExtras);

0 comments on commit 936e9b3

Please sign in to comment.