fix(up-wip): recording permissions

This commit is contained in:
devthejo 2025-10-02 19:29:24 +02:00
parent c5ccfa8d08
commit 749a09aa5e
No known key found for this signature in database
GPG key ID: 00CCA7A92B1D5351
3 changed files with 96 additions and 22 deletions

View file

@ -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",

View file

@ -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,
}); });

View file

@ -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]);