wip try triggering a request permission on toggle

This commit is contained in:
lebaudantoine
2026-08-10 12:57:35 +02:00
parent dff8c5696e
commit a9be74a5a4
2 changed files with 45 additions and 8 deletions
@@ -1,7 +1,7 @@
import { ToggleButton } from '@/primitives'
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce'
import { useMemo, useState } from 'react'
import { useMemo, useRef, useState } from 'react'
import { appendShortcutLabel } from '@/features/shortcuts/utils'
import { useTranslation } from 'react-i18next'
import { PermissionNeededButton } from './PermissionNeededButton'
@@ -16,6 +16,7 @@ import type { ButtonRecipeProps } from '@/primitives/buttonRecipe'
import type { ToggleButtonProps } from '@/primitives/ToggleButton'
import { openPermissionsDialog } from '@/stores/permissions'
import { useCannotUseDevice } from '../../../hooks/useCannotUseDevice'
import { requestDevicePermission } from '../../../hooks/useJoinTracks'
import { useDeviceIcons } from '../../../hooks/useDeviceIcons'
import { useDeviceShortcut } from '../../../hooks/useDeviceShortcut'
import type {
@@ -93,6 +94,27 @@ export const ToggleDevice = <T extends ToggleSource>({
const deviceShortcut = useDeviceShortcut(kind)
const announce = useScreenReaderAnnounce()
const isRequestingPermission = useRef(false)
const onPress = async () => {
if (!cannotUseDevice) {
toggle()
return
}
if (isRequestingPermission.current) return
isRequestingPermission.current = true
try {
const granted = await requestDevicePermission(kind)
if (granted) {
toggle()
} else {
openPermissionsDialog(kind)
}
} finally {
isRequestingPermission.current = false
}
}
useRegisterKeyboardShortcut({
id: deviceShortcut?.id,
handler: async () => {
@@ -147,13 +169,7 @@ export const ToggleDevice = <T extends ToggleSource>({
isDisabled || cannotUseDevice || !enabled ? errorVariant : variant
}
shySelected
onPress={() => {
if (cannotUseDevice) {
openPermissionsDialog(kind)
} else {
toggle()
}
}}
onPress={onPress}
aria-label={toggleLabel}
tooltip={
cannotUseDevice
@@ -33,6 +33,11 @@ const VOICE_AUDIO_CONSTRAINTS = {
sampleSize: 16,
} as const
const PERMISSION_KIND: Record<'audioinput' | 'videoinput', PermissionKind> = {
audioinput: 'microphone',
videoinput: 'camera',
}
export const onJoinPreviewError = (e: Error, kind?: PermissionKind) => {
reportError('join_preview_failure', e, { path: 'join_preview' })
if (
@@ -49,6 +54,22 @@ const disableVideo = () => saveVideoInputEnabled(false)
const stopAll = (stream: MediaStream) =>
stream.getTracks().forEach((track) => track.stop())
export const requestDevicePermission = async (
kind: 'audioinput' | 'videoinput'
): Promise<boolean> => {
try {
const track =
kind === 'audioinput'
? await createLocalAudioTrack()
: await createLocalVideoTrack()
track.stop()
return true
} catch (error) {
onJoinPreviewError(error as Error, PERMISSION_KIND[kind])
return false
}
}
/**
* Requests camera and microphone once on mount (one combined call → at
* most one browser dialog) and releases them immediately. Returns true