test.tsx 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import { CameraView, useCameraPermissions } from 'expo-camera';
  2. import { useRef, useState } from 'react';
  3. import {
  4. Button,
  5. Dimensions,
  6. Pressable,
  7. ScrollView,
  8. StyleSheet,
  9. Text,
  10. View
  11. } from 'react-native';
  12. import ChooseCarForChargingRow from '../../component/global/chooseCarForChargingRow';
  13. import { SafeAreaView } from 'react-native-safe-area-context';
  14. import { CrossLogoWhiteSvg, QuestionSvg } from '../../component/global/SVG';
  15. import { router } from 'expo-router';
  16. export default function Test() {
  17. const [permission, requestPermission] = useCameraPermissions();
  18. const [scanned, setScanned] = useState(false);
  19. const viewRef = useRef(null);
  20. if (!permission) {
  21. return <View />;
  22. }
  23. if (!permission.granted) {
  24. return (
  25. <View style={styles.container}>
  26. <Text style={{ textAlign: 'center' }}>
  27. We need your permission to show the camera
  28. </Text>
  29. <Button onPress={requestPermission} title="grant permission" />
  30. </View>
  31. );
  32. }
  33. const { width: screenWidth, height: screenHeight } =
  34. Dimensions.get('window');
  35. const handleBarCodeScanned = ({ bounds, data, type }) => {
  36. const { origin, size } = bounds;
  37. // Calculate the size of the square transparent area
  38. const transparentAreaSize = Math.min(
  39. screenWidth * 0.6,
  40. screenHeight * 0.3
  41. );
  42. const transparentAreaX = (screenWidth - transparentAreaSize) / 2;
  43. const transparentAreaY = (screenHeight - transparentAreaSize) / 2;
  44. // Check if the barcode is within the transparent area
  45. if (
  46. origin.x >= transparentAreaX &&
  47. origin.y >= transparentAreaY &&
  48. origin.x + size.width <= transparentAreaX + transparentAreaSize &&
  49. origin.y + size.height <= transparentAreaY + transparentAreaSize
  50. ) {
  51. setScanned(true);
  52. console.log(` type: ${type} data: ${data} `);
  53. if (type === 'qr') {
  54. console.log('QR Code link:', data);
  55. }
  56. setTimeout(() => {
  57. setScanned(false);
  58. }, 5000);
  59. }
  60. };
  61. const dummyDataChooseCarForCharging = [
  62. {
  63. imageUrl: require('../../assets/car1.png'),
  64. VehicleName: 'TESLA - Model 3',
  65. isDefault: true
  66. },
  67. { VehicleName: 'TESLA - Model Y', isDefault: false },
  68. {
  69. imageUrl: require('../../assets/car1.png'),
  70. VehicleName: 'TESLA - Model X',
  71. isDefault: false
  72. },
  73. { VehicleName: 'TESLA - Model 3', isDefault: false }
  74. ];
  75. const ChooseCar = () => {
  76. const isLargeScreen = screenHeight >= 800;
  77. return (
  78. <View
  79. style={{
  80. ...(isLargeScreen
  81. ? {
  82. marginTop: '10%',
  83. marginBottom: '12%',
  84. paddingBottom: 12,
  85. backgroundColor: 'rgba(0,0,0,0.7)'
  86. }
  87. : {
  88. marginVertical: '5%',
  89. paddingBottom: 12,
  90. backgroundColor: 'rgba(0,0,0,0.7)'
  91. })
  92. }}
  93. >
  94. <View className="mx-[5%] items-center">
  95. <View className="flex-row items-center justify-between w-full">
  96. <View className="pt-2">
  97. <Pressable
  98. onPress={() => {
  99. if (router.canGoBack()) {
  100. router.back();
  101. } else {
  102. router.replace('mainPage');
  103. }
  104. }}
  105. >
  106. <CrossLogoWhiteSvg />
  107. </Pressable>
  108. </View>
  109. <Text className="text-base text-white pt-2">
  110. 選擇充電車輛
  111. </Text>
  112. <Text className="text-xl text-white pt-2"></Text>
  113. </View>
  114. <ScrollView
  115. horizontal={true}
  116. showsHorizontalScrollIndicator={false}
  117. contentContainerStyle={{
  118. alignItems: 'center',
  119. flexDirection: 'row',
  120. marginVertical: 8
  121. }}
  122. className="space-x-2"
  123. >
  124. {dummyDataChooseCarForCharging.map((car, index) => (
  125. <ChooseCarForChargingRow
  126. imageUrl={car.imageUrl}
  127. key={`${car.VehicleName}+${index}`}
  128. VehicleName={car.VehicleName}
  129. isDefault={car.isDefault}
  130. />
  131. ))}
  132. </ScrollView>
  133. </View>
  134. </View>
  135. );
  136. };
  137. return (
  138. <SafeAreaView className="flex-1" edges={['top', 'right', 'left']}>
  139. <View style={styles.container} ref={viewRef}>
  140. <CameraView
  141. style={styles.camera}
  142. facing="back"
  143. barcodeScannerSettings={{
  144. barcodeTypes: ['qr']
  145. }}
  146. onBarcodeScanned={
  147. scanned ? undefined : handleBarCodeScanned
  148. }
  149. responsiveOrientationWhenOrientationLocked={true}
  150. >
  151. <View style={styles.overlay}>
  152. <View style={styles.topOverlay}>
  153. <ChooseCar />
  154. </View>
  155. <View style={styles.centerRow}>
  156. <View style={styles.leftOverlay}></View>
  157. <View style={styles.transparentArea}></View>
  158. <View style={styles.rightOverlay} />
  159. </View>
  160. <View
  161. className="items-center justify-between"
  162. style={styles.bottomOverlay}
  163. >
  164. <View>
  165. <Text className="text-white text-lg font-bold mt-2 ">
  166. 請掃瞄充電座上的二維碼
  167. </Text>
  168. </View>
  169. <View className="flex-row space-x-2 items-center ">
  170. <QuestionSvg />
  171. <Pressable
  172. onPress={() => console.log('需要協助?')}
  173. >
  174. <Text className="text-white text-base">
  175. 需要協助?
  176. </Text>
  177. </Pressable>
  178. </View>
  179. <View />
  180. </View>
  181. </View>
  182. </CameraView>
  183. </View>
  184. </SafeAreaView>
  185. );
  186. }
  187. const styles = StyleSheet.create({
  188. container: {
  189. flex: 1
  190. },
  191. camera: {
  192. flex: 1
  193. },
  194. overlay: {
  195. flex: 1
  196. },
  197. topOverlay: {
  198. flex: 35,
  199. alignItems: 'center',
  200. backgroundColor: 'rgba(0,0,0,0.5)'
  201. },
  202. centerRow: {
  203. flex: 30,
  204. flexDirection: 'row'
  205. },
  206. leftOverlay: {
  207. flex: 20,
  208. backgroundColor: 'rgba(0,0,0,0.5)'
  209. },
  210. transparentArea: {
  211. flex: 60,
  212. aspectRatio: 1,
  213. position: 'relative'
  214. },
  215. rightOverlay: {
  216. flex: 20,
  217. backgroundColor: 'rgba(0,0,0,0.5)'
  218. },
  219. bottomOverlay: {
  220. flex: 35,
  221. backgroundColor: 'rgba(0,0,0,0.5)'
  222. }
  223. });