fix(up-wip): recording permissions
This commit is contained in:
parent
c5ccfa8d08
commit
749a09aa5e
3 changed files with 96 additions and 22 deletions
|
@ -1,5 +1,5 @@
|
||||||
import React, { useState, useCallback, useEffect, useRef } from "react";
|
import React, { useState, useCallback, useEffect, useRef } from "react";
|
||||||
import { View, Text, TouchableOpacity } from "react-native";
|
import { View, Text, TouchableOpacity, Platform, Alert } from "react-native";
|
||||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||||
import {
|
import {
|
||||||
useAudioRecorder,
|
useAudioRecorder,
|
||||||
|
@ -11,6 +11,14 @@ import {
|
||||||
AudioQuality,
|
AudioQuality,
|
||||||
} from "expo-audio";
|
} from "expo-audio";
|
||||||
|
|
||||||
|
import {
|
||||||
|
check,
|
||||||
|
request,
|
||||||
|
PERMISSIONS,
|
||||||
|
RESULTS,
|
||||||
|
openSettings,
|
||||||
|
} from "react-native-permissions";
|
||||||
|
|
||||||
import Countdown from "react-countdown";
|
import Countdown from "react-countdown";
|
||||||
|
|
||||||
import { useAlertState, getLocationState, useSessionState } from "~/stores";
|
import { useAlertState, getLocationState, useSessionState } from "~/stores";
|
||||||
|
@ -74,6 +82,51 @@ const recordingOptionsFallback = {
|
||||||
|
|
||||||
const activeOpacity = 0.7;
|
const activeOpacity = 0.7;
|
||||||
|
|
||||||
|
const withTimeout = (promise, ms = 10000) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const id = setTimeout(
|
||||||
|
() => reject(new Error("Permission request timeout")),
|
||||||
|
ms,
|
||||||
|
);
|
||||||
|
promise
|
||||||
|
.then((v) => {
|
||||||
|
clearTimeout(id);
|
||||||
|
resolve(v);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
clearTimeout(id);
|
||||||
|
reject(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const ensureMicPermission = async () => {
|
||||||
|
if (Platform.OS !== "android") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const status = await check(PERMISSIONS.ANDROID.RECORD_AUDIO);
|
||||||
|
if (status === RESULTS.GRANTED) return true;
|
||||||
|
if (status === RESULTS.BLOCKED) {
|
||||||
|
try {
|
||||||
|
Alert.alert(
|
||||||
|
"Autorisation micro bloquée",
|
||||||
|
"Veuillez autoriser le micro dans les paramètres de l'application.",
|
||||||
|
[
|
||||||
|
{ text: "Annuler", style: "cancel" },
|
||||||
|
{ text: "Ouvrir les paramètres", onPress: openSettings },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const res = await request(PERMISSIONS.ANDROID.RECORD_AUDIO);
|
||||||
|
return res === RESULTS.GRANTED;
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Mic permission check failed", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default React.memo(function ChatInput({
|
export default React.memo(function ChatInput({
|
||||||
style,
|
style,
|
||||||
labelStyle,
|
labelStyle,
|
||||||
|
@ -146,8 +199,30 @@ export default React.memo(function ChatInput({
|
||||||
|
|
||||||
const startRecording = useCallback(async () => {
|
const startRecording = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Requesting permissions..");
|
console.log("Requesting microphone permission..");
|
||||||
await requestRecordingPermissionsAsync();
|
const grantedPre = await ensureMicPermission();
|
||||||
|
if (!grantedPre) {
|
||||||
|
console.log("Microphone permission not granted or blocked");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await withTimeout(requestRecordingPermissionsAsync(), 10000);
|
||||||
|
} catch (permErr) {
|
||||||
|
console.log("Microphone permission request failed/timed out:", permErr);
|
||||||
|
if (Platform.OS === "android") {
|
||||||
|
try {
|
||||||
|
Alert.alert(
|
||||||
|
"Autorisation micro requise",
|
||||||
|
"Impossible d'obtenir l'autorisation du microphone. Ouvrir les paramètres pour l'accorder.",
|
||||||
|
[
|
||||||
|
{ text: "Annuler", style: "cancel" },
|
||||||
|
{ text: "Ouvrir les paramètres", onPress: openSettings },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
await setAudioModeAsync({
|
await setAudioModeAsync({
|
||||||
allowsRecording: true,
|
allowsRecording: true,
|
||||||
interruptionMode: "doNotMix",
|
interruptionMode: "doNotMix",
|
||||||
|
|
|
@ -46,22 +46,27 @@ export default async () => {
|
||||||
|
|
||||||
// Handle Android permissions
|
// Handle Android permissions
|
||||||
permissionLogger.debug("Requesting Android notification permissions");
|
permissionLogger.debug("Requesting Android notification permissions");
|
||||||
const { status } = await requestNotifications(["alert"]);
|
const { status } = await requestNotifications(["alert", "sound", "badge"]);
|
||||||
|
|
||||||
permissionLogger.debug(
|
let postNotifications = RESULTS.UNAVAILABLE;
|
||||||
"Requesting POST_NOTIFICATIONS permission (Android 13+)",
|
if (Platform.Version >= 33) {
|
||||||
);
|
permissionLogger.debug(
|
||||||
const postNotifications = await request(
|
"Requesting POST_NOTIFICATIONS permission (Android 13+)",
|
||||||
PERMISSIONS.ANDROID.POST_NOTIFICATIONS,
|
);
|
||||||
);
|
postNotifications = await request(PERMISSIONS.ANDROID.POST_NOTIFICATIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine grant state:
|
||||||
|
// - Android 13+ requires POST_NOTIFICATIONS granted
|
||||||
|
// - Below 13, POST_NOTIFICATIONS is unavailable; use requestNotifications result
|
||||||
const isGranted =
|
const isGranted =
|
||||||
status === RESULTS.GRANTED &&
|
(Platform.Version >= 33 && postNotifications === RESULTS.GRANTED) ||
|
||||||
(postNotifications === "granted" || postNotifications === "unavailable");
|
(Platform.Version < 33 && status === RESULTS.GRANTED);
|
||||||
|
|
||||||
permissionLogger.info("Android notification permission result", {
|
permissionLogger.info("Android notification permission result", {
|
||||||
notificationStatus: status,
|
notificationStatus: status,
|
||||||
postNotificationsStatus: postNotifications,
|
postNotificationsStatus: postNotifications,
|
||||||
|
osVersion: Platform.Version,
|
||||||
granted: isGranted,
|
granted: isGranted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,23 +3,17 @@ import { useEffect } from "react";
|
||||||
|
|
||||||
import requestPermissionFcm from "./requestPermissionFcm";
|
import requestPermissionFcm from "./requestPermissionFcm";
|
||||||
|
|
||||||
export default async function usePermissionFcm() {
|
export default function usePermissionFcm() {
|
||||||
const { fcm } = usePermissionsState(["fcm"]);
|
const { fcm } = usePermissionsState(["fcm"]);
|
||||||
|
|
||||||
const { setFcm } = permissionsActions;
|
const { setFcm } = permissionsActions;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// if (fcm) {
|
if (fcm) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
(async () => {
|
(async () => {
|
||||||
// const authStatus = await messaging().requestPermission();
|
|
||||||
// setFcm(
|
|
||||||
// authStatus === AuthorizationStatus.AUTHORIZED ||
|
|
||||||
// authStatus === AuthorizationStatus.PROVISIONAL,
|
|
||||||
// );
|
|
||||||
const granted = await requestPermissionFcm();
|
const granted = await requestPermissionFcm();
|
||||||
|
|
||||||
setFcm(granted);
|
setFcm(granted);
|
||||||
})();
|
})();
|
||||||
}, [fcm, setFcm]);
|
}, [fcm, setFcm]);
|
||||||
|
|
Loading…
Add table
Reference in a new issue