Merge branch 'master' into dev_aamir

# Conflicts:
#	lib/extensions/string_extensions.dart
#	lib/presentation/my_family/widget/family_cards.dart
#	lib/widgets/chip/app_custom_chip_widget.dart
#	lib/widgets/common_bottom_sheet.dart
pull/76/head
aamir-csol 5 months ago
commit e5488299b8

File diff suppressed because one or more lines are too long

@ -0,0 +1,3 @@
<svg width="30" height="26" viewBox="0 0 30 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.7787 1.62383C17.9327 0.00618458 21.4984 -0.965477 25.473 1.47256C28.2213 3.15838 29.7678 6.67982 29.2251 10.7258C28.6799 14.7914 26.0484 19.3896 20.4756 23.5144L20.3369 23.6171C18.4017 25.0503 17.1201 25.9994 15.0001 25.9994C12.88 25.9994 11.5984 25.0503 9.66323 23.6171L9.5245 23.5144C3.95169 19.3896 1.32025 14.7914 0.77498 10.7258C0.232334 6.67982 1.77878 3.15838 4.5271 1.47256C8.50173 -0.965478 12.0674 0.00618442 14.2214 1.62383C14.5758 1.88996 14.819 2.07209 15.0001 2.19508C15.1811 2.07209 15.4243 1.88996 15.7787 1.62383ZM15.2118 2.3251C15.2117 2.3251 15.2108 2.32473 15.209 2.32395L15.2072 2.32309C15.2104 2.32437 15.2119 2.32511 15.2118 2.3251ZM14.7929 2.32309C14.7875 2.32524 14.7868 2.32588 14.7911 2.32395L14.7929 2.32309ZM24.4273 3.17739C21.2508 1.22896 18.5751 2.02499 16.9797 3.22308L16.9519 3.24398C16.5914 3.51473 16.2816 3.74735 16.0339 3.90952C15.9052 3.99381 15.7626 4.07964 15.6146 4.1465C15.4742 4.20996 15.2585 4.28934 15.0001 4.28934C14.7416 4.28934 14.5259 4.20996 14.3855 4.1465C14.2375 4.07964 14.0949 3.99381 13.9662 3.90952C13.7185 3.74736 13.4089 3.51481 13.0484 3.24407L13.0204 3.22308C11.4251 2.02499 8.74927 1.22896 5.57284 3.17739C3.62867 4.36994 2.29796 7.03563 2.75723 10.46C2.76742 10.536 2.7785 10.6123 2.79049 10.689C2.85811 10.6746 2.92826 10.667 3.00018 10.667L5.7991 10.6669C6.42367 10.666 6.97406 10.6652 7.47333 10.8468C8.17556 11.1023 8.66627 11.6989 8.95799 12.0536C8.982 12.0828 9.00493 12.1106 9.02624 12.1362C9.04161 12.1547 9.05631 12.1736 9.07032 12.1932L10.2586 13.8481L13.476 8.48583C13.6606 8.17823 13.9958 7.99305 14.3544 8.00054C14.7131 8.00804 15.0402 8.20707 15.2118 8.52212L17.452 12.6363C17.7498 13.112 17.7869 13.1449 17.8184 13.1691C17.9144 13.2428 18.0296 13.289 18.2138 13.3136C18.3868 13.3367 18.5557 13.3358 18.7968 13.3344C18.8593 13.334 18.9267 13.3337 19.0002 13.3337H20.3335C20.8858 13.3337 21.3335 13.7814 21.3335 14.3337C21.3335 14.8859 20.8858 15.3337 20.3335 15.3337H19.0002C18.9535 15.3337 18.9012 15.3345 18.8442 15.3355C18.3195 15.3445 17.388 15.3603 16.6002 14.7552C16.2445 14.4821 16.0142 14.1116 15.7919 13.7542L15.7402 13.6711C15.7296 13.6541 15.7195 13.6369 15.7099 13.6193L14.2914 11.0141L11.191 16.1815C11.0178 16.4701 10.711 16.6523 10.3747 16.6661C10.0383 16.68 9.71756 16.5237 9.52122 16.2502L7.46691 13.3891C7.08115 12.9274 6.93061 12.7776 6.78959 12.7263C6.66628 12.6815 6.50179 12.667 5.66685 12.667H3.28376C4.27649 15.5775 6.55282 18.8266 10.7144 21.9068C12.8239 23.4682 13.5939 23.9994 15.0001 23.9994C16.4062 23.9994 17.1762 23.4682 19.2858 21.9068C24.5367 18.0202 26.7862 13.8648 27.2429 10.46C27.7021 7.03563 26.3714 4.36994 24.4273 3.17739Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

@ -0,0 +1,3 @@
<svg width="26" height="28" viewBox="0 0 26 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.666748 8.66634C0.666748 12.9303 3.86919 16.4463 8.00008 16.9403V20.333C8.00008 24.3831 11.2833 27.6663 15.3334 27.6663C19.3835 27.6663 22.6667 24.3831 22.6667 20.333V19.5283C24.2058 19.093 25.3334 17.678 25.3334 15.9997C25.3334 13.9746 23.6918 12.333 21.6667 12.333C19.6417 12.333 18.0001 13.9746 18.0001 15.9997C18.0001 17.678 19.1277 19.093 20.6667 19.5283V20.333C20.6667 23.2785 18.2789 25.6663 15.3334 25.6663C12.3879 25.6663 10.0001 23.2785 10.0001 20.333V16.9403C14.131 16.4463 17.3334 12.9303 17.3334 8.66634V3.99967C17.3334 2.71101 16.2887 1.66634 15.0001 1.66634H13.3334V1.33301C13.3334 0.780724 12.8857 0.333008 12.3334 0.333008C11.7811 0.333008 11.3334 0.780724 11.3334 1.33301V3.99967C11.3334 4.55196 11.7811 4.99967 12.3334 4.99967C12.8857 4.99967 13.3334 4.55196 13.3334 3.99967V3.66634H15.0001C15.1842 3.66634 15.3334 3.81558 15.3334 3.99967V8.66634C15.3334 12.1641 12.4979 14.9997 9.00008 14.9997C5.50228 14.9997 2.66675 12.1641 2.66675 8.66634V3.99967C2.66675 3.81558 2.81599 3.66634 3.00008 3.66634H4.66675V3.99967C4.66675 4.55196 5.11446 4.99967 5.66675 4.99967C6.21903 4.99967 6.66675 4.55196 6.66675 3.99967V1.33301C6.66675 0.780724 6.21903 0.333008 5.66675 0.333008C5.11446 0.333008 4.66675 0.780724 4.66675 1.33301V1.66634H3.00008C1.71142 1.66634 0.666748 2.71101 0.666748 3.99967V8.66634ZM21.6667 17.6663C20.7463 17.6663 20.0001 16.9202 20.0001 15.9997C20.0001 15.0792 20.7463 14.333 21.6667 14.333C22.5872 14.333 23.3334 15.0792 23.3334 15.9997C23.3334 16.9202 22.5872 17.6663 21.6667 17.6663Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -1,8 +1,5 @@
<svg data-name="Group 8404" height="26" id="Group_8404" viewBox="0 0 26 26"
width="26" xmlns="http://www.w3.org/2000/svg">
<rect data-name="Rectangle 17531" fill="#69a6e2" height="26" id="Rectangle_17531" rx="4"
width="26" />
<path d="M2.914,17.807s.731-.005,1.246-.005l3.9.019c.466,0,.854-.488.876-1.193l0-3.213c0-.685.311-1.221.793-1.252l1.2-.009c.483.029.814.572.814,1.253l0,3.231c.021.7.346,1.165.814,1.165l5.254.014.01-3.971c0-.683-.333-1.214-.82-1.245l-2.11-.01c-.467,0-.834-.486-.854-1.191l-.008-1.074c.023-.7.392-1.189.86-1.189l2.122.006c.482-.031.8-.592.8-1.274l.005-4.957a2.126,2.126,0,0,1-.693.69,2.164,2.164,0,0,1-.933.312l-3.569,0c-.465,0-.854.5-.876,1.2V8.295c-.022.7-.387,1.2-.854,1.2l-1.08-.008c-.468,0-.842-.482-.864-1.183l0-3.218c-.021-.705-.392-1.178-.859-1.178l-5.179,0V7.87c0,.684.324,1.231.808,1.263l2.122-.009c.48.031.82.595.82,1.275l-.007.916c0,.683-.328,1.23-.81,1.261l-2.126-.005c-.484.034-.808.572-.808,1.256Z" data-name="Path 5276"
fill="#fff"
id="Path_5276" transform="translate(2.327 2.327)" />
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="14" height="14" rx="3" fill="#0B85F7"/>
<path d="M2.54806 11.4469C2.54806 11.4469 2.98492 11.4437 3.29241 11.4437L5.6242 11.455C5.90252 11.455 6.13431 11.1634 6.14737 10.7422L6.15002 8.82227C6.15002 8.41291 6.3357 8.09262 6.6236 8.07432L7.33877 8.06869C7.62708 8.08618 7.825 8.4105 7.825 8.81725L7.82316 10.7474C7.83581 11.1685 8.03006 11.4433 8.30981 11.4433L11.4488 11.4518L11.4545 9.07923C11.4545 8.67107 11.2554 8.354 10.9648 8.3353L9.70382 8.32907C9.4249 8.32907 9.20555 8.03893 9.19372 7.6173L9.18882 6.97551C9.20269 6.55449 9.42326 6.26496 9.7028 6.26496L10.9707 6.26858C11.2588 6.25028 11.4465 5.91511 11.4465 5.50755L11.4496 2.5459C11.346 2.71309 11.2043 2.85421 11.0357 2.95807C10.8671 3.06193 10.6763 3.12568 10.4784 3.14426L8.34613 3.14245C8.06843 3.14245 7.83602 3.44083 7.82296 3.86185L7.82296 5.76371C7.8099 6.18393 7.59178 6.4813 7.31285 6.4813L6.66767 6.47647C6.38793 6.47647 6.1643 6.18875 6.15165 5.76974L6.15328 3.84698C6.14063 3.42575 5.91904 3.14326 5.63991 3.14326L2.54562 3.14466L2.54562 5.50997C2.54562 5.91853 2.73925 6.24565 3.02817 6.26455L4.29609 6.25933C4.58277 6.27782 4.78579 6.61481 4.78579 7.02115L4.78192 7.56865C4.78192 7.97701 4.58604 8.30373 4.29793 8.32223L3.02797 8.31921C2.73905 8.33932 2.54541 8.66102 2.54541 9.06938L2.54806 11.4469Z" fill="white"/>
<path d="M2.54806 11.4469C2.54806 11.4469 2.98492 11.4437 3.29241 11.4437L5.6242 11.455C5.90252 11.455 6.13431 11.1634 6.14737 10.7422L6.15002 8.82227C6.15002 8.41291 6.3357 8.09262 6.6236 8.07432L7.33877 8.06869C7.62708 8.08618 7.825 8.4105 7.825 8.81725L7.82316 10.7474C7.83581 11.1685 8.03006 11.4433 8.30981 11.4433L11.4488 11.4518L11.4545 9.07923C11.4545 8.67107 11.2554 8.354 10.9648 8.3353L9.70382 8.32907C9.4249 8.32907 9.20555 8.03893 9.19372 7.6173L9.18882 6.97551C9.20269 6.55449 9.42326 6.26496 9.7028 6.26496L10.9707 6.26858C11.2588 6.25028 11.4465 5.91511 11.4465 5.50755L11.4496 2.5459C11.346 2.71309 11.2043 2.85421 11.0357 2.95807C10.8671 3.06193 10.6763 3.12568 10.4784 3.14426L8.34613 3.14245C8.06843 3.14245 7.83602 3.44083 7.82296 3.86185L7.82296 5.76371C7.8099 6.18393 7.59178 6.4813 7.31285 6.4813L6.66767 6.47647C6.38793 6.47647 6.1643 6.18875 6.15165 5.76974L6.15328 3.84698C6.14063 3.42575 5.91904 3.14326 5.63991 3.14326L2.54562 3.14466L2.54562 5.50997C2.54562 5.91853 2.73925 6.24565 3.02817 6.26455L4.29609 6.25933C4.58277 6.27782 4.78579 6.61481 4.78579 7.02115L4.78192 7.56865C4.78192 7.97701 4.58604 8.30373 4.29793 8.32223L3.02797 8.31921C2.73905 8.33932 2.54541 8.66102 2.54541 9.06938L2.54806 11.4469Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -1,8 +1,5 @@
<svg data-name="Group 8404" height="26" id="Group_8404" viewBox="0 0 26 26"
width="26" xmlns="http://www.w3.org/2000/svg">
<rect data-name="Rectangle 17531" fill="#cc2229" height="26" id="Rectangle_17531" rx="4"
width="26" />
<path d="M2.914,17.807s.731-.005,1.246-.005l3.9.019c.466,0,.854-.488.876-1.193l0-3.213c0-.685.311-1.221.793-1.252l1.2-.009c.483.029.814.572.814,1.253l0,3.231c.021.7.346,1.165.814,1.165l5.254.014.01-3.971c0-.683-.333-1.214-.82-1.245l-2.11-.01c-.467,0-.834-.486-.854-1.191l-.008-1.074c.023-.7.392-1.189.86-1.189l2.122.006c.482-.031.8-.592.8-1.274l.005-4.957a2.126,2.126,0,0,1-.693.69,2.164,2.164,0,0,1-.933.312l-3.569,0c-.465,0-.854.5-.876,1.2V8.295c-.022.7-.387,1.2-.854,1.2l-1.08-.008c-.468,0-.842-.482-.864-1.183l0-3.218c-.021-.705-.392-1.178-.859-1.178l-5.179,0V7.87c0,.684.324,1.231.808,1.263l2.122-.009c.48.031.82.595.82,1.275l-.007.916c0,.683-.328,1.23-.81,1.261l-2.126-.005c-.484.034-.808.572-.808,1.256Z" data-name="Path 5276"
fill="#fff"
id="Path_5276" transform="translate(2.327 2.327)" />
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="14" height="14" rx="3" fill="#ED1C2B"/>
<path d="M2.54806 11.4469C2.54806 11.4469 2.98492 11.4437 3.29241 11.4437L5.6242 11.455C5.90252 11.455 6.13431 11.1634 6.14737 10.7422L6.15002 8.82227C6.15002 8.41291 6.3357 8.09262 6.6236 8.07432L7.33877 8.06869C7.62708 8.08618 7.825 8.4105 7.825 8.81725L7.82316 10.7474C7.83581 11.1685 8.03006 11.4433 8.30981 11.4433L11.4488 11.4518L11.4545 9.07923C11.4545 8.67107 11.2554 8.354 10.9648 8.3353L9.70382 8.32907C9.4249 8.32907 9.20555 8.03893 9.19372 7.6173L9.18882 6.97551C9.20269 6.55449 9.42326 6.26496 9.7028 6.26496L10.9707 6.26858C11.2588 6.25028 11.4465 5.91511 11.4465 5.50755L11.4496 2.5459C11.346 2.71309 11.2043 2.85421 11.0357 2.95807C10.8671 3.06193 10.6763 3.12568 10.4784 3.14426L8.34613 3.14245C8.06843 3.14245 7.83602 3.44083 7.82296 3.86185L7.82296 5.76371C7.8099 6.18393 7.59178 6.4813 7.31285 6.4813L6.66767 6.47647C6.38793 6.47647 6.1643 6.18875 6.15165 5.76974L6.15328 3.84698C6.14063 3.42575 5.91904 3.14326 5.63991 3.14326L2.54562 3.14466L2.54562 5.50997C2.54562 5.91853 2.73925 6.24565 3.02817 6.26455L4.29609 6.25933C4.58277 6.27782 4.78579 6.61481 4.78579 7.02115L4.78192 7.56865C4.78192 7.97701 4.58604 8.30373 4.29793 8.32223L3.02797 8.31921C2.73905 8.33932 2.54541 8.66102 2.54541 9.06938L2.54806 11.4469Z" fill="white"/>
<path d="M2.54806 11.4469C2.54806 11.4469 2.98492 11.4437 3.29241 11.4437L5.6242 11.455C5.90252 11.455 6.13431 11.1634 6.14737 10.7422L6.15002 8.82227C6.15002 8.41291 6.3357 8.09262 6.6236 8.07432L7.33877 8.06869C7.62708 8.08618 7.825 8.4105 7.825 8.81725L7.82316 10.7474C7.83581 11.1685 8.03006 11.4433 8.30981 11.4433L11.4488 11.4518L11.4545 9.07923C11.4545 8.67107 11.2554 8.354 10.9648 8.3353L9.70382 8.32907C9.4249 8.32907 9.20555 8.03893 9.19372 7.6173L9.18882 6.97551C9.20269 6.55449 9.42326 6.26496 9.7028 6.26496L10.9707 6.26858C11.2588 6.25028 11.4465 5.91511 11.4465 5.50755L11.4496 2.5459C11.346 2.71309 11.2043 2.85421 11.0357 2.95807C10.8671 3.06193 10.6763 3.12568 10.4784 3.14426L8.34613 3.14245C8.06843 3.14245 7.83602 3.44083 7.82296 3.86185L7.82296 5.76371C7.8099 6.18393 7.59178 6.4813 7.31285 6.4813L6.66767 6.47647C6.38793 6.47647 6.1643 6.18875 6.15165 5.76974L6.15328 3.84698C6.14063 3.42575 5.91904 3.14326 5.63991 3.14326L2.54562 3.14466L2.54562 5.50997C2.54562 5.91853 2.73925 6.24565 3.02817 6.26455L4.29609 6.25933C4.58277 6.27782 4.78579 6.61481 4.78579 7.02115L4.78192 7.56865C4.78192 7.97701 4.58604 8.30373 4.29793 8.32223L3.02797 8.31921C2.73905 8.33932 2.54541 8.66102 2.54541 9.06938L2.54806 11.4469Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1,3 @@
<svg width="18" height="14" viewBox="0 0 18 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.55403 0.250001H6.69598C5.50451 0.249979 4.5346 0.249962 3.76973 0.352797C2.97174 0.460084 2.28552 0.691519 1.73852 1.23852C1.19152 1.78552 0.960084 2.47174 0.852797 3.26973C0.749962 4.0346 0.749979 5.00446 0.750001 6.19592V7.80403C0.749979 8.9955 0.749962 9.9654 0.852797 10.7303C0.960084 11.5283 1.19152 12.2145 1.73852 12.7615C2.28552 13.3085 2.97174 13.5399 3.76973 13.6472C4.53462 13.75 5.5045 13.75 6.696 13.75H7.55401C8.74551 13.75 9.71539 13.75 10.4803 13.6472C11.2783 13.5399 11.9645 13.3085 12.5115 12.7615C13.0406 12.2323 13.2745 11.5729 13.3863 10.808C13.7298 11.078 14.0404 11.3056 14.3208 11.4749C14.846 11.7922 15.5117 12.0579 16.1947 11.7194C16.8671 11.386 17.0755 10.7028 17.1622 10.0899C17.2493 9.47366 17.2493 8.64442 17.2493 7.64834V6.35366C17.2493 5.35758 17.2493 4.52834 17.1622 3.91212C17.0755 3.29915 16.8671 2.61597 16.1947 2.28264C15.5117 1.94405 14.846 2.20976 14.3208 2.52707C14.0405 2.69639 13.7299 2.92386 13.3866 3.19378C13.2748 2.42814 13.0411 1.76809 12.5115 1.23852C11.9645 0.691519 11.2783 0.460084 10.4803 0.352797C9.7154 0.249962 8.7455 0.249979 7.55403 0.250001ZM13.4957 5.03688C13.5 5.39712 13.5 5.78326 13.5 6.196V7.80401C13.5 8.2175 13.5 8.6043 13.4957 8.9651C14.2136 9.55664 14.7094 9.95725 15.0964 10.191C15.2999 10.314 15.4227 10.3584 15.4898 10.3717C15.5046 10.3746 15.5147 10.3756 15.5207 10.3759C15.5237 10.376 15.527 10.376 15.527 10.376L15.5285 10.3754C15.5298 10.3748 15.5308 10.3741 15.5316 10.3736C15.5326 10.3729 15.5331 10.3724 15.5331 10.3724C15.5352 10.3702 15.5464 10.3581 15.5624 10.3268C15.5983 10.2567 15.6425 10.1231 15.6769 9.87979C15.7474 9.38156 15.7493 8.66013 15.7493 7.58744V6.41456C15.7493 5.34186 15.7474 4.62044 15.6769 4.12221C15.6425 3.87891 15.5983 3.74533 15.5624 3.67518C15.5464 3.64392 15.5355 3.63212 15.5334 3.6299C15.5334 3.6299 15.5318 3.6282 15.5285 3.62659L15.5274 3.62604C15.5274 3.62604 15.5237 3.62597 15.5207 3.62613C15.5147 3.62643 15.5046 3.62741 15.4898 3.63035C15.4227 3.64362 15.2999 3.68801 15.0964 3.81097C14.7094 4.04475 14.2136 4.44534 13.4957 5.03688ZM7.5 4C7.5 3.58579 7.83579 3.25 8.25 3.25L9.75 3.25C10.1642 3.25 10.5 3.58579 10.5 4C10.5 4.41422 10.1642 4.75 9.75 4.75L8.25 4.75C7.83579 4.75 7.5 4.41422 7.5 4Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -0,0 +1,4 @@
<svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.99992 0.228516C2.7918 0.228516 1.81242 1.20789 1.81242 2.41602C1.81242 3.04229 2.13626 3.65197 2.52655 4.09024C2.72604 4.31425 2.95689 4.50994 3.19989 4.65217C3.43884 4.79203 3.71565 4.89518 3.99992 4.89518C4.28419 4.89518 4.56099 4.79203 4.79995 4.65217C5.04295 4.50994 5.2738 4.31425 5.47329 4.09024C5.86358 3.65197 6.18742 3.04229 6.18742 2.41602C6.18742 1.20789 5.20804 0.228516 3.99992 0.228516Z" fill="#2E3039"/>
<path d="M1.61723 4.36783C1.63636 4.38209 1.65653 4.40812 1.69687 4.46017C1.75478 4.53488 1.8138 4.6057 1.8731 4.67228C2.12459 4.95469 2.42491 5.21256 2.7579 5.40745C3.07856 5.59513 3.50915 5.77031 3.99992 5.77031C4.49069 5.77031 4.92128 5.59513 5.24194 5.40745C5.57493 5.21256 5.87525 4.95469 6.12674 4.67228C6.18603 4.60571 6.24504 4.5349 6.30294 4.4602C6.3434 4.408 6.36363 4.3819 6.38283 4.36761C6.4397 4.3253 6.51163 4.32078 6.57335 4.35564C6.59419 4.36741 6.61516 4.38841 6.6571 4.4304C7.62953 5.28979 8.31909 6.79331 7.70799 8.24712C7.52984 8.67092 7.11767 8.95186 6.65499 8.95186L6.49354 8.95055C6.3607 8.94948 6.29428 8.94894 6.24626 8.9863C6.19823 9.02366 6.18241 9.08817 6.15078 9.21719L5.58834 11.511C5.40816 12.2458 4.75708 12.7704 4.00002 12.7704C3.24297 12.7704 2.59188 12.2458 2.41171 11.511L1.84927 9.21719C1.81763 9.08817 1.80181 9.02366 1.75379 8.9863C1.70576 8.94894 1.63934 8.94948 1.5065 8.95055L1.34506 8.95186C0.882379 8.95186 0.470201 8.67092 0.292058 8.24712C-0.319046 6.7933 0.370548 5.28979 1.34297 4.43041C1.38478 4.38854 1.40569 4.3676 1.42646 4.35585C1.48825 4.32088 1.5603 4.32541 1.61723 4.36783Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -10,12 +10,12 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
40721B3F0DC8DB0598443DBF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E824BDA50EF77318022F59D /* Pods_Runner.framework */; };
478CFA942E638C8E0064F3D7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
B976FB9C47411C32B24D5E01 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ACE60DF9393168FD748550B3 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -44,16 +44,16 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1E824BDA50EF77318022F59D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
62D069322AC3B532E0B4F137 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7595037DD52211B91157B0F3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8E12CEEB8E334EE22D5259D7 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -61,8 +61,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
ACE60DF9393168FD748550B3 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D6BB17A036DF7FCE75271203 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
B35471C63C8DD1B1DECDB3A5 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
D0FB40CE52522242F351743B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -70,7 +70,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B976FB9C47411C32B24D5E01 /* Pods_Runner.framework in Frameworks */,
40721B3F0DC8DB0598443DBF /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -88,9 +88,9 @@
79DD2093A1D9674C94359FC8 /* Pods */ = {
isa = PBXGroup;
children = (
8E12CEEB8E334EE22D5259D7 /* Pods-Runner.debug.xcconfig */,
7595037DD52211B91157B0F3 /* Pods-Runner.release.xcconfig */,
D6BB17A036DF7FCE75271203 /* Pods-Runner.profile.xcconfig */,
62D069322AC3B532E0B4F137 /* Pods-Runner.debug.xcconfig */,
D0FB40CE52522242F351743B /* Pods-Runner.release.xcconfig */,
B35471C63C8DD1B1DECDB3A5 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -114,7 +114,7 @@
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
79DD2093A1D9674C94359FC8 /* Pods */,
A07D637C76A0ABB38659D189 /* Frameworks */,
C1312CE4ABEB9ED47FF21174 /* Frameworks */,
);
sourceTree = "<group>";
};
@ -144,10 +144,10 @@
path = Runner;
sourceTree = "<group>";
};
A07D637C76A0ABB38659D189 /* Frameworks */ = {
C1312CE4ABEB9ED47FF21174 /* Frameworks */ = {
isa = PBXGroup;
children = (
ACE60DF9393168FD748550B3 /* Pods_Runner.framework */,
1E824BDA50EF77318022F59D /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -176,15 +176,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
BFED6CCFE59BB148875A533B /* [CP] Check Pods Manifest.lock */,
E3E41B3FF6C30233949963A9 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
8372B02399CDF54531650AD4 /* [CP] Embed Pods Frameworks */,
81DE7C26F41956799E954FCE /* [CP] Copy Pods Resources */,
968C3FBB62CE1E0E307ECBCE /* [CP] Embed Pods Frameworks */,
CC3E3923FDE40035D0CA6762 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -273,24 +273,7 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
81DE7C26F41956799E954FCE /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
8372B02399CDF54531650AD4 /* [CP] Embed Pods Frameworks */ = {
968C3FBB62CE1E0E307ECBCE /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -322,7 +305,24 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
BFED6CCFE59BB148875A533B /* [CP] Check Pods Manifest.lock */ = {
CC3E3923FDE40035D0CA6762 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
E3E41B3FF6C30233949963A9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (

@ -9,7 +9,6 @@ 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/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:http/http.dart' as http;
@ -80,14 +79,11 @@ abstract class ApiClient {
class ApiClientImp implements ApiClient {
final _analytics = getIt<GAnalytics>();
final LoggerService _loggerService;
final AppState _appState;
ApiClientImp({
required LoggerService loggerService,
required AppState appState,
}) : _appState = appState,
_loggerService = loggerService;
}) : _appState = appState;
@override
post(
@ -177,7 +173,7 @@ class ApiClientImp implements ApiClient {
}
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 3628599;
// body['PatientID'] = 4767477;
}
body.removeWhere((key, value) => value == null);
@ -200,7 +196,6 @@ class ApiClientImp implements ApiClient {
final int statusCode = response.statusCode;
log("response.body: ${response.body}");
if (statusCode < 200 || statusCode >= 400) {
var parsed = json.decode(utf8.decode(response.bodyBytes));
onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data"));
logApiEndpointError(endPoint, 'Error While Fetching data', statusCode);
} else {
@ -218,6 +213,7 @@ class ApiClientImp implements ApiClient {
} else {
if (parsed['ErrorType'] == 4) {
//TODO : handle app update
onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, failureType: AppUpdateFailure("parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']"));
logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
}
if (parsed['ErrorType'] == 2) {
@ -225,9 +221,9 @@ class ApiClientImp implements ApiClient {
onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
statusCode,
failureType: MessageStatusFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']),
failureType: UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
);
// logApiEndpointError(endPoint, "session logged out", statusCode);
// logApiEndpointError(endPoint, "session logged out", statusCode);
}
if (isAllowAny) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
@ -248,6 +244,12 @@ class ApiClientImp implements ApiClient {
}
} else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['IsAuthenticated'] == false) {
onFailure(
"User is not Authenticated",
statusCode,
failureType: UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
);
} else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
@ -277,7 +279,6 @@ class ApiClientImp implements ApiClient {
logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
}
}
} else if (!parsed['IsAuthenticated']) {
} else {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);

@ -727,7 +727,7 @@ const FAMILY_FILES= 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatu
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

@ -134,6 +134,10 @@ class AppAssets {
static const String minus = '$svgBasePath/minus.svg';
static const String home_lab_result_icon = '$svgBasePath/home_lab_result_icon.svg';
static const String visa_mastercard_icon = '$svgBasePath/visa_mastercard.svg';
static const String small_livecare_icon = '$svgBasePath/small_livecare_icon.svg';
static const String walkin_appointment_icon = '$svgBasePath/walkin_appointment_icon.svg';
static const String cardiology_clinic_icon = '$svgBasePath/cardiology_clinic_icon.svg';
static const String generic_clinic_icon = '$svgBasePath/generic_clinic_icon.svg';
static const String lab_result_indicator = '$svgBasePath/refernce_range_indicator.svg';
static const String ic_date_filter = '$svgBasePath/ic_date_filter.svg';
static const String ic_list = '$svgBasePath/ic_list.svg';
@ -181,4 +185,5 @@ class AppAnimations {
static const String errorAnimation = '$lottieBasePath/ErrorAnimation.json';
static const String warningAnimation = '$lottieBasePath/warningAnimation.json';
static const String splashLaunching = '$lottieBasePath/splash_launching.json';
static const String noData = '$lottieBasePath/Nodata.json';
}

@ -6,7 +6,7 @@ class DataPoint {
final double value;
///label shown on the bottom of the graph
String label;
String refernceValue;
String referenceValue;
String actualValue;
DateTime time;
String displayTime;
@ -14,7 +14,7 @@ class DataPoint {
DataPoint(
{required this.value,
required this.label,
required this.refernceValue,
required this.referenceValue,
required this.actualValue,
required this.time,
required this.displayTime,

@ -77,7 +77,7 @@ class AppDependencies {
final sharedPreferences = await SharedPreferences.getInstance();
getIt.registerLazySingleton<CacheService>(() => CacheServiceImp(sharedPreferences: sharedPreferences, loggerService: getIt()));
getIt.registerLazySingleton<ApiClient>(() => ApiClientImp(loggerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<ApiClient>(() => ApiClientImp(appState: getIt()));
// Repositories
getIt.registerLazySingleton<CommonRepo>(() => CommonRepoImp(loggerService: getIt()));
@ -126,11 +126,7 @@ class AppDependencies {
);
getIt.registerLazySingleton<MyAppointmentsViewModel>(
() => MyAppointmentsViewModel(
myAppointmentsRepo: getIt(),
errorHandlerService: getIt(),
appState: getIt()
),
() => MyAppointmentsViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()),
);
getIt.registerLazySingleton<PayfortViewModel>(
@ -155,13 +151,7 @@ class AppDependencies {
);
getIt.registerLazySingleton<BookAppointmentsViewModel>(
() => BookAppointmentsViewModel(
bookAppointmentsRepo: getIt(),
errorHandlerService: getIt(),
navigationService: getIt(),
myAppointmentsViewModel: getIt(),
locationUtils: getIt()
),
() => BookAppointmentsViewModel(bookAppointmentsRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt(), myAppointmentsViewModel: getIt(), locationUtils: getIt()),
);
getIt.registerLazySingleton<AuthenticationViewModel>(

@ -7,7 +7,9 @@ abstract class Failure extends Equatable implements Exception {
}
class ServerFailure extends Failure {
const ServerFailure(super.message);
final String url;
const ServerFailure(super.message, {this.url = ""});
@override
List<Object?> get props => [message];
@ -27,6 +29,13 @@ class MessageStatusFailure extends Failure {
List<Object?> get props => [message];
}
class AppUpdateFailure extends Failure {
const AppUpdateFailure(super.message);
@override
List<Object?> get props => [message];
}
class StatusCodeFailure extends Failure {
const StatusCodeFailure(super.message);
@ -34,6 +43,15 @@ class StatusCodeFailure extends Failure {
List<Object?> get props => [message];
}
class UnAuthenticatedUserFailure extends Failure {
final String url;
const UnAuthenticatedUserFailure(super.message, {this.url = ""});
@override
List<Object?> get props => [message];
}
class ConnectivityFailure extends Failure {
const ConnectivityFailure(super.message);
@ -56,7 +74,9 @@ class DataParsingFailure extends Failure {
}
class UnknownFailure extends Failure {
const UnknownFailure(super.message);
final String url;
const UnknownFailure(super.message, {this.url = ""});
@override
List<Object?> get props => [message];

@ -2,11 +2,12 @@ import 'dart:math';
import 'package:hmg_patient_app_new/core/cache_consts.dart' show CacheConst;
import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils;
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' show RegionList, PatientDoctorAppointmentList, DoctorList, PatientDoctorAppointmentListByRegion;
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
class DoctorMapper{
static Future<RegionList> getMappedDoctor(List<DoctorList> doctorList,
static Future<RegionList> getMappedDoctor(List<DoctorsListResponseModel> doctorList,
{bool isArabic = false,double lat = 0.0,double long = 0.0}) async {
RegionList regionList = RegionList();
@ -41,16 +42,16 @@ class DoctorMapper{
isHMC: element.isHMC
);
if(element.projectDistanceInKiloMeters!= null ){
if(regionDoctorList!.distance>element.projectDistanceInKiloMeters){
regionDoctorList.distance = element.projectDistanceInKiloMeters;
if(regionDoctorList!.distance>element.projectDistanceInKiloMeters!){
regionDoctorList.distance = element.projectDistanceInKiloMeters!;
}
if (element.isHMC == true &&
element.projectDistanceInKiloMeters <
element.projectDistanceInKiloMeters! <
regionDoctorList.hmcDistance) {
regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters;
} else if (element.projectDistanceInKiloMeters <
regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters!;
} else if (element.projectDistanceInKiloMeters! <
regionDoctorList.hmgDistance) {
regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters;
regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters!;
}
}else
if (lat != 0&&
@ -65,12 +66,12 @@ class DoctorMapper{
regionDoctorList.distance = distance;
}
if (element.isHMC == true &&
element.projectDistanceInKiloMeters <
(element.projectDistanceInKiloMeters??0) <
regionDoctorList.hmcDistance) {
regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters;
} else if (element.projectDistanceInKiloMeters <
regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters??0;
} else if ((element.projectDistanceInKiloMeters??0) <
regionDoctorList.hmgDistance) {
regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters;
regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters??0;
}
}
targetList?.add(newAppointment);

@ -301,13 +301,17 @@ class Utils {
return false;
}
static Widget getNoDataWidget(BuildContext context, {String? errorText}) {
static Widget getNoDataWidget(BuildContext context, {double width = 124, double height = 124, String? noDataText, Widget callToActionButton = const SizedBox.shrink(), bool isSmallWidget = false}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SvgPicture.asset('assets/images/svg/not_found.svg', width: 150.0, height: 150.0),
(errorText ?? LocaleKeys.noDataAvailable.tr()).toText16(isCenter: true).paddingOnly(top: 15),
SizedBox(height: isSmallWidget ? 0.h : 48.h),
Lottie.asset(AppAnimations.noData, 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).paddingSymmetrical(64.h, 0.h),
SizedBox(height: 16.h),
callToActionButton
],
).center;
}

@ -1,16 +1,16 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:get_it/get_it.dart';
import 'package:hijri_gregorian_calendar/hijri_gregorian_calendar.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
import 'package:hmg_patient_app_new/core/common_models/privilege/HMCProjectListModel.dart';
import 'package:hmg_patient_app_new/core/common_models/privilege/PrivilegeModel.dart';
import 'package:hmg_patient_app_new/core/common_models/privilege/ProjectDetailListModel.dart';
import 'package:hmg_patient_app_new/core/common_models/privilege/VidaPlusProjectListModel.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
@ -19,7 +19,6 @@ import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/core/utils/request_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/extensions/context_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart';
import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_activation_code_register_request_model.dart';
@ -40,7 +39,6 @@ import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/localauth_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/bottomsheet/exception_bottom_sheet.dart';
import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart';
import 'models/request_models/get_user_mobile_device_data.dart';

@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_profile_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_livecare_clinics_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/services/logger_service.dart';
@ -45,6 +46,26 @@ abstract class BookAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList();
Future<Either<Failure, GenericApiModel<List<GetClinicsListResponseModel>>>> getClinicsWithRespectToClinicId(String projectID);
Future<Either<Failure, GenericApiModel<List<GetLiveCareClinicsResponseModel>>>> getLiveCareScheduleClinics(int age, int genderID);
Future<Either<Failure, GenericApiModel<List<DoctorsListResponseModel>>>> getLiveCareDoctorsList(int serviceID, int age, int genderID, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getLiveCareDoctorFreeSlots(int clinicID, int serviceID, int projectID, int doctorId, bool isBookingForLiveCare,
{Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> insertSpecificAppointmentForLiveCare(
{required int docID,
required int clinicID,
required int projectID,
required String selectedTime,
required String selectedDate,
required int initialSlotDuration,
required int genderID,
required int userAge,
required int serviceID,
Function(dynamic)? onSuccess,
Function(String)? onError});
}
class BookAppointmentsRepoImp implements BookAppointmentsRepo {
@ -443,4 +464,197 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<GetLiveCareClinicsResponseModel>>>> getLiveCareScheduleClinics(int age, int genderID) async {
Map<String, dynamic> mapDevice = {"Age": age, "Gender": genderID};
try {
GenericApiModel<List<GetLiveCareClinicsResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_LIVECARE_SCHEDULE_CLINICS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ClinicsHaveScheduleList'];
// if (list == null || list.isEmpty) {
// throw Exception("lab list is empty");
// }
final clinicsList = list.map((item) => GetLiveCareClinicsResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetLiveCareClinicsResponseModel>();
apiResponse = GenericApiModel<List<GetLiveCareClinicsResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: clinicsList,
);
} 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<DoctorsListResponseModel>>>> getLiveCareDoctorsList(int serviceID, int age, int genderID,
{Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"ServiceID": serviceID,
"Age": age,
"Gender": genderID,
};
try {
GenericApiModel<List<DoctorsListResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_LIVECARE_SCHEDULE_CLINIC_DOCTOR_LIST,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
onError!(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['DoctorByClinicIDList'];
final doctorsList = list.map((item) => DoctorsListResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<DoctorsListResponseModel>();
apiResponse = GenericApiModel<List<DoctorsListResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: doctorsList,
);
} 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>> getLiveCareDoctorFreeSlots(int clinicID, int serviceID, int projectID, int doctorId, bool isBookingForLiveCare,
{Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"DoctorID": doctorId,
"IsBookingForLiveCare": true,
"ClinicID": clinicID,
"ServiceID": serviceID,
"ProjectID": projectID,
"OriginalClinicID": clinicID,
"days": 50,
"isReschadual": false,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
GET_LIVECARE_SCHEDULE_DOCTOR_TIME_SLOTS,
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>> insertSpecificAppointmentForLiveCare(
{required int docID,
required int clinicID,
required int projectID,
required String selectedTime,
required String selectedDate,
required int initialSlotDuration,
required int genderID,
required int userAge,
required int serviceID,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"IsForLiveCare": true,
"ProjectID": projectID,
"ClinicID": clinicID,
"DoctorID": docID,
"ServiceID": serviceID,
"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_LIVECARE_SCHEDULE_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()));
}
}
}

@ -29,6 +29,8 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:location/location.dart' show Location;
import 'models/resp_models/get_livecare_clinics_response_model.dart';
class BookAppointmentsViewModel extends ChangeNotifier {
int selectedTabIndex = 0;
@ -37,6 +39,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool isDoctorProfileLoading = false;
bool isDoctorSearchByNameStarted = false;
bool isLiveCareSchedule = false;
int initialSlotDuration = 0;
LocationUtils locationUtils;
@ -44,12 +48,17 @@ class BookAppointmentsViewModel extends ChangeNotifier {
List<GetClinicsListResponseModel> clinicsList = [];
List<GetClinicsListResponseModel> _filteredClinicsList = [];
List<GetLiveCareClinicsResponseModel> liveCareClinicsList = [];
List<GetClinicsListResponseModel> get filteredClinicsList => _filteredClinicsList;
List<DoctorsListResponseModel> doctorsList = [];
List<DoctorsListResponseModel> liveCareDoctorsList = [];
GetClinicsListResponseModel selectedClinic = GetClinicsListResponseModel();
DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel();
GetLiveCareClinicsResponseModel selectedLiveCareClinic = GetLiveCareClinicsResponseModel();
late DoctorsProfileResponseModel doctorsProfileResponseModel;
@ -78,7 +87,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool shouldLoadSpecificClinic = false;
String? currentlySelectedHospitalFromRegionFlow;
BookAppointmentsViewModel({required this.bookAppointmentsRepo, required this.errorHandlerService, required this.navigationService, required this.myAppointmentsViewModel, required this.locationUtils}) {;
BookAppointmentsViewModel(
{required this.bookAppointmentsRepo, required this.errorHandlerService, required this.navigationService, required this.myAppointmentsViewModel, required this.locationUtils}) {
;
initBookAppointmentViewModel();
}
@ -101,8 +112,11 @@ class BookAppointmentsViewModel extends ChangeNotifier {
isClinicsListLoading = true;
isDoctorsListLoading = true;
isDoctorProfileLoading = true;
isLiveCareSchedule = false;
currentlySelectedHospitalFromRegionFlow = null;
clinicsList.clear();
doctorsList.clear();
liveCareClinicsList.clear();
// getLocation();
notifyListeners();
}
@ -154,6 +168,16 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
setIsLiveCareSchedule(bool value) {
isLiveCareSchedule = value;
notifyListeners();
}
setLiveCareSelectedClinic(GetLiveCareClinicsResponseModel clinic) {
selectedLiveCareClinic = clinic;
notifyListeners();
}
void onTabChanged(int index) {
selectedTabIndex = index;
notifyListeners();
@ -161,10 +185,11 @@ class BookAppointmentsViewModel extends ChangeNotifier {
/// this function will decide which clinic api to be called
/// either api for region flow or the select clinic api
Future<void> getClinics() async
{
if(shouldLoadSpecificClinic) {
Future<void> getClinics() async {
if (shouldLoadSpecificClinic) {
getRegionSelectedClinics();
} else if (isLiveCareSchedule) {
getLiveCareScheduleClinics();
} else {
getAllClinics();
}
@ -191,11 +216,58 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> getLiveCareScheduleClinics({Function(dynamic)? onSuccess, Function(String)? onError}) async {
liveCareClinicsList.clear();
final result = await bookAppointmentsRepo.getLiveCareScheduleClinics(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!);
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) {
liveCareClinicsList = apiResponse.data!;
isClinicsListLoading = false;
initializeFilteredList();
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getLiveCareDoctorsList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
doctorsList.clear();
final result =
await bookAppointmentsRepo.getLiveCareDoctorsList(selectedLiveCareClinic.serviceID!, _appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!, onError: onError);
result.fold(
(failure) async {
onError!("No doctors found for the search criteria".needTranslation);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
liveCareDoctorsList = apiResponse.data!;
isDoctorsListLoading = false;
// initializeFilteredList();
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
//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, String doctorName = "", isContinueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
doctorsList.clear();
projectID = currentlySelectedHospitalFromRegionFlow != null?int.parse(currentlySelectedHospitalFromRegionFlow!):projectID;
projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID;
final result = await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, isNearest, doctorId, doctorName);
result.fold(
@ -218,6 +290,42 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> getMappedDoctors(
{int projectID = 0, bool isNearest = false, int doctorId = 0, String doctorName = "", isContinueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
filteredHospitalList = null;
hospitalList = null;
isRegionListLoading = true;
notifyListeners();
projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID;
final result = await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, isNearest, doctorId, doctorName);
result.fold(
(failure) async {
onError!("No doctors found for the search criteria".needTranslation);
},
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
var doctorList = apiResponse.data!;
hospitalList = await DoctorMapper.getMappedDoctor(
doctorList,
isArabic: _appState.isArabic(),
lat: _appState.userLat,
long: _appState.userLong,
);
var isLocationEnabled = (_appState.userLat != 0) && (_appState.userLong != 0);
hospitalList = await DoctorMapper.sortList(isLocationEnabled, hospitalList!);
isRegionListLoading = false;
filteredHospitalList = hospitalList;
notifyListeners();
}
},
);
}
Future<void> getDoctorProfile({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.getDoctorProfile(selectedDoctor.clinicID ?? 0, selectedDoctor.projectID ?? 0, selectedDoctor.doctorID ?? 0, onError: onError);
@ -238,7 +346,6 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
//TODO: Handle the cases for LiveCare Schedule
Future<void> getDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear();
DateTime date;
@ -281,6 +388,50 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> getLiveCareDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear();
DateTime date;
final DateFormat formatter = DateFormat('HH:mm');
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map<DateTime, List> _eventsParsed;
final result = await bookAppointmentsRepo.getLiveCareDoctorFreeSlots(
selectedDoctor.clinicID ?? 0, selectedLiveCareClinic.serviceID ?? 0, selectedDoctor.projectID ?? 0, selectedDoctor.doctorID ?? 0, isBookingForLiveCare,
onError: onError);
result.fold(
(failure) async {
print(failure);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage ?? "Unknown error occurred");
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data['PatientER_DoctorFreeSlots'] == null || apiResponse.data['PatientER_DoctorFreeSlots'].isEmpty) {
onError!("No free slots available".tr());
return;
}
initialSlotDuration = apiResponse.data["InitialSlotDuration"];
freeSlotsResponse = apiResponse.data['PatientER_DoctorFreeSlots'];
freeSlotsResponse.forEach((element) {
// date = (isLiveCareSchedule != null && isLiveCareSchedule)
// ? DateUtil.convertStringToDate(element)
// :
date = DateUtil.convertStringToDateSaudiTimezone(element, int.parse(selectedDoctor.projectID.toString()));
slotsList.add(FreeSlot(date, ['slot']));
docFreeSlots.add(TimeSlot(isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date, vidaDate: element));
});
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel);
@ -300,18 +451,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
//TODO: Handle the cases for LiveCare Schedule, Dental & Laser Clinics
//TODO: Handle the cases for Dental & Laser Clinics
Future<void> insertSpecificAppointment(
{
// required int docID,
// required int clinicID,
// required int projectID,
// required String selectedTime,
// required String selectedDate,
// required int initialSlotDuration,
// required int genderID,
// required int userAge,
String? procedureID,
{String? procedureID,
num? testTypeEnum,
num? testProcedureEnum,
int? invoiceNumber,
@ -413,28 +555,123 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> insertSpecificAppointmentForLiveCare({Function(dynamic p1)? onSuccess, Function(dynamic p1)? onError}) async {
_appState = getIt<AppState>();
final result = await bookAppointmentsRepo.insertSpecificAppointmentForLiveCare(
docID: selectedDoctor.doctorID!,
clinicID: selectedDoctor.clinicID!,
projectID: selectedDoctor.projectID!,
serviceID: selectedLiveCareClinic.serviceID!,
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) {
// onError!(apiResponse);
LoadingUtils.hideFullScreenLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!,
child: Utils.getWarningWidget(
loadingText: apiResponse.data["ErrorEndUserMessage"],
isShowActionButtons: true,
onCancelTap: () {
navigationService.pop();
},
onConfirmTap: () async {
navigationService.pop();
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel = PatientAppointmentHistoryResponseModel(
appointmentNo: apiResponse.data["SameClinicApptList"][0]['AppointmentNo'],
clinicID: apiResponse.data["SameClinicApptList"][0]['ClinicID'],
projectID: apiResponse.data["SameClinicApptList"][0]['ProjectID'],
endDate: apiResponse.data["SameClinicApptList"][0]['EndTime'],
startTime: apiResponse.data["SameClinicApptList"][0]['StartTime'],
doctorID: apiResponse.data["SameClinicApptList"][0]['DoctorID'],
isLiveCareAppointment: apiResponse.data["SameClinicApptList"][0]['IsLiveCareAppointment'],
originalClinicID: 0,
originalProjectID: 0,
appointmentDate: apiResponse.data["SameClinicApptList"][0]['AppointmentDate'],
);
showCommonBottomSheet(navigationService.navigatorKey.currentContext!,
child: Utils.getLoadingWidget(loadingText: "Cancelling your previous appointment....".needTranslation),
callBackFunc: (str) {},
title: "",
height: ResponsiveExtension.screenHeight * 0.3,
isCloseButtonVisible: false,
isDismissible: false,
isFullScreen: false);
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
navigationService.pop();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
await insertSpecificAppointment(
onError: (err) {},
onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
await Future.delayed(Duration(milliseconds: 4000)).then((value) {
LoadingUtils.hideFullScreenLoader();
Navigator.pushAndRemoveUntil(
navigationService.navigatorKey.currentContext!,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
});
});
});
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data == null || apiResponse.data!.isEmpty) {
onError!("No free slots available".tr());
return;
}
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getRegionMappedProjectList() async {
isRegionListLoading = true;
notifyListeners();
final result = await bookAppointmentsRepo.getProjectList();
result.fold(
(failure) async =>
await errorHandlerService.handleError(failure: failure),
(apiResponse) async {
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
var projectList = apiResponse.data!;
hospitalList = await DoctorMapper.getMappedHospitals(projectList,
hospitalList = await DoctorMapper.getMappedHospitals(
projectList,
isArabic: _appState.isArabic(),
lat: _appState.userLat,
lng: _appState.userLong,
);
var isLocationEnabled = (_appState.userLat != 0) && (_appState.userLong != 0);
hospitalList =
await DoctorMapper.sortList(isLocationEnabled, hospitalList!);
hospitalList = await DoctorMapper.sortList(isLocationEnabled, hospitalList!);
isRegionListLoading = false;
filteredHospitalList = hospitalList;
@ -450,22 +687,21 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
void filterHospitalListByString(String? value, String? selectedRegionId, bool isHMG) {
if(value ==null || value.isEmpty){
if (value == null || value.isEmpty) {
filteredHospitalList = hospitalList;
} else {
filteredHospitalList = RegionList();
var list = isHMG
? hospitalList?.registeredDoctorMap![selectedRegionId]!.hmgDoctorList
: hospitalList?.registeredDoctorMap![selectedRegionId]!.hmcDoctorList;
var list = isHMG ? hospitalList?.registeredDoctorMap![selectedRegionId]!.hmgDoctorList : hospitalList?.registeredDoctorMap![selectedRegionId]!.hmcDoctorList;
if(list != null && list.isEmpty){ notifyListeners(); return;}
if (list != null && list.isEmpty) {
notifyListeners();
return;
}
var filteredList = list!.where((element) =>
element.filterName!.toLowerCase().contains(value.toLowerCase())
).toList();
var filteredList = list!.where((element) => element.filterName!.toLowerCase().contains(value.toLowerCase())).toList();
var regionData = PatientDoctorAppointmentListByRegion();
if(isHMG){
if (isHMG) {
regionData.hmgDoctorList = filteredList;
regionData.hmgSize = filteredList.length;
} else {
@ -473,9 +709,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
regionData.hmcSize = filteredList.length;
}
filteredHospitalList?.registeredDoctorMap = {
selectedRegionId! : regionData
};
filteredHospitalList?.registeredDoctorMap = {selectedRegionId!: regionData};
}
notifyListeners();
}
@ -498,12 +732,12 @@ class BookAppointmentsViewModel extends ChangeNotifier {
currentlySelectedHospitalFromRegionFlow = mainProjectID;
}
Future<void> getRegionSelectedClinics() async{
final result = await bookAppointmentsRepo.getClinicsWithRespectToClinicId(currentlySelectedHospitalFromRegionFlow??"");
Future<void> getRegionSelectedClinics() async {
final result = await bookAppointmentsRepo.getClinicsWithRespectToClinicId(currentlySelectedHospitalFromRegionFlow ?? "");
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
@ -515,12 +749,12 @@ class BookAppointmentsViewModel extends ChangeNotifier {
},
);
}
void resetFilterList(){
void resetFilterList() {
filteredHospitalList = hospitalList;
}
void getLocation(){
void getLocation() {
locationUtils.getLocation();
}
}

@ -59,6 +59,13 @@ class DoctorsListResponseModel {
int? virtualEmploymentType;
dynamic workingHours;
dynamic vida3Id;
String? region;
String? regionArabic;
String? regionEnglish;
String? regionID;
String? projectBottomName;
String? projectTopName;
DoctorsListResponseModel(
{this.clinicID,
@ -120,7 +127,13 @@ class DoctorsListResponseModel {
this.transactionType,
this.virtualEmploymentType,
this.workingHours,
this.vida3Id});
this.vida3Id,
this.region,
this.regionArabic,
this.regionEnglish,
this.regionID,
this.projectBottomName,
this.projectTopName,});
DoctorsListResponseModel.fromJson(Map<String, dynamic> json) {
clinicID = json['ClinicID'];
@ -183,6 +196,10 @@ class DoctorsListResponseModel {
virtualEmploymentType = json['VirtualEmploymentType'];
workingHours = json['WorkingHours'];
vida3Id = json['vida3Id'];
regionArabic = json['RegionNameN'];
regionEnglish = json['RegionName'];
projectBottomName = json['ProjectNameBottom'];
projectTopName = json['ProjectNameTop'];
}
Map<String, dynamic> toJson() {
@ -249,4 +266,21 @@ class DoctorsListResponseModel {
data['vida3Id'] = this.vida3Id;
return data;
}
String? getRegionName(bool isArabic) {
if (isArabic) {
return regionArabic;
}
return regionEnglish;
}
String getProjectCompleteName(){
return "${this.projectTopName} ${this.projectBottomName}";
}
String getProjectCompleteNameWithLocale({bool isArabic = false}) {
if (isArabic) {
return "${this.projectBottomName} ${this.projectTopName}";
}
return "${this.projectTopName} ${this.projectBottomName}";
}
}

@ -12,8 +12,8 @@ class GetClinicsListResponseModel {
GetClinicsListResponseModel.fromJson(Map<String, dynamic> json) {
clinicID = json['ClinicID'];
clinicDescription = json['ClinicDescription'];
clinicDescriptionN = json['ClinicDescriptionN'];
clinicDescription = json['ClinicDescription'] ?? "LiveCare Clinic";
clinicDescriptionN = json['ClinicDescriptionN'] ?? "LiveCare Clinic";
age = json['Age'];
gender = json['Gender'];
isLiveCareClinicAndOnline = json['IsLiveCareClinicAndOnline'];

@ -0,0 +1,33 @@
class GetLiveCareClinicsResponseModel {
int? clinicID;
int? serviceID;
int? projectID;
String? clinicDesc;
String? clinicDescN;
String? projectDesc;
String? projectDescN;
GetLiveCareClinicsResponseModel({this.clinicID, this.serviceID, this.projectID, this.clinicDesc, this.clinicDescN, this.projectDesc, this.projectDescN});
GetLiveCareClinicsResponseModel.fromJson(Map<String, dynamic> json) {
clinicID = json['ClinicID'];
serviceID = json['ServiceID'];
projectID = json['ProjectID'];
clinicDesc = json['ClinicDesc'] ?? "LiveCare Clinic";
clinicDescN = json['ClinicDescN'];
projectDesc = json['ProjectDesc'];
projectDescN = json['ProjectDescN'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ClinicID'] = this.clinicID;
data['ServiceID'] = this.serviceID;
data['ProjectID'] = this.projectID;
data['ClinicDesc'] = this.clinicDesc;
data['ClinicDescN'] = this.clinicDescN;
data['ProjectDesc'] = this.projectDesc;
data['ProjectDescN'] = this.projectDescN;
return data;
}
}

@ -1,4 +1,5 @@
import 'dart:core';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -52,7 +53,8 @@ class LabViewModel extends ChangeNotifier {
Set<TestDetails> uniqueTests = {};
double maxYForThreeDots = 0.0;
double maxY = 0.0;
double maxX = double.infinity;
LabViewModel(
{required this.labRepo,
@ -72,7 +74,12 @@ class LabViewModel extends ChangeNotifier {
final result = await labRepo.getPatientLabOrders();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {
isLabOrdersLoading = false;
isLabResultsLoading = false;
notifyListeners();
},
// => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
@ -136,6 +143,7 @@ class LabViewModel extends ChangeNotifier {
LoaderBottomSheet.showLoader();
mainLabResults.clear();
filteredGraphValues.clear();
maxY = double.negativeInfinity;
final result = await labRepo.getPatientLabResults(
laborder,
@ -160,16 +168,20 @@ class LabViewModel extends ChangeNotifier {
try {
var dateTime =
DateUtil.convertStringToDate(element.verifiedOnDateTime!);
if (double.parse(element.resultValue!) > maxYForThreeDots) {
maxYForThreeDots = double.parse(element.resultValue!);
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
if (resultValue>maxY) {
maxY = resultValue;
maxX = maxY;
}
filteredGraphValues.add(DataPoint(
value: transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??""),
value: transformedValue,
actualValue:element.resultValue!,
label: formatDateAsMMYY(dateTime),
displayTime: resultDate(dateTime),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
refernceValue: element.calculatedResultFlag ?? "",
referenceValue: element.calculatedResultFlag ?? "",
));
counter++;
@ -177,6 +189,7 @@ class LabViewModel extends ChangeNotifier {
});
LabResult recentResult = recentThree.first;
recentResult.verifiedOn = resultDate(DateUtil.convertStringToDate(recentResult.verifiedOnDateTime!));
// filteredGraphValues = [filteredGraphValues.first];
navigationService.push(MaterialPageRoute(
builder: (_) =>
LabResultDetails(recentLabResult: recentResult)));
@ -228,24 +241,32 @@ class LabViewModel extends ChangeNotifier {
final normalizedValue = clampedValue / 100.0; // Normalize input to 0-1
// Map the normalized value to the target range bounds
final transformedValue = rangeStart + (normalizedValue * (rangeEnd - rangeStart));
final transformedValue = rangeStart + ((normalizedValue * (rangeEnd - rangeStart)));
debugPrint("the actual value is $inputValue");
debugPrint("the flag is $flag");
debugPrint("the transformed value is $transformedValue");
return transformedValue;
}
void getSelectedDateRange(DateTime? start, DateTime? end) {
maxY = double.negativeInfinity;
if(start == null && end == null) {
print("the dates are null");
mainLabResults.forEach((element) {
final time = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
try{
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
if (resultValue > maxY) {
maxY = resultValue;
}
filteredGraphValues.add(DataPoint(
value: transformValueInRange(double.parse(element.resultValue!),
element.calculatedResultFlag ?? ""),
value: transformedValue,
actualValue: element.resultValue!,
label: formatDateAsMMYY(time),
displayTime: resultDate(time),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
refernceValue: element.calculatedResultFlag ?? "",
referenceValue: element.calculatedResultFlag ?? "",
));
}catch(e){
@ -259,33 +280,34 @@ class LabViewModel extends ChangeNotifier {
try {
var dateTime =
DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
if (resultValue > maxY) {
maxY = resultValue;
}
if (start != null && end == null) {
if (dateTime.isAtSameMomentAs(start)) {
filteredGraphValues.add(DataPoint(
value: transformValueInRange(
double.parse(element.resultValue!),
element.calculatedResultFlag ?? ""),
value: transformedValue,
actualValue: element.resultValue!,
label: formatDateAsMMYY(dateTime),
displayTime: resultDate(dateTime),
time:
DateUtil.convertStringToDate(element.verifiedOnDateTime),
refernceValue: element.calculatedResultFlag ?? ""));
referenceValue: element.calculatedResultFlag ?? ""));
}
} else if (start != null && end != null) {
if ((dateTime.isAfter(start)) && (dateTime.isBefore(end))) {
filteredGraphValues.add(DataPoint(
value: transformValueInRange(
double.parse(element.resultValue!),
element.calculatedResultFlag ?? ""),
value: transformedValue,
actualValue: element.resultValue!,
label: formatDateAsMMYY(dateTime),
displayTime: resultDate(dateTime),
time:
DateUtil.convertStringToDate(element.verifiedOnDateTime),
refernceValue: element.calculatedResultFlag ?? ""));
referenceValue: element.calculatedResultFlag ?? ""));
}
}
} catch (e) {}
@ -299,8 +321,7 @@ class LabViewModel extends ChangeNotifier {
String formatDateAsMMYY(DateTime date) {
String year = date.year.toString().substring(2);
return '${months[date.month-1]},$year';
return '${months[date.month-1]}, ${date.year}';
}

@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart' show ChangeNotifier;
import 'package:hmg_patient_app_new/core/app_state.dart' show AppState;
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_doctor_page.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
@ -14,6 +15,11 @@ enum AppointmentViaRegionState {
DOCTOR_SELECTION
}
enum RegionBottomSheetType{
FOR_REGION,
FOR_CLINIIC
}
class AppointmentViaRegionViewmodel extends ChangeNotifier {
String? selectedRegionId;
String? selectedFacilityType;
@ -23,6 +29,8 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
AppointmentViaRegionState.REGION_SELECTION;
final AppState appState;
RegionBottomSheetType regionBottomSheetType = RegionBottomSheetType.FOR_REGION;
AppointmentViaRegionViewmodel({required this.navigationService,required this.appState});
void setSelectedRegionId(String? regionId) {
@ -35,15 +43,20 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
notifyListeners();
}
void setBottomSheetType(RegionBottomSheetType type) {
regionBottomSheetType = type;
notifyListeners();
}
void setBottomSheetState(AppointmentViaRegionState state) {
bottomSheetState = state;
notifyListeners();
}
void handleLastStep(){
void handleLastStepForRegion(){
navigationService.pop();
navigationService.push(CustomPageRoute(
page: SelectClinicPage(),
page: SelectClinicPage(isFromRegionFlow: true,),
),);
}
@ -65,6 +78,7 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
void flush() {
setSelectedRegionId(null);
setFacility(null);
setBottomSheetType(RegionBottomSheetType.FOR_REGION);
setBottomSheetState(AppointmentViaRegionState.REGION_SELECTION);
}
@ -73,4 +87,11 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
}
bool get isArabic => appState.isArabic();
void handleLastStepForClinic() {
navigationService.pop();
navigationService.push(CustomPageRoute(
page: SelectDoctorPage(),
),);
}
}

@ -1,4 +1,5 @@
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
class DoctorList {
@ -236,7 +237,7 @@ class DoctorList {
class PatientDoctorAppointmentList {
String? filterName = "";
String? distanceInKMs = "";
List<DoctorList>? patientDoctorAppointmentList = [];
List<DoctorsListResponseModel>? patientDoctorAppointmentList = [];
String? projectTopName = "";
String? projectBottomName = "";
bool? isHMC;
@ -247,7 +248,7 @@ class PatientDoctorAppointmentList {
this.distanceInKMs,
this.projectTopName,
this.projectBottomName,
DoctorList? patientDoctorAppointment,
DoctorsListResponseModel? patientDoctorAppointment,
HospitalsModel? model,
this.isHMC = false}) {
if (model != null) {

@ -1,10 +1,13 @@
import 'dart:io';
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/cache_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/hospital_model.dart'
show HospitalsModel;
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
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';
@ -12,7 +15,8 @@ import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointments({required bool isActiveAppointment, required bool isArrivedAppointments});
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareAppointment({required int projectID, required int clinicID, required String appointmentNo});
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareAppointment(
{required int projectID, required int clinicID, required String appointmentNo, required bool isLiveCareAppointment});
Future<Either<Failure, GenericApiModel<dynamic>>> createAdvancePayment(
{required String paymentMethodName,
@ -39,7 +43,7 @@ abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientDoctorsList();
Future<Either<Failure, GenericApiModel<dynamic>>> insertLiveCareVIDARequest({required clientRequestID, required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel});
}
class MyAppointmentsRepoImp implements MyAppointmentsRepo {
@ -99,14 +103,15 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
}
@override
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareAppointment({required int projectID, required int clinicID, required String appointmentNo}) async {
Map<String, dynamic> mapRequest = {"ProjectID": projectID, "ClinicID": clinicID, "AppointmentNo": appointmentNo, "IsActiveAppointment": true};
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareAppointment(
{required int projectID, required int clinicID, required String appointmentNo, required bool isLiveCareAppointment}) async {
Map<String, dynamic> mapRequest = {"ProjectID": projectID, "ClinicID": clinicID, "AppointmentNo": appointmentNo, "IsActiveAppointment": true, "IsForLiveCare": isLiveCareAppointment};
try {
GenericApiModel<PatientAppointmentShareResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_SHARE,
isLiveCareAppointment ? GET_PATIENT_SHARE_LIVECARE : GET_PATIENT_SHARE,
body: mapRequest,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
@ -495,4 +500,50 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> insertLiveCareVIDARequest({required clientRequestID, required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}) async {
Map<String, dynamic> requestBody = {
"AppointmentNo": patientAppointmentHistoryResponseModel.appointmentNo,
"AppointmentDate": patientAppointmentHistoryResponseModel.appointmentDate,
"ClientRequestID": clientRequestID,
"ClinicID": patientAppointmentHistoryResponseModel.clinicID,
"ProjectID": patientAppointmentHistoryResponseModel.projectID,
"ServiceID": patientAppointmentHistoryResponseModel.serviceID,
"AcceptedBy": patientAppointmentHistoryResponseModel.doctorID,
"IsFlutter": true,
"DeviceToken": await Utils.getStringFromPrefs(CacheConst.pushToken),
"VoipToken": "", // TODO: Add VoIP Token functionality
"IsVoip": Platform.isIOS ? true : false
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
INSERT_VIDA_REQUEST,
body: requestBody,
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()));
}
}
}

@ -19,6 +19,8 @@ class MyAppointmentsViewModel extends ChangeNotifier {
bool isTimeLineAppointmentsLoading = false;
bool isPatientMyDoctorsLoading = false;
bool isAppointmentDataToBeLoaded = true;
List<PatientAppointmentHistoryResponseModel> patientAppointmentsHistoryList = [];
List<PatientAppointmentHistoryResponseModel> patientUpcomingAppointmentsHistoryList = [];
@ -38,15 +40,17 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
initAppointmentsViewModel() {
patientAppointmentsHistoryList.clear();
patientUpcomingAppointmentsHistoryList.clear();
patientArrivedAppointmentsHistoryList.clear();
patientTimelineAppointmentsList.clear();
patientMyDoctorsList.clear();
isMyAppointmentsLoading = true;
if (isAppointmentDataToBeLoaded) {
patientAppointmentsHistoryList.clear();
patientUpcomingAppointmentsHistoryList.clear();
patientArrivedAppointmentsHistoryList.clear();
patientTimelineAppointmentsList.clear();
isMyAppointmentsLoading = true;
isTimeLineAppointmentsLoading = true;
patientMyDoctorsList.clear();
isPatientMyDoctorsLoading = true;
}
isAppointmentPatientShareLoading = true;
isTimeLineAppointmentsLoading = true;
isPatientMyDoctorsLoading = true;
notifyListeners();
}
@ -70,6 +74,11 @@ class MyAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
setIsAppointmentDataToBeLoaded(bool val) {
isAppointmentDataToBeLoaded = val;
notifyListeners();
}
setAppointmentReminder(bool value, PatientAppointmentHistoryResponseModel item) {
int index = patientAppointmentsHistoryList.indexOf(item);
if (index != -1) {
@ -79,6 +88,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getPatientAppointments(bool isActiveAppointment, bool isArrivedAppointments, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isAppointmentDataToBeLoaded) return;
patientAppointmentsHistoryList.clear();
patientUpcomingAppointmentsHistoryList.clear();
@ -95,6 +105,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) {
patientUpcomingAppointmentsHistoryList = apiResponse.data!;
isMyAppointmentsLoading = false;
isAppointmentDataToBeLoaded = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
@ -127,8 +138,8 @@ class MyAppointmentsViewModel extends ChangeNotifier {
print('All Appointments: ${patientAppointmentsHistoryList.length}');
}
Future<void> getPatientShareAppointment(int projectID, int clinicID, String appointmentNo, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.getPatientShareAppointment(projectID: projectID, clinicID: clinicID, appointmentNo: appointmentNo);
Future<void> getPatientShareAppointment(int projectID, int clinicID, String appointmentNo, bool isLiveCareAppointment, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.getPatientShareAppointment(projectID: projectID, clinicID: clinicID, appointmentNo: appointmentNo, isLiveCareAppointment: isLiveCareAppointment);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
@ -284,6 +295,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getPatientMyDoctors({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isAppointmentDataToBeLoaded) return;
final result = await myAppointmentsRepo.getPatientDoctorsList();
result.fold(
@ -305,4 +317,24 @@ class MyAppointmentsViewModel extends ChangeNotifier {
},
);
}
Future<void> insertLiveCareVIDARequest(
{required clientRequestID, required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.insertLiveCareVIDARequest(clientRequestID: clientRequestID, patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -71,6 +71,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {
isPrescriptionsOrdersLoading = false;
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {

@ -22,7 +22,7 @@ import 'package:hmg_patient_app_new/presentation/appointments/appointment_paymen
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@ -81,33 +81,11 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// "Appointment Details".needTranslation.toText20(isBold: true),
// if (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel))
// CustomButton(
// text: "Report".needTranslation,
// 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,
// iconSize: 16.h,
// icon: AppAssets.report_icon,
// iconColor: AppColors.primaryRedColor,
// )
// ],
// ),
// SizedBox(height: 24.h),
AppointmentDoctorCard(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onAskDoctorTap: () {},
onCancelTap: () async {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(),
callBackFunc: (str) {},
@ -162,42 +140,60 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
? "Not Confirmed".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
: "Confirmed".needTranslation.toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)),
SizedBox(height: 16.h),
Stack(
children: [
ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(24),
child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng",
fit: BoxFit.contain,
),
),
Positioned(
bottom: 0,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.785,
child: CustomButton(
text: "Get Directions".needTranslation,
onPressed: () {
MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName);
},
backgroundColor: AppColors.textColor.withOpacity(0.8),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: AppColors.whiteColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
icon: AppAssets.directions_icon,
iconColor: AppColors.whiteColor,
iconSize: 13.h,
).paddingAll(12.h),
//TODO Add countdown timer in case of LiveCare Appointment
widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false
? Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"The doctor will call you once the appointment time approaches."
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),
],
)
: Stack(
children: [
ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(24),
child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng",
fit: BoxFit.contain,
),
),
Positioned(
bottom: 0,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.785,
child: CustomButton(
text: "Get Directions".needTranslation,
onPressed: () {
MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName);
},
backgroundColor: AppColors.textColor.withOpacity(0.8),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: AppColors.whiteColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
icon: AppAssets.directions_icon,
iconColor: AppColors.whiteColor,
iconSize: 13.h,
).paddingAll(12.h),
),
),
],
),
),
],
),
],
),
),
@ -476,6 +472,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
: CustomButton(
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
onPressed: () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction);
},
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),

@ -21,15 +21,14 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/services/cache_service.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/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/in_app_browser/InAppBrowser.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.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';
import 'package:smooth_corner/smooth_corner.dart';
@ -61,6 +60,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false,
);
});
super.initState();
@ -361,8 +361,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
}
void checkPaymentStatus() async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
LoaderBottomSheet.showLoader();
await payfortViewModel.checkPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
@ -388,6 +387,21 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
onSuccess: (value) async {
if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
//TODO: Implement LiveCare Check-In API Call
await myAppointmentsViewModel.insertLiveCareVIDARequest(
clientRequestID: transID,
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
},
onError: (error) {});
} else {
await myAppointmentsViewModel.generateAppointmentQR(
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
@ -396,16 +410,16 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
Navigator.of(context).pop();
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
Navigator.of(context).push(
CustomPageRoute(page: MyAppointmentsPage()),
);
// Navigator.of(context).push(
// CustomPageRoute(page: MyAppointmentsPage()),
// );
});
});
}

@ -1,17 +1,23 @@
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_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:provider/provider.dart';
@ -116,7 +122,30 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
),
),
)
: Utils.getNoDataWidget(context);
: Utils.getNoDataWidget(
context,
noDataText: "You don't have any appointments yet.".needTranslation,
callToActionButton: CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: BookAppointmentPage(),
),
);
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40,
icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor,
).paddingSymmetrical(48.h, 0.h),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
@ -159,7 +188,30 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
),
),
)
: Utils.getNoDataWidget(context);
: Utils.getNoDataWidget(
context,
noDataText: "You don't have any appointments yet.".needTranslation,
callToActionButton: CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: BookAppointmentPage(),
),
);
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40,
icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor,
).paddingSymmetrical(48.h, 0.h),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
@ -202,7 +254,30 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
),
),
)
: Utils.getNoDataWidget(context);
: Utils.getNoDataWidget(
context,
noDataText: "You don't have any appointments yet.".needTranslation,
callToActionButton: CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: BookAppointmentPage(),
),
);
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40,
icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor,
).paddingSymmetrical(48.h, 0.h),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
@ -213,3 +288,4 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
}
}
}

@ -10,7 +10,7 @@ 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/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';

@ -18,6 +18,7 @@ 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:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:smooth_corner/smooth_corner.dart';
class AppointmentCard extends StatefulWidget {
AppointmentCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel, this.isLoading = false, this.isFromHomePage = false});
@ -63,44 +64,38 @@ class _AppointmentCardState extends State<AppointmentCard> {
spacing: 6.h,
runSpacing: 6.h,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: widget.isLoading
? "OutPatient"
: 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: widget.isLoading ? "Booked" : 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,
),
],
),
AppCustomChipWidget(
icon: widget.isLoading
? AppAssets.walkin_appointment_icon
: (!widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon),
iconColor: widget.isLoading
? AppColors.textColor
: !widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!
? AppColors.textColor
: AppColors.whiteColor,
labelText: widget.isLoading
? "Walk In"
: widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!
? LocaleKeys.livecare.tr(context: context)
: "Walk In".needTranslation,
backgroundColor:
widget.isLoading ? AppColors.greyColor : (!widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor),
textColor: widget.isLoading ? AppColors.textColor : (!widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor),
).toShimmer2(isShow: widget.isLoading),
AppCustomChipWidget(
labelText: widget.isLoading
? "OutPatient"
: appState.isArabic()
? widget.patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN!
: widget.patientAppointmentHistoryResponseModel.isInOutPatientDescription!,
backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
textColor: AppColors.primaryRedColor,
).toShimmer2(isShow: widget.isLoading),
AppCustomChipWidget(
labelText: widget.isLoading ? "Booked" : AppointmentType.getAppointmentStatusType(widget.patientAppointmentHistoryResponseModel.patientStatusType!),
backgroundColor: AppColors.successColor.withOpacity(0.1),
textColor: AppColors.successColor,
).toShimmer2(isShow: widget.isLoading),
],
).toShimmer2(isShow: widget.isLoading),
),

@ -59,6 +59,13 @@ class AppointmentDoctorCard extends StatelessWidget {
icon: AppAssets.doctor_calendar_icon,
labelText:
"${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}, ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}"),
AppCustomChipWidget(
icon: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon,
iconColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor,
labelText: patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? LocaleKeys.livecare.tr(context: context) : "Walk In".needTranslation,
backgroundColor: !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}"),
],
),
@ -113,29 +120,8 @@ class AppointmentDoctorCard extends StatelessWidget {
iconSize: 16.h,
);
} 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(
return patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false
? CustomButton(
text: LocaleKeys.cancel.tr(),
onPressed: () {
onCancelTap();
@ -150,10 +136,48 @@ class AppointmentDoctorCard extends StatelessWidget {
icon: AppAssets.cancel,
iconColor: AppColors.whiteColor,
iconSize: 16.h,
),
),
],
);
)
: 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,
),
),
],
);
}
}
}

@ -12,7 +12,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
@ -96,9 +96,16 @@ class HospitalBottomSheetBody extends StatelessWidget {
isLocationEnabled: appointmentsViewModel.isLocationEnabled(),
).onPress(() {
regionalViewModel.setHospitalModel(hospital);
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.CLINIC_SELECTION);
regionalViewModel.handleLastStep();
});},
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION) {
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.CLINIC_SELECTION);
regionalViewModel.handleLastStepForRegion();
}else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) {
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.DOCTOR_SELECTION);
regionalViewModel.handleLastStepForClinic();
}
});},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),

@ -6,14 +6,11 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils;
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'
show MyAppointmentsViewModel;
import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart'
show RegionListItem;
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart' show MyAppointmentsViewModel;
import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart' show RegionListItem;
import 'package:provider/provider.dart';
class RegionBottomSheetBody extends StatefulWidget {
const RegionBottomSheetBody({super.key});
@override
@ -27,7 +24,11 @@ class _RegionBottomSheetBodyState extends State<RegionBottomSheetBody> {
@override
void initState() {
scheduleMicrotask(() {
myAppointmentsViewModel.getRegionMappedProjectList();
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION) {
myAppointmentsViewModel.getRegionMappedProjectList();
} else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) {
myAppointmentsViewModel.getMappedDoctors();
}
});
super.initState();
}
@ -53,26 +54,19 @@ class _RegionBottomSheetBodyState extends State<RegionBottomSheetBody> {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.5,
child: ListView.separated(
itemCount:
myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ??
0,
itemCount: myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? 0,
separatorBuilder: (_, __) {
return SizedBox(
height: 16.h,
);
},
itemBuilder: (_, index) {
String key = myAppointmentsVM
.hospitalList?.registeredDoctorMap?.keys
.toList()[index] ??
'';
String key = myAppointmentsVM.hospitalList?.registeredDoctorMap?.keys.toList()[index] ?? '';
return RegionListItem(
title: key,
subTitle: "",
hmcCount:
"${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}",
hmgCount:
"${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}",
hmcCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}",
hmgCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}",
).onPress(() {
regionalViewModel.setSelectedRegionId(key);
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.TYPE_SELECTION);

@ -17,7 +17,7 @@ import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_s
import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart' show RegionBottomSheetBody;
import 'package:hmg_patient_app_new/presentation/book_appointment/search_doctor_by_name.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart' show showCommonBottomSheetWithoutHeight;
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
@ -42,6 +42,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
@override
void initState() {
scheduleMicrotask(() {
bookAppointmentsViewModel.selectedTabIndex = 0;
bookAppointmentsViewModel.initBookAppointmentViewModel();
bookAppointmentsViewModel.getLocation();
});
@ -57,7 +58,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.bookAppo.tr(context: context),
isLeading: Navigator.canPop(context),
isLeading: Navigator.of(context).canPop(),
child: SingleChildScrollView(
child: Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Column(
@ -123,6 +124,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
bookAppointmentsViewModel.setLoadSpecificClinic(false);
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
bookAppointmentsViewModel.setProjectID(null);
Navigator.of(context).push(
CustomPageRoute(
@ -154,6 +156,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
],
).onPress(() {
bookAppointmentsViewModel.setIsDoctorSearchByNameStarted(false);
bookAppointmentsViewModel.setProjectID(null);
Navigator.of(context).push(
CustomPageRoute(
page: SearchDoctorByName(),
@ -183,7 +186,114 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h)),
],
).onPress(() {
openRegionListBottomSheet(context);
bookAppointmentsViewModel.setProjectID(null);
openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION);
}),
],
),
),
),
],
).paddingSymmetrical(24.h, 0.h);
case 1:
//TODO: Get LiveCare type Select UI from Hussain
return Column(
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_clinic_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Immediate Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h)),
],
).onPress(() {
// bookAppointmentsViewModel.setIsClinicsListLoading(true);
// bookAppointmentsViewModel.setLoadSpecificClinic(false);
// bookAppointmentsViewModel.setProjectID(null);
// Navigator.of(context).push(
// CustomPageRoute(
// page: SelectClinicPage(),
// ),
// );
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_doctor_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Scheduled Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
bookAppointmentsViewModel.setIsLiveCareSchedule(true);
Navigator.of(context).push(
CustomPageRoute(
page: SelectClinicPage(),
),
);
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Pharma LiveCare".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h)),
],
).onPress(() {
openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION);
}),
],
),
@ -197,14 +307,11 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
return Container();
}
void openRegionListBottomSheet(BuildContext context) {
void openRegionListBottomSheet(BuildContext context, RegionBottomSheetType type) {
regionalViewModel.flush();
regionalViewModel.setBottomSheetType(type);
// AppointmentViaRegionViewmodel? viewmodel = null;
showCommonBottomSheetWithoutHeight(context,
title: "",
titleWidget: Consumer<AppointmentViaRegionViewmodel>(
builder: (_, data, __) => getTitle(data)),
isDismissible: false,
showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
return getRegionalSelectionWidget(data);
}), callBackFunc: () {});
@ -238,19 +345,16 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
if (data.selectedRegionId == null) {
return LocaleKeys.selectRegion.tr().toText20(weight: FontWeight.w600);
} else {
return
Transform.flip(
flipX: data.isArabic ? true : false,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
data.handleBackPress();
});
return Transform.flip(
flipX: data.isArabic ? true : false,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
data.handleBackPress();
});
}
}
}

@ -14,7 +14,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/chip/app_custom_chip_widget.dart';
@ -115,29 +115,53 @@ class DoctorProfilePage extends StatelessWidget {
text: "View available appointments".needTranslation,
onPressed: () async {
LoaderBottomSheet.showLoader();
await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation,
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
bookAppointmentsViewModel.isLiveCareSchedule
? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots(
isBookingForLiveCare: true,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation,
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
})
: await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation,
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,

@ -10,14 +10,14 @@ 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/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_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';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
class ReviewAppointmentPage extends StatefulWidget {
@ -31,10 +31,12 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
late AppState appState;
late BookAppointmentsViewModel bookAppointmentsViewModel;
late AuthenticationViewModel authVM;
late MyAppointmentsViewModel myAppointmentsViewModel;
@override
Widget build(BuildContext context) {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context, listen: false);
authVM = Provider.of<AuthenticationViewModel>(context, listen: false);
appState = getIt.get<AppState>();
return Scaffold(
@ -203,35 +205,48 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
void initiateBookAppointment() async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
await bookAppointmentsViewModel.insertSpecificAppointment(onError: (err) {
print(err.data["ErrorEndUserMessage"]);
LoadingUtils.hideFullScreenLoader();
}, onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
await Future.delayed(Duration(milliseconds: 4000)).then((value) {
LoadingUtils.hideFullScreenLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
if (bookAppointmentsViewModel.isLiveCareSchedule) {
await bookAppointmentsViewModel.insertSpecificAppointmentForLiveCare(onError: (err) {
print(err.data["ErrorEndUserMessage"]);
LoadingUtils.hideFullScreenLoader();
}, onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
await Future.delayed(Duration(milliseconds: 4000)).then((value) {
LoadingUtils.hideFullScreenLoader();
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
});
});
});
// await Future.delayed(Duration(milliseconds: 4000)).then((value) async {
// LoadingUtils.hideFullScreenLoader();
// await Future.delayed(Duration(milliseconds: 50)).then((value) async {
// LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
// await Future.delayed(Duration(milliseconds: 4000)).then((value) {
// LoadingUtils.hideFullScreenLoader();
// });
// });
// });
} else {
await bookAppointmentsViewModel.insertSpecificAppointment(onError: (err) {
print(err.data["ErrorEndUserMessage"]);
LoadingUtils.hideFullScreenLoader();
}, onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
await Future.delayed(Duration(milliseconds: 4000)).then((value) {
LoadingUtils.hideFullScreenLoader();
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
});
});
}
}
}

@ -12,7 +12,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/book_appointments
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/common_bottom_sheet.dart';

@ -12,19 +12,27 @@ 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/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_livecare_clinics_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_type_selection_widget.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_doctor_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_livecare_clinic_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/clinic_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
class SelectClinicPage extends StatefulWidget {
const SelectClinicPage({super.key});
bool isFromRegionFlow;
SelectClinicPage({super.key, this.isFromRegionFlow = false});
@override
State<SelectClinicPage> createState() => _SelectClinicPageState();
@ -33,7 +41,7 @@ class SelectClinicPage extends StatefulWidget {
class _SelectClinicPageState extends State<SelectClinicPage> {
TextEditingController searchEditingController = TextEditingController();
FocusNode textFocusNode = FocusNode();
late AppointmentViaRegionViewmodel regionalViewModel;
late AppState appState;
late BookAppointmentsViewModel bookAppointmentsViewModel;
@ -54,11 +62,12 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
@override
Widget build(BuildContext context) {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(context, listen: true);
appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.selectClinic.tr(context: context),
title: bookAppointmentsViewModel.isLiveCareSchedule ? "Select LiveCare Clinic".needTranslation : LocaleKeys.selectClinic.tr(context: context),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h),
@ -94,40 +103,83 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
horizontal: ResponsiveExtension(15).h,
),
),
ListView.separated(
padding: EdgeInsets.only(top: 24.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isClinicsListLoading ? 5 : bookAppointmentsVM.filteredClinicsList.length,
itemBuilder: (context, index) {
return bookAppointmentsVM.isClinicsListLoading
? ClinicCard(
clinicsListResponseModel: GetClinicsListResponseModel(),
isLoading: bookAppointmentsVM.isClinicsListLoading,
)
: 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,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: ClinicCard(
clinicsListResponseModel: bookAppointmentsVM.filteredClinicsList[index],
isLoading: bookAppointmentsVM.isClinicsListLoading,
).onPress(() {
onClinicSelected(bookAppointmentsVM.filteredClinicsList[index]);
}),
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
bookAppointmentsVM.isLiveCareSchedule
? ListView.separated(
padding: EdgeInsets.only(top: 24.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isClinicsListLoading ? 5 : bookAppointmentsVM.liveCareClinicsList.length,
itemBuilder: (context, index) {
return bookAppointmentsVM.isClinicsListLoading
? ClinicCard(
bookAppointmentsVM: bookAppointmentsVM,
liveCareClinicsResponseModel: GetLiveCareClinicsResponseModel(),
clinicsListResponseModel: GetClinicsListResponseModel(),
isLoading: bookAppointmentsVM.isClinicsListLoading,
)
: 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,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: ClinicCard(
bookAppointmentsVM: bookAppointmentsVM,
liveCareClinicsResponseModel: bookAppointmentsVM.liveCareClinicsList[index],
clinicsListResponseModel: GetClinicsListResponseModel(),
isLoading: bookAppointmentsVM.isClinicsListLoading,
).onPress(() {
onLiveCareClinicSelected(bookAppointmentsVM.liveCareClinicsList[index]);
}),
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
)
: ListView.separated(
padding: EdgeInsets.only(top: 24.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isClinicsListLoading ? 5 : bookAppointmentsVM.filteredClinicsList.length,
itemBuilder: (context, index) {
return bookAppointmentsVM.isClinicsListLoading
? ClinicCard(
bookAppointmentsVM: bookAppointmentsVM,
liveCareClinicsResponseModel: GetLiveCareClinicsResponseModel(),
clinicsListResponseModel: GetClinicsListResponseModel(),
isLoading: bookAppointmentsVM.isClinicsListLoading,
)
: 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,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: ClinicCard(
bookAppointmentsVM: bookAppointmentsVM,
liveCareClinicsResponseModel: GetLiveCareClinicsResponseModel(),
clinicsListResponseModel: bookAppointmentsVM.filteredClinicsList[index],
isLoading: bookAppointmentsVM.isClinicsListLoading,
).onPress(() {
onClinicSelected(bookAppointmentsVM.filteredClinicsList[index]);
}),
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
],
);
}),
@ -137,21 +189,92 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
);
}
void onLiveCareClinicSelected(GetLiveCareClinicsResponseModel clinic) {
bookAppointmentsViewModel.setLiveCareSelectedClinic(clinic);
bookAppointmentsViewModel.setIsDoctorsListLoading(true);
Navigator.of(context).push(
CustomPageRoute(
page: SelectDoctorPage(),
),
);
}
void onClinicSelected(GetClinicsListResponseModel clinic) {
bookAppointmentsViewModel.setSelectedClinic(clinic);
bookAppointmentsViewModel.setIsDoctorsListLoading(true);
if (clinic.isLiveCareClinicAndOnline ?? false) {
Navigator.of(context).push(
CustomPageRoute(
page: SelectLivecareClinicPage(),
page: SelectLivecareClinicPage(onNegativeClicked: (){
handleDoctorScreen();
},),
),
);
} else {
handleDoctorScreen();
}
}
void handleDoctorScreen() {
if (widget.isFromRegionFlow) {
Navigator.of(context).push(
CustomPageRoute(
page: SelectDoctorPage(),
),
);
} else {
openRegionListBottomSheet(context, RegionBottomSheetType.FOR_CLINIIC);
}
}
void openRegionListBottomSheet(BuildContext context, RegionBottomSheetType type) {
bookAppointmentsViewModel.setProjectID(null);
regionalViewModel.flush();
regionalViewModel.setBottomSheetType(type);
// AppointmentViaRegionViewmodel? viewmodel = null;
showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
return getRegionalSelectionWidget(data);
}), callBackFunc: () {});
}
Widget getRegionalSelectionWidget(AppointmentViaRegionViewmodel data) {
if (data.bottomSheetState == AppointmentViaRegionState.REGION_SELECTION) {
return RegionBottomSheetBody();
}
if (data.bottomSheetState == AppointmentViaRegionState.TYPE_SELECTION) {
bookAppointmentsViewModel.resetFilterList();
return FacilityTypeSelectionWidget(
selectedRegion: data.selectedRegionId ?? "",
);
}
if (data.bottomSheetState == AppointmentViaRegionState.HOSPITAL_SELECTION) {
return HospitalBottomSheetBody();
}
if(data.bottomSheetState == AppointmentViaRegionState.DOCTOR_SELECTION){
bookAppointmentsViewModel.setProjectID(regionalViewModel.selectedHospital?.patientDoctorAppointmentList?.first.projectID.toString());
}
else {
return SizedBox.shrink();
}
return SizedBox.shrink();
}
getTitle(AppointmentViaRegionViewmodel data) {
if (data.selectedRegionId == null) {
return LocaleKeys.selectRegion.tr().toText20(weight: FontWeight.w600);
} else {
return Transform.flip(
flipX: data.isArabic ? true : false,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
data.handleBackPress();
});
}
}
}

@ -15,7 +15,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/resp_model
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
@ -42,7 +42,11 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
@override
void initState() {
scheduleMicrotask(() {
bookAppointmentsViewModel.getDoctorsList();
if (bookAppointmentsViewModel.isLiveCareSchedule) {
bookAppointmentsViewModel.getLiveCareDoctorsList();
} else {
bookAppointmentsViewModel.getDoctorsList();
}
});
super.initState();
}
@ -96,7 +100,8 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
padding: EdgeInsets.only(top: 24.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : bookAppointmentsVM.doctorsList.length,
itemCount:
bookAppointmentsVM.isDoctorsListLoading ? 5 : (bookAppointmentsVM.isLiveCareSchedule ? bookAppointmentsVM.liveCareDoctorsList.length : bookAppointmentsVM.doctorsList.length),
itemBuilder: (context, index) {
return bookAppointmentsVM.isDoctorsListLoading
? DoctorCard(
@ -115,11 +120,12 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
curve: Curves.easeInOut,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: DoctorCard(
doctorsListResponseModel: bookAppointmentsVM.doctorsList[index],
doctorsListResponseModel: bookAppointmentsVM.isLiveCareSchedule ? bookAppointmentsVM.liveCareDoctorsList[index] : bookAppointmentsVM.doctorsList[index],
isLoading: false,
bookAppointmentsViewModel: bookAppointmentsViewModel,
).onPress(() async {
bookAppointmentsVM.setSelectedDoctor(bookAppointmentsVM.doctorsList[index]);
bookAppointmentsVM
.setSelectedDoctor(bookAppointmentsVM.isLiveCareSchedule ? bookAppointmentsVM.liveCareDoctorsList[index] : bookAppointmentsVM.doctorsList[index]);
// bookAppointmentsVM.setSelectedDoctor(DoctorsListResponseModel());
LoaderBottomSheet.showLoader();
await bookAppointmentsVM.getDoctorProfile(onSuccess: (dynamic respData) {

@ -7,14 +7,16 @@ 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';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_doctor_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
class SelectLivecareClinicPage extends StatelessWidget {
const SelectLivecareClinicPage({super.key});
final VoidCallback? onNegativeClicked;
const SelectLivecareClinicPage({super.key, this.onNegativeClicked});
@override
Widget build(BuildContext context) {
@ -122,11 +124,12 @@ class SelectLivecareClinicPage extends StatelessWidget {
text: "No, Thanks. I would like a physical visit".needTranslation,
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).push(
CustomPageRoute(
page: SelectDoctorPage(),
),
);
onNegativeClicked?.call();
// Navigator.of(context).push(
// CustomPageRoute(
// page: SelectDoctorPage(),
// ),
// );
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,

@ -59,8 +59,8 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
@override
void initState() {
_calendarController = CalendarController();
scheduleMicrotask(() {
_calendarController = CalendarController();
_events = {
_selectedDay: ['Event A0']
};

@ -6,14 +6,18 @@ 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/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_livecare_clinics_response_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class ClinicCard extends StatelessWidget {
ClinicCard({super.key, required this.clinicsListResponseModel, required this.isLoading});
ClinicCard({super.key, required this.clinicsListResponseModel, required this.liveCareClinicsResponseModel, required this.isLoading, required this.bookAppointmentsVM});
GetClinicsListResponseModel clinicsListResponseModel;
GetLiveCareClinicsResponseModel liveCareClinicsResponseModel;
bool isLoading;
BookAppointmentsViewModel bookAppointmentsVM;
@override
Widget build(BuildContext context) {
@ -28,14 +32,17 @@ class ClinicCard extends StatelessWidget {
child: Column(
children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
"".toText16(isBold: true).toShimmer2(isShow: isLoading),
Utils.buildSvgWithAssets(icon: AppAssets.generic_clinic_icon, width: 24.h, height: 24.h, fit: BoxFit.contain).toShimmer2(isShow: isLoading),
(clinicsListResponseModel.isLiveCareClinicAndOnline ?? true)
? Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain).toShimmer2(isShow: isLoading)
: SizedBox.shrink(),
]),
SizedBox(height: 16.h),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Expanded(child: (isLoading ? "Cardiology" : clinicsListResponseModel.clinicDescription!).toText16(isBold: true).toShimmer2(isShow: isLoading)),
Expanded(
child: (isLoading ? "Cardiology" : (bookAppointmentsVM.isLiveCareSchedule ? liveCareClinicsResponseModel.clinicDesc! : clinicsListResponseModel.clinicDescription!))
.toText16(isBold: true)
.toShimmer2(isShow: isLoading)),
Transform.flip(
flipX: appState.isArabic() ? true : false,
child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor).toShimmer2(isShow: isLoading)),

@ -108,29 +108,53 @@ class DoctorCard extends StatelessWidget {
onPressed: () async {
bookAppointmentsViewModel.setSelectedDoctor(doctorsListResponseModel);
LoaderBottomSheet.showLoader();
await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation,
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
bookAppointmentsViewModel.isLiveCareSchedule
? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots(
isBookingForLiveCare: true,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation,
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
})
: await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation,
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),

@ -10,7 +10,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/routes/custom_page_route.dart';

@ -13,7 +13,7 @@ import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_mode
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/wallet_payment_confirm_page.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/widgets/select_hospital_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/common_bottom_sheet.dart';

@ -17,7 +17,7 @@ import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_mode
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';

@ -13,7 +13,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/widgets/hospital_list_item.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';

@ -180,7 +180,7 @@ class _LandingPageState extends State<LandingPage> {
),
);
}),
SizedBox(height: 12.h),
SizedBox(height: 16.h),
Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return myAppointmentsVM.isMyAppointmentsLoading
? Container(
@ -211,7 +211,7 @@ class _LandingPageState extends State<LandingPage> {
: 3,
layout: SwiperLayout.STACK,
loop: true,
itemWidth: MediaQuery.of(context).size.width - 72,
itemWidth: MediaQuery.of(context).size.width - 48.h,
indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right,
controller: _controller,
@ -289,49 +289,46 @@ class _LandingPageState extends State<LandingPage> {
),
);
}),
SizedBox(height: 12.h),
SizedBox(height: 16.h),
Container(
height: 127.h,
height: 120.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
children: [
Expanded(
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getLoggedInServiceCardsList.length,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 0, right: 8),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
icon: LandingPageData.getLoggedInServiceCardsList[index].icon,
title: LandingPageData.getLoggedInServiceCardsList[index].title,
subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle,
iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor,
textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor,
backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor,
isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold,
serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName,
),
child: Column(
children: [
Expanded(
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getLoggedInServiceCardsList.length,
shrinkWrap: true,
padding: EdgeInsets.only(left: 16.h, right: 16.h),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
icon: LandingPageData.getLoggedInServiceCardsList[index].icon,
title: LandingPageData.getLoggedInServiceCardsList[index].title,
subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle,
iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor,
textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor,
backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor,
isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold,
serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName,
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 0.width,
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 0.width,
),
],
),
),
],
),
).paddingSymmetrical(24.h, 0.h),
],
@ -342,41 +339,38 @@ class _LandingPageState extends State<LandingPage> {
color: AppColors.whiteColor,
borderRadius: 24,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
children: [
Expanded(
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getNotLoggedInServiceCardsList.length,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 0, right: 8),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon,
title: LandingPageData.getNotLoggedInServiceCardsList[index].title,
subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle,
iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor,
textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor,
backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor,
isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold,
),
child: Column(
children: [
Expanded(
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getNotLoggedInServiceCardsList.length,
shrinkWrap: true,
padding: EdgeInsets.only(left: 16.h, right: 16.h),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon,
title: LandingPageData.getNotLoggedInServiceCardsList[index].title,
subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle,
iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor,
textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor,
backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor,
isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold,
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 0.width,
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 0.width,
),
],
),
),
],
),
).paddingSymmetrical(24.h, 0.h),
Row(

@ -34,6 +34,7 @@ class _LandingNavigationState extends State<LandingNavigation> {
],
),
bottomNavigationBar: BottomNavigation(
context: context,
currentIndex: _currentIndex,
onTap: (index) {
setState(() => _currentIndex = index);

@ -39,7 +39,7 @@ class SmallServiceCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 3.h),
padding: EdgeInsets.symmetric(horizontal: 0.h, vertical: 12.h),
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: backgroundColor,

@ -9,7 +9,7 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/enums.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/lab/lab_range_view_model.dart';
@ -20,7 +21,7 @@ import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'collapsing_list_view.dart';
import '../../widgets/appbar/collapsing_list_view.dart';
class LabOrdersPage extends StatefulWidget {
const LabOrdersPage({super.key});
@ -37,6 +38,7 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
int? expandedIndex;
String? selectedFilterText = '';
int activeIndex = 0;
@override
void initState() {
scheduleMicrotask(() {
@ -90,10 +92,8 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
// CustomTabBarModel(null, "Completed".needTranslation),
],
onTabChange: (index) {
activeIndex = index;
setState(() {
});
activeIndex = index;
setState(() {});
},
),
SizedBox(height: 16.h),
@ -109,7 +109,11 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length,
itemCount: model.isLabOrdersLoading
? 5
: model.patientLabOrders.isNotEmpty
? model.patientLabOrders.length
: 1,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
@ -119,39 +123,42 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
index: index,
isLoading: true,
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabResultItemView(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
labOrder: model.patientLabOrders[index],
index: index,
isExpanded: isExpanded)),
),
);
: model.patientLabOrders.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabResultItemView(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
labOrder: model.patientLabOrders[index],
index: index,
isExpanded: isExpanded)),
),
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any lab results yet.".needTranslation);
},
)
: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading ? 5 :model.uniqueTests.toList().length,
itemCount: model.isLabOrdersLoading ? 5 : model.uniqueTests.toList().length,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
) : AnimationConfiguration.staggeredList(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
@ -173,7 +180,6 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
isExpanded: isExpanded)),
),
);
},
)
],

@ -1,26 +1,23 @@
import 'package:dartz/dartz.dart';
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/common_models/data_points.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/lab/history/lab_history_viewmodel.dart';
import 'package:hmg_patient_app_new/features/lab/lab_range_view_model.dart' show LabRangeViewModel;
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/lab_result.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_results/lab_result_calender.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_results/lab_result_list_item.dart';
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/graph/custom_graph.dart';
import 'package:provider/provider.dart' show Consumer, Provider;
import '../../../widgets/common_bottom_sheet.dart'
show showCommonBottomSheetWithoutHeight;
import '../../book_appointment/widgets/appointment_calendar.dart'
show AppointmentCalendar;
class LabResultDetails extends StatelessWidget {
final LabResult recentLabResult;
@ -62,6 +59,7 @@ class LabResultDetails extends StatelessWidget {
recentLabResult.testCode ?? "",
style: TextStyle(
fontSize: 32,
fontFamily: 'Poppins',
fontWeight: FontWeight.w600,
color: AppColors.textColor,
letterSpacing: -2),
@ -70,6 +68,7 @@ class LabResultDetails extends StatelessWidget {
"Result of ${recentLabResult.verifiedOn ?? ""}".needTranslation,
style: TextStyle(
fontSize: 12,
fontFamily: 'Poppins',
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
),
@ -91,6 +90,7 @@ class LabResultDetails extends StatelessWidget {
style: TextStyle(
fontSize: 24.fSize,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
color: model.getColor(
recentLabResult.calculatedResultFlag ?? "",
),
@ -108,6 +108,7 @@ class LabResultDetails extends StatelessWidget {
style: TextStyle(
fontSize: 12.fSize,
fontWeight: FontWeight.w500,
fontFamily: 'Poppins',
color: AppColors.greyTextColor,
),
overflow: TextOverflow.ellipsis,
@ -153,6 +154,8 @@ class LabResultDetails extends StatelessWidget {
model.isGraphVisible?"History FlowChart".needTranslation: "History".needTranslation,
style: TextStyle(
fontSize: 16,
fontFamily: 'Poppins',
fontWeight: FontWeight.w600,
color: AppColors.textColor,
),
@ -202,7 +205,7 @@ class LabResultDetails extends StatelessWidget {
return Text(
value,
style: TextStyle(
fontWeight: FontWeight.w300,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
fontSize: 8.fSize,
color: AppColors.textColor,
@ -226,26 +229,36 @@ class LabResultDetails extends StatelessWidget {
Widget historyBody(LabRangeViewModel model, LabViewModel labmodel) {
if(model.isGraphVisible){
var graphColor = labmodel.getColor(recentLabResult.calculatedResultFlag??"N");
return CustomGraph(
dataPoints: labmodel.filteredGraphValues,
maxY: 100,
// maxY: 100,
makeGraphBasedOnActualValue: true,
leftLabelReservedSize: 40,
leftLabelInterval: getInterval(labmodel),
maxY: (labmodel.maxY)+(getInterval(labmodel)??0)/2,
leftLabelFormatter: (value) {
switch (value.toInt()) {
case 20:
return leftLabels("Critical Low".needTranslation);
case 40:
return leftLabels("Low".needTranslation);
case 60:
return leftLabels("Normal".needTranslation);
case 80:
return leftLabels("High".needTranslation);
case 100:
return leftLabels(
"Critical High".needTranslation);
default:
return SizedBox.shrink();
}
return leftLabels(value.toStringAsFixed(2).tr());
// switch (value.toInt()) {
// case 10:
// return leftLabels("Critical Low".needTranslation);
// case 30:
// return leftLabels("Low".needTranslation);
// case 50:
// return leftLabels("Normal".needTranslation);
// case 70:
// return leftLabels("High".needTranslation);
// case 90:
// return leftLabels(
// "Critical High".needTranslation);
// default:
// return SizedBox.shrink();
// }
},
graphColor:graphColor ,
graphShadowColor: graphColor.withOpacity(.4),
graphGridColor: graphColor.withOpacity(.4),
bottomLabelFormatter: (value, data) {
if(data.isEmpty) return SizedBox.shrink();
if (value == 0) {
@ -259,6 +272,7 @@ class LabResultDetails extends StatelessWidget {
}
return SizedBox.shrink();
},
minX:(labmodel.filteredGraphValues.length == 1)?null : -.2,
scrollDirection: Axis.horizontal,
height: 180.h);
}else {
@ -276,8 +290,8 @@ class LabResultDetails extends StatelessWidget {
return LabHistoryItem(
dayNameAndDate: labmodel.getFormattedDate(data.time),
result: data.actualValue,
assetUrl: labmodel.getAssetUrlWRTResult(data.refernceValue),
shouldRotateIcon: labmodel.getRotationWRTResult(data.refernceValue),
assetUrl: labmodel.getAssetUrlWRTResult(data.referenceValue),
shouldRotateIcon: labmodel.getRotationWRTResult(data.referenceValue),
);
},
separatorBuilder: (_, __) => Divider(
@ -287,4 +301,14 @@ class LabResultDetails extends StatelessWidget {
),
);
}
double? getInterval(LabViewModel labmodel) {
var maxX = labmodel.maxY;
if(maxX >1 && maxX < 5) return 1;
if(maxX >5 && maxX < 10) return 5;
if(maxX >10 && maxX < 50) return 10;
if(maxX >50 && maxX < 100) return 20;
if(maxX >100 && maxX < 200) return 30;
return 50;
}
}

@ -4,7 +4,7 @@ import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/input_widget.dart';

@ -29,14 +29,14 @@ import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointme
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_reports_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves_list_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/vaccine_list_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_sick_leave_card.dart';
import 'package:hmg_patient_app_new/presentation/my_family/my_Family.dart';
import 'package:hmg_patient_app_new/presentation/my_family/my_family.dart';
import 'package:hmg_patient_app_new/presentation/my_family/widget/my_family_sheet.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -285,7 +285,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
}),
Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return SizedBox(
height: 200.h,
height: myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty ? 200.h : 175.h,
child: ListView.separated(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.only(top: 16.h, left: 24.h, right: 24.h, bottom: 0.h),
@ -478,7 +478,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontSize: 13,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
height: 40.h,
@ -495,7 +495,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontSize: 13,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
height: 40.h,
@ -510,7 +510,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
),
),
).paddingSymmetrical(24.h, 0.h)
: SizedBox.shrink();
: Utils.getNoDataWidget(context, noDataText: "You don't have any prescriptions yet.".needTranslation, isSmallWidget: true, width: 62, height: 62).paddingSymmetrical(24.h, 0.h);
}),
SizedBox(height: 24.h),
//My Doctor Section
@ -541,7 +541,11 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
height: 120.h,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: myAppointmentsVM.isPatientMyDoctorsLoading ? 5 : myAppointmentsVM.patientMyDoctorsList.length,
itemCount: myAppointmentsVM.isPatientMyDoctorsLoading
? 5
: myAppointmentsVM.patientMyDoctorsList.isNotEmpty
? myAppointmentsVM.patientMyDoctorsList.length
: 1,
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.h, right: 24.h),
itemBuilder: (context, index) {
@ -564,13 +568,14 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
],
),
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SizedBox(
: myAppointmentsVM.patientMyDoctorsList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SizedBox(
width: 80.h,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
@ -593,7 +598,9 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
),
),
),
);
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any completed visits yet.".needTranslation, isSmallWidget: true, width: 62, height: 62)
.paddingSymmetrical(24.h, 0.h);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 8.h),
),

@ -5,7 +5,7 @@ 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/features/medical_file/models/patient_medical_response_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_medical_report_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';

@ -4,11 +4,13 @@ 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/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/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';
@ -50,7 +52,11 @@ class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
children: [
ListView.separated(
scrollDirection: Axis.vertical,
itemCount: medicalFileVM.isPatientSickLeaveListLoading ? 3 : medicalFileVM.patientSickLeaveList.length,
itemCount: medicalFileVM.isPatientSickLeaveListLoading
? 3
: medicalFileVM.patientSickLeaveList.isNotEmpty
? medicalFileVM.patientSickLeaveList.length
: 1,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
@ -73,7 +79,7 @@ class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
),
),
)
: SizedBox.shrink();
: Utils.getNoDataWidget(context, noDataText: "You don't have any sick leaves yet.".needTranslation);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 8.h),
),

@ -8,7 +8,7 @@ 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/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';

@ -32,7 +32,7 @@ class LabRadCard extends StatelessWidget {
fit: BoxFit.contain,
).toShimmer2(isShow: false, radius: 12.h),
SizedBox(width: 8.h),
labelText.toText14(isBold: true).toShimmer2(isShow: false, radius: 6.h, height: 32.h),
labelText.toText13(isBold: true).toShimmer2(isShow: false, radius: 6.h, height: 32.h),
],
),
SizedBox(height: 16.h),

@ -110,15 +110,15 @@ class PatientMedicalReportCard extends StatelessWidget {
onPressed: () async {
getMedicalReportPDF(false, context, _appState);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
height: 40.h,
icon: AppAssets.download_1,
iconColor: AppColors.primaryRedColor,
iconColor: AppColors.whiteColor,
iconSize: 16.h,
).toShimmer2(isShow: isLoading),
),

@ -43,7 +43,7 @@ class PatientSickLeaveCard extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".toText16(isBold: true),
"${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".toText16(isBold: true).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: isLoading ? "" : getStatusText(context),
backgroundColor: getStatusColor().withOpacity(0.15),

@ -1,11 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
@ -15,7 +13,6 @@ import 'package:hmg_patient_app_new/features/medical_file/models/family_file_res
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/my_family/widget/family_cards.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -153,9 +150,9 @@ class _FamilyMedicalScreenState extends State<FamilyMedicalScreen> {
}
}
void showModelSheet() {
Future<void> showModelSheet() async {
AuthenticationViewModel authVm = getIt.get<AuthenticationViewModel>();
return showCommonBottomSheetWithoutHeight(context,
return await showCommonBottomSheetWithoutHeight(context,
title: "Add Family Member",
useSafeArea: true,
child: Column(

@ -1,15 +1,13 @@
import 'package:flutter/material.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/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/presentation/my_family/my_Family.dart';
import 'package:hmg_patient_app_new/presentation/my_family/widget/family_cards.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
class MyFamilySheet {
static void show(BuildContext context, List<FamilyFileResponseModelLists> familyLists, Function(FamilyFileResponseModelLists) onSelect) {
return showCommonBottomSheetWithoutHeight(
static Future<void> show(BuildContext context, List<FamilyFileResponseModelLists> familyLists, Function(FamilyFileResponseModelLists) onSelect) async {
return await showCommonBottomSheetWithoutHeight(
context,
titleWidget: Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -13,7 +13,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.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/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_item_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_reminder_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';

@ -13,7 +13,8 @@ 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/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -93,20 +94,30 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
SizedBox(height: 20.h),
// Expandable list
ListView.builder(
itemCount: model.isPrescriptionsOrdersLoading ? 4 : model.patientPrescriptionOrdersViewList.length,
itemCount: model.isPrescriptionsOrdersLoading
? 4
: model.patientPrescriptionOrders.isNotEmpty
? model.patientPrescriptionOrdersViewList.length
: 1,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.only(left: 0, right: 8),
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isPrescriptionsOrdersLoading
? const MoviesShimmerWidget()
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: model.patientPrescriptionOrders.isNotEmpty
? 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,
@ -290,7 +301,8 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
),
),
),
);
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any prescriptions yet.".needTranslation);
},
).paddingSymmetrical(24.h, 0.h),
],

@ -11,7 +11,7 @@ import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_mode
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/app_language_change.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';

@ -11,7 +11,8 @@ 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';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/radiology/radiology_result_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -61,130 +62,143 @@ class _RadiologyOrdersPageState extends State<RadiologyOrdersPage> {
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: model.isRadiologyOrdersLoading ? 5 : model.patientRadiologyOrders.length,
itemCount: model.isRadiologyOrdersLoading
? 5
: model.patientRadiologyOrders.isNotEmpty
? model.patientRadiologyOrders.length
: 1,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return 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: 20.h, hasShadow: true),
child: InkWell(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16.h),
return model.isRadiologyOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: model.patientRadiologyOrders.isNotEmpty
? 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: 20.h, hasShadow: true),
child: InkWell(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppCustomChipWidget(
labelText: LocaleKeys.resultsAvailable.tr(context: context),
backgroundColor: AppColors.successColor.withOpacity(0.15),
textColor: AppColors.successColor,
).toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 100),
SizedBox(height: 8.h),
Row(
children: [
Image.network(
model.isRadiologyOrdersLoading
? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png"
: model.patientRadiologyOrders[index].doctorImageURL!,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,
).circle(100).toShimmer2(isShow: model.isRadiologyOrdersLoading),
SizedBox(width: 4.h),
(model.isRadiologyOrdersLoading ? "Dr John Smith" : model.patientRadiologyOrders[index].doctorName!)
.toText16(isBold: true)
.toShimmer2(isShow: model.isRadiologyOrdersLoading)
],
),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
labelText: model.isRadiologyOrdersLoading ? "01 Jan 2025" : DateUtil.formatDateToDate(model.patientRadiologyOrders[index].orderDate!, false),
).toShimmer2(isShow: model.isRadiologyOrdersLoading),
AppCustomChipWidget(
labelText: model.isRadiologyOrdersLoading ? "01 Jan 2025" : model.patientRadiologyOrders[index].clinicDescription!,
).toShimmer2(isShow: model.isRadiologyOrdersLoading),
Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppCustomChipWidget(
labelText: LocaleKeys.resultsAvailable.tr(context: context),
backgroundColor: AppColors.successColor.withOpacity(0.15),
textColor: AppColors.successColor,
).toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 100),
SizedBox(height: 8.h),
Row(
children: [
Image.network(
model.isRadiologyOrdersLoading
? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png"
: model.patientRadiologyOrders[index].doctorImageURL!,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,
).circle(100).toShimmer2(isShow: model.isRadiologyOrdersLoading),
SizedBox(width: 4.h),
(model.isRadiologyOrdersLoading ? "Dr John Smith" : model.patientRadiologyOrders[index].doctorName!)
.toText16(isBold: true)
.toShimmer2(isShow: model.isRadiologyOrdersLoading)
],
),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
labelText: model.isRadiologyOrdersLoading ? "01 Jan 2025" : DateUtil.formatDateToDate(model.patientRadiologyOrders[index].orderDate!, false),
).toShimmer2(isShow: model.isRadiologyOrdersLoading),
AppCustomChipWidget(
labelText: model.isRadiologyOrdersLoading ? "01 Jan 2025" : model.patientRadiologyOrders[index].clinicDescription!,
).toShimmer2(isShow: model.isRadiologyOrdersLoading),
// AppCustomChipWidget(labelText: "").toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 16.h),
// AppCustomChipWidget(labelText: "").toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 16.h),
],
// AppCustomChipWidget(labelText: "").toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 16.h),
// AppCustomChipWidget(labelText: "").toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 16.h),
],
),
],
),
),
model.isRadiologyOrdersLoading
? SizedBox.shrink()
: AnimatedCrossFade(
firstChild: SizedBox.shrink(),
secondChild: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: '${model.patientRadiologyOrders[index].description}'.toText14(weight: FontWeight.w500),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(),
CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewReport.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: RadiologyResultPage(patientRadiologyResponseModel: model.patientRadiologyOrders[index]),
),
);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.bold,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
),
crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
duration: Duration(milliseconds: 300),
),
],
),
),
model.isRadiologyOrdersLoading
? SizedBox.shrink()
: AnimatedCrossFade(
firstChild: SizedBox.shrink(),
secondChild: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: '${model.patientRadiologyOrders[index].description}'.toText14(weight: FontWeight.w500),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(),
CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewReport.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: RadiologyResultPage(patientRadiologyResponseModel: model.patientRadiologyOrders[index]),
),
);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.bold,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
),
crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
duration: Duration(milliseconds: 300),
),
],
),
),
),
),
),
),
);
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any radiology results yet.".needTranslation);
},
),
],

@ -11,7 +11,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/common_bottom_sheet.dart';

@ -4,18 +4,15 @@ 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/extensions/route_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/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/bottomsheet/exception_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:provider/provider.dart';
abstract class DialogService {
Future<void> showErrorBottomSheet({required String message, Function()? onOkPressed});
Future<void> showErrorBottomSheet({String title = "", required String message, Function()? onOkPressed, Function()? onCancelPressed});
Future<void> showExceptionBottomSheet({required String message, required Function() onOkPressed, Function()? onCancelPressed});
@ -28,21 +25,40 @@ abstract class DialogService {
class DialogServiceImp implements DialogService {
final NavigationService navigationService;
bool _isErrorSheetShowing = false;
DialogServiceImp({required this.navigationService});
@override
Future<void> showErrorBottomSheet({required String message, Function()? onOkPressed}) async {
Future<void> showErrorBottomSheet({String title = "", required String message, Function()? onOkPressed, Function()? onCancelPressed}) async {
if (_isErrorSheetShowing) return;
final context = navigationService.navigatorKey.currentContext;
if (context == null) return;
_isErrorSheetShowing = true;
await showModalBottomSheet(
context: context,
isScrollControlled: false,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (_) => _ErrorBottomSheet(message: message, onOkPressed: onOkPressed ?? () {}),
builder: (_) => ExceptionBottomSheet(
// title: title,
message: message,
showCancel: onCancelPressed != null ? true : false,
onOkPressed: () {
if (onOkPressed != null) {
onOkPressed();
}
},
onCancelPressed: () {
if (onCancelPressed != null) {
context.pop();
}
},
),
);
_isErrorSheetShowing = false;
}
@override
@ -89,10 +105,10 @@ class DialogServiceImp implements DialogService {
Widget exceptionBottomSheetWidget({required BuildContext context, required String message, required Function() onOkPressed, Function()? onCancelPressed}) {
return Column(
children: [
(message ?? "").toText16(isBold: false, color: AppColors.textColor),
(message).toText16(isBold: false, color: AppColors.textColor),
SizedBox(height: 10.h),
SizedBox(height: 24.h),
if (onOkPressed != null && onCancelPressed != null)
if (onCancelPressed != null)
Row(
children: [
Expanded(
@ -111,7 +127,7 @@ Widget exceptionBottomSheetWidget({required BuildContext context, required Strin
SizedBox(width: 5.h),
Expanded(
child: CustomButton(
text: onCancelPressed != null ? LocaleKeys.confirm.tr() : LocaleKeys.ok.tr(),
text: LocaleKeys.confirm.tr(),
onPressed: onOkPressed,
backgroundColor: AppColors.bgGreenColor,
borderColor: AppColors.bgGreenColor,
@ -121,14 +137,14 @@ Widget exceptionBottomSheetWidget({required BuildContext context, required Strin
),
],
),
if (onOkPressed != null && onCancelPressed == null)
if (onCancelPressed == null)
Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: CustomButton(
text: LocaleKeys.ok.tr(),
onPressed: (onOkPressed != null && onCancelPressed == null)
onPressed: (onCancelPressed == null)
? () {
Navigator.of(context).pop();
context.pop();
}
: onOkPressed,
backgroundColor: AppColors.primaryRedColor,
@ -143,7 +159,6 @@ Widget exceptionBottomSheetWidget({required BuildContext context, required Strin
Widget showPhoneNumberPickerWidget({required BuildContext context, String? message, required Function() onSMSPress, required Function() onWhatsappPress}) {
return StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) {
AuthenticationViewModel authViewModel = context.read<AuthenticationViewModel>();
return Column(
children: [
(message ?? "").toText16(isBold: false, color: AppColors.textColor),
@ -201,56 +216,3 @@ Widget showPhoneNumberPickerWidget({required BuildContext context, String? messa
// );
});
}
class _ErrorBottomSheet extends StatelessWidget {
final String message;
final Function()? onOkPressed;
const _ErrorBottomSheet({required this.message, this.onOkPressed});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 40),
const SizedBox(height: 12),
Text(
"Error",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
message,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
if (onOkPressed != null) {
onOkPressed!();
} else {
context.pop();
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text("OK", style: TextStyle(color: Colors.white)).onPress(() {
Navigator.of(context).pop();
}),
),
],
),
);
}
}

@ -3,7 +3,6 @@ import 'dart:io';
import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -28,46 +27,54 @@ class ErrorHandlerServiceImp implements ErrorHandlerService {
if (failure is APIException) {
loggerService.errorLogs("API Exception: ${failure.message}");
} else if (failure is ServerFailure) {
loggerService.errorLogs("Server Failure: ${failure.message}");
await _showDialog(failure);
loggerService.errorLogs("URL: ${failure.url} \n Server Failure: ${failure.message}");
await _showDialog(failure, title: "Server Failure");
} else if (failure is DataParsingFailure) {
loggerService.errorLogs("Data Parsing Failure: ${failure.message}");
await _showDialog(failure, title: "Data Error");
} else if (failure is StatusCodeFailure) {
loggerService.errorLogs("StatusCode Failure: ${failure.message}");
await _showDialog(failure, title: "Status Code Failure Error");
await _showDialog(failure, title: "StatusCodeFailure");
} else if (failure is ConnectivityFailure) {
loggerService.errorLogs("ConnectivityFailure : ${failure.message}");
await _showDialog(failure, title: "ConnectivityFailure ", onOkPressed: () {});
} else if (failure is UnAuthenticatedUserFailure) {
loggerService.errorLogs("URL: ${failure.url} \n UnAuthenticatedUser Failure: ${failure.message}");
await _showDialog(failure, title: "UnAuthenticatedUser Failure", onOkPressed: () => navigationService.replaceAllRoutesAndNavigateToLanding());
} else if (failure is AppUpdateFailure) {
loggerService.errorLogs("AppUpdateFailure : ${failure.message}");
await _showDialog(failure, title: "AppUpdateFailure Error", onOkPressed: () => navigationService.replaceAllRoutesAndNavigateToLanding());
} else if (failure is HttpException) {
loggerService.errorLogs("Http Exception: ${failure.message}");
await _showDialog(failure, title: "Network Error");
} else if (failure is UnknownFailure) {
loggerService.errorLogs("Unknown Failure: ${failure.message}");
await _showDialog(failure, title: "Unknown Error");
loggerService.errorLogs("URL: ${failure.url} \n Unknown Failure: ${failure.message}");
await _showDialog(failure, title: "Unknown Failure");
} else if (failure is InvalidCredentials) {
loggerService.errorLogs("Invalid Credentials : ${failure.message}");
await _showDialog(failure, title: "Unknown Error");
await _showDialog(failure, title: "Invalid Credentials ");
} else if (failure is UserIntimationFailure) {
if (onUnHandledFailure != null) {
onUnHandledFailure(failure);
} else {
await _showDialog(failure, title: "Error", onOkPressed: onOkPressed);
await _showDialog(failure, title: "UserIntimationFailure", onOkPressed: onOkPressed);
}
} else if (failure is MessageStatusFailure) {
if (onMessageStatusFailure != null) {
onMessageStatusFailure(failure);
} else {
await _showDialog(failure, title: "Error", onOkPressed: onOkPressed);
await _showDialog(failure, title: "MessageStatusFailure", onOkPressed: onOkPressed);
}
} else {
loggerService.errorLogs("Unhandled failure type: $failure");
await _showDialog(failure, title: "Error", onOkPressed: onOkPressed);
await _showDialog(failure, title: "Unhandled Error", onOkPressed: onOkPressed);
}
}
Future<void> _showDialog(Failure failure, {String title = "Error", Function()? onOkPressed}) async {
Future<void> _showDialog(Failure failure, {required String title, Function()? onOkPressed}) async {
if (LoadingUtils.isLoading) {
LoadingUtils.hideFullScreenLoader();
}
await dialogService.showErrorBottomSheet(message: failure.message, onOkPressed: onOkPressed);
await dialogService.showErrorBottomSheet(title: title, message: failure.message, onOkPressed: onOkPressed);
}
}

@ -1,5 +1,8 @@
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/features/authentication/widgets/otp_verification_screen.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@ -18,6 +21,15 @@ class NavigationService {
navigatorKey.currentState?.popUntil(ModalRoute.withName(routeName));
}
void replaceAllRoutesAndNavigateToLanding() {
AppState appState = getIt.get<AppState>();
appState.isAuthenticated = false;
navigatorKey.currentState?.pushNamedAndRemoveUntil(
AppRoutes.landingScreen,
(Route<dynamic> route) => false,
);
}
void pushAndReplace(String routeName) {
navigatorKey.currentState?.pushReplacementNamed(routeName);
}

@ -12,27 +12,26 @@ import 'package:hmg_patient_app_new/theme/colors.dart';
class BottomNavigation extends StatelessWidget {
final int currentIndex;
final ValueChanged<int> onTap;
BuildContext? context;
const BottomNavigation({
super.key,
required this.currentIndex,
required this.onTap,
});
BottomNavigation({super.key, required this.currentIndex, required this.onTap, this.context});
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
AppState appState = getIt.get<AppState>();
final items = [
BottomNavItem(icon: AppAssets.homeBottom, label: LocaleKeys.home.tr()),
appState.isAuthenticated ? BottomNavItem(icon: AppAssets.myFilesBottom, label: LocaleKeys.myFiles.tr()) : BottomNavItem(icon: AppAssets.feedback, label: LocaleKeys.feedback.tr()),
BottomNavItem(icon: AppAssets.homeBottom, label: LocaleKeys.home.tr(context: context)),
appState.isAuthenticated
? BottomNavItem(icon: AppAssets.myFilesBottom, label: LocaleKeys.myFiles.tr(context: context))
: BottomNavItem(icon: AppAssets.feedback, label: LocaleKeys.feedback.tr()),
BottomNavItem(
icon: AppAssets.bookAppoBottom,
label: LocaleKeys.appointment.tr(),
label: LocaleKeys.appointment.tr(context: context),
iconSize: 27,
isSpecial: true,
),
appState.isAuthenticated ? BottomNavItem(icon: AppAssets.toDoBottom, label: LocaleKeys.todoList.tr()) : BottomNavItem(icon: AppAssets.news, label: LocaleKeys.news.tr()) ,
BottomNavItem(icon: AppAssets.servicesBottom, label: LocaleKeys.services2.tr()),
appState.isAuthenticated ? BottomNavItem(icon: AppAssets.toDoBottom, label: LocaleKeys.todoList.tr(context: context)) : BottomNavItem(icon: AppAssets.news, label: LocaleKeys.news.tr()),
BottomNavItem(icon: AppAssets.servicesBottom, label: LocaleKeys.services2.tr(context: context)),
];
return Container(
@ -42,7 +41,7 @@ class BottomNavigation extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: List.generate(
items.length,
(index) => _buildNavItem(items[index], index),
(index) => _buildNavItem(items[index], index),
),
),
);
@ -57,23 +56,22 @@ class BottomNavigation extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Center(
child: Utils.buildSvgWithAssets(
icon: item.icon,
height: item.iconSize.h,
width: item.iconSize.h,
// iconColor: isSelected ? Colors.black87 : Colors.black87,
),
Center(
child: Utils.buildSvgWithAssets(
icon: item.icon,
height: item.iconSize.h,
width: item.iconSize.h,
// iconColor: isSelected ? Colors.black87 : Colors.black87,
),
),
const SizedBox(height: 10),
item.label.toText12(
fontWeight:FontWeight.w500,
fontWeight: FontWeight.w500,
// color: Colors.black87,
// textAlign: TextAlign.center,
),
SizedBox(height: item.isSpecial ? 5:0 )
SizedBox(height: item.isSpecial ? 5 : 0)
],
),
);
}

@ -11,13 +11,14 @@ import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
class ExceptionBottomSheet extends StatelessWidget {
String message;
bool showOKButton;
bool showCancel;
Function() onOkPressed;
Function()? onCancelPressed;
final String? title;
final String message;
final bool showOKButton;
final bool showCancel;
final Function() onOkPressed;
final Function()? onCancelPressed;
ExceptionBottomSheet({Key? key, required this.message, this.showOKButton = true, this.showCancel = false, required this.onOkPressed, this.onCancelPressed}) : super(key: key);
const ExceptionBottomSheet({super.key, this.title, required this.message, this.showOKButton = true, this.showCancel = false, required this.onOkPressed, this.onCancelPressed});
@override
Widget build(BuildContext context) {
@ -44,7 +45,7 @@ class ExceptionBottomSheet extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.notice.tr().toText28(),
(title ?? LocaleKeys.notice.tr()).toText28(),
InkWell(
onTap: () {
Navigator.of(context).pop();
@ -54,7 +55,7 @@ class ExceptionBottomSheet extends StatelessWidget {
],
),
SizedBox(height: 10.h),
(message ?? "").toText16(isBold: false, color: AppColors.textColor),
(message).toText16(isBold: false, color: AppColors.textColor),
SizedBox(height: 10.h),
SizedBox(height: 24.h),
if (showOKButton && showCancel)

@ -71,7 +71,7 @@ class CustomButton extends StatelessWidget {
child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconSize, height: iconSize),
),
Padding(
padding: EdgeInsets.only(top: 2.5),
padding: EdgeInsets.only(top: 0),
child: Text(
text,
overflow: textOverflow,

@ -3,40 +3,43 @@ import 'package:fl_chart/fl_chart.dart';
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
/// A customizable line graph widget using `fl_chart`.
///
/// CustomGraph(dataPoints: sampleData, scrollDirection: Axis.horizontal,height: 200,maxY: 100, maxX:2.5,
/// leftLabelFormatter: (value){
/// Widget buildLabel(String label) {
/// return Padding(
/// padding: const EdgeInsets.only(right: 8),
/// child: Text(
/// label,
/// style: TextStyle(
/// fontSize: 8.fSize, color: AppColors.textColor,
/// fontFamily:
/// FontUtils.getFontFamilyForLanguage(false)
/// ),
/// textAlign: TextAlign.right,
/// ),
/// );
/// }
/// switch (value.toInt()) {
/// Displays a line chart with configurable axis labels, colors, and data points.
/// Useful for visualizing time series or other sequential data.
///
/// case 20:
/// return buildLabel("Critical Low");
/// case 40:
/// return buildLabel("Low");
/// case 60:
/// return buildLabel("Normal");
/// case 80:
/// return buildLabel("High");
/// case 100:
/// return buildLabel("Critical High");
/// }
/// return const SizedBox.shrink();
/// },
/// **Parameters:**
/// - [dataPoints]: List of `DataPoint` objects to plot.
/// - [leftLabelFormatter]: Function to build left axis labels.
/// - [bottomLabelFormatter]: Function to build bottom axis labels.
/// - [width]: Optional width of the chart.
/// - [height]: Required height of the chart.
/// - [maxY], [maxX], [minX]: Axis bounds.
/// - [spotColor]: Color of the touched spot marker.
/// - [graphColor]: Color of the line.
/// - [graphShadowColor]: Color of the area below the line.
/// - [graphGridColor]: Color of the grid lines.
/// - [bottomLabelColor]: Color of bottom axis labels.
/// - [bottomLabelSize]: Font size for bottom axis labels.
/// - [bottomLabelFontWeight]: Font weight for bottom axis labels.
/// - [leftLabelInterval]: Interval between left axis labels.
/// - [leftLabelReservedSize]: Reserved space for left axis labels.
/// - [scrollDirection]: Axis direction for scrolling.
/// - [showBottomTitleDates]: Whether to show bottom axis labels.
/// - [isFullScreeGraph]: Whether the graph is fullscreen.
/// - [makeGraphBasedOnActualValue]: Use `actualValue` for plotting.
///
/// ),
/// Example usage:
/// ```dart
/// CustomGraph(
/// dataPoints: sampleData,
/// leftLabelFormatter: (value) => ...,
/// bottomLabelFormatter: (value, dataPoints) => ...,
/// height: 200,
/// scrollDirection: Axis.horizontal,
/// maxY: 100,
/// maxX: 2.5,
/// )
class CustomGraph extends StatelessWidget {
final List<DataPoint> dataPoints;
final double? width;
@ -51,6 +54,8 @@ class CustomGraph extends StatelessWidget {
final Color bottomLabelColor;
final double? bottomLabelSize;
final FontWeight? bottomLabelFontWeight;
final double? leftLabelInterval;
final double? leftLabelReservedSize;
///creates the left label and provide it to the chart as it will be used by other part of the application so the label will be different for every chart
final Widget Function(double) leftLabelFormatter;
@ -60,6 +65,7 @@ class CustomGraph extends StatelessWidget {
final Axis scrollDirection;
final bool showBottomTitleDates;
final bool isFullScreeGraph;
final bool makeGraphBasedOnActualValue;
const CustomGraph({
super.key,
@ -79,6 +85,9 @@ class CustomGraph extends StatelessWidget {
this.bottomLabelColor = AppColors.textColor,
this.bottomLabelFontWeight = FontWeight.w500,
this.bottomLabelSize,
this.leftLabelInterval,
this.leftLabelReservedSize,
this.makeGraphBasedOnActualValue = false,
required this.bottomLabelFormatter,
this.minX,
});
@ -87,13 +96,7 @@ class CustomGraph extends StatelessWidget {
Widget build(BuildContext context) {
// var maxY = 0.0;
double interval = 20;
if ((maxY ?? 0) > 10 && (maxY ?? 0) <= 20) {
interval = 2;
} else if ((maxY ?? 0) > 5 && (maxY ?? 0) <= 10) {
interval = 1;
} else if ((maxY ?? 0) >= 0 && (maxY ?? 0) <= 5) {
interval = .4;
}
return Material(
color: Colors.white,
child: SizedBox(
@ -102,11 +105,11 @@ class CustomGraph extends StatelessWidget {
child: LineChart(
LineChartData(
minY: 0,
maxY:
((maxY?.ceilToDouble() ?? 0.0) + interval).floorToDouble(),
// maxY: ((maxY?.ceilToDouble() ?? 0.0) + interval).floorToDouble(),
maxY: maxY,
// minX: dataPoints.first.labelValue - 1,
maxX: maxX,
minX: minX ??-0.2,
minX: minX ,
lineTouchData: LineTouchData(
getTouchLineEnd: (_, __) => 0,
getTouchedSpotIndicator: (barData, indicators) {
@ -140,7 +143,7 @@ class CustomGraph extends StatelessWidget {
return LineTooltipItem(
// '${dataPoint.label} ${spot.y.toStringAsFixed(2)}',
'${dataPoint.actualValue} ${dataPoint.displayTime}',
'${dataPoint.value} - ${dataPoint.actualValue} - ${dataPoint.displayTime}',
TextStyle(
color: Colors.black,
fontSize: 12.fSize,
@ -156,8 +159,8 @@ class CustomGraph extends StatelessWidget {
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 77,
interval: .1, // Let fl_chart handle it
reservedSize: leftLabelReservedSize??80,
interval: leftLabelInterval ?? .1, // Let fl_chart handle it
getTitlesWidget: (value, _) {
return leftLabelFormatter(value);
},
@ -190,12 +193,12 @@ class CustomGraph extends StatelessWidget {
gridData: FlGridData(
show: true,
drawVerticalLine: false,
horizontalInterval: 20,
// horizontalInterval: 40,
checkToShowHorizontalLine: (value) =>
value >= 0 && value <= 100,
getDrawingHorizontalLine: (value) {
return FlLine(
color: AppColors.graphGridColor,
color: graphGridColor,
strokeWidth: 1,
dashArray: [5, 5],
);
@ -208,7 +211,9 @@ class CustomGraph extends StatelessWidget {
List<LineChartBarData> _buildColoredLineSegments(List<DataPoint> dataPoints) {
final List<FlSpot> allSpots = dataPoints.asMap().entries.map((entry) {
return FlSpot(entry.key.toDouble(), entry.value.value);
double value = (makeGraphBasedOnActualValue)?double.tryParse(entry.value.actualValue)??0.0:entry.value.value;
debugPrint("the value is $value");
return FlSpot(entry.key.toDouble(), value);
}).toList();
var data = [

@ -55,7 +55,7 @@ dependencies:
uuid: ^4.5.1
health: ^13.1.3
# health: 12.0.1
fl_chart: ^1.1.1
fl_chart: ^1.0.0
geolocator: ^14.0.2
dropdown_search: ^6.0.2
google_maps_flutter: ^2.12.3

Loading…
Cancel
Save