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: