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

Fix: Permission Handling Issues in Microphone and Camera Capture Dialogs #8830

Merged
2 changes: 2 additions & 0 deletions src/Locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
"audio__allow_permission": "Please allow microphone permission in site settings",
"audio__allow_permission_button": "Click here to know how to allow",
"audio__allow_permission_helper": "You might have denied microphone access in the past.",
"audio__permission_message": "Please grant microphone permission to record audio.",
"audio__record": "Record Audio",
"audio__record_helper": "Click the button to start recording",
"audio__recorded": "Audio Recorded",
Expand Down Expand Up @@ -1156,6 +1157,7 @@
"summary": "Summary",
"support": "Support",
"switch": "Switch",
"switch_camera_is_not_available": "Switch camera is not available.",
"systolic": "Systolic",
"tachycardia": "Tachycardia",
"target_dosage": "Target Dosage",
Expand Down
5 changes: 3 additions & 2 deletions src/Utils/useRecorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import { useEffect, useState } from "react";
import { Error } from "./Notifications";
import { useTranslation } from "react-i18next";

const useRecorder = (handleMicPermission) => {
const [audioURL, setAudioURL] = useState("");
const [isRecording, setIsRecording] = useState(false);
const [recorder, setRecorder] = useState(null);
const [newBlob, setNewBlob] = useState(null);

const { t } = useTranslation();
useEffect(() => {
if (!isRecording && recorder && audioURL) {
setRecorder(null);
Expand All @@ -26,7 +27,7 @@ const useRecorder = (handleMicPermission) => {
},
() => {
Error({
msg: "Please grant microphone permission to record audio.",
msg: t("audio__permission_message"),
});
setIsRecording(false);
handleMicPermission(false);
Expand Down
4 changes: 3 additions & 1 deletion src/Utils/useSegmentedRecorder.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useState, useEffect } from "react";
import * as Notify from "./Notifications";
import { useTranslation } from "react-i18next";

const useSegmentedRecording = () => {
const [isRecording, setIsRecording] = useState(false);
const [recorder, setRecorder] = useState<MediaRecorder | null>(null);
const [audioBlobs, setAudioBlobs] = useState<Blob[]>([]);
const [restart, setRestart] = useState(false);
const { t } = useTranslation();

const bufferInterval = 1 * 1000;
const splitSizeLimit = 20 * 1000000; // 20MB
Expand All @@ -28,7 +30,7 @@ const useSegmentedRecording = () => {
},
() => {
Notify.Error({
msg: "Please grant microphone permission to record audio.",
msg: t("audio__permission_message"),
});
setIsRecording(false);
},
Expand Down
23 changes: 17 additions & 6 deletions src/components/Files/AudioCaptureDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import useRecorder from "../../Utils/useRecorder";
import { Link } from "raviger";
import CareIcon from "../../CAREUI/icons/CareIcon";
import { useTimer } from "../../Utils/useTimer";
import { t } from "i18next";
import { useTranslation } from "react-i18next";
import * as Notify from "../../Utils/Notifications";

export interface AudioCaptureDialogProps {
show: boolean;
Expand All @@ -20,8 +21,8 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) {
| "RECORDED";

const { show, onHide, onCapture, autoRecord = false } = props;

const [status, setStatus] = useState<Status | null>(null);
const { t } = useTranslation();

const [audioURL, , startRecording, stopRecording, , resetRecording] =
useRecorder((permission: boolean) => {
Expand All @@ -35,9 +36,19 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) {
const timer = useTimer();

const handleStartRecording = () => {
setStatus("RECORDING");
startRecording();
timer.start();
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(() => {
setStatus("RECORDING");
startRecording();
timer.start();
})
.catch(() => {
Notify.Error({
msg: t("audio__permission_message"),
});
setStatus("PERMISSION_DENIED");
});
};

const handleStopRecording = () => {
Expand Down Expand Up @@ -87,7 +98,7 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) {
}, [show]);

useEffect(() => {
if (autoRecord && show && status === "WAITING_TO_RECORD") {
if (autoRecord && show && status === "RECORDING") {
handleStartRecording();
}
}, [autoRecord, status, show]);
Expand Down
27 changes: 24 additions & 3 deletions src/components/Files/CameraCaptureDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import CareIcon from "../../CAREUI/icons/CareIcon";
import DialogModal from "@/components/Common/Dialog";
import ButtonV2, { Submit } from "@/components/Common/components/ButtonV2";
import { t } from "i18next";
import { useCallback, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import useWindowDimensions from "@/common/hooks/useWindowDimensions";
import * as Notify from "../../Utils/Notifications";

export interface CameraCaptureDialogProps {
show: boolean;
Expand All @@ -24,9 +25,29 @@ export default function CameraCaptureDialog(props: CameraCaptureDialogProps) {
height: { ideal: 2160 },
facingMode: "user",
};

useEffect(() => {
if (!show) return;
navigator.mediaDevices.getUserMedia({ video: true }).catch(() => {
Notify.Warn({
msg: t("camera_permission_denied"),
});
onHide();
});
}, [show]);
const handleSwitchCamera = useCallback(() => {
setCameraFacingFront((prevState) => !prevState);
const supportedConstraints =
navigator.mediaDevices.getSupportedConstraints();
if (
!isLaptopScreen &&
typeof supportedConstraints.facingMode === "string" &&
(supportedConstraints.facingMode as string).includes("environment")
) {
setCameraFacingFront((prevState) => !prevState);
} else {
Notify.Warn({
msg: t("switch_camera_is_not_available"),
});
}
}, []);

const { width } = useWindowDimensions();
Expand Down
Loading