diff --git a/android/key.properties b/android/key.properties
index 6a8cd33e..ef160512 100644
--- a/android/key.properties
+++ b/android/key.properties
@@ -1,4 +1,5 @@
storePassword=Cloud@AtomsSA
keyPassword=Cloud@AtomsSA
keyAlias=playstore
-storeFile=/Users/sikandersaleem/StudioProjects/cloudsolutions-atoms/android/AtomsSA-playStore.jks
+#storeFile=/Users/sikandersaleem/StudioProjects/cloudsolutions-atoms/android/AtomsSA-playStore.jks
+storeFile=/Users/waseem/CsProjects/android/AtomsSA-playStore.jks
diff --git a/assets/audio/success_tone_android.mp3 b/assets/audio/success_tone_android.mp3
new file mode 100644
index 00000000..b8ad93f9
Binary files /dev/null and b/assets/audio/success_tone_android.mp3 differ
diff --git a/assets/audio/success_tone_ios.caf b/assets/audio/success_tone_ios.caf
new file mode 100644
index 00000000..f2bcbaf6
Binary files /dev/null and b/assets/audio/success_tone_ios.caf differ
diff --git a/assets/images/ic_done.png b/assets/images/ic_done.png
new file mode 100644
index 00000000..5b802855
Binary files /dev/null and b/assets/images/ic_done.png differ
diff --git a/assets/images/ic_nfc.png b/assets/images/ic_nfc.png
new file mode 100644
index 00000000..274e1b8c
Binary files /dev/null and b/assets/images/ic_nfc.png differ
diff --git a/assets/images/nfc_icon.svg b/assets/images/nfc_icon.svg
new file mode 100644
index 00000000..11e61f7c
--- /dev/null
+++ b/assets/images/nfc_icon.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/images/success_swipe.svg b/assets/images/success_swipe.svg
new file mode 100644
index 00000000..499c58c7
--- /dev/null
+++ b/assets/images/success_swipe.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/images/swipe.svg b/assets/images/swipe.svg
new file mode 100644
index 00000000..d389f93a
--- /dev/null
+++ b/assets/images/swipe.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/images/swipe_success.svg b/assets/images/swipe_success.svg
new file mode 100644
index 00000000..68021f2e
--- /dev/null
+++ b/assets/images/swipe_success.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/images/wifi_icon.svg b/assets/images/wifi_icon.svg
new file mode 100644
index 00000000..645396d9
--- /dev/null
+++ b/assets/images/wifi_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/lottie/done.json b/assets/lottie/done.json
new file mode 100644
index 00000000..02ca04d4
--- /dev/null
+++ b/assets/lottie/done.json
@@ -0,0 +1 @@
+{"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":29.9700012207031,"ip":0,"op":60.0000024438501,"w":500,"h":500,"nm":"Comp 2","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[188]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[-84.167,-170.667,0],"ti":[-134.833,-161.333,0]},{"t":39.0000015885026,"s":[672,243,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[40,40,100],"ix":6}},"ao":0,"shapes":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":50,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":100,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.96862745285,0.807843148708,0.082352943718,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[273]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[183.833,67.333,0],"ti":[27.167,-153.333,0]},{"t":39.0000015885026,"s":[579,742,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[40,40,100],"ix":6}},"ao":0,"shapes":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":50,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":100,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.96862745285,0.807843148708,0.082352943718,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[-292]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[1.833,-220.667,0],"ti":[85.167,-23.333,0]},{"t":39.0000015885026,"s":[71,152,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[40,40,100],"ix":6}},"ao":0,"shapes":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":50,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":100,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.96862745285,0.807843148708,0.082352943718,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 9","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[264]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[31.833,-98.667,0],"ti":[83.167,-235.333,0]},{"t":39.0000015885026,"s":[661,546,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,40],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.152941176471,0.682352941176,0.376470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 8","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[264]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[165.833,-82.667,0],"ti":[301.167,-47.333,0]},{"t":39.0000015885026,"s":[249,72,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,40],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.152941176471,0.682352941176,0.376470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 7","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[-249]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[-190.167,-64.667,0],"ti":[-230.833,-141.333,0]},{"t":39.0000015885026,"s":[277,728,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,40],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.152941176471,0.682352941176,0.376470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 12","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[-249]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[11.833,-130.667,0],"ti":[89.167,-117.333,0]},{"t":39.0000015885026,"s":[207,340,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.023529411765,0.458823529412,0.733333333333,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 11","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[264]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[29.833,131.333,0],"ti":[127.167,80.667,0]},{"t":39.0000015885026,"s":[531,332,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.023529411765,0.458823529412,0.733333333333,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 10","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[264]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[81.833,71.333,0],"ti":[97.167,80.667,0]},{"t":39.0000015885026,"s":[259,534,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.023529411765,0.458823529412,0.733333333333,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 6","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[264]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[149.833,41.333,0],"ti":[143.167,-43.333,0]},{"t":39.0000015885026,"s":[407,682,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.117647059262,0.690196096897,0.901960790157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[264]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[187.833,-16.667,0],"ti":[207.167,58.667,0]},{"t":39.0000015885026,"s":[413,164,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.117647059262,0.690196096897,0.901960790157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[1],"y":[1]},"o":{"x":[0.01],"y":[0]},"t":0,"s":[100]},{"t":39.0000015885026,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":39.0000015885026,"s":[-249]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.01,"y":0},"t":0,"s":[400,400,0],"to":[-110.167,-134.667,0],"ti":[-14.833,-199.333,0]},{"t":39.0000015885026,"s":[91,556,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.117647059262,0.690196096897,0.901960790157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"done button Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[-33]},{"t":15.0000006109625,"s":[0]}],"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":10,"s":[100,100,100]},{"t":15.0000006109625,"s":[75,75,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.694,-1.67],[15.064,2.812],[8.969,5.292],[0,0],[-7.438,7.439],[0,0]],"o":[[-13.577,6.137],[-10.287,-1.92],[0,0],[7.438,7.439],[0,0],[-3.486,2.006]],"v":[[30.437,-12.293],[-13.069,-3.639],[-41.19,-16.698],[-14.093,10.398],[12.954,10.398],[41.19,-17.837]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827000038297,0.917999985639,0.851000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[229.522,306.324],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.391,-4.208],[0,0],[7.482,-5.727]],"o":[[0,0],[-6.835,-6.835],[10.243,0.324]],"v":[[15.056,6.169],[10.072,1.185],[-15.056,-0.442]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[191.834,247.92],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-16.443,-1.661],[-0.313,0.336],[1.295,0.958],[6.404,-6.405],[0,0]],"o":[[0.327,-0.317],[-0.973,-1.171],[-7.283,-5.386],[0,0],[13.474,-9.127]],"v":[[22.713,-3.631],[23.676,-4.605],[20.288,-7.821],[-4.854,-5.613],[-23.676,13.208]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[314.643,200.928],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.588,7.091],[6.406,-6.405],[0,0],[1.994,1.993],[0,0],[7.438,-7.438],[-7.438,-7.437],[0,0],[-7.438,7.438],[0,0]],"o":[[-7.282,-5.386],[0,0],[-1.994,1.993],[0,0],[-7.439,-7.438],[-7.438,7.438],[0,0],[7.438,7.438],[0,0],[8.113,-8.114]],"v":[[78.594,-62.834],[53.45,-60.625],[-23.775,16.601],[-30.995,16.601],[-54.432,-6.836],[-81.48,-6.836],[-81.48,20.21],[-40.909,60.782],[-13.862,60.782],[80.805,-33.884]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941000007181,0.969000004787,0.948999980852,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256.338,255.941],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256],"ix":2},"a":{"a":0,"k":[256,256],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[110,110]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[110,110]},{"t":35.0000014255792,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.133,5.479],[-1.358,9.199],[-7.938,12.606],[-53.77,-6.535],[-7.744,-1.454],[29.459,0],[0,-66.275],[-6.771,-15.025]],"o":[[-0.227,-9.304],[2.172,-14.72],[30.259,-48.052],[7.867,0.956],[-20.883,-17.615],[-66.275,0],[0,17.549],[-0.723,-5.424]],"v":[[-89.563,68.28],[-87.253,40.663],[-71.874,-1.463],[75.237,-59.898],[98.656,-56.382],[21.344,-84.619],[-98.656,35.381],[-88.109,84.619]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.231000010173,0.736999990426,0.411999990426,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[234.657,220.62],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-41.145],[41.146,0],[0,41.146],[-41.145,0]],"o":[[0,41.146],[-41.145,0],[0,-41.145],[41.146,0]],"v":[[74.5,0],[0,74.5],[-74.5,0],[0,-74.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.149000010771,0.638999968884,0.344999994016,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[277.5,292.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-66.274],[66.274,0],[0,66.274],[-66.274,0]],"o":[[0,66.274],[-66.274,0],[0,-66.274],[66.274,0]],"v":[[120,0],[0,120],[-120,0],[0,-120]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.152999997606,0.681999954523,0.375999989229,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256],"ix":2},"a":{"a":0,"k":[256,256],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Comp 3","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[400,400,0],"ix":1},"s":{"a":0,"k":[61,61,100],"ix":6}},"ao":0,"w":800,"h":800,"ip":5.00000020365417,"op":155.000006313279,"st":5.00000020365417,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Comp 3","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[400,400,0],"ix":1},"s":{"a":0,"k":[61,61,100],"ix":6}},"ao":0,"w":800,"h":800,"ip":0,"op":150.000006109625,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/lib/controllers/api_routes/api_manager.dart b/lib/controllers/api_routes/api_manager.dart
index e8464923..70ddece5 100644
--- a/lib/controllers/api_routes/api_manager.dart
+++ b/lib/controllers/api_routes/api_manager.dart
@@ -91,6 +91,37 @@ class ApiManager {
return response;
}
+ Future postWithOutBody(String url, {Map headers}) async {
+ headers ??= {};
+
+ headers.addAll(_headers);
+
+ Uri _url = Uri.parse(url);
+ if (!kReleaseMode) {
+ print("URL:$_url");
+ print("Headers:$headers");
+ }
+
+ var request = http.Request('POST', _url);
+ request.headers.addAll(headers);
+
+ http.StreamedResponse _streamedResponse = await request.send();
+ http.Response response = await http.Response.fromStream(_streamedResponse);
+ try {
+ if (response.statusCode == 401) {
+ showLoginDialog();
+ } else {
+ if (jsonDecode(response.body) is Map) {
+ final message = jsonDecode(response.body)["message"];
+ if (message != null && message.toString().isNotEmpty) {
+ Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG);
+ }
+ }
+ }
+ } catch (ex) {}
+
+ return response;
+ }
Future put(
String url, {
diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart
index 7964ce5e..4d101273 100644
--- a/lib/controllers/api_routes/urls.dart
+++ b/lib/controllers/api_routes/urls.dart
@@ -32,6 +32,14 @@ class URLs {
static get getAssetById => "$_baseUrl/Asset/GetAssetById?assetId="; // get
static get getModels => "$_baseUrl/ModelDefinition/GetModelDefinitionAsset"; // get ?client=2
+ //Reset Password Apis...
+ static get sendForgetPasswordOtp => "$_baseUrl/Account/SendForgotPasswordOtp"; // send OTP.
+ static get sendForgetPasswordValidateOtp => "$_baseUrl/Account/SendForgotPasswordValidateOtp"; // validate OTP.
+ static get updateNewPassword => "$_baseUrl/Account/UpdatenewPassword"; // validate OTP.
+ //Swipe module Api..
+ static get swipeUrl=> '$_baseUrl/Swipe/Swipe';
+ static get getSwipeLastTransactionUrl=> '$_baseUrl/Swipe/GetLastTransaction';
+
static get getAllRequestsAndCount => "$_baseUrl/CallRequest/GetAllRequestsAndCount"; // get
// 08051
static get getServiceRequests => "$_baseUrl/CallRequest/GetCallRequests"; // get
diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart
index 6fe00e30..c28e43b9 100644
--- a/lib/controllers/providers/api/user_provider.dart
+++ b/lib/controllers/providers/api/user_provider.dart
@@ -5,7 +5,12 @@ import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/new_views/forget_password_module/models/general_response_model.dart';
+import 'package:test_sa/new_views/swipe_module/models/swipe_model.dart';
+import 'package:test_sa/new_views/forget_password_module/models/update_password.dart';
+import 'package:test_sa/new_views/forget_password_module/models/verify_otp_model.dart';
import 'package:test_sa/models/user.dart';
+import 'package:test_sa/new_views/swipe_module/models/swipe_transaction_model.dart';
import '../../../new_views/common_widgets/app_lazy_loading.dart';
@@ -15,6 +20,8 @@ class UserProvider extends ChangeNotifier {
_user = null;
ApiManager.instance.user = user;
_loading = false;
+ isUserConfirmSwipe = false;
+ swipeTransactionModel = null;
}
// contain user data
@@ -22,9 +29,21 @@ class UserProvider extends ChangeNotifier {
User _user;
User get user => _user;
+ String _newPassword;
+
+ String get newPassword => _newPassword;
+
+ set newPassword(String value) {
+ _newPassword = value;
+ notifyListeners();
+ }
+
+ String _confirmPassword;
File profileImage;
+ bool isUserConfirmSwipe = false;
+
set user(User user) {
_user = user;
ApiManager.instance.user = user;
@@ -34,6 +53,23 @@ class UserProvider extends ChangeNotifier {
// when login or register in-process _login = true
// when login or register is done or not start = false
bool _loading = false;
+ VerifyOtpModel _verifyOtpModel;
+ SwipeTransaction _swipeTransactionModel=SwipeTransaction();
+
+
+ SwipeTransaction get swipeTransactionModel => _swipeTransactionModel;
+
+ set swipeTransactionModel(SwipeTransaction value) {
+ _swipeTransactionModel = value;
+ notifyListeners();
+ }
+
+ VerifyOtpModel get verifyOtpModel => _verifyOtpModel;
+
+ set verifyOtpModel(VerifyOtpModel value) {
+ _verifyOtpModel = value;
+ notifyListeners();
+ }
bool get isLoading => _loading;
@@ -141,6 +177,157 @@ class UserProvider extends ChangeNotifier {
return -1;
}
}
+//this need to be in seprate provider but for now place here...
+ Future makeSwipe({@required Swipe model}) async {
+ isLoading = true;
+ SwipeModel swipeResponse = SwipeModel(data: false, message: '', responseCode: 0, isSuccess: false);
+ notifyListeners();
+ Response response;
+ try {
+ response = await ApiManager.instance.post(URLs.swipeUrl, body: model.toJson());
+ swipeResponse = SwipeModel.fromJson(json.decode(response.body));
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ isUserConfirmSwipe = true;
+ await getSwipeLastTransaction(userId: user.userID);
+ notifyListeners();
+ }
+
+ notifyListeners();
+ return swipeResponse;
+ } catch (error) {
+ notifyListeners();
+ return swipeResponse;
+ }
+ }
+
+ Future getSwipeLastTransaction({@required String userId}) async {
+ isLoading = true;
+ notifyListeners();
+ Response response;
+ var body = {
+ "userId": userId,
+ };
+ try {
+ response = await ApiManager.instance.post(URLs.getSwipeLastTransactionUrl, body: body);
+
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ swipeTransactionModel = SwipeTransaction.fromJson(json.decode(response.body)['data']);
+ }
+ notifyListeners();
+ return response.statusCode;
+ } catch (error) {
+ notifyListeners();
+ return -1;
+ }
+ }
+
+ Future sendForgetPasswordOtp({@required BuildContext context, @required String employeeId}) async {
+ GeneralResponseModel generalResponseModel= GeneralResponseModel(responseCode: -1) ;
+ if (_loading == true) return generalResponseModel;
+ _loading = true;
+ notifyListeners();
+ Response response;
+ try {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ response = await ApiManager.instance.postWithOutBody(
+ URLs.sendForgetPasswordOtp + '?employeeId=$employeeId',
+ );
+ generalResponseModel = GeneralResponseModel.fromJson(json.decode(response.body));
+ print('data i got is ${generalResponseModel.data}');
+ _loading = false;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ notifyListeners();
+ Navigator.pop(context);
+ return generalResponseModel;
+ }
+ notifyListeners();
+ Navigator.pop(context);
+ return generalResponseModel;
+ } catch (error) {
+ // debugPrint(error);
+ Navigator.pop(context);
+ _loading = false;
+ notifyListeners();
+ return generalResponseModel;
+ }
+ }
+
+
+ Future forgetPasswordValidateOtp({@required BuildContext context, @required String employeeId, @required String otp}) async {
+ print('payload i got is ${employeeId} code ${otp}');
+ GeneralResponseModel generalResponseModel= GeneralResponseModel(responseCode: -1) ;
+ // if (_loading == true) return generalResponseModel;
+ _loading = true;
+ notifyListeners();
+ Response response;
+ try {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ response = await ApiManager.instance.postWithOutBody(
+ URLs.sendForgetPasswordValidateOtp + '?employeeId=$employeeId&otp=$otp',
+ );
+ generalResponseModel = GeneralResponseModel.fromJson(json.decode(response.body));
+ print('response model i got is ${generalResponseModel.data}');
+ _loading = false;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ print('i got status ${response.statusCode}');
+ if(generalResponseModel.data!=null){
+ print('inside data not null ${generalResponseModel.data}');
+ verifyOtpModel = VerifyOtpModel.fromJson(generalResponseModel.data);
+ }
+ notifyListeners();
+ Navigator.pop(context);
+ return generalResponseModel;
+ }
+ notifyListeners();
+ Navigator.pop(context);
+ return generalResponseModel;
+ } catch (error) {
+ // debugPrint(error);
+ Navigator.pop(context);
+ _loading = false;
+ notifyListeners();
+ return generalResponseModel;
+ }
+ }
+
+ Future updateNewPassword({@required BuildContext context,UpdatePasswordModel updatePasswordModel}) async {
+ GeneralResponseModel generalResponseModel= GeneralResponseModel(responseCode: -1) ;
+ if (_loading == true) return generalResponseModel;
+ _loading = true;
+ notifyListeners();
+ Response response;
+ try {
+
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ response = await ApiManager.instance.post(
+ URLs.updateNewPassword,
+ body:updatePasswordModel.toJson()
+ );
+ generalResponseModel = GeneralResponseModel.fromJson(json.decode(response.body));
+ _loading = false;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ notifyListeners();
+ Navigator.pop(context);
+ return generalResponseModel;
+ }
+ notifyListeners();
+ Navigator.pop(context);
+ return generalResponseModel;
+ } catch (error) {
+ // debugPrint(error);
+ Navigator.pop(context);
+ _loading = false;
+ notifyListeners();
+ return generalResponseModel;
+ }
+ }
+
+ String get confirmPassword => _confirmPassword;
+
+ set confirmPassword(String value) {
+ _confirmPassword = value;
+ notifyListeners();
+ }
// Future updateProfile({
// @required String host,
diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb
index 33f48a18..5e795e77 100644
--- a/lib/l10n/app_ar.arb
+++ b/lib/l10n/app_ar.arb
@@ -8,12 +8,22 @@
"confirm": "تاكيد",
"done": "تم",
"exit": "إغلاق",
+ "newPassword": "كلمة المرور الجديدة",
+ "otpVerification": "التحقق من OTP",
+ "pleaseEnterTheOtpSentTo": "يرجى إدخال OTP المرسل إلى",
+ "resetPassword": "إعادة تعيين كلمة المرور",
+ "pleaseEnterTheNewPassword": "يرجى إدخال كلمة المرور الجديدة",
+ "verify": "تحقق",
+ "employeeIdIsRequired": "رقم الموظف مطلوب",
"exitAlert": "هل انت متاكد من رغبتك في إغلاق التطبيق؟",
"signOut": "تسجيل الخروج",
"logoutAlert": "هل انت متاكد من رغبتك في تسجيل الخروج؟",
"language": "اللغة",
"name": "الاسم",
"email": "البريد الالكتروني",
+ "checkIn": "تسجيل الدخول",
+ "markAttendance": "تسجيل الحضور",
+ "selectMethodToMarkAttendance": "اختر الطريقة لتسجيل الحضور",
"phoneNumber": "رقم الهاتف",
"password": "كلمة المرور",
"confirmPassword": "تاكيد كلمة المرور",
@@ -29,6 +39,8 @@
"termsAndConditionsValidateMessage": "موافقة علي الشروط والاحكام مطاوبة",
"update": "تحديث",
"step": "خطوة",
+ "successful": "ناجح",
+ "youHaveSuccessfullyMarkedYourAttendance": "لقد قمت بتسجيل حضورك بنجاح",
"forgetPasswordWithMark": "نسيت كلمة المرور؟",
"showPassword": "اظهار كلمة المرور",
"wrongEmailOrPassword": "البريد الالكتروني او كلمة المرور غير صحيح",
@@ -196,6 +208,7 @@
"comment": "تعليق",
"updateServiceRequest": "تعديل طلب الخدمة",
"repairLocation": "موقع الإصلاح",
+
"travelingExpense": "مصاريف التنقل",
"startDate": "وقت البدء",
"requestedQuantity": "الكمية المطلوبة",
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index 2c157481..fda46544 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -6,8 +6,20 @@
"requestLockMessage": "Wait until your request complete",
"cancel": "Cancel",
"confirm": "Confirm",
+ "newPassword": "New Password",
+ "resetPassword": "Reset Password",
+ "otpVerification": "OTP Verification",
+ "pleaseEnterTheOtpSentTo": "Please enter the OTP sent to",
+ "pleaseEnterTheNewPassword": "Please enter the new password",
+ "markAttendance": "Mark Attendance",
+ "selectMethodToMarkAttendance": "Select the method to mark the attendance",
+ "verify": "Verify",
+ "employeeIdIsRequired": "Employee Id is required",
+ "successful": "Successful",
+ "youHaveSuccessfullyMarkedYourAttendance": "You have successfully marked your attendance",
"done": "Done",
"exit": "Exit",
+ "checkIn": "Check in",
"exitAlert": "Are you sure you want to exit?",
"signOut": "Sign Out",
"logoutAlert": "Are you sure you want to Sign Out?",
diff --git a/lib/main.dart b/lib/main.dart
index 3b3ab99a..93fc94e4 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -50,6 +50,8 @@ import 'package:test_sa/new_views/pages/login_page.dart';
import 'package:test_sa/new_views/pages/report_bug_page.dart';
import 'package:test_sa/new_views/pages/settings_page.dart';
import 'package:test_sa/new_views/pages/splash_page.dart';
+import 'package:test_sa/new_views/pages/usSafeDevice_view.dart';
+import 'package:test_sa/new_views/swipe_module/swipe_success_view.dart';
import 'package:test_sa/providers/asset_transfer/asset_transfer_status_provider.dart';
import 'package:test_sa/providers/department_provider.dart';
import 'package:test_sa/providers/gas_request_providers/cylinder_size_provider.dart';
@@ -255,6 +257,8 @@ class MyApp extends StatelessWidget {
routes: {
SplashPage.routeName: (_) => const SplashPage(),
LoginPage.routeName: (_) => const LoginPage(),
+ UnsafeDeviceScreen.routeName: (_) => const UnsafeDeviceScreen(),
+ SwipeSuccessView.routeName: (_) => const SwipeSuccessView(),
///todo deleted
//old.LandPage.id: (_) => const old.LandPage(),
LandPage.routeName: (_) => const LandPage(),
diff --git a/lib/models/user.dart b/lib/models/user.dart
index 367c05ec..bc2c1c82 100644
--- a/lib/models/user.dart
+++ b/lib/models/user.dart
@@ -3,12 +3,18 @@ import 'dart:io';
import 'package:test_sa/controllers/notification/firebase_notification_manger.dart';
import 'package:test_sa/models/enums/user_types.dart';
+
class User {
int clientId;
String clientName;
List departmentId;
List departmentName;
String message;
+ bool employeeIsHMG;
+ bool enableWifi;
+ bool enableNFC;
+ bool enableQR;
+
String username;
String userID;
String email;
@@ -48,6 +54,10 @@ class User {
this.email,
this.password,
this.token,
+ this.employeeIsHMG,
+ this.enableNFC,
+ this.enableQR,
+ this.enableWifi,
this.roles,
this.userRoles,
this.tokenlife,
@@ -126,6 +136,11 @@ class User {
map['email'] = email;
map['password'] = password;
map['token'] = token;
+
+ map['employeeIsHMG'] = employeeIsHMG;
+ map['enableWifi'] = enableWifi;
+ map['enableNFC'] = enableNFC;
+ map['enableQR'] = enableQR;
map['roles'] = roles;
if (userRoles != null) {
map['userRoles'] = userRoles.map((v) => v.toJson()).toList();
@@ -176,6 +191,10 @@ class User {
email = json['email'];
password = json['password'];
token = json['token'];
+ employeeIsHMG = json['employeeIsHMG'];
+ enableWifi = json['enableWifi'];
+ enableNFC = json['enableNFC'];
+ enableQR = json['enableQR'];
roles = json['roles'];
if (json['userRoles'] != null) {
userRoles = [];
diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart
index 1dbfbc6c..92bfaa11 100644
--- a/lib/new_views/app_style/app_color.dart
+++ b/lib/new_views/app_style/app_color.dart
@@ -19,10 +19,21 @@ class AppColor {
static const Color neutral50 = Color(0xff3B3D4A);
static const Color neutral60 = Color(0xff2C2C31);
static const Color neutral70 = Color(0xff111427);
+ static const Color neutral80 = Color(0xff212936);
+
//background
static const Color backgroundLight = Color(0xffF7F9FB);
+ static const Color white936 = Color(0xffF7F9FB);
+ static const Color white10 = Color(0xffE4E5E6);
+ static const Color white20 = Color(0xff7D859A);
+ static const Color white40 = Color(0xffF1F1F1);
+ static const Color white = Color(0xffFFFFFF);
+
+ //Todo replace with correct colors.
static const Color backgroundDark = Color(0xff111427);
+ static const Color white30 = Color(0xff111427);
+ static const Color black35 = Color(0xff111427);
//red
static const Color red40 = Color(0xffFFDBDC);
diff --git a/lib/new_views/common_widgets/app_bottom_nav_bar.dart b/lib/new_views/common_widgets/app_bottom_nav_bar.dart
index 53d78b9f..9a4af051 100644
--- a/lib/new_views/common_widgets/app_bottom_nav_bar.dart
+++ b/lib/new_views/common_widgets/app_bottom_nav_bar.dart
@@ -16,7 +16,11 @@ class AppBottomNavigationBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
- bool isEngineer = (Provider.of(context, listen: false).user.type) == UsersTypes.engineer;
+ bool isEngineer = false;
+ UserProvider _userProvider = Provider.of(context, listen: false);
+ if(_userProvider.user!=null&&(_userProvider.user.type) == UsersTypes.engineer){
+ isEngineer=true;
+ }
return ClipRRect(
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
child: Container(
diff --git a/lib/new_views/common_widgets/app_text_form_field.dart b/lib/new_views/common_widgets/app_text_form_field.dart
index 3fe19929..dfe82e81 100644
--- a/lib/new_views/common_widgets/app_text_form_field.dart
+++ b/lib/new_views/common_widgets/app_text_form_field.dart
@@ -16,6 +16,7 @@ class AppTextFormField extends StatefulWidget {
final String initialValue;
final TextStyle style;
final bool enable;
+ final bool showBorder;
final TextAlign textAlign;
final FocusNode node;
final Widget suffixIcon;
@@ -39,6 +40,7 @@ class AppTextFormField extends StatefulWidget {
this.onChange,
this.obscureText,
this.showPassword,
+ this.showBorder=false,
this.hintText,
this.labelText,
this.textInputType = TextInputType.text,
@@ -128,6 +130,7 @@ class _AppTextFormFieldState extends State {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
+ border: widget.showBorder?Border.all(color: AppColor.white10,width: 1):null,
boxShadow: widget.showShadow ? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)] : null,
),
child: textField,
diff --git a/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart b/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart
new file mode 100644
index 00000000..7f25d7b0
--- /dev/null
+++ b/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart
@@ -0,0 +1,300 @@
+// import 'package:flutter/material.dart';
+// import 'package:pinput/pinput.dart';
+// import 'package:provider/provider.dart';
+// import 'package:test_sa/controllers/providers/api/user_provider.dart';
+// import 'package:test_sa/extensions/context_extension.dart';
+// import 'package:test_sa/extensions/int_extensions.dart';
+// import 'package:test_sa/extensions/text_extensions.dart';
+// import 'package:test_sa/extensions/widget_extensions.dart';
+// import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+// import 'package:test_sa/new_views/forget_password_module/models/general_response_model.dart';
+// import 'package:test_sa/new_views/app_style/app_color.dart';
+// import 'package:test_sa/new_views/forget_password_module/reset_password_view.dart';
+//
+// class ForgetPasswordVerifyOtpView extends StatelessWidget {
+// static const String routeName = "/verify_otp";
+// String otp = '';
+// ForgetPasswordVerifyOtpView({Key key}) : super(key: key);
+// @override
+// Widget build(BuildContext context) {
+// final defaultPinTheme = PinTheme(
+// width: 68.toScreenWidth,
+// height: 86.toScreenHeight,
+// textStyle: const TextStyle(
+// fontSize: 22,
+// color: Colors.black,
+// ),
+// decoration: BoxDecoration(
+// color: AppColor.white,
+// borderRadius: BorderRadius.circular(15),
+// border: Border.all(color: AppColor.white10, width: 1),
+// ),
+// );
+// return Scaffold(
+// body: Column(
+// children: [
+// SingleChildScrollView(
+// child: Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// mainAxisAlignment: MainAxisAlignment.center,
+// children: [
+// context.translation.otpVerification.heading2(context).custom(color: AppColor.neutral80, fontWeight: FontWeight.w500),
+// 8.height,
+// '${context.translation.pleaseEnterTheOtpSentTo} 8997987979879'.bodyText2(context).custom(color: AppColor.white20, fontWeight: FontWeight.w500),
+// 40.height,
+// Center(
+// child: Pinput(
+// length: 4,
+// defaultPinTheme: defaultPinTheme,
+// focusedPinTheme: defaultPinTheme.copyWith(
+// decoration: defaultPinTheme.decoration?.copyWith(
+// border: Border.all(color: AppColor.white10, width: 1),
+// ),
+// ),
+// onCompleted: (pin) async {
+// otp = pin;
+// },
+// ),
+// ),
+//
+// Row(
+// children: [
+// 'resend'.bodyText2(context).custom(color: AppColor.black35),
+// 7.width,
+// ValueListenableBuilder(
+// //add actual timer value...
+// valueListenable: ValueNotifier("0:00"),
+// builder: (context, value, _) {
+// return Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// mainAxisAlignment: MainAxisAlignment.center,
+// children: [
+// value.bodyText2(context).custom(
+// color: context.isDark ? AppColor.neutral10 : AppColor.neutral10,
+// ),
+// ],
+// );
+// },
+// ),
+// 7.width,
+// InkWell(
+// onTap: () async {
+// UserProvider _userProvider = Provider.of(context, listen: false);
+// String employeeId = '';
+// if (_userProvider.user != null && _userProvider.user.userName != null) {
+// employeeId = _userProvider.user.userName;
+// } else {
+// employeeId = 'OUT3893';
+// }
+// GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(context: context, employeeId: employeeId);
+// // if(response.isSuccess){
+// // Navigator.push(context, MaterialPageRoute(builder: (context)=>ForgetPasswordVerifyOtpView()));
+// // // Navigator.push(context, ForgetPasswordVerifyOtpView.routeName);
+// // }else{
+// // Fluttertoast.showToast(msg: response?.message ?? context.translation.failedToCompleteRequest);
+// // }
+// print('response of send otp i got is ${response.toJson()}');
+// },
+// child: Text(
+// 'resend',
+// style: TextStyle(
+// color: AppColor.primary30,
+// fontWeight: FontWeight.w500,
+// fontSize: 12.toScreenWidth,
+// decorationColor: AppColor.primary30,
+// decoration: TextDecoration.underline,
+// ),
+// ),
+// ),
+// ],
+// ),
+// ],
+// ),
+// ).center.expanded,
+// AppFilledButton(label: context.translation.verify, maxWidth: true, onPressed: () async {
+// if(otp.isNotEmpty){
+// UserProvider _userProvider = Provider.of(context, listen: false);
+// GeneralResponseModel generalResponseModel = await _userProvider.forgetPasswordValidateOtp(context: context, employeeId: 'OUT3893', otp: otp);
+// if (generalResponseModel.isSuccess) {
+// Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ResetPasswordView()));
+// }
+// }
+//
+// }),
+// ],
+// ).paddingOnly(start: 20,end: 20,bottom: 16),
+// );
+// }
+// }
+
+import 'dart:async';
+import 'package:flutter/material.dart';
+import 'package:pinput/pinput.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/providers/api/user_provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/forget_password_module/models/general_response_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/forget_password_module/reset_password_view.dart';
+
+class ForgetPasswordVerifyOtpView extends StatefulWidget {
+ static const String routeName = "/verify_otp";
+ String employeeId = '';
+
+ ForgetPasswordVerifyOtpView({Key key,this.employeeId}) : super(key: key);
+
+ @override
+ State createState() => _ForgetPasswordVerifyOtpViewState();
+}
+
+class _ForgetPasswordVerifyOtpViewState extends State {
+ String otp = '';
+ Timer _timer;
+ int _remainingSeconds = 180; // 3 minutes in seconds
+
+ @override
+ void initState() {
+ super.initState();
+ _startTimer();
+ }
+
+ @override
+ void dispose() {
+ _timer.cancel();
+ super.dispose();
+ }
+
+ void _startTimer() {
+ setState(() {
+ _remainingSeconds = 180;
+ });
+
+ _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
+ if (_remainingSeconds > 0) {
+ setState(() {
+ _remainingSeconds--;
+ });
+ } else {
+ _timer.cancel();
+ }
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final defaultPinTheme = PinTheme(
+ width: 68.toScreenWidth,
+ height: 86.toScreenHeight,
+ textStyle: const TextStyle(
+ fontSize: 22,
+ color: Colors.black,
+ ),
+ decoration: BoxDecoration(
+ color: AppColor.white,
+ borderRadius: BorderRadius.circular(15),
+ border: Border.all(color: AppColor.white10, width: 1),
+ ),
+ );
+
+ final minutes = (_remainingSeconds ~/ 60).toString().padLeft(2, '0');
+ final seconds = (_remainingSeconds % 60).toString().padLeft(2, '0');
+
+ return Scaffold(
+ body: Column(
+ children: [
+ SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ context.translation.otpVerification.heading2(context).custom(color: AppColor.neutral80, fontWeight: FontWeight.w500),
+ 8.height,
+ '${context.translation.pleaseEnterTheOtpSentTo} 8997987979879'.bodyText2(context).custom(color: AppColor.white20, fontWeight: FontWeight.w500),
+ 40.height,
+ Center(
+ child: Pinput(
+ length: 4,
+ defaultPinTheme: defaultPinTheme,
+ focusedPinTheme: defaultPinTheme.copyWith(
+ decoration: defaultPinTheme.decoration?.copyWith(
+ border: Border.all(color: AppColor.white10, width: 1),
+ ),
+ ),
+ onCompleted: (pin) {
+ setState(() {
+ otp = pin;
+ });
+ verifyOtp();
+ },
+ ),
+ ),
+ 18.height,
+ Row(
+ // mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ InkWell(
+ onTap: _remainingSeconds == 0
+ ? () async {
+ UserProvider _userProvider = Provider.of(context, listen: false);
+ String employeeId = widget.employeeId;
+ GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(
+ context: context,
+ employeeId: employeeId,
+ );
+ print('Response of send OTP: ${response.toJson()}');
+
+ // Restart the timer
+ _startTimer();
+ }
+ : null,
+ child: Text(
+ 'Resend',
+ style: TextStyle(
+ color: _remainingSeconds == 0 ? AppColor.primary40 : AppColor.white10,
+ fontWeight: FontWeight.w500,
+ fontSize: 16.toScreenWidth,
+ decorationColor: AppColor.primary30,
+ decoration: _remainingSeconds == 0 ? TextDecoration.underline : null,
+ ),
+ ),
+ ),
+ 7.width,
+ '$minutes:$seconds'.bodyText(context).custom(color: AppColor.neutral10),
+
+
+ ],
+ ),
+ ],
+ ),
+ ).center.expanded,
+ AppFilledButton(
+ label: context.translation.verify,
+ maxWidth: true,
+ onPressed:verifyOtp,
+ ),
+ ],
+ ).paddingOnly(start: 20, end: 20, bottom: 16),
+ );
+ }
+ void verifyOtp() async{
+ if (otp.isNotEmpty) {
+ UserProvider _userProvider = Provider.of(context, listen: false);
+ GeneralResponseModel generalResponseModel = await _userProvider.forgetPasswordValidateOtp(
+ context: context,
+ employeeId:widget.employeeId,
+ otp: otp,
+ );
+ if (generalResponseModel.isSuccess) {
+ Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ResetPasswordView()));
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/lib/new_views/forget_password_module/models/general_response_model.dart b/lib/new_views/forget_password_module/models/general_response_model.dart
new file mode 100644
index 00000000..fbf72fe2
--- /dev/null
+++ b/lib/new_views/forget_password_module/models/general_response_model.dart
@@ -0,0 +1,32 @@
+class GeneralResponseModel {
+ dynamic data;
+ String message;
+ String title;
+ String innerMessage;
+ int responseCode;
+ bool isSuccess;
+
+ GeneralResponseModel({this.data, this.message, this.title, this.innerMessage, this.responseCode, this.isSuccess});
+
+ factory GeneralResponseModel.fromJson(Map json) {
+ return GeneralResponseModel(
+ data: json['data'],
+ message: json['message'] ?? '',
+ title: json['title'],
+ innerMessage: json['innerMessage'],
+ responseCode: json['responseCode'],
+ isSuccess: json['isSuccess'],
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'data': data,
+ 'message': message,
+ 'title': title,
+ 'innerMessage': innerMessage,
+ 'responseCode': responseCode,
+ 'isSuccess': isSuccess,
+ };
+ }
+}
\ No newline at end of file
diff --git a/lib/new_views/forget_password_module/models/update_password.dart b/lib/new_views/forget_password_module/models/update_password.dart
new file mode 100644
index 00000000..808957e0
--- /dev/null
+++ b/lib/new_views/forget_password_module/models/update_password.dart
@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+
+class UpdatePasswordModel {
+ final String password;
+ final String confirmPassword;
+ final String userId;
+ final String token;
+
+ UpdatePasswordModel({
+ @required this.password,
+ @required this.confirmPassword,
+ @required this.userId,
+ @required this.token,
+ });
+
+ Map toJson() {
+ return {
+ 'password': password,
+ 'confirmPassword': confirmPassword,
+ 'userId': userId,
+ 'token': token,
+ };
+ }
+}
diff --git a/lib/new_views/forget_password_module/models/verify_otp_model.dart b/lib/new_views/forget_password_module/models/verify_otp_model.dart
new file mode 100644
index 00000000..a7607336
--- /dev/null
+++ b/lib/new_views/forget_password_module/models/verify_otp_model.dart
@@ -0,0 +1,41 @@
+
+
+import 'package:flutter/material.dart';
+
+class VerifyOtpModel {
+ final String userId;
+ final String userName;
+ final String email;
+ final String token;
+ final DateTime validTo;
+
+ VerifyOtpModel({
+ @required this.userId,
+ @required this.userName,
+ @required this.email,
+ @required this.token,
+ @required this.validTo,
+ });
+
+ // Factory constructor to create an instance from a JSON map
+ factory VerifyOtpModel.fromJson(Map json) {
+ return VerifyOtpModel(
+ userId: json['userId'],
+ userName: json['userName'],
+ email: json['email'],
+ token: json['token'],
+ validTo: DateTime.parse(json['validTo']),
+ );
+ }
+
+ // Convert the instance to a JSON map
+ Map toJson() {
+ return {
+ 'userId': userId,
+ 'userName': userName,
+ 'email': email,
+ 'token': token,
+ 'validTo': validTo.toIso8601String(),
+ };
+ }
+}
diff --git a/lib/new_views/forget_password_module/reset_password_view.dart b/lib/new_views/forget_password_module/reset_password_view.dart
new file mode 100644
index 00000000..68f522c4
--- /dev/null
+++ b/lib/new_views/forget_password_module/reset_password_view.dart
@@ -0,0 +1,148 @@
+import 'package:flutter/material.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/forget_password_module/models/general_response_model.dart';
+import 'package:test_sa/new_views/forget_password_module/models/update_password.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/new_views/pages/login_page.dart';
+import '../../controllers/providers/api/user_provider.dart';
+import '../../controllers/validator/validator.dart';
+
+class ResetPasswordView extends StatefulWidget {
+ static const String routeName = "/resetPassword";
+
+ ResetPasswordView({Key key}) : super(key: key);
+
+ @override
+ State createState() => _ResetPasswordViewState();
+}
+
+class _ResetPasswordViewState extends State {
+ UserProvider _userProvider;
+ bool _passwordVisible =false;
+ bool _confirmPasswordVisible =false;
+
+ final GlobalKey _formKey = GlobalKey();
+
+ @override
+ Widget build(BuildContext context) {
+ _userProvider = Provider.of(context);
+ return Form(
+ key: _formKey,
+ child: Scaffold(
+ body: Column(
+ children: [
+ SingleChildScrollView(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+
+ context.translation.resetPassword.heading2(context).custom(color: AppColor.neutral80, fontWeight: FontWeight.w500),
+ 8.height,
+ context.translation.pleaseEnterTheNewPassword.bodyText2(context).custom(color: AppColor.white20, fontWeight: FontWeight.w500),
+
+ 32.height,
+ AppTextFormField(
+ initialValue: _userProvider.newPassword,
+ showBorder: true,
+ validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField,
+ labelText: context.translation.password,
+ obscureText: !_passwordVisible,
+ suffixIcon: IconButton(
+ icon: Icon(
+ // Based on passwordVisible state choose the icon
+ _passwordVisible
+ ? Icons.visibility
+ : Icons.visibility_off,
+ color: context.isDark ? AppColor.neutral10 : AppColor.neutral20,
+ ),
+ onPressed: () {
+ // Update the state i.e. toogle the state of passwordVisible variable
+ setState(() {
+ _passwordVisible = !_passwordVisible;
+ });
+ },
+ ),
+ onSaved: (value) {
+ _userProvider.newPassword = value;
+ },
+ ),
+ 16.height,
+ AppTextFormField(
+ initialValue: _userProvider.confirmPassword,
+ labelText: context.translation.confirmPassword,
+ obscureText: !_confirmPasswordVisible,
+ showBorder: true,
+ validator: (value) => Validator.isValidPassword(value)
+ ? null
+ : value.isEmpty
+ ? context.translation.requiredField
+ : context.translation.passwordLengthMessage,
+ onSaved: (value) {
+ _userProvider.confirmPassword = value;
+ },
+ suffixIcon: IconButton(
+ icon: Icon(
+ // Based on passwordVisible state choose the icon
+ _confirmPasswordVisible
+ ? Icons.visibility
+ : Icons.visibility_off,
+ color: context.isDark ? AppColor.neutral10 : AppColor.neutral20,
+ ),
+ onPressed: () {
+ // Update the state i.e. toogle the state of passwordVisible variable
+ setState(() {
+ _confirmPasswordVisible = !_confirmPasswordVisible;
+ });
+ },
+ ),
+ ),
+ 138.height,
+ AppFilledButton(label: context.translation.resetPassword, maxWidth: true, onPressed: () => _resetPassword(context: context)),
+ ],
+ ),
+ ).center.expanded,
+
+ ],
+ ).paddingOnly(start: 16, end: 16, bottom: 24, top: 24),
+ ),
+ );
+ }
+
+ Future _resetPassword({BuildContext context}) async {
+ if (!_formKey.currentState.validate()) return;
+ _formKey.currentState.save();
+ if (_userProvider.newPassword != _userProvider.confirmPassword) {
+ Fluttertoast.showToast(msg: 'Password not matched try again');
+ } else {
+ UpdatePasswordModel updatePasswordModel = UpdatePasswordModel(
+ password: _userProvider.newPassword, confirmPassword: _userProvider.confirmPassword, userId: _userProvider.verifyOtpModel.userId, token: _userProvider.verifyOtpModel.token);
+ GeneralResponseModel generalResponseModel = await _userProvider.updateNewPassword(context: context, updatePasswordModel: updatePasswordModel);
+ if (generalResponseModel.isSuccess) {
+ _userProvider.newPassword='';
+ _userProvider.confirmPassword='';
+ Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
+ }
+ }
+
+ // if (status >= 200 && status < 300 && _userProvider.user.isAuthenticated ?? false) {
+ // await _settingProvider.setUser(_userProvider.user);
+ // (await SharedPreferences.getInstance()).remove(ASettings.localAuth);
+ // await _settingProvider.setRememberMe(_user.userName, _user.password, rememberMe);
+ //
+ // /// The below line for the new design
+ // // Navigator.pushNamed(context, LandPage.routeName);
+ // Navigator.pushNamed(context, LandPage.routeName);
+ // } else {
+ // Fluttertoast.showToast(msg: _userProvider.user?.message ?? context.translation.failedToCompleteRequest);
+ // }
+ }
+}
diff --git a/lib/new_views/pages/land_page/land_page.dart b/lib/new_views/pages/land_page/land_page.dart
index 8b3f37d8..51e3a009 100644
--- a/lib/new_views/pages/land_page/land_page.dart
+++ b/lib/new_views/pages/land_page/land_page.dart
@@ -1,6 +1,8 @@
import 'dart:io';
+import 'dart:ui';
import 'package:flutter/material.dart';
+import 'package:nfc_manager/nfc_manager.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
@@ -9,14 +11,17 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/pages/land_page/calendar_page.dart';
import 'package:test_sa/new_views/pages/land_page/my_request/my_requests_page.dart';
+import 'package:test_sa/new_views/swipe_module/mark_attendance_widget.dart';
import 'package:test_sa/new_views/pages/settings_page.dart';
+import 'package:test_sa/new_views/swipe_module/swipe_success_view.dart';
+import 'package:test_sa/new_views/swipe_module/utils/swipe_general_utils.dart';
import 'package:test_sa/views/widgets/equipment/single_device_picker.dart';
-
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../views/widgets/dialogs/dialog.dart';
import '../../common_widgets/app_bottom_nav_bar.dart';
@@ -35,6 +40,7 @@ class LandPage extends StatefulWidget {
class _LandPageState extends State {
final GlobalKey _scaffoldKey = GlobalKey();
+ bool isNfcSupported = false;
int currentPageIndex = 0;
bool showAppbar = true;
List _pages;
@@ -43,6 +49,7 @@ class _LandPageState extends State {
@override
void initState() {
_pages = [];
+
super.initState();
}
@@ -96,10 +103,19 @@ class _LandPageState extends State {
}
}
+ Future checkNfcSupported() async {
+ isNfcSupported = await NfcManager.instance.isAvailable();
+ setState(() {});
+ }
+
@override
Widget build(BuildContext context) {
if (_userProvider == null) {
_userProvider = Provider.of(context, listen: false);
+ // if (_userProvider.isUserConfirmSwipe) {
+ if (!_userProvider.user.employeeIsHMG) {
+ checkNfcSupported();
+ }
_pages = [
DashboardPage(onDrawerPress: (() {
_scaffoldKey.currentState.isDrawerOpen ? _scaffoldKey.currentState.closeDrawer() : _scaffoldKey.currentState.openDrawer();
@@ -109,6 +125,8 @@ class _LandPageState extends State {
const MyAssetsPage(fromBottomBar: true),
if (_userProvider.user.type == UsersTypes.engineer) const CalendarPage(),
];
+
+ // }
checkLocalAuth();
}
@@ -126,39 +144,89 @@ class _LandPageState extends State {
}
return false;
},
- child: Scaffold(
- key: _scaffoldKey,
- drawer: const AppDrawer(),
- body: _pages[currentPageIndex],
- bottomNavigationBar: AppBottomNavigationBar(
- selectedIndex: currentPageIndex,
- onPressed: (index) {
- bool isEngineer = _userProvider.user.type == UsersTypes.engineer;
+ child: Consumer(builder: (context, userProvider, child) {
+ return Stack(
+ children: [
+ Scaffold(
+ key: _scaffoldKey,
+ drawer: const AppDrawer(),
+ body: _pages[currentPageIndex],
+ bottomNavigationBar: AppBottomNavigationBar(
+ selectedIndex: currentPageIndex,
+ onPressed: (index) {
+ bool isEngineer = _userProvider.user.type == UsersTypes.engineer;
- if (index == (isEngineer ? 4 : 3)) {
- showModalBottomSheet(
- context: context,
- useSafeArea: true,
- backgroundColor: Colors.transparent,
- builder: (context) => const ContactUsBottomSheet(),
- );
- } else {
- setState(() {
- currentPageIndex = index;
- });
- if (index == 1) {
- setState(() {
- showAppbar = false;
- });
- } else {
- setState(() {
- showAppbar = true;
- });
- }
- }
- },
- ),
- ),
+ if (index == (isEngineer ? 4 : 3)) {
+ showModalBottomSheet(
+ context: context,
+ useSafeArea: true,
+ backgroundColor: Colors.transparent,
+ builder: (context) => const ContactUsBottomSheet(),
+ );
+ } else {
+ setState(() {
+ currentPageIndex = index;
+ });
+ if (index == 1) {
+ setState(() {
+ showAppbar = false;
+ });
+ } else {
+ setState(() {
+ showAppbar = true;
+ });
+ }
+ }
+ },
+ ),
+ ),
+ Visibility(
+ visible: !userProvider.isUserConfirmSwipe && userProvider.user != null && !userProvider.user.employeeIsHMG,
+ child: BackdropFilter(
+ filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
+ child: Container(
+ color: Colors.black.withOpacity(0.2), // Optional tint effect
+ ),
+ ),
+ ),
+ if (userProvider.user != null && !userProvider.user.employeeIsHMG)
+ Positioned(
+ right:_userProvider.user.type==UsersTypes.engineer? 20.toScreenWidth:null,
+ left:_userProvider.user.type!=UsersTypes.engineer? 20.toScreenWidth:null ,
+ bottom: 130.toScreenHeight,
+ child: GestureDetector(
+ onTap: () {
+ SwipeGeneralUtils.showSwipeTypeBottomSheetSheet(context: context, isNfcSupported: isNfcSupported);
+ },
+ child: CircularAnimationWithProgressIndicator(
+ child: Container(
+ width: 120.toScreenWidth,
+ height: 120.toScreenHeight,
+ decoration: const BoxDecoration(
+ shape: BoxShape.circle,
+ color: AppColor.white,
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ 'swipe'.toSvgAsset(width: 32, height: 32),
+ 8.height,
+ context.translation.checkIn.bodyText(context).custom(color: AppColor.neutral80),
+ 8.height,
+ userProvider.swipeTransactionModel != null && userProvider.swipeTransactionModel.swipeTime != null
+ ? SwipeGeneralUtils.formatTimeOnly(userProvider.swipeTransactionModel.swipeTime).bodyText(context).custom(color: AppColor.neutral80)
+ : '--:--'.bodyText(context).custom(color: AppColor.neutral80),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }),
);
+ // );
}
}
diff --git a/lib/new_views/pages/land_page/nfc/nfc_reader_sheet.dart b/lib/new_views/pages/land_page/nfc/nfc_reader_sheet.dart
new file mode 100644
index 00000000..c6049271
--- /dev/null
+++ b/lib/new_views/pages/land_page/nfc/nfc_reader_sheet.dart
@@ -0,0 +1,203 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:nfc_manager/nfc_manager.dart';
+import 'package:nfc_manager/platform_tags.dart';
+
+void showNfcReader(BuildContext context, { Function(String nfcId) onNcfScan}) {
+ showModalBottomSheet(
+ context: context,
+ enableDrag: false,
+ isDismissible: false,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)),
+ ),
+ backgroundColor: Colors.white,
+ builder: (context) {
+ return NfcLayout(
+ onNcfScan: onNcfScan,
+ );
+ },
+ );
+}
+
+class NfcLayout extends StatefulWidget {
+ Function(String nfcId) onNcfScan;
+
+ NfcLayout({this.onNcfScan});
+
+ @override
+ _NfcLayoutState createState() => _NfcLayoutState();
+}
+
+class _NfcLayoutState extends State {
+ bool _reading = false;
+ Widget mainWidget;
+ String nfcId;
+
+ @override
+ void initState() {
+ super.initState();
+
+ NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
+ var f;
+ if (Platform.isAndroid) {
+ f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
+ } else {
+ f = MifareUltralight(tag: tag, identifier: tag.data["mifare"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
+ }
+ String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join('');
+ nfcId = identifier;
+
+ setState(() {
+ _reading = true;
+ mainWidget = doneNfc();
+ });
+
+ Future.delayed(const Duration(seconds: 1), () {
+ NfcManager.instance.stopSession();
+ Navigator.pop(context);
+ // if (Platform.isAndroid) {
+ // Navigator.pop(context);
+ // } else {
+ // Navigator.pop(context);
+ // Navigator.pop(context);
+ // }
+ widget.onNcfScan(nfcId);
+ });
+ }).catchError((err) {
+ print(err);
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc();
+ return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget);
+ }
+
+ Widget scanNfc() {
+ return Container(
+ key: ValueKey(1),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SizedBox(
+ height: 30,
+ ),
+ const Text(
+ "Ready To Scan",
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 24,
+ ),
+ ),
+ SizedBox(
+ height: 30,
+ ),
+
+ Image.asset(
+ "assets/images/ic_nfc.png",
+ height: MediaQuery.of(context).size.width / 3,
+ width: double.infinity,
+ ),
+ const SizedBox(
+ height: 30,
+ ),
+ const Text(
+ "Approach an NFC Tag",
+ style: TextStyle(
+ fontSize: 18,
+ ),
+ ),
+ const SizedBox(
+ height: 30,
+ ),
+ ButtonTheme(
+ minWidth: MediaQuery.of(context).size.width / 1.2,
+ height: 45.0,
+ buttonColor: Colors.grey[300],
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(6),
+ ),
+ child: TextButton(
+ onPressed: () {
+ NfcManager.instance.stopSession();
+ Navigator.pop(context);
+ },
+ // elevation: 0,
+ child: const Text("CANCEL"),
+ ),
+ ),
+ SizedBox(
+ height: 30,
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget doneNfc() {
+ return Container(
+ key: ValueKey(2),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SizedBox(
+ height: 30,
+ ),
+ Text(
+ "Successfully Scanned",
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 24,
+ ),
+ ),
+ SizedBox(
+ height: 30,
+ ),
+ Image.asset(
+ // "assets/icons/nfc/ic_done.png",
+ "assets/images/ic_done.png",
+ height: MediaQuery.of(context).size.width / 3,
+ width: double.infinity,
+ ),
+ SizedBox(
+ height: 30,
+ ),
+ Text(
+ "Approach an NFC Tag",
+ style: TextStyle(
+ fontSize: 18,
+ ),
+ ),
+ SizedBox(
+ height: 30,
+ ),
+ ButtonTheme(
+ minWidth: MediaQuery.of(context).size.width / 1.2,
+ height: 45.0,
+ buttonColor: Colors.grey[300],
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(6),
+ ),
+ child: TextButton(
+ // onPressed: () {
+ // _stream?.cancel();
+ // widget.onNcfScan(nfcId);
+ // Navigator.pop(context);
+ // },
+ onPressed: null,
+ // elevation: 0,
+ child: Text("DONE"),
+ ),
+ ),
+ SizedBox(
+ height: 30,
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/new_views/pages/land_page/widgets/dialogs/dialog.dart b/lib/new_views/pages/land_page/widgets/dialogs/dialog.dart
new file mode 100644
index 00000000..0832ca24
--- /dev/null
+++ b/lib/new_views/pages/land_page/widgets/dialogs/dialog.dart
@@ -0,0 +1,35 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+
+class AAlertDialog extends StatelessWidget {
+ final String title;
+ final String content;
+
+ const AAlertDialog({Key key, this.title, this.content}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ //
+ return CupertinoAlertDialog(
+ title: title != null ? Text(title) : null,
+ content: content != null ? Text(content) : null,
+ actions: [
+ TextButton(
+ // child: Text(_subtitle.confirm),
+ child: Text(context.translation.confirm),
+ onPressed: () {
+ Navigator.of(context).pop(true);
+ },
+ ),
+ TextButton(
+ // child: Text(_subtitle.cancel),
+ child: Text(context.translation.cancel),
+ onPressed: () {
+ Navigator.of(context).pop(false);
+ },
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart
index 578448d0..06ce38b3 100644
--- a/lib/new_views/pages/login_page.dart
+++ b/lib/new_views/pages/login_page.dart
@@ -8,8 +8,10 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/forget_password_module/models/general_response_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/pages/land_page/land_page.dart';
+import 'package:test_sa/new_views/forget_password_module/forget_passwod_verify_otp.dart';
import '../../controllers/providers/api/user_provider.dart';
import '../../controllers/providers/settings/setting_provider.dart';
@@ -29,8 +31,10 @@ class LoginPage extends StatefulWidget {
class _LoginPageState extends State {
final User _user = User();
+ bool _passwordVisible = false;
UserProvider _userProvider;
SettingProvider _settingProvider;
+ TextEditingController userNameController = TextEditingController();
final GlobalKey _formKey = GlobalKey();
bool rememberMe = false;
@@ -50,6 +54,7 @@ class _LoginPageState extends State {
rememberMe = _settingProvider.rememberMe;
if (rememberMe) {
_user.userName = _settingProvider.username;
+ userNameController.text=_user.userName??'';
_user.password = _settingProvider.password;
}
}
@@ -71,6 +76,7 @@ class _LoginPageState extends State {
32.height,
AppTextFormField(
initialValue: _user?.userName,
+ controller: userNameController,
validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField,
labelText: context.translation.username,
textInputType: TextInputType.text,
@@ -82,7 +88,22 @@ class _LoginPageState extends State {
AppTextFormField(
initialValue: _user?.password,
labelText: context.translation.password,
- obscureText: true,
+ suffixIcon: IconButton(
+ icon: Icon(
+ // Based on passwordVisible state choose the icon
+ _passwordVisible
+ ? Icons.visibility
+ : Icons.visibility_off,
+ color: context.isDark ? AppColor.neutral10 : AppColor.neutral20,
+ ),
+ onPressed: () {
+ // Update the state i.e. toogle the state of passwordVisible variable
+ setState(() {
+ _passwordVisible = !_passwordVisible;
+ });
+ },
+ ),
+ obscureText: !_passwordVisible,
validator: (value) => Validator.isValidPassword(value)
? null
: value.isEmpty
@@ -110,8 +131,18 @@ class _LoginPageState extends State {
Align(
alignment: AlignmentDirectional.centerEnd,
child: InkWell(
- onTap: () {
- /// TODO [zaid] : push to another screen
+ onTap: () async {
+ if(userNameController.text.isNotEmpty){
+ GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(context: context, employeeId: userNameController.text);
+ if(response.isSuccess){
+ Navigator.push(context, MaterialPageRoute(builder: (context)=>ForgetPasswordVerifyOtpView(employeeId:userNameController.text,)));
+ // Navigator.push(context, ForgetPasswordVerifyOtpView.routeName);
+ }else{
+ Fluttertoast.showToast(msg: response?.message ?? context.translation.failedToCompleteRequest);
+ }
+ }else{
+ Fluttertoast.showToast(msg: context.translation.employeeIdIsRequired);
+ }
},
child: context.translation.forgotPassword.bodyText(context).custom(color: AppColor.primary50, fontWeight: FontWeight.w500),
),
diff --git a/lib/new_views/pages/splash_page.dart b/lib/new_views/pages/splash_page.dart
index 9b5d0e36..11769f54 100644
--- a/lib/new_views/pages/splash_page.dart
+++ b/lib/new_views/pages/splash_page.dart
@@ -10,7 +10,8 @@ import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/new_views/pages/land_page/land_page.dart';
import 'package:test_sa/new_views/pages/login_page.dart';
-
+import 'package:safe_device/safe_device.dart';
+import 'package:test_sa/new_views/pages/usSafeDevice_view.dart';
import '../../models/size_config.dart';
class SplashPage extends StatefulWidget {
@@ -105,10 +106,17 @@ class _SplashPageState extends State {
fit: BoxFit.contain,
animation: "splash",
callback: (animation) async {
- if (_settingProvider.isLoaded && (_settingProvider.user != null)) {
- checkTokenValidity(_settingProvider.user.token);
- } else {
- Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
+ bool isSafe = await checkDeviceSafety();
+ print('is safe is ${isSafe}');
+ if(!isSafe){
+ Navigator.pushNamedAndRemoveUntil(context,UnsafeDeviceScreen.routeName, (_) => false);
+ }else{
+ if (_settingProvider.isLoaded && (_settingProvider.user != null)) {
+ checkTokenValidity(_settingProvider.user.token);
+ } else {
+ Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
+ }
+
}
// if (_settingProvider.isLoaded && (_settingProvider.user?.isLiveToken ?? false)) {
@@ -129,4 +137,28 @@ class _SplashPageState extends State {
),
);
}
+ Future checkDeviceSafety() async {
+ bool isOnExternalStorage=false;
+ bool isDevelopmentModeEnable=false;
+ bool isJailBroken=false;
+ bool isRealDevice=false;
+
+ try {
+ isJailBroken = await SafeDevice.isJailBroken;
+ isRealDevice = await SafeDevice.isRealDevice;
+ if (Platform.isAndroid) {
+ isOnExternalStorage = await SafeDevice.isOnExternalStorage;
+ isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable;
+ }
+ //TODO correct isDevelopmentModeEnable when publish to prod...
+ if (isJailBroken || !isRealDevice || isOnExternalStorage || !isDevelopmentModeEnable) {
+ return false;
+ }else{
+ return true;
+ }
+ } catch (error) {
+ print(error);
+ return false;
+ }
+}
}
diff --git a/lib/new_views/pages/usSafeDevice_view.dart b/lib/new_views/pages/usSafeDevice_view.dart
new file mode 100644
index 00000000..110eed72
--- /dev/null
+++ b/lib/new_views/pages/usSafeDevice_view.dart
@@ -0,0 +1,80 @@
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+
+class UnsafeDeviceScreen extends StatefulWidget {
+ const UnsafeDeviceScreen({Key key}) : super(key: key);
+ static const String routeName = "/unSafeDevice";
+
+
+ @override
+ State createState() => _UnsafeDeviceScreenState();
+}
+
+class _UnsafeDeviceScreenState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: SafeArea(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ 21.height,
+ // Center(child: Image.asset("assets/images/logos/main_mohemm_logo.png", width: 200, height: 50)),
+ "logo".toSvgAsset(height: 64),
+ 50.height,
+ "Sorry".heading5(context),
+ 21.height,
+ "You are using Atoms app on an unsafe device. To be able to use the app with all it's features, Please make sure that the below points are considered: "
+ .heading5(context).paddingOnly(start: 20, end: 20),
+ 48.height,
+ passwordConstraintsUI("The device is not jailbroken or rooted.", true).paddingOnly(start: 24, end: 5),
+ 8.height,
+ passwordConstraintsUI("The app is not installed on external storage.", true).paddingOnly(start: 24, end: 5),
+ 8.height,
+ passwordConstraintsUI("Development mode is disabled.", true).paddingOnly(start: 24, end: 5),
+ 21.height,
+ AppFilledButton(label: context.translation.done, maxWidth: true, onPressed: () async {
+ if (Platform.isAndroid) {
+ SystemChannels.platform.invokeMethod('SystemNavigator.pop');
+ } else {
+ // MinimizeApp.minimizeApp();
+ }
+ }).paddingAll(24),
+ // DefaultButton(LocaleKeys.ok.tr(), () async {
+ // if (Platform.isAndroid) {
+ // SystemChannels.platform.invokeMethod('SystemNavigator.pop');
+ // } else {
+ // // MinimizeApp.minimizeApp();
+ // }
+ // })
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget passwordConstraintsUI(String description, bool check) {
+ return Row(
+ children: [
+ 4.width,
+ SizedBox(
+ width: 12,
+ height: 12,
+ child: Checkbox(fillColor: MaterialStateProperty.all(AppColor.backgroundDark), shape: const CircleBorder(), value: check, onChanged: null),
+ ),
+ 8.width,
+ description.heading6(context)
+ ],
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/new_views/swipe_module/dialoge/confirm_dialog.dart b/lib/new_views/swipe_module/dialoge/confirm_dialog.dart
new file mode 100644
index 00000000..f586e36c
--- /dev/null
+++ b/lib/new_views/swipe_module/dialoge/confirm_dialog.dart
@@ -0,0 +1,62 @@
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+
+class ConfirmDialog extends StatelessWidget {
+ final String title;
+ final String message;
+ final String okTitle;
+ final VoidCallback onTap;
+ final VoidCallback onCloseTap;
+
+ const ConfirmDialog({Key key, this.title, this.message, this.okTitle, this.onTap, this.onCloseTap}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ print('message i got is $message');
+ return Dialog(
+ backgroundColor: Colors.white,
+ shape: const RoundedRectangleBorder(),
+ insetPadding: const EdgeInsets.only(left: 21, right: 21),
+ child: Padding(
+ padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: Text(
+ title ?? "Confirm",
+ style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: Colors.black87, height: 35 / 24, letterSpacing: -0.96),
+ ).paddingOnly(top: 16),
+ ),
+ IconButton(
+ padding: EdgeInsets.zero,
+ icon: const Icon(Icons.close),
+ color: Colors.black87,
+ constraints: const BoxConstraints(),
+ onPressed: () => onCloseTap ?? Navigator.pop(context),
+ // onPressed: () => Navigator.pop(context),
+ )
+ ],
+ ),
+ message.heading5(context).custom(color: AppColor.black35),
+ 28.height,
+ AppFilledButton(
+ label: okTitle ?? "OK",
+ onPressed: onTap ?? () => Navigator.pop(context),
+ textColor: Colors.white,
+ //color: Ap.green,
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/new_views/swipe_module/dialoge/qr_scanner_dialog.dart b/lib/new_views/swipe_module/dialoge/qr_scanner_dialog.dart
new file mode 100644
index 00000000..42a191f3
--- /dev/null
+++ b/lib/new_views/swipe_module/dialoge/qr_scanner_dialog.dart
@@ -0,0 +1,79 @@
+
+import 'package:flutter/material.dart';
+
+import 'package:qr_code_scanner/qr_code_scanner.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+
+class QrScannerDialog extends StatefulWidget {
+ @override
+ State createState() => _QrScannerDialogState();
+}
+
+class _QrScannerDialogState extends State {
+ final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
+ Barcode result;
+ QRViewController controller;
+ bool isPicked = false;
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Container(
+ width: double.infinity,
+ height: double.infinity,
+ color: Colors.white,
+ child: Column(
+ children: [
+ Expanded(
+ flex: 1,
+ child: QRView(
+ key: qrKey,
+ onQRViewCreated: _onQRViewCreated,
+ ),
+ ),
+ // Expanded(
+ // flex: 1,
+ // child: Center(
+ // child: (result != null)
+ // ? Text(
+ // 'Barcode Type: ${result!.format} Data: ${result!.code}')
+ // : Text('Scan a code'),
+ // ),
+ // ),
+ Padding(
+ padding: const EdgeInsets.all(12.0),
+ child: AppFilledButton(
+ label: "Cancel",
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ void _onQRViewCreated(QRViewController controller) {
+ this.controller = controller;
+
+ controller.scannedDataStream.listen((scanData) {
+ setState(() {
+ result = scanData;
+ if (!isPicked) {
+ isPicked = true;
+ Navigator.pop(context, result.code);
+ }
+ });
+ });
+ controller.pauseCamera();
+ controller.resumeCamera();
+ }
+
+ @override
+ void dispose() {
+ controller?.dispose();
+ super.dispose();
+ }
+}
diff --git a/lib/new_views/swipe_module/dialoge/success_dialog.dart b/lib/new_views/swipe_module/dialoge/success_dialog.dart
new file mode 100644
index 00000000..0e64296d
--- /dev/null
+++ b/lib/new_views/swipe_module/dialoge/success_dialog.dart
@@ -0,0 +1,76 @@
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:just_audio/just_audio.dart';
+import 'package:lottie/lottie.dart';
+
+class SuccessDialog extends StatefulWidget {
+ bool isFromDashboard;
+
+ SuccessDialog(this.isFromDashboard);
+
+ @override
+ State createState() => _SuccessDialogState();
+}
+
+class _SuccessDialogState extends State with TickerProviderStateMixin {
+ AnimationController _controller;
+
+ @override
+ void initState() {
+ _controller = AnimationController(vsync: this);
+
+ super.initState();
+ }
+
+ Future playSuccessSound() async {
+ AudioPlayer player = AudioPlayer();
+ String audioAsset = "";
+ if (Platform.isAndroid) {
+ audioAsset = "assets/audio/success_tone_android.mp3";
+ } else {
+ audioAsset = "assets/audio/success_tone_ios.caf";
+ }
+ await player.setAsset(audioAsset);
+ await player.load();
+ player.play();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ double size = MediaQuery.of(context).size.width / 1.8;
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ width: size,
+ height: size,
+ child: Card(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(25.0),
+ ),
+ child: Lottie.asset(
+ //TODO replace with original lottie file...
+ 'assets/lottie/done.json',
+ repeat: false,
+ reverse: false,
+ controller: _controller,
+ frameRate: FrameRate(60.0),
+ onLoaded: (LottieComposition v) async {
+ await playSuccessSound();
+ _controller
+ ..duration = v.duration
+ ..forward().whenComplete(() async {
+ Navigator.pop(context);
+ if (widget.isFromDashboard) Navigator.pop(context);
+ });
+ },
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/new_views/swipe_module/enums/swipe_type.dart b/lib/new_views/swipe_module/enums/swipe_type.dart
new file mode 100644
index 00000000..8c4ff449
--- /dev/null
+++ b/lib/new_views/swipe_module/enums/swipe_type.dart
@@ -0,0 +1,18 @@
+enum SwipeTypeEnum {
+ NFC, // 1
+ QR, // 2
+ Wifi, // 3
+}
+
+extension EnumExtensionsSwipeType on SwipeTypeEnum {
+ int getIntFromSwipeTypeEnum() {
+ switch (this) {
+ case SwipeTypeEnum.NFC:
+ return 1;
+ case SwipeTypeEnum.QR:
+ return 2;
+ case SwipeTypeEnum.Wifi:
+ return 3;
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/new_views/swipe_module/mark_attendance_widget.dart b/lib/new_views/swipe_module/mark_attendance_widget.dart
new file mode 100644
index 00000000..f4931ee7
--- /dev/null
+++ b/lib/new_views/swipe_module/mark_attendance_widget.dart
@@ -0,0 +1,851 @@
+import 'dart:async';
+import 'dart:developer';
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:geolocator/geolocator.dart';
+import 'package:huawei_location/huawei_location.dart';
+import 'package:nfc_manager/nfc_manager.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/providers/api/user_provider.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/swipe_module/enums/swipe_type.dart';
+import 'package:test_sa/new_views/swipe_module/models/swipe_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/pages/land_page/nfc/nfc_reader_sheet.dart';
+import 'package:test_sa/new_views/swipe_module/utils/swipe_general_utils.dart';
+import 'package:test_sa/new_views/swipe_module/utils/location_utils.dart';
+import 'package:test_sa/new_views/swipe_module/dialoge/confirm_dialog.dart';
+import 'package:test_sa/new_views/swipe_module/dialoge/success_dialog.dart';
+import 'package:test_sa/new_views/swipe_module/dialoge/qr_scanner_dialog.dart';
+import 'package:wifi_iot/wifi_iot.dart';
+
+class MarkAttendanceWidget extends StatefulWidget {
+ double topPadding;
+ bool isFromDashboard;
+
+ MarkAttendanceWidget({Key key, this.topPadding = 0, this.isFromDashboard = false}) : super(key: key);
+
+ // todo MarkAttendanceWidget(this.model, {Key? key, this.topPadding = 0, this.isFromDashboard = false}) : super(key: key);
+
+ @override
+ _MarkAttendanceWidgetState createState() {
+ return _MarkAttendanceWidgetState();
+ }
+}
+
+class _MarkAttendanceWidgetState extends State {
+ bool isNfcEnabled = false, isQrEnabled = false, isWifiEnabled = false;
+ UserProvider _userProvider;
+
+ int _locationUpdateCbId = 0;
+
+ @override
+ void initState() {
+ super.initState();
+ checkAttendanceAvailability();
+ }
+
+ void checkAttendanceAvailability() async {
+ _userProvider = Provider.of(context, listen: false);
+ bool isAvailable = await NfcManager.instance.isAvailable();
+ log('backend enabled values are nfc ${_userProvider.user.enableNFC} qr ${_userProvider.user.enableQR} wifi ${_userProvider.user.enableWifi}');
+ setState(() {
+ if (isAvailable && _userProvider.user.enableNFC) isNfcEnabled = true;
+ if (_userProvider.user.enableQR) isQrEnabled = true;
+ if (_userProvider.user.enableWifi) isWifiEnabled = true;
+ });
+ }
+
+ void checkHuaweiLocationPermission(SwipeTypeEnum attendanceType,BuildContext context) async {
+ // Permission_Handler permissionHandler = PermissionHandler();
+ LocationUtilities.isEnabled((bool isEnabled) async {
+ if (isEnabled) {
+ LocationUtilities.havePermission((bool permission) async {
+ if (permission) {
+ getHuaweiCurrentLocation(attendanceType,context);
+ } else {
+ bool has = await requestPermissions();
+ if (has) {
+ getHuaweiCurrentLocation(attendanceType,context);
+ } else {
+ showDialog(
+ context: context,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: "You need to give location permission to mark attendance",
+ onTap: () {
+ Navigator.pop(context);
+ },
+ ),
+ );
+ }
+ }
+ });
+ } else {
+ showDialog(
+ context: context,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: "You need to enable location services to mark attendance",
+ onTap: () async {
+ Navigator.pop(context);
+ await Geolocator.openLocationSettings();
+ },
+ ),
+ );
+ }
+ });
+
+ // if (await permissionHandler.hasLocationPermission()) {
+ // getHuaweiCurrentLocation(attendanceType);
+ // } else {
+ // bool has = await requestPermissions();
+ // if (has) {
+ // getHuaweiCurrentLocation(attendanceType);
+ // } else {
+ // showDialog(
+ // context: context,
+ // builder: (BuildContext cxt) => ConfirmDialog(
+ // message: "You need to give location permission to mark attendance",
+ // onTap: () {
+ // Navigator.pop(context);
+ // },
+ // ),
+ // );
+ // }
+ // }
+ }
+
+ Future requestPermissions() async {
+ var result = await [
+ Permission.location,
+ ].request();
+ return (result[Permission.location] == PermissionStatus.granted || result[Permission.locationAlways] == PermissionStatus.granted);
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ // Stop Session
+ NfcManager.instance.stopSession();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return
+ Container(
+ padding: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: widget.topPadding),
+ decoration: const BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white),
+ width: double.infinity,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ 20.height,
+ 'click me '.heading5(context),
+ // LocaleKeys.markAttendance.tr().toSectionHeading(),
+ // LocaleKeys.selectMethodOfAttendance.tr().toText11(color: const Color(0xff535353)),
+ GridView(
+ physics: const NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ padding: const EdgeInsets.only(bottom: 0, top: 21),
+ gridDelegate:
+ SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: (MediaQuery.of(context).size.width < 550) ? 3 : 5, childAspectRatio: 1 / 1, crossAxisSpacing: 8, mainAxisSpacing: 8),
+ children: availableAttendanceMethodList(context: context),
+ )
+ ],
+ ),
+ );
+ }
+
+
+
+
+ void handleSwipe({
+ SwipeTypeEnum swipeType,
+ @required bool isEnable,
+ @required BuildContext context,
+ }) {
+ // if (AppState().getIsHuawei) {
+ if (false) {
+ checkHuaweiLocationPermission(swipeType,context);
+ } else {
+ LocationUtilities.isEnabled((bool isEnabled) {
+ if (isEnabled) {
+ LocationUtilities.havePermission((bool permission) {
+ if (permission) {
+ SwipeGeneralUtils.showLoading(context);
+ LocationUtilities.getCurrentLocation(
+ (Position position, bool isMocked) {
+ if (isMocked) {
+ SwipeGeneralUtils.hideLoading(context);
+ SwipeGeneralUtils.markFakeAttendance(swipeType.name, position.latitude.toString() ?? "", position.longitude.toString() ?? "", context);
+ } else {
+ SwipeGeneralUtils.hideLoading(context);
+ //todo performNfcAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? "");
+ handleSwipeOperation(swipeType: swipeType, lat: position.latitude, lang: position.longitude);
+ }
+ },
+ () {
+ SwipeGeneralUtils.hideLoading(context);
+ SwipeGeneralUtils.confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working.");
+ },
+ context,
+ );
+ } else {
+ showDialog(
+ context: context,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: "You need to give location permission to mark attendance",
+ onTap: () async {
+ Navigator.pop(context);
+ await Geolocator.openAppSettings();
+ },
+ ),
+ );
+ }
+ });
+ } else {
+ showDialog(
+ context: context,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: "You need to enable location services to mark attendance",
+ onTap: () async {
+ Navigator.pop(context);
+ await Geolocator.openLocationSettings();
+ },
+ ),
+ );
+ }
+ });
+ }
+ }
+
+ void handleSwipeOperation({@required SwipeTypeEnum swipeType, double lat, double lang,BuildContext context}) {
+ switch (swipeType) {
+ case SwipeTypeEnum.NFC:
+ handleNfcAttendance(latitude: lat, longitude: lang,context: context);
+ return;
+ case SwipeTypeEnum.QR:
+ performQrCodeAttendance(latitude: lat, longitude: lang,context:context);
+ return;
+ case SwipeTypeEnum.Wifi:
+ //TODO need to implement.
+ return;
+ }
+ }
+
+ void getHuaweiCurrentLocation(SwipeTypeEnum attendanceType,BuildContext context) async {
+ try {
+ SwipeGeneralUtils.showLoading(context);
+ FusedLocationProviderClient locationService = FusedLocationProviderClient()..initFusedLocationService();
+ LocationRequest locationRequest = LocationRequest();
+ locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;
+ locationRequest.interval = 500;
+ List locationRequestList = [locationRequest];
+ LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList);
+
+ StreamSubscription _streamSubscription;
+ int requestCode = (await (locationService.requestLocationUpdates(locationRequest)));
+
+ _streamSubscription = locationService.onLocationData.listen(
+ (Location location) async {
+ SwipeGeneralUtils.hideLoading(context);
+ await locationService.removeLocationUpdates(requestCode);
+ handleSwipeOperation(swipeType: attendanceType);
+ requestCode = 0;
+ },
+ );
+
+ // locationService.checkLocationSettings(locationSettingsRequest).then((settings) async {
+ // await locationService.getLastLocation().then((value) {
+ // if (value.latitude == null || value.longitude == null) {
+ // showDialog(
+ // context: context,
+ // builder: (BuildContext cxt) => ConfirmDialog(
+ // message: "Unable to get your location, Please check your location settings & try again.",
+ // onTap: () {
+ // Navigator.pop(context);
+ // },
+ // ),
+ // );
+ // } else {
+ // if (attendanceType == "QR") {
+ // performQrCodeAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? "");
+ // }
+ // if (attendanceType == "WIFI") {
+ // performWifiAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? "");
+ // }
+ // if (attendanceType == "NFC") {
+ // performNfcAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? "");
+ // }
+ // }
+ // }).catchError((error) {
+ // log("HUAWEI LOCATION getLastLocation ERROR!!!!!");
+ // log(error);
+ // });
+ // }).catchError((error) {
+ // log("HUAWEI LOCATION checkLocationSettings ERROR!!!!!");
+ // log(error);
+ // if (error.code == "LOCATION_SETTINGS_NOT_AVAILABLE") {
+ // // Location service not enabled.
+ // }
+ // });
+ } catch (error) {
+ log("HUAWEI LOCATION ERROR!!!!!");
+ log('$error');
+ SwipeGeneralUtils.hideLoading(context);
+ // SwipeGeneralUtils.handleException(error, context, null);
+ }
+ }
+
+ Future handleNfcAttendance({double latitude = 0, double longitude = 0,BuildContext context}) async {
+ final userProvider = Provider.of(context, listen: false);
+
+ if (Platform.isIOS) {
+ SwipeGeneralUtils.readNFc(onRead: (String nfcId) async {
+ await _processNfcAttendance(userProvider, nfcId, latitude, longitude,context);
+ });
+ } else {
+ showNfcReader(context, onNcfScan: (String nfcId) async {
+ await _processNfcAttendance(userProvider, nfcId ?? '', latitude, longitude,context);
+ });
+ }
+ }
+
+ Future _processNfcAttendance(
+ UserProvider userProvider,
+ String nfcId,
+ double latitude,
+ double longitude,
+ BuildContext context,
+ ) async {
+ SwipeGeneralUtils.showLoading(context);
+ try {
+ // final swipeModel = Swipe(
+ // swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(),
+ // value: nfcId,
+ // latitude: latitude,
+ // longitude: longitude,
+ // );
+ //Test model...
+ final swipeModel = Swipe(
+ swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(),
+ value: '123',
+ latitude: 24.70865415364271,
+ longitude: 46.66600861881879,
+ );
+ print('swipe model to call api is ${swipeModel.toJson()} ');
+ final swipeResponse = await userProvider.makeSwipe(model: swipeModel);
+ log('swipe response i got is ${swipeResponse.toJson()}');
+
+ if (swipeResponse.isSuccess) {
+ if (Platform.isIOS) await Future.delayed(const Duration(seconds: 3));
+ SwipeGeneralUtils.hideLoading(context);
+ SwipeGeneralUtils.showSuccessDialog(context: context, fromDashBoard: widget.isFromDashboard);
+ } else {
+ SwipeGeneralUtils.hideLoading(context);
+ SwipeGeneralUtils.showErrorDialog(message: swipeResponse.message ?? "Unexpected error occurred", context: context);
+ }
+ } catch (errSwipeGeneralUtilsor) {
+ SwipeGeneralUtils.hideLoading(context);
+ // Uncomment below line for error handling if needed
+ // SwipeGeneralUtils.handleException(error, context, null);
+ }
+ }
+
+ Future closeWifiRequest() async {
+ if (Platform.isAndroid) {
+ await WiFiForIoTPlugin.forceWifiUsage(false);
+ }
+ return await WiFiForIoTPlugin.disconnect();
+ }
+
+ Future performQrCodeAttendance({double latitude, double longitude ,BuildContext context}) async {
+ UserProvider userProvider = Provider.of(context, listen: false);
+ var qrCodeValue = await Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (BuildContext context) => QrScannerDialog(),
+ ),
+ );
+ if (qrCodeValue != null) {
+ SwipeGeneralUtils.showLoading(context);
+ try {
+ //test model..
+ final swipeModel = Swipe(
+ swipeTypeValue: SwipeTypeEnum.QR.getIntFromSwipeTypeEnum(),
+ value: '2323',
+ latitude: 24.70865415364271,
+ longitude: 46.66600861881879,
+ );
+ // final swipeModel = Swipe(
+ // swipeTypeValue: SwipeTypeEnum.QR.getIntFromSwipeTypeEnum(),
+ // value: qrCodeValue,
+ // latitude: latitude,
+ // longitude: longitude,
+ // );
+ log('model i got to scan qr is ${swipeModel.toJson()}');
+ final swipeResponse = await userProvider.makeSwipe(model: swipeModel);
+ log('response of swipe is ${swipeResponse.toJson()}');
+
+ if (swipeResponse.isSuccess) {
+ SwipeGeneralUtils.hideLoading(context);
+ SwipeGeneralUtils.showMDialog(
+ context,
+ backgroundColor: Colors.transparent,
+ isDismissable: true,
+ child: SuccessDialog(widget.isFromDashboard),
+ );
+ } else {
+ SwipeGeneralUtils.hideLoading(context);
+ showDialog(
+ barrierDismissible: true,
+ context: context,
+ builder: (cxt) => ConfirmDialog(
+ message: swipeResponse.message ?? "",
+ onTap: () {
+ Navigator.pop(context);
+ },
+ onCloseTap: () {},
+ ),
+ );
+ }
+ } catch (ex) {
+ log('$ex');
+ SwipeGeneralUtils.hideLoading(context);
+ //this need to confirm where it comes..
+ // SwipeGeneralUtils.handleException(ex, context, null);
+ }
+ }
+ }
+
+ List availableAttendanceMethodList({@required BuildContext context}) {
+ List availableMethods = [];
+ if (isNfcEnabled) {
+ availableMethods.add(attendanceMethod(SwipeTypeEnum.NFC.name, 'nfc_icon', isNfcEnabled, () {
+ handleSwipe(swipeType: SwipeTypeEnum.NFC, isEnable: isNfcEnabled,context: context);
+ }));
+ }
+ if (isQrEnabled) {
+ availableMethods.add(attendanceMethod(SwipeTypeEnum.QR.name, 'wifi_icon', isQrEnabled, () {
+ handleSwipe(swipeType: SwipeTypeEnum.QR, isEnable: isQrEnabled,context: context);
+ }));
+ }
+ if (isWifiEnabled) {
+ availableMethods.add(attendanceMethod(SwipeTypeEnum.Wifi.name, 'wifi_icon', isWifiEnabled, () {
+ handleSwipe(swipeType: SwipeTypeEnum.Wifi, isEnable: isWifiEnabled,context: context);
+ }));
+ }
+ return availableMethods;
+ }
+
+
+
+
+ Widget attendanceMethod(String title, String icon, bool isEnabled, VoidCallback onPress) {
+ return Container(
+ padding: EdgeInsets.all(12),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(18),
+ border: Border.all(color: AppColor.white40, width: 2),
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ icon.toSvgAsset(),
+ title.heading5(context).custom(color: AppColor.neutral50),
+ // Text(
+ // title,
+ // style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
+ // ),
+ ],
+ ),
+ ).onPress(
+ () {
+ log('isEnabled is ${!isEnabled}');
+ if (!isEnabled) return;
+ onPress();
+ },
+ );
+ // return Container(
+ // decoration: BoxDecoration(
+ // borderRadius: BorderRadius.circular(15),
+ // color: isEnabled ? null : Colors.grey.withOpacity(.5),
+ // gradient: isEnabled
+ // ? const LinearGradient(
+ // transform: GradientRotation(.64),
+ // begin: Alignment.topRight,
+ // end: Alignment.bottomLeft,
+ // colors: [
+ // //ToDo set Colors according to design provided by designer...
+ // Colors.blue,
+ // Colors.green,
+ // // AppColor.gradiantEndColor,
+ // // MyColors.gradiantStartColor,
+ // ],
+ // )
+ // : null,
+ // ),
+ // clipBehavior: Clip.antiAlias,
+ // padding: const EdgeInsets.only(left: 10, right: 10, top: 14, bottom: 14),
+ // child: Column(
+ // crossAxisAlignment: CrossAxisAlignment.start,
+ // children: [
+ // // SvgPicture.asset(image, color: Colors.white, alignment: Alignment.topLeft).expanded,
+ // Icon(iconData, color: isEnabled ? AppColor.black35 : Colors.grey),
+ // title.heading6(context),
+ // // title.toText17(isBold: true, color: Colors.white),
+ // ],
+ // ),
+ // ).onPress(
+ // () {
+ // log('isEnabled is ${!isEnabled}');
+ // if (!isEnabled) return;
+ // onPress();
+ // },
+ // );
+ }
+}
+
+// Widget customListItem({required String icon, required String heading, required String subHeading, required VoidCallback onTap}) {
+// return GestureDetector(
+// onTap: onTap, // Handles the tap
+// child: Card(
+// shape: RoundedRectangleBorder(
+// borderRadius: BorderRadius.circular(14), // Circular border radius
+// ),
+// color: Colors.white,
+// child: Row(
+// crossAxisAlignment: CrossAxisAlignment.start, // Align items at the top
+// children: [
+// // Icon Section
+// icon
+// .toSvgAsset(
+// width: 32,
+// color: AppColor.neutral120,
+// height: 29,
+// )
+// .paddingOnly(top: 8),
+// 14.width,
+// Expanded(
+// child: Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// children: [
+// Text(
+// heading,
+// style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50),
+// ),
+// 7.height,
+// Text(
+// subHeading,
+// style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
+// ),
+// ],
+// ).paddingOnly(end: 50),
+// ),
+// ],
+// ).paddingAll(12),
+// ),
+// );
+// }
+
+//qr older code...
+
+//nfc older code widget
+
+// // if (AppState().getIsHuawei) {
+// if (false) {
+// checkHuaweiLocationPermission(SwipeTypeEnum.NFC);
+// } else {
+// LocationUtilities.isEnabled((bool isEnabled) {
+// if (isEnabled) {
+// LocationUtilities.havePermission((bool permission) {
+// if (permission) {
+// SwipeGeneralUtils.showLoading(context);
+// LocationUtilities.getCurrentLocation(
+// (Position position, bool isMocked) {
+// if (isMocked) {
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.markFakeAttendance("NFC", position.latitude.toString() ?? "", position.longitude.toString() ?? "",context);
+// } else {
+// SwipeGeneralUtils.hideLoading(context);
+// //todo performNfcAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? "");
+// }
+// },
+// () {
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working.");
+// },
+// context,
+// );
+// } else {
+// showDialog(
+// context: context,
+// builder: (BuildContext cxt) => ConfirmDialog(
+// message: "You need to give location permission to mark attendance",
+// onTap: () async {
+// Navigator.pop(context);
+// await Geolocator.openAppSettings();
+// },
+// ),
+// );
+// }
+// });
+// } else {
+// showDialog(
+// context: context,
+// builder: (BuildContext cxt) => ConfirmDialog(
+// message: "You need to enable location services to mark attendance",
+// onTap: () async {
+// Navigator.pop(context);
+// await Geolocator.openLocationSettings();
+// },
+// ),
+// );
+// }
+// });
+// }
+
+//older code....
+// Future performNfcAttendance({double lat = 0, double lng = 0}) async {
+// UserProvider userProvider = Provider.of(context,listen:false);
+// if (Platform.isIOS) {
+// SwipeGeneralUtils.readNFc(onRead: (String nfcId) async {
+// SwipeGeneralUtils.showLoading(context);
+// try {
+// SwipeModel swipeResponse = await userProvider.makeSwipe(model: Swipe(swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(), value: '', latitude: lat, longitude: lng));
+// if (swipeResponse.responseCode != 1) {
+// SwipeGeneralUtils.hideLoading(context);
+// showDialog(
+// context: context,
+// builder: (BuildContext cxt) => ConfirmDialog(
+// message: swipeResponse.message ?? "Unexpected error occurred",
+// onTap: () {
+// Navigator.pop(context);
+// },
+// ),
+// );
+// } else {
+// bool status = swipeResponse.data;
+// if (Platform.isIOS) await Future.delayed(const Duration(seconds: 3));
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.showMDialog(
+// context,
+// backgroundColor: Colors.transparent,
+// isDismissable: true,
+// child: SuccessDialog(widget.isFromDashboard),
+// );
+// }
+// } catch (ex) {
+// SwipeGeneralUtils.hideLoading(context);
+// // SwipeGeneralUtils.handleException(ex, context, null);
+// }
+// });
+// } else {
+// showNfcReader(context, onNcfScan: (String nfcId) async {
+// SwipeGeneralUtils.showLoading(context);
+// try {
+// SwipeModel swipeResponse = await userProvider.makeSwipe(model: Swipe(swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(), value: nfcId??'', latitude: lat, longitude: lng));
+// log('api response i got is ${swipeResponse.toJson()}');
+// if (swipeResponse.responseCode != 1) {
+// SwipeGeneralUtils.hideLoading(context);
+// showDialog(
+// context: context,
+// builder: (BuildContext cxt) => ConfirmDialog(
+// message: swipeResponse.message ?? "Unexpected error occurred",
+// onTap: () {
+// Navigator.pop(context);
+// },
+// ),
+// );
+// } else {
+// bool status = swipeResponse.data; //use this status to get transactions.
+// if (Platform.isIOS) await Future.delayed(const Duration(seconds: 3));
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.showMDialog(
+// context,
+// backgroundColor: Colors.transparent,
+// isDismissable: true,
+// child: SuccessDialog(widget.isFromDashboard),
+// );
+// }
+// } catch (ex) {
+// SwipeGeneralUtils.hideLoading(context);
+// // SwipeGeneralUtils.handleException(ex, context, null);
+// }
+// // SwipeGeneralUtils.showLoading(context);
+// // try {
+// // GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? "", isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng);
+// // if (g?.messageStatus != 1) {
+// // SwipeGeneralUtils.hideLoading(context);
+// // showDialog(
+// // context: context,
+// // builder: (BuildContext cxt) => ConfirmDialog(
+// // message: g?.errorEndUserMessage ?? "Unexpected error occurred",
+// // onTap: () {
+// // Navigator.pop(context);
+// // },
+// // ),
+// // );
+// // } else {
+// // bool status = await model.fetchAttendanceTracking(context);
+// // SwipeGeneralUtils.hideLoading(context);
+// // showMDialog(
+// // context,
+// // backgroundColor: Colors.transparent,
+// // isDismissable: false,
+// // child: SuccessDialog(widget.isFromDashboard),
+// // );
+// // }
+// // } catch (ex) {
+// // log(ex);
+// // SwipeGeneralUtils.hideLoading(context);
+// // // SwipeGeneralUtils.handleException(ex, context, (String msg) {
+// // // SwipeGeneralUtils.confirmDialog(context, msg);
+// // // });
+// // }
+// });
+// }
+// }
+
+//
+// Future checkSession() async {
+// try {
+// SwipeGeneralUtils.showLoading(context);
+// await DashboardApiClient().getOpenMissingSwipes();
+// SwipeGeneralUtils.hideLoading(context);
+// return true;
+// } catch (ex) {
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.handleException(ex, context, null);
+// return false;
+// }
+// }
+
+//TODO need to confirm ....
+// Future performWifiAttendance({double? latitude, double? lng}) async {
+// // if (Platform.isAndroid) {
+// // if (!(await checkSession())) {
+// // return;
+// // }
+// // }
+// SwipeGeneralUtils.showLoading(context);
+// bool isConnected = await WiFiForIoTPlugin.connect(AppState().getMohemmWifiSSID ?? "",
+// password: AppState().getMohemmWifiPassword ?? "", joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false);
+//
+// if (Platform.isIOS) {
+// if (await WiFiForIoTPlugin.getSSID() == AppState().getMohemmWifiSSID) {
+// isConnected = true;
+// } else {
+// isConnected = false;
+// }
+// }
+//
+// if (isConnected && AppState().isAuthenticated) {
+// await WiFiForIoTPlugin.forceWifiUsage(true);
+// await Future.delayed(const Duration(seconds: 6));
+// try {
+// GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 3, nfcValue: "", isGpsRequired: isWifiLocationEnabled, lat: lat, long: lng);
+// bool status = await model.fetchAttendanceTracking(context);
+// SwipeGeneralUtils.hideLoading(context);
+// await closeWifiRequest();
+// if (g?.messageStatus == 2) {
+// showDialog(
+// barrierDismissible: true,
+// context: context,
+// builder: (cxt) => ConfirmDialog(
+// message: g?.errorEndUserMessage ?? "",
+// onTap: () {
+// Navigator.pop(context);
+// },
+// onCloseTap: () {},
+// ),
+// );
+// } else {
+// showMDialog(
+// context,
+// backgroundColor: Colors.transparent,
+// isDismissable: false,
+// child: SuccessDialog(widget.isFromDashboard),
+// );
+// }
+// } catch (ex) {
+// await closeWifiRequest();
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.handleException(ex, context, null);
+// }
+// } else {
+// if (AppState().isAuthenticated) {
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.confirmDialog(context, "LocaleKeys.comeNearHMGWifi.tr()");
+// } else {
+// await closeWifiRequest();
+// }
+// }
+// }
+
+// older grid widget..
+// attendanceMethod(SwipeTypeEnum.NFC.name, Icons.nfc, isNfcEnabled, () {
+// handleSwipe(swipeType: SwipeTypeEnum.NFC, isEnable: isNfcEnabled);
+// }),
+// attendanceMethod(SwipeTypeEnum.QR.name, Icons.qr_code_2, isQrEnabled, () async {
+// handleSwipe(swipeType: SwipeTypeEnum.QR, isEnable: true);
+// }),
+// //if (isWifiEnabled) //todo
+// attendanceMethod(SwipeTypeEnum.Wifi.name, Icons.wifi, isWifiEnabled, () {
+// // if (AppState().getIsHuawei) {
+// if (false) {
+// checkHuaweiLocationPermission(SwipeTypeEnum.Wifi);
+// } else {
+// LocationUtilities.isEnabled((bool isEnabled) {
+// if (isEnabled) {
+// LocationUtilities.havePermission((bool permission) {
+// if (permission) {
+// SwipeGeneralUtils.showLoading(context);
+// LocationUtilities.getCurrentLocation(
+// (Position position, bool isMocked) {
+// if (isMocked) {
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.markFakeAttendance("WIFI", position.latitude.toString() ?? "", position.longitude.toString() ?? "", context);
+// } else {
+// SwipeGeneralUtils.hideLoading(context);
+// //todo performWifiAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? "");
+// }
+// },
+// () {
+// SwipeGeneralUtils.hideLoading(context);
+// SwipeGeneralUtils.confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working.");
+// },
+// context,
+// );
+// } else {
+// showDialog(
+// context: context,
+// builder: (BuildContext cxt) => ConfirmDialog(
+// message: "You need to give location permission to mark attendance",
+// onTap: () async {
+// Navigator.pop(context);
+// await Geolocator.openAppSettings();
+// },
+// ),
+// );
+// }
+// });
+// } else {
+// showDialog(
+// context: context,
+// builder: (BuildContext cxt) => ConfirmDialog(
+// message: "You need to enable location services to mark attendance",
+// onTap: () async {
+// Navigator.pop(context);
+// await Geolocator.openLocationSettings();
+// },
+// ),
+// );
+// }
+// });
+// }
+// }),
diff --git a/lib/new_views/swipe_module/models/swipe_model.dart b/lib/new_views/swipe_module/models/swipe_model.dart
new file mode 100644
index 00000000..ab7f8235
--- /dev/null
+++ b/lib/new_views/swipe_module/models/swipe_model.dart
@@ -0,0 +1,68 @@
+
+import 'package:flutter/material.dart';
+
+class SwipeModel {
+ final bool data;
+ final String message;
+ final String title;
+ final String innerMessage;
+ final int responseCode;
+ final bool isSuccess;
+
+ SwipeModel({
+ @required this.data,
+ @required this.message,
+ this.title,
+ this.innerMessage,
+ @required this.responseCode,
+ @required this.isSuccess,
+ });
+
+ factory SwipeModel.fromJson(Map json) {
+ return SwipeModel(
+ data: json['data'] as bool,
+ message: json['message'] as String,
+ title: json['title'] as String,
+ innerMessage: json['innerMessage'] as String,
+ responseCode: json['responseCode'] as int,
+ isSuccess: json['isSuccess'] as bool,
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'data': data,
+ 'message': message,
+ 'title': title,
+ 'innerMessage': innerMessage,
+ 'responseCode': responseCode,
+ 'isSuccess': isSuccess,
+ };
+ }
+
+
+}
+
+class Swipe {
+ final int swipeTypeValue;
+ final String value;
+ final double latitude;
+ final double longitude;
+
+ Swipe({
+ @required this.swipeTypeValue,
+ @required this.value,
+ @required this.latitude,
+ @required this.longitude,
+ });
+
+ Map toJson() {
+ return {
+ 'swipeTypeValue': swipeTypeValue,
+ 'value': value,
+ 'latitude': latitude,
+ 'longitude': longitude,
+ };
+ }
+}
+
diff --git a/lib/new_views/swipe_module/models/swipe_transaction_model.dart b/lib/new_views/swipe_module/models/swipe_transaction_model.dart
new file mode 100644
index 00000000..9c727368
--- /dev/null
+++ b/lib/new_views/swipe_module/models/swipe_transaction_model.dart
@@ -0,0 +1,47 @@
+class SwipeTransaction {
+ final int id;
+ final String swipeTypeName;
+ final String userName;
+ final String siteName;
+ final String pointName;
+ final DateTime swipeTime;
+ final bool isSuccess;
+ final String errorMessage;
+
+ SwipeTransaction({
+ this.id,
+ this.swipeTypeName,
+ this.userName,
+ this.siteName,
+ this.pointName,
+ this.swipeTime,
+ this.isSuccess,
+ this.errorMessage,
+ });
+
+ factory SwipeTransaction.fromJson(Map json) {
+ return SwipeTransaction(
+ id: json['id'] as int,
+ swipeTypeName: json['swipeTypeName'] ,
+ userName: json['userName'] ,
+ siteName: json['siteName'] ,
+ pointName: json['pointName'] ,
+ swipeTime: DateTime.parse(json['swipeTime']),
+ isSuccess: json['isSuccess'] ,
+ errorMessage: json['errorMessage'] ,
+ );
+ }
+
+ // Map toJson() {
+ // return {
+ // 'id': id,
+ // 'swipeTypeName': swipeTypeName,
+ // 'userName': userName,
+ // 'siteName': siteName,
+ // 'pointName': pointName,
+ // 'swipeTime': swipeTime.toIso8601String(),
+ // 'isSuccess': isSuccess,
+ // 'errorMessage': errorMessage,
+ // };
+ // }
+}
diff --git a/lib/new_views/swipe_module/non_hmg_employee_swipe_view.dart b/lib/new_views/swipe_module/non_hmg_employee_swipe_view.dart
new file mode 100644
index 00000000..999a1228
--- /dev/null
+++ b/lib/new_views/swipe_module/non_hmg_employee_swipe_view.dart
@@ -0,0 +1,84 @@
+import 'package:flutter/material.dart';
+import 'package:nfc_manager/nfc_manager.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+
+class NonHmgEmployeeSwipeView extends StatefulWidget {
+ NonHmgEmployeeSwipeView({Key key}) : super(key: key);
+
+ @override
+ _NonHmgEmployeeSwipeViewState createState() {
+ return _NonHmgEmployeeSwipeViewState();
+ }
+}
+
+class _NonHmgEmployeeSwipeViewState extends State {
+ bool isNfcEnabled = false;
+
+ @override
+ void initState() {
+ super.initState();
+ checkForNfcAndLocationPermission();
+ }
+
+ void checkForNfcAndLocationPermission() async {
+ isNfcEnabled = await NfcManager.instance.isAvailable();
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.all(16),
+ margin: const EdgeInsets.only(top: 21),
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(30), color: Colors.white, border: Border.all(color: AppColor.white936.withOpacity(.05), width: 1)),
+ width: double.infinity,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "Mark Attendance",
+ style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ GridView(
+ physics: const NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ padding: const EdgeInsets.only(bottom: 0, top: 16),
+ gridDelegate:
+ SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: (MediaQuery.of(context).size.width < 550) ? 3 : 5, childAspectRatio: 1 / 1, crossAxisSpacing: 16, mainAxisSpacing: 16),
+ children: [
+ gridItem("Nfc", Icons.nfc, isNfcEnabled).onPress(isNfcEnabled ? () {} : null),
+ gridItem("Qr Scan", Icons.qr_code, true).onPress(() {}),
+ ],
+ )
+ ],
+ ),
+ );
+ }
+
+ Widget gridItem(String label, IconData iconData, bool enable) {
+ return Container(
+ padding: const EdgeInsets.all(16),
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(25), color: AppColor.white30, border: Border.all(color: AppColor.white936.withOpacity(.03), width: 1)),
+ alignment: Alignment.center,
+ child: Column(
+ //mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Icon(iconData, color: enable ? AppColor.black35 : Colors.grey),
+ Text(
+ label,
+ style: AppTextStyles.heading6.copyWith(color: enable ? AppColor.black35 : Colors.grey),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/new_views/swipe_module/swipe_success_view.dart b/lib/new_views/swipe_module/swipe_success_view.dart
new file mode 100644
index 00000000..3b36e1af
--- /dev/null
+++ b/lib/new_views/swipe_module/swipe_success_view.dart
@@ -0,0 +1,116 @@
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+
+class SwipeSuccessView extends StatelessWidget {
+ static const routeName = '/swipe_success_view';
+ const SwipeSuccessView({Key key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment:CrossAxisAlignment.center,
+ children: [
+ 'swipe_success'.toSvgAsset(),
+ 17.height,
+ context.translation.successful.heading4(context).custom(color: AppColor.neutral80),
+ 8.height,
+ context.translation.youHaveSuccessfullyMarkedYourAttendance.bodyText2(context).custom(color: AppColor.white20),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+
+class CircularAnimationWithProgressIndicator extends StatefulWidget {
+ Widget child;
+ CircularAnimationWithProgressIndicator({Key key, this.child}) : super(key: key);
+ @override
+ _CircularAnimationWithProgressIndicatorState createState() =>
+ _CircularAnimationWithProgressIndicatorState();
+}
+
+class _CircularAnimationWithProgressIndicatorState
+ extends State
+ with SingleTickerProviderStateMixin {
+ AnimationController _controller;
+
+
+ @override
+ void initState() {
+ super.initState();
+
+ // Animation controller for progress indicator
+ _controller = AnimationController(
+ vsync: this,
+ duration: const Duration(seconds: 40), // Duration of one full rotation
+ )..repeat(); // Repeat animation continuously
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Center(
+ child: Stack(
+ alignment: Alignment.center,
+ children: [
+ // Animated CircularProgressIndicator
+ AnimatedBuilder(
+ animation: _controller,
+ builder: (context, child) {
+ return Transform.rotate(
+ angle: _controller.value * 2 * 3.1416, // Full rotation
+ child: child,
+ );
+ },
+ child: SizedBox(
+ width: 120.toScreenHeight,
+ height: 120.toScreenWidth,
+ child: const CircularProgressIndicator(
+ strokeWidth: 3.0,
+ backgroundColor: AppColor.primary30,
+
+ value: null, // Infinite animation
+ ),
+ ),
+ ),
+
+ // Static container in the center
+ widget.child?? const SizedBox(),
+ ],
+ ),
+ );
+ }
+}
+
+
+// ClipOval(
+// child: Container(
+// color: Colors.grey.withOpacity(0.2),
+// padding: const EdgeInsets.all(10),
+// child: ClipOval(
+// child: Container(
+// color: AppColor.white.withOpacity(0.2),
+// padding: const EdgeInsets.all(10),
+// child: ClipOval(
+// child: Container(
+// color: AppColor.white,
+// child: 'success_swipe'.toSvgAsset().paddingAll(50),
+// ),
+// ).paddingAll(20),
+// ),
+// ),
+// ),
+// )
diff --git a/lib/new_views/swipe_module/utils/location_utils.dart b/lib/new_views/swipe_module/utils/location_utils.dart
new file mode 100644
index 00000000..9545fef9
--- /dev/null
+++ b/lib/new_views/swipe_module/utils/location_utils.dart
@@ -0,0 +1,67 @@
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:geolocator/geolocator.dart';
+import 'package:permission_handler/permission_handler.dart';
+
+class LocationUtilities {
+ static void havePermission(Function(bool) callback) {
+ Geolocator.checkPermission().then((value) async {
+ if (value == LocationPermission.denied || value == LocationPermission.deniedForever) {
+ value = await Geolocator.requestPermission();
+ callback(![LocationPermission.denied, LocationPermission.deniedForever].contains(value));
+ } else {
+ callback(true);
+ }
+ });
+ }
+
+ static void isEnabled(Function(bool) callback) {
+ Geolocator.isLocationServiceEnabled().then((value) => callback(value));
+ }
+
+ static bool _listeningSettingChange = true;
+
+ static void listenGPS({bool change = true, Function(bool) onChange}) async {
+ _listeningSettingChange = change;
+ if (change == false) return;
+
+ Future.doWhile(() async {
+ await Future.delayed(const Duration(milliseconds: 1000));
+ var enable = await Geolocator.isLocationServiceEnabled();
+ onChange(enable);
+ return _listeningSettingChange;
+ });
+ }
+
+ static void locationFun(Function(bool) completion, BuildContext context) {
+ Permission.location.isGranted.then((isGranted) {
+ if (!isGranted) {
+ Permission.location.request().then((granted) {
+ completion(granted == PermissionStatus.granted);
+ });
+ }
+ completion(isGranted);
+ });
+ }
+
+ static void getCurrentLocation(Function(Position position, bool isMocked) callback, Function errorCallBack, BuildContext context) {
+ void done(Position position) {
+ //AppStorage.sp.saveLocation(position);
+ bool isMocked = position.isMocked;
+ callback(position, isMocked);
+ }
+
+ locationFun((granted) {
+ if (granted) {
+ Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 5)).then((value) {
+ done(value);
+ }).catchError((err) {
+ errorCallBack();
+ });
+ } else {
+ // AppPermissions
+ }
+ }, context);
+ }
+}
diff --git a/lib/new_views/swipe_module/utils/swipe_general_utils.dart b/lib/new_views/swipe_module/utils/swipe_general_utils.dart
new file mode 100644
index 00000000..d430b29f
--- /dev/null
+++ b/lib/new_views/swipe_module/utils/swipe_general_utils.dart
@@ -0,0 +1,909 @@
+import 'dart:async';
+import 'dart:developer';
+import 'dart:io';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:geolocator/geolocator.dart';
+import 'package:google_api_availability/google_api_availability.dart';
+import 'package:huawei_location/huawei_location.dart';
+import 'package:intl/intl.dart';
+import 'package:nfc_manager/nfc_manager.dart';
+import 'package:nfc_manager/platform_tags.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:provider/provider.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'package:test_sa/controllers/providers/api/user_provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/main.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
+import 'package:test_sa/new_views/pages/land_page/nfc/nfc_reader_sheet.dart';
+import 'package:test_sa/new_views/swipe_module/dialoge/confirm_dialog.dart';
+import 'package:test_sa/new_views/swipe_module/dialoge/qr_scanner_dialog.dart';
+import 'package:test_sa/new_views/swipe_module/enums/swipe_type.dart';
+import 'package:test_sa/new_views/swipe_module/models/swipe_model.dart';
+import 'package:test_sa/new_views/swipe_module/swipe_success_view.dart';
+import 'package:test_sa/new_views/swipe_module/utils/location_utils.dart';
+
+
+class SwipeGeneralUtils {
+ static bool _isLoadingVisible = false;
+
+ static bool get isLoading => _isLoadingVisible;
+
+ static void showToast(String message, {bool longDuration = true}) {
+ Fluttertoast.showToast(
+ msg: message,
+ toastLength: longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
+ gravity: ToastGravity.BOTTOM,
+ timeInSecForIosWeb: 1,
+ backgroundColor: Colors.black54,
+ textColor: Colors.white,
+ fontSize: 13.0);
+ }
+
+ static dynamic getNotNullValue(List list, int index) {
+ try {
+ return list[index];
+ } catch (ex) {
+ return null;
+ }
+ }
+
+ static void markFakeAttendance(dynamic sourceName, String lat, String long, @required BuildContext context) async {
+ showLoading(context);
+ try {
+ hideLoading(navigatorKey.currentState.overlay.context);
+ confirmDialog(navigatorKey.currentState.overlay.context, "Fake Location)");
+ } catch (ex) {
+ log('$ex');
+ hideLoading(context);
+ //handleException(ex, context, null);
+ }
+ }
+
+ static int stringToHex(String colorCode) {
+ try {
+ return int.parse(colorCode.replaceAll("#", "0xff"));
+ } catch (ex) {
+ return (0xff000000);
+ }
+ }
+
+ static Future delay(int millis) async {
+ return await Future.delayed(Duration(milliseconds: millis));
+ }
+
+ static void showLoading(BuildContext context) {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ _isLoadingVisible = true;
+
+ // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+
+ showDialog(
+ context: context,
+ barrierColor: Colors.black.withOpacity(0.5),
+ useRootNavigator: false,
+ builder: (BuildContext context) => const AppLazyLoading(),
+ ).then((value) {
+ _isLoadingVisible = false;
+ });
+ });
+ }
+
+ static void hideLoading(BuildContext context) {
+ if (_isLoadingVisible) {
+ _isLoadingVisible = false;
+ Navigator.of(context).pop();
+ }
+ _isLoadingVisible = false;
+ }
+
+ static Future getStringFromPrefs(String key) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ return prefs.getString(key) ?? "";
+ }
+
+ static Future removeStringFromPrefs(String key) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ return prefs.remove(key);
+ }
+
+ static Future saveStringFromPrefs(String key, String value) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ return await prefs.setString(key, value);
+ }
+
+ // static void handleException(dynamic exception, cxt, Function(String)? onErrorMessage) {
+ // String errorMessage;
+ // if (exception.error.errorType != null && exception.error.errorType == 4) {
+ // Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.appUpdateScreen, (_) => false, arguments: exception.error?.errorMessage);
+ // } else {
+ // if (exception is APIException) {
+ // if (exception.message == APIException.UNAUTHORIZED) {
+ // return;
+ // } else {
+ // errorMessage = exception.error?.errorMessage ?? exception.message;
+ // }
+ // } else {
+ // errorMessage = APIException.UNKNOWN;
+ // }
+ // if (onErrorMessage != null) {
+ // onErrorMessage(errorMessage);
+ // } else {
+ // if (!AppState().isAuthenticated) {
+ // showDialog(
+ // barrierDismissible: false,
+ // context: cxt,
+ // builder: (cxt) => ConfirmDialog(
+ // message: errorMessage,
+ // onTap: () {
+ // Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false);
+ // },
+ // onCloseTap: () {},
+ // ),
+ // );
+ // } else {
+ // if (cxt != null) {
+ // confirmDialog(cxt, errorMessage);
+ // } else {
+ // showToast(errorMessage);
+ // }
+ // }
+ // }
+ // }
+ // }
+ //
+ // static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message}) async {
+ // return showDialog(
+ // context: context,
+ // builder: (BuildContext context) => ConfirmDialog(
+ // message: message,
+ // onTap: onOkTapped,
+ // ),
+ // );
+ // }
+ //
+ static void confirmDialog(cxt, String message, {VoidCallback onTap}) {
+ showDialog(
+ context: cxt,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: message,
+ onTap: onTap,
+ ),
+ );
+ }
+
+
+ static void showErrorDialog({String message, @required BuildContext context}) {
+ showDialog(
+ context: context,
+ builder: (context) => ConfirmDialog(
+ message: message,
+ title: 'Error',
+ onTap: () => Navigator.pop(context),
+ ),
+ );
+ }
+
+ static void showMDialog(context, {Widget child, Color backgroundColor, bool isDismissable = true, bool isBusniessCard = false}) async {
+ return showDialog(
+ context: context,
+ barrierDismissible: isDismissable,
+ builder: (context) {
+ return Dialog(
+ shape: isBusniessCard
+ ? const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(
+ Radius.circular(15.0),
+ ),
+ )
+ : null,
+ backgroundColor: backgroundColor,
+ child: child,
+ );
+ },
+ );
+ }
+
+ static Widget attendanceTypeCard(String title, String icon, bool isEnabled, VoidCallback onPress, BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.all(12),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(18),
+ border: Border.all(color: AppColor.white40, width: 2),
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ icon.toSvgAsset(),
+ title.heading5(context).custom(color: AppColor.neutral50),
+ ],
+ ),
+ ).onPress(
+ () {
+ log('isEnabled is ${!isEnabled}');
+ if (!isEnabled) return;
+ onPress();
+ },
+ );
+ // return Container(
+ // decoration: BoxDecoration(
+ // borderRadius: BorderRadius.circular(15),
+ // color: isEnabled ? null : Colors.grey.withOpacity(.5),
+ // gradient: isEnabled
+ // ? const LinearGradient(
+ // transform: GradientRotation(.64),
+ // begin: Alignment.topRight,
+ // end: Alignment.bottomLeft,
+ // colors: [
+ // //ToDo set Colors according to design provided by designer...
+ // Colors.blue,
+ // Colors.green,
+ // // AppColor.gradiantEndColor,
+ // // MyColors.gradiantStartColor,
+ // ],
+ // )
+ // : null,
+ // ),
+ // clipBehavior: Clip.antiAlias,
+ // padding: const EdgeInsets.only(left: 10, right: 10, top: 14, bottom: 14),
+ // child: Column(
+ // crossAxisAlignment: CrossAxisAlignment.start,
+ // children: [
+ // // SvgPicture.asset(image, color: Colors.white, alignment: Alignment.topLeft).expanded,
+ // Icon(iconData, color: isEnabled ? AppColor.black35 : Colors.grey),
+ // title.heading6(context),
+ // // title.toText17(isBold: true, color: Colors.white),
+ // ],
+ // ),
+ // ).onPress(
+ // () {
+ // log('isEnabled is ${!isEnabled}');
+ // if (!isEnabled) return;
+ // onPress();
+ // },
+ // );
+ }
+
+ //huawei permission part....
+ static void getHuaweiCurrentLocation({SwipeTypeEnum attendanceType, BuildContext context}) async {
+ try {
+ showLoading(context);
+ FusedLocationProviderClient locationService = FusedLocationProviderClient()..initFusedLocationService();
+ LocationRequest locationRequest = LocationRequest();
+ locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;
+ locationRequest.interval = 500;
+ List locationRequestList = [locationRequest];
+ LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList);
+
+ StreamSubscription _streamSubscription;
+ int requestCode = (await (locationService.requestLocationUpdates(locationRequest)));
+
+ _streamSubscription = locationService.onLocationData.listen(
+ (Location location) async {
+ hideLoading(context);
+ await locationService.removeLocationUpdates(requestCode);
+ handleSwipeOperation(swipeType: attendanceType, context: context);
+ requestCode = 0;
+ },
+ );
+
+ // locationService.checkLocationSettings(locationSettingsRequest).then((settings) async {
+ // await locationService.getLastLocation().then((value) {
+ // if (value.latitude == null || value.longitude == null) {
+ // showDialog(
+ // context: context,
+ // builder: (BuildContext cxt) => ConfirmDialog(
+ // message: "Unable to get your location, Please check your location settings & try again.",
+ // onTap: () {
+ // Navigator.pop(context);
+ // },
+ // ),
+ // );
+ // } else {
+ // if (attendanceType == "QR") {
+ // performQrCodeAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? "");
+ // }
+ // if (attendanceType == "WIFI") {
+ // performWifiAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? "");
+ // }
+ // if (attendanceType == "NFC") {
+ // performNfcAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? "");
+ // }
+ // }
+ // }).catchError((error) {
+ // log("HUAWEI LOCATION getLastLocation ERROR!!!!!");
+ // log(error);
+ // });
+ // }).catchError((error) {
+ // log("HUAWEI LOCATION checkLocationSettings ERROR!!!!!");
+ // log(error);
+ // if (error.code == "LOCATION_SETTINGS_NOT_AVAILABLE") {
+ // // Location service not enabled.
+ // }
+ // });
+ } catch (error) {
+ log("HUAWEI LOCATION ERROR!!!!!");
+ log('$error');
+ hideLoading(context);
+ // handleException(error, context, null);
+ }
+ }
+
+ static Future requestPermissions() async {
+ var result = await [
+ Permission.location,
+ ].request();
+ return (result[Permission.location] == PermissionStatus.granted || result[Permission.locationAlways] == PermissionStatus.granted);
+ }
+
+ static void checkHuaweiLocationPermission({SwipeTypeEnum attendanceType, BuildContext context}) async {
+ // Permission_Handler permissionHandler = PermissionHandler();
+ LocationUtilities.isEnabled((bool isEnabled) async {
+ if (isEnabled) {
+ LocationUtilities.havePermission((bool permission) async {
+ if (permission) {
+ getHuaweiCurrentLocation(attendanceType: attendanceType, context: context);
+ } else {
+ bool has = await requestPermissions();
+ if (has) {
+ getHuaweiCurrentLocation(attendanceType: attendanceType, context: context);
+ } else {
+ showDialog(
+ context: context,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: "You need to give location permission to mark attendance",
+ onTap: () {
+ Navigator.pop(context);
+ },
+ ),
+ );
+ }
+ }
+ });
+ } else {
+ showDialog(
+ context: context,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: "You need to enable location services to mark attendance",
+ onTap: () async {
+ Navigator.pop(context);
+ await Geolocator.openLocationSettings();
+ },
+ ),
+ );
+ }
+ });
+
+ // if (await permissionHandler.hasLocationPermission()) {
+ // getHuaweiCurrentLocation(attendanceType);
+ // } else {
+ // bool has = await requestPermissions();
+ // if (has) {
+ // getHuaweiCurrentLocation(attendanceType);
+ // } else {
+ // showDialog(
+ // context: context,
+ // builder: (BuildContext cxt) => ConfirmDialog(
+ // message: "You need to give location permission to mark attendance",
+ // onTap: () {
+ // Navigator.pop(context);
+ // },
+ // ),
+ // );
+ // }
+ // }
+ }
+
+ // general methods......
+
+ static void handleSwipeOperation({@required SwipeTypeEnum swipeType, double lat, double lang, BuildContext context}) {
+ switch (swipeType) {
+ case SwipeTypeEnum.NFC:
+ handleNfcAttendance(latitude: lat, longitude: lang, context: context);
+ return;
+ case SwipeTypeEnum.QR:
+ performQrCodeAttendance(latitude: lat, longitude: lang, context: context);
+ return;
+ case SwipeTypeEnum.Wifi:
+ //TODO need to implement.
+ return;
+ }
+ }
+
+ static String formatTimeOnly(DateTime dateTime) {
+ return DateFormat.Hms().format(dateTime);
+ }
+
+ static Future performQrCodeAttendance({double latitude, double longitude, BuildContext context}) async {
+ UserProvider userProvider = Provider.of(context, listen: false);
+ var qrCodeValue = await Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (BuildContext context) => QrScannerDialog(),
+ ),
+ );
+ if (qrCodeValue != null) {
+ showLoading(context);
+ try {
+ //test model..
+ final swipeModel = Swipe(
+ swipeTypeValue: SwipeTypeEnum.QR.getIntFromSwipeTypeEnum(),
+ value: '456',
+ latitude: 24.70865415364271,
+ longitude: 46.66600861881879,
+ );
+ // final swipeModel = Swipe(
+ // swipeTypeValue: SwipeTypeEnum.QR.getIntFromSwipeTypeEnum(),
+ // value: qrCodeValue,
+ // latitude: latitude,
+ // longitude: longitude,
+ // );
+ log('model i got to scan qr is ${swipeModel.toJson()}');
+ final swipeResponse = await userProvider.makeSwipe(model: swipeModel);
+ log('response of swipe is ${swipeResponse.toJson()}');
+
+ if (swipeResponse.isSuccess) {
+ hideLoading(context);
+ showSuccessDialog(context: context);
+ } else {
+ hideLoading(context);
+ showDialog(
+ barrierDismissible: true,
+ context: context,
+ builder: (cxt) => ConfirmDialog(
+ message: swipeResponse.message ?? "",
+ onTap: () {
+ Navigator.pop(context);
+ },
+ onCloseTap: () {},
+ ),
+ );
+ }
+ } catch (ex) {
+ log('$ex');
+ hideLoading(context);
+ //this need to confirm where it comes..
+ // handleException(ex, context, null);
+ }
+ }
+ }
+
+ static Future handleNfcAttendance({double latitude = 0, double longitude = 0, BuildContext context}) async {
+ // UserProvider _userProvider = Provider.of(context,listen:false);
+
+ if (Platform.isIOS) {
+ readNFc(onRead: (String nfcId) async {
+ await _processNfcAttendance(nfcId, latitude, longitude, context);
+ });
+ } else {
+ showNfcReader(context, onNcfScan: (String nfcId) async {
+ await _processNfcAttendance(nfcId ?? '', latitude, longitude, context);
+ });
+ }
+ }
+
+ static Future _processNfcAttendance(
+ String nfcId,
+ double latitude,
+ double longitude,
+ BuildContext context,
+ ) async {
+ showLoading(context);
+ try {
+ // final swipeModel = Swipe(
+ // swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(),
+ // value: nfcId,
+ // latitude: latitude,
+ // longitude: longitude,
+ // );
+ UserProvider userProvider = Provider.of(context, listen: false);
+ //Test model...
+
+ final swipeModel = Swipe(
+ swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(),
+ value: '123',
+ latitude: 24.70865415364271,
+ longitude: 46.66600861881879,
+ );
+ final swipeResponse = await userProvider.makeSwipe(model: swipeModel);
+
+ if (swipeResponse.isSuccess) {
+ hideLoading(context);
+ showSuccessDialog(context: context, fromDashBoard: true);
+ } else {
+ hideLoading(context);
+ showErrorDialog(message: swipeResponse.message ?? "Unexpected error occurred", context: context);
+ }
+ } catch (errSwipeGeneralUtilsor) {
+ hideLoading(context);
+ // Uncomment below line for error handling if needed
+ // handleException(error, context, null);
+ }
+ }
+
+ static void handleSwipe({
+ SwipeTypeEnum swipeType,
+ @required bool isEnable,
+ @required BuildContext context,
+ }) async {
+ if (!(await isGoogleServicesAvailable())) {
+ checkHuaweiLocationPermission(attendanceType: swipeType, context: context);
+ } else {
+ LocationUtilities.isEnabled((bool isEnabled) {
+ if (isEnabled) {
+ LocationUtilities.havePermission((bool permission) {
+ if (permission) {
+ showLoading(context);
+ LocationUtilities.getCurrentLocation(
+ (Position position, bool isMocked) {
+ if (isMocked) {
+ hideLoading(context);
+ markFakeAttendance(swipeType.name, position.latitude.toString() ?? "", position.longitude.toString() ?? "", context);
+ } else {
+ hideLoading(context);
+ handleSwipeOperation(swipeType: swipeType, lat: position.latitude, lang: position.longitude, context: context);
+ }
+ },
+ () {
+ hideLoading(context);
+ confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working.");
+ },
+ context,
+ );
+ } else {
+ showInfoDialog(
+ message: "You need to give location permission to mark attendance",
+ onTap: () async {
+ await Geolocator.openAppSettings();
+ });
+ }
+ });
+ } else {
+ showInfoDialog(
+ message: "You need to enable location services to mark attendance",
+ onTap: () async {
+ await Geolocator.openLocationSettings();
+ });
+ }
+ });
+ }
+ }
+
+ static void showInfoDialog({@required String message, VoidCallback onTap}) {
+ showDialog(
+ context: navigatorKey.currentState.overlay.context,
+ builder: (BuildContext cxt) => ConfirmDialog(
+ message: message,
+ onTap: () async {
+ Navigator.pop(navigatorKey.currentState.overlay.context);
+ onTap();
+ },
+ ),
+ );
+ }
+
+ static List availableAttendanceMethodList({@required BuildContext context, @required UserProvider userProvider, @required bool isNfcSupported}) {
+ List availableMethods = [];
+ if (userProvider.user.enableNFC) {
+ availableMethods.add(attendanceTypeCard(SwipeTypeEnum.NFC.name, 'nfc_icon', userProvider.user.enableNFC, () {
+ handleSwipe(swipeType: SwipeTypeEnum.NFC, isEnable: userProvider.user.enableNFC, context: navigatorKey.currentState.overlay.context);
+ }, context));
+ }
+ if (userProvider.user.enableQR) {
+ availableMethods.add(attendanceTypeCard(SwipeTypeEnum.QR.name, 'qr', userProvider.user.enableQR, () {
+ handleSwipe(swipeType: SwipeTypeEnum.QR, isEnable: userProvider.user.enableQR, context: navigatorKey.currentState.overlay.context);
+ }, context));
+ }
+ if (userProvider.user.enableWifi) {
+ availableMethods.add(attendanceTypeCard(SwipeTypeEnum.Wifi.name, 'wifi_icon', userProvider.user.enableWifi, () {
+ handleSwipe(swipeType: SwipeTypeEnum.Wifi, isEnable: userProvider.user.enableWifi, context: navigatorKey.currentState.overlay.context);
+ }, context));
+ }
+ return availableMethods;
+ }
+
+ static Future showSwipeTypeBottomSheetSheet({@required BuildContext context, @required bool isNfcSupported}) {
+ UserProvider _userProvider = Provider.of(context, listen: false);
+
+ return showModalBottomSheet(
+ context: context,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(
+ top: Radius.circular(20),
+ ),
+ ),
+ clipBehavior: Clip.antiAliasWithSaveLayer,
+ builder: (BuildContext context) => Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ context.translation.markAttendance.heading4(context).custom(color: AppColor.neutral80),
+ 8.height,
+ context.translation.selectMethodToMarkAttendance.bodyText2(context).custom(color: AppColor.white20),
+ 12.height,
+ GridView(
+ padding: const EdgeInsets.all(0),
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12),
+ children: availableAttendanceMethodList(context: context, userProvider: _userProvider, isNfcSupported: isNfcSupported)),
+ ],
+ ).paddingAll(16),
+ );
+ }
+
+ static void showSuccessDialog({@required BuildContext context, bool fromDashBoard}) {
+ Navigator.pushReplacementNamed(context, SwipeSuccessView.routeName);
+ // showMDialog(
+ // context,
+ // backgroundColor: Colors.transparent,
+ // isDismissable: true,
+ // child: SuccessDialog(fromDashBoard),
+ // );
+ }
+
+ static void readNFc({Function(String) onRead}) {
+ NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
+ MifareUltralight f;
+ if (Platform.isAndroid) {
+ f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
+ } else {
+ f = MifareUltralight(tag: tag, identifier: tag.data["mifare"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
+ }
+ String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join('');
+ NfcManager.instance.stopSession();
+ onRead(identifier);
+ }).catchError((err) {
+ print(err);
+ });
+ }
+
+ //HUAWEI DECISION MAKING
+ static Future isGoogleServicesAvailable() async {
+ GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
+ String status = availability.toString().split('.').last;
+ if (status == "success") {
+ return true;
+ }
+ return false;
+ }
+//
+// static bool isDate(String input, String format) {
+// try {
+// DateTime d = DateFormat(format).parseStrict(input);
+// //print(d);
+// return true;
+// } catch (e) {
+// //print(e);
+// return false;
+// }
+// }
+}
+
+
+//
+// static Widget getNoDataWidget(BuildContext context) {
+// return Column(
+// mainAxisAlignment: MainAxisAlignment.center,
+// crossAxisAlignment: CrossAxisAlignment.center,
+// children: [
+// SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0),
+// LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15),
+// ],
+// ).center;
+// }
+//
+// static Widget getNoChatWidget(BuildContext context) {
+// return Column(
+// mainAxisAlignment: MainAxisAlignment.center,
+// crossAxisAlignment: CrossAxisAlignment.center,
+// children: [
+// SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0),
+// LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15),
+// ],
+// ).center;
+// }
+//
+// static Uint8List getPostBytes(img) {
+// try {
+// var b64 = img.replaceFirst('data:image/png;base64,', '');
+// if (img != null && GeneralUtils.isBase64(b64)) return GeneralUtils.dataFromBase64String(b64);
+// } catch (e) {}
+// return Uint8List.fromList([]);
+// }
+//
+// static String getBase64FromJpeg(img) {
+// try {
+// var b64 = img.replaceFirst('data:image/jpeg;base64,', '');
+// return b64;
+// } catch (e) {}
+// return "";
+// }
+//
+// static bool isBase64(String str) {
+// RegExp _base64 = RegExp(r'^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$');
+// return _base64.hasMatch(str);
+// }
+//
+// static Uint8List dataFromBase64String(String base64String) {
+// return base64Decode(base64String);
+// }
+//
+// static Widget tableColumnTitle(String? text, {bool showDivider = true, bool alignCenter = false}) {
+// text ??= "";
+// return Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// mainAxisSize: MainAxisSize.min,
+// children: [
+// 6.height,
+// alignCenter ? text.toText12().center : text.toText12(),
+// 5.height,
+// if (showDivider)
+// const Divider(
+// height: 1,
+// color: Color(0xff2E303A),
+// thickness: 1,
+// )
+// ],
+// );
+// }
+//
+// static Decoration containerRadius(Color background, double radius) {
+// return BoxDecoration(
+// color: background,
+// border: Border.all(
+// width: 1, //
+// color: background // <--- border width here
+// ),
+// borderRadius: BorderRadius.circular(radius),
+// );
+// }
+//
+// static Widget mHeight(double h) {
+// return Container(
+// height: h,
+// );
+// }
+//
+// static Widget mDivider(Color color) {
+// return Divider(
+// // width: double.infinity,
+// height: 1,
+// color: color,
+// );
+// }
+//
+// static Widget tableColumnValue(String text, {bool isCapitable = true, bool alignCenter = false}) {
+// return Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// mainAxisSize: MainAxisSize.min,
+// children: [
+// 12.height,
+// if (alignCenter)
+// (isCapitable ? text.toLowerCase().capitalizeFirstofEach : text).toText12(color: MyColors.normalTextColor).center
+// else
+// (isCapitable ? text.toLowerCase().capitalizeFirstofEach : text).toText12(color: MyColors.normalTextColor),
+// 12.height,
+// ],
+// );
+// }
+//
+// /// EIT Forms date formats
+//
+// static String getMonthNamedFormat(DateTime date) {
+// /// it will return like "29-Sep-2022"
+// return DateFormat('dd-MMM-yyyy', "en_US").format(date);
+// }
+//
+// static String reverseFormatDate(String date) {
+// String formattedDate;
+// if (date.isNotEmpty) {
+// formattedDate = date.replaceAll('/', '-');
+// formattedDate = formattedDate.replaceAll(' 00:00:00', '');
+// } else {
+// formattedDate = date;
+// }
+// return formattedDate;
+// }
+//
+// static String formatStandardDate(String date) {
+// String formattedDate;
+// if (date.isNotEmpty) {
+// formattedDate = date.replaceAll('-', '/');
+// } else {
+// formattedDate = date;
+// }
+// return formattedDate;
+// }
+//
+// static String reverseFormatStandardDate(String date) {
+// String formattedDate;
+// if (date.isNotEmpty) {
+// formattedDate = date.replaceAll('/', '-');
+// } else {
+// formattedDate = date;
+// }
+// return formattedDate;
+// }
+//
+// static String formatDate(String date) {
+// String formattedDate;
+//
+// if (date.isNotEmpty) {
+// date = date.substring(0, 10);
+// formattedDate = date.replaceAll('-', '/');
+// formattedDate = formattedDate + ' 00:00:00';
+// } else {
+// formattedDate = date;
+// }
+// return formattedDate;
+// }
+//
+// static String formatDateNew(String date) {
+// String formattedDate;
+// if (date.isNotEmpty) {
+// formattedDate = date.split('T')[0];
+// if (!formattedDate.contains("00:00:00")) {
+// formattedDate = formattedDate + ' 00:00:00';
+// }
+// } else {
+// formattedDate = date;
+// }
+// return formattedDate;
+// }
+//
+// static String formatDateDefault(String date) {
+// if (date.isNotEmpty) {
+// if (date.toLowerCase().contains("t")) {
+// date = date.toLowerCase().split("t")[0];
+// if (!date.contains("00:00:00")) {
+// date = date + ' 00:00:00';
+// }
+// return date;
+// } else {
+// if (date.toLowerCase().split("-")[1].length == 3) {
+// return DateFormat('dd-MM-yyyy', "en_US").format(DateFormat('dd-MMM-yyyy', "en_US").parseLoose(date));
+// } else {
+// return DateFormat('dd-MM-yyyy', "en_US").format(DateFormat('yyyy-MM-dd', "en_US").parseLoose(date));
+// }
+// // return DateFormat('yyyy-MM-dd').format(DateFormat('dd-MM-yyyy').parseLoose(date));
+// }
+// } else {
+// return date;
+// }
+// }
+//
+// static Future selectDate(BuildContext context, DateTime selectedDate) async {
+// if (!Platform.isIOS) {
+// await showCupertinoModalPopup(
+// context: context,
+// builder: (BuildContext cxt) => Container(
+// height: 250,
+// color: Colors.white,
+// child: CupertinoDatePicker(
+// backgroundColor: Colors.white,
+// mode: CupertinoDatePickerMode.date,
+// onDateTimeChanged: (DateTime value) {
+// if (value != null && value != selectedDate) {
+// selectedDate = value;
+// }
+// },
+// initialDateTime: selectedDate,
+// ),
+// ),
+// );
+// } else {
+// DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate, initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2015, 8), lastDate: DateTime(2101));
+// if (picked != null && picked != selectedDate) {
+// selectedDate = picked;
+// }
+// }
+// return selectedDate;
+// }
\ No newline at end of file
diff --git a/pubspec.lock b/pubspec.lock
index d0b92c83..22f4805a 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -33,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.10.0"
+ audio_session:
+ dependency: transitive
+ description:
+ name: audio_session
+ sha256: "343e83bc7809fbda2591a49e525d6b63213ade10c76f15813be9aed6657b3261"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.21"
audioplayers:
dependency: "direct main"
description:
@@ -541,6 +549,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "10.4.0"
+ geolocator:
+ dependency: "direct main"
+ description:
+ name: geolocator
+ sha256: "5c23f3613f50586c0bbb2b8f970240ae66b3bd992088cf60dd5ee2e6f7dde3a8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "9.0.2"
+ geolocator_android:
+ dependency: transitive
+ description:
+ name: geolocator_android
+ sha256: "93906636752ea4d4e778afa981fdfe7409f545b3147046300df194330044d349"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.3.1"
+ geolocator_apple:
+ dependency: transitive
+ description:
+ name: geolocator_apple
+ sha256: "6154ea2682563f69fc0125762ed7e91e7ed85d0b9776595653be33918e064807"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.8+1"
+ geolocator_platform_interface:
+ dependency: transitive
+ description:
+ name: geolocator_platform_interface
+ sha256: b8cc1d3be0ca039a3f2174b0b026feab8af3610e220b8532e42cff8ec6658535
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.1.0"
+ geolocator_web:
+ dependency: transitive
+ description:
+ name: geolocator_web
+ sha256: "102e7da05b48ca6bf0a5bda0010f886b171d1a08059f01bfe02addd0175ebece"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.1"
+ geolocator_windows:
+ dependency: transitive
+ description:
+ name: geolocator_windows
+ sha256: "4f4218f122a6978d0ad655fa3541eea74c67417440b09f0657238810d5af6bdc"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.3"
google_api_availability:
dependency: "direct main"
description:
@@ -589,6 +645,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
+ huawei_location:
+ dependency: "direct main"
+ description:
+ name: huawei_location
+ sha256: db937f0df4073ba6f3cdc1005855ee231aaf6bf5c2bd05a702d928d7e8bb4ee9
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.12.0+303"
huawei_push:
dependency: "direct main"
description:
@@ -717,6 +781,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.8.1"
+ just_audio:
+ dependency: "direct main"
+ description:
+ name: just_audio
+ sha256: b7cb6bbf3750caa924d03f432ba401ec300fd90936b3f73a9b33d58b1e96286b
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.9.37"
+ just_audio_platform_interface:
+ dependency: transitive
+ description:
+ name: just_audio_platform_interface
+ sha256: "0243828cce503c8366cc2090cefb2b3c871aa8ed2f520670d76fd47aa1ab2790"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.3.0"
+ just_audio_web:
+ dependency: transitive
+ description:
+ name: just_audio_web
+ sha256: "134356b0fe3d898293102b33b5fd618831ffdc72bb7a1b726140abdf22772b70"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.4.9"
lints:
dependency: transitive
description:
@@ -829,6 +917,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
+ nfc_manager:
+ dependency: "direct main"
+ description:
+ name: nfc_manager
+ sha256: f5be75e90f8f2bff3ee49fbd7ef65bdd4a86ee679c2412e71ab2846a8cff8c59
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.5.0"
octo_image:
dependency: transitive
description:
@@ -981,6 +1077,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.1.0"
+ pinput:
+ dependency: "direct main"
+ description:
+ name: pinput
+ sha256: "7bf9aa7d0eeb3da9f7d49d2087c7bc7d36cd277d2e94cc31c6da52e1ebb048d0"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.0.0"
platform:
dependency: transitive
description:
@@ -1069,6 +1173,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.27.7"
+ safe_device:
+ dependency: "direct main"
+ description:
+ name: safe_device
+ sha256: ae53e6ad4b7e3a9a89c3317636b52babd5916a6bf8c1e83ca82264cf82f6b2cc
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.9"
share:
dependency: "direct main"
description:
@@ -1306,6 +1418,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.2"
+ universal_platform:
+ dependency: transitive
+ description:
+ name: universal_platform
+ sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
url_launcher:
dependency: "direct main"
description:
@@ -1386,6 +1506,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
+ wifi_iot:
+ dependency: "direct main"
+ description:
+ name: wifi_iot
+ sha256: "4a3301f71663a908bb50ffe6d9dc9e8b8383fab48368accf978409bde96e9aca"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.19+1"
win32:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index e0204a23..13b2ef8a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -80,6 +80,13 @@ dependencies:
local_auth: ^2.1.6
google_api_availability: ^5.0.0
huawei_push: ^6.12.0+302
+ huawei_location: ^6.11.0+301
+ geolocator: ^9.0.2
+ nfc_manager: ^3.2.0
+ wifi_iot: ^0.3.19+1
+ just_audio: ^0.9.30
+ pinput:
+ safe_device: ^1.1.9
dev_dependencies:
flutter_test:
@@ -113,6 +120,7 @@ flutter:
- assets/subtitles/
- assets/rives/
- assets/translations/
+ - assets/audio/
fonts:
- family: Swiss
fonts: