Skip to content

Commit 70c1151

Browse files
committed
fixup! Fix camera permissions race condition
Convert checkAndRequestPermission to ThunkAction that dispatches Redux updates, per swansontec comment: "We don't want to track state locally in the component - that's the job of the permission subsystem. The problem is that the permission subsystem is modifying things and then forgetting to update redux."
1 parent ac4c893 commit 70c1151

File tree

2 files changed

+24
-22
lines changed

2 files changed

+24
-22
lines changed

src/components/modals/ScanModal.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { sprintf } from 'sprintf-js'
1717
import { useLayout } from '../../hooks/useLayout'
1818
import { lstrings } from '../../locales/strings'
1919
import { config } from '../../theme/appConfig'
20-
import { useSelector } from '../../types/reactRedux'
20+
import { useDispatch, useSelector } from '../../types/reactRedux'
2121
import { triggerHaptic } from '../../util/haptic'
2222
import { logActivity } from '../../util/logger'
2323
import { ModalButtons } from '../buttons/ModalButtons'
@@ -62,6 +62,7 @@ export const ScanModal: React.FC<Props> = props => {
6262
scanModalTitle
6363
} = props
6464

65+
const dispatch = useDispatch()
6566
const theme = useTheme()
6667
const styles = getStyles(theme)
6768

@@ -75,10 +76,7 @@ export const ScanModal: React.FC<Props> = props => {
7576
handleBarCodeRead(codes)
7677
}
7778
})
78-
const reduxCameraPermission = useSelector(state => state.permissions.camera)
79-
const [cameraPermission, setCameraPermission] = React.useState(
80-
reduxCameraPermission
81-
)
79+
const cameraPermission = useSelector(state => state.permissions.camera)
8280
const [torchEnabled, setTorchEnabled] = React.useState(false)
8381
const [scanEnabled, setScanEnabled] = React.useState(false)
8482

@@ -90,17 +88,13 @@ export const ScanModal: React.FC<Props> = props => {
9088
// Mount effects
9189
React.useEffect(() => {
9290
setScanEnabled(true)
93-
checkAndRequestPermission('camera')
94-
.then(status => {
95-
setCameraPermission(status)
96-
})
97-
.catch((error: unknown) => {
98-
showError(error)
99-
})
91+
dispatch(checkAndRequestPermission('camera')).catch((error: unknown) => {
92+
showError(error)
93+
})
10094
return () => {
10195
setScanEnabled(false)
10296
}
103-
}, [])
97+
}, [dispatch])
10498

10599
const handleBarCodeRead = (codes: Code[]): void => {
106100
setScanEnabled(false)

src/components/services/PermissionsManager.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,22 @@ export async function requestContactsPermission(
9090
* Checks permission and attempts to request permissions (only if checked
9191
* permission was 'denied')
9292
*/
93-
export async function checkAndRequestPermission(
94-
data: Permission
95-
): Promise<PermissionStatus> {
96-
const status: PermissionStatus = await check(permissionNames[data])
97-
98-
if (status === 'denied') return await request(permissionNames[data])
99-
else return status
100-
}
93+
export const checkAndRequestPermission =
94+
(permission: Permission): ThunkAction<Promise<PermissionStatus>> =>
95+
async dispatch => {
96+
const status: PermissionStatus = await check(permissionNames[permission])
97+
98+
if (status !== 'denied') return status
99+
100+
const newStatus = await request(permissionNames[permission])
101+
if (newStatus !== status) {
102+
dispatch({
103+
type: 'PERMISSIONS/UPDATE',
104+
data: { [permission]: newStatus }
105+
})
106+
}
107+
return newStatus
108+
}
101109

102110
export const checkIfDenied = (status: PermissionStatus) =>
103111
status === 'blocked' || status === 'denied' || status === 'unavailable'
@@ -126,7 +134,7 @@ export async function requestPermissionOnSettings(
126134

127135
// User first time check. If mandatory, it needs to be checked if denied or accepted
128136
if (status === 'denied') {
129-
const result = await checkAndRequestPermission(data)
137+
const result = await request(permissionNames[data])
130138
return mandatory && checkIfDenied(result)
131139
}
132140

0 commit comments

Comments
 (0)