ReCommit: Removed header for all screens. Updated QRScanner Screen UI to be responsive to screen size

This commit is contained in:
2024-08-07 12:07:17 +08:00
parent 7cb5cbbe34
commit f893f3285a
10 changed files with 140 additions and 104 deletions

View File

@@ -33,6 +33,7 @@ const App: React.FC = () => {
<Tab.Navigator <Tab.Navigator
initialRouteName="QRScanner" initialRouteName="QRScanner"
tabBar={(props) => <CustomTabBar {...props} clearScanData={clearScanData} />} tabBar={(props) => <CustomTabBar {...props} clearScanData={clearScanData} />}
screenOptions={{ headerShown: false }} // turn of header for all screens
> >
<Tab.Screen name="History" component={HistoryScreen} /> <Tab.Screen name="History" component={HistoryScreen} />
<Tab.Screen name="QRScanner"> <Tab.Screen name="QRScanner">
@@ -40,6 +41,11 @@ const App: React.FC = () => {
</Tab.Screen> </Tab.Screen>
<Tab.Screen name="Email" component={EmailScreen} /> <Tab.Screen name="Email" component={EmailScreen} />
</Tab.Navigator> </Tab.Navigator>
</NavigationContainer> </NavigationContainer>
</QRCodeContext.Provider> </QRCodeContext.Provider>
</Provider> </Provider>

BIN
assets/SafeQR_Logo 1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -76,7 +76,7 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
} }
}; };
const getRedirectIcon = () => { const getSheildIcon = () => {
if (redirects === 0) { if (redirects === 0) {
return <Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#44c167" />; return <Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#44c167" />;
} else if (redirects <= 2) { } else if (redirects <= 2) {
@@ -99,19 +99,24 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
}; };
return ( return (
<View style={styles.dataBox}> <View style={styles.dataBox}>
<TouchableOpacity style={styles.closeButton} onPress={clearScanData}> <TouchableOpacity style={styles.closeButton} onPress={clearScanData}>
<Ionicons name="close-circle-outline" size={screenWidth * 0.05} color="#ff69b4" /> <Ionicons name="close-circle-outline" size={screenWidth * 0.05} color="#ff69b4" />
</TouchableOpacity> </TouchableOpacity>
{/* The Top Scan Icon with payload, truncated */}
<View style={[styles.row, styles.shadowBox]}> <View style={[styles.row, styles.shadowBox]}>
<Image source={require('../assets/ScanIcon3.png')} style={styles.scan_icon} /> <Image source={require('../assets/ScanIcon3.png')} style={styles.scan_icon} />
<Text style={styles.payload} onPress={() => setIsContentModalVisible(true)}> <Text style={styles.payload} onPress={() => setIsContentModalVisible(true)}>
{truncateContent(contents, 30)} {/* Truncated content further */} {truncateContent(contents, 30)}
</Text> </Text>
</View> </View>
<View style={styles.mainContent}> <View style={styles.mainContent}>
{/* Display QR Code , timestamp and Description */}
<View style={styles.qrSection}> <View style={styles.qrSection}>
<QRCode value={contents || 'No Data'} size={screenWidth * 0.2} backgroundColor="transparent" /> <QRCode value={contents || 'No Data'} size={screenWidth * 0.2} backgroundColor="transparent" />
</View> </View>
@@ -123,11 +128,12 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
</View> </View>
</View> </View>
{/* The Main Result in appropriate color */}
<Text style={[styles.resultText, { color: getResultColor() }]}> <Text style={[styles.resultText, { color: getResultColor() }]}>
Result: {getResultText()} Result: {getResultText()}
</Text> </Text>
{/* Change the UI based on Type */}
{type === 'URL' && ( {type === 'URL' && (
<> <>
<View style={styles.displayCheck}> <View style={styles.displayCheck}>
@@ -140,31 +146,19 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
<> <>
<SimpleLineIcons name="shield" size={screenWidth * 0.045} color="#ff0000" /> <SimpleLineIcons name="shield" size={screenWidth * 0.045} color="#ff0000" />
<Text style={styles.moreInfoButtonText}>Not Secure</Text> <Text style={styles.moreInfoButtonText}>Not Secure</Text>
</> </>
)} )}
</View> </View>
<TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsRedirectModalVisible(true)}> <TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsRedirectModalVisible(true)}>
{getRedirectIcon()} {getSheildIcon()}
<Text style={styles.moreInfoButtonText}>Redirects</Text> <Text style={styles.moreInfoButtonText}>Redirects</Text>
<Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" /> <Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" />
</TouchableOpacity> </TouchableOpacity>
</>
)}
{type === 'SMS' && (
<>
<Text style={styles.moreInfoButtonText}>Recipient Phone Number: {details.phone || 'Undefined'}</Text>
<Text style={styles.moreInfoButtonText}>Message Content: {details.message || 'Undefined'}</Text>
</>
)}
{type === 'TEXT' && (
<TouchableOpacity style={[styles.contentBox, styles.shadowBox]} onPress={() => setIsContentModalVisible(true)}>
<Text style={styles.moreInfoButtonText}>
Content: {truncateContent(contents, 30)} {/* Truncated content further */}
</Text>
</TouchableOpacity>
)}
<TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsModalVisible(true)}> <TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsModalVisible(true)}>
<Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#ff69b4" /> <Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#ff69b4" />
@@ -210,6 +204,32 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
</View> </View>
</Modal> </Modal>
</>
)}
{type === 'SMS' && (
<>
<Text style={styles.moreInfoButton}>Recipient Phone Number: {details.phone || 'Undefined'}</Text>
<Text style={styles.moreInfoButton}>Message Content: {details.message || 'Undefined'}</Text>
</>
)}
{type === 'TEXT' && (
<TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsContentModalVisible(true)}>
<Text >
Content: {truncateContent(contents, 30)} {/* Truncated content further */}
</Text>
<Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" />
</TouchableOpacity>
)}
<Modal <Modal
visible={isContentModalVisible} visible={isContentModalVisible}
transparent={true} transparent={true}
@@ -288,7 +308,7 @@ const styles = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
padding: screenWidth * 0.0125, padding: screenWidth * 0.0525,
}, },
qrSection: { qrSection: {
flex: 1, flex: 1,
@@ -306,7 +326,7 @@ const styles = StyleSheet.create({
timestampText: { timestampText: {
fontSize: screenWidth * 0.0275, fontSize: screenWidth * 0.03,
color: '#000', color: '#000',
marginBottom: screenWidth * 0.01875, marginBottom: screenWidth * 0.01875,
}, },

View File

@@ -6,19 +6,17 @@ import HistoryScreen from '../screens/HistoryScreen';
import SettingsScreen from '../screens/SettingsScreen'; import SettingsScreen from '../screens/SettingsScreen';
import CustomTabBar from '../components/CustomTabBar'; import CustomTabBar from '../components/CustomTabBar';
// Create a bottom tab navigator
const Tab = createBottomTabNavigator(); const Tab = createBottomTabNavigator();
// Main navigation component
const AppNavigator = () => { const AppNavigator = () => {
return ( return (
// Wrap the navigator in a NavigationContainer to manage the navigation tree
<NavigationContainer> <NavigationContainer>
<Tab.Navigator
{/* Define the tab navigator with custom tab bar and initial route */} initialRouteName="QRScanner"
<Tab.Navigator initialRouteName="QR Scanner" tabBar={props => <CustomTabBar {...props} />}> tabBar={props => <CustomTabBar clearScanData={function (): void {
throw new Error('Function not implemented.');
{/* Define each tab with a name and corresponding component */} } } {...props} />}
>
<Tab.Screen name="History" component={HistoryScreen} /> <Tab.Screen name="History" component={HistoryScreen} />
<Tab.Screen name="QRScanner" component={QRScannerScreen} /> <Tab.Screen name="QRScanner" component={QRScannerScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} />

7
package-lock.json generated
View File

@@ -42,7 +42,8 @@
"react-native-svg": "15.2.0", "react-native-svg": "15.2.0",
"react-native-webview": "^13.8.6", "react-native-webview": "^13.8.6",
"react-redux": "^9.1.2", "react-redux": "^9.1.2",
"redux": "^5.0.1" "redux": "^5.0.1",
"safeqr": "file:"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",
@@ -16952,6 +16953,10 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/safeqr": {
"resolved": "",
"link": true
},
"node_modules/sax": { "node_modules/sax": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",

View File

@@ -46,7 +46,8 @@
"react-native-svg": "15.2.0", "react-native-svg": "15.2.0",
"react-native-webview": "^13.8.6", "react-native-webview": "^13.8.6",
"react-redux": "^9.1.2", "react-redux": "^9.1.2",
"redux": "^5.0.1" "redux": "^5.0.1",
"safeqr": "file:"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect, useCallback } from 'react'; import React, { useState, useEffect, useCallback } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Modal, TouchableWithoutFeedback } from 'react-native'; import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Modal, Image, Dimensions } from 'react-native';
import { Camera, CameraView, scanFromURLAsync } from 'expo-camera'; import { Camera, CameraView, scanFromURLAsync } from 'expo-camera';
import { Ionicons } from '@expo/vector-icons'; import { Ionicons } from '@expo/vector-icons';
import { useFocusEffect, useNavigation } from '@react-navigation/native'; import { useFocusEffect, useNavigation } from '@react-navigation/native';
@@ -7,10 +7,11 @@ import * as ImagePicker from 'expo-image-picker';
import ScannedDataBox from '../components/ScannedDataBox'; import ScannedDataBox from '../components/ScannedDataBox';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { AppDispatch } from '../store'; import { AppDispatch } from '../store';
import { addQRCode } from '../reducers/qrCodesReducer';
import { scanQRCode, getUserInfo } from '../api/qrCodeAPI'; import { scanQRCode, getUserInfo } from '../api/qrCodeAPI';
import SettingsScreen from './SettingsScreen'; import SettingsScreen from './SettingsScreen';
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanData }) => { const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanData }) => {
const navigation = useNavigation(); // Navigation hook const navigation = useNavigation(); // Navigation hook
const dispatch = useDispatch<AppDispatch>(); // Use dispatch for Redux actions const dispatch = useDispatch<AppDispatch>(); // Use dispatch for Redux actions
@@ -141,8 +142,9 @@ const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanDat
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.headerText}>SafeQR</Text> <Text style={styles.titleText}>Welcome to</Text>
<Text style={styles.welcomeText}>Welcome to SafeQR code Scanner</Text> <Image source={require('../assets/SafeQR_Logo 1.png')} style={styles.logo} />
<Text style={styles.welcomeText}>Please point the camera at the QR Code</Text>
<View style={styles.cameraContainer}> <View style={styles.cameraContainer}>
{cameraVisible && ( {cameraVisible && (
@@ -155,10 +157,10 @@ const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanDat
)} )}
<TouchableOpacity onPress={toggleTorch} style={styles.flashButton}> <TouchableOpacity onPress={toggleTorch} style={styles.flashButton}>
<Ionicons name="flashlight" size={24} color="#fff" /> <Ionicons name="flashlight" size={screenWidth * 0.06} color="#fff" />
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={readQRFromImage} style={styles.galleryButton}> <TouchableOpacity onPress={readQRFromImage} style={styles.galleryButton}>
<Ionicons name="image" size={24} color="#fff" /> <Ionicons name="image" size={screenWidth * 0.06} color="#fff" />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
@@ -172,10 +174,9 @@ const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanDat
</View> </View>
)} )}
{/* Settings Icon */} {/* Settings Icon */}
<TouchableOpacity onPress={() => setIsSettingsModalVisible(true)} style={styles.settingsButton}> <TouchableOpacity onPress={() => setIsSettingsModalVisible(true)} style={styles.settingsButton}>
<Ionicons name="settings" size={24} color="#000" /> <Ionicons name="settings" size={screenWidth * 0.06} color="#000" />
</TouchableOpacity> </TouchableOpacity>
{/* Settings Modal */} {/* Settings Modal */}
@@ -205,12 +206,36 @@ const styles = StyleSheet.create({
backgroundColor: '#f8f0fc', backgroundColor: '#f8f0fc',
padding: 20, padding: 20,
}, },
headerText: { titleText: {
fontSize: 24,
fontWeight: 'bold',
color: '#ff69b4',
textAlign: 'center', textAlign: 'center',
marginBottom: 20, fontSize: 20,
marginTop: screenHeight * 0.05,
color: 'black',
},
logo: {
alignSelf: 'center',
width: screenWidth * 0.5,
height: screenWidth * 0.2,
resizeMode: 'contain',
marginVertical: 10,
},
welcomeText: {
textAlign: 'center',
fontSize: 20,
marginVertical: 10,
color: 'black',
},
cameraContainer: {
height: '60%',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
overflow: 'hidden',
},
settingsButton: {
position: 'absolute',
top: screenHeight * 0.05,
right: 20,
}, },
splashContainer: { splashContainer: {
flex: 1, flex: 1,
@@ -220,38 +245,31 @@ const styles = StyleSheet.create({
height: '100%', height: '100%',
width: '100%', width: '100%',
}, },
cameraContainer: {
height: '60%',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
overflow: 'hidden',
},
camera: { camera: {
width: '100%', width: '100%',
height: '100%', height: '100%',
}, },
flashButton: { flashButton: {
position: 'absolute', position: 'absolute',
bottom: 20, bottom: screenHeight * 0.025,
left: 100, left: screenWidth * 0.2,
width: 50, width: screenWidth * 0.125,
height: 50, height: screenWidth * 0.125,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
backgroundColor: '#000', backgroundColor: '#000',
borderRadius: 25, borderRadius: screenWidth * 0.0625,
}, },
galleryButton: { galleryButton: {
position: 'absolute', position: 'absolute',
bottom: 20, bottom: screenHeight * 0.025,
right: 100, right: screenWidth * 0.2,
width: 50, width: screenWidth * 0.125,
height: 50, height: screenWidth * 0.125,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
backgroundColor: '#000', backgroundColor: '#000',
borderRadius: 25, borderRadius: screenWidth * 0.0625,
}, },
scannedDataBoxPopup: { scannedDataBoxPopup: {
position: 'absolute', position: 'absolute',
@@ -259,51 +277,39 @@ const styles = StyleSheet.create({
left: '5%', left: '5%',
right: '5%', right: '5%',
zIndex: 2, zIndex: 2,
backgroundColor: 'white', // Optional: Set a background color if needed backgroundColor: 'white',
borderRadius: 10, // Optional: Add rounded corners borderRadius: screenWidth * 0.025,
padding: 10, // Optional: Add padding around the content padding: screenWidth * 0.025,
elevation: 5, // Optional: Add elevation for shadow effect elevation: 5,
}, },
welcomeText: {
textAlign: 'center',
fontSize: 20,
marginVertical: 10,
color: 'black',
},
settingsButton: {
position: 'absolute',
top: 40,
right: 20,
zIndex: 2,
},
settingsModal: { settingsModal: {
backgroundColor: 'rgba(0, 0, 0, 0.5)', // Semi-transparent background backgroundColor: 'rgba(0, 0, 0, 0.5)', // Semi-transparent background
}, },
settingsModalContainer: { settingsModalContainer: {
flex: 2, flex: 1,
justifyContent: 'center', // Center the modal vertically justifyContent: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.5)', backgroundColor: 'rgba(0, 0, 0, 0.5)',
}, },
settingsModalContent: { settingsModalContent: {
width: '100%', width: '100%',
height: '80%', // Increase the height to make the modal taller height: '80%',
backgroundColor: 'white', backgroundColor: 'white',
padding: 20, padding: screenWidth * 0.05,
borderTopLeftRadius: 10, borderTopLeftRadius: screenWidth * 0.025,
borderTopRightRadius: 10, borderTopRightRadius: screenWidth * 0.025,
alignItems: 'center', alignItems: 'center',
}, },
closeButton: { closeButton: {
marginTop: 10, marginTop: screenHeight * 0.01,
padding: 10, padding: screenWidth * 0.025,
backgroundColor: '#ff69b4', backgroundColor: '#ff69b4',
borderRadius: 5, borderRadius: screenWidth * 0.0125,
}, },
closeButtonText: { closeButtonText: {
color: 'white', color: 'white',
fontWeight: 'bold', fontWeight: 'bold',
} },
}); });
export default QRScannerScreen; export default QRScannerScreen;

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB