Merge remote-tracking branch 'origin/master'

hospital_filter
tahaalam 1 month ago
commit e083cbc82b

@ -69,4 +69,7 @@
# Penguin classes
-keep class com.peng.pennavmap.models.** { *; }
-keep class com.peng.pennavmap.db.** { *; }
-keep class com.peng.pennavmap.db.** { *; }
-keep class com.hiennv.flutter_callkit_incoming.** { *; }
-keepattributes Signature, Annotation, InnerClasses, EnclosingMethod

@ -30,9 +30,6 @@
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"
tools:node="remove" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"
tools:node="remove" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"
tools:node="remove" />
@ -91,6 +88,12 @@
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
<uses-feature
android:name="android.hardware.location.network"
android:required="false" />
@ -115,6 +118,7 @@
</queries>
<application
android:foregroundServiceType="mediaPlayback|connectedDevice|dataSync"
android:name=".Application"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher_local"

@ -0,0 +1,3 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="mapbox_access_token" translatable="false" tools:ignore="UnusedResources">sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg</string>
</resources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

@ -0,0 +1,22 @@
export const icons = {
chatSend: require('./chat-send.png'),
defaultAvatar: require('./default-avatar.png'),
locked: require('./locked.png'),
more: require('./more.png'),
mute: require('./mute.png'),
muted: require('./muted.png'),
shareOn: require('./share-on.png'),
shareOff: require('./share-off.png'),
speakerOn: require('./speaker-on.png'),
speakerOff: require('./speaker-off.png'),
switchCamera: require('./switch-camera.png'),
hamburger: require('./hamburger.png'),
questionBalloon: require('./question-ballon.png'),
talking: require('./talking.png'),
unmute: require('./unmute.png'),
unlocked: require('./unlocked.png'),
videoOn: require('./video-on.png'),
videoOff: require('./video-off.png'),
};
export type IconTypes = keyof typeof icons;

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 10.4189C5 6.60727 8.12437 3.5 12 3.5C15.8756 3.5 19 6.60727 19 10.4189C19 11.7227 18.6361 12.94 18.003 13.98C17.7158 14.4518 17.8654 15.067 18.3372 15.3542C18.8089 15.6414 19.4242 15.4917 19.7113 15.02C20.5292 13.6763 21 12.1008 21 10.4189C21 5.48352 16.9609 1.5 12 1.5C7.03907 1.5 3 5.48352 3 10.4189C3 12.1008 3.47075 13.6763 4.28867 15.02C4.57584 15.4917 5.19107 15.6414 5.66283 15.3542C6.13458 15.067 6.28421 14.4518 5.99704 13.98C5.36394 12.94 5 11.7227 5 10.4189Z" fill="#FFAF15"/>
<path d="M16.2105 15.755C16.1022 15.75 15.9736 15.75 15.8432 15.75L13 15.75L13 12.3377C13.6525 12.122 14.2312 11.7074 14.7242 11.1896C15.1051 10.7896 15.0896 10.1567 14.6896 9.77581C14.2896 9.39495 13.6567 9.41044 13.2758 9.81041C12.783 10.3279 12.3512 10.5 12 10.5C11.6488 10.5 11.217 10.3279 10.7242 9.81041C10.3433 9.41045 9.71037 9.39495 9.31041 9.77581C8.91044 10.1567 8.89495 10.7896 9.27581 11.1896C9.76884 11.7074 10.3475 12.122 11 12.3377L11 15.75H8.15684C8.02643 15.75 7.89781 15.75 7.78945 15.755C7.67503 15.7602 7.52127 15.7728 7.3611 15.8212C6.8626 15.9717 6.5267 16.3363 6.50126 16.7498C6.49309 16.8826 6.52614 16.9996 6.55585 17.0857C6.8873 18.7676 7.57151 19.25 8.1569 19.25L15.8431 19.25C16.4285 19.25 17.1127 18.7676 17.4441 17.0857C17.4739 16.9996 17.5069 16.8826 17.4987 16.7498C17.4733 16.3363 17.1374 15.9717 16.6389 15.8212C16.4787 15.7728 16.325 15.7602 16.2105 15.755Z" fill="#FFAF15"/>
<path d="M10.3321 22.4013C10.6774 22.5018 11.0856 22.5018 11.9019 22.5018C12.7182 22.5018 13.1264 22.5018 13.4717 22.4013C14.0057 22.2458 14.4551 21.9204 14.7324 21.4884C14.8356 21.3276 14.906 21.1423 14.9776 20.8791C15.0674 20.5491 15.1123 20.3841 15.0223 20.2663C14.9322 20.1484 14.7551 20.1484 14.4009 20.1484L9.40295 20.1484C9.04873 20.1484 8.87162 20.1484 8.78156 20.2663C8.69151 20.3841 8.73641 20.5491 8.82623 20.8791C8.89786 21.1423 8.96819 21.3276 9.07142 21.4884C9.34876 21.9204 9.79812 22.2458 10.3321 22.4013Z" fill="#FFAF15"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1,4 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.14286 7.27526C6.06081 7.19321 5.94953 7.14712 5.8335 7.14712C5.68326 7.14712 5.53722 7.14711 5.396 7.14757V9.54083C6.06931 9.73127 6.56266 10.3503 6.56266 11.0846V11.668C6.56266 11.9096 6.36679 12.1055 6.12516 12.1055C5.88354 12.1055 5.68766 11.9096 5.68766 11.668V11.0846C5.68766 10.6819 5.3612 10.3555 4.9585 10.3555C4.55579 10.3555 4.22933 10.6819 4.22933 11.0846V11.668C4.22933 11.9096 4.03345 12.1055 3.79183 12.1055C3.55021 12.1055 3.35433 11.9096 3.35433 11.668V11.0846C3.35433 10.3503 3.84768 9.73127 4.521 9.54083V7.16254C4.27509 7.17241 4.05216 7.18858 3.85498 7.21509C3.32991 7.28568 2.88782 7.4367 2.5367 7.78782C2.18558 8.13894 2.03456 8.58103 1.96397 9.1061C1.89598 9.61182 1.89598 10.2548 1.896 11.0526V12.8346C1.896 13.0762 2.09187 13.2721 2.3335 13.2721H11.6668C11.9085 13.2721 12.1043 13.0762 12.1043 12.8346V11.0526C12.1043 10.2548 12.1044 9.61183 12.0364 9.1061C11.9658 8.58103 11.8147 8.13894 11.4636 7.78782C11.1125 7.4367 10.6704 7.28568 10.1454 7.21509C10.0293 7.19949 9.90432 7.18746 9.771 7.1782V10.4725C10.0325 10.6238 10.2085 10.9066 10.2085 11.2305C10.2085 11.7137 9.81675 12.1055 9.3335 12.1055C8.85025 12.1055 8.4585 11.7137 8.4585 11.2305C8.4585 10.9066 8.63446 10.6238 8.896 10.4725V7.14936C8.66672 7.14711 8.42324 7.14711 8.16711 7.14712C8.05108 7.14712 7.93952 7.19321 7.85747 7.27526L7.00016 8.13257L6.14286 7.27526Z" fill="#18C273"/>
<path d="M7.00016 0.730469C5.63096 0.730469 4.521 1.84043 4.521 3.20964V3.79297C4.521 5.16217 5.63096 6.27214 7.00016 6.27214C8.36937 6.27214 9.47933 5.16217 9.47933 3.79297V3.20964C9.47933 1.84043 8.36937 0.730469 7.00016 0.730469Z" fill="#18C273"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,4 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.5658 1.95717C9.82689 0.890531 8.26692 1.31563 7.32452 2.02335C7.26938 2.06476 7.22039 2.10153 7.17659 2.13413C7.08676 2.20099 7.04185 2.23442 6.98387 2.23442C6.92589 2.23442 6.88098 2.20099 6.79115 2.13413C6.74735 2.10153 6.69836 2.06476 6.64322 2.02335C5.70082 1.31563 4.14085 0.890531 2.40195 1.95717C1.53619 2.48823 0.943044 3.43564 0.767402 4.5853C0.741775 4.75304 0.728961 4.83691 0.781341 4.89789C0.83372 4.95888 0.923033 4.95887 1.10166 4.95885L3.00095 4.95868C3.24133 4.95767 3.64619 4.95596 4.03964 5.0991C4.19392 5.15522 4.33336 5.22877 4.4573 5.3094C4.63656 5.42602 4.72618 5.48433 4.79864 5.46761C4.87109 5.45089 4.92018 5.36908 5.01835 5.20545L5.44147 4.50026C5.71062 4.05168 6.19943 3.78162 6.72246 3.79256C7.24549 3.80349 7.72259 4.09374 7.97275 4.55319L8.72948 5.94294C8.77795 6.03196 8.80218 6.07647 8.8435 6.10102C8.88482 6.12557 8.9355 6.12557 9.03686 6.12557H9.31698C10.1224 6.12557 10.7753 6.77849 10.7753 7.5839C10.7753 8.38932 10.1224 9.04224 9.31698 9.04224L8.66574 9.04348C8.42373 9.04908 7.69714 9.06588 7.06184 8.57794C7.0432 8.56363 7.02501 8.54906 7.00725 8.5343C6.81047 8.37075 6.71208 8.28898 6.63276 8.30247C6.55344 8.31596 6.49635 8.41111 6.38218 8.6014L6.19249 8.91754C5.93991 9.33851 5.49248 9.60414 5.00197 9.62434C4.51146 9.64453 4.0437 9.41658 3.75738 9.0178L3.04199 8.02146C2.99064 7.94995 2.96497 7.91419 2.92736 7.8949C2.88975 7.8756 2.84573 7.8756 2.75769 7.8756L1.88603 7.87559C1.63453 7.87558 1.50878 7.87558 1.45819 7.96269C1.40759 8.0498 1.46788 8.15548 1.58846 8.36685C2.2106 9.45742 3.18686 10.5632 4.58832 11.6005C5.43495 12.2275 6.05634 12.6877 6.98387 12.6877C7.91141 12.6877 8.53279 12.2275 9.37943 11.6005C11.8175 9.79586 12.9688 7.78416 13.2073 6.00548C13.4447 4.23535 12.7682 2.69472 11.5658 1.95717Z" fill="#ED1C2B"/>
<path d="M7.20469 4.97105C7.10463 4.78727 6.91379 4.67117 6.70458 4.66679C6.49537 4.66242 6.29984 4.77044 6.19218 4.94988L4.8987 7.10568L4.50819 6.5618C4.50002 6.55043 4.49145 6.53935 4.48248 6.52859C4.47338 6.51766 4.4634 6.50547 4.45255 6.49222C4.32787 6.33991 4.08822 6.04716 3.74091 5.92081C3.49697 5.83206 3.23003 5.83265 2.965 5.83324L2.90072 5.83333H1.73405C1.41188 5.83333 1.15072 6.0945 1.15072 6.41667C1.15072 6.73883 1.41188 7 1.73405 7H2.90072C3.27245 7 3.31696 7.00823 3.34111 7.01684C3.34329 7.01792 3.36229 7.02776 3.40145 7.06546C3.45005 7.11226 3.4979 7.16947 3.57276 7.25931L4.46854 8.50689C4.58307 8.6664 4.77018 8.75758 4.96638 8.74951C5.16258 8.74143 5.34156 8.63518 5.44259 8.46679L6.66782 6.42473L7.16648 7.34054C7.17206 7.35078 7.17794 7.36086 7.18412 7.37075L7.20842 7.40983C7.30282 7.56206 7.41744 7.74688 7.59523 7.88343C7.98366 8.18176 8.4448 8.17225 8.67006 8.16761C8.69423 8.16711 8.71569 8.16667 8.73405 8.16667H9.31738C9.63955 8.16667 9.90072 7.9055 9.90072 7.58333C9.90072 7.26117 9.63955 7 9.31738 7H8.73405C8.69863 7 8.66723 7.00017 8.63892 7.00032C8.53614 7.00086 8.47421 7.00119 8.40933 6.99253C8.35288 6.98499 8.32768 6.97346 8.31135 6.96218C8.30864 6.95892 8.30403 6.95313 8.29726 6.94384C8.27206 6.90926 8.24113 6.86063 8.18271 6.76722L7.20469 4.97105Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

@ -0,0 +1,4 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" rx="10" fill="#FEE9EA"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.9293 15.7788C22.9291 15.779 22.9294 15.7785 22.9293 15.7788L21.1713 19.3237C20.9847 19.7062 20.6726 20.0338 20.3511 20.2741C20.029 20.5149 19.6281 20.7199 19.2149 20.7907L19.2123 20.7911L16.023 21.3254C15.1361 21.4744 14.8447 21.8265 14.7764 22.0421C14.7072 22.2607 14.7447 22.7225 15.3814 23.3644L17.8611 25.8646C18.1828 26.189 18.3978 26.6224 18.5163 27.0398C18.6349 27.4576 18.6791 27.9375 18.5806 28.3802L18.5795 28.3851L17.8696 31.4802C17.6047 32.6346 17.8722 33.0603 18.0105 33.162C18.1449 33.2609 18.6222 33.3909 19.6332 32.786L22.6284 30.9983C23.0448 30.754 23.5438 30.6532 24.0016 30.6532C24.4586 30.6532 24.9578 30.7537 25.3721 31.0012C25.372 31.0011 25.3722 31.0012 25.3721 31.0012L28.3612 32.7852C28.361 32.7852 28.3613 32.7853 28.3612 32.7852C29.3805 33.3922 29.8572 33.2626 29.9892 33.1656C30.1243 33.0662 30.3919 32.6431 30.1259 31.4796L29.415 28.3802C29.3166 27.9375 29.3608 27.4576 29.4794 27.0398C29.5979 26.6224 29.8128 26.189 30.1346 25.8646L32.6143 23.3644L32.6161 23.3625C33.2569 22.7208 33.2925 22.2603 33.2234 22.0435C33.1545 21.8272 32.8603 21.4745 31.9726 21.3254L28.7834 20.7911C28.366 20.721 27.9619 20.5167 27.6372 20.2751C27.3136 20.0343 27.0011 19.7064 26.8143 19.3237L25.055 15.776C24.6328 14.92 24.2045 14.75 23.9966 14.75C23.7873 14.75 23.3564 14.9223 22.9293 15.7788ZM26.4 15.1119C25.8724 14.0425 25.0459 13.25 23.9966 13.25C22.9485 13.25 22.1194 14.0411 21.5868 15.1096L21.5861 15.111L19.8263 18.6597L19.8236 18.6652C19.7701 18.7754 19.6431 18.9305 19.453 19.0727C19.2632 19.2146 19.0797 19.2917 18.9628 19.312C18.9625 19.3121 18.9621 19.3121 18.9618 19.3122L15.7748 19.8461C14.6219 20.0398 13.6581 20.6052 13.3464 21.5893C13.0357 22.5704 13.4931 23.5906 14.3163 24.4206L16.7961 26.9209C16.8943 27.0199 17.0043 27.2064 17.0733 27.4494C17.1418 27.6908 17.1479 27.9107 17.1168 28.0527C17.1167 28.0534 17.1165 28.0541 17.1164 28.0547L16.4076 31.1447C16.4076 31.1448 16.4076 31.1447 16.4076 31.1447C16.1126 32.43 16.215 33.7032 17.1216 34.3702C18.032 35.04 19.2745 34.7487 20.4034 34.0732L23.3874 32.2921C23.3881 32.2917 23.3887 32.2914 23.3893 32.291C23.5231 32.2132 23.7432 32.1532 24.0016 32.1532C24.2618 32.1532 24.4775 32.214 24.603 32.289L27.593 34.0736C28.7232 34.7467 29.9672 35.0433 30.8776 34.3742C31.7848 33.7073 31.8822 32.4317 31.5882 31.1454L30.8793 28.0547C30.8791 28.0541 30.879 28.0534 30.8788 28.0527C30.8478 27.9107 30.8539 27.6908 30.9224 27.4494C30.9914 27.2064 31.1014 27.0199 31.1996 26.9209L33.6775 24.4225C33.6778 24.4222 33.6781 24.4219 33.6783 24.4216C34.5068 23.5916 34.9658 22.5705 34.6526 21.5879C34.339 20.6045 33.3734 20.0397 32.2212 19.8461L29.0316 19.3118C28.909 19.2912 28.7228 19.2131 28.5326 19.0716C28.3421 18.93 28.2155 18.7751 28.1621 18.6652L26.4 15.1119C26.4001 15.1121 26.4 15.1118 26.4 15.1119Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

@ -0,0 +1,7 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" rx="10" fill="#FEE9EA"/>
<path d="M17.3238 34.75C16.8934 34.75 16.453 34.71 16.0226 34.6301C15.7623 34.5801 15.5421 34.4002 15.452 34.1503C15.362 33.9004 15.412 33.6205 15.5722 33.4206C16.0426 32.8409 16.3629 32.1512 16.503 31.4016C16.5431 31.1717 16.4229 30.8918 16.1827 30.6419C14.291 28.7228 13.25 26.204 13.25 23.5652C13.25 17.8779 18.0745 13.25 24.01 13.25C24.7307 13.25 25.4514 13.32 26.152 13.4499C26.5624 13.5299 26.8226 13.9197 26.7426 14.3295C26.6625 14.7393 26.2721 14.9992 25.8617 14.9192C25.2512 14.7993 24.6306 14.7393 24 14.7393C18.8952 14.7393 14.7414 18.6975 14.7414 23.5552C14.7414 25.8042 15.6322 27.9432 17.2437 29.5824C17.8443 30.1821 18.1045 30.9518 17.9644 31.6714C17.8643 32.2212 17.6841 32.7409 17.4439 33.2307C18.3347 33.2107 19.2155 32.9808 20.0163 32.561L20.0959 32.5198C20.583 32.2673 20.8312 32.1387 21.0973 32.0912C21.3876 32.0513 21.6678 32.1012 22.1983 32.2012C22.7889 32.3111 23.3994 32.3411 23.99 32.3611C29.0947 32.3611 33.2486 28.413 33.2486 23.5452C33.2486 23.1354 33.5889 22.7956 33.9993 22.7956C34.4097 22.7956 34.75 23.1354 34.75 23.5452C34.75 29.2326 29.9255 33.8604 23.99 33.8604C23.3294 33.8604 22.5987 33.8005 21.9181 33.6705C21.8571 33.6592 21.7957 33.6475 21.7364 33.6361C21.5326 33.597 21.354 33.5628 21.3075 33.5706C21.2667 33.5909 21.0067 33.7208 20.737 33.8704C19.666 34.4401 18.4849 34.73 17.3038 34.73L17.3238 34.75Z" fill="#ED1C2B"/>
<path d="M24.02 25.0052C23.4695 25.0052 23.0191 24.5552 23.0191 24.0052C23.0191 23.4552 23.4595 23.0052 24.02 23.0052C24.5706 23.0052 25.021 23.4552 25.021 24.0052C25.021 24.5552 24.5706 25.0052 24.02 25.0052Z" fill="#ED1C2B"/>
<path d="M20.0263 25.0052C19.4758 25.0052 19.0254 24.5552 19.0254 24.0052C19.0254 23.4552 19.4658 23.0052 20.0263 23.0052C20.5768 23.0052 21.0273 23.4552 21.0273 24.0052C21.0273 24.5552 20.5768 25.0052 20.0263 25.0052Z" fill="#ED1C2B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.6415 22.4355C25.8818 22.6654 26.1921 22.7954 26.5224 22.7954L26.5124 22.7853C26.6024 22.7853 26.6925 22.7754 26.7826 22.7554L29.0147 22.2756C29.5552 22.1756 30.0557 21.9158 30.456 21.5159L34.0794 17.8277C34.5098 17.4079 34.74 16.8381 34.74 16.2384C34.74 15.6387 34.5098 15.069 34.0794 14.6492L33.3888 13.9595C32.538 13.1099 31.0566 13.1099 30.2058 13.9595L26.5324 17.6277C26.142 18.0176 25.8818 18.5173 25.7817 19.0471L25.3012 21.286C25.2111 21.7058 25.3413 22.1356 25.6415 22.4355ZM31.2768 15.019C31.4169 14.879 31.6071 14.7991 31.8073 14.7991V14.809C32.0075 14.809 32.1976 14.889 32.3378 15.0289L33.0284 15.7186C33.1686 15.8586 33.2486 16.0485 33.2486 16.2484C33.2486 16.4483 33.1786 16.6282 33.0284 16.7781L29.405 20.4664C29.2249 20.6463 28.9947 20.7663 28.7244 20.8163L26.8527 21.2261L27.253 19.3469C27.3031 19.0971 27.4232 18.8672 27.6034 18.6872L31.2768 15.019Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

@ -0,0 +1,4 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.25 20C9.25 25.928 14.072 30.75 20 30.75C25.928 30.75 30.75 25.928 30.75 20C30.75 14.0721 25.9282 9.25021 20.0004 9.25C14.0724 9.25 9.25 14.072 9.25 20ZM28.9732 17.75C29.154 18.4705 29.25 19.2243 29.25 20C29.25 20.7757 29.154 21.5295 28.9732 22.25H24.5746C24.687 21.5359 24.751 20.7846 24.751 19.9997C24.751 19.2151 24.687 18.464 24.5747 17.75H28.9732ZM28.4553 16.25H24.2585C23.6395 13.9132 22.5564 12.0788 21.7158 10.9096C24.7331 11.4779 27.2382 13.5166 28.4553 16.25ZM23.049 17.75C23.1761 18.4613 23.25 19.213 23.25 19.9997C23.25 20.7866 23.1761 21.5386 23.049 22.25H16.9511C16.8239 21.5386 16.75 20.7866 16.75 19.9997C16.75 19.2131 16.8239 18.4613 16.9509 17.75H23.049ZM17.309 16.25H22.6909C21.966 13.828 20.7108 12.0282 20 11.1427C19.2892 12.0276 18.0339 13.8277 17.309 16.25ZM15.4263 17.75C15.314 18.464 15.25 19.2151 15.25 19.9997C15.25 20.7846 15.3141 21.5359 15.4264 22.25H11.0268C10.846 21.5295 10.75 20.7757 10.75 20C10.75 19.2243 10.846 18.4705 11.0268 17.75H15.4263ZM11.5447 16.25H15.7424C16.3613 13.9131 17.4442 12.0786 18.2848 10.9094C15.2672 11.4776 12.7619 13.5164 11.5447 16.25ZM21.7159 29.0904C24.7331 28.522 27.2382 26.4834 28.4553 23.75H24.2584C23.6395 26.0869 22.5565 27.9213 21.7159 29.0904ZM20 28.8568C20.7107 27.9719 21.9659 26.1721 22.6908 23.75H17.3093C18.0342 26.1717 19.2893 27.9713 20 28.8568ZM18.2858 29.0907C17.4451 27.9217 16.3618 26.0871 15.7427 23.75H11.5447C12.7621 26.4839 15.2678 28.5228 18.2858 29.0907Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="31" height="31" viewBox="0 0 31 31">
<g id="Group_8325" data-name="Group 8325" transform="translate(-75 -236)">
<circle id="Ellipse_223" data-name="Ellipse 223" cx="15.5" cy="15.5" r="15.5" transform="translate(75 236)" fill="#359846"/>
<path id="hour-glass" d="M8.73,10.811a1.46,1.46,0,0,0,0-2.122L8.647,8.61C7.085,7.119,5.878,5.968,5.515,3.556A1.413,1.413,0,0,1,6.992,2h7.091A1.413,1.413,0,0,1,15.56,3.556C15.2,5.968,13.99,7.119,12.429,8.61l-.083.079a1.46,1.46,0,0,0,0,2.122l.083.079c1.562,1.491,2.768,2.642,3.132,5.054A1.413,1.413,0,0,1,14.083,17.5H6.992a1.413,1.413,0,0,1-1.477-1.556c.364-2.412,1.57-3.563,3.132-5.054Zm.529,1.316-.006,0c-1.19,1.064-2.076,1.856-2.191,3.816a.363.363,0,0,0,.13.3.382.382,0,0,0,.247.09h6.194a.382.382,0,0,0,.282-.122.361.361,0,0,0,.1-.268c-.115-1.959-1-2.752-2.191-3.816-.315-.281-.651-.582-1-.928a.4.4,0,0,0-.569,0c-.347.344-.681.643-.993.923Z" transform="translate(80.35 241.75)" fill="#fff" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1021 B

@ -1,122 +1,128 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"idiom" : "iphone",
"scale" : "1x",
"size" : "29x29"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"size" : "1024x1024",
"filename" : "icon 1.jpg",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
"scale" : "1x",
"size" : "1024x1024"
},
{
"filename" : "Icon-App-76x76@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "76x76"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@ -175,8 +175,7 @@ class ApiClientImp implements ApiClient {
}
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 4772429;
// body['PatientID'] = 1231755;
// body['PatientID'] = 1018977;
// body['PatientTypeID'] = 1;
//
// body['PatientOutSA'] = 0;
@ -184,9 +183,6 @@ class ApiClientImp implements ApiClient {
}
body.removeWhere((key, value) => value == null);
log("uri: ${Uri.parse(url.trim())}");
log("body: ${json.encode(body)}");
final bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck);
@ -204,7 +200,7 @@ class ApiClientImp implements ApiClient {
final int statusCode = response.statusCode;
log("uri: ${Uri.parse(url.trim())}");
log("body: ${json.encode(body)}");
log("response.body: ${response.body}");
// log("response.body: ${response.body}");
// log("response.body: ${response.body}");
if (statusCode < 200 || statusCode >= 400) {
onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data"));

@ -710,7 +710,7 @@ var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatb
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -749,7 +749,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
@ -759,7 +759,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
@ -779,7 +779,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
@ -789,7 +789,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
@ -862,7 +862,7 @@ class ApiConsts {
// ************ static values for Api ****************
static final double appVersionID = 19.3;
static final double appVersionID = 50.3;
static final int appChannelId = 3;
static final String appIpAddress = "10.20.10.20";
static final String appGeneralId = "Cs2020@2016\$2958";

@ -175,6 +175,13 @@ class AppAssets {
static const String comprehensiveCheckup = '$svgBasePath/comprehensive_checkup.svg';
static const String all_payment_method = '$svgBasePath/all_payment_method.svg';
static const String ic_rrt_vehicle = '$svgBasePath/ic_rrt_vehicle.svg';
static const String doctor_profile_rating_icon = '$svgBasePath/doctor_profile_rating_icon.svg';
static const String doctor_profile_reviews_icon = '$svgBasePath/doctor_profile_reviews_icon.svg';
static const String waiting_appointment_icon = '$svgBasePath/waitingAppo.svg';
static const String call_for_vitals = '$svgBasePath/call_for_vitals.svg';
static const String call_for_doctor = '$svgBasePath/call_for_doctor.svg';
static const String bulb_icon = '$svgBasePath/bulb_icon.svg';
static const String select_city_icon = '$svgBasePath/select_city_icon.svg';
//bottom navigation//

@ -74,4 +74,7 @@ class CacheConst {
static const String patientOccupationList = 'patient-occupation-list';
static const String hasEnabledQuickLogin = 'has-enabled-quick-login';
static const String quickLoginEnabled = 'quick-login-enabled';
static const String zoomRoomID = 'zoom-room-id';
static String isAppOpenedFromCall = "is_app_opened_from_call";
}

@ -5,6 +5,8 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_repo.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart';
@ -116,6 +118,7 @@ class AppDependencies {
getIt.registerLazySingleton<LocationRepo>(() => LocationRepoImpl(apiClient: getIt()));
getIt.registerLazySingleton<ContactUsRepo>(() => ContactUsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<HmgServicesRepo>(() => HmgServicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<BloodDonationRepo>(() => BloodDonationRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -130,7 +133,7 @@ class AppDependencies {
),
);
getIt.registerLazySingleton<PrescriptionsViewModel>(() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<PrescriptionsViewModel>(() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
getIt.registerLazySingleton<InsuranceViewModel>(() => InsuranceViewModel(insuranceRepo: getIt(), errorHandlerService: getIt()));
@ -224,6 +227,10 @@ class AppDependencies {
() => HmgServicesViewModel(bookAppointmentsRepo: getIt(), hmgServicesRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt()),
);
getIt.registerLazySingleton<BloodDonationViewModel>(
() => BloodDonationViewModel(bloodDonationRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt()),
);
// Screen-specific VMs Factory
// getIt.registerFactory<BookAppointmentsViewModel>(
// () => BookAppointmentsViewModel(

@ -1,316 +0,0 @@
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:device_calendar/device_calendar.dart';
import 'package:flutter/widgets.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_reminder_view.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/permission_service.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:jiffy/jiffy.dart';
import 'package:manage_calendar_events/manage_calendar_events.dart' as ios;
import 'package:permission_handler/permission_handler.dart';
import 'package:timezone/data/latest.dart' as tzl;
final DeviceCalendarPlugin deviceCalendarPlugin = DeviceCalendarPlugin();
final ios.CalendarPlugin _myPlugin = ios.CalendarPlugin();
class CalendarUtils {
static Completer<CalendarUtils>? _completer;
dynamic get writableCalendars => calendars.firstWhere((c) => !c.isReadOnly!);
dynamic calendars;
CalendarUtils._(this.calendars);
// static Future<CalendarUtils> getInstance() async {
// if (_completer == null) {
// _completer = Completer<CalendarUtils>();
// print(_completer!.isCompleted);
// try {
// final dynamic calendarsResult;
// if (Platform.isIOS) {
// calendarsResult = await _myPlugin.getCalendars();
// if (!_completer!.isCompleted) {
// _completer?.complete(CalendarUtils._(await calendarsResult!));
// }
// } else {
// calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
// if (!_completer!.isCompleted) {
// _completer?.complete(CalendarUtils._(await calendarsResult.data!));
// }
// }
// } on Exception catch (e) {
// if (!_completer!.isCompleted) {
// _completer!.completeError(e);
// }
// }
// }
// return _completer!.future;
// }
static Future<CalendarUtils> getInstance() async {
tzl.initializeTimeZones();
if (_completer != null) {
return _completer!.future;
}
_completer = Completer<CalendarUtils>();
try {
final dynamic calendarsResult;
if (Platform.isIOS) {
calendarsResult = await _myPlugin.getCalendars();
_completer!.complete(CalendarUtils._(calendarsResult));
} else {
calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
_completer!.complete(CalendarUtils._(calendarsResult.data));
}
} catch (e) {
_completer!.completeError(e);
}
return _completer!.future;
}
Future createOrUpdateEvents({List<DateTime>? scheduleList, String? title, String? description, List<DateTime>? scheduleDateTime, List<DayOfWeek>? daysOfWeek}) async {
tzl.initializeTimeZones();
List<Event> events = [];
Location _currentLocation;
if (DateTime.now().timeZoneName == "+04")
_currentLocation = getLocation('Asia/Dubai');
else
_currentLocation = getLocation('Asia/Riyadh');
scheduleDateTime!.forEach((element) {
RecurrenceRule recurrenceRule = RecurrenceRule(
// RecurrenceFrequency.Daily,
// daysOfWeek: daysOfWeek,
// endDate: element,
until: element, frequency: Frequency.daily,
);
//added byAamir Tz Time
Event event = Event(writableCalendars!.id,
recurrenceRule: recurrenceRule,
start: TZDateTime.from(element, _currentLocation),
end: TZDateTime.from(element.add(Duration(minutes: 30)), _currentLocation),
title: title,
description: description);
events.add(event);
});
events.forEach((element) {
deviceCalendarPlugin.createOrUpdateEvent(element);
});
}
Future createOrUpdateEvent({required String title, required String description, required String location, DateTime? scheduleDateTime, String? eventId}) async {
RecurrenceRule recurrenceRule = RecurrenceRule(
// RecurrenceFrequency.Daily,
// daysOfWeek: daysOfWeek,
// endDate: scheduleDateTime,
until: scheduleDateTime, frequency: Frequency.daily,
);
Location _currentLocation;
// if (DateTime.now().timeZoneName == "+04")
// _currentLocation = getLocation('Asia/Dubai');
// else
_currentLocation = getLocation('Asia/Riyadh');
TZDateTime scheduleDateTimeUTZ = TZDateTime.from(scheduleDateTime!, _currentLocation);
print("writableCalendars-name: " + writableCalendars.name);
print("writableCalendars-Id: " + writableCalendars.id);
print("writableCalendarsToString: " + writableCalendars.toString());
print("writableCalendarsToString: " + writableCalendars!.id!);
Event event = Event(
writableCalendars!.id,
start: scheduleDateTimeUTZ,
end: scheduleDateTimeUTZ.add(Duration(minutes: 30)),
title: title,
description: description,
);
ios.CalendarEvent iosCalEvent =
ios.CalendarEvent(location: location, startDate: scheduleDateTimeUTZ, endDate: scheduleDateTimeUTZ.add(Duration(minutes: 30)), title: title, description: description, isAllDay: false);
if (Platform.isAndroid) {
Result<bool> result = await deviceCalendarPlugin.hasPermissions();
print(result);
await deviceCalendarPlugin.createOrUpdateEvent(event).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID " + eventId!);
});
} else {
await _myPlugin.createEvent(calendarId: writableCalendars.id!, event: iosCalEvent).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID iOS " + eventId!);
});
}
}
deleteEvent(String _calendarId, String _eventId) async {
if (Platform.isIOS) {
await _myPlugin.deleteEvent(calendarId: _calendarId, eventId: _eventId);
} else {
await deviceCalendarPlugin.deleteEvent(_calendarId, _eventId);
}
}
Future retrieveEvents(
String calendarId,
RetrieveEventsParams retrieveEventsParams,
) async {
if (Platform.isIOS) {
return await _myPlugin.getEvents(calendarId: calendarId);
} else {
return await deviceCalendarPlugin.retrieveEvents(calendarId, retrieveEventsParams);
}
}
Future createCalendar(
String calendarName, {
Color? calendarColor,
String? localAccountName,
}) async {
return await deviceCalendarPlugin.createCalendar(calendarName, calendarColor: calendarColor, localAccountName: localAccountName);
}
}
Future<Map<Permission, PermissionStatus>> requestPermissions() async {
var permissionResults = [Permission.calendarFullAccess].request();
return permissionResults;
}
showReminderBottomSheet(BuildContext context, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted,
{required Function() onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool isMultiAllowed = false}) async {
if (Platform.isAndroid) {
if (await PermissionService.isCalendarPermissionEnabled()) {
_showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
} else {
// Utils.showPermissionConsentDialog(context, TranslationBase.of(context).calendarPermission, () async {
// if (await Permission.calendarFullAccess.request().isGranted) {
// _showReminderDialog(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
// onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
// }
// });
}
} else {
if (await Permission.calendarWriteOnly.request().isGranted) {
if (await Permission.calendarFullAccess.request().isGranted) {
_showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
}
}
}
}
Future<void> _showReminderBottomSheet(BuildContext providedContext, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted,
{required Function onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool? isMultiAllowed}) async {
showCommonBottomSheetWithoutHeight(providedContext, title: "Set the timer of reminder".needTranslation, child: PrescriptionReminderView(
setReminder: (int value) async {
if (!isMultiAllowed!) {
if (onMultiDateSuccess == null) {
CalendarUtils calendarUtils = await CalendarUtils.getInstance();
await calendarUtils.createOrUpdateEvent(
title: title ?? "You have appointment with Dr. ".needTranslation + doctorName,
description: description ?? "At " + appoDateFormatted + " " + appoTimeFormatted,
scheduleDateTime: dateTime,
eventId: eventId,
location: '');
onSuccess();
}
} else {
onMultiDateSuccess!(value);
}
},
), callBackFunc: () {}, isFullScreen: false);
}
setCalender(BuildContext context,
{required String eventId, required int selectedMinutes, int? frequencyNumber, required int days, required String orderDate, required String itemDescriptionN, required String route}) async {
DateTime actualDate = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0);
frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2
int remainingDays = days - (Jiffy.parseFromDateTime(DateTime.now()).diff(Jiffy.parseFromDateTime(DateUtil.convertStringToDate(orderDate)), unit: Unit.day) as int);
if (remainingDays.isNegative) {
getIt.get<DialogService>().showErrorBottomSheet(message: "Prescription date has been already passed you can not add a reminder for this prescription.");
return;
}
CalendarUtils calendarUtils = await CalendarUtils.getInstance();
try {
for (int i = 0; i < remainingDays; i++) {
//event for number of days.
for (int j = 0; j < frequencyNumber; j++) {
// event for number of times per day.
if (j != 0) {
actualDate.add(new Duration(hours: 8)); // 8 hours addition for daily dose.
}
//Time subtraction from actual reminder time. like before 30, or 1 hour.
actualDate = Jiffy.parseFromDateTime(actualDate).subtract(minutes: selectedMinutes).dateTime;
calendarUtils.createOrUpdateEvent(
title: "$itemDescriptionN} Prescription Reminder",
description: "$itemDescriptionN $frequencyNumber $route ",
scheduleDateTime: actualDate,
eventId: eventId + (i.toString() + j.toString()),
location: '', //event id with varitions
);
actualDate = DateTime(actualDate.year, actualDate.month, actualDate.day, 8, 0);
}
actualDate = Jiffy.parseFromDateTime(actualDate).add(days: 1).dateTime;
}
} catch (ex) {
getIt.get<DialogService>().showErrorBottomSheet(message: "catch:$ex");
}
}
Future<void> checkAndRemove(hasReminder, {bool delete = false, String itemDescriptionN = ""}) async {
final ios.CalendarPlugin _myPlugin = ios.CalendarPlugin();
CalendarUtils calendarUtils = await CalendarUtils.getInstance();
DateTime startEventsDate = Jiffy.parseFromDateTime(DateTime.now()).subtract(days: 30).dateTime;
DateTime endEventsDate = Jiffy.parseFromDateTime(DateTime.now()).add(days: 120).dateTime;
RetrieveEventsParams params = RetrieveEventsParams(startDate: startEventsDate, endDate: endEventsDate);
if (calendarUtils.calendars != null) {
if (Platform.isAndroid) {
await processEvents(calendarUtils.calendars, calendarUtils, params, delete, itemDescriptionN, hasReminder);
} else {
List<ios.Calendar>? iosCalendars = await _myPlugin.getCalendars();
if (iosCalendars != null) {
await processEvents(iosCalendars.map((cal) => Calendar(id: cal.id, name: cal.name, accountName: cal.accountName)).toList(), calendarUtils, params, delete, itemDescriptionN, hasReminder);
}
}
}
}
Future<void> processEvents(List<Calendar> calendars, calendarUtils, params, delete, String itemDescriptionN, hasReminder) async {
for (var calendar in calendars) {
Result<UnmodifiableListView<Event>> events = await calendarUtils.retrieveEvents(calendar.id!, params);
for (var event in events.data!) {
if (event.title!.contains(itemDescriptionN)) {
if (delete) {
await calendarUtils.deleteEvent(calendar, event);
// AppToast.showSuccessToast(message: TranslationBase.of(context).reminderCancelSuccess);
hasReminder = false;
} else {
hasReminder = false;
// setState(() {
// hasReminder = true;
// });
}
}
}
}
}

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:device_calendar_plus/device_calendar_plus.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:jiffy/jiffy.dart' show Jiffy;
class CalenderUtilsNew {
@ -15,7 +16,7 @@ class CalenderUtilsNew {
Future<void> getCalenders() async {
CalendarPermissionStatus result = await DeviceCalendar.instance.hasPermissions();
if(result != CalendarPermissionStatus.granted) await DeviceCalendar.instance.requestPermissions();
if (result != CalendarPermissionStatus.granted) await DeviceCalendar.instance.requestPermissions();
var calenders = await calender.listCalendars();
calenders.forEach((calender) {
if (!calender.readOnly) {
@ -25,64 +26,131 @@ class CalenderUtilsNew {
}
FutureOr<bool> createOrUpdateEvent({required String title, required String description, required String location, DateTime? scheduleDateTime, String? eventId, int? reminderMinutes}) async {
print("the reminder minutes are $reminderMinutes");
if (writableCalender.isEmpty) {
await getCalenders();
}
var writableCalendars = writableCalender.first;
print("writableCalendars-name: " + writableCalendars.name);
print("writableCalendars-Id: " + writableCalendars.id);
print("writableCalendarsToString: " + writableCalendars.toString());
print("writableCalendarsToString: " + writableCalendars!.id!);
String eventResult = "";
CalendarPermissionStatus result = await DeviceCalendar.instance.hasPermissions();
if(result != CalendarPermissionStatus.granted) await DeviceCalendar.instance.requestPermissions();
if (result != CalendarPermissionStatus.granted) await DeviceCalendar.instance.requestPermissions();
print(result);
String eventResult = await DeviceCalendar.instance.createEvent(
calendarId: writableCalendars!.id,
title: title,
description: description,
startDate: scheduleDateTime!,
endDate: scheduleDateTime!.add(Duration(minutes: 30)),
reminderMinutes: reminderMinutes
);
print("the event Result is ${eventResult}");
// String eventId = await getEventIdIfEventExist(title!.split("#").last);
// if (eventId.isEmpty) {
eventResult = await DeviceCalendar.instance.createEvent(
calendarId: writableCalendars!.id,
title: title,
description: description,
startDate: scheduleDateTime!,
endDate: scheduleDateTime!.add(Duration(minutes: 30)),
reminderMinutes: reminderMinutes);
return eventResult.isNotEmpty;
// }
// await DeviceCalendar.instance.updateEvent(
// eventId: eventId,
// title: title,
// description: description,
// startDate: scheduleDateTime!,
// endDate: scheduleDateTime!.add(Duration(minutes: 30)),
// );
// return eventId.isNotEmpty;
}
FutureOr<bool> createMultipleEvents(
{required int reminderMinutes,
int? frequencyNumber,
required int days,
required String orderDate,
required String itemDescriptionN,
required String route,
Function(String)? onFailure,
String? prescriptionNumber}) async {
DateTime currentDay = DateTime.now();
DateTime actualDate = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0);
print("the frequency is $frequencyNumber");
frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2
int interval = calculateIntervalAsPerFrequency(frequencyNumber);
// int remainingDays = days - (Jiffy.parseFromDateTime(DateTime.now()).diff(Jiffy.parseFromDateTime(DateUtil.convertStringToDate(orderDate)), unit: Unit.day) as int);
Duration difference = (actualDate.difference(DateUtil.convertStringToDate(orderDate)));
int remainingDays = 5;
// if (remainingDays.isNegative) {
// onFailure?.call("Prescription date has been already passed you can not add a reminder for this prescription.");
// return false;
// }
bool statusOfOperation = false;
for (int i = 0; i < remainingDays; i++) {
//event for number of days.
for (int j = 0; j < frequencyNumber; j++) {
statusOfOperation = await createOrUpdateEvent(
title: "$itemDescriptionN} Medication about to due for prescription , #$prescriptionNumber",
description: "$itemDescriptionN $frequencyNumber $route ",
scheduleDateTime: actualDate,
location: '',
//event id with varitions
reminderMinutes: reminderMinutes);
if (!statusOfOperation) return false;
actualDate = actualDate.add(Duration(hours: interval));
// if (actualDate.difference(currentDay).inDays == 1) break;
}
// actualDate = actualDate.add(Duration(days: 1));
}
return statusOfOperation;
}
int calculateIntervalAsPerFrequency(int frequencyNumber) {
return 24 ~/ frequencyNumber;
}
FutureOr<List<Event>> getEvents() async {
var availableCalender = writableCalender.first;
DateTime startEventsDate = Jiffy.parseFromDateTime(DateTime.now()).subtract(days: 30).dateTime;
DateTime endEventsDate = Jiffy.parseFromDateTime(DateTime.now()).add(days: 120).dateTime;
return await calender.listEvents(startEventsDate, endEventsDate, calendarIds: [availableCalender.id]);
return await calender.listEvents(startEventsDate, endEventsDate, calendarIds: [availableCalender.id]);
}
FutureOr<bool> checkIfEventExist(String admissionId) async {
if(writableCalender.isEmpty)return false;
if (writableCalender.isEmpty) {
await getCalenders();
}
List<Event> events = await getEvents();
if(events.isEmpty) return false;
for(var event in events){
if (events.isEmpty) return false;
for (var event in events) {
List<String> title = event.title!.split("#");
print("the splitted admission id is ${title}");
if(title.contains(admissionId)) return true;
if (title.contains(admissionId)) return true;
}
return false;
return false;
}
FutureOr<String> getEventIdIfEventExist(String admissionId) async {
if (writableCalender.isEmpty) {
await getCalenders();
}
List<Event> events = await getEvents();
if (events.isEmpty) return "";
for (var event in events) {
List<String> title = event.title!.split("#");
if (title.contains(admissionId)) return event.eventId;
}
return "";
}
FutureOr<bool> checkAndRemove({required String id}) async {
if(writableCalender.isEmpty)return false;
if (writableCalender.isEmpty) {
await getCalenders();
}
List<Event> events = await getEvents();
if(events.isEmpty) return false;
for(var event in events){
if (events.isEmpty) return false;
for (var event in events) {
List<String> title = event.title!.split("#");
print("the splitted admission id is ${title}");
if(title.contains(id)) {
if (title.contains(id)) {
calender.deleteEvent(eventId: event.eventId);
return true;
}
@ -90,5 +158,21 @@ class CalenderUtilsNew {
return false;
}
FutureOr<bool> checkAndRemoveMultipleItems({required String id}) async {
if (writableCalender.isEmpty) {
await getCalenders();
}
List<Event> events = await getEvents();
if (events.isEmpty) return false;
bool statusOfOperation = false;
for (var event in events) {
List<String> title = event.title.split("#");
if (title.contains(id)) {
calender.deleteEvent(eventId: event.eventId);
statusOfOperation = true;
}
}
return statusOfOperation;
}
}

@ -369,6 +369,29 @@ class DateUtil {
}
}
static String getDateStringForNearestSlot(String date) {
DateTime dateObj = DateUtil.convertStringToDate(date);
return DateUtil.getWeekDay(dateObj.weekday) +
", " +
dateObj.day.toString() +
" " +
DateUtil.getMonth(dateObj.month) +
" " +
dateObj.year.toString() +
" " +
dateObj.hour.toString() +
":" +
getMinute(dateObj);
}
static String getMinute(DateTime dateObj) {
if (dateObj.minute == 0) {
return dateObj.minute.toString() + "0";
} else {
return dateObj.minute.toString();
}
}
static String getMonthDayYearLangDateFormatted(DateTime dateTime, String lang) {
if (dateTime != null) {
return lang == 'en'

@ -0,0 +1,38 @@
import 'dart:math';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:hmg_patient_app_new/core/utils/zoom_config.dart';
String makeId(int length) {
String result = "";
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
int charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters[Random().nextInt(charactersLength)];
}
return result;
}
String generateJwt(String sessionName, String roleType) {
try {
var iat = DateTime.now();
var exp = DateTime.now().add(Duration(days: 2));
final jwt = JWT(
{
'app_key': configs["ZOOM_SDK_KEY"],
'version': 1,
'user_identity': makeId(10),
'iat': (iat.millisecondsSinceEpoch / 1000).round(),
'exp': (exp.millisecondsSinceEpoch / 1000).round(),
'tpc': sessionName,
'role_type': int.parse(roleType),
'cloud_recording_option': 1,
},
);
var token = jwt.sign(SecretKey(configs["ZOOM_SDK_SECRET"]));
return token;
} catch (e) {
print(e);
return '';
}
}

@ -8,14 +8,22 @@ import 'package:firebase_messaging/firebase_messaging.dart' as fir;
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/entities/android_params.dart';
import 'package:flutter_callkit_incoming/entities/call_kit_params.dart';
import 'package:flutter_callkit_incoming/entities/ios_params.dart';
import 'package:flutter_callkit_incoming/entities/notification_params.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_ios_voip_kit_karmm/call_state_type.dart';
import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart';
// import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/utils/local_notifications.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
import '../cache_consts.dart';
@ -36,16 +44,83 @@ Future<dynamic> backgroundMessageHandler(dynamic message) async {
callPage(String sessionID, String token) async {}
_incomingCall(Map<String, dynamic> data) async {
print('the value of the _incomingCall remote message is $data');
// LandingPage.incomingCallData = IncomingCallData.fromJson(data);
// var dataItem = await AppSharedPreferences().getObject('call_data');
// if(dataItem != null ) return; // to stop repeated attempt to invoke the call
// if (LandingPage.isOpenCallPage == false) {
// LandingPage.isOpenCallPage = true;
String roomID = data['session_id'] ?? '';
// GetIt.instance<CacheService>().saveString(key: CacheConst.zoomRoomID, value: roomID);
// GetIt.instance<CacheService>().saveBool(key: CacheConst.isAppOpenedFromCall, value: true);
Utils.saveStringFromPrefs(CacheConst.zoomRoomID, roomID);
Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, true);
WidgetsFlutterBinding.ensureInitialized();
// var _currentUuid = Uuid().v4();
// await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
// }
// LandingPage.isOpenCallPage = false;
var _currentUuid = Uuid().v4();
CallKitParams callKitParams = CallKitParams(
id: _currentUuid,
nameCaller: "Dr Al Habib",
appName: 'Dr Al Habib',
avatar: 'https://play-lh.googleusercontent.com/FBNNpxb7m6eM6wtW7MV1Ffp6OXOGLI38q47zcvP29OCYA1yhYH5mZzl5itZi0TgOyZpG',
// handle: LandingPage.incomingCallData.name,
type: 1,
textAccept: 'Accept',
textDecline: 'Decline',
missedCallNotification: NotificationParams(
showNotification: true,
isShowCallback: false,
subtitle: 'Missed call',
callbackText: '',
),
callingNotification: const NotificationParams(
showNotification: false,
isShowCallback: true,
subtitle: 'Calling...',
callbackText: 'Hang Up',
),
duration: 30000,
extra: <String, dynamic>{'userId': '1a2b3c4d'},
headers: <String, dynamic>{'apiKey': 'Abc@123!', 'platform': 'flutter'},
android: const AndroidParams(
isImportant: true,
isShowFullLockedScreen: true,
isCustomNotification: true,
isShowLogo: false,
logoUrl: "https://play-lh.googleusercontent.com/FBNNpxb7m6eM6wtW7MV1Ffp6OXOGLI38q47zcvP29OCYA1yhYH5mZzl5itZi0TgOyZpG",
ringtonePath: 'system_ringtone_default',
backgroundColor: '#ED1C2B',
backgroundUrl: 'https://saudipedia.com/en/saudipediaen/uploads/images/2024/08/02/97358.jpg',
actionColor: '#4CAF50',
textColor: '#000000',
incomingCallNotificationChannelName: "Incoming Call",
missedCallNotificationChannelName: "Missed Call",
isShowCallID: false),
ios: IOSParams(
iconName: 'Meena Health',
handleType: 'generic',
supportsVideo: true,
maximumCallGroups: 2,
maximumCallsPerCallGroup: 1,
audioSessionMode: 'default',
audioSessionActive: true,
audioSessionPreferredSampleRate: 44100.0,
audioSessionPreferredIOBufferDuration: 0.005,
supportsDTMF: true,
supportsHolding: true,
supportsGrouping: false,
supportsUngrouping: false,
ringtonePath: 'system_ringtone_default',
),
);
FlutterCallkitIncoming.unsilenceEvents();
await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
await Future.delayed(Duration(milliseconds: 500));
}
@ -224,7 +299,9 @@ class PushNotificationHandler {
print('🎈 example: onDidAcceptIncomingCall $uuid - $callerId');
await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
await voIPKit.callConnected();
await Future.delayed(Duration(seconds: 1));
await Future.delayed(Duration(seconds: 2)).then((val) async {
await voIPKit.endCall();
});
// Navigator.pushNamed(
// locator<NavigationService>().navigatorKey.currentContext!,
@ -232,8 +309,6 @@ class PushNotificationHandler {
// arguments: CallArguments("hoover-dam", "123", "Patient", "40", "1", false),
// );
await voIPKit.endCall();
// Navigator.pushNamed(navigatorKey.currentContext!, VIDEO_CALL_SCREEN,
// arguments: VideoArgus(
// reservationId: int.parse(callerId), token: null, isVideo: true));

@ -330,7 +330,7 @@ class Utils {
repeat: false, reverse: false, frameRate: FrameRate(60), width: width.h, height: height.h, fit: BoxFit.fill),
SizedBox(height: 16.h),
(noDataText ?? LocaleKeys.noDataAvailable.tr())
.toText16(weight: FontWeight.w500, color: AppColors.greyTextColor, isCenter: true)
.toText14(weight: FontWeight.w500, color: AppColors.greyTextColor, isCenter: true)
.paddingSymmetrical(64.w, 0.h),
SizedBox(height: 16.h),
callToActionButton
@ -807,7 +807,11 @@ class Utils {
static Future<bool> checkConnection({bool bypassConnectionCheck = false}) async {
if (bypassConnectionCheck) return true;
List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult.contains(ConnectivityResult.mobile) || connectivityResult.contains(ConnectivityResult.wifi)) {
if (connectivityResult.contains(ConnectivityResult.mobile) ||
connectivityResult.contains(ConnectivityResult.wifi) ||
connectivityResult.contains(ConnectivityResult.ethernet) ||
connectivityResult.contains(ConnectivityResult.bluetooth) ||
connectivityResult.contains(ConnectivityResult.vpn)) {
return true;
} else {
return false;
@ -871,4 +875,54 @@ class Utils {
Uri uri = Uri.parse(url);
launchUrl(uri, mode: LaunchMode.inAppBrowserView);
}
static Color getCardBorderColor(int currentQueueStatus) {
switch (currentQueueStatus) {
case 0:
return AppColors.ratingColorYellow;
case 1:
return AppColors.primaryRedColor;
case 2:
return AppColors.successColor;
}
return AppColors.textColor;
}
static Color getCardButtonColor(int currentQueueStatus) {
switch (currentQueueStatus) {
case 0:
return AppColors.textColor.withValues(alpha: 0.08);
case 1:
return AppColors.primaryRedColor;
case 2:
return AppColors.successColor;
}
return AppColors.primaryRedColor;
}
static Color getCardButtonTextColor(int currentQueueStatus) {
switch (currentQueueStatus) {
case 0:
return Color(0xFFA2A2A2);
case 1:
return AppColors.whiteColor;
case 2:
return AppColors.whiteColor;
}
return AppColors.primaryRedColor;
}
static String getCardButtonText(int currentQueueStatus) {
switch (currentQueueStatus) {
case 0:
return "Please wait! you will be called for vital signs".needTranslation;
case 1:
return "Please visit Room S5 for vital signs".needTranslation;
case 2:
return "Please visit Room S5 to the Doctor".needTranslation;
}
return "";
}
}

@ -0,0 +1,4 @@
const Map configs = {
'ZOOM_SDK_KEY': 'b9T74nhfTg-ioP9urm970A',
'ZOOM_SDK_SECRET': 'KOzmjBNXQ1f4IPHpnngfL29uZvJMufSy2Fk8',
};

@ -263,7 +263,7 @@ extension EmailValidator on String {
style: TextStyle(fontSize: 19.f, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText20({Color? color, FontWeight? weight, bool isBold = false}) => Text(
Widget toText20({Color? color, FontWeight? weight, bool isBold = false, }) => Text(
this,
style: TextStyle(
fontSize: 20.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
@ -301,14 +301,14 @@ extension EmailValidator on String {
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false}) => Text(
Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: height ?? 23 / 28,
color: color ?? AppColors.blackColor,
fontSize: 28.f,
letterSpacing: -1,
letterSpacing: letterSpacing ?? -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);

@ -101,10 +101,7 @@ class AuthenticationRepoImp implements AuthenticationRepo {
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({
required dynamic checkPatientAuthenticationReq,
String? languageID,
}) async {
Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({required dynamic checkPatientAuthenticationReq, String? languageID}) async {
int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1;
checkPatientAuthenticationReq.patientOutSA = isOutKsa;
try {
@ -149,7 +146,6 @@ class AuthenticationRepoImp implements AuthenticationRepo {
sendActivationCodeReq.isDentalAllowedBackend = false;
final payload = sendActivationCodeReq.toJson();
if (isFormFamilyFile) {
payload.remove("MobileNo");
payload.remove("NationalID");
payload.remove("SMSSignature");
@ -265,6 +261,12 @@ class AuthenticationRepoImp implements AuthenticationRepo {
newRequest.isDentalAllowedBackend = false;
newRequest.forRegisteration = newRequest.isRegister ?? false;
newRequest.isRegister = false;
//silent login case removed token and login token
// if(newRequest.logInTokenID.isEmpty && newRequest.isSilentLogin == true) {
// newRequest.logInTokenID = null;
// newRequest.deviceToken = null;
// }
}
Map<String, dynamic> familyRequest = {};

@ -852,16 +852,13 @@ class AuthenticationViewModel extends ChangeNotifier {
request['isRegister'] = true;
_appState.setAppAuthToken = response['LogInTokenID'];
if (isPatientOutsideSA(request: response)) {
print("=======OUT SA=======");
sendActivationCode(
otpTypeEnum: OTPTypeEnumExtension.fromInt(request["OTP_SendType"]),
nationalIdOrFileNumber: request["PatientIdentificationID"].toString(),
phoneNumber: request["PatientMobileNumber"].toString(),
payload: request,
isForRegister: true,
);
otpTypeEnum: OTPTypeEnumExtension.fromInt(request["OTP_SendType"]),
nationalIdOrFileNumber: request["PatientIdentificationID"].toString(),
phoneNumber: request["PatientMobileNumber"].toString(),
payload: request,
isForRegister: true);
} else {
print("=======IN SA=======");
chekUserNHICData(request: request);
}
}

@ -0,0 +1,95 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_response_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/cities_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class BloodDonationRepo {
Future<Either<Failure, GenericApiModel<List<CitiesModel>>>> getAllCities();
Future<Either<Failure, GenericApiModel<List_BloodGroupDetailsModel>>> getPatientBloodGroupDetails();
}
class BloodDonationRepoImp implements BloodDonationRepo {
final ApiClient apiClient;
final LoggerService loggerService;
BloodDonationRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<CitiesModel>>>> getAllCities() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<CitiesModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_CITIES_REQUEST,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ListCities'];
final citiesList = list.map((item) => CitiesModel.fromJson(item as Map<String, dynamic>)).toList().cast<CitiesModel>();
apiResponse = GenericApiModel<List<CitiesModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: citiesList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List_BloodGroupDetailsModel>>> getPatientBloodGroupDetails() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List_BloodGroupDetailsModel>? apiResponse;
Failure? failure;
await apiClient.post(
GET_BLOOD_REQUEST,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_BloodGroupDetails'][0];
final patientBloodGroup = List_BloodGroupDetailsModel.fromJson(list);
apiResponse = GenericApiModel<List_BloodGroupDetailsModel>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: patientBloodGroup,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,133 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_repo.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_list_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_response_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/cities_model.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
class BloodDonationViewModel extends ChangeNotifier {
final DialogService dialogService;
BloodDonationRepo bloodDonationRepo;
ErrorHandlerService errorHandlerService;
final NavigationService navigationService;
final AppState appState;
List<CitiesModel> citiesList = [];
List<BloodGroupListModel> bloodGroupList = [
BloodGroupListModel("O+", 0),
BloodGroupListModel("O-", 1),
BloodGroupListModel("AB+", 2),
BloodGroupListModel("AB-", 3),
BloodGroupListModel("A+", 4),
BloodGroupListModel("A-", 5),
BloodGroupListModel("B+", 6),
BloodGroupListModel("B-", 7),
];
late CitiesModel selectedCity;
late BloodGroupListModel selectedBloodGroup;
int _selectedHospitalIndex = 0;
int _selectedBloodTypeIndex = 0;
String _selectedBloodType = '';
List_BloodGroupDetailsModel patientBloodGroupDetailsModel = List_BloodGroupDetailsModel();
BloodDonationViewModel({required this.bloodDonationRepo, required this.errorHandlerService, required this.navigationService, required this.dialogService, required this.appState});
setSelectedCity(CitiesModel city) {
selectedCity = city;
notifyListeners();
}
Future<void> getRegionSelectedClinics({Function(dynamic)? onSuccess, Function(String)? onError}) async {
citiesList.clear();
selectedCity = CitiesModel();
notifyListeners();
final result = await bloodDonationRepo.getAllCities();
result.fold(
(failure) async {
onError!(failure.message);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage ?? 'An unexpected error occurred');
} else if (apiResponse.messageStatus == 1) {
citiesList = apiResponse.data!;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getPatientBloodGroupDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bloodDonationRepo.getPatientBloodGroupDetails();
result.fold(
(failure) async {
onError!(failure.message);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage ?? 'An unexpected error occurred');
} else if (apiResponse.messageStatus == 1) {
patientBloodGroupDetailsModel = apiResponse.data!;
CitiesModel citiesModel = CitiesModel();
citiesModel.iD = getSelectedCityID();
_selectedHospitalIndex = (citiesModel.iD! - 1);
citiesModel.description = citiesList[_selectedHospitalIndex].description;
citiesModel.descriptionN = citiesList[_selectedHospitalIndex].descriptionN;
selectedCity = citiesModel;
_selectedBloodType = patientBloodGroupDetailsModel.bloodGroup!;
_selectedBloodTypeIndex = getBloodIndex(_selectedBloodType);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
int getSelectedCityID() {
int cityID = 1;
citiesList.forEach((element) {
if (element.description == patientBloodGroupDetailsModel.city) {
cityID = element.iD!;
}
});
return cityID;
}
int getBloodIndex(String type) {
switch (type) {
case "O+":
return 0;
case "O-":
return 1;
case "AB+":
return 2;
case "AB-":
return 3;
case "A+":
return 4;
case "A-":
return 5;
case "B+":
return 6;
case "B-":
return 7;
default:
return 0;
}
}
}

@ -0,0 +1,6 @@
class BloodGroupListModel {
String name;
int value;
BloodGroupListModel(this.name, this.value);
}

@ -0,0 +1,61 @@
class List_BloodGroupDetailsModel {
int? iD;
int? patientID;
int? patientType;
bool? patientOutSA;
int? zipCode;
String? cellNumber;
String? cityCode;
String? city;
int? gender;
String? bloodGroup;
String? nationalID;
bool? isActive;
List_BloodGroupDetailsModel({
this.iD,
this.patientID,
this.patientType,
this.patientOutSA,
this.zipCode,
this.cellNumber,
this.cityCode,
this.city,
this.gender,
this.bloodGroup,
this.nationalID,
this.isActive,
});
List_BloodGroupDetailsModel.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
patientID = json['PatientID'];
patientType = json['PatientType'];
patientOutSA = json['PatientOutSA'];
zipCode = json['ZipCode'];
cellNumber = json['CellNumber'];
cityCode = json['CityCode'];
city = json['City'];
gender = json['Gender'];
bloodGroup = json['BloodGroup'];
nationalID = json['NationalID'];
isActive = json['IsActive'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['PatientID'] = this.patientID;
data['PatientType'] = this.patientType;
data['PatientOutSA'] = this.patientOutSA;
data['ZipCode'] = this.zipCode;
data['CellNumber'] = this.cellNumber;
data['CityCode'] = this.cityCode;
data['City'] = this.city;
data['Gender'] = this.gender;
data['BloodGroup'] = this.bloodGroup;
data['NationalID'] = this.nationalID;
data['IsActive'] = this.isActive;
return data;
}
}

@ -0,0 +1,21 @@
class CitiesModel {
int? iD;
String? description;
String? descriptionN;
CitiesModel({this.iD, this.description, this.descriptionN});
CitiesModel.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
description = json['Description'];
descriptionN = json['DescriptionN'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['Description'] = this.description;
data['DescriptionN'] = this.descriptionN;
return data;
}
}

@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/resp_model
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_patient_dental_plan_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.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/models/resp_models/patient_appointment_share_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'models/resp_models/laser_body_parts.dart';
@ -84,6 +85,22 @@ abstract class BookAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<LaserBodyPart>>>> getLaserClinics(int laserCategoryID, int projectID, int languageID,
{Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> checkScannedNFCAndQRCode(String nfcCode, int projectId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareWalkInAppointment({required int projectID, required int clinicID, required int doctorID});
Future<Either<Failure, GenericApiModel<dynamic>>> insertSpecificAppointmentForWalkIn(
{required int docID,
required int clinicID,
required int projectID,
required String selectedTime,
required String selectedDate,
required int initialSlotDuration,
required int genderID,
required int userAge,
Function(dynamic)? onSuccess,
Function(String)? onError});
}
class BookAppointmentsRepoImp implements BookAppointmentsRepo {
@ -848,4 +865,144 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> checkScannedNFCAndQRCode(String nfcCode, int projectId, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {"NFC_Code": nfcCode, "ProjectID": projectId};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
CHECK_SCANNED_NFC_QR_CODE,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareWalkInAppointment({required int projectID, required int clinicID, required int doctorID}) async {
Map<String, dynamic> mapRequest = {"ProjectID": projectID, "ClinicID": clinicID, "DoctorID": doctorID};
try {
GenericApiModel<PatientAppointmentShareResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_SHARE_FOR_WALKIN_APPOINTMENT,
body: mapRequest,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['OnlineCheckInAppointmentsWalkInModel'];
if (list == null || list.isEmpty) {
throw Exception("patient share list is empty");
}
final patientShareObj = PatientAppointmentShareResponseModel.fromJson(list);
patientShareObj.isCash = response["IsCash"];
patientShareObj.isEligible = response["IsEligible"];
patientShareObj.isInsured = response["IsInsured"];
apiResponse = GenericApiModel<PatientAppointmentShareResponseModel>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: patientShareObj,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> insertSpecificAppointmentForWalkIn(
{required int docID,
required int clinicID,
required int projectID,
required String selectedTime,
required String selectedDate,
required int initialSlotDuration,
required int genderID,
required int userAge,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"IsForLiveCare": true,
"ProjectID": projectID,
"ClinicID": clinicID,
"DoctorID": docID,
"StartTime": selectedTime,
"SelectedTime": selectedTime,
"EndTime": selectedTime,
"InitialSlotDuration": initialSlotDuration,
"StrAppointmentDate": selectedDate,
"IsVirtual": false,
"BookedBy": 102,
"VisitType": 1,
"VisitFor": 1,
"GenderID": genderID,
"Age": userAge
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
INSERT_WALKIN_APPOINTMENT,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final appointmentNo = response['AppointmentNo'];
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: response["ErrorEndUserMessage"],
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -24,6 +24,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/timeslots.
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.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/models/resp_models/patient_appointment_share_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/home/navigation_screen.dart';
@ -112,6 +113,15 @@ class BookAppointmentsViewModel extends ChangeNotifier {
String? selectedClinicForFilters;
bool applyFilters = false;
bool isWaitingAppointmentAvailable = false;
bool isWaitingAppointmentSelected = false;
int waitingAppointmentProjectID = 0;
DoctorsListResponseModel? waitingAppointmentDoctor;
String waitingAppointmentNFCCode = "";
PatientAppointmentShareResponseModel? patientWalkInAppointmentShareResponseModel;
///variables for laser clinic
List<LaserCategoryType> femaleLaserCategory = [
LaserCategoryType(1, 'bodyString'),
@ -171,11 +181,32 @@ class BookAppointmentsViewModel extends ChangeNotifier {
dentalChiefComplaintsList.clear();
isContinueDentalPlan = false;
isChiefComplaintsListLoading = true;
isWaitingAppointmentSelected = false;
bodyTypes = [maleLaserCategory, femaleLaserCategory];
// getLocation();
notifyListeners();
}
setIsWaitingAppointmentSelected(bool isWaitingAppointmentSelected) {
this.isWaitingAppointmentSelected = isWaitingAppointmentSelected;
notifyListeners();
}
setWaitingAppointmentDoctor(DoctorsListResponseModel waitingAppointmentDoctor) {
this.waitingAppointmentDoctor = waitingAppointmentDoctor;
notifyListeners();
}
setWaitingAppointmentNFCCode(String waitingAppointmentNFCCode) {
this.waitingAppointmentNFCCode = waitingAppointmentNFCCode;
notifyListeners();
}
setWaitingAppointmentProjectID(int projectID) {
waitingAppointmentProjectID = projectID;
notifyListeners();
}
setIsDoctorsListLoading(bool value) {
if (value) {
doctorsList.clear();
@ -337,22 +368,20 @@ class BookAppointmentsViewModel extends ChangeNotifier {
//TODO: Make the API dynamic with parameters for ProjectID, isNearest, languageID, doctorId, doctorName
Future<void> getDoctorsList(
{int projectID = 0,
bool isNearest = false,
int doctorId = 0,
{int projectID = 0, bool isNearest = true, int doctorId = 0,
String doctorName = "",
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
doctorsList.clear();
projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID;
final result = await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, isNearest, doctorId, doctorName,
isContinueDentalPlan: isContinueDentalPlan);
final result =
await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, doctorName.isNotEmpty ? false : isNearest, doctorId, doctorName, isContinueDentalPlan: isContinueDentalPlan);
result.fold(
(failure) async {
isDoctorsListLoading = false;
if (onError != null) onError("No doctors found for the search criteria".needTranslation);
onError!("No doctors found for the search criteria".needTranslation);
notifyListeners();
},
(apiResponse) {
@ -468,6 +497,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
initialSlotDuration = apiResponse.data["InitialSlotDuration"];
freeSlotsResponse = apiResponse.data['FreeTimeSlots'];
isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"];
// isWaitingAppointmentAvailable = true;
freeSlotsResponse.forEach((element) {
// date = (isLiveCareSchedule != null && isLiveCareSchedule)
// ? DateUtil.convertStringToDate(element)
@ -1165,4 +1197,95 @@ class BookAppointmentsViewModel extends ChangeNotifier {
laserBodyPartsList = [];
duration = 0;
}
Future<void> checkScannedNFCAndQRCode(String nfcCode, int projectId, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.checkScannedNFCAndQRCode(nfcCode, projectId);
result.fold(
(failure) async {
onError!("Invalid verification point scanned.".needTranslation);
},
(apiResponse) {
// if (apiResponse.data['returnValue'] == 0) {
// onError!("Invalid verification point scanned.".needTranslation);
// } else if (apiResponse.data['returnValue'] == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
// }
},
);
}
Future<void> getWalkInPatientShareAppointment({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.getPatientShareWalkInAppointment(projectID: waitingAppointmentProjectID, clinicID: selectedDoctor.clinicID!, doctorID: selectedDoctor.doctorID!);
result.fold(
(failure) async {
if (onError != null) {
onError(failure.message);
}
// await errorHandlerService.handleError(
// failure: failure,
// onOkPressed: () {
// onError!(failure.message);
// });
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientWalkInAppointmentShareResponseModel = apiResponse.data!;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> insertSpecificAppointmentForWalkIn({Function(dynamic p1)? onSuccess, Function(dynamic p1)? onError}) async {
_appState = getIt<AppState>();
final result = await bookAppointmentsRepo.insertSpecificAppointmentForWalkIn(
docID: selectedDoctor.doctorID!,
clinicID: selectedDoctor.clinicID!,
projectID: selectedDoctor.projectID!,
selectedDate: selectedAppointmentDate,
selectedTime: selectedAppointmentTime,
initialSlotDuration: initialSlotDuration,
genderID: _appState.getAuthenticatedUser()!.gender!,
userAge: _appState.getAuthenticatedUser()!.age!,
onError: onError);
result.fold(
(failure) async {
print(failure);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
LoadingUtils.hideFullScreenLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!,
child: Utils.getErrorWidget(loadingText: apiResponse.errorMessage),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data == null || apiResponse.data!.isEmpty) {
onError!("Unexpected Error Occurred".needTranslation);
return;
}
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -0,0 +1,37 @@
class GetAllergiesResponseModel {
int? patientID;
int? allergyDiseaseType;
int? allergyDiseaseID;
String? description;
String? descriptionN;
String? remarks;
GetAllergiesResponseModel({
this.patientID,
this.allergyDiseaseType,
this.allergyDiseaseID,
this.description,
this.descriptionN,
this.remarks,
});
GetAllergiesResponseModel.fromJson(Map<String, dynamic> json) {
patientID = json['PatientID'];
allergyDiseaseType = json['AllergyDiseaseType'];
allergyDiseaseID = json['AllergyDiseaseID'];
description = json['Description'];
descriptionN = json['DescriptionN'];
remarks = json['Remarks'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['PatientID'] = this.patientID;
data['AllergyDiseaseType'] = this.allergyDiseaseType;
data['AllergyDiseaseID'] = this.allergyDiseaseID;
data['Description'] = this.description;
data['DescriptionN'] = this.descriptionN;
data['Remarks'] = this.remarks;
return data;
}
}

@ -1054,8 +1054,8 @@ class EmergencyServicesViewModel extends ChangeNotifier {
bool result = await navServices.push(
CustomPageRoute(
page: MapUtilityScreen(
confirmButtonString: "Submit Request ".needTranslation,
titleString: "Select Location",
confirmButtonString: "Submit Request".needTranslation,
titleString: "Select Location".needTranslation,
subTitleString: "Please select the location".needTranslation,
isGmsAvailable: appState.isGMSAvailable,
),

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
@ -36,6 +38,10 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
late AppState _appState;
Duration countdownDuration = Duration(minutes: 1, seconds: 0);
late ValueNotifier<Duration> durationNotifier;
late Timer timer;
initImmediateLiveCare() {
_appState = getIt<AppState>();
immediateLiveCareClinicsList = [];
@ -144,7 +150,11 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
patientLiveCareHistoryList = apiResponse.data!;
if (patientLiveCareHistoryList.isNotEmpty) {
if (patientLiveCareHistoryList[0].callStatus! < 4) {
countdownDuration = Duration(seconds: 0);
patientHasPendingLiveCareRequest = true;
countdownDuration = Duration(minutes: patientLiveCareHistoryList.first.watingtimeInteger!, seconds: 0);
durationNotifier = ValueNotifier<Duration>(countdownDuration);
startTimer();
} else {
patientHasPendingLiveCareRequest = false;
}
@ -159,4 +169,20 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
},
);
}
void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime());
notifyListeners();
}
void addTime() {
final seconds = durationNotifier.value.inSeconds - 1;
if (seconds < 0) {
timer?.cancel();
// Handle end of timer here
// showEndMessage();
} else {
durationNotifier.value = Duration(seconds: seconds);
}
}
}

@ -78,10 +78,12 @@ class InsuranceViewModel extends ChangeNotifier {
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {
isInsuranceLoading = false;
isInsuranceDataToBeLoaded = false;
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
isInsuranceDataToBeLoaded = false;
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientInsuranceList = apiResponse.data!;

@ -289,7 +289,7 @@ class LabViewModel extends ChangeNotifier {
);
}
Future<void> getPatientLabResult(PatientLabOrdersResponseModel laborder, String procedureName, String testDescription) async {
Future<void> getPatientLabResult(PatientLabOrdersResponseModel laborder, String procedureName, String testDescription, String unitOfMeasure) async {
LoaderBottomSheet.showLoader();
mainLabResults.clear();
filteredGraphValues.clear();
@ -339,6 +339,7 @@ class LabViewModel extends ChangeNotifier {
} catch (e) {}
});
LabResult recentResult = recentThree.first;
recentResult.uOM = unitOfMeasure;
checkIfGraphShouldBeDisplayed(recentResult);
recentResult.verifiedOn = resultDate(DateUtil.convertStringToDate(recentResult.verifiedOnDateTime!));
// filteredGraphValues = [filteredGraphValues.first];

@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_allergies_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine_response_model.dart';
@ -38,6 +39,8 @@ abstract class MedicalFileRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> removeFamilyFile({required int? id});
Future<Either<Failure, GenericApiModel<dynamic>>> acceptRejectFamilyFile({required int? id, required int? status});
Future<Either<Failure, GenericApiModel<List<GetAllergiesResponseModel>>>> getPatientAllergiesList({Function(dynamic)? onSuccess, Function(String)? onError});
}
class MedicalFileRepoImp implements MedicalFileRepo {
@ -549,4 +552,42 @@ class MedicalFileRepoImp implements MedicalFileRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<GetAllergiesResponseModel>>>> getPatientAllergiesList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {"isDentalAllowedBackend": false, "OutSA": 0};
try {
GenericApiModel<List<GetAllergiesResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_ALLERGIES,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['Patient_Allergies'];
final vaccinesList = list.map((item) => GetAllergiesResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetAllergiesResponseModel>();
apiResponse = GenericApiModel<List<GetAllergiesResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: vaccinesList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/utils/request_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_allergies_response_model.dart';
import 'package:hmg_patient_app_new/features/common/models/family_file_request.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart';
@ -27,6 +28,7 @@ class MedicalFileViewModel extends ChangeNotifier {
bool isPatientSickLeaveListLoading = false;
bool isPatientSickLeavePDFLoading = false;
bool isPatientMedicalReportsListLoading = false;
bool isPatientAllergiesListLoading = false;
MedicalFileRepo medicalFileRepo;
ErrorHandlerService errorHandlerService;
@ -34,6 +36,8 @@ class MedicalFileViewModel extends ChangeNotifier {
List<PatientVaccineResponseModel> patientVaccineList = [];
List<PatientSickLeavesResponseModel> patientSickLeaveList = [];
List<GetAllergiesResponseModel> patientAllergiesList = [];
List<PatientMedicalReportResponseModel> patientMedicalReportList = [];
List<PatientMedicalReportResponseModel> patientMedicalReportRequestedList = [];
@ -69,8 +73,10 @@ class MedicalFileViewModel extends ChangeNotifier {
initMedicalFileProvider() {
patientMedicalReportAppointmentHistoryList.clear();
patientAllergiesList.clear();
isPatientVaccineListLoading = true;
isPatientMedicalReportsListLoading = true;
isPatientAllergiesListLoading = true;
notifyListeners();
}
@ -89,7 +95,6 @@ class MedicalFileViewModel extends ChangeNotifier {
void onFamilyFileTabChange(int index) {
setSelectedFamilyFileTabIndex = index;
notifyListeners();
}
setIsPatientVaccineListLoading(bool isLoading) {
@ -162,6 +167,32 @@ class MedicalFileViewModel extends ChangeNotifier {
);
}
Future<void> getPatientAllergiesList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isPatientAllergiesListLoading = true;
patientAllergiesList.clear();
notifyListeners();
final result = await medicalFileRepo.getPatientAllergiesList();
result.fold(
(failure) async {
isPatientAllergiesListLoading = false;
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientAllergiesList = apiResponse.data!;
isPatientAllergiesListLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getPatientSickLeaveList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
patientSickLeaveList.clear();
final result = await medicalFileRepo.getPatientSickLeavesList();
@ -442,9 +473,6 @@ class MedicalFileViewModel extends ChangeNotifier {
);
}
Future<void> addFamilyFile({required OTPTypeEnum otpTypeEnum}) async {
LoaderBottomSheet.showLoader();
AuthenticationViewModel authVM = getIt.get<AuthenticationViewModel>();
@ -489,6 +517,13 @@ class MedicalFileViewModel extends ChangeNotifier {
});
}
Future<void> clearAuthValues() async {
authVM.nationalIdController.clear();
authVM.phoneNumberController.clear();
authVM.emailController.clear();
authVM.dobController.clear();
}
Future<void> handleFamilyFileRequestOTPVerification() async {
LoaderBottomSheet.showLoader();
if (!_appState.getIsChildLoggedIn) {
@ -600,7 +635,7 @@ class MedicalFileViewModel extends ChangeNotifier {
getFamilyFiles(status: 0);
getAllPendingRecordsByResponseId();
LoaderBottomSheet.hideLoader();
onFamilyFileTabChange(0);
// onFamilyFileTabChange(0);
}
},
);

@ -141,7 +141,7 @@ class PatientAppointmentShareResponseModel {
doctorID = json['DoctorID'];
doctorImageURL = json['DoctorImageURL'];
doctorNameObj = json['DoctorNameObj'];
doctorSpeciality = json['DoctorSpeciality'].cast<String>();
// doctorSpeciality = json['DoctorSpeciality'].cast<String>();
errCode = json['ErrCode'];
groupID = json['GroupID'];
iSAllowOnlineCheckedIN = json['ISAllowOnlineCheckedIN'];

@ -37,6 +37,9 @@ class MyAppointmentsViewModel extends ChangeNotifier {
DateTime? start = null;
DateTime? end = null;
bool isPatientHasQueueAppointment = false;
int currentQueueStatus = 0;
List<PatientAppointmentHistoryResponseModel> patientAppointmentsHistoryList = [];
List<PatientAppointmentHistoryResponseModel> filteredAppointmentList = [];
@ -85,6 +88,12 @@ class MyAppointmentsViewModel extends ChangeNotifier {
isTamaraDetailsLoading = true;
isAppointmentPatientShareLoading = true;
isEyeMeasurementsAppointmentsLoading = true;
isPatientHasQueueAppointment = false;
notifyListeners();
}
setCurrentQueueStatus(int currentQueueStatus) {
this.currentQueueStatus = currentQueueStatus;
notifyListeners();
}

@ -0,0 +1,318 @@
class PrescriptionDeliveryResponseModel {
int? iD;
int? patientId;
int? patientOutSa;
bool? isOutPatient;
int? projectId;
int? nearestProjectId;
dynamic longitude;
dynamic latitude;
dynamic appointmentNo;
dynamic dischargeId;
int? statusId;
int? serviceId;
int? channel;
Orderpayment? orderpayment;
dynamic orderselectedservice;
dynamic wforder;
dynamic orderapprovalobj;
String? created;
dynamic createdBy;
dynamic modified;
dynamic modifiedBy;
bool? isDeleted;
String? statusText;
int? paymentStatus;
dynamic clientRequestid;
dynamic paymentStatusText;
String? projectName;
String? nearestProjectName;
dynamic paymentAmount;
WFOrder? wFOrder;
String? serviceText;
bool? isSentForApproval;
int? exaCartOrderId;
bool? isTimer;
int? timeSeconds;
int? totalPendingSeconds;
int? timeMinute;
int? timeHour;
int? timeTotalSeconds;
int? timeTotalMinute;
int? timeTotalHour;
dynamic approvalStatus;
bool? isActive;
int? clickButton;
List<dynamic>? procedures;
dynamic pickupLocation;
dynamic dropOffLocation;
dynamic clinicName;
dynamic doctorName;
dynamic branch;
dynamic time;
dynamic notes;
PrescriptionDeliveryResponseModel(
{this.iD,
this.patientId,
this.patientOutSa,
this.isOutPatient,
this.projectId,
this.nearestProjectId,
this.longitude,
this.latitude,
this.appointmentNo,
this.dischargeId,
this.statusId,
this.serviceId,
this.channel,
this.orderpayment,
this.orderselectedservice,
this.wforder,
this.orderapprovalobj,
this.created,
this.createdBy,
this.modified,
this.modifiedBy,
this.isDeleted,
this.statusText,
this.paymentStatus,
this.clientRequestid,
this.paymentStatusText,
this.projectName,
this.nearestProjectName,
this.paymentAmount,
this.wFOrder,
this.serviceText,
this.isSentForApproval,
this.exaCartOrderId,
this.isTimer,
this.timeSeconds,
this.totalPendingSeconds,
this.timeMinute,
this.timeHour,
this.timeTotalSeconds,
this.timeTotalMinute,
this.timeTotalHour,
this.approvalStatus,
this.isActive,
this.clickButton,
this.procedures,
this.pickupLocation,
this.dropOffLocation,
this.clinicName,
this.doctorName,
this.branch,
this.time,
this.notes});
PrescriptionDeliveryResponseModel.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
patientId = json['PatientId'];
patientOutSa = json['PatientOutSa'];
isOutPatient = json['IsOutPatient'];
projectId = json['ProjectId'];
nearestProjectId = json['NearestProjectId'];
longitude = json['Longitude'];
latitude = json['Latitude'];
appointmentNo = json['AppointmentNo'];
dischargeId = json['DischargeId'];
statusId = json['StatusId'];
serviceId = json['ServiceId'];
channel = json['Channel'];
orderpayment = json['orderpayment'] != null ? new Orderpayment.fromJson(json['orderpayment']) : null;
orderselectedservice = json['orderselectedservice'];
wforder = json['wforder'];
orderapprovalobj = json['orderapprovalobj'];
created = json['Created'];
createdBy = json['CreatedBy'];
modified = json['Modified'];
modifiedBy = json['ModifiedBy'];
isDeleted = json['IsDeleted'];
statusText = json['StatusText'];
paymentStatus = json['PaymentStatus'];
clientRequestid = json['ClientRequestid'];
paymentStatusText = json['PaymentStatusText'];
projectName = json['ProjectName'];
nearestProjectName = json['NearestProjectName'];
paymentAmount = json['PaymentAmount'];
wFOrder = json['WF_order'] != null ? new WFOrder.fromJson(json['WF_order']) : null;
serviceText = json['ServiceText'];
isSentForApproval = json['isSentForApproval'];
exaCartOrderId = json['ExaCart_OrderId'];
isTimer = json['isTimer'];
timeSeconds = json['TimeSeconds'];
totalPendingSeconds = json['TotalPendingSeconds'];
timeMinute = json['TimeMinute'];
timeHour = json['TimeHour'];
timeTotalSeconds = json['TimeTotalSeconds'];
timeTotalMinute = json['TimeTotalMinute'];
timeTotalHour = json['TimeTotalHour'];
approvalStatus = json['ApprovalStatus'];
isActive = json['isActive'];
clickButton = json['ClickButton'];
pickupLocation = json['PickupLocation'];
dropOffLocation = json['DropOffLocation'];
clinicName = json['clinicName'];
doctorName = json['DoctorName'];
branch = json['Branch'];
time = json['Time'];
notes = json['Notes'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['PatientId'] = this.patientId;
data['PatientOutSa'] = this.patientOutSa;
data['IsOutPatient'] = this.isOutPatient;
data['ProjectId'] = this.projectId;
data['NearestProjectId'] = this.nearestProjectId;
data['Longitude'] = this.longitude;
data['Latitude'] = this.latitude;
data['AppointmentNo'] = this.appointmentNo;
data['DischargeId'] = this.dischargeId;
data['StatusId'] = this.statusId;
data['ServiceId'] = this.serviceId;
data['Channel'] = this.channel;
if (this.orderpayment != null) {
data['orderpayment'] = this.orderpayment!.toJson();
}
data['orderselectedservice'] = this.orderselectedservice;
data['wforder'] = this.wforder;
data['orderapprovalobj'] = this.orderapprovalobj;
data['Created'] = this.created;
data['CreatedBy'] = this.createdBy;
data['Modified'] = this.modified;
data['ModifiedBy'] = this.modifiedBy;
data['IsDeleted'] = this.isDeleted;
data['StatusText'] = this.statusText;
data['PaymentStatus'] = this.paymentStatus;
data['ClientRequestid'] = this.clientRequestid;
data['PaymentStatusText'] = this.paymentStatusText;
data['ProjectName'] = this.projectName;
data['NearestProjectName'] = this.nearestProjectName;
data['PaymentAmount'] = this.paymentAmount;
if (this.wFOrder != null) {
data['WF_order'] = this.wFOrder!.toJson();
}
data['ServiceText'] = this.serviceText;
data['isSentForApproval'] = this.isSentForApproval;
data['ExaCart_OrderId'] = this.exaCartOrderId;
data['isTimer'] = this.isTimer;
data['TimeSeconds'] = this.timeSeconds;
data['TotalPendingSeconds'] = this.totalPendingSeconds;
data['TimeMinute'] = this.timeMinute;
data['TimeHour'] = this.timeHour;
data['TimeTotalSeconds'] = this.timeTotalSeconds;
data['TimeTotalMinute'] = this.timeTotalMinute;
data['TimeTotalHour'] = this.timeTotalHour;
data['ApprovalStatus'] = this.approvalStatus;
data['isActive'] = this.isActive;
data['ClickButton'] = this.clickButton;
data['PickupLocation'] = this.pickupLocation;
data['DropOffLocation'] = this.dropOffLocation;
data['clinicName'] = this.clinicName;
data['DoctorName'] = this.doctorName;
data['Branch'] = this.branch;
data['Time'] = this.time;
data['Notes'] = this.notes;
return data;
}
}
class Orderpayment {
int? iD;
int? orderId;
dynamic clientRequestId;
dynamic totalAmount;
int? paymentStatus;
dynamic order;
String? created;
dynamic createdBy;
dynamic modified;
dynamic modifiedBy;
bool? isDeleted;
Orderpayment({this.iD, this.orderId, this.clientRequestId, this.totalAmount, this.paymentStatus, this.order, this.created, this.createdBy, this.modified, this.modifiedBy, this.isDeleted});
Orderpayment.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
orderId = json['OrderId'];
clientRequestId = json['ClientRequestId'];
totalAmount = json['TotalAmount'];
paymentStatus = json['PaymentStatus'];
order = json['Order'];
created = json['Created'];
createdBy = json['CreatedBy'];
modified = json['Modified'];
modifiedBy = json['ModifiedBy'];
isDeleted = json['IsDeleted'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['OrderId'] = this.orderId;
data['ClientRequestId'] = this.clientRequestId;
data['TotalAmount'] = this.totalAmount;
data['PaymentStatus'] = this.paymentStatus;
data['Order'] = this.order;
data['Created'] = this.created;
data['CreatedBy'] = this.createdBy;
data['Modified'] = this.modified;
data['ModifiedBy'] = this.modifiedBy;
data['IsDeleted'] = this.isDeleted;
return data;
}
}
class WFOrder {
dynamic wfButtonsDTO;
int? iD;
int? orderId;
int? previousStep;
int? nextStep;
int? serviceId;
dynamic order;
String? created;
dynamic createdBy;
dynamic modified;
dynamic modifiedBy;
bool? isDeleted;
WFOrder({this.wfButtonsDTO, this.iD, this.orderId, this.previousStep, this.nextStep, this.serviceId, this.order, this.created, this.createdBy, this.modified, this.modifiedBy, this.isDeleted});
WFOrder.fromJson(Map<String, dynamic> json) {
wfButtonsDTO = json['wf_ButtonsDTO'];
iD = json['ID'];
orderId = json['OrderId'];
previousStep = json['PreviousStep'];
nextStep = json['NextStep'];
serviceId = json['ServiceId'];
order = json['Order'];
created = json['Created'];
createdBy = json['CreatedBy'];
modified = json['Modified'];
modifiedBy = json['ModifiedBy'];
isDeleted = json['IsDeleted'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['wf_ButtonsDTO'] = this.wfButtonsDTO;
data['ID'] = this.iD;
data['OrderId'] = this.orderId;
data['PreviousStep'] = this.previousStep;
data['NextStep'] = this.nextStep;
data['ServiceId'] = this.serviceId;
data['Order'] = this.order;
data['Created'] = this.created;
data['CreatedBy'] = this.createdBy;
data['Modified'] = this.modified;
data['ModifiedBy'] = this.modifiedBy;
data['IsDeleted'] = this.isDeleted;
return data;
}
}

@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_delivery_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
@ -15,7 +16,13 @@ abstract class PrescriptionsRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> getPrescriptionInstructionsPDF({required PatientPrescriptionsResponseModel prescriptionsResponseModel});
Future<Either<Failure, GenericApiModel<dynamic>>> getPrescriptionPDF({required PatientPrescriptionsResponseModel prescriptionsResponseModel, required List<PrescriptionDetailResponseModel> prescriptionDetailsList});
Future<Either<Failure, GenericApiModel<dynamic>>> getPrescriptionPDF(
{required PatientPrescriptionsResponseModel prescriptionsResponseModel, required List<PrescriptionDetailResponseModel> prescriptionDetailsList});
Future<Either<Failure, GenericApiModel<dynamic>>> submitPrescriptionDeliveryRequest(
{required String latitude, required String longitude, required String appointmentNo, required String dischargeID, required String projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> getPrescriptionOrdersList();
}
class PrescriptionsRepoImp implements PrescriptionsRepo {
@ -158,7 +165,8 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
}
@override
Future<Either<Failure, GenericApiModel>> getPrescriptionPDF({required PatientPrescriptionsResponseModel prescriptionsResponseModel, required List<PrescriptionDetailResponseModel> prescriptionDetailsList}) async {
Future<Either<Failure, GenericApiModel>> getPrescriptionPDF(
{required PatientPrescriptionsResponseModel prescriptionsResponseModel, required List<PrescriptionDetailResponseModel> prescriptionDetailsList}) async {
Map<String, dynamic> mapDevice = {
"AppointmentDate": prescriptionsResponseModel.appointmentDate,
"ClinicName": prescriptionsResponseModel.clinicDescription,
@ -206,4 +214,84 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> submitPrescriptionDeliveryRequest(
{required String latitude, required String longitude, required String appointmentNo, required String dischargeID, required String projectID}) async {
Map<String, dynamic> mapDevice = {
"latitude": latitude,
"longitude": longitude,
"AppointmentNo": appointmentNo,
"DischargeID": dischargeID,
"ProjectID": projectID,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
isRCService: true,
ADD_PRESCRIPTION_ORDER_RC,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> getPrescriptionOrdersList() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
isRCService: true,
GET_ALL_PRESCRIPTION_ORDERS_RC,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final prescriptionOrders = response['response'].map((item) => PrescriptionDeliveryResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PrescriptionDeliveryResponseModel>();
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: prescriptionOrders,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -1,8 +1,26 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/calender_utils_new.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_delivery_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_delivery_order_summary_page.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/map/map_utility_screen.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class PrescriptionsViewModel extends ChangeNotifier {
bool isPrescriptionsOrdersLoading = false;
@ -10,6 +28,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
PrescriptionsRepo prescriptionsRepo;
ErrorHandlerService errorHandlerService;
NavigationService navServices;
// Prescription Orders Lists
List<PatientPrescriptionsResponseModel> patientPrescriptionOrders = [];
@ -27,19 +46,31 @@ class PrescriptionsViewModel extends ChangeNotifier {
String prescriptionPDFBase64Data = "";
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService});
late GeocodeResponse locationGeocodeResponse;
bool isPrescriptionsDeliveryOrdersLoading = false;
List<PrescriptionDeliveryResponseModel> prescriptionsOrderList = [];
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices});
initPrescriptionsViewModel() {
patientPrescriptionOrders.clear();
patientPrescriptionOrdersByClinic.clear();
patientPrescriptionOrdersByHospital.clear();
patientPrescriptionOrdersViewList.clear();
prescriptionsOrderList.clear();
isPrescriptionsOrdersLoading = true;
isSortByClinic = true;
isPrescriptionsDeliveryOrdersLoading = true;
getPatientPrescriptionOrders();
notifyListeners();
}
checkIfReminderExistForPrescription(int index) async {
prescriptionDetailsList[index].hasReminder = await CalenderUtilsNew.instance.checkIfEventExist(prescriptionDetailsList[index].itemID?.toString() ?? "");
}
setPrescriptionsDetailsLoading() {
isPrescriptionsDetailsLoading = true;
prescriptionDetailsList.clear();
@ -121,6 +152,9 @@ class PrescriptionsViewModel extends ChangeNotifier {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
prescriptionDetailsList = apiResponse.data!;
prescriptionDetailsList.forEach((element) async {
await checkIfReminderExistForPrescription(prescriptionDetailsList.indexOf(element));
});
isPrescriptionsDetailsLoading = false;
notifyListeners();
if (onSuccess != null) {
@ -173,4 +207,92 @@ class PrescriptionsViewModel extends ChangeNotifier {
},
);
}
showError(String errorMessage) {
getIt<DialogService>().showErrorBottomSheet(message: errorMessage);
}
Future<void> submitPrescriptionDeliveryRequest(
{required String latitude,
required String longitude,
required String appointmentNo,
required String dischargeID,
required String projectID,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
final result = await prescriptionsRepo.submitPrescriptionDeliveryRequest(latitude: latitude, longitude: longitude, appointmentNo: appointmentNo, dischargeID: dischargeID, projectID: projectID);
result.fold(
(failure) async {
onError!(failure.message);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
void initiatePrescriptionDelivery() async {
getIt.get<LocationUtils>().getLocation(
isShowConfirmDialog: true,
onSuccess: (position) async {
bool result = await navServices.push(
CustomPageRoute(
page: MapUtilityScreen(
confirmButtonString: LocaleKeys.next.tr(),
titleString: "Select Location".needTranslation,
subTitleString: "Please select the location for prescription delivery".needTranslation,
isGmsAvailable: getIt.get<AppState>().isGMSAvailable,
),
direction: AxisDirection.down),
);
print("Location Selected: $result");
if (result) {
LocationViewModel locationViewModel = getIt.get<LocationViewModel>();
locationGeocodeResponse = locationViewModel.geocodeResponse!;
navServices.push(
CustomPageRoute(
page: PrescriptionDeliveryOrderSummaryPage(),
),
);
}
});
}
Future<void> getPrescriptionOrdersList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isPrescriptionsDeliveryOrdersLoading = true;
prescriptionsOrderList.clear();
notifyListeners();
final result = await prescriptionsRepo.getPrescriptionOrdersList();
result.fold(
(failure) async {
isPrescriptionsDeliveryOrdersLoading = false;
notifyListeners();
onError!(failure.message);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
isPrescriptionsDeliveryOrdersLoading = false;
notifyListeners();
onError!(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
isPrescriptionsDeliveryOrdersLoading = false;
prescriptionsOrderList = apiResponse.data!;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart';
@ -145,6 +146,9 @@ void main() async {
),
ChangeNotifierProvider<HmgServicesViewModel>(
create: (_) => getIt.get<HmgServicesViewModel>(),
),
ChangeNotifierProvider<BloodDonationViewModel>(
create: (_) => getIt.get<BloodDonationViewModel>(),
)
], child: MyApp()),
),

@ -0,0 +1,138 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.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/medical_file/medical_file_view_model.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/appbar/collapsing_list_view.dart';
import 'package:provider/provider.dart';
class AllergiesListPage extends StatelessWidget {
AllergiesListPage({super.key});
late MedicalFileViewModel medicalFileViewModel;
@override
Widget build(BuildContext context) {
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.allergies.tr(),
child: SingleChildScrollView(
child: Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
ListView.separated(
scrollDirection: Axis.vertical,
itemCount: medicalFileVM.isPatientAllergiesListLoading
? 5
: medicalFileVM.patientAllergiesList.isNotEmpty
? medicalFileVM.patientAllergiesList.length
: 1,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.only(left: 24.h, right: 24.h),
itemBuilder: (context, index) {
return medicalFileVM.isPatientAllergiesListLoading
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.allergy_info_icon, width: 36.w, height: 36.h, fit: BoxFit.contain).toShimmer2(isShow: true),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Dr John Smith".toText16(isBold: true).toShimmer2(isShow: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
// AppCustomChipWidget(labelText: "").toShimmer2(isShow: true, width: 16.h),
// AppCustomChipWidget(labelText: "").toShimmer2(isShow: true, width: 16.h),
],
),
],
),
),
],
),
],
),
),
)
: medicalFileVM.patientAllergiesList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.allergy_info_icon, width: 36.w, height: 36.h, fit: BoxFit.contain),
SizedBox(height: 16.h),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(medicalFileVM.patientAllergiesList[index].description).toString().toText16(isBold: true).toShimmer2(isShow: false),
(medicalFileVM.patientAllergiesList[index].remarks).toString().toText12(),
],
),
),
],
),
],
),
),
),
),
),
)
: Utils.getNoDataWidget(context, noDataText: "No allergies data found...".needTranslation);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
SizedBox(height: 60.h),
],
);
}),
),
),
);
}
}

@ -8,7 +8,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/utils/calendar_utils.dart';
import 'package:hmg_patient_app_new/core/utils/calender_utils_new.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
@ -73,7 +72,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
var doesExist = await calendarUtils.checkIfEventExist("${widget.patientAppointmentHistoryResponseModel.appointmentNo}");
print("the appointment reminder exist $doesExist");
myAppointmentsViewModel.setAppointmentReminder(doesExist, widget.patientAppointmentHistoryResponseModel);
setState((){
});
});
super.initState();
@ -142,6 +143,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
},
onCancelTap: () async {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
var isEventAddedOrRemoved = await CalenderUtilsNew.instance.checkAndRemove( id:"${widget.patientAppointmentHistoryResponseModel.appointmentNo}", );
setState(() {
myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
});
LoaderBottomSheet.showLoader(loadingText: "Cancelling Appointment, Please Wait...".needTranslation);
await myAppointmentsViewModel.cancelAppointment(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
@ -287,7 +292,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
DateTime startDate = DateTime.now();
DateTime endDate = DateUtil.convertStringToDate(widget
.patientAppointmentHistoryResponseModel.appointmentDate);
showReminderBottomSheet(
BottomSheetUtils().showReminderBottomSheet(
context,
endDate,
widget.patientAppointmentHistoryResponseModel.doctorNameObj??"",
@ -323,7 +328,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
}else {
isEventAddedOrRemoved = await calender.checkAndRemove( id:"${widget.patientAppointmentHistoryResponseModel.appointmentNo}", );
setState(() {
myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
myAppointmentsViewModel.setAppointmentReminder(!isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
});
}
@ -747,8 +752,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
onPressed: () {
openDoctorScheduleCalendar();
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
backgroundColor: AppColors.successColor,
borderColor: AppColors.successColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,

@ -0,0 +1,220 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.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/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
class AppointmentQueuePage extends StatelessWidget {
AppointmentQueuePage({super.key});
AppState? appState;
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return Column(
children: [
Expanded(
child: CollapsingListView(
title: "Queueing".needTranslation,
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
side: BorderSide(color: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus), width: 2.w),
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppCustomChipWidget(
labelText: myAppointmentsVM.currentQueueStatus == 0 ? "In Queue".needTranslation : "Your Turn".needTranslation,
backgroundColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.20),
textColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus),
),
Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h),
],
),
SizedBox(height: 10.h),
"Hala ${appState!.getAuthenticatedUser()!.firstName}!!!".needTranslation.toText16(isBold: true),
SizedBox(height: 8.h),
"Thank you for your patience, here is your queue number.".needTranslation.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 8.h),
"IMD W-A-5".needTranslation.toText32(isBold: true),
SizedBox(height: 8.h),
CustomButton(
text: Utils.getCardButtonText(myAppointmentsVM.currentQueueStatus),
onPressed: () {},
backgroundColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus),
borderColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.01),
textColor: Utils.getCardButtonTextColor(myAppointmentsVM.currentQueueStatus),
fontSize: 12.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
),
],
),
),
),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Serving Now".needTranslation.toText16(isBold: true),
SizedBox(height: 18.h),
ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: 3,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"IMD W-A-2".needTranslation.toText17(isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
"Room: S2".toText12(fontWeight: FontWeight.w500),
SizedBox(width: 8.w),
AppCustomChipWidget(
deleteIcon: AppAssets.call_for_vitals,
labelText: "Call for vital signs".needTranslation,
iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor,
iconSize: 14.w,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
labelPadding: EdgeInsetsDirectional.only(start: 8.h, end: -2.h),
),
],
),
],
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 8.h),
),
],
),
),
),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.bulb_icon, width: 24.w, height: 24.h),
SizedBox(width: 8.w),
"Things to ask your doctor today".needTranslation.toText16(isBold: true),
],
),
SizedBox(height: 8.h),
// What can I do to improve my overall health?
// Are there any routine screenings I should get?
// What is this medication for?
// Are there any side effects I should know about?
// When should I come back for a follow-up?
"${"What can I do to improve my overall health?"}".needTranslation.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h),
"${"Are there any routine screenings I should get?"}".needTranslation.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h),
"${"What is this medication for?"}".needTranslation.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h),
"${"Are there any side effects I should know about?"}".needTranslation.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h),
"${"When should I come back for a follow-up?"}".needTranslation.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 16.h),
],
),
),
),
],
),
),
),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: true,
),
child: CustomButton(
text: "Go to homepage".needTranslation,
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 50.h,
icon: AppAssets.homeBottom,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(16.h, 24.h),
)
],
);
}),
);
}
}

@ -123,22 +123,46 @@ class AppointmentCard extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
isLoading
? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png'
: patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: isLoading),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
isLoading ? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png' : patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.w,
height: 63.h,
fit: BoxFit.cover,
).circle(100.r).toShimmer2(isShow: isLoading),
Transform.translate(
offset: Offset(0.0, -20.h),
child: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: AppColors.whiteColor,
shape: BoxShape.circle, // Makes the container circular
border: Border.all(
color: AppColors.scaffoldBgColor, // Color of the border
width: 1.5.w, // Width of the border
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h),
SizedBox(height: 2.h),
"${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor),
],
),
).circle(100).toShimmer2(isShow: isLoading),
),
],
),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(isLoading
? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png'
: patientAppointmentHistoryResponseModel.doctorNameObj!)
(isLoading ? 'John Doe' : "${patientAppointmentHistoryResponseModel.doctorTitle} ${patientAppointmentHistoryResponseModel.doctorNameObj!}")
.toText16(isBold: true, maxlines: 1)
.toShimmer2(isShow: isLoading),
SizedBox(height: 8.h),
@ -147,26 +171,39 @@ class AppointmentCard extends StatelessWidget {
spacing: 3.h,
runSpacing: 4.h,
children: [
if (!isFromHomePage)
AppCustomChipWidget(labelText: isLoading ? 'Cardiology' : patientAppointmentHistoryResponseModel.clinicName!)
.toShimmer2(isShow: isLoading),
if (!isFromHomePage)
AppCustomChipWidget(labelText: isLoading ? 'Olaya' : patientAppointmentHistoryResponseModel.projectName!)
.toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: isLoading
? 'Cardiology'
: (patientAppointmentHistoryResponseModel.clinicName!.length > 15
? '${patientAppointmentHistoryResponseModel.clinicName!.substring(0, 12)}...'
: patientAppointmentHistoryResponseModel.clinicName!),
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(labelText: isLoading ? 'Olaya' : patientAppointmentHistoryResponseModel.projectName!).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
icon: AppAssets.appointment_calendar_icon,
labelText: isLoading
? 'Cardiology'
: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false),
: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
isIconPNG: true,
icon: getIt.get<AppState>().getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg,
iconSize: 18.h,
labelText: isLoading ? 'Cardiology' : "Patient: ${getIt.get<AppState>().getAuthenticatedUser()!.firstName!}",
).toShimmer2(isShow: isLoading),
if (!isFromMedicalReport)
AppCustomChipWidget(
icon: AppAssets.appointment_time_icon,
labelText: isLoading
? 'Cardiology'
: DateUtil.formatDateToTimeLang(
DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false),
).toShimmer2(isShow: isLoading),
// if (!isFromMedicalReport)
// AppCustomChipWidget(
// icon: AppAssets.appointment_time_icon,
// labelText: isLoading
// ? 'Cardiology'
// : DateUtil.formatDateToTimeLang(
// DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false),
// ).toShimmer2(isShow: isLoading),
// AppCustomChipWidget(
// icon: AppAssets.rating_icon,
// iconColor: AppColors.ratingColorYellow,
// labelText: isLoading ? "Rating" : "Rating: ${patientAppointmentHistoryResponseModel.decimalDoctorRate}".needTranslation)
// .toShimmer2(isShow: isLoading),
],
),
],
@ -269,7 +306,6 @@ class AppointmentCard extends StatelessWidget {
clinicId: patientAppointmentHistoryResponseModel.clinicID,
onSuccess: (value) async {
if (value) {
print("Doctor is available");
await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(

@ -13,6 +13,7 @@ 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/appointment_queue_page.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';
@ -156,7 +157,9 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
),
(r) => false);
Navigator.of(context).push(
CustomPageRoute(page: MyAppointmentsPage()),
CustomPageRoute(
page: AppointmentQueuePage(),
),
);
}, isFullScreen: false);
},

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.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';
@ -42,25 +43,55 @@ class AppointmentDoctorCard extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.w,
height: 63.h,
fit: BoxFit.cover,
).circle(100.r),
Column(
children: [
Image.network(
patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.w,
height: 63.h,
fit: BoxFit.cover,
).circle(100.r),
Transform.translate(
offset: Offset(0.0, -20.h),
child: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: AppColors.whiteColor,
shape: BoxShape.circle, // Makes the container circular
border: Border.all(
color: AppColors.scaffoldBgColor, // Color of the border
width: 1.5.w, // Width of the border
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h),
SizedBox(height: 2.h),
"${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor),
],
),
).circle(100),
),
],
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: patientAppointmentHistoryResponseModel.clinicName!,
labelText: (patientAppointmentHistoryResponseModel.clinicName!.length > 15
? '${patientAppointmentHistoryResponseModel.clinicName!.substring(0, 12)}...'
: patientAppointmentHistoryResponseModel.clinicName!),
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
@ -69,8 +100,7 @@ class AppointmentDoctorCard extends StatelessWidget {
),
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
labelText:
"${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}, ${DateUtil.formatDateToTimeLang(
labelText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(
DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
false,
)}",
@ -87,10 +117,6 @@ class AppointmentDoctorCard extends StatelessWidget {
!patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor,
textColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor,
),
AppCustomChipWidget(
icon: AppAssets.rating_icon,
iconColor: AppColors.ratingColorYellow,
labelText: "Rating: ${patientAppointmentHistoryResponseModel.decimalDoctorRate}"),
],
),
],
@ -98,8 +124,7 @@ class AppointmentDoctorCard extends StatelessWidget {
),
],
),
SizedBox(height: 16.h),
SizedBox(height: 8.h),
Visibility(
visible: renderWidgetForERDisplay == false,
child: getAppointmentActionButtons(

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save