From fd6b5dc83ae311367aaede798e2a47910dd67fcc Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Mon, 30 Dec 2024 11:42:26 +0300 Subject: [PATCH] add swipe and forget password functionality ready for initial test --- android/key.properties | 3 +- assets/audio/success_tone_android.mp3 | Bin 0 -> 21741 bytes assets/audio/success_tone_ios.caf | Bin 0 -> 254144 bytes assets/images/ic_done.png | Bin 0 -> 18338 bytes assets/images/ic_nfc.png | Bin 0 -> 19686 bytes assets/images/nfc_icon.svg | 12 + assets/images/success_swipe.svg | 11 + assets/images/swipe.svg | 8 + assets/images/swipe_success.svg | 14 + assets/images/wifi_icon.svg | 5 + assets/lottie/done.json | 1 + lib/controllers/api_routes/api_manager.dart | 31 + lib/controllers/api_routes/urls.dart | 8 + .../providers/api/user_provider.dart | 187 ++++ lib/l10n/app_ar.arb | 13 + lib/l10n/app_en.arb | 12 + lib/main.dart | 4 + lib/models/user.dart | 19 + lib/new_views/app_style/app_color.dart | 11 + .../common_widgets/app_bottom_nav_bar.dart | 6 +- .../common_widgets/app_text_form_field.dart | 3 + .../forget_passwod_verify_otp.dart | 300 ++++++ .../models/general_response_model.dart | 32 + .../models/update_password.dart | 24 + .../models/verify_otp_model.dart | 41 + .../reset_password_view.dart | 148 +++ lib/new_views/pages/land_page/land_page.dart | 134 ++- .../pages/land_page/nfc/nfc_reader_sheet.dart | 203 ++++ .../land_page/widgets/dialogs/dialog.dart | 35 + lib/new_views/pages/login_page.dart | 37 +- lib/new_views/pages/splash_page.dart | 42 +- lib/new_views/pages/usSafeDevice_view.dart | 80 ++ .../swipe_module/dialoge/confirm_dialog.dart | 62 ++ .../dialoge/qr_scanner_dialog.dart | 79 ++ .../swipe_module/dialoge/success_dialog.dart | 76 ++ .../swipe_module/enums/swipe_type.dart | 18 + .../swipe_module/mark_attendance_widget.dart | 851 ++++++++++++++++ .../swipe_module/models/swipe_model.dart | 68 ++ .../models/swipe_transaction_model.dart | 47 + .../non_hmg_employee_swipe_view.dart | 84 ++ .../swipe_module/swipe_success_view.dart | 116 +++ .../swipe_module/utils/location_utils.dart | 67 ++ .../utils/swipe_general_utils.dart | 909 ++++++++++++++++++ pubspec.lock | 128 +++ pubspec.yaml | 8 + 45 files changed, 3894 insertions(+), 43 deletions(-) create mode 100644 assets/audio/success_tone_android.mp3 create mode 100644 assets/audio/success_tone_ios.caf create mode 100644 assets/images/ic_done.png create mode 100644 assets/images/ic_nfc.png create mode 100644 assets/images/nfc_icon.svg create mode 100644 assets/images/success_swipe.svg create mode 100644 assets/images/swipe.svg create mode 100644 assets/images/swipe_success.svg create mode 100644 assets/images/wifi_icon.svg create mode 100644 assets/lottie/done.json create mode 100644 lib/new_views/forget_password_module/forget_passwod_verify_otp.dart create mode 100644 lib/new_views/forget_password_module/models/general_response_model.dart create mode 100644 lib/new_views/forget_password_module/models/update_password.dart create mode 100644 lib/new_views/forget_password_module/models/verify_otp_model.dart create mode 100644 lib/new_views/forget_password_module/reset_password_view.dart create mode 100644 lib/new_views/pages/land_page/nfc/nfc_reader_sheet.dart create mode 100644 lib/new_views/pages/land_page/widgets/dialogs/dialog.dart create mode 100644 lib/new_views/pages/usSafeDevice_view.dart create mode 100644 lib/new_views/swipe_module/dialoge/confirm_dialog.dart create mode 100644 lib/new_views/swipe_module/dialoge/qr_scanner_dialog.dart create mode 100644 lib/new_views/swipe_module/dialoge/success_dialog.dart create mode 100644 lib/new_views/swipe_module/enums/swipe_type.dart create mode 100644 lib/new_views/swipe_module/mark_attendance_widget.dart create mode 100644 lib/new_views/swipe_module/models/swipe_model.dart create mode 100644 lib/new_views/swipe_module/models/swipe_transaction_model.dart create mode 100644 lib/new_views/swipe_module/non_hmg_employee_swipe_view.dart create mode 100644 lib/new_views/swipe_module/swipe_success_view.dart create mode 100644 lib/new_views/swipe_module/utils/location_utils.dart create mode 100644 lib/new_views/swipe_module/utils/swipe_general_utils.dart 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 0000000000000000000000000000000000000000..b8ad93f95e2b4628ce07ba6493e9f7f96584d660 GIT binary patch literal 21741 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 z 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 literal 0 HcmV?d00001 diff --git a/assets/images/ic_done.png b/assets/images/ic_done.png new file mode 100644 index 0000000000000000000000000000000000000000..5b802855ce8942032b0948c1fdaa56e885b4c78e GIT binary patch literal 18338 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 literal 0 HcmV?d00001 diff --git a/assets/images/ic_nfc.png b/assets/images/ic_nfc.png new file mode 100644 index 0000000000000000000000000000000000000000..274e1b8c0d81daca3127e8a2b6d0522b43d6bb8d GIT binary patch literal 19686 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 literal 0 HcmV?d00001 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: