Skip to content
This repository was archived by the owner on Oct 18, 2021. It is now read-only.
This repository was archived by the owner on Oct 18, 2021. It is now read-only.

Camera mount error #14

@clems36

Description

@clems36

Hi, when i navigate to my Camera component for the first time, the onCameraReady method is correctly fired, but when i navigate there again, the onMountError method is fired. The docs say that this method returns an object containing a message, but when i try to log the object, i get undefined:
onMountError={(obj) => console.log('Camera mount error', JSON.stringify(obj)).
This means that i can see the buttons in my render, but the camera screen is black.
I thought the issue might be that the Cam component would still be mounted, but I checked and whenever i leave it, componentWillUnmount is correctly fired.
I based my code on the doc's example and removed a lot of things. Here it is:

export class CameraModule extends Component<IProps, IState> {
    camera: any;
    constructor(props: IProps) {
        super(props);
        this.handleBackButtonClick = this.handleBackButtonClick.bind(this);
        this.state = {
            type: Camera.Constants.Type.back,
            flash: 'off',
            zoom: 0,
            autoFocus: 'on',
            depth: 0,
            whiteBalance: 'auto',
            ratio: '16:9',
            ratios: [],
            showGallery: false,
            permissionsGranted: false,
        };
    }

    async componentWillMount() {
        BackHandler.addEventListener(C.HARDWARE_BACK_PRESS, this.handleBackButtonClick);
        const { status } = await Permissions.askAsync(Permissions.CAMERA);
        this.setState({ permissionsGranted: status === 'granted' });
    }

    componentWillUnmount() {
        BackHandler.removeEventListener(C.HARDWARE_BACK_PRESS, this.handleBackButtonClick);
    }

    handleBackButtonClick() {
        this.props.navigation.goBack(null);
        return true;
    }

    toggleFacing() {
        this.setState({ type: this.state.type === 'back' ? 'front' : 'back' });
    }

    toggleFlash() {
        this.setState({ flash: flashModeOrder[this.state.flash] });
    }

    setRatio(ratio: string) {
        this.setState({ ratio });
    }

    toggleWB() {
        this.setState({ whiteBalance: wbOrder[this.state.whiteBalance] });
    }

    toggleFocus() {
        this.setState({ autoFocus: this.state.autoFocus === 'on' ? 'off' : 'on' });
    }

    zoomOut = () => {
        const { zoom } = this.state;
        if (zoom > 0) {
            this.setState({ zoom: zoom - 0.01 });
        }
    }

    zoomIn = () => {
        const { zoom } = this.state;
        if (zoom < 0.5) {
            this.setState({ zoom: zoom + 0.01 });
        }
    }

    setFocusDepth(depth: number) {
        this.setState({ depth });
    }

    resize = async (url: string) => {
        const manipResult = await ImageManipulator.manipulate(url,
            [{ resize: { height: 512 } }],
            { format: 'jpeg', compress: 1, base64: true },
        );
        return manipResult.base64;
    }

    takePicture = async () => {
        if (this.camera) {
            const { auth: { sessionId }, appReducer: { currentJob: { id } } } = this.props;
            this.props.setIsTakingPicture(true);
            this.camera.takePictureAsync({ base64: true, quality: 0.5 }).then(data => {
                console.log('Photo taken');
                this.resize(data.uri).then(base64 => {
                    this.props.setPictureId(this.props.appReducer.pictureId + 1);
                    setTimeout(() => {
                        const newPic = {
                            id: this.props.appReducer.pictureId,
                            jobId: id,
                            captureDate: moment().valueOf(),
                            picture: base64,
                        };
                        const { appReducer: { localPictures = [] } } = this.props;
                        if (isValid(localPictures)) {
                            this.props.setLocalPictures([...localPictures, newPic]);
                        } else {
                            this.props.setLocalPictures([newPic]);
                        }
                        this.props.setIsTakingPicture(false);
                    }, 0);
                });
            });
        }
    }

    renderNoPermissions() {
        const { t } = this.props;
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', padding: 10 }}>
                <Text>{t('aidooTechnician:noPermission')}</Text>
            </View>
        );
    }

    renderCamera() {
        const { navigation: { navigate }, appReducer: { theme = null, shape = C.SHAPE_ROUND, isTakingPicture }, pictureReducer: { isAddingPicture } } = this.props;
        const { colorMain = C.COLOR_THEME } = theme;
        const { type, flash, autoFocus, zoom, whiteBalance, ratio, depth } = this.state;
        const borderRadius = shape === C.SHAPE_ROUND ? 25 : 0;
        const pictureButtonBorderRadius = shape === C.SHAPE_ROUND ? 40 : 0;
        return (
            <Camera
                ref={ref => this.camera = ref}
                style={{ flex: 1 }}
                type={type}
                flashMode={flash}
                autoFocus={autoFocus}
                zoom={zoom}
                whiteBalance={whiteBalance}
                ratio={ratio}
                focusDepth={depth}
                onCameraReady={() => console.log('Camera ready')}
                onMountError={(message) => console.log('Camera mount error', JSON.stringify(message))}>
                <View style={{ flex: 1, backgroundColor: 'transparent' }}>
                    <View
                        style={{
                            backgroundColor: 'transparent',
                            flexDirection: 'row',
                            justifyContent: 'space-around',
                            paddingTop: Constants.statusBarHeight / 2,
                        }}>
                        <TouchableOpacity style={[s.camButton, { borderRadius, backgroundColor: 'white' }]} onPress={() => this.handleBackButtonClick()}>
                            <Icon name={C.ICON_BACK_BUTTON} />
                        </TouchableOpacity>
                        <TouchableOpacity style={[s.camButton, { borderRadius }]} onPress={() => this.toggleFlash()}>
                            {flash === 'on' && <Image source={require('../../../../assets/camera/flash_on.png')} style={{ height: 30, width: 30 }} />}
                            {flash === 'off' && <Image source={require('../../../../assets/camera/flash_off.png')} style={{ height: 30, width: 30 }} />}
                            {flash === 'auto' && <Image source={require('../../../../assets/camera/flash_auto.png')} style={{ height: 30, width: 30 }} />}
                            {flash === 'torch' && <Icon name={C.ICON_BULB} style={{ fontSize: 30, color: 'white' }} />}
                        </TouchableOpacity>
                        <TouchableOpacity
                            style={[s.camButton, { borderRadius }]}
                            onPress={() => this.toggleFocus()}>
                            <Text style={{ fontWeight: C.NUMBER_BOLD, color: 'white' }}>AF</Text>
                            <Text style={{ color: 'white' }}>{autoFocus} </Text>
                        </TouchableOpacity>
                    </View>
                    {autoFocus !== 'on' ? (
                        <Slider
                            style={{ width: 150, marginTop: 15, marginRight: 15, alignSelf: 'flex-end' }}
                            onValueChange={value => this.setFocusDepth(value)}
                            step={0.1}
                        />
                    ) : null}
                </View>
                <View
                    style={{
                        paddingBottom: isIPhoneX ? 20 : 0,
                        backgroundColor: 'transparent',
                        flexDirection: 'row',
                        alignSelf: 'flex-end',
                    }}>
                    <View style={{ flex: 0.4, alignSelf: 'flex-end' }}>
                        <TouchableOpacity
                            style={[s.camButton, { borderRadius, marginLeft: 10 }]}
                            onPress={() => this.toggleFacing()}>
                            <Icon name={C.ICON_REVERSE_CAMERA} style={{ color: 'white' }} />
                        </TouchableOpacity>
                    </View>
                    <View style={{ flex: 0.2, alignSelf: 'flex-end' }}>
                        <TouchableOpacity
                            style={[s.pictureButton, { borderRadius: pictureButtonBorderRadius }]}
                            onPress={() => this.takePicture()}>
                            <Icon name={C.ICON_CAMERA} style={{ color: 'white' }} />
                        </TouchableOpacity>
                    </View>
                    <View style={{ flex: 0.4, alignItems: 'flex-end' }}>
                        <TouchableOpacity
                            style={[s.camButton, { marginRight: 10, borderRadius }]}
                            onPress={this.zoomIn}>
                            <Text style={{ color: 'white', fontSize: 22 }}> + </Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            style={[s.camButton, { marginRight: 10, borderRadius }]}
                            onPress={this.zoomOut}>
                            <Text style={{ color: 'white', fontSize: 22 }}> - </Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            style={[s.camButton, { marginRight: 10, borderRadius, backgroundColor: colorMain }]}
                            onPress={() => navigate(C.SCREEN_GALLERY)}>
                            <Icon name={C.ICON_FORWARD_BUTTON} style={{ color: 'white' }} />
                        </TouchableOpacity>
                    </View>
                </View>
            </Camera >
        );
    }

    render() {
        const { permissionsGranted } = this.state;
        return <View style={{ flex: 1 }}>{permissionsGranted ? this.renderCamera() : this.renderNoPermissions()}</View>;
    }
}

const flashModeOrder = {
    off: 'on',
    on: 'auto',
    auto: 'torch',
    torch: 'off',
};

const wbOrder = {
    auto: 'sunny',
    sunny: 'cloudy',
    cloudy: 'shadow',
    shadow: 'fluorescent',
    fluorescent: 'incandescent',
    incandescent: 'auto',
};

const mapStateToProps = ({ appReducer, auth, pictureReducer }) => ({
    appReducer,
    auth,
    pictureReducer,
});

const mapDispatchToProps = (dispatch: Function) => ({
    setPictureId: (pictureId: number) => dispatch(setPictureId(pictureId)),
    setIsTakingPicture: (isTakingPicture: boolean) => dispatch(setIsTakingPicture(isTakingPicture)),
    setLocalPictures: (localPictures: ILocalPicture[]) => dispatch(setLocalPictures(localPictures)),
});

export default connect(mapStateToProps, mapDispatchToProps)(CameraModule);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions