/* * Copyright (c) 2019 - 2020 Arnaud Vergnet. * * This file is part of Campus INSAT. * * Campus INSAT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Campus INSAT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Campus INSAT. If not, see . */ import * as React from 'react'; import { Linking, Platform, StyleSheet, View } from 'react-native'; import { Button, Text } from 'react-native-paper'; import { BarCodeReadEvent, RNCamera } from 'react-native-camera'; import { BarcodeMask } from '@nartc/react-native-barcode-mask'; import i18n from 'i18n-js'; import { PERMISSIONS, request, RESULTS } from 'react-native-permissions'; import URLHandler from '../../utils/URLHandler'; import AlertDialog from '../../components/Dialogs/AlertDialog'; import { TAB_BAR_HEIGHT } from '../../components/Tabbar/CustomTabBar'; import LoadingConfirmDialog from '../../components/Dialogs/LoadingConfirmDialog'; import { MASCOT_STYLE } from '../../components/Mascot/Mascot'; import MascotPopup from '../../components/Mascot/MascotPopup'; type StateType = { hasPermission: boolean; scanned: boolean; dialogVisible: boolean; mascotDialogVisible: boolean; loading: boolean; }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, button: { position: 'absolute', bottom: 20, width: '80%', left: '10%', }, permissionContainer: { marginLeft: 10, marginRight: 10, }, permissionButton: { marginTop: 10, marginLeft: 'auto', marginRight: 'auto', }, }); type PermissionResults = | 'unavailable' | 'denied' | 'blocked' | 'granted' | 'limited'; class ScannerScreen extends React.Component<{}, StateType> { constructor(props: {}) { super(props); this.state = { hasPermission: false, scanned: false, mascotDialogVisible: false, dialogVisible: false, loading: false, }; } componentDidMount() { this.requestPermissions(); } /** * Gets a view asking user for permission to use the camera * * @returns {*} */ getPermissionScreen() { return ( {i18n.t('screens.scanner.permissions.error')} ); } /** * Gets a view with the scanner. * This scanner uses the back camera, can only scan qr codes and has a square mask on the center. * The mask is only for design purposes as a code is scanned as soon as it enters the camera view * * @returns {*} */ getScanner() { const { state } = this; return ( ); } /** * Requests permission to use the camera */ requestPermissions = () => { if (Platform.OS === 'android') { request(PERMISSIONS.ANDROID.CAMERA).then(this.updatePermissionStatus); } else { request(PERMISSIONS.IOS.CAMERA).then(this.updatePermissionStatus); } }; /** * Updates the state permission status * * @param result */ updatePermissionStatus = (result: PermissionResults) => { this.setState({ hasPermission: result === RESULTS.GRANTED, }); }; /** * Shows a dialog indicating the user the scanned code was invalid */ showErrorDialog() { this.setState({ dialogVisible: true, scanned: true, }); } /** * Shows a dialog indicating how to use the scanner */ showHelpDialog = () => { this.setState({ mascotDialogVisible: true, scanned: true, }); }; /** * Shows a loading dialog */ showOpeningDialog = () => { this.setState({ loading: true, scanned: true, }); }; /** * Hide any dialog */ onDialogDismiss = () => { this.setState({ dialogVisible: false, scanned: false, }); }; onMascotDialogDismiss = () => { this.setState({ mascotDialogVisible: false, scanned: false, }); }; /** * Opens scanned link if it is a valid app link or shows and error dialog * * @param event */ onCodeScanned = (event: BarCodeReadEvent) => { if (!URLHandler.isUrlValid(event.data)) { this.showErrorDialog(); } else { this.showOpeningDialog(); Linking.openURL(event.data); } }; render() { const { state } = this; return ( {state.hasPermission ? this.getScanner() : this.getPermissionScreen()} ); } } export default ScannerScreen;