react-native-timacare 3.3.56-alert → 3.3.58-cccd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/lib/commonjs/assets/icons/index.js +1 -1
  2. package/lib/commonjs/assets/icons/index.js.flow +2 -0
  3. package/lib/commonjs/assets/icons/index.js.map +1 -1
  4. package/lib/commonjs/assets/icons/modal_confirm.svg +5 -5
  5. package/lib/commonjs/assets/icons/modal_notice.svg +32 -32
  6. package/lib/commonjs/assets/icons/modal_success.svg +26 -26
  7. package/lib/commonjs/assets/icons/modal_warning.svg +21 -21
  8. package/lib/commonjs/assets/icons/user_security.svg +10 -0
  9. package/lib/commonjs/assets/tts/Frame1000011947.png +0 -0
  10. package/lib/commonjs/components/AlertLoan.js +1 -1
  11. package/lib/commonjs/components/AlertLoan.js.flow +1 -1
  12. package/lib/commonjs/components/AlertLoan.js.map +1 -1
  13. package/lib/commonjs/components/AppModal.js +1 -1
  14. package/lib/commonjs/components/AppModal.js.flow +40 -2
  15. package/lib/commonjs/components/AppModal.js.map +1 -1
  16. package/lib/commonjs/components/ItemTimaOne.js +1 -1
  17. package/lib/commonjs/components/ItemTimaOne.js.flow +1 -1
  18. package/lib/commonjs/components/ItemTimaOne.js.map +1 -1
  19. package/lib/commonjs/components/ModalNotification/AlertGlobal.js +1 -1
  20. package/lib/commonjs/components/ModalNotification/AlertGlobal.js.flow +92 -33
  21. package/lib/commonjs/components/ModalNotification/AlertGlobal.js.map +1 -1
  22. package/lib/commonjs/components/ModalNotification/index.js +1 -1
  23. package/lib/commonjs/components/ModalNotification/index.js.flow +7 -0
  24. package/lib/commonjs/components/ModalNotification/index.js.map +1 -1
  25. package/lib/commonjs/components/ModalOptionLoan.js +1 -1
  26. package/lib/commonjs/components/ModalOptionLoan.js.flow +1 -1
  27. package/lib/commonjs/components/ModalOptionLoan.js.map +1 -1
  28. package/lib/commonjs/components/ModalOptionLoanDigital.js +1 -1
  29. package/lib/commonjs/components/ModalOptionLoanDigital.js.flow +1 -1
  30. package/lib/commonjs/components/ModalOptionLoanDigital.js.map +1 -1
  31. package/lib/commonjs/components/modalStack.js +2 -0
  32. package/lib/commonjs/components/modalStack.js.flow +47 -0
  33. package/lib/commonjs/components/modalStack.js.map +1 -0
  34. package/lib/commonjs/navigation/primary-navigator.js +1 -1
  35. package/lib/commonjs/navigation/primary-navigator.js.flow +7 -0
  36. package/lib/commonjs/navigation/primary-navigator.js.map +1 -1
  37. package/lib/commonjs/screens/NFC/OcrStart.js +2 -0
  38. package/lib/commonjs/screens/NFC/OcrStart.js.flow +171 -0
  39. package/lib/commonjs/screens/NFC/OcrStart.js.map +1 -0
  40. package/lib/commonjs/screens/NFC/ScanMRZ.js +2 -0
  41. package/lib/commonjs/screens/NFC/ScanMRZ.js.flow +563 -0
  42. package/lib/commonjs/screens/NFC/ScanMRZ.js.map +1 -0
  43. package/lib/commonjs/screens/camera/CCCDCameraScreen.js +1 -1
  44. package/lib/commonjs/screens/camera/CCCDCameraScreen.js.flow +203 -133
  45. package/lib/commonjs/screens/camera/CCCDCameraScreen.js.map +1 -1
  46. package/lib/commonjs/screens/camera/index.js +1 -1
  47. package/lib/commonjs/screens/camera/index.js.flow +1 -1
  48. package/lib/commonjs/screens/camera/index.js.map +1 -1
  49. package/lib/commonjs/screens/detail-loan/PaymentInfo.js +1 -1
  50. package/lib/commonjs/screens/detail-loan/PaymentInfo.js.flow +1 -1
  51. package/lib/commonjs/screens/detail-loan/PaymentInfo.js.map +1 -1
  52. package/lib/commonjs/screens/detail-loan/ShowQrCode.js +1 -1
  53. package/lib/commonjs/screens/detail-loan/ShowQrCode.js.flow +1 -1
  54. package/lib/commonjs/screens/detail-loan/ShowQrCode.js.map +1 -1
  55. package/lib/commonjs/screens/digital-lending/Step6.js +1 -1
  56. package/lib/commonjs/screens/digital-lending/Step6.js.flow +1 -1
  57. package/lib/commonjs/screens/digital-lending/Step6.js.map +1 -1
  58. package/lib/commonjs/screens/eSign/index.js +1 -1
  59. package/lib/commonjs/screens/eSign/index.js.flow +1 -1
  60. package/lib/commonjs/screens/eSign/index.js.map +1 -1
  61. package/lib/commonjs/screens/home/DigitalTopupItem.js +1 -1
  62. package/lib/commonjs/screens/home/DigitalTopupItem.js.flow +1 -1
  63. package/lib/commonjs/screens/home/DigitalTopupItem.js.map +1 -1
  64. package/lib/commonjs/screens/home/ItemMotoBikeLoan.js +1 -1
  65. package/lib/commonjs/screens/home/ItemMotoBikeLoan.js.flow +1 -1
  66. package/lib/commonjs/screens/home/ItemMotoBikeLoan.js.map +1 -1
  67. package/lib/commonjs/screens/home/index.js +1 -1
  68. package/lib/commonjs/screens/home/index.js.flow +8 -113
  69. package/lib/commonjs/screens/home/index.js.map +1 -1
  70. package/lib/commonjs/screens/nationalID/index.js +1 -1
  71. package/lib/commonjs/screens/nationalID/index.js.flow +123 -218
  72. package/lib/commonjs/screens/nationalID/index.js.map +1 -1
  73. package/lib/commonjs/screens/nationalIDBack/index.js +1 -1
  74. package/lib/commonjs/screens/nationalIDBack/index.js.flow +129 -209
  75. package/lib/commonjs/screens/nationalIDBack/index.js.map +1 -1
  76. package/lib/commonjs/screens/payment-evidence/ModalGuideline.js +1 -1
  77. package/lib/commonjs/screens/payment-evidence/ModalGuideline.js.flow +1 -1
  78. package/lib/commonjs/screens/payment-evidence/ModalGuideline.js.map +1 -1
  79. package/lib/commonjs/screens/toan-trinh-so/OCR.js +1 -1
  80. package/lib/commonjs/screens/toan-trinh-so/OCR.js.flow +270 -556
  81. package/lib/commonjs/screens/toan-trinh-so/OCR.js.map +1 -1
  82. package/lib/commonjs/screens/toan-trinh-so/RegisterCamera.js +1 -1
  83. package/lib/commonjs/screens/toan-trinh-so/RegisterCamera.js.flow +1 -1
  84. package/lib/commonjs/screens/toan-trinh-so/RegisterCamera.js.map +1 -1
  85. package/lib/commonjs/screens/toan-trinh-so/VehicleCamera.js +1 -1
  86. package/lib/commonjs/screens/toan-trinh-so/VehicleCamera.js.flow +226 -288
  87. package/lib/commonjs/screens/toan-trinh-so/VehicleCamera.js.map +1 -1
  88. package/lib/commonjs/utils/cameraCrop.js +2 -0
  89. package/lib/commonjs/utils/cameraCrop.js.flow +96 -0
  90. package/lib/commonjs/utils/cameraCrop.js.map +1 -0
  91. package/lib/module/assets/icons/index.js +1 -1
  92. package/lib/module/assets/icons/index.js.map +1 -1
  93. package/lib/module/assets/icons/modal_confirm.svg +5 -5
  94. package/lib/module/assets/icons/modal_notice.svg +32 -32
  95. package/lib/module/assets/icons/modal_success.svg +26 -26
  96. package/lib/module/assets/icons/modal_warning.svg +21 -21
  97. package/lib/module/assets/icons/user_security.svg +10 -0
  98. package/lib/module/assets/tts/Frame1000011947.png +0 -0
  99. package/lib/module/components/AlertLoan.js +1 -1
  100. package/lib/module/components/AlertLoan.js.map +1 -1
  101. package/lib/module/components/AppModal.js +1 -1
  102. package/lib/module/components/AppModal.js.map +1 -1
  103. package/lib/module/components/ItemTimaOne.js +1 -1
  104. package/lib/module/components/ItemTimaOne.js.map +1 -1
  105. package/lib/module/components/ModalNotification/AlertGlobal.js +1 -1
  106. package/lib/module/components/ModalNotification/AlertGlobal.js.map +1 -1
  107. package/lib/module/components/ModalNotification/index.js +1 -1
  108. package/lib/module/components/ModalNotification/index.js.map +1 -1
  109. package/lib/module/components/ModalOptionLoan.js +1 -1
  110. package/lib/module/components/ModalOptionLoan.js.map +1 -1
  111. package/lib/module/components/ModalOptionLoanDigital.js +1 -1
  112. package/lib/module/components/ModalOptionLoanDigital.js.map +1 -1
  113. package/lib/module/components/modalStack.js +2 -0
  114. package/lib/module/components/modalStack.js.map +1 -0
  115. package/lib/module/navigation/primary-navigator.js +1 -1
  116. package/lib/module/navigation/primary-navigator.js.map +1 -1
  117. package/lib/module/screens/NFC/OcrStart.js +2 -0
  118. package/lib/module/screens/NFC/OcrStart.js.map +1 -0
  119. package/lib/module/screens/NFC/ScanMRZ.js +2 -0
  120. package/lib/module/screens/NFC/ScanMRZ.js.map +1 -0
  121. package/lib/module/screens/camera/CCCDCameraScreen.js +1 -1
  122. package/lib/module/screens/camera/CCCDCameraScreen.js.map +1 -1
  123. package/lib/module/screens/camera/index.js +1 -1
  124. package/lib/module/screens/camera/index.js.map +1 -1
  125. package/lib/module/screens/detail-loan/PaymentInfo.js +1 -1
  126. package/lib/module/screens/detail-loan/PaymentInfo.js.map +1 -1
  127. package/lib/module/screens/detail-loan/ShowQrCode.js +1 -1
  128. package/lib/module/screens/detail-loan/ShowQrCode.js.map +1 -1
  129. package/lib/module/screens/digital-lending/Step6.js +1 -1
  130. package/lib/module/screens/digital-lending/Step6.js.map +1 -1
  131. package/lib/module/screens/eSign/index.js +1 -1
  132. package/lib/module/screens/eSign/index.js.map +1 -1
  133. package/lib/module/screens/home/DigitalTopupItem.js +1 -1
  134. package/lib/module/screens/home/DigitalTopupItem.js.map +1 -1
  135. package/lib/module/screens/home/ItemMotoBikeLoan.js +1 -1
  136. package/lib/module/screens/home/ItemMotoBikeLoan.js.map +1 -1
  137. package/lib/module/screens/home/index.js +1 -1
  138. package/lib/module/screens/home/index.js.map +1 -1
  139. package/lib/module/screens/nationalID/index.js +1 -1
  140. package/lib/module/screens/nationalID/index.js.map +1 -1
  141. package/lib/module/screens/nationalIDBack/index.js +1 -1
  142. package/lib/module/screens/nationalIDBack/index.js.map +1 -1
  143. package/lib/module/screens/payment-evidence/ModalGuideline.js +1 -1
  144. package/lib/module/screens/payment-evidence/ModalGuideline.js.map +1 -1
  145. package/lib/module/screens/toan-trinh-so/OCR.js +1 -1
  146. package/lib/module/screens/toan-trinh-so/OCR.js.map +1 -1
  147. package/lib/module/screens/toan-trinh-so/RegisterCamera.js +1 -1
  148. package/lib/module/screens/toan-trinh-so/RegisterCamera.js.map +1 -1
  149. package/lib/module/screens/toan-trinh-so/VehicleCamera.js +1 -1
  150. package/lib/module/screens/toan-trinh-so/VehicleCamera.js.map +1 -1
  151. package/lib/module/utils/cameraCrop.js +2 -0
  152. package/lib/module/utils/cameraCrop.js.map +1 -0
  153. package/lib/typescript/assets/icons/index.d.ts +2 -1
  154. package/lib/typescript/assets/icons/index.d.ts.map +1 -1
  155. package/lib/typescript/components/AppModal.d.ts +6 -1
  156. package/lib/typescript/components/AppModal.d.ts.map +1 -1
  157. package/lib/typescript/components/ModalNotification/AlertGlobal.d.ts +20 -4
  158. package/lib/typescript/components/ModalNotification/AlertGlobal.d.ts.map +1 -1
  159. package/lib/typescript/components/ModalNotification/index.d.ts +6 -1
  160. package/lib/typescript/components/ModalNotification/index.d.ts.map +1 -1
  161. package/lib/typescript/components/modalStack.d.ts +11 -0
  162. package/lib/typescript/components/modalStack.d.ts.map +1 -0
  163. package/lib/typescript/navigation/primary-navigator.d.ts +3 -0
  164. package/lib/typescript/navigation/primary-navigator.d.ts.map +1 -1
  165. package/lib/typescript/screens/NFC/OcrStart.d.ts +2 -0
  166. package/lib/typescript/screens/NFC/OcrStart.d.ts.map +1 -0
  167. package/lib/typescript/screens/NFC/ScanMRZ.d.ts +15 -0
  168. package/lib/typescript/screens/NFC/ScanMRZ.d.ts.map +1 -0
  169. package/lib/typescript/screens/camera/CCCDCameraScreen.d.ts.map +1 -1
  170. package/lib/typescript/screens/home/index.d.ts.map +1 -1
  171. package/lib/typescript/screens/nationalID/index.d.ts.map +1 -1
  172. package/lib/typescript/screens/nationalIDBack/index.d.ts.map +1 -1
  173. package/lib/typescript/screens/toan-trinh-so/OCR.d.ts.map +1 -1
  174. package/lib/typescript/screens/toan-trinh-so/VehicleCamera.d.ts.map +1 -1
  175. package/lib/typescript/utils/cameraCrop.d.ts +43 -0
  176. package/lib/typescript/utils/cameraCrop.d.ts.map +1 -0
  177. package/package.json +2 -1
  178. package/src/assets/icons/index.tsx +2 -0
  179. package/src/assets/icons/modal_confirm.svg +5 -5
  180. package/src/assets/icons/modal_notice.svg +32 -32
  181. package/src/assets/icons/modal_success.svg +26 -26
  182. package/src/assets/icons/modal_warning.svg +21 -21
  183. package/src/assets/icons/user_security.svg +10 -0
  184. package/src/assets/tts/Frame1000011947.png +0 -0
  185. package/src/components/AlertLoan.tsx +1 -1
  186. package/src/components/AppModal.tsx +40 -2
  187. package/src/components/ItemTimaOne.tsx +1 -1
  188. package/src/components/ModalNotification/AlertGlobal.tsx +92 -33
  189. package/src/components/ModalNotification/index.tsx +7 -0
  190. package/src/components/ModalOptionLoan.tsx +1 -1
  191. package/src/components/ModalOptionLoanDigital.tsx +1 -1
  192. package/src/components/modalStack.ts +47 -0
  193. package/src/navigation/primary-navigator.tsx +7 -0
  194. package/src/screens/NFC/OcrStart.tsx +171 -0
  195. package/src/screens/NFC/ScanMRZ.tsx +563 -0
  196. package/src/screens/camera/CCCDCameraScreen.tsx +203 -133
  197. package/src/screens/camera/index.tsx +1 -1
  198. package/src/screens/detail-loan/PaymentInfo.tsx +1 -1
  199. package/src/screens/detail-loan/ShowQrCode.tsx +1 -1
  200. package/src/screens/digital-lending/Step6.tsx +1 -1
  201. package/src/screens/eSign/index.tsx +1 -1
  202. package/src/screens/home/DigitalTopupItem.tsx +1 -1
  203. package/src/screens/home/ItemMotoBikeLoan.tsx +1 -1
  204. package/src/screens/home/index.tsx +8 -113
  205. package/src/screens/nationalID/index.tsx +123 -218
  206. package/src/screens/nationalIDBack/index.tsx +129 -209
  207. package/src/screens/payment-evidence/ModalGuideline.tsx +1 -1
  208. package/src/screens/toan-trinh-so/OCR.tsx +270 -556
  209. package/src/screens/toan-trinh-so/RegisterCamera.tsx +1 -1
  210. package/src/screens/toan-trinh-so/VehicleCamera.tsx +226 -288
  211. package/src/utils/cameraCrop.ts +96 -0
@@ -1,7 +1,12 @@
1
1
  // @ts-nocheck
2
- import React, { useEffect, useRef, useState } from 'react';
2
+ import React, {
3
+ useCallback,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState,
8
+ } from 'react';
3
9
  import {
4
- Dimensions,
5
10
  Image,
6
11
  ImageStyle,
7
12
  Platform,
@@ -12,15 +17,10 @@ import {
12
17
  ViewStyle,
13
18
  } from 'react-native';
14
19
  import { useNavigation, useIsFocused } from '@react-navigation/native';
15
- import Modal from 'react-native-modal';
20
+ import Modal from '../../components/AppModal';
16
21
  import { MText } from '../../components/MText';
17
22
  import LinearGradient from 'react-native-linear-gradient';
18
- import {
19
- CloseIcon,
20
- IconBackWhite,
21
- TakePhotoSvg,
22
- TimaSmall,
23
- } from '../../assets/icons';
23
+ import { CloseIcon, IconBack, TakePhotoSvg, TimaSmall } from '../../assets/icons';
24
24
  import MButton from '../../components/MButton';
25
25
  import {
26
26
  request,
@@ -28,23 +28,21 @@ import {
28
28
  RESULTS,
29
29
  openSettings,
30
30
  } from 'react-native-permissions';
31
- import {
32
- Camera as VisionCamera,
33
- useCameraDevice,
34
- useCameraFormat,
35
- } from 'react-native-vision-camera';
36
- import { commonStyles } from '../CommonStyles';
31
+ import { Camera as VisionCamera, useCameraDevices } from 'react-native-vision-camera';
37
32
  import { ScreenNames } from '../../navigation';
38
33
  import { load, OCR_V2, save } from '../../utils/storage';
39
- import { IconUpload } from '../../assets/svgs';
40
34
  import ImagePicker from 'react-native-image-crop-picker';
41
35
  import { launchImageLibrary } from 'react-native-image-picker';
42
36
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
43
37
  import { AlertGlobal } from '../../components/ModalNotification/AlertGlobal';
38
+ import {
39
+ cropPhotoToAspect,
40
+ pickClosestFocusDevice,
41
+ } from '../../utils/cameraCrop';
44
42
 
45
- const { width: screenWidth } = Dimensions.get('window');
46
- const frameWidth = screenWidth * 0.85;
47
- const frameHeight = frameWidth * 0.63; // tỷ lệ giống CCCD
43
+ const ORANGE = '#F05123';
44
+ // Đăng xe (cà vẹt) có tỉ lệ gần với thẻ ID-1: 85.6mm x 54mm
45
+ const CARD_ASPECT_RATIO = 85.6 / 54;
48
46
 
49
47
  export default function VehicleCamera(props: any) {
50
48
  const insets = useSafeAreaInsets();
@@ -59,28 +57,45 @@ export default function VehicleCamera(props: any) {
59
57
  const [shouldRenderCamera, setShouldRenderCamera] = useState(false);
60
58
  const navigation = useNavigation();
61
59
  const [showModal, setShowModal] = useState(false);
62
- const [title, setTitle] = useState(
60
+ const [title] = useState(
63
61
  props?.route?.params?.front
64
62
  ? 'Chụp đăng ký xe mặt trước'
65
63
  : 'Chụp đăng ký xe mặt sau'
66
64
  );
67
65
  const [taking, setTaking] = useState(false);
68
66
  const [passPermission, setPassPermission] = useState(false);
67
+ const [focusPoint, setFocusPoint] = useState(null);
69
68
 
70
69
  const myCamera = useRef(null);
71
- const device = useCameraDevice('back');
72
- const format = useCameraFormat(device, [
73
- { photoResolution: { width: 1280, height: 720 } },
70
+ const frameSize = useRef({ width: 0, height: 0 });
71
+ const focusTimer = useRef(null);
72
+
73
+ // Chọn ống kính sau lấy nét gần nhất (macro) để chụp cận thẻ mà không mờ
74
+ const devices = useCameraDevices();
75
+ const device = useMemo(() => pickClosestFocusDevice(devices, 'back'), [
76
+ devices,
74
77
  ]);
75
78
 
76
- const takePhoto = async () => {
77
- if (myCamera.current == null || taking) return;
78
- setTaking(true);
79
- const data = await myCamera.current.takePhoto({
80
- qualityPrioritization: 'quality',
81
- });
82
- const uri = 'file://' + data.path;
83
- setTaking(false);
79
+ // Lấy nét vào một điểm (toạ độ theo hệ khung preview = camera view). Dùng cho
80
+ // chạm-để-lấy-nét lấy nét giữa khung trước khi chụp -> tránh mờ khi gần.
81
+ const focusAt = useCallback(
82
+ async (x, y) => {
83
+ const cam = myCamera.current;
84
+ if (cam == null || !device?.supportsFocus) return;
85
+ setFocusPoint({ x, y });
86
+ if (focusTimer.current) clearTimeout(focusTimer.current);
87
+ focusTimer.current = setTimeout(() => setFocusPoint(null), 800);
88
+ try {
89
+ await cam.focus({ x, y });
90
+ } catch (e) {
91
+ // focus có thể lỗi nếu đang lấy nét dở hoặc điểm ngoài vùng -> bỏ qua
92
+ }
93
+ },
94
+ [device]
95
+ );
96
+
97
+ // Điều hướng sau khi có ảnh (giữ nguyên logic gốc của VehicleCamera)
98
+ const goNextWithUri = (uri) => {
84
99
  if (props?.route?.params?.front) {
85
100
  navigation.push(ScreenNames.VehicleRegistrationFront, {
86
101
  uri,
@@ -97,6 +112,36 @@ export default function VehicleCamera(props: any) {
97
112
  }
98
113
  };
99
114
 
115
+ const takePhoto = async () => {
116
+ if (myCamera.current == null || taking) return;
117
+ setTaking(true);
118
+ try {
119
+ // Lấy nét giữa khung trước khi chụp để tài liệu ở gần vẫn nét
120
+ const { width: fw, height: fh } = frameSize.current;
121
+ if (device?.supportsFocus && fw && fh) {
122
+ try {
123
+ await myCamera.current.focus({ x: fw / 2, y: fh / 2 });
124
+ } catch (e) {}
125
+ }
126
+ const data = await myCamera.current.takePhoto({
127
+ qualityPrioritization: 'quality',
128
+ });
129
+ // Cắt ảnh vừa đúng khung theo tỉ lệ thẻ (xử lý orientation trong util)
130
+ const uri = await cropPhotoToAspect(data, CARD_ASPECT_RATIO);
131
+ setTaking(false);
132
+ goNextWithUri(uri);
133
+ } catch (e) {
134
+ console.error(e);
135
+ setTaking(false);
136
+ AlertGlobal.show({
137
+ type: 'warning',
138
+ title: 'Thông báo',
139
+ message: 'Không chụp được ảnh. Vui lòng thử lại.',
140
+ primaryText: 'Đồng ý',
141
+ });
142
+ }
143
+ };
144
+
100
145
  const requestPermissions = () => {
101
146
  request(
102
147
  Platform.OS === 'ios'
@@ -189,6 +234,9 @@ export default function VehicleCamera(props: any) {
189
234
  useEffect(() => {
190
235
  requestPermissions();
191
236
  loadIntro();
237
+ return () => {
238
+ if (focusTimer.current) clearTimeout(focusTimer.current);
239
+ };
192
240
  }, []);
193
241
 
194
242
  useEffect(() => {
@@ -205,228 +253,92 @@ export default function VehicleCamera(props: any) {
205
253
  return () => clearTimeout(timeout);
206
254
  }, [isFocused]);
207
255
 
256
+ // Giữ nguyên logic chọn ảnh từ thư viện của VehicleCamera
208
257
  const pickImageFromGallery = async () => {
209
258
  if (Platform.OS === 'android') {
210
- const result = await launchImageLibrary({
211
- mediaType: 'photo',
212
- });
259
+ const result = await launchImageLibrary({ mediaType: 'photo' });
213
260
  if (result.assets) {
214
- if (props?.route?.params?.front) {
215
- navigation.push(ScreenNames.VehicleRegistrationFront, {
216
- uri: result.assets[0]?.uri,
217
- loan: props?.route?.params?.loan,
218
- });
219
- } else if (props.route?.params?.callback) {
220
- navigation.goBack();
221
- props.route?.params?.callback(result.assets[0]?.uri);
222
- } else {
223
- navigation.push(ScreenNames.VehicleRegistrationBack, {
224
- uri: result.assets[0]?.uri,
225
- loan: props?.route?.params?.loan,
226
- });
227
- }
261
+ goNextWithUri(result.assets[0]?.uri);
228
262
  }
229
263
  } else {
230
264
  ImagePicker.openPicker({}).then((image) => {
231
- if (props?.route?.params?.front) {
232
- navigation.push(ScreenNames.VehicleRegistrationFront, {
233
- uri:
234
- Platform.OS === 'android' ? image?.path : 'file://' + image?.path,
235
- loan: props?.route?.params?.loan,
236
- });
237
- } else if (props.route?.params?.callback) {
238
- navigation.goBack();
239
- props.route?.params?.callback(
240
- Platform.OS === 'android' ? image?.path : 'file://' + image?.path
241
- );
242
- } else {
243
- navigation.push(ScreenNames.VehicleRegistrationBack, {
244
- uri:
245
- Platform.OS === 'android' ? image?.path : 'file://' + image?.path,
246
- loan: props?.route?.params?.loan,
247
- });
248
- }
265
+ goNextWithUri(
266
+ Platform.OS === 'android' ? image?.path : 'file://' + image?.path
267
+ );
249
268
  });
250
269
  }
251
270
  };
252
271
 
253
272
  return (
254
- <View
255
- style={[$flex, { backgroundColor: '#000' }]}
256
- pointerEvents={'box-none'}
257
- >
273
+ <View style={styles.container}>
258
274
  {passPermission && shouldRenderCamera ? (
259
- <View style={{ flex: 1 }}>
260
- {device ? (
261
- <VisionCamera
262
- key={cameraKey}
263
- ref={myCamera}
264
- style={{
265
- flex: 1,
266
- }}
267
- device={device}
268
- isActive={true}
269
- photo={true}
270
- format={format}
271
- />
272
- ) : null}
273
- <View style={$overlay}>
274
- <View style={$darkOverlayTop} />
275
- <View style={$overlayRow}>
276
- <View style={$darkOverlaySide} />
277
- <View style={$frameBorder}>
278
- <Corner
279
- style={{
280
- top: 0,
281
- left: 0,
282
- borderTopWidth: CORNER_WIDTH,
283
- borderLeftWidth: CORNER_WIDTH,
284
- borderColor: BORDER_COLOR,
285
- }}
286
- />
287
-
288
- <Corner
289
- style={{
290
- top: 0,
291
- right: 0,
292
- borderTopWidth: CORNER_WIDTH,
293
- borderRightWidth: CORNER_WIDTH,
294
- borderColor: BORDER_COLOR,
295
- }}
296
- />
297
-
298
- <Corner
299
- style={{
300
- bottom: 0,
301
- left: 0,
302
- borderBottomWidth: CORNER_WIDTH,
303
- borderLeftWidth: CORNER_WIDTH,
304
- borderColor: BORDER_COLOR,
305
- }}
306
- />
307
-
308
- <Corner
309
- style={{
310
- bottom: 0,
311
- right: 0,
312
- borderBottomWidth: CORNER_WIDTH,
313
- borderRightWidth: CORNER_WIDTH,
314
- borderColor: BORDER_COLOR,
315
- }}
316
- />
317
- </View>
318
- <View style={$darkOverlaySide} />
275
+ <>
276
+ <View style={[styles.header, { paddingTop: insets.top + 16 }]}>
277
+ <TouchableOpacity
278
+ onPress={() => navigation.goBack()}
279
+ hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
280
+ >
281
+ <IconBack />
282
+ </TouchableOpacity>
283
+ <View style={styles.titleWrap}>
284
+ <MText style={styles.headerTitle}>ĐĂNG KÝ XE</MText>
319
285
  </View>
320
- <View style={$darkOverlayBottom} />
321
286
  </View>
322
287
 
288
+ <MText style={styles.instruction}>{title}</MText>
289
+
290
+ {/* Khung tỉ lệ thẻ: vùng nhìn thấy của preview = vùng sẽ crop.
291
+ Chạm vào khung để lấy nét thủ công. */}
323
292
  <View
324
- style={{
325
- position: 'absolute',
326
- bottom: 20,
327
- left: 0,
328
- right: 0,
329
- zIndex: 1000,
293
+ style={styles.photoFrame}
294
+ onLayout={(e) => {
295
+ frameSize.current = e.nativeEvent.layout;
330
296
  }}
297
+ onStartShouldSetResponder={() => true}
298
+ onResponderRelease={(e) =>
299
+ focusAt(e.nativeEvent.locationX, e.nativeEvent.locationY)
300
+ }
331
301
  >
332
- {/* <TouchableOpacity
333
- onPress={() => {
334
- pickImageFromGallery();
335
- }}
336
- style={{
337
- flexDirection: 'row',
338
- alignItems: 'center',
339
- justifyContent: 'center',
340
- gap: 8,
341
- marginBottom: 50,
342
- }}
343
- >
344
- <IconUpload />
345
- <MText
346
- style={{
347
- color: 'white',
348
- fontSize: 12,
349
- }}
350
- >
351
- Tải ảnh từ thư viện
352
- </MText>
353
- </TouchableOpacity> */}
354
- {!taking && (
355
- <>
356
- <MText
357
- style={{
358
- color: 'white',
359
- textAlign: 'center',
360
- fontSize: 14,
361
- }}
362
- >
363
- Vui lòng đặt giấy tờ nằm vừa khung hình chữ nhật,{'\n'}chụp đủ
364
- ánh sáng và rõ nét.
365
- </MText>
366
- <View
367
- style={{
368
- alignItems: 'center',
369
- marginVertical: 24,
370
- }}
371
- >
372
- <MButton
373
- onPress={() => {
374
- takePhoto();
375
- }}
376
- >
377
- <TakePhotoSvg />
378
- </MButton>
379
- </View>
380
- </>
381
- )}
382
- </View>
383
- <View
384
- style={[
385
- commonStyles.fill,
386
- { position: 'absolute', width: '100%', height: '100%' },
387
- ]}
388
- >
389
- <View
390
- style={[
391
- commonStyles.row,
392
- commonStyles.alignCenter,
393
- { paddingVertical: 16, marginTop: insets.top },
394
- ]}
395
- >
396
- <MButton
397
- onPress={() => {
398
- navigation.goBack();
399
- }}
302
+ {device ? (
303
+ <VisionCamera
304
+ key={cameraKey}
305
+ ref={myCamera}
306
+ style={StyleSheet.absoluteFill}
307
+ device={device}
308
+ isActive={isFocused}
309
+ photo={true}
310
+ />
311
+ ) : null}
312
+ <View style={[styles.corner, styles.cornerTL]} />
313
+ <View style={[styles.corner, styles.cornerTR]} />
314
+ <View style={[styles.corner, styles.cornerBL]} />
315
+ <View style={[styles.corner, styles.cornerBR]} />
316
+ {focusPoint && (
317
+ <View
318
+ pointerEvents="none"
400
319
  style={[
401
- {
402
- width: 48,
403
- height: 48,
404
- zIndex: 1000,
405
- position: 'absolute',
406
- left: 16,
407
- top: 16,
408
- },
320
+ styles.focusRing,
321
+ { left: focusPoint.x - 32, top: focusPoint.y - 32 },
409
322
  ]}
410
- >
411
- <IconBackWhite />
412
- </MButton>
413
- <View style={{ flex: 1, alignItems: 'center' }}>
414
- <MText style={$title}>ĐĂNG KÝ XE</MText>
415
- </View>
416
- </View>
417
- <MText
418
- style={{
419
- color: 'white',
420
- textAlign: 'center',
421
- }}
422
- >
423
- {title}
424
- </MText>
323
+ />
324
+ )}
425
325
  </View>
426
- </View>
427
- ) : (
428
- <View></View>
429
- )}
326
+
327
+ <View style={styles.spacer} />
328
+ <MText style={[styles.hint, { marginTop: 0, marginBottom: 20 }]}>
329
+ Đưa giấy tờ lại gần cho vừa khung, chạm vào màn hình{'\n'}để lấy nét
330
+ nếu ảnh bị mờ.
331
+ </MText>
332
+ <TouchableOpacity
333
+ style={[styles.captureButton, { marginBottom: insets.bottom + 24 }]}
334
+ onPress={takePhoto}
335
+ disabled={taking}
336
+ >
337
+ <TakePhotoSvg />
338
+ </TouchableOpacity>
339
+ </>
340
+ ) : null}
341
+
430
342
  <Modal
431
343
  isVisible={showModal}
432
344
  style={$modal}
@@ -551,58 +463,88 @@ export default function VehicleCamera(props: any) {
551
463
  );
552
464
  }
553
465
 
554
- const CORNER_SIZE = 20;
555
- const CORNER_WIDTH = 2;
556
- const BORDER_COLOR = '#FDFDFD';
557
-
558
- const Corner = ({ style }: { style: ViewStyle }) => (
559
- <View
560
- style={[
561
- style,
562
- {
563
- position: 'absolute',
564
- width: CORNER_SIZE,
565
- height: CORNER_SIZE,
566
- },
567
- ]}
568
- />
569
- );
570
-
571
- const overlayColor = 'rgba(22, 22, 22, 0.7)';
572
-
573
- const $overlay: ViewStyle = {
574
- ...StyleSheet.absoluteFillObject,
575
- justifyContent: 'center',
576
- alignItems: 'center',
577
- };
578
-
579
- const $darkOverlayTop: ViewStyle = {
580
- width: '100%',
581
- flex: 1,
582
- backgroundColor: overlayColor,
583
- };
584
-
585
- const $darkOverlayBottom: ViewStyle = {
586
- width: '100%',
587
- flex: 1,
588
- backgroundColor: overlayColor,
589
- };
590
- const $darkOverlaySide: ViewStyle = {
591
- flex: 1,
592
- height: frameHeight,
593
- backgroundColor: overlayColor,
594
- };
595
- const $frameBorder: ViewStyle = {
596
- width: frameWidth,
597
- height: frameHeight,
598
- };
599
-
600
- const $overlayRow: ViewStyle = {
601
- width: '100%',
602
- height: frameHeight,
603
- flexDirection: 'row',
604
- alignItems: 'center',
605
- };
466
+ const styles = StyleSheet.create({
467
+ container: { flex: 1, backgroundColor: '#FFFFFF' },
468
+ header: {
469
+ flexDirection: 'row',
470
+ alignItems: 'center',
471
+ paddingHorizontal: 16,
472
+ paddingTop: 8,
473
+ },
474
+ titleWrap: {
475
+ flex: 1,
476
+ alignItems: 'center',
477
+ justifyContent: 'center',
478
+ marginRight: 24,
479
+ },
480
+ headerTitle: { color: '#333333', fontSize: 16, fontWeight: '600' },
481
+ instruction: {
482
+ textAlign: 'center',
483
+ color: '#333333',
484
+ fontSize: 14,
485
+ lineHeight: 20,
486
+ marginTop: 20,
487
+ marginBottom: 28,
488
+ },
489
+ photoFrame: {
490
+ marginHorizontal: 24,
491
+ aspectRatio: CARD_ASPECT_RATIO,
492
+ borderRadius: 8,
493
+ overflow: 'hidden',
494
+ backgroundColor: '#000000',
495
+ },
496
+ corner: {
497
+ position: 'absolute',
498
+ width: 26,
499
+ height: 26,
500
+ borderColor: ORANGE,
501
+ },
502
+ focusRing: {
503
+ position: 'absolute',
504
+ width: 64,
505
+ height: 64,
506
+ borderRadius: 8,
507
+ borderWidth: 1.5,
508
+ borderColor: '#FFD54A',
509
+ },
510
+ cornerTL: {
511
+ top: 0,
512
+ left: 0,
513
+ borderTopWidth: 4,
514
+ borderLeftWidth: 4,
515
+ borderTopLeftRadius: 8,
516
+ },
517
+ cornerTR: {
518
+ top: 0,
519
+ right: 0,
520
+ borderTopWidth: 4,
521
+ borderRightWidth: 4,
522
+ borderTopRightRadius: 8,
523
+ },
524
+ cornerBL: {
525
+ bottom: 0,
526
+ left: 0,
527
+ borderBottomWidth: 4,
528
+ borderLeftWidth: 4,
529
+ borderBottomLeftRadius: 8,
530
+ },
531
+ cornerBR: {
532
+ bottom: 0,
533
+ right: 0,
534
+ borderBottomWidth: 4,
535
+ borderRightWidth: 4,
536
+ borderBottomRightRadius: 8,
537
+ },
538
+ hint: {
539
+ textAlign: 'center',
540
+ color: '#555555',
541
+ fontSize: 13,
542
+ lineHeight: 19,
543
+ marginTop: 48,
544
+ },
545
+ spacer: { flex: 1 },
546
+ captureButton: { alignSelf: 'center' },
547
+ });
606
548
 
607
549
  const $row: ViewStyle = {
608
550
  flexDirection: 'row',
@@ -651,10 +593,6 @@ const $description: TextStyle = {
651
593
  textAlign: 'center',
652
594
  };
653
595
 
654
- const $flex: ViewStyle = {
655
- flex: 1,
656
- };
657
-
658
596
  const $modal: ViewStyle = {
659
597
  justifyContent: 'flex-end',
660
598
  margin: 0,