Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

40/add push to talk #72

Merged
merged 13 commits into from
Apr 19, 2024
2 changes: 1 addition & 1 deletion src/components/landing-page/create-production.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export const CreateProduction = () => {

<ActionButton
type="submit"
className={loading ? "submit" : ""}
className={loading ? "with-loader" : ""}
onClick={handleSubmit(onSubmit)}
>
Create Production
Expand Down
2 changes: 1 addition & 1 deletion src/components/landing-page/form-elements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const ActionButton = styled.button`
box-shadow: inset 0.1rem 0.1rem 0 rgba(0, 0, 0, 0.2);
}

&.submit {
&.with-loader {
position: relative;
color: rgba(255, 255, 255, 0);
}
Expand Down
16 changes: 8 additions & 8 deletions src/components/loader/loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@ import styled from "@emotion/styled";
import { FC, useEffect, useState } from "react";

const Loading = styled.div`
border: 4px solid rgba(0, 0, 0, 0.1);
border-top: 4px solid #333;
border: 0.4rem solid rgba(0, 0, 0, 0.1);
border-top: 0.4rem solid #333;
border-radius: 50%;
width: 30px;
height: 30px;
width: 3rem;
height: 3rem;
animation: spin 1s linear infinite;
margin: auto;

&.create-production {
position: absolute;
top: 5px;
left: 60px;
top: 0.5rem;
left: 6rem;
}

&.join-production {
border: 4px solid rgba(201, 201, 201, 0.1);
border-top: 4px solid #e2e2e2;
border: 0.4rem solid rgba(201, 201, 201, 0.1);
border-top: 0.4rem solid #e2e2e2;
}

@keyframes spin {
Expand Down
86 changes: 86 additions & 0 deletions src/components/production-line/long-press-to-talk-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { useEffect, useState } from "react";
import styled from "@emotion/styled";
import { ActionButton } from "../landing-page/form-elements";
import { isMobile } from "../../bowser";

type TLongPressToTalkButton = {
setMicMute: (input: boolean) => void;
};

const Button = styled(ActionButton)`
position: relative;

&.active-btn {
color: rgba(255, 255, 255, 0);
animation: pulse 0.7s ease-in-out infinite alternate;
}

&.mobile {
user-select: none;
}

@keyframes pulse {
0% {
background: #4ada1e;
}
100% {
background: rgba(255, 255, 255, 0.78);
}
}
`;

export const LongPressToTalkButton = ({
setMicMute,
}: TLongPressToTalkButton) => {
const [isToggled, setIsToggled] = useState(false);
const [longPressTimeout, setLongPressTimeout] =
useState<ReturnType<typeof setTimeout>>();

useEffect(() => {
return () => {
if (longPressTimeout) {
clearTimeout(longPressTimeout);
}
};
}, [longPressTimeout]);

const toggleMuteAfterTimeout = (e: React.PointerEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
e.currentTarget.setPointerCapture(e.pointerId);

let timeoutId: NodeJS.Timeout;

switch (e.type) {
case "pointerdown":
timeoutId = setTimeout(() => {
setMicMute(false);
setIsToggled(true);
}, 300);
setLongPressTimeout(timeoutId);
break;
case "pointerup":
setIsToggled(false);
setMicMute(true);
clearTimeout(longPressTimeout);
break;
default:
console.error(`Invalid event type received: ${e.type}`);
}
};

return (
<Button
className={`${isMobile ? "mobile" : ""} ${isToggled ? "active-btn" : ""}`}
type="button"
onPointerDown={(e) => {
toggleMuteAfterTimeout(e);
}}
onPointerUp={(e) => {
toggleMuteAfterTimeout(e);
}}
>
Press to Talk
</Button>
);
};
7 changes: 6 additions & 1 deletion src/components/production-line/production-line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import { DisplayContainer, FlexContainer } from "../generic-components.ts";
import { useHeartbeat } from "./use-heartbeat.ts";
import { JoinProduction } from "../landing-page/join-production.tsx";
import { useDeviceLabels } from "./use-device-labels.ts";
import { useLineHotkeys } from "./use-line-hotkeys.ts";
import { isMobile } from "../../bowser.ts";
import { useLineHotkeys } from "./use-line-hotkeys.ts";
import { LongPressToTalkButton } from "./long-press-to-talk-button.tsx";
import { useLinePolling } from "./use-line-polling.ts";
import { useFetchProduction } from "../landing-page/use-fetch-production.ts";
import { useIsLoading } from "./use-is-loading.ts";
Expand Down Expand Up @@ -134,6 +135,7 @@ export const ProductionLine: FC = () => {
});

// TODO detect if browser back button is pressed and run exit();

return (
<>
<HeaderWrapper>
Expand Down Expand Up @@ -190,6 +192,9 @@ export const ProductionLine: FC = () => {
</ButtonIcon>
{isInputMuted ? "Muted" : "Unmuted"}
</UserControlBtn>
<LongPressToTalkButton
setMicMute={(input: boolean) => setIsInputMuted(input)}
/>
</TempDiv>
)}

Expand Down
Loading