My appointments implementation contd.

pull/13/head
haroon amjad 2 months ago
parent 43fa08b8b6
commit a0bdc34685

@ -247,7 +247,7 @@
<!-- </receiver> &lt;!&ndash; Huawei Push Notifications &ndash;&gt;-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyCyDbWUM9d_sBUGIE8PcuShzPaqO08NSC8" />
android:value="AIzaSyCiD4YqVqLNYbt8-htvFy4Wp8XSph9E3wM" />
<!--
Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java

@ -0,0 +1,3 @@
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 0.0839844C3.82217 0.0839844 4.08333 0.345152 4.08333 0.667318V0.720827C4.72328 0.667291 5.49135 0.667304 6.39988 0.667318L7.60012 0.667318C8.50865 0.667304 9.27672 0.667291 9.91667 0.720827V0.667318C9.91667 0.345152 10.1778 0.0839844 10.5 0.0839844C10.8222 0.0839844 11.0833 0.345152 11.0833 0.667318V0.929147C11.5274 1.06999 11.9132 1.29145 12.2395 1.64417C12.7228 2.16666 12.9309 2.8214 13.0292 3.61237C13.125 4.38254 13.125 5.36553 13.125 6.6021V6.98254C13.125 8.21911 13.125 9.2021 13.0292 9.97227C12.9309 10.7632 12.7228 11.418 12.2395 11.9405C11.7502 12.4694 11.1269 12.7032 10.3744 12.8126C9.65334 12.9174 8.73662 12.9173 7.60012 12.9173H6.39988C5.26338 12.9173 4.34666 12.9174 3.62561 12.8126C2.87312 12.7032 2.2498 12.4694 1.76051 11.9405C1.2772 11.418 1.06913 10.7632 0.970761 9.97227C0.874981 9.20211 0.874989 8.21911 0.875 6.98256L0.875 6.60208C0.874989 5.36553 0.874981 4.38253 0.970761 3.61237C1.06913 2.8214 1.2772 2.16666 1.76051 1.64417C2.08678 1.29145 2.47265 1.06999 2.91667 0.929148V0.667318C2.91667 0.345152 3.17783 0.0839844 3.5 0.0839844ZM2.13725 4.83475C2.22244 4.75065 2.3562 4.75065 2.62373 4.75065L11.3763 4.75065C11.6438 4.75065 11.7776 4.75065 11.8628 4.83475C11.9479 4.91884 11.9497 5.05091 11.9531 5.31503C11.9582 5.70771 11.9583 6.14726 11.9583 6.64255V6.94209C11.9583 8.22826 11.9573 9.13855 11.8715 9.82829C11.7873 10.5056 11.6301 10.8811 11.383 11.1483C11.1419 11.4089 10.8123 11.57 10.2066 11.658C9.57916 11.7492 8.74752 11.7507 7.55417 11.7507H6.44583C5.25248 11.7507 4.42084 11.7492 3.79342 11.658C3.18774 11.57 2.85808 11.4089 2.61696 11.1483C2.36987 10.8811 2.21274 10.5056 2.12851 9.82829C2.04273 9.13855 2.04167 8.22826 2.04167 6.94209V6.64255C2.04167 6.14726 2.04183 5.70771 2.04692 5.31503C2.05034 5.05091 2.05206 4.91884 2.13725 4.83475Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,4 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.5 0.75C3.91421 0.75 4.25 1.08579 4.25 1.5V1.5688C5.07278 1.49997 6.06031 1.49998 7.22842 1.5L8.77158 1.5C9.93969 1.49998 10.9272 1.49997 11.75 1.5688V1.5C11.75 1.08579 12.0858 0.75 12.5 0.75C12.9142 0.75 13.25 1.08579 13.25 1.5V1.83664C13.8209 2.01772 14.317 2.30245 14.7365 2.75595C15.3213 3.3882 15.5927 4.1711 15.7281 5.10899C15.861 6.03001 15.8733 7.1875 15.8748 8.62422V9.75C15.8748 10.1642 15.539 10.5 15.1248 10.5C14.7106 10.5 14.3748 10.1642 14.3748 9.75V8.62579C14.3742 8.06266 14.3716 7.56155 14.3621 7.1128C14.3578 6.91051 14.1918 6.75 13.9895 6.75L2.01043 6.75C1.80809 6.75 1.64212 6.91043 1.63785 7.11272C1.62532 7.70596 1.625 8.3885 1.625 9.18243L1.625 9.56757C1.625 11.2212 1.62637 12.3916 1.73665 13.2784C1.84496 14.1492 2.04697 14.632 2.36467 14.9755C2.67467 15.3106 3.09852 15.5177 3.87725 15.6309C4.68393 15.7481 5.75319 15.75 7.2875 15.75C7.70171 15.75 8.0375 16.0858 8.0375 16.5C8.0375 16.9142 7.70171 17.25 7.2875 17.25H7.22842C5.76721 17.25 4.58856 17.25 3.6615 17.1153C2.69401 16.9747 1.8926 16.6741 1.26352 15.9941C0.64212 15.3223 0.374593 14.4805 0.248121 13.4635C0.124976 12.4733 0.124987 11.2094 0.125 9.6196L0.125 9.1304C0.124987 7.54055 0.124976 6.2767 0.248121 5.28649C0.374593 4.26954 0.64212 3.42773 1.26352 2.75595C1.683 2.30245 2.17912 2.01772 2.75 1.83664L2.75 1.5C2.75 1.08579 3.08579 0.75 3.5 0.75Z" fill="#D48D05"/>
<path d="M14.7502 13.8794C15.1644 13.8794 15.5002 13.5436 15.5002 13.1294C15.5002 12.7152 15.1644 12.3794 14.7502 12.3794H11.3751L11.3752 11.9337C11.3752 11.802 11.3754 11.6402 11.3588 11.5079L11.3585 11.5054C11.3467 11.4106 11.2928 10.9785 10.8686 10.7728C10.4435 10.5665 10.0684 10.793 9.98722 10.842L9.63585 11.0963C9.35398 11.3173 8.96814 11.6216 8.67488 11.9069C8.52855 12.0493 8.37762 12.2122 8.25849 12.3854C8.15259 12.5394 8.00014 12.802 8.00014 13.125C8.00014 13.448 8.15259 13.7106 8.25849 13.8646C8.37762 14.0378 8.52855 14.2007 8.67488 14.3431C8.96814 14.6284 9.35398 14.9327 9.63585 15.1537L9.98722 15.408C10.0684 15.457 10.4435 15.6835 10.8686 15.4772C11.2928 15.2715 11.3467 14.8394 11.3585 14.7446L11.3588 14.7421C11.3754 14.6098 11.3752 14.448 11.3752 14.3163L11.3751 13.8794H14.7502Z" fill="#D48D05"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -0,0 +1,4 @@
<svg width="17" height="14" viewBox="0 0 17 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.66067 0.4375C11.0399 0.437493 12.1231 0.437487 12.9771 0.533949C13.8487 0.632408 14.5555 0.837715 15.143 1.30171C15.3189 1.44062 15.482 1.59404 15.6303 1.76035C16.1299 2.32076 16.353 3.00002 16.4593 3.83339C16.4715 3.92927 16.4776 3.97722 16.4666 4.01934C16.4491 4.08665 16.3974 4.14531 16.3329 4.17126C16.2925 4.1875 16.2419 4.1875 16.1408 4.1875L0.859177 4.1875C0.758099 4.1875 0.707553 4.1875 0.667164 4.17126C0.602615 4.14532 0.550957 4.08665 0.533383 4.01934C0.522386 3.97722 0.5285 3.92927 0.540728 3.83338C0.647 3.00002 0.870114 2.32076 1.36975 1.76035C1.51802 1.59404 1.68109 1.44062 1.85698 1.30171C2.44451 0.837715 3.15132 0.632408 4.02294 0.533949C4.87689 0.437487 5.9601 0.437493 7.33936 0.4375L9.66067 0.4375Z" fill="#0B85F7"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5625 7.03956C16.5625 8.33257 16.5625 9.35705 16.4593 10.1666C16.353 11 16.1299 11.6792 15.6303 12.2397C15.482 12.406 15.3189 12.5594 15.143 12.6983C14.5555 13.1623 13.8487 13.3676 12.9771 13.4661C12.1231 13.5625 11.0399 13.5625 9.66066 13.5625H7.33934C5.96009 13.5625 4.87688 13.5625 4.02294 13.4661C3.15131 13.3676 2.4445 13.1623 1.85697 12.6983C1.68108 12.5594 1.51801 12.406 1.36974 12.2397C0.870106 11.6792 0.646992 11 0.540719 10.1666C0.437482 9.35705 0.43749 8.33255 0.4375 7.03955V6.96044C0.437497 6.52863 0.437494 6.12674 0.441337 5.75281C0.443461 5.54605 0.444524 5.44267 0.510282 5.37758C0.57604 5.3125 0.680207 5.3125 0.888543 5.3125L16.1115 5.3125C16.3198 5.3125 16.424 5.3125 16.4897 5.37758C16.5555 5.44267 16.5565 5.54605 16.5587 5.75281C16.5625 6.12662 16.5625 6.52836 16.5625 6.96003V7.03956ZM7.18749 10C7.18749 9.68934 7.43933 9.4375 7.74999 9.4375H8.87499C9.18565 9.4375 9.43749 9.68934 9.43749 10C9.43749 10.3107 9.18565 10.5625 8.87499 10.5625H7.74999C7.43933 10.5625 7.18749 10.3107 7.18749 10ZM11.125 9.4375C10.8143 9.4375 10.5625 9.68934 10.5625 10C10.5625 10.3107 10.8143 10.5625 11.125 10.5625L13.75 10.5625C14.0607 10.5625 14.3125 10.3107 14.3125 10C14.3125 9.68934 14.0607 9.4375 13.75 9.4375L11.125 9.4375Z" fill="#0B85F7"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,3 @@
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.00008 0.228516C3.5368 0.228516 0.729248 3.03606 0.729248 6.49935C0.729248 9.96263 3.5368 12.7702 7.00008 12.7702C10.4634 12.7702 13.2709 9.96263 13.2709 6.49935C13.2709 3.03606 10.4634 0.228516 7.00008 0.228516ZM9.74589 4.57849C9.9737 4.35069 9.9737 3.98134 9.74589 3.75354C9.51809 3.52573 9.14874 3.52573 8.92094 3.75354L7.00012 5.67435L5.95421 4.62852C5.7264 4.40072 5.35705 4.40074 5.12925 4.62855C4.90146 4.85636 4.90147 5.22571 5.12928 5.45351L6.17516 6.49931L6.00427 6.6702C5.77646 6.89801 5.77646 7.26736 6.00427 7.49516C6.23207 7.72297 6.60142 7.72297 6.82923 7.49516L7.00015 7.32424L7.17088 7.49496C7.39869 7.72276 7.76804 7.72275 7.99584 7.49493C8.22363 7.26712 8.22362 6.89777 7.99581 6.66998L7.8251 6.49928L9.74589 4.57849Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 913 B

@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.9375 8.67504C0.9375 4.37879 4.57142 0.9375 9 0.9375C13.4286 0.9375 17.0625 4.37879 17.0625 8.67504C17.0625 12.9713 13.4286 16.4126 9 16.4126C8.4781 16.4132 7.95776 16.3649 7.44524 16.2687C7.26734 16.2353 7.15432 16.2142 7.07022 16.2027C7.0075 16.1931 6.94448 16.2164 6.92081 16.2293C6.83492 16.2701 6.72051 16.3308 6.54535 16.4239C5.47156 16.995 4.21878 17.1975 3.01047 16.9727C2.81535 16.9365 2.6538 16.8 2.58535 16.6137C2.5169 16.4275 2.55168 16.2189 2.67688 16.0649C3.02773 15.6333 3.26897 15.1135 3.37566 14.5539C3.40453 14.4 3.3392 14.191 3.13838 13.987C1.77729 12.6049 0.9375 10.7358 0.9375 8.67504ZM8.25 6.94368C8.25 6.71747 8.49208 6.375 9 6.375C9.50792 6.375 9.75 6.71747 9.75 6.94368C9.75 7.03521 9.72061 7.12658 9.65713 7.21331C9.57168 7.33005 9.46169 7.45479 9.32273 7.60662L9.25602 7.67927C9.13971 7.80573 9.00656 7.9505 8.88529 8.09703C8.60705 8.4332 8.25 8.93789 8.25 9.58104V9.91071C8.25 10.3249 8.58579 10.6607 9 10.6607C9.41421 10.6607 9.75 10.3249 9.75 9.91071V9.58104C9.75 9.49591 9.79997 9.34445 10.0408 9.05343C10.1348 8.93985 10.2363 8.82947 10.352 8.70347L10.4292 8.61937C10.569 8.46668 10.7288 8.28875 10.8675 8.09927C11.1049 7.77502 11.25 7.37719 11.25 6.94368C11.25 5.71331 10.1489 4.875 9 4.875C7.85106 4.875 6.75 5.71331 6.75 6.94368C6.75 7.35789 7.08579 7.69368 7.5 7.69368C7.91421 7.69368 8.25 7.35789 8.25 6.94368ZM9 11.625C8.58579 11.625 8.25 11.9608 8.25 12.375C8.25 12.7892 8.58579 13.125 9 13.125H9.00898C9.42319 13.125 9.75898 12.7892 9.75898 12.375C9.75898 11.9608 9.42319 11.625 9.00898 11.625H9Z" fill="#F43333"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,4 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.25 1.5C4.25 1.08579 3.91421 0.75 3.5 0.75C3.08579 0.75 2.75 1.08579 2.75 1.5L2.75 1.83664C2.17912 2.01772 1.683 2.30245 1.26352 2.75595C0.64212 3.42773 0.374593 4.26954 0.248121 5.28649C0.124976 6.2767 0.124987 7.54054 0.125 9.13039L0.125 9.61959C0.124987 11.2094 0.124976 12.4733 0.248121 13.4635C0.374593 14.4805 0.64212 15.3223 1.26352 15.9941C1.86304 16.6422 2.61224 16.9476 3.52132 17.0965C4.39992 17.2403 5.507 17.2491 6.87495 17.2499L7.62495 17.25C8.03916 17.25 8.37497 16.9142 8.375 16.5C8.37503 16.0858 8.03927 15.75 7.62505 15.75L6.87547 15.7499C5.47193 15.749 4.49783 15.7364 3.7637 15.6162C3.06006 15.501 2.66455 15.2997 2.36467 14.9755C2.04697 14.632 1.84496 14.1492 1.73665 13.2784C1.62637 12.3916 1.625 11.2212 1.625 9.56757L1.625 9.18243C1.625 8.54564 1.6252 7.98051 1.63175 7.47564C1.63616 7.13604 1.63836 6.96625 1.74789 6.85813C1.85742 6.75 2.02941 6.75 2.37337 6.75L13.6266 6.75C13.9705 6.75 14.1425 6.75 14.252 6.8581C14.3616 6.9662 14.3638 7.136 14.3683 7.4756C14.3715 7.71952 14.3732 7.97803 14.3741 8.25239C14.3754 8.6666 14.7122 9.00132 15.1264 9C15.5407 8.99868 15.8754 8.66183 15.8741 8.24762C15.8699 6.92805 15.8479 5.85257 15.7094 4.98584C15.5681 4.10202 15.2953 3.36008 14.7365 2.75595C14.317 2.30245 13.8209 2.01772 13.25 1.83664V1.5C13.25 1.08579 12.9142 0.75 12.5 0.75C12.0858 0.75 11.75 1.08579 11.75 1.5V1.5688C10.9272 1.49997 9.93969 1.49998 8.77159 1.5L7.22842 1.5C6.06032 1.49998 5.07278 1.49997 4.25 1.5688V1.5Z" fill="#18C273"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3754 11.8119L14.3754 11.0156C14.3754 9.98687 13.5164 9.1875 12.5004 9.1875C11.4843 9.1875 10.6254 9.98687 10.6254 11.0156L10.6254 11.8119C10.569 11.829 10.513 11.8495 10.4574 11.8742C9.99227 12.0806 9.63454 12.4707 9.4506 12.9465C9.37118 13.152 9.34065 13.3629 9.32648 13.5854C9.31284 13.7995 9.31285 14.0604 9.31285 14.3729L9.31268 14.4979C9.31219 14.7306 9.31169 14.9637 9.32648 15.1958C9.34065 15.4183 9.37118 15.6293 9.4506 15.8347C9.63454 16.3105 9.99227 16.7007 10.4574 16.9071C10.8265 17.0709 11.2497 17.0671 11.6516 17.0635C11.7097 17.063 11.7675 17.0625 11.8245 17.0625H13.1762C13.2332 17.0625 13.291 17.063 13.3491 17.0635C13.751 17.0671 14.1742 17.0709 14.5433 16.9071C15.0084 16.7007 15.3662 16.3105 15.5501 15.8347C15.6295 15.6293 15.6601 15.4183 15.6742 15.1958C15.689 14.9637 15.6885 14.7306 15.688 14.4979L15.6879 14.3729C15.6879 14.0604 15.6879 13.7995 15.6742 13.5854C15.6601 13.3629 15.6295 13.152 15.5501 12.9465C15.3662 12.4707 15.0084 12.0806 14.5433 11.8742C14.4877 11.8495 14.4317 11.829 14.3754 11.8119ZM11.7504 11.0156C11.7504 10.6464 12.0667 10.3125 12.5004 10.3125C12.934 10.3125 13.2504 10.6464 13.2504 11.0156L13.2504 11.7188H11.7504L11.7504 11.0156Z" fill="#18C273"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

@ -0,0 +1,7 @@
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 870" width="1000" height="870">
<title>Layer copy</title>
<style>
.s0 { fill: #000000 }
</style>
<path id="Layer copy" class="s0" d="m88.3 1c0.4 0.6 2.6 3.3 4.7 5.9 15.3 18.2 26.8 47.8 33 85.1 4.1 24.5 4.3 32.2 4.3 125.6v87h-41.8c-38.2 0-42.6-0.2-50.1-1.7-11.8-2.5-24-9.2-32.2-17.8-6.5-6.9-6.3-7.3-5.9 13.6 0.5 17.3 0.7 19.2 3.2 28.6 4 14.9 9.5 26 17.8 35.9 11.3 13.6 22.8 21.2 39.2 26.3 3.5 1 10.9 1.4 37.1 1.6l32.7 0.5v43.3 43.4l-46.1-0.3-46.3-0.3-8-3.2c-9.5-3.8-13.8-6.6-23.1-14.9l-6.8-6.1 0.4 19.1c0.5 17.7 0.6 19.7 3.1 28.7 8.7 31.8 29.7 54.5 57.4 61.9 6.9 1.9 9.6 2 38.5 2.4l30.9 0.4v89.6c0 54.1-0.3 94-0.8 100.8-0.5 6.2-2.1 17.8-3.5 25.9-6.5 37.3-18.2 65.4-35 83.6l-3.4 3.7h169.1c101.1 0 176.7-0.4 187.8-0.9 19.5-1 63-5.3 72.8-7.4 3.1-0.6 8.9-1.5 12.7-2.1 8.1-1.2 21.5-4 40.8-8.9 27.2-6.8 52-15.3 76.3-26.1 7.6-3.4 29.4-14.5 35.2-18 3.1-1.8 6.8-4 8.2-4.7 3.9-2.1 10.4-6.3 19.9-13.1 4.7-3.4 9.4-6.7 10.4-7.4 4.2-2.8 18.7-14.9 25.3-21 25.1-23.1 46.1-48.8 62.4-76.3 2.3-4 5.3-9 6.6-11.1 3.3-5.6 16.9-33.6 18.2-37.8 0.6-1.9 1.4-3.9 1.8-4.3 2.6-3.4 17.6-50.6 19.4-60.9 0.6-3.3 0.9-3.8 3.4-4.3 1.6-0.3 24.9-0.3 51.8-0.1 53.8 0.4 53.8 0.4 65.7 5.9 6.7 3.1 8.7 4.5 16.1 11.2 9.7 8.7 8.8 10.1 8.2-11.7-0.4-12.8-0.9-20.7-1.8-23.9-3.4-12.3-4.2-14.9-7.2-21.1-9.8-21.4-26.2-36.7-47.2-44l-8.2-3-33.4-0.4-33.3-0.5 0.4-11.7c0.4-15.4 0.4-45.9-0.1-61.6l-0.4-12.6 44.6-0.2c38.2-0.2 45.3 0 49.5 1.1 12.6 3.5 21.1 8.3 31.5 17.8l5.8 5.4v-14.8c0-17.6-0.9-25.4-4.5-37-7.1-23.5-21.1-41-41.1-51.8-13-7-13.8-7.2-58.5-7.5-26.2-0.2-39.9-0.6-40.6-1.2-0.6-0.6-1.1-1.6-1.1-2.4 0-0.8-1.5-7.1-3.5-13.9-23.4-82.7-67.1-148.4-131-197.1-8.7-6.7-30-20.8-38.6-25.6-3.3-1.9-6.9-3.9-7.8-4.5-4.2-2.3-28.3-14.1-34.3-16.6-3.6-1.6-8.3-3.6-10.4-4.4-35.3-15.3-94.5-29.8-139.7-34.3-7.4-0.7-17.2-1.8-21.7-2.2-20.4-2.3-48.7-2.6-209.4-2.6-135.8 0-169.9 0.3-169.4 1zm330.7 43.3c33.8 2 54.6 4.6 78.9 10.5 74.2 17.6 126.4 54.8 164.3 117 3.5 5.8 18.3 36 20.5 42.1 10.5 28.3 15.6 45.1 20.1 67.3 1.1 5.4 2.6 12.6 3.3 16 0.7 3.3 1 6.4 0.7 6.7-0.5 0.4-100.9 0.6-223.3 0.5l-222.5-0.2-0.3-128.5c-0.1-70.6 0-129.3 0.3-130.4l0.4-1.9h71.1c39 0 78 0.4 86.5 0.9zm297.5 350.3c0.7 4.3 0.7 77.3 0 80.9l-0.6 2.7-227.5-0.2-227.4-0.3-0.2-42.4c-0.2-23.3 0-42.7 0.2-43.1 0.3-0.5 97.2-0.8 227.7-0.8h227.2zm-10.2 171.7c0.5 1.5-1.9 13.8-6.8 33.8-5.6 22.5-13.2 45.2-20.9 62-3.8 8.6-13.3 27.2-15.6 30.7-1.1 1.6-4.3 6.7-7.1 11.2-18 28.2-43.7 53.9-73 72.9-10.7 6.8-32.7 18.4-38.6 20.2-1.2 0.3-2.5 0.9-3 1.3-0.7 0.6-9.8 4-20.4 7.8-19.5 6.9-56.6 14.4-86.4 17.5-19.3 1.9-22.4 2-96.7 2h-76.9v-129.7-129.8l220.9-0.4c121.5-0.2 221.6-0.5 222.4-0.7 0.9-0.1 1.8 0.5 2.1 1.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -151,7 +151,8 @@ class ApiClientImp implements ApiClient {
// request.languageID = (languageID == 'ar' ? 1 : 2);
// request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1;
body['VersionID'] = ApiConsts.appVersionID.toString();
// body['VersionID'] = ApiConsts.appVersionID.toString();
body['VersionID'] = "50.0";
body['Channel'] = ApiConsts.appChannelId.toString();
body['IPAdress'] = ApiConsts.appIpAddress;
body['generalid'] = ApiConsts.appGeneralId;

@ -75,6 +75,13 @@ class AppAssets {
static const String insurance = '$svgBasePath/insurance.svg';
static const String requests = '$svgBasePath/requests.svg';
static const String more = '$svgBasePath/more.svg';
static const String appointment_calendar_icon = '$svgBasePath/appointment_calendar_icon.svg';
static const String appointment_time_icon = '$svgBasePath/appointment_time_icon.svg';
static const String confirm_appointment_icon = '$svgBasePath/confirm_appointment_icon.svg';
static const String appointment_pay_icon = '$svgBasePath/appointment_pay_icon.svg';
static const String appointment_checkin_icon = '$svgBasePath/appointment_checkin_icon.svg';
static const String ask_doctor_icon = '$svgBasePath/ask_doctor_icon.svg';
static const String uae_dirham_symbol = '$svgBasePath/uae_dirham_symbol.svg';
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';

@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
@ -102,12 +103,19 @@ class AppDependencies {
);
getIt.registerLazySingleton<InsuranceViewModel>(
() => InsuranceViewModel(
() => InsuranceViewModel(
insuranceRepo: getIt(),
errorHandlerService: getIt(),
),
);
getIt.registerLazySingleton<MyAppointmentsViewModel>(
() => MyAppointmentsViewModel(
myAppointmentsRepo: getIt(),
errorHandlerService: getIt(),
),
);
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(),

@ -11,6 +11,7 @@ import 'package:google_api_availability/google_api_availability.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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@ -474,6 +475,35 @@ class Utils {
);
}
static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize, {bool isSaudiCurrency = true}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
appState.isArabic()
? Container()
: Utils.buildSvgWithAssets(
icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol,
iconColor: iconColor,
width: iconSize.h,
height: iconSize.h,
fit: BoxFit.contain,
),
SizedBox(width: 5.h),
paymentAmountWidget,
SizedBox(width: 5.h),
!appState.isArabic()
? Container()
: Utils.buildSvgWithAssets(
icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol,
iconColor: iconColor,
width: iconSize.h,
height: iconSize.h,
fit: BoxFit.contain,
),
],
);
}
static Future<bool> isGoogleServicesAvailable() async {
GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
String status = availability.toString().split('.').last;

@ -150,14 +150,14 @@ extension EmailValidator on String {
decoration: isUnderLine ? TextDecoration.underline : null),
);
Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines}) => Text(
Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines, double? letterSpacing = -0.4,}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
style: TextStyle(
color: color ?? AppColors.blackColor,
fontSize: 15.fSize,
letterSpacing: -1,
letterSpacing: letterSpacing,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null),
);

@ -0,0 +1,12 @@
import 'package:flutter/material.dart';
class MedicalFileViewModel extends ChangeNotifier {
int selectedTabIndex = 0;
void onTabChanged(int index) {
selectedTabIndex = index;
notifyListeners();
}
}

@ -0,0 +1,311 @@
class PatientAppointmentHistoryResponseModel {
String? setupID;
dynamic projectID;
dynamic appointmentNo;
String? appointmentDate;
dynamic appointmentDateN;
dynamic appointmentType;
String? bookDate;
dynamic patientType;
dynamic patientID;
dynamic clinicID;
dynamic doctorID;
String? endDate;
String? startTime;
String? endTime;
dynamic status;
dynamic visitType;
dynamic visitFor;
dynamic patientStatusType;
dynamic companyID;
dynamic bookedBy;
String? bookedOn;
dynamic confirmedBy;
dynamic confirmedOn;
dynamic arrivalChangedBy;
dynamic arrivedOn;
dynamic editedBy;
dynamic editedOn;
dynamic doctorName;
dynamic doctorNameN;
String? statusDesc;
dynamic statusDescN;
bool? vitalStatus;
dynamic vitalSignAppointmentNo;
dynamic episodeID;
dynamic actualDoctorRate;
String? clinicName;
bool? complainExists;
String? doctorImageURL;
String? doctorNameObj;
dynamic doctorRate;
dynamic decimalDoctorRate;
List<String>? doctorSpeciality;
String? doctorTitle;
dynamic gender;
String? genderDescription;
bool? iSAllowOnlineCheckedIN;
bool? isActiveDoctor;
bool? isActiveDoctorProfile;
bool? isDoctorAllowVedioCall;
bool? isExecludeDoctor;
dynamic isFollowup;
bool? isLiveCareAppointment;
bool? isInOutPatient;
bool? isMedicalReportRequested;
bool? isOnlineCheckedIN;
String? latitude;
dynamic listHISGetContactLensPerscription;
dynamic listHISGetGlassPerscription;
String? longitude;
dynamic nextAction;
dynamic noOfPatientsRate;
dynamic originalClinicID;
dynamic originalProjectID;
String? projectName;
String? qR;
int? remaniningHoursTocanPay;
bool? sMSButtonVisable;
dynamic serviceID;
String? isInOutPatientDescription;
String? isInOutPatientDescriptionN;
bool? hasReminder;
num? patientShare;
num? patientShareWithTax;
num? patientTaxAmount;
PatientAppointmentHistoryResponseModel({
this.setupID,
this.projectID,
this.appointmentNo,
this.appointmentDate,
this.appointmentDateN,
this.appointmentType,
this.bookDate,
this.patientType,
this.patientID,
this.clinicID,
this.doctorID,
this.endDate,
this.startTime,
this.endTime,
this.status,
this.visitType,
this.visitFor,
this.patientStatusType,
this.companyID,
this.bookedBy,
this.bookedOn,
this.confirmedBy,
this.confirmedOn,
this.arrivalChangedBy,
this.arrivedOn,
this.editedBy,
this.editedOn,
this.doctorName,
this.doctorNameN,
this.statusDesc,
this.statusDescN,
this.vitalStatus,
this.vitalSignAppointmentNo,
this.episodeID,
this.actualDoctorRate,
this.clinicName,
this.complainExists,
this.doctorImageURL,
this.doctorNameObj,
this.doctorRate,
this.decimalDoctorRate,
this.doctorSpeciality,
this.doctorTitle,
this.gender,
this.genderDescription,
this.iSAllowOnlineCheckedIN,
this.isActiveDoctor,
this.isActiveDoctorProfile,
this.isDoctorAllowVedioCall,
this.isExecludeDoctor,
this.isFollowup,
this.isLiveCareAppointment,
this.isMedicalReportRequested,
this.isOnlineCheckedIN,
this.latitude,
this.listHISGetContactLensPerscription,
this.listHISGetGlassPerscription,
this.longitude,
this.nextAction,
this.noOfPatientsRate,
this.originalClinicID,
this.originalProjectID,
this.projectName,
this.qR,
this.remaniningHoursTocanPay,
this.sMSButtonVisable,
this.serviceID,
this.isInOutPatientDescription,
this.isInOutPatientDescriptionN,
this.hasReminder = false,
this.patientShare,
this.patientShareWithTax,
this.patientTaxAmount,
});
PatientAppointmentHistoryResponseModel.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
projectID = json['ProjectID'];
appointmentNo = json['AppointmentNo'];
appointmentDate = json['AppointmentDate'];
appointmentDateN = json['AppointmentDateN'];
appointmentType = json['AppointmentType'];
bookDate = json['BookDate'];
patientType = json['PatientType'];
patientID = json['PatientID'];
clinicID = json['ClinicID'];
doctorID = json['DoctorID'];
endDate = json['EndDate'];
startTime = json['StartTime'];
endTime = json['EndTime'];
status = json['Status'];
visitType = json['VisitType'];
visitFor = json['VisitFor'];
patientStatusType = json['PatientStatusType'];
companyID = json['CompanyID'];
bookedBy = json['BookedBy'];
bookedOn = json['BookedOn'];
confirmedBy = json['ConfirmedBy'];
confirmedOn = json['ConfirmedOn'];
arrivalChangedBy = json['ArrivalChangedBy'];
arrivedOn = json['ArrivedOn'];
editedBy = json['EditedBy'];
editedOn = json['EditedOn'];
doctorName = json['DoctorName'];
doctorNameN = json['DoctorNameN'];
statusDesc = json['StatusDesc'];
statusDescN = json['StatusDescN'];
vitalStatus = json['VitalStatus'];
vitalSignAppointmentNo = json['VitalSignAppointmentNo'];
episodeID = json['EpisodeID'];
actualDoctorRate = json['ActualDoctorRate'];
clinicName = json['ClinicName'];
complainExists = json['ComplainExists'];
doctorImageURL = json['DoctorImageURL'];
doctorNameObj = json['DoctorNameObj'];
doctorRate = json['DoctorRate'];
decimalDoctorRate = json['DecimalDoctorRate'];
doctorSpeciality = json['DoctorSpeciality'] != null ? json['DoctorSpeciality'].cast<String>() : ["null"];
doctorTitle = json['DoctorTitle'];
gender = json['Gender'];
genderDescription = json['GenderDescription'];
iSAllowOnlineCheckedIN = json['ISAllowOnlineCheckedIN'];
isActiveDoctor = json['IsActiveDoctor'];
isActiveDoctorProfile = json['IsActiveDoctorProfile'];
isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
isExecludeDoctor = json['IsExecludeDoctor'];
isFollowup = json['IsFollowup'];
isLiveCareAppointment = json['IsLiveCareAppointment'];
isInOutPatient = json['IsInOutPatient'];
isMedicalReportRequested = json['IsMedicalReportRequested'];
isOnlineCheckedIN = json['IsOnlineCheckedIN'];
latitude = json['Latitude'];
listHISGetContactLensPerscription = json['List_HIS_GetContactLensPerscription'];
listHISGetGlassPerscription = json['List_HIS_GetGlassPerscription'];
longitude = json['Longitude'];
nextAction = json['NextAction'];
noOfPatientsRate = json['NoOfPatientsRate'];
originalClinicID = json['OriginalClinicID'];
originalProjectID = json['OriginalProjectID'];
projectName = json['ProjectName'];
qR = json['QR'];
remaniningHoursTocanPay = json['RemaniningHoursTocanPay'];
sMSButtonVisable = json['SMSButtonVisable'];
serviceID = json['ServiceID'];
isInOutPatientDescription = json['IsInOutPatientDescription'];
isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
hasReminder = false;
patientShare = json['PatientShare'];
patientShareWithTax = json['PatientShareWithTax'];
patientTaxAmount = json['PatientTaxAmount'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupID'] = this.setupID;
data['ProjectID'] = this.projectID;
data['AppointmentNo'] = this.appointmentNo;
data['AppointmentDate'] = this.appointmentDate;
data['AppointmentDateN'] = this.appointmentDateN;
data['AppointmentType'] = this.appointmentType;
data['BookDate'] = this.bookDate;
data['PatientType'] = this.patientType;
data['PatientID'] = this.patientID;
data['ClinicID'] = this.clinicID;
data['DoctorID'] = this.doctorID;
data['EndDate'] = this.endDate;
data['StartTime'] = this.startTime;
data['EndTime'] = this.endTime;
data['Status'] = this.status;
data['VisitType'] = this.visitType;
data['VisitFor'] = this.visitFor;
data['PatientStatusType'] = this.patientStatusType;
data['CompanyID'] = this.companyID;
data['BookedBy'] = this.bookedBy;
data['BookedOn'] = this.bookedOn;
data['ConfirmedBy'] = this.confirmedBy;
data['ConfirmedOn'] = this.confirmedOn;
data['ArrivalChangedBy'] = this.arrivalChangedBy;
data['ArrivedOn'] = this.arrivedOn;
data['EditedBy'] = this.editedBy;
data['EditedOn'] = this.editedOn;
data['DoctorName'] = this.doctorName;
data['DoctorNameN'] = this.doctorNameN;
data['StatusDesc'] = this.statusDesc;
data['StatusDescN'] = this.statusDescN;
data['VitalStatus'] = this.vitalStatus;
data['VitalSignAppointmentNo'] = this.vitalSignAppointmentNo;
data['EpisodeID'] = this.episodeID;
data['ActualDoctorRate'] = this.actualDoctorRate;
data['ClinicName'] = this.clinicName;
data['ComplainExists'] = this.complainExists;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorNameObj'] = this.doctorNameObj;
data['DoctorRate'] = this.doctorRate;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['DoctorSpeciality'] = this.doctorSpeciality;
data['DoctorTitle'] = this.doctorTitle;
data['Gender'] = this.gender;
data['GenderDescription'] = this.genderDescription;
data['ISAllowOnlineCheckedIN'] = this.iSAllowOnlineCheckedIN;
data['IsActiveDoctor'] = this.isActiveDoctor;
data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
data['IsExecludeDoctor'] = this.isExecludeDoctor;
data['IsFollowup'] = this.isFollowup;
data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
data['IsInOutPatient'] = this.isInOutPatient;
data['IsMedicalReportRequested'] = this.isMedicalReportRequested;
data['IsOnlineCheckedIN'] = this.isOnlineCheckedIN;
data['Latitude'] = this.latitude;
data['List_HIS_GetContactLensPerscription'] = this.listHISGetContactLensPerscription;
data['List_HIS_GetGlassPerscription'] = this.listHISGetGlassPerscription;
data['Longitude'] = this.longitude;
data['NextAction'] = this.nextAction;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
data['OriginalClinicID'] = this.originalClinicID;
data['OriginalProjectID'] = this.originalProjectID;
data['ProjectName'] = this.projectName;
data['QR'] = this.qR;
data['RemaniningHoursTocanPay'] = this.remaniningHoursTocanPay;
data['SMSButtonVisable'] = this.sMSButtonVisable;
data['ServiceID'] = this.serviceID;
return data;
}
}
class PatientAppointmentList {
String? filterName = "";
List<PatientAppointmentHistoryResponseModel>? patientDoctorAppointmentList = [];
PatientAppointmentList({this.filterName, PatientAppointmentHistoryResponseModel? patientDoctorAppointment}) {
patientDoctorAppointmentList!.add(patientDoctorAppointment!);
}
}

@ -1,11 +1,14 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_exception.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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class MyAppointmentsRepo {
Future<Either<Failure, dynamic>> getMyAppointments();
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointments(
{required String patientId, required bool isActiveAppointment, required bool isArrivedAppointments});
}
class MyAppointmentsRepoImp implements MyAppointmentsRepo {
@ -15,57 +18,64 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
MyAppointmentsRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, dynamic>> getMyAppointments() async {
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointments(
{required String patientId, required bool isActiveAppointment, required bool isArrivedAppointments}) async {
final mapDevice = {
"IsActiveAppointment": isActiveAppointment,
"VersionID": 19.0,
"Channel": 3,
"IPAdress": "10.20.10.20",
"generalid": "Cs2020@2016\$2958",
"SessionID": "HdXmi80U6ocW3ZOdT8EpfDDke1ncXyEfIaDLJJjihvA",
"isDentalAllowedBackend": false,
"DeviceTypeID": 1,
"PatientID": patientId,
"PatientTypeID": 1,
"IsComingFromCOC": false,
"PatientType": 1,
"LanguageID": 2,
"isForUpcomming": false,
"IsForArrived": isArrivedAppointments,
"Latitude": 0.0,
"Longitude": 0.0,
"TokenID": "@dm!n",
"PatientOutSA": 0
};
try {
// Mock API call with delayed response
final result = await Future.delayed(
const Duration(seconds: 2),
() => {
'success': true,
'data': [
{
'id': '1',
'doctorName': 'Dr. Ahmed Hassan',
'specialty': 'Cardiology',
'appointmentDate': '2025-09-05',
'appointmentTime': '10:00 AM',
'status': 'confirmed',
'clinicName': 'HMG Hospital',
'patientName': 'John Doe'
},
{
'id': '2',
'doctorName': 'Dr. Sarah Johnson',
'specialty': 'Dermatology',
'appointmentDate': '2025-09-08',
'appointmentTime': '2:30 PM',
'status': 'pending',
'clinicName': 'HMG Medical Center',
'patientName': 'John Doe'
},
{
'id': '3',
'doctorName': 'Dr. Mohamed Ali',
'specialty': 'Pediatrics',
'appointmentDate': '2025-08-25',
'appointmentTime': '11:15 AM',
'status': 'completed',
'clinicName': 'HMG Children\'s Clinic',
'patientName': 'John Doe'
}
]
GenericApiModel<List<PatientAppointmentHistoryResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_APPOINTMENT_HISTORY,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['AppoimentAllHistoryResultList'];
if (list == null || list.isEmpty) {
throw Exception("Appointments list is empty");
}
final appointmentsList = list.map((item) => PatientAppointmentHistoryResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientAppointmentHistoryResponseModel>();
apiResponse = GenericApiModel<List<PatientAppointmentHistoryResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: appointmentsList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (result != null && result is Map && result['success'] != null && result['success'] != false) {
return Right(result);
} else {
loggerService.errorLogs(result.toString());
return Left(ServerFailure(result.toString()));
}
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
loggerService.errorLogs(e.toString());
return Left(ServerFailure(e.toString()));
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,61 @@
import 'package:flutter/material.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_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class MyAppointmentsViewModel extends ChangeNotifier {
int selectedTabIndex = 0;
MyAppointmentsRepo myAppointmentsRepo;
ErrorHandlerService errorHandlerService;
bool isMyAppointmentsLoading = false;
List<PatientAppointmentHistoryResponseModel> patientAppointmentsHistoryList = [];
MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService});
void onTabChange(int index) {
selectedTabIndex = index;
notifyListeners();
}
initAppointmentsViewModel() {
patientAppointmentsHistoryList.clear();
isMyAppointmentsLoading = true;
notifyListeners();
}
setIsAppointmentsHistoryLoading(bool val) {
isMyAppointmentsLoading = val;
notifyListeners();
}
setAppointmentReminder(bool value, PatientAppointmentHistoryResponseModel item) {
int index = patientAppointmentsHistoryList.indexOf(item);
if (index != -1) {
patientAppointmentsHistoryList[index].hasReminder = value;
notifyListeners();
}
}
Future<void> getPatientAppointments(bool isActiveAppointment, bool isArrivedAppointments, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.getPatientAppointments(patientId: "3628599", isActiveAppointment: isActiveAppointment, isArrivedAppointments: isArrivedAppointments);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientAppointmentsHistoryList = apiResponse.data!;
isMyAppointmentsLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -0,0 +1,102 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/extensions/string_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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class AppointmentType {
static var BOOKED = 0;
static const BOOKED_STR = 'booked';
static var CONFIRMED = 42;
static const CONFIRMED_STR = 'confirmed';
static var ARRIVED = 43;
static const ARRIVED_STR = 'arrived';
static bool isConfirmed(PatientAppointmentHistoryResponseModel appo) {
return AppointmentType.isValid(appo) && appo.patientStatusType == AppointmentType.CONFIRMED;
}
static bool isBooked(PatientAppointmentHistoryResponseModel appo) {
return AppointmentType.isValid(appo) && appo.patientStatusType == AppointmentType.BOOKED;
}
static bool isArrived(PatientAppointmentHistoryResponseModel appo) {
return AppointmentType.isValid(appo) && appo.patientStatusType == AppointmentType.ARRIVED;
}
static isValid(appo) {
return appo != null && appo.patientStatusType != null;
}
static String getAppointmentStatusType(int appoStatus) {
switch (appoStatus) {
case 0:
return LocaleKeys.booked.tr();
case 42:
return LocaleKeys.confirmed.tr();
case 43:
return LocaleKeys.arrived.tr();
default:
return LocaleKeys.booked.tr();
}
}
static Color getNextActionButtonColor(nextAction) {
switch (nextAction) {
case 0:
return AppColors.successColor;
case 10:
return AppColors.successColor;
case 15:
return AppColors.greyColor;
case 20:
return AppColors.infoColor;
case 50:
return AppColors.successColor;
case 90:
return AppColors.alertColor;
default:
return AppColors.successColor;
}
}
static String getNextActionText(nextAction) {
switch (nextAction) {
case 0:
return "No Action".needTranslation;
case 10:
return LocaleKeys.confirm.tr();
case 15:
return LocaleKeys.pendingPayment.tr();
case 20:
return LocaleKeys.payNow.tr();
case 50:
return LocaleKeys.confirmLiveCare.tr();
case 90:
return LocaleKeys.checkinOption.tr();
default:
return "No Action".needTranslation;
}
}
static String getNextActionIcon(nextAction) {
switch (nextAction) {
case 0:
return AppAssets.checkmark_icon;
case 10:
return AppAssets.confirm_appointment_icon;
case 15:
return AppAssets.appointment_pay_icon;
case 20:
return AppAssets.appointment_pay_icon;
case 50:
return AppAssets.confirm_appointment_icon;
case 90:
return AppAssets.appointment_checkin_icon;
default:
return AppAssets.checkmark_icon;
}
}
}

@ -11,6 +11,8 @@ 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/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
@ -91,6 +93,15 @@ void main() async {
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<MedicalFileViewModel>(
create: (_) => MedicalFileViewModel(),
),
ChangeNotifierProvider<MyAppointmentsViewModel>(
create: (_) => MyAppointmentsViewModel(
myAppointmentsRepo: getIt(),
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<AuthenticationViewModel>(
create: (_) => AuthenticationViewModel(
authenticationRepo: getIt(),

@ -0,0 +1,140 @@
import 'package:flutter/cupertino.dart';
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/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/features/my_appointments/utils/appointment_type.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:provider/provider.dart';
class AppointmentDetailsPage extends StatefulWidget {
AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel});
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@override
State<AppointmentDetailsPage> createState() => _AppointmentDetailsPageState();
}
class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
late MyAppointmentsViewModel myAppointmentsViewModel;
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: "Appointment Details".needTranslation.toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Appointment Details".needTranslation.toText24(isBold: true),
],
),
SizedBox(height: 24.h),
AppointmentDoctorCard(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onAskDoctorTap: () {},
onCancelTap: () {},
onRescheduleTap: () {},
),
SizedBox(height: 16.h),
if (!AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel))
Container(
height: 200.h,
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: [
"Appointment Status".needTranslation.toText16(isBold: true),
],
),
SizedBox(height: 4.h),
(!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
? "Not Confirmed".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
: "Confirmed".needTranslation.toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)),
SizedBox(height: 16.h),
],
),
),
),
],
).paddingSymmetrical(24.h, 24.h),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: true,
),
child: SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Total amount to pay".needTranslation.toText18(isBold: true),
Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
],
),
],
).paddingSymmetrical(24.h, 24.h),
CustomButton(
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
onPressed: () {},
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: AppColors.whiteColor,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction),
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 24.h),
],
),
),
),
],
),
);
}
}

@ -0,0 +1,111 @@
import 'dart:async';
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_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/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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:provider/provider.dart';
class MyAppointmentsPage extends StatefulWidget {
const MyAppointmentsPage({super.key});
@override
State<MyAppointmentsPage> createState() => _MyAppointmentsPageState();
}
class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
late MyAppointmentsViewModel myAppointmentsViewModel;
@override
void initState() {
scheduleMicrotask(() {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
});
super.initState();
}
@override
Widget build(BuildContext context) {
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: "Appointments List".needTranslation.toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Appointments List".needTranslation.toText24(isBold: true),
],
).paddingSymmetrical(24.h, 24.h),
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [
CustomTabBarModel(null, "All Appt.".needTranslation),
CustomTabBarModel(null, "Upcoming".needTranslation),
CustomTabBarModel(null, LocaleKeys.request.tr(context: context)),
],
onTabChange: (index) {
print(index);
},
).paddingSymmetrical(24.h, 0.h),
Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
// Expandable list
ListView.separated(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: myAppointmentsVM.isMyAppointmentsLoading ? 5 : myAppointmentsVM.patientAppointmentsHistoryList.length,
itemBuilder: (context, index) {
return myAppointmentsVM.isMyAppointmentsLoading
? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0.h)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index],
myAppointmentsViewModel: myAppointmentsViewModel,
),
).paddingSymmetrical(24.h, 0.h),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
],
);
}),
],
),
),
);
}
}

@ -0,0 +1,251 @@
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/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';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
class AppointmentCard extends StatefulWidget {
AppointmentCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel});
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
MyAppointmentsViewModel myAppointmentsViewModel;
@override
State<AppointmentCard> createState() => _AppointmentCardState();
}
class _AppointmentCardState extends State<AppointmentCard> {
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
return InkWell(
onTap: () {
Navigator.of(context).push(
FadePage(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
),
);
},
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Wrap(
alignment: WrapAlignment.start,
direction: Axis.horizontal,
spacing: 6.h,
runSpacing: 6.h,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: appState.isArabic()
? widget.patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN!
: widget.patientAppointmentHistoryResponseModel.isInOutPatientDescription!,
onPressed: () {},
backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
borderColor: AppColors.primaryRedColor.withOpacity(0.0),
textColor: AppColors.primaryRedColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: AppointmentType.getAppointmentStatusType(widget.patientAppointmentHistoryResponseModel.patientStatusType!),
onPressed: () {},
backgroundColor: AppColors.successColor.withOpacity(0.1),
borderColor: AppColors.successColor.withOpacity(0.0),
textColor: AppColors.successColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
],
),
),
// TODO: Implement the logic to enable/disable the switch based on reminder status
Switch(
activeColor: AppColors.successColor,
activeTrackColor: AppColors.successColor.withValues(alpha: .15),
thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
(Set<WidgetState> states) {
if (states.contains(WidgetState.selected)) {
return const Icon(Icons.check); // Icon when switch is ON
}
return const Icon(Icons.close); // Icon when switch is OFF
},
),
value: widget.patientAppointmentHistoryResponseModel.hasReminder!,
onChanged: (newValue) {
setState(() {
widget.myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel);
});
},
),
],
),
SizedBox(height: 16.h),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
widget.patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 16.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true),
SizedBox(height: 8.h),
Row(
children: [
CustomButton(
text: widget.patientAppointmentHistoryResponseModel.clinicName!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
SizedBox(width: 6.h),
CustomButton(
text: widget.patientAppointmentHistoryResponseModel.projectName!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
SizedBox(height: 6.h),
Row(
children: [
CustomButton(
icon: AppAssets.appointment_calendar_icon,
iconColor: AppColors.blackColor,
iconSize: 12.h,
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
SizedBox(width: 6.h),
CustomButton(
icon: AppAssets.appointment_time_icon,
iconColor: AppColors.blackColor,
iconSize: 12.h,
text: DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
)
],
),
],
),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
flex: 6,
child: CustomButton(
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
onPressed: () {},
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.1),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction),
iconColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),
iconSize: 14.h,
),
),
SizedBox(width: 8.h),
Expanded(
flex: 1,
child: Container(
height: 40.h,
width: 40.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.textColor,
borderRadius: 10.h,
),
child: Padding(
padding: EdgeInsets.all(10.h),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
width: 10.h,
height: 10.h,
fit: BoxFit.contain,
),
),
),
),
],
),
],
),
),
);
}
void performAppointmentNextAction(nextAction) {}
}

@ -0,0 +1,189 @@
import 'package:easy_localization/easy_localization.dart';
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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
class AppointmentDoctorCard extends StatelessWidget {
AppointmentDoctorCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.onRescheduleTap, required this.onCancelTap, required this.onAskDoctorTap});
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
late Function onRescheduleTap;
late Function onCancelTap;
late Function onAskDoctorTap;
@override
Widget build(BuildContext context) {
return 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(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 16.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true),
SizedBox(height: 8.h),
Row(
children: [
CustomButton(
text: patientAppointmentHistoryResponseModel.clinicName!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
SizedBox(width: 6.h),
CustomButton(
text: patientAppointmentHistoryResponseModel.projectName!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
SizedBox(height: 6.h),
Row(
children: [
CustomButton(
icon: AppAssets.appointment_calendar_icon,
iconColor: AppColors.blackColor,
iconSize: 12.h,
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
SizedBox(width: 6.h),
CustomButton(
icon: AppAssets.appointment_time_icon,
iconColor: AppColors.blackColor,
iconSize: 12.h,
text: DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
)
],
),
],
),
SizedBox(height: 16.h),
getAppointmentActionButtons(
AppointmentType.isArrived(patientAppointmentHistoryResponseModel),
),
],
),
),
);
}
Widget getAppointmentActionButtons(bool isAppointmentArrived) {
if (isAppointmentArrived) {
return CustomButton(
text: LocaleKeys.askDoctor.tr(),
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
icon: AppAssets.ask_doctor_icon,
iconColor: AppColors.primaryRedColor,
);
} else {
return Row(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.reschedule.tr(),
onPressed: () {
onRescheduleTap();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
height: 40.h,
icon: AppAssets.appointment_calendar_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
),
),
SizedBox(width: 16.h),
Expanded(
child: CustomButton(
text: LocaleKeys.cancel.tr(),
onPressed: () {
onCancelTap();
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
height: 40.h,
icon: AppAssets.cancel,
iconColor: AppColors.whiteColor,
iconSize: 16.h,
),
),
],
);
}
}
}

@ -128,7 +128,13 @@ class _LandingPageState extends State<LandingPage> {
],
),
],
).paddingSymmetrical(24.h, 0.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
Navigator.of(context).push(
FadePage(
page: MedicalFilePage(),
),
);
}),
SizedBox(height: 12.h),
Container(
height: 127.h,

@ -60,17 +60,19 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.labResults.tr(context: context).toText24(isBold: true),
Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(() {
if(model.isLabOrdersLoading){
Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(() {
if (model.isLabOrdersLoading) {
return;
}else {
showCommonBottomSheet(context, child: SearchLabResultsContent(labSuggestionsList: model.labSuggestions),
} else {
showCommonBottomSheet(context,
child: SearchLabResultsContent(labSuggestionsList: model.labSuggestions),
callBackFunc: () {},
title: LocaleKeys.searchLabReport.tr(),
height: ResponsiveExtension.screenHeight,
isFullScreen: true,
isCloseButtonVisible: true);
} }),
}
}),
],
),
SizedBox(height: 16.h),
@ -275,13 +277,11 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
return "";
}
}
getLabSuggestions(LabViewModel model) {
if(model.patientLabOrders.isEmpty){
if (model.patientLabOrders.isEmpty) {
return [];
}
return model.patientLabOrders.map((m) => m.testDetails).toList();
return model.patientLabOrders.map((m) => m.testDetails).toList();
}
}

@ -8,7 +8,9 @@ import 'package:hmg_patient_app_new/core/utils/size_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/insurance/insurance_view_model.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/presentation/appointments/my_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@ -16,6 +18,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
class MedicalFilePage extends StatefulWidget {
@ -28,6 +31,8 @@ class MedicalFilePage extends StatefulWidget {
class _MedicalFilePageState extends State<MedicalFilePage> {
late InsuranceViewModel insuranceViewModel;
int currentIndex = 0;
@override
void initState() {
scheduleMicrotask(() {
@ -182,19 +187,65 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
),
).paddingSymmetrical(24.h, 0.0),
SizedBox(height: 16.h),
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [
CustomTabBarModel(AppAssets.myFilesBottom, LocaleKeys.general.tr(context: context).needTranslation),
CustomTabBarModel(AppAssets.insurance, LocaleKeys.insurance.tr(context: context)),
CustomTabBarModel(AppAssets.requests, LocaleKeys.request.tr(context: context).needTranslation),
CustomTabBarModel(AppAssets.more, "More".needTranslation),
Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
return Column(
children: [
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [
CustomTabBarModel(AppAssets.myFilesBottom, LocaleKeys.general.tr(context: context).needTranslation),
CustomTabBarModel(AppAssets.insurance, LocaleKeys.insurance.tr(context: context)),
CustomTabBarModel(AppAssets.requests, LocaleKeys.request.tr(context: context).needTranslation),
CustomTabBarModel(AppAssets.more, "More".needTranslation),
],
onTabChange: (index) {
print(index);
medicalFileVM.onTabChanged(index);
},
).paddingSymmetrical(24.h, 0.0),
SizedBox(height: 24.h),
getSelectedTabData(medicalFileVM.selectedTabIndex),
],
);
}),
],
),
),
);
}
Widget getSelectedTabData(int index) {
switch (index) {
case 0:
//General Tab Data
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Appointments & visits".needTranslation.toText18(isBold: true),
Row(
children: [
LocaleKeys.viewAll.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
SizedBox(width: 2.h),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h),
],
),
],
onTabChange: (index) {},
).paddingSymmetrical(24.h, 0.0),
SizedBox(height: 16.h),
//Insurance Tab Data
).paddingSymmetrical(24.h, 0.h).onPress(() {
Navigator.of(context).push(
FadePage(
page: MyAppointmentsPage(),
),
);
}),
],
);
case 1:
//Insurance Tab Data
return Column(
children: [
Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) {
return insuranceVM.isInsuranceLoading
? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0.0)
@ -217,8 +268,13 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
).paddingSymmetrical(24.h, 0.0),
SizedBox(height: 16.h),
],
),
),
);
);
case 2:
return Container();
case 3:
return Container();
default:
return Container();
}
}
}

@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/int_extensions.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/theme/colors.dart';
class CustomTabBarModel {
String? image;
@ -78,9 +79,9 @@ class _CustomTabBarState extends State<CustomTabBar> {
return Container(
height: 62.h,
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(11),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 11,
),
child: parentWidget);
}
@ -91,9 +92,9 @@ class _CustomTabBarState extends State<CustomTabBar> {
height: 54.h,
padding: EdgeInsets.only(top: 4, bottom: 4, left: 16, right: 16),
alignment: Alignment.center,
decoration: BoxDecoration(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: isSelected ? widget.activeBackgroundColor : widget.inActiveBackgroundColor,
borderRadius: BorderRadius.circular(7),
borderRadius: 12,
),
child: Row(
mainAxisSize: MainAxisSize.min,
@ -101,7 +102,7 @@ class _CustomTabBarState extends State<CustomTabBar> {
children: [
if (tabBar.image != null) Utils.buildSvgWithAssets(icon: tabBar.image!, height: 18, width: 18, iconColor: isSelected ? widget.activeTextColor : widget.inActiveTextColor),
tabBar.title
.toText16(weight: isSelected ? FontWeight.w600 : FontWeight.w500, color: isSelected ? widget.activeTextColor : widget.inActiveTextColor, letterSpacing: isSelected ? -0.3 : -0.1),
.toText15(weight: isSelected ? FontWeight.w600 : FontWeight.w500, color: isSelected ? widget.activeTextColor : widget.inActiveTextColor, letterSpacing: isSelected ? -0.3 : -0.1),
],
)).onPress(() {
setState(() {

Loading…
Cancel
Save