From b10523dac35ef32a2c8c75815b476d103c30000a Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 9 Sep 2025 17:41:05 +0300 Subject: [PATCH] Online CheckIn implementation contd. --- assets/animations/lottie/ErrorAnimation.json | 1 + lib/core/api/api_client.dart | 292 +++++++++--------- lib/core/app_assets.dart | 1 + lib/core/utils/utils.dart | 13 + .../my_appointments/my_appointments_repo.dart | 45 +++ .../my_appointments_view_model.dart | 24 ++ .../appointment_details_page.dart | 1 + .../appointment_checkin_bottom_sheet.dart | 108 ++++++- .../widgets/appointment_queueing_screen.dart | 0 lib/widgets/nfc/nfc_reader_sheet.dart | 212 +++++++++++++ pubspec.yaml | 2 + 11 files changed, 546 insertions(+), 153 deletions(-) create mode 100644 assets/animations/lottie/ErrorAnimation.json create mode 100644 lib/presentation/appointments/widgets/appointment_queueing_screen.dart create mode 100644 lib/widgets/nfc/nfc_reader_sheet.dart diff --git a/assets/animations/lottie/ErrorAnimation.json b/assets/animations/lottie/ErrorAnimation.json new file mode 100644 index 0000000..a9fc775 --- /dev/null +++ b/assets/animations/lottie/ErrorAnimation.json @@ -0,0 +1 @@ +{"nm":"Bouncy Fail","ddd":0,"h":512,"w":512,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"X line 2","sr":1,"st":0,"op":60,"ip":26,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[41,-3,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256,256,0],"ix":2},"r":{"a":0,"k":90,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[112,-74],[-30,68]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":2,"ml":1,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8863,0.1176,0.1882],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[100],"t":26},{"s":[0],"t":40}],"ix":1},"m":1}],"ind":1},{"ty":4,"nm":"X line 1","sr":1,"st":0,"op":60,"ip":26,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[41,-3,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256,256,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[112,-74],[-30,68]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":2,"ml":1,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8863,0.1176,0.1882],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":26},{"s":[100],"t":40}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1}],"ind":2},{"ty":4,"nm":"Circle 2","sr":1,"st":0,"op":360,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[140.061,140.061,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.667,"y":1},"s":[0,0,100],"t":10},{"s":[140,140,100],"t":20}],"ix":6,"x":"var $bm_rt;\nvar scaleInertialBounce, scaleBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\nscaleInertialBounce = effect('Bounce & Drop - ukramedia.com')(16);\nscaleBounceBack = effect('Bounce & Drop - ukramedia.com')(17);\ntry {\n if (scaleInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(19);\n freq = effect('Bounce & Drop - ukramedia.com')(20);\n decay = effect('Bounce & Drop - ukramedia.com')(21);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (scaleBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(24);\n g = effect('Bounce & Drop - ukramedia.com')(25);\n nMax = effect('Bounce & Drop - ukramedia.com')(26);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256,256,0],"ix":2,"x":"var $bm_rt;\nvar positionInertialBounce, positionBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\npositionInertialBounce = effect('Bounce & Drop - ukramedia.com')(2);\npositionBounceBack = effect('Bounce & Drop - ukramedia.com')(3);\ntry {\n if (positionInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(5);\n freq = effect('Bounce & Drop - ukramedia.com')(6);\n decay = effect('Bounce & Drop - ukramedia.com')(7);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (positionBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(10);\n g = effect('Bounce & Drop - ukramedia.com')(11);\n nMax = effect('Bounce & Drop - ukramedia.com')(12);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"},"r":{"a":0,"k":0,"ix":10,"x":"var $bm_rt;\nvar rotationInertialBounce, rotationBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\nrotationInertialBounce = effect('Bounce & Drop - ukramedia.com')(30);\nrotationBounceBack = effect('Bounce & Drop - ukramedia.com')(31);\ntry {\n if (rotationInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(33);\n freq = effect('Bounce & Drop - ukramedia.com')(34);\n decay = effect('Bounce & Drop - ukramedia.com')(35);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (rotationBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(38);\n g = effect('Bounce & Drop - ukramedia.com')(39);\n nMax = effect('Bounce & Drop - ukramedia.com')(40);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11,"x":"var $bm_rt;\nvar opacityInertialBounce, opacityBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\nopacityInertialBounce = effect('Bounce & Drop - ukramedia.com')(44);\nopacityBounceBack = effect('Bounce & Drop - ukramedia.com')(45);\ntry {\n if (opacityInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(47);\n freq = effect('Bounce & Drop - ukramedia.com')(48);\n decay = effect('Bounce & Drop - ukramedia.com')(49);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (opacityBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(52);\n g = effect('Bounce & Drop - ukramedia.com')(53);\n nMax = effect('Bounce & Drop - ukramedia.com')(54);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"}},"ef":[{"ty":5,"mn":"Pseudo/animationControl","nm":"Bounce & Drop - ukramedia.com","ix":1,"en":1,"ef":[{"ty":6,"mn":"Pseudo/animationControl-0001","nm":"Position","ix":1,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0002","nm":"Enable Inertial Bounce","ix":2,"v":{"a":0,"k":0,"ix":2}},{"ty":7,"mn":"Pseudo/animationControl-0003","nm":"Enable Bounce Back","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":6,"mn":"Pseudo/animationControl-0004","nm":"Inertial Bounce Options","ix":4,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0005","nm":"Amplitude","ix":5,"v":{"a":0,"k":0.05,"ix":5}},{"ty":0,"mn":"Pseudo/animationControl-0006","nm":"Frequency","ix":6,"v":{"a":0,"k":4,"ix":6}},{"ty":0,"mn":"Pseudo/animationControl-0007","nm":"Decay","ix":7,"v":{"a":0,"k":8,"ix":7}},{"ty":6,"mn":"Pseudo/animationControl-0008","nm":"","ix":8,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0009","nm":"Bounce Back Options","ix":9,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0010","nm":"Elasticity","ix":10,"v":{"a":0,"k":0.7,"ix":10}},{"ty":0,"mn":"Pseudo/animationControl-0011","nm":"Gravity","ix":11,"v":{"a":0,"k":5000,"ix":11}},{"ty":0,"mn":"Pseudo/animationControl-0012","nm":"nMax","ix":12,"v":{"a":0,"k":9,"ix":12}},{"ty":6,"mn":"Pseudo/animationControl-0013","nm":"","ix":13,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0014","nm":"","ix":14,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0015","nm":"Scale","ix":15,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0016","nm":"Enable Inertial Bounce","ix":16,"v":{"a":0,"k":1,"ix":16}},{"ty":7,"mn":"Pseudo/animationControl-0017","nm":"Enable Bounce Back","ix":17,"v":{"a":0,"k":0,"ix":17}},{"ty":6,"mn":"Pseudo/animationControl-0018","nm":"Inertial Bounce Options","ix":18,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0019","nm":"Amplitude","ix":19,"v":{"a":0,"k":0.8,"ix":19}},{"ty":0,"mn":"Pseudo/animationControl-0020","nm":"Frequency","ix":20,"v":{"a":0,"k":4,"ix":20}},{"ty":0,"mn":"Pseudo/animationControl-0021","nm":"Decay","ix":21,"v":{"a":0,"k":8,"ix":21}},{"ty":6,"mn":"Pseudo/animationControl-0022","nm":"","ix":22,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0023","nm":"Bounce Back Options","ix":23,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0024","nm":"Elasticity","ix":24,"v":{"a":0,"k":0.7,"ix":24}},{"ty":0,"mn":"Pseudo/animationControl-0025","nm":"Gravity","ix":25,"v":{"a":0,"k":5000,"ix":25}},{"ty":0,"mn":"Pseudo/animationControl-0026","nm":"nMax","ix":26,"v":{"a":0,"k":9,"ix":26}},{"ty":6,"mn":"Pseudo/animationControl-0027","nm":"","ix":27,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0028","nm":"","ix":28,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0029","nm":"Rotation","ix":29,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0030","nm":"Enable Inertial Bounce","ix":30,"v":{"a":0,"k":0,"ix":30}},{"ty":7,"mn":"Pseudo/animationControl-0031","nm":"Enable Bounce Back","ix":31,"v":{"a":0,"k":0,"ix":31}},{"ty":6,"mn":"Pseudo/animationControl-0032","nm":"Inertial Bounce Options","ix":32,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0033","nm":"Amplitude","ix":33,"v":{"a":0,"k":0.05,"ix":33}},{"ty":0,"mn":"Pseudo/animationControl-0034","nm":"Frequency","ix":34,"v":{"a":0,"k":4,"ix":34}},{"ty":0,"mn":"Pseudo/animationControl-0035","nm":"Decay","ix":35,"v":{"a":0,"k":8,"ix":35}},{"ty":6,"mn":"Pseudo/animationControl-0036","nm":"","ix":36,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0037","nm":"Bounce Back Options","ix":37,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0038","nm":"Elasticity","ix":38,"v":{"a":0,"k":0.7,"ix":38}},{"ty":0,"mn":"Pseudo/animationControl-0039","nm":"Gravity","ix":39,"v":{"a":0,"k":5000,"ix":39}},{"ty":0,"mn":"Pseudo/animationControl-0040","nm":"nMax","ix":40,"v":{"a":0,"k":9,"ix":40}},{"ty":6,"mn":"Pseudo/animationControl-0041","nm":"","ix":41,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0042","nm":"","ix":42,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0043","nm":"Opacity","ix":43,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0044","nm":"Enable Inertial Bounce","ix":44,"v":{"a":0,"k":0,"ix":44}},{"ty":7,"mn":"Pseudo/animationControl-0045","nm":"Enable Bounce Back","ix":45,"v":{"a":0,"k":0,"ix":45}},{"ty":6,"mn":"Pseudo/animationControl-0046","nm":"Inertial Bounce Options","ix":46,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0047","nm":"Amplitude","ix":47,"v":{"a":0,"k":0.05,"ix":47}},{"ty":0,"mn":"Pseudo/animationControl-0048","nm":"Frequency","ix":48,"v":{"a":0,"k":4,"ix":48}},{"ty":0,"mn":"Pseudo/animationControl-0049","nm":"Decay","ix":49,"v":{"a":0,"k":8,"ix":49}},{"ty":6,"mn":"Pseudo/animationControl-0050","nm":"","ix":50,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0051","nm":"Bounce Back Options","ix":51,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0052","nm":"Elasticity","ix":52,"v":{"a":0,"k":0.7,"ix":52}},{"ty":0,"mn":"Pseudo/animationControl-0053","nm":"Gravity","ix":53,"v":{"a":0,"k":5000,"ix":53}},{"ty":0,"mn":"Pseudo/animationControl-0054","nm":"nMax","ix":54,"v":{"a":0,"k":9,"ix":54}},{"ty":6,"mn":"Pseudo/animationControl-0055","nm":"","ix":55,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0056","nm":"","ix":56,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0057","nm":"Global Inertial Bounce Options","ix":57,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0058","nm":"Enable Global Inertial Bounce","ix":58,"v":{"a":0,"k":0,"ix":58}},{"ty":0,"mn":"Pseudo/animationControl-0059","nm":"Amplitude","ix":59,"v":{"a":0,"k":0.05,"ix":59}},{"ty":0,"mn":"Pseudo/animationControl-0060","nm":"Frequency","ix":60,"v":{"a":0,"k":4,"ix":60}},{"ty":0,"mn":"Pseudo/animationControl-0061","nm":"Decay","ix":61,"v":{"a":0,"k":8,"ix":61}},{"ty":6,"mn":"Pseudo/animationControl-0062","nm":"","ix":62,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0063","nm":"Global Bounce Back Options","ix":63,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0064","nm":"Enable Global Bounce Back","ix":64,"v":{"a":0,"k":0,"ix":64}},{"ty":0,"mn":"Pseudo/animationControl-0065","nm":"Elasticity","ix":65,"v":{"a":0,"k":0.7,"ix":65}},{"ty":0,"mn":"Pseudo/animationControl-0066","nm":"Gravity","ix":66,"v":{"a":0,"k":5000,"ix":66}},{"ty":0,"mn":"Pseudo/animationControl-0067","nm":"nMax","ix":67,"v":{"a":0,"k":9,"ix":67}},{"ty":6,"mn":"Pseudo/animationControl-0068","nm":"","ix":68,"v":0}]}],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-77.215],[77.216,0],[0,77.215],[-77.215,0]],"o":[[0,77.215],[-77.215,0],[0,-77.215],[77.216,0]],"v":[[139.811,0],[0,139.811],[-139.811,0],[0,-139.811]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8863,0.1176,0.1882],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[140.061,140.061],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"Circle 1","sr":1,"st":0,"op":360,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[140.061,140.061,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.667,"y":1},"s":[0,0,100],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.667,"y":1},"s":[132,132,100],"t":10},{"o":{"x":0.167,"y":0.167},"i":{"x":0.667,"y":1},"s":[130,130,100],"t":35},{"s":[175,175,100],"t":55}],"ix":6,"x":"var $bm_rt;\nvar scaleInertialBounce, scaleBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\nscaleInertialBounce = effect('Bounce & Drop - ukramedia.com')(16);\nscaleBounceBack = effect('Bounce & Drop - ukramedia.com')(17);\ntry {\n if (scaleInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(19);\n freq = effect('Bounce & Drop - ukramedia.com')(20);\n decay = effect('Bounce & Drop - ukramedia.com')(21);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (scaleBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(24);\n g = effect('Bounce & Drop - ukramedia.com')(25);\n nMax = effect('Bounce & Drop - ukramedia.com')(26);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256,256,0],"ix":2,"x":"var $bm_rt;\nvar positionInertialBounce, positionBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\npositionInertialBounce = effect('Bounce & Drop - ukramedia.com')(2);\npositionBounceBack = effect('Bounce & Drop - ukramedia.com')(3);\ntry {\n if (positionInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(5);\n freq = effect('Bounce & Drop - ukramedia.com')(6);\n decay = effect('Bounce & Drop - ukramedia.com')(7);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (positionBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(10);\n g = effect('Bounce & Drop - ukramedia.com')(11);\n nMax = effect('Bounce & Drop - ukramedia.com')(12);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"},"r":{"a":0,"k":0,"ix":10,"x":"var $bm_rt;\nvar rotationInertialBounce, rotationBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\nrotationInertialBounce = effect('Bounce & Drop - ukramedia.com')(30);\nrotationBounceBack = effect('Bounce & Drop - ukramedia.com')(31);\ntry {\n if (rotationInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(33);\n freq = effect('Bounce & Drop - ukramedia.com')(34);\n decay = effect('Bounce & Drop - ukramedia.com')(35);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (rotationBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(38);\n g = effect('Bounce & Drop - ukramedia.com')(39);\n nMax = effect('Bounce & Drop - ukramedia.com')(40);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.667,"y":1},"s":[50],"t":41.25},{"s":[0],"t":55}],"ix":11,"x":"var $bm_rt;\nvar opacityInertialBounce, opacityBounceBack, n, n, t, t, v, amp, freq, decay, v, amp, freq, decay, e, g, nMax, e, g, nMax, n, n, t, v, vl, vu, vu, tCur, segDur, tNext, nb, delta;\nopacityInertialBounce = effect('Bounce & Drop - ukramedia.com')(44);\nopacityBounceBack = effect('Bounce & Drop - ukramedia.com')(45);\ntry {\n if (opacityInertialBounce == 1) {\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n }\n if (n == 0) {\n $bm_rt = t = 0;\n } else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n }\n if (effect('Bounce & Drop - ukramedia.com')(58) == 1) {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(59);\n freq = effect('Bounce & Drop - ukramedia.com')(60);\n decay = effect('Bounce & Drop - ukramedia.com')(61);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n } else {\n if (n > 0 && t < 1) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = effect('Bounce & Drop - ukramedia.com')(47);\n freq = effect('Bounce & Drop - ukramedia.com')(48);\n decay = effect('Bounce & Drop - ukramedia.com')(49);\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n } else {\n $bm_rt = value;\n }\n }\n } else if (opacityBounceBack == 1) {\n if (effect('Bounce & Drop - ukramedia.com')(64) == 1) {\n e = effect('Bounce & Drop - ukramedia.com')(65);\n g = effect('Bounce & Drop - ukramedia.com')(66);\n nMax = effect('Bounce & Drop - ukramedia.com')(67);\n } else {\n e = effect('Bounce & Drop - ukramedia.com')(52);\n g = effect('Bounce & Drop - ukramedia.com')(53);\n nMax = effect('Bounce & Drop - ukramedia.com')(54);\n }\n $bm_rt = n = 0;\n if (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n }\n if (n > 0) {\n t = $bm_sub(time, key(n).time);\n v = $bm_mul($bm_neg(velocityAtTime($bm_sub(key(n).time, 0.001))), e);\n vl = length(v);\n if ($bm_isInstanceOfArray(value)) {\n vu = vl > 0 ? normalize(v) : [\n 0,\n 0,\n 0\n ];\n } else {\n vu = v < 0 ? -1 : 1;\n }\n tCur = 0;\n segDur = $bm_div($bm_mul(2, vl), g);\n tNext = segDur;\n nb = 1;\n while (tNext < t && nb <= nMax) {\n vl *= e;\n segDur *= e;\n tCur = tNext;\n tNext = $bm_sum(tNext, segDur);\n nb++;\n }\n if (nb <= nMax) {\n delta = $bm_sub(t, tCur);\n $bm_rt = $bm_sum(value, $bm_mul($bm_mul(vu, delta), $bm_sub(vl, $bm_div($bm_mul(g, delta), 2))));\n } else {\n $bm_rt = value;\n }\n } else\n $bm_rt = value;\n } else {\n $bm_rt = value;\n }\n} catch (err) {\n $bm_rt = value;\n}"}},"ef":[{"ty":5,"mn":"Pseudo/animationControl","nm":"Bounce & Drop - ukramedia.com","ix":1,"en":1,"ef":[{"ty":6,"mn":"Pseudo/animationControl-0001","nm":"Position","ix":1,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0002","nm":"Enable Inertial Bounce","ix":2,"v":{"a":0,"k":0,"ix":2}},{"ty":7,"mn":"Pseudo/animationControl-0003","nm":"Enable Bounce Back","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":6,"mn":"Pseudo/animationControl-0004","nm":"Inertial Bounce Options","ix":4,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0005","nm":"Amplitude","ix":5,"v":{"a":0,"k":0.05,"ix":5}},{"ty":0,"mn":"Pseudo/animationControl-0006","nm":"Frequency","ix":6,"v":{"a":0,"k":4,"ix":6}},{"ty":0,"mn":"Pseudo/animationControl-0007","nm":"Decay","ix":7,"v":{"a":0,"k":8,"ix":7}},{"ty":6,"mn":"Pseudo/animationControl-0008","nm":"","ix":8,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0009","nm":"Bounce Back Options","ix":9,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0010","nm":"Elasticity","ix":10,"v":{"a":0,"k":0.7,"ix":10}},{"ty":0,"mn":"Pseudo/animationControl-0011","nm":"Gravity","ix":11,"v":{"a":0,"k":5000,"ix":11}},{"ty":0,"mn":"Pseudo/animationControl-0012","nm":"nMax","ix":12,"v":{"a":0,"k":9,"ix":12}},{"ty":6,"mn":"Pseudo/animationControl-0013","nm":"","ix":13,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0014","nm":"","ix":14,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0015","nm":"Scale","ix":15,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0016","nm":"Enable Inertial Bounce","ix":16,"v":{"a":0,"k":1,"ix":16}},{"ty":7,"mn":"Pseudo/animationControl-0017","nm":"Enable Bounce Back","ix":17,"v":{"a":0,"k":0,"ix":17}},{"ty":6,"mn":"Pseudo/animationControl-0018","nm":"Inertial Bounce Options","ix":18,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0019","nm":"Amplitude","ix":19,"v":{"a":0,"k":0.8,"ix":19}},{"ty":0,"mn":"Pseudo/animationControl-0020","nm":"Frequency","ix":20,"v":{"a":0,"k":4,"ix":20}},{"ty":0,"mn":"Pseudo/animationControl-0021","nm":"Decay","ix":21,"v":{"a":0,"k":8,"ix":21}},{"ty":6,"mn":"Pseudo/animationControl-0022","nm":"","ix":22,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0023","nm":"Bounce Back Options","ix":23,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0024","nm":"Elasticity","ix":24,"v":{"a":0,"k":0.7,"ix":24}},{"ty":0,"mn":"Pseudo/animationControl-0025","nm":"Gravity","ix":25,"v":{"a":0,"k":5000,"ix":25}},{"ty":0,"mn":"Pseudo/animationControl-0026","nm":"nMax","ix":26,"v":{"a":0,"k":9,"ix":26}},{"ty":6,"mn":"Pseudo/animationControl-0027","nm":"","ix":27,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0028","nm":"","ix":28,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0029","nm":"Rotation","ix":29,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0030","nm":"Enable Inertial Bounce","ix":30,"v":{"a":0,"k":0,"ix":30}},{"ty":7,"mn":"Pseudo/animationControl-0031","nm":"Enable Bounce Back","ix":31,"v":{"a":0,"k":0,"ix":31}},{"ty":6,"mn":"Pseudo/animationControl-0032","nm":"Inertial Bounce Options","ix":32,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0033","nm":"Amplitude","ix":33,"v":{"a":0,"k":0.05,"ix":33}},{"ty":0,"mn":"Pseudo/animationControl-0034","nm":"Frequency","ix":34,"v":{"a":0,"k":4,"ix":34}},{"ty":0,"mn":"Pseudo/animationControl-0035","nm":"Decay","ix":35,"v":{"a":0,"k":8,"ix":35}},{"ty":6,"mn":"Pseudo/animationControl-0036","nm":"","ix":36,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0037","nm":"Bounce Back Options","ix":37,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0038","nm":"Elasticity","ix":38,"v":{"a":0,"k":0.7,"ix":38}},{"ty":0,"mn":"Pseudo/animationControl-0039","nm":"Gravity","ix":39,"v":{"a":0,"k":5000,"ix":39}},{"ty":0,"mn":"Pseudo/animationControl-0040","nm":"nMax","ix":40,"v":{"a":0,"k":9,"ix":40}},{"ty":6,"mn":"Pseudo/animationControl-0041","nm":"","ix":41,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0042","nm":"","ix":42,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0043","nm":"Opacity","ix":43,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0044","nm":"Enable Inertial Bounce","ix":44,"v":{"a":0,"k":0,"ix":44}},{"ty":7,"mn":"Pseudo/animationControl-0045","nm":"Enable Bounce Back","ix":45,"v":{"a":0,"k":0,"ix":45}},{"ty":6,"mn":"Pseudo/animationControl-0046","nm":"Inertial Bounce Options","ix":46,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0047","nm":"Amplitude","ix":47,"v":{"a":0,"k":0.05,"ix":47}},{"ty":0,"mn":"Pseudo/animationControl-0048","nm":"Frequency","ix":48,"v":{"a":0,"k":4,"ix":48}},{"ty":0,"mn":"Pseudo/animationControl-0049","nm":"Decay","ix":49,"v":{"a":0,"k":8,"ix":49}},{"ty":6,"mn":"Pseudo/animationControl-0050","nm":"","ix":50,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0051","nm":"Bounce Back Options","ix":51,"v":0},{"ty":0,"mn":"Pseudo/animationControl-0052","nm":"Elasticity","ix":52,"v":{"a":0,"k":0.7,"ix":52}},{"ty":0,"mn":"Pseudo/animationControl-0053","nm":"Gravity","ix":53,"v":{"a":0,"k":5000,"ix":53}},{"ty":0,"mn":"Pseudo/animationControl-0054","nm":"nMax","ix":54,"v":{"a":0,"k":9,"ix":54}},{"ty":6,"mn":"Pseudo/animationControl-0055","nm":"","ix":55,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0056","nm":"","ix":56,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0057","nm":"Global Inertial Bounce Options","ix":57,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0058","nm":"Enable Global Inertial Bounce","ix":58,"v":{"a":0,"k":0,"ix":58}},{"ty":0,"mn":"Pseudo/animationControl-0059","nm":"Amplitude","ix":59,"v":{"a":0,"k":0.05,"ix":59}},{"ty":0,"mn":"Pseudo/animationControl-0060","nm":"Frequency","ix":60,"v":{"a":0,"k":4,"ix":60}},{"ty":0,"mn":"Pseudo/animationControl-0061","nm":"Decay","ix":61,"v":{"a":0,"k":8,"ix":61}},{"ty":6,"mn":"Pseudo/animationControl-0062","nm":"","ix":62,"v":0},{"ty":6,"mn":"Pseudo/animationControl-0063","nm":"Global Bounce Back Options","ix":63,"v":0},{"ty":7,"mn":"Pseudo/animationControl-0064","nm":"Enable Global Bounce Back","ix":64,"v":{"a":0,"k":0,"ix":64}},{"ty":0,"mn":"Pseudo/animationControl-0065","nm":"Elasticity","ix":65,"v":{"a":0,"k":0.7,"ix":65}},{"ty":0,"mn":"Pseudo/animationControl-0066","nm":"Gravity","ix":66,"v":{"a":0,"k":5000,"ix":66}},{"ty":0,"mn":"Pseudo/animationControl-0067","nm":"nMax","ix":67,"v":{"a":0,"k":9,"ix":67}},{"ty":6,"mn":"Pseudo/animationControl-0068","nm":"","ix":68,"v":0}]}],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-77.215],[77.216,0],[0,77.215],[-77.215,0]],"o":[[0,77.215],[-77.215,0],[0,-77.215],[77.216,0]],"v":[[139.811,0],[0,139.811],[-139.811,0],[0,-139.811]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8863,0.1176,0.1882],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[140.061,140.061],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4}],"v":"5.7.11","fr":30,"op":60,"ip":0,"assets":[]} \ No newline at end of file diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 7555400..2fd8082 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -17,6 +17,7 @@ import '../exceptions/api_failure.dart'; abstract class ApiClient { static final NavigationService _navigationService = getIt.get(); + Future post( String endPoint, { required Map body, @@ -93,7 +94,7 @@ class ApiClientImp implements ApiClient { required Map body, required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess, required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, - bool isAllowAny = true, + bool isAllowAny = false, bool isExternal = false, bool isRCService = false, bool bypassConnectionCheck = false, @@ -109,187 +110,186 @@ class ApiClientImp implements ApiClient { } } // try { - var user = _appState.getAuthenticatedUser(); - Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; - if (!isExternal) { - String? token = _appState.appAuthToken; + var user = _appState.getAuthenticatedUser(); + Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; + if (!isExternal) { + String? token = _appState.appAuthToken; - if (body.containsKey('SetupID')) { - body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] ?? body[''] : SETUP_ID; - } else {} + if (body.containsKey('SetupID')) { + body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] ?? body[''] : SETUP_ID; + } else {} - if (body.containsKey('isDentalAllowedBackend')) { - body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; - } + if (body.containsKey('isDentalAllowedBackend')) { + body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; + } - if (!body.containsKey('IsPublicRequest')) { - // if (!body.containsKey('PatientType')) { - if (user != null && user.patientType != null) { - body['PatientType'] = user.patientType; - } else { - body['PatientType'] = PATIENT_TYPE.toString(); - } + if (!body.containsKey('IsPublicRequest')) { + // if (!body.containsKey('PatientType')) { + if (user != null && user.patientType != null) { + body['PatientType'] = user.patientType; + } else { + body['PatientType'] = PATIENT_TYPE.toString(); + } - if (user != null && user.patientType != null) { - body['PatientTypeID'] = user.patientType; - } else { - body['PatientType'] = PATIENT_TYPE_ID.toString(); - } + if (user != null && user.patientType != null) { + body['PatientTypeID'] = user.patientType; + } else { + body['PatientType'] = PATIENT_TYPE_ID.toString(); + } - // TODO : These should be from the appState - if (user != null) { - body['TokenID'] = body['TokenID'] ?? token; - body['PatientID'] = body['PatientID'] ?? user.patientId; + // TODO : These should be from the appState + if (user != null) { + body['TokenID'] = body['TokenID'] ?? token; + body['PatientID'] = body['PatientID'] ?? user.patientId; - body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] ?? user.outSa : user.outSa; - body['SessionID'] = body['TokenID'] == null ? ApiConsts.sessionID : getSessionId(body['TokenID'] ?? ""); //getSe - } - // else { - // body['SessionID'] = body['TokenID'] == null ? ApiConsts.sessionID : getSessionId(body['TokenID'] ?? ""); //getSe - // - // } + body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] ?? user.outSa : user.outSa; + body['SessionID'] = body['TokenID'] == null ? ApiConsts.sessionID : getSessionId(body['TokenID'] ?? ""); //getSe } + // else { + // body['SessionID'] = body['TokenID'] == null ? ApiConsts.sessionID : getSessionId(body['TokenID'] ?? ""); //getSe + // + // } } + } - // request.versionID = VERSION_ID; - // request.channel = CHANNEL; - // request.iPAdress = IP_ADDRESS; - // request.generalid = GENERAL_ID; - // request.languageID = (languageID == 'ar' ? 1 : 2); - // request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1; - - // body['VersionID'] = ApiConsts.appVersionID.toString(); - if (!isExternal) { - body['VersionID'] = "50.0"; - body['Channel'] = ApiConsts.appChannelId.toString(); - body['IPAdress'] = ApiConsts.appIpAddress; - body['generalid'] = ApiConsts.appGeneralId; - - body['LanguageID'] = _appState.getLanguageID().toString(); - body['Latitude'] = _appState.userLat.toString(); - body['Longitude'] = _appState.userLong.toString(); - body['DeviceTypeID'] = _appState.deviceTypeID; - if (_appState.appAuthToken.isNotEmpty) { - body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; - } - - // body['TokenID'] = "@dm!n"; - // body['PatientID'] = "4767477"; + // request.versionID = VERSION_ID; + // request.channel = CHANNEL; + // request.iPAdress = IP_ADDRESS; + // request.generalid = GENERAL_ID; + // request.languageID = (languageID == 'ar' ? 1 : 2); + // request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1; + + // body['VersionID'] = ApiConsts.appVersionID.toString(); + if (!isExternal) { + body['VersionID'] = "50.0"; + body['Channel'] = ApiConsts.appChannelId.toString(); + body['IPAdress'] = ApiConsts.appIpAddress; + body['generalid'] = ApiConsts.appGeneralId; + + body['LanguageID'] = _appState.getLanguageID().toString(); + body['Latitude'] = _appState.userLat.toString(); + body['Longitude'] = _appState.userLong.toString(); + body['DeviceTypeID'] = _appState.deviceTypeID; + if (_appState.appAuthToken.isNotEmpty) { + body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; } - body.removeWhere((key, value) => value == null); - log("body: ${json.encode(body)}"); - log("uri: ${Uri.parse(url.trim())}"); + // body['TokenID'] = "@dm!n"; + // body['PatientID'] = "4767477"; + } - final bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck); + body.removeWhere((key, value) => value == null); + log("body: ${json.encode(body)}"); + log("uri: ${Uri.parse(url.trim())}"); - if (!networkStatus) { - onFailure( - 'Please Check The Internet Connection 1', - -1, - failureType: ConnectivityFailure("Please Check The Internet Connection 1"), - ); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - return; - } + final bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck); - final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); - final int statusCode = response.statusCode; - log("response.body: ${response.body}"); - if (statusCode < 200 || statusCode >= 400) { - var parsed = json.decode(utf8.decode(response.bodyBytes)); - onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data")); - logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); + if (!networkStatus) { + onFailure( + 'Please Check The Internet Connection 1', + -1, + failureType: ConnectivityFailure("Please Check The Internet Connection 1"), + ); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + return; + } + + final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); + final int statusCode = response.statusCode; + log("response.body: ${response.body}"); + if (statusCode < 200 || statusCode >= 400) { + var parsed = json.decode(utf8.decode(response.bodyBytes)); + onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data")); + logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); + } else { + var parsed = json.decode(utf8.decode(response.bodyBytes)); + if (isAllowAny) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage']); } else { - var parsed = json.decode(utf8.decode(response.bodyBytes)); - if (isAllowAny) { - onSuccess(parsed, statusCode, messageStatus: 1, errorMessage: ""); + if (parsed['Response_Message'] != null) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else { - if (parsed['Response_Message'] != null) { + if (parsed['ErrorType'] == 4) { + //TODO : handle app update + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + } + if (parsed['ErrorType'] == 2) { + // todo: handle Logout + logApiEndpointError(endPoint, "session logged out", statusCode); + } + if (isAllowAny) { onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else { - if (parsed['ErrorType'] == 4) { - //TODO : handle app update + } else if (parsed['IsAuthenticated'] == null) { + if (parsed['isSMSSent'] == true) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else if (parsed['MessageStatus'] == 1) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else if (parsed['Result'] == 'OK') { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: MessageStatusFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']), + ); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } - if (parsed['ErrorType'] == 2) { - // todo: handle Logout - logApiEndpointError(endPoint, "session logged out", statusCode); - } - if (isAllowAny) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else if (parsed['IsAuthenticated'] == null) { - if (parsed['isSMSSent'] == true) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else if (parsed['MessageStatus'] == 1) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else if (parsed['Result'] == 'OK') { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else { - onFailure( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode, - failureType: MessageStatusFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']), - ); - logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); - } - } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { + } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { + if (parsed['SameClinicApptList'] != null) { onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { - if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else { - if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { - if (parsed['ErrorSearchMsg'] == null) { - onFailure( - "Server Error found with no available message", - statusCode, - failureType: ServerFailure("Error While Fetching data"), - ); - logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); - } else { - onFailure( - parsed['ErrorSearchMsg'], - statusCode, - failureType: ServerFailure("Error While Fetching data"), - ); - logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); - } - } else { - onFailure( - parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode, - failureType: UserIntimationFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']), - ); - logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); - } - } - } else if (!parsed['IsAuthenticated']) { - } else { - if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); - } else { - if (parsed['message'] != null) { + if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { + if (parsed['ErrorSearchMsg'] == null) { onFailure( - parsed['message'] ?? parsed['message'], + "Server Error found with no available message", statusCode, failureType: ServerFailure("Error While Fetching data"), ); - logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); + logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { onFailure( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + parsed['ErrorSearchMsg'], statusCode, failureType: ServerFailure("Error While Fetching data"), ); - logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); } + } else { + onFailure( + parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: UserIntimationFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']), + ); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); + } + } + } else if (!parsed['IsAuthenticated']) { + } else { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else { + if (parsed['message'] != null) { + onFailure( + parsed['message'] ?? parsed['message'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); + } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } } } + } // } catch (e, stackTrace) { // _loggerService.errorLogs(stackTrace.toString()); // if (e.toString().contains("ClientException")) { diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 35371cc..a2cbc49 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -121,4 +121,5 @@ class AppAnimations { static const String register = '$lottieBasePath/register.json'; static const String checkmark = '$lottieBasePath/checkmark.json'; static const String loadingAnimation = '$lottieBasePath/Loader.json'; + static const String errorAnimation = '$lottieBasePath/ErrorAnimation.json'; } diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 75c0cf9..216da22 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -323,6 +323,19 @@ class Utils { ).center; } + static Widget getErrorWidget({String? loadingText}) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Lottie.asset(AppAnimations.errorAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill), + SizedBox(height: 8.h), + (loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor), + SizedBox(height: 8.h), + ], + ).center; + } + static bool isVidaPlusProject(AppState appState, int projectID) { bool isVidaPlus = false; for (var element in appState.vidaPlusProjectList) { diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 8fc477c..804f9f9 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -29,6 +29,9 @@ abstract class MyAppointmentsRepo { Future>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}); Future>> confirmAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}); + + Future>> sendCheckInNfcRequest( + {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String scannedCode, required int checkInType}); } class MyAppointmentsRepoImp implements MyAppointmentsRepo { @@ -350,4 +353,46 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future> sendCheckInNfcRequest( + {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String scannedCode, required int checkInType}) async { + Map requestBody = { + "AppointmentNo": patientAppointmentHistoryResponseModel.appointmentNo, + "NFC_Code": scannedCode, + "ProjectID": patientAppointmentHistoryResponseModel.projectID, + "ClinicID": patientAppointmentHistoryResponseModel.clinicID, + "CheckinBy": checkInType, + }; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + SEND_CHECK_IN_NFC_REQUEST, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + isAllowAny: true, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } } diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 2815977..4a921da 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -229,4 +229,28 @@ class MyAppointmentsViewModel extends ChangeNotifier { }, ); } + + Future sendCheckInNfcRequest( + {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, + required String scannedCode, + required int checkInType, + Function(dynamic)? onSuccess, + Function(String)? onError}) async { + final result = await myAppointmentsRepo.sendCheckInNfcRequest(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, scannedCode: scannedCode, checkInType: checkInType); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + onError!(apiResponse.errorMessage!); + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index d6ff672..7188620 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -522,6 +522,7 @@ class _AppointmentDetailsPageState extends State { title: LocaleKeys.onlineCheckIn.tr(), child: AppointmentCheckinBottomSheet( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, + myAppointmentsViewModel: myAppointmentsViewModel, ), callBackFunc: () {}, isFullScreen: false); diff --git a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart index f3f05b3..f8e0f59 100644 --- a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart +++ b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart @@ -1,44 +1,138 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_nfc_kit/flutter_nfc_kit.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart'; +import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:barcode_scan2/barcode_scan2.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/nfc/nfc_reader_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; class AppointmentCheckinBottomSheet extends StatelessWidget { - AppointmentCheckinBottomSheet({super.key, required this.patientAppointmentHistoryResponseModel}); + AppointmentCheckinBottomSheet({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel}); PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; + MyAppointmentsViewModel myAppointmentsViewModel; + + bool _supportsNFC = false; @override Widget build(BuildContext context) { + FlutterNfcKit.nfcAvailability.then((value) { + _supportsNFC = (value == NFCAvailability.available); + }); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - checkInOptionCard(AppAssets.checkin_location_icon, "Live Location".needTranslation, "".needTranslation), + checkInOptionCard( + AppAssets.checkin_location_icon, + "Live Location".needTranslation, + "Verify your location to be at hospital to check in".needTranslation, + ).onPress(() { + Navigator.of(context).pop(); + }), SizedBox(height: 16.h), - checkInOptionCard(AppAssets.checkin_nfc_icon, "NFC (Near Field Communication)".needTranslation, "".needTranslation), + checkInOptionCard( + AppAssets.checkin_nfc_icon, + "NFC (Near Field Communication)".needTranslation, + "Scan your phone via NFC board to check in".needTranslation, + ).onPress(() { + Future.delayed(const Duration(milliseconds: 500), () { + showNfcReader(context, onNcfScan: (String nfcId) { + Future.delayed(const Duration(milliseconds: 100), () { + sendCheckInRequest(nfcId, context); + }); + }, onCancel: () {}); + }); + }), SizedBox(height: 16.h), - checkInOptionCard(AppAssets.checkin_qr_icon, "QR Code".needTranslation, "".needTranslation), + checkInOptionCard( + AppAssets.checkin_qr_icon, + "QR Code".needTranslation, + "Scan QR code with your camera to check in".needTranslation, + ).onPress(() async { + String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent)); + if (onlineCheckInQRCode != "") { + sendCheckInRequest(onlineCheckInQRCode, context); + } else {} + }), ], ); } Widget checkInOptionCard(String icon, String title, String subTitle) { return Container( - height: 120.h, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, ), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.buildSvgWithAssets(icon: icon), + Utils.buildSvgWithAssets(icon: icon, width: 40.h, height: 40.h, fit: BoxFit.fill), + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title.toText16(isBold: true, color: AppColors.textColor), + subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + ], + ), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ), + ], + ), ], - ), + ).paddingAll(16.h), + ); + } + + void sendCheckInRequest(String scannedCode, BuildContext context) async { + showCommonBottomSheet(context, + child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false); + await myAppointmentsViewModel.sendCheckInNfcRequest( + patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, + scannedCode: scannedCode, + checkInType: 2, + onSuccess: (apiResponse) { + Navigator.of(context).pop(); + showCommonBottomSheetWithoutHeight(context, title: "Success".needTranslation, child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () { + Navigator.of(context).pop(); + Navigator.pushAndRemoveUntil( + context, + FadePage( + page: LandingNavigation(), + ), + (r) => false); + Navigator.of(context).push( + FadePage(page: MyAppointmentsPage()), + ); + }, isFullScreen: false); + }, + onError: (error) { + Navigator.of(context).pop(); + showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: error), callBackFunc: () { + Navigator.of(context).pop(); + }, isFullScreen: false); + }, ); } } diff --git a/lib/presentation/appointments/widgets/appointment_queueing_screen.dart b/lib/presentation/appointments/widgets/appointment_queueing_screen.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/widgets/nfc/nfc_reader_sheet.dart b/lib/widgets/nfc/nfc_reader_sheet.dart new file mode 100644 index 0000000..b76b36f --- /dev/null +++ b/lib/widgets/nfc/nfc_reader_sheet.dart @@ -0,0 +1,212 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_nfc_kit/flutter_nfc_kit.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; + +void showNfcReader(BuildContext context, {required Function onNcfScan, required VoidCallback onCancel}) { + showModalBottomSheet( + context: context, + enableDrag: false, + isDismissible: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), + ), + backgroundColor: Colors.white, + builder: (context) { + return NfcLayout( + onNcfScan: onNcfScan, + onCancel: onCancel, + ); + }); +} + +class NfcLayout extends StatefulWidget { + Function? onNcfScan; + VoidCallback? onCancel; + + NfcLayout({this.onNcfScan, this.onCancel}); + + @override + _NfcLayoutState createState() => _NfcLayoutState(); +} + +class _NfcLayoutState extends State { + bool _reading = false; + Widget? mainWidget; + late String nfcId; + + @override + void initState() { + super.initState(); + readNFC(); + } + + void readNFC() async { + FlutterNfcKit.finish(); + FlutterNfcKit.poll(timeout: Duration(seconds: 10), androidPlatformSound: true, androidCheckNDEF: false, iosMultipleTagMessage: "Multiple tags found!").then((value) async { + setState(() { + _reading = true; + mainWidget = doneNfc(); + }); + Future.delayed(const Duration(milliseconds: 500), () async { + await FlutterNfcKit.finish(); + widget.onNcfScan!(nfcId); + Navigator.pop(context); + }); + nfcId = value.id; + }).catchError((err) { + print(err); + Navigator.of(context).pop(); + }); + } + + @override + Widget build(BuildContext context) { + // return SizedBox(); + (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); + return Platform.isAndroid ? AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget) : SizedBox.shrink(); + } + + Widget scanNfc() { + return Container( + key: ValueKey(1), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 30, + ), + Text( + "Ready To Scan", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + SizedBox( + height: 30, + ), + SvgPicture.asset( + "assets/images/nfc/contactless.svg", + height: MediaQuery.of(context).size.width / 3, + ), + 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: CustomButton( + text: LocaleKeys.cancel.tr(), + onPressed: () { + widget.onCancel!(); + Navigator.pop(context); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12.h, + height: 40.h, + icon: AppAssets.cancel, + iconColor: AppColors.whiteColor, + iconSize: 16.h, + ), + ), + 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/images/nfc/ic_done.png", + height: MediaQuery.of(context).size.width / 3, + ), + 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: CustomButton( + text: LocaleKeys.done.tr(), + onPressed: () { + widget.onCancel!(); + Navigator.pop(context); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12.h, + height: 40.h, + icon: AppAssets.cancel, + iconColor: AppColors.whiteColor, + iconSize: 16.h, + ), + ), + SizedBox( + height: 30, + ), + ], + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 7536aaa..afbac11 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -73,6 +73,8 @@ dependencies: maps_launcher: ^3.0.0+1 amazon_payfort: ^1.1.4 network_info_plus: ^6.1.4 + flutter_nfc_kit: ^3.6.0 + barcode_scan2: ^4.5.1 dev_dependencies: flutter_test: