health calculator design & timer & bell icon switch changes

dev_aamir
aamir-csol 4 hours ago
parent 90bcdf674d
commit 461fa11df3

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.7501 1.97257C12.7352 1.56461 12.3967 1.24352 11.9885 1.2501C11.5804 1.25668 11.2524 1.58851 11.2506 1.99674C11.2485 2.4854 10.9063 3.79916 9.52097 5.66527C9.37283 5.86481 9.44668 6.1691 9.68599 6.23616C9.86992 6.28771 10.1456 6.22765 10.2355 6.05914C10.5779 5.4179 11.2584 4.98778 12.0331 5.00026C13.1216 5.01781 13.9961 5.9027 14.0008 6.99131C14.0014 7.00025 14.0076 7.09332 14.0573 7.27852C14.1079 7.46728 14.1966 7.72504 14.3438 8.04628C14.6377 8.68804 15.1562 9.56385 16.038 10.6233C16.0555 10.6443 16.0726 10.6657 16.0892 10.6873C17.2456 12.1985 18.0009 14.0834 18.0009 16C18.0009 16.0825 17.9995 16.1645 17.9969 16.246C17.9813 16.7261 17.9735 16.9661 18.1166 17.0581C18.2597 17.1502 18.4513 17.0552 18.8347 16.8653C21.1457 15.7203 22.7506 13.565 22.7506 11C22.7506 9.40543 22.1171 7.78106 21.0962 6.44698C21.09 6.43884 21.0836 6.43082 21.0771 6.42294C19.19 4.15586 18.753 2.54913 18.7506 1.99674C18.7488 1.58851 18.4209 1.25668 18.0127 1.2501C17.6045 1.24352 17.2661 1.56461 17.2511 1.97257C17.233 2.46736 16.9266 2.82542 16.5831 2.95502C16.2811 3.06897 15.9181 3.02413 15.6247 2.58398C15.4856 2.37533 15.2514 2.25 15.0006 2.25C14.7499 2.25 14.5157 2.37533 14.3766 2.58398C14.0831 3.02413 13.7201 3.06897 13.4181 2.95502C13.0746 2.82542 12.7682 2.46736 12.7501 1.97257ZM16.1637 5.82934C15.7932 6.01459 15.643 6.46509 15.8283 6.83557L16.3283 7.83557C16.5135 8.20606 16.964 8.35623 17.3345 8.17098C17.705 7.98574 17.8552 7.53524 17.6699 7.16475L17.1699 6.16475C16.9847 5.79427 16.5342 5.6441 16.1637 5.82934Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.98718 6.2501C6.39536 6.24352 6.73384 6.56461 6.74877 6.97257C6.76687 7.46736 7.07325 7.82542 7.41675 7.95502C7.71875 8.06897 8.08179 8.02413 8.37523 7.58398C8.51433 7.37533 8.7485 7.25 8.99927 7.25C9.25003 7.25 9.48421 7.37533 9.62331 7.58398C9.91674 8.02413 10.2798 8.06897 10.5818 7.95502C10.9253 7.82542 11.2317 7.46736 11.2498 6.97257C11.2647 6.56461 11.6032 6.24352 12.0114 6.2501C12.4195 6.25668 12.7475 6.58851 12.7493 6.99674C12.7517 7.54913 13.1886 9.15586 15.0757 11.4229C15.0823 11.4308 15.0887 11.4388 15.0949 11.447C16.1157 12.7811 16.7493 14.4054 16.7493 16C16.7493 19.8322 13.1668 22.75 8.99927 22.75C4.83169 22.75 1.24927 19.8322 1.24927 16C1.24927 14.4054 1.88281 12.7811 2.90364 11.447C2.90987 11.4388 2.91627 11.4308 2.92283 11.4229C4.8099 9.15586 5.24687 7.54913 5.24927 6.99674C5.25105 6.58851 5.579 6.25668 5.98718 6.2501ZM7.83484 10.8292C8.20533 11.0144 8.35549 11.4649 8.17025 11.8354L7.67025 12.8354C7.48501 13.2059 7.03451 13.356 6.66402 13.1708C6.29354 12.9856 6.14337 12.5351 6.32861 12.1646L6.82861 11.1646C7.01385 10.7941 7.46436 10.6439 7.83484 10.8292ZM10.164 10.8292C10.5345 10.6439 10.985 10.7941 11.1703 11.1646L11.6703 12.1646C11.8555 12.5351 11.7053 12.9856 11.3348 13.1708C10.9644 13.356 10.5139 13.2059 10.3286 12.8354L9.82861 11.8354C9.64337 11.4649 9.79354 11.0144 10.164 10.8292Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.6464 4.85841C12.9445 4.48673 13.1271 4.01976 13.1271 3.5C13.1271 2.20288 12.0081 1.25 10.7543 1.25H5.24524C3.99144 1.25 2.87244 2.20288 2.87244 3.5C2.87244 4.01976 3.055 4.48673 3.35316 4.85841C3.52079 5.06738 3.6046 5.17187 3.61356 5.26012C3.62251 5.34837 3.57237 5.44614 3.47209 5.64169C2.15246 8.21494 1.24963 10.6245 1.24963 13.7771V18C1.24963 19.6296 1.41033 20.9586 2.31169 21.7918C2.76397 22.2098 3.3378 22.4427 3.99127 22.5754C4.63937 22.707 5.41717 22.75 6.32711 22.75H9.67242C10.0971 22.75 10.536 22.7311 10.9492 22.6976C11.458 22.6563 11.7124 22.6356 11.7825 22.466C11.8525 22.2965 11.6681 22.0801 11.2993 21.6473C10.355 20.5392 9.74963 19.1021 9.74963 17.3845C9.74963 15.5039 10.3683 13.8652 11.2997 12.6615C11.9146 11.867 12.7887 11.1221 13.8271 10.7559C14.1207 10.6524 14.2674 10.6007 14.3223 10.4975C14.3772 10.3943 14.343 10.2627 14.2747 9.9996C13.8827 8.49067 13.2713 7.09213 12.5274 5.64158C12.4271 5.44611 12.377 5.34837 12.386 5.26012C12.3949 5.17187 12.4787 5.06738 12.6464 4.85841Z" fill="white"/>
<path d="M20.7264 10C20.7264 9.44771 20.2787 9 19.7264 9C18.4312 9 17.4699 9.67339 16.8679 10.5139C16.515 11.0066 16.2718 11.5713 16.1343 12.1362C15.845 12.0691 15.5182 12.0195 15.1816 12.0195C14.1838 12.0195 13.1925 12.667 12.4862 13.5798C11.7591 14.5195 11.2498 15.8349 11.2498 17.3848C11.2498 20.6682 14.1829 22.7503 16.9998 22.7503C19.8167 22.7503 22.7498 20.6682 22.7498 17.3848C22.7498 15.8349 22.2406 14.5195 21.5134 13.5798C20.8071 12.667 19.8158 12.0195 18.818 12.0196C18.6312 12.0195 18.4473 12.0348 18.2712 12.0599C18.3347 11.9256 18.409 11.7969 18.4939 11.6785C18.801 11.2497 19.2033 11 19.7264 11C20.2787 11 20.7264 10.5523 20.7264 10Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6439 1.25L13.3561 1.25C14.259 1.24997 15.0211 1.24994 15.6249 1.32042C16.255 1.39396 16.8707 1.55847 17.3706 2.00915C17.5958 2.21222 17.7873 2.44899 17.9376 2.71113C18.2326 3.22573 18.2812 3.77334 18.2347 4.31609C19.2103 4.4287 20.0196 4.68604 20.6521 5.31966C21.2538 5.92238 21.5125 6.68113 21.6335 7.58241C21.75 8.4507 21.75 9.55477 21.75 10.9249V16.043C21.75 17.4131 21.75 18.5172 21.6335 19.3855C21.5125 20.2867 21.2538 21.0455 20.6521 21.6482C20.0502 22.2511 19.2923 22.5105 18.3919 22.6318C17.5249 22.7486 16.4225 22.7486 15.055 22.7485L8.94504 22.7485C7.57752 22.7486 6.47513 22.7486 5.60808 22.6318C4.70774 22.5105 3.94976 22.2511 3.3479 21.6482C2.74621 21.0455 2.48747 20.2867 2.3665 19.3855C2.24997 18.5172 2.24998 17.4131 2.25 16.0431L2.25 10.9248C2.24998 9.55478 2.24997 8.45069 2.3665 7.58241C2.48747 6.68113 2.74621 5.92238 3.3479 5.31966C3.98043 4.68604 4.78975 4.4287 5.76534 4.31608C5.71879 3.77334 5.76736 3.22573 6.06239 2.71113C6.21268 2.44899 6.40422 2.21222 6.62944 2.00915C7.1293 1.55847 7.74503 1.39396 8.37506 1.32042C8.97893 1.24994 9.74097 1.24997 10.6439 1.25ZM8.60067 3.2073C8.13641 3.26149 7.99252 3.35241 7.92575 3.4126C7.8493 3.48154 7.78534 3.56095 7.73568 3.64756C7.69637 3.71613 7.64027 3.8608 7.69746 4.30137C7.75673 4.75797 7.91092 5.36081 8.14823 6.27796C8.33725 7.00848 8.46246 7.48783 8.59555 7.84684C8.72171 8.18716 8.82647 8.33584 8.9287 8.43308C9.00978 8.51021 9.10016 8.57847 9.1982 8.63631C9.32461 8.71091 9.5056 8.77465 9.88389 8.81094C10.1378 8.83531 10.4406 8.84448 10.8301 8.84793L11.5514 6.68404C11.726 6.1601 12.2924 5.87694 12.8163 6.05159C13.3402 6.22624 13.6234 6.79256 13.4488 7.3165L12.9378 8.84935C13.4424 8.84743 13.8138 8.83994 14.1161 8.81094C14.4944 8.77465 14.6754 8.71091 14.8018 8.63631C14.8998 8.57847 14.9902 8.51021 15.0713 8.43308C15.1735 8.33584 15.2783 8.18716 15.4045 7.84684C15.5375 7.48783 15.6628 7.00848 15.8518 6.27796C16.0891 5.36081 16.2433 4.75797 16.3025 4.30137C16.3597 3.8608 16.3036 3.71613 16.2643 3.64756C16.2147 3.56095 16.1507 3.48153 16.0742 3.4126C16.0075 3.35241 15.8636 3.26149 15.3993 3.2073C14.9218 3.15157 14.2747 3.15 13.2979 3.15L10.7021 3.15C9.72532 3.15 9.07816 3.15157 8.60067 3.2073ZM10 17C9.44772 17 9 17.4477 9 18C9 18.5523 9.44772 19 10 19H14C14.5523 19 15 18.5523 15 18C15 17.4477 14.5523 17 14 17L10 17Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 209 KiB

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.25 8C9.25 7.58579 9.58579 7.25 10 7.25H10.0081C10.4223 7.25 10.7581 7.58579 10.7581 8C10.7581 8.41421 10.4223 8.75 10.0081 8.75H10C9.58579 8.75 9.25 8.41421 9.25 8Z" fill="white"/>
<path d="M13.25 8C13.25 7.58579 13.5858 7.25 14 7.25H14.0081C14.4223 7.25 14.7581 7.58579 14.7581 8C14.7581 8.41421 14.4223 8.75 14.0081 8.75H14C13.5858 8.75 13.25 8.41421 13.25 8Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0039 1.25C8.27598 1.25 5.25391 4.27208 5.25391 8C5.25391 9.38824 5.67299 10.6786 6.39155 11.7515C5.6694 12.8779 5.25 14.2322 5.25 15.6847C5.25 19.5503 8.23629 22.7505 12 22.7505C14.6194 22.7505 16.868 21.1942 17.9876 18.9496C16.4713 18.291 14.8272 17.3477 13.3318 16.1767C12.767 15.7344 12.2184 15.2558 11.7036 14.7434C11.8031 14.7478 11.9033 14.75 12.0039 14.75C12.5875 14.75 13.1538 14.6759 13.694 14.5367C13.8779 14.6931 14.0656 14.8462 14.2566 14.9957C15.6278 16.0694 17.1339 16.9362 18.5141 17.5427C18.668 16.9498 18.75 16.3267 18.75 15.6847C18.75 14.2348 18.3321 12.8827 17.6123 11.7574C18.3333 10.6834 18.7539 9.39081 18.7539 8C18.7539 4.27208 15.7318 1.25 12.0039 1.25ZM9.30582 4.0036C8.02465 4.87025 7.18248 6.33678 7.18248 8C7.18248 10.6628 9.3411 12.8214 12.0039 12.8214C14.6667 12.8214 16.8253 10.6628 16.8253 8C16.8253 5.3372 14.6667 3.17857 12.0039 3.17857C11.5521 3.17857 11.2325 3.5278 11.2325 3.90179C11.2325 4.27578 11.5521 4.625 12.0039 4.625C12.2101 4.625 12.3921 4.55043 12.528 4.43216C12.9298 4.08256 13.5389 4.12485 13.8885 4.5266C14.2381 4.92836 14.1958 5.53744 13.794 5.88704C13.3158 6.30318 12.6868 6.55357 12.0039 6.55357C10.5721 6.55357 9.36055 5.44435 9.30582 4.0036Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.22103 1.7795C9.81474 1.35942 10.537 1.15927 11.4457 1.41276L13.8325 2.07854C13.8415 2.08106 13.8506 2.08358 13.8596 2.08609C14.1283 2.16063 14.401 2.23626 14.6357 2.39226C14.867 2.54596 15.0425 2.76342 15.2153 2.9775C15.2248 2.98922 15.2343 3.00093 15.2437 3.01262C17.8745 6.25803 19.615 8.80922 21.0951 12.0611L21.1211 12.1182C21.683 13.3527 22.1426 14.3625 22.3793 15.2434C22.6308 16.1796 22.6491 17.0304 22.2891 17.9326C21.9294 18.8342 21.3483 19.4157 20.5396 19.8663C19.7934 20.2819 18.8182 20.603 17.6511 20.9872L17.5852 21.0089C15.2201 21.7876 13.0748 21.9411 10.669 21.1702C10.5551 21.1337 10.4982 21.1155 10.4464 21.1264C10.3946 21.1373 10.3485 21.178 10.2564 21.2596C9.06151 22.3173 7.45354 22.815 5.89016 22.8005C4.19123 22.7847 2.45139 22.163 1.26272 20.8727C1.13515 20.7342 1.06433 20.5528 1.06433 20.3646V12.9848C1.06433 12.7866 1.14282 12.5964 1.28264 12.4558C2.54568 11.1863 4.38273 10.5793 6.17069 10.5601C7.07426 10.5504 7.99402 10.6905 8.85052 10.9896C9.09931 11.0765 9.22371 11.1199 9.25049 11.2234C9.27728 11.3268 9.18109 11.4347 8.98871 11.6505C8.81551 11.8448 8.65167 12.0526 8.50126 12.2661C8.0296 12.9357 7.62672 13.7512 7.4766 14.5559C7.40064 14.9631 7.66916 15.3548 8.07634 15.4308C8.48353 15.5067 8.8752 15.2382 8.95116 14.831C9.0507 14.2974 9.33974 13.6805 9.72756 13.1299C9.99274 12.7535 10.2755 12.4484 10.5286 12.2379C10.6156 12.1656 10.6592 12.1294 10.7767 12.0747C10.8942 12.02 10.9653 12.0072 11.1074 11.9817C11.9593 11.8286 12.7692 11.8715 13.5198 12.0602C13.6644 12.0966 13.7367 12.1147 13.7763 12.0789C13.8159 12.0432 13.8053 11.9704 13.7841 11.8248C13.7289 11.4458 13.6909 11.0636 13.6531 10.6817C13.626 10.409 13.599 10.1364 13.5656 9.86524C13.5521 9.75498 13.5275 9.58286 13.5086 9.45334C13.4917 9.33746 13.4511 9.22589 13.3827 9.13085C13.2693 8.97333 13.1507 8.81947 13.0322 8.6657C13.0045 8.62974 12.9768 8.59379 12.9492 8.5578C12.877 8.46331 12.8062 8.36863 12.7357 8.27426C12.5251 7.9923 12.3165 7.7131 12.0765 7.45006C12.0344 7.40383 11.9726 7.38127 11.9104 7.38829C11.6833 7.41395 11.119 7.47937 10.8177 7.52912C10.2109 7.62929 9.32812 7.58686 8.55022 7.34492C7.81147 7.11515 6.86667 6.60136 6.68264 5.54605C6.59164 5.02417 6.73496 4.58765 6.98353 4.19587C7.19707 3.8593 7.52123 3.50757 7.86706 3.13234C7.95848 3.03313 8.04835 2.93256 8.13781 2.83158C8.44695 2.48267 8.81614 2.06598 9.22103 1.7795Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 11.75C7.30964 11.75 6.75 12.3096 6.75 13C6.75 13.6904 7.30964 14.25 8 14.25H8.00897C8.69933 14.25 9.25897 13.6904 9.25897 13C9.25897 12.3096 8.69933 11.75 8.00897 11.75H8Z" fill="white"/>
<path d="M11.9955 11.75C11.3052 11.75 10.7455 12.3096 10.7455 13C10.7455 13.6904 11.3052 14.25 11.9955 14.25H12.0045C12.6948 14.25 13.2545 13.6904 13.2545 13C13.2545 12.3096 12.6948 11.75 12.0045 11.75H11.9955Z" fill="white"/>
<path d="M15.991 11.75C15.3007 11.75 14.741 12.3096 14.741 13C14.741 13.6904 15.3007 14.25 15.991 14.25H16C16.6904 14.25 17.25 13.6904 17.25 13C17.25 12.3096 16.6904 11.75 16 11.75H15.991Z" fill="white"/>
<path d="M8 15.75C7.30964 15.75 6.75 16.3096 6.75 17C6.75 17.6904 7.30964 18.25 8 18.25H8.00897C8.69933 18.25 9.25897 17.6904 9.25897 17C9.25897 16.3096 8.69933 15.75 8.00897 15.75H8Z" fill="white"/>
<path d="M11.9955 15.75C11.3052 15.75 10.7455 16.3096 10.7455 17C10.7455 17.6904 11.3052 18.25 11.9955 18.25H12.0045C12.6948 18.25 13.2545 17.6904 13.2545 17C13.2545 16.3096 12.6948 15.75 12.0045 15.75H11.9955Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2C7 1.44772 6.55229 1 6 1C5.44772 1 5 1.44772 5 2V2.44885C4.23882 2.6903 3.57734 3.06994 3.01802 3.6746C2.18949 4.57031 1.83279 5.69272 1.66416 7.04866C1.49997 8.36894 1.49998 10.0541 1.5 12.1739L1.5 12.8261C1.49998 14.9459 1.49997 16.6311 1.66416 17.9513C1.83279 19.3073 2.18949 20.4297 3.01802 21.3254C3.8568 22.2322 4.92535 22.6329 6.21533 22.8204C7.45141 23.0001 9.02291 23 10.9712 23H13.0288C14.977 23 16.5486 23.0001 17.7847 22.8204C19.0747 22.6329 20.1432 22.2322 20.982 21.3254C21.8105 20.4297 22.1672 19.3073 22.3358 17.9513C22.5 16.6311 22.5 14.9459 22.5 12.8261V12.1739C22.5 10.0541 22.5 8.36895 22.3358 7.04866C22.1672 5.69272 21.8105 4.57031 20.982 3.6746C20.4227 3.06993 19.7612 2.6903 19 2.44885V2C19 1.44772 18.5523 1 18 1C17.4477 1 17 1.44772 17 2V2.09173C15.903 1.99995 14.5863 1.99998 13.0288 2L10.9712 2C9.41376 1.99998 8.09704 1.99995 7 2.09173V2ZM4.49783 9C4.03921 9 3.8099 9 3.66385 9.14417C3.51781 9.28833 3.51487 9.51472 3.509 9.96751C3.50027 10.6407 3.5 11.3942 3.5 12.2432V12.7568C3.5 14.9616 3.50182 16.5221 3.64887 17.7045C3.79327 18.8656 4.06263 19.5094 4.48622 19.9673C4.89956 20.4142 5.4647 20.6903 6.503 20.8412C7.57858 20.9975 9.00425 21 11.05 21H12.95C14.9957 21 16.4214 20.9975 17.497 20.8412C18.5353 20.6903 19.1004 20.4142 19.5138 19.9673C19.9374 19.5094 20.2067 18.8656 20.3511 17.7045C20.4982 16.5221 20.5 14.9616 20.5 12.7568V12.2432C20.5 11.3942 20.4997 10.6407 20.491 9.96751C20.4851 9.51472 20.4822 9.28833 20.3362 9.14417C20.1901 9 19.9608 9 19.5022 9L4.49783 9Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 11.75C7.30964 11.75 6.75 12.3096 6.75 13C6.75 13.6904 7.30964 14.25 8 14.25H8.00897C8.69933 14.25 9.25897 13.6904 9.25897 13C9.25897 12.3096 8.69933 11.75 8.00897 11.75H8Z" fill="white"/>
<path d="M11.9955 11.75C11.3052 11.75 10.7455 12.3096 10.7455 13C10.7455 13.6904 11.3052 14.25 11.9955 14.25H12.0045C12.6948 14.25 13.2545 13.6904 13.2545 13C13.2545 12.3096 12.6948 11.75 12.0045 11.75H11.9955Z" fill="white"/>
<path d="M15.991 11.75C15.3007 11.75 14.741 12.3096 14.741 13C14.741 13.6904 15.3007 14.25 15.991 14.25H16C16.6904 14.25 17.25 13.6904 17.25 13C17.25 12.3096 16.6904 11.75 16 11.75H15.991Z" fill="white"/>
<path d="M8 15.75C7.30964 15.75 6.75 16.3096 6.75 17C6.75 17.6904 7.30964 18.25 8 18.25H8.00897C8.69933 18.25 9.25897 17.6904 9.25897 17C9.25897 16.3096 8.69933 15.75 8.00897 15.75H8Z" fill="white"/>
<path d="M11.9955 15.75C11.3052 15.75 10.7455 16.3096 10.7455 17C10.7455 17.6904 11.3052 18.25 11.9955 18.25H12.0045C12.6948 18.25 13.2545 17.6904 13.2545 17C13.2545 16.3096 12.6948 15.75 12.0045 15.75H11.9955Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2C7 1.44772 6.55229 1 6 1C5.44772 1 5 1.44772 5 2V2.44885C4.23882 2.6903 3.57734 3.06994 3.01802 3.6746C2.18949 4.57031 1.83279 5.69272 1.66416 7.04866C1.49997 8.36894 1.49998 10.0541 1.5 12.1739L1.5 12.8261C1.49998 14.9459 1.49997 16.6311 1.66416 17.9513C1.83279 19.3073 2.18949 20.4297 3.01802 21.3254C3.8568 22.2322 4.92535 22.6329 6.21533 22.8204C7.45141 23.0001 9.02291 23 10.9712 23H13.0288C14.977 23 16.5486 23.0001 17.7847 22.8204C19.0747 22.6329 20.1432 22.2322 20.982 21.3254C21.8105 20.4297 22.1672 19.3073 22.3358 17.9513C22.5 16.6311 22.5 14.9459 22.5 12.8261V12.1739C22.5 10.0541 22.5 8.36895 22.3358 7.04866C22.1672 5.69272 21.8105 4.57031 20.982 3.6746C20.4227 3.06993 19.7612 2.6903 19 2.44885V2C19 1.44772 18.5523 1 18 1C17.4477 1 17 1.44772 17 2V2.09173C15.903 1.99995 14.5863 1.99998 13.0288 2L10.9712 2C9.41376 1.99998 8.09704 1.99995 7 2.09173V2ZM4.49783 9C4.03921 9 3.8099 9 3.66385 9.14417C3.51781 9.28833 3.51487 9.51472 3.509 9.96751C3.50027 10.6407 3.5 11.3942 3.5 12.2432V12.7568C3.5 14.9616 3.50182 16.5221 3.64887 17.7045C3.79327 18.8656 4.06263 19.5094 4.48622 19.9673C4.89956 20.4142 5.4647 20.6903 6.503 20.8412C7.57858 20.9975 9.00425 21 11.05 21H12.95C14.9957 21 16.4214 20.9975 17.497 20.8412C18.5353 20.6903 19.1004 20.4142 19.5138 19.9673C19.9374 19.5094 20.2067 18.8656 20.3511 17.7045C20.4982 16.5221 20.5 14.9616 20.5 12.7568V12.2432C20.5 11.3942 20.4997 10.6407 20.491 9.96751C20.4851 9.51472 20.4822 9.28833 20.3362 9.14417C20.1901 9 19.9608 9 19.5022 9L4.49783 9Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -1177,14 +1177,22 @@
"monitorCholesterolLevels": "راقب مستويات الكوليسترول، وقيّم مخاطر صحة القلب، واتخذ خطوات استباقية للرفاهية.",
"triglyceridesFatBlood": "الدهون الثلاثية في الدم",
"understandTriglyceridesImpact": "افهم تأثير الدهون الثلاثية على صحة القلب مع رؤى مخصصة وتوصيات الخبراء.",
"bmiCalculator": "حاسبة\nمؤشر كتلة الجسم",
"caloriesCalculator": "حاسبة\nالسعرات الحرارية",
"bmrCalculator": "حاسبة\nمعدل الأيض الأساسي",
"idealBodyWeight": "الوزن المثالي\nللجسم",
"bodyFatCalculator": "حاسبة\nدهون الجسم",
"carbsProteinFat": "الكربوهيدرات\nالبروتين والدهون",
"ovulationPeriod": "فترة\nالإباضة",
"deliveryDueDate": "تاريخ الولادة\nالمتوقع",
"bmiCalculator": "حاسبة مؤشر كتلة الجسم",
"bmiCalculatorDesc": "احسب مؤشر كتلة جسمك لفهم نطاق وزنك الصحي.",
"caloriesCalculator": "حاسبةالسعرات الحرارية",
"caloriesCalculatorDesc": "اكتشف عدد السعرات الحرارية التي تحتاجها يومياً للحفاظ على الوزن أو فقدانه.",
"bmrCalculator": "حاسبة معدل الأيض الأساسي",
"bmrCalculatorDesc": "حدد معدل الأيض الأساسي ومتطلباتك اليومية من الطاقة.",
"idealBodyWeight": "الوزن المثالي للجسم",
"idealBodyWeightDesc": "اكتشف وزنك المثالي بناءً على الطول والعمر وبنية الجسم.",
"bodyFatCalculator": "حاسبة دهون الجسم",
"bodyFatCalculatorDesc": "قدّر نسبة دهون جسمك لتتبع أهداف اللياقة والصحة.",
"carbsProteinFat": "الكربوهيدرات البروتين والدهون",
"carbsProteinFatDesc": "وازن بين العناصر الغذائية مع النسب الصحيحة من الكربوهيدرات والبروتين والدهون.",
"ovulationPeriod": "فترة الإباضة",
"ovulationPeriodDesc": "تتبع فترة خصوبتك وخطط للحمل بدقة.",
"deliveryDueDate": "تاريخ الولادة المتوقع",
"deliveryDueDateDesc": "احسب تاريخ ولادتك المتوقع وراقب مراحل الحمل.",
"low": "منخفض",
"preDiabetic": "ما قبل السكري",
"high": "مرتفع",

@ -1168,14 +1168,22 @@
"monitorCholesterolLevels": "Monitor cholesterol levels, assess heart health risks, and take proactive steps for well-being.",
"triglyceridesFatBlood": "Triglycerides Fat Blood",
"understandTriglyceridesImpact": "Understand triglycerides' impact on heart health with personalized insights and expert recommendations.",
"bmiCalculator": "BMI\nCalculator",
"caloriesCalculator": "Calories\nCalculator",
"bmrCalculator": "BMR\nCalculator",
"idealBodyWeight": "Ideal Body\nWeight",
"bodyFatCalculator": "Body Fat\nCalculator",
"carbsProteinFat": "Carbs\nProtein & Fat",
"ovulationPeriod": "Ovulation\nPeriod",
"deliveryDueDate": "Delivery\nDue Date",
"bmiCalculator": "BMI Calculator",
"bmiCalculatorDesc": "Calculate your body mass index to understand your healthy weight range.",
"caloriesCalculator": "Calories Calculator",
"caloriesCalculatorDesc": "Find out how many calories you need daily to maintain or lose weight.",
"bmrCalculator": "BMR Calculator",
"bmrCalculatorDesc": "Determine your basal metabolic rate and daily energy requirements.",
"idealBodyWeight": "Ideal Body Weight",
"idealBodyWeightDesc": "Discover your ideal weight based on height, age, and body structure.",
"bodyFatCalculator": "Body Fat Calculator",
"bodyFatCalculatorDesc": "Estimate your body fat percentage to track fitness and health goals.",
"carbsProteinFat": "Carbs Protein & Fat",
"carbsProteinFatDesc": "Balance your macros with the right carbs, protein, and fat ratios.",
"ovulationPeriod": "Ovulation Period",
"ovulationPeriodDesc": "Track your fertile window and plan for conception with accuracy.",
"deliveryDueDate": "Delivery Due Date",
"deliveryDueDateDesc": "Calculate your expected delivery date and monitor pregnancy milestones.",
"low": "Low",
"preDiabetic": "Pre-diabetic",
"high": "High",

@ -363,6 +363,14 @@ class AppAssets {
static const String files = '$svgBasePath/files.svg';
static const String online_checkin_icon = '$svgBasePath/online_checkin_icon.svg';
//Health Calculators
static const String bodyfatcalc = '$svgBasePath/bfc.svg';
static const String duedatecalc = '$svgBasePath/ddc.svg';
static const String idealbodyweightcacl = '$svgBasePath/ibwc.svg';
static const String ovluationperiod = '$svgBasePath/op.svg';
static const String bmicalc = '$svgBasePath/bmi1.svg';
static const String bmrcalc = '$svgBasePath/bmr1.svg';
// PNGS //
static const String hmgLogo = '$pngBasePath/hmg_logo.png';
static const String liveCareService = '$pngBasePath/livecare_service.png';

@ -52,13 +52,7 @@ class CalenderUtilsNew {
});
}
FutureOr<bool> createOrUpdateEvent(
{required String title,
required String description,
required String location,
DateTime? scheduleDateTime,
String? eventId,
int? reminderMinutes}) async {
FutureOr<bool> createOrUpdateEvent({required String title, required String description, required String location, DateTime? scheduleDateTime, String? eventId, int? reminderMinutes}) async {
if (writableCalender.isEmpty) {
await getCalenders();
}
@ -93,19 +87,19 @@ class CalenderUtilsNew {
// return eventId.isNotEmpty;
}
FutureOr<bool> createMultipleEvents(
{required int reminderMinutes,
int? frequencyNumber,
required int days,
required String orderDate,
required String itemDescriptionN,
required String route,
Function(String)? onFailure,
String? prescriptionNumber,
DateTime? scheduleDateTime,
}) async {
FutureOr<bool> createMultipleEvents({
required int reminderMinutes,
int? frequencyNumber,
required int days,
required String orderDate,
required String itemDescriptionN,
required String route,
Function(String)? onFailure,
String? prescriptionNumber,
DateTime? scheduleDateTime,
}) async {
DateTime currentDay = DateTime.now();
DateTime actualDate = scheduleDateTime??DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0);
DateTime actualDate = scheduleDateTime ?? DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0);
print("the frequency is $frequencyNumber");
frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2
int interval = calculateIntervalAsPerFrequency(frequencyNumber);

@ -0,0 +1,50 @@
/// Enum to define different types of reminders
enum ReminderType {
/// Reminder for appointment schedule
appointment,
/// Reminder for payment due
payment,
/// Reminder for check-in
checkIn,
}
extension ReminderTypeExtension on ReminderType {
/// Get display name for the reminder type
String get displayName {
switch (this) {
case ReminderType.appointment:
return 'Appointment Reminder';
case ReminderType.payment:
return 'Payment Reminder';
case ReminderType.checkIn:
return 'Check-In Reminder';
}
}
/// Get description for the reminder type
String get description {
switch (this) {
case ReminderType.appointment:
return 'Appointment scheduled reminder';
case ReminderType.payment:
return 'Payment due reminder';
case ReminderType.checkIn:
return 'Check-in reminder';
}
}
/// Get event ID prefix for calendar events
String get eventIdPrefix {
switch (this) {
case ReminderType.appointment:
return 'APPT';
case ReminderType.payment:
return 'PAY';
case ReminderType.checkIn:
return 'CHKIN';
}
}
}

@ -8,6 +8,7 @@ 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/features/book_appointments/models/resp_models/get_favorite_doctors_list.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/appointemnet_filters.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/reminder_type.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_rated_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart';
@ -20,6 +21,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
@ -1113,9 +1115,13 @@ class MyAppointmentsViewModel extends ChangeNotifier {
/// Creates a reminder for the appointment
/// Shows a bottom sheet to select reminder time and creates calendar event
/// [reminderType] specifies the type of reminder (appointment, payment, or check-in)
/// For payment and check-in reminders, shows only 1, 2, 3 hours before appointment
/// Automatically removes previous reminders when creating a new one
Future<void> createReminder({
required BuildContext context,
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
ReminderType reminderType = ReminderType.appointment,
Function(bool)? onSuccess,
Function(String)? onError,
}) async {
@ -1123,39 +1129,329 @@ class MyAppointmentsViewModel extends ChangeNotifier {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
DateTime endDate = DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate);
BottomSheetUtils().showReminderBottomSheet(
context,
endDate,
patientAppointmentHistoryResponseModel.doctorNameObj ?? "",
"${patientAppointmentHistoryResponseModel.appointmentNo}",
"",
"",
title: "Appointment with ${patientAppointmentHistoryResponseModel.doctorNameObj}",
description: "${patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${patientAppointmentHistoryResponseModel.appointmentDate}",
onSuccess: () {
setAppointmentReminder(true, patientAppointmentHistoryResponseModel);
if (onSuccess != null) {
onSuccess(true);
}
},
isMultiAllowed: true,
onMultiDateSuccess: (int selectedIndex) async {
bool isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title: "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}",
description: "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} in ${patientAppointmentHistoryResponseModel.projectName}",
scheduleDateTime: DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
eventId: "${patientAppointmentHistoryResponseModel.appointmentNo}",
location: '',
reminderMinutes: selectedIndex,
);
setAppointmentReminder(isEventAddedOrRemoved, patientAppointmentHistoryResponseModel);
// Generate title and description based on reminder type
String title;
String description;
String eventIdPrefix = reminderType.eventIdPrefix;
switch (reminderType) {
case ReminderType.appointment:
title = "Appointment with ${patientAppointmentHistoryResponseModel.doctorNameObj}";
description = "${patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${patientAppointmentHistoryResponseModel.appointmentDate}";
break;
case ReminderType.payment:
title = "Payment Due for Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}";
description = "Payment reminder for appointment with ${patientAppointmentHistoryResponseModel.doctorNameObj} at ${patientAppointmentHistoryResponseModel.projectName}";
break;
case ReminderType.checkIn:
title = "Check-In Reminder for Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}";
description = "Don't forget to check in for your appointment with ${patientAppointmentHistoryResponseModel.doctorNameObj}";
break;
}
if (onSuccess != null) {
onSuccess(isEventAddedOrRemoved);
}
},
// For payment and check-in, remove existing reminders first
if (reminderType == ReminderType.payment || reminderType == ReminderType.checkIn) {
// Remove all existing reminder types
await _removeAllRemindersForAppointment(patientAppointmentHistoryResponseModel);
}
// For payment and check-in reminders, use custom hour-based options
if (reminderType == ReminderType.payment || reminderType == ReminderType.checkIn) {
_showHourBasedReminderSheet(
context: context,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
reminderType: reminderType,
title: title,
description: description,
eventIdPrefix: eventIdPrefix,
endDate: endDate,
onSuccess: onSuccess,
onError: onError,
);
} else {
// For appointment reminders, use the standard reminder sheet with all options
BottomSheetUtils().showReminderBottomSheet(
context,
endDate,
patientAppointmentHistoryResponseModel.doctorNameObj ?? "",
"${patientAppointmentHistoryResponseModel.appointmentNo}",
"",
"",
title: title,
description: description,
onSuccess: () {
setAppointmentReminder(true, patientAppointmentHistoryResponseModel);
if (onSuccess != null) {
onSuccess(true);
}
},
isMultiAllowed: true,
onMultiDateSuccess: (int selectedIndex) async {
String eventTitle;
String eventDescription;
switch (reminderType) {
case ReminderType.appointment:
eventTitle = "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}";
eventDescription = "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} in ${patientAppointmentHistoryResponseModel.projectName}";
break;
case ReminderType.payment:
eventTitle = "Payment Due Reminder for Appointment #${patientAppointmentHistoryResponseModel.appointmentNo} with ${patientAppointmentHistoryResponseModel.doctorNameObj}";
eventDescription = "Payment reminder for ${patientAppointmentHistoryResponseModel.doctorNameObj} at ${patientAppointmentHistoryResponseModel.projectName}";
break;
case ReminderType.checkIn:
eventTitle = "Check-In Reminder for Appointment #${patientAppointmentHistoryResponseModel.appointmentNo} with ${patientAppointmentHistoryResponseModel.doctorNameObj}";
eventDescription = "Check-in reminder for appointment with ${patientAppointmentHistoryResponseModel.doctorNameObj} at ${patientAppointmentHistoryResponseModel.projectName}";
break;
}
bool isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title: eventTitle,
description: eventDescription,
scheduleDateTime: DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
eventId: "${eventIdPrefix}_${patientAppointmentHistoryResponseModel.appointmentNo}",
location: patientAppointmentHistoryResponseModel.projectName ?? '',
reminderMinutes: selectedIndex,
);
setAppointmentReminder(isEventAddedOrRemoved, patientAppointmentHistoryResponseModel);
if (onSuccess != null) {
onSuccess(isEventAddedOrRemoved);
}
},
);
}
} catch (e) {
if (onError != null) {
onError(e.toString());
}
}
}
/// Removes all reminder types for an appointment (internal helper)
Future<void> _removeAllRemindersForAppointment(PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel) async {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
// Remove all possible reminder types
for (var type in ReminderType.values) {
try {
await calender.checkAndRemove(
id: "${type.eventIdPrefix}_${patientAppointmentHistoryResponseModel.appointmentNo}",
);
} catch (e) {
// Ignore errors if reminder doesn't exist
debugPrint("No existing ${type.displayName} to remove");
}
}
}
/// Shows hour-based reminder selection for payment and check-in reminders
void _showHourBasedReminderSheet({
required BuildContext context,
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
required ReminderType reminderType,
required String title,
required String description,
required String eventIdPrefix,
required DateTime endDate,
Function(bool)? onSuccess,
Function(String)? onError,
}) {
showCommonBottomSheetWithoutHeight(
context,
title: "Select Reminder Time",
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Text(
"When would you like to be reminded?",
style: TextStyle(
fontSize: 14.f,
color: AppColors.greyTextColor,
),
textAlign: TextAlign.center,
),
),
SizedBox(height: 24.h),
_buildHourOption(
context: context,
hours: 1,
icon: Icons.alarm,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
reminderType: reminderType,
title: title,
description: description,
eventIdPrefix: eventIdPrefix,
endDate: endDate,
onSuccess: onSuccess,
onError: onError,
),
SizedBox(height: 12.h),
_buildHourOption(
context: context,
hours: 2,
icon: Icons.alarm,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
reminderType: reminderType,
title: title,
description: description,
eventIdPrefix: eventIdPrefix,
endDate: endDate,
onSuccess: onSuccess,
onError: onError,
),
SizedBox(height: 12.h),
_buildHourOption(
context: context,
hours: 3,
icon: Icons.alarm,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
reminderType: reminderType,
title: title,
description: description,
eventIdPrefix: eventIdPrefix,
endDate: endDate,
onSuccess: onSuccess,
onError: onError,
),
],
),
),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
/// Builds an hour option button for payment/check-in reminders
Widget _buildHourOption({
required BuildContext context,
required int hours,
required IconData icon,
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
required ReminderType reminderType,
required String title,
required String description,
required String eventIdPrefix,
required DateTime endDate,
Function(bool)? onSuccess,
Function(String)? onError,
}) {
return GestureDetector(
onTap: () async {
Navigator.of(context).pop(); // Close the selection sheet
// Create reminder with selected hours (converted to minutes)
await _createReminderWithHours(
hours: hours,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
reminderType: reminderType,
title: title,
description: description,
eventIdPrefix: eventIdPrefix,
endDate: endDate,
onSuccess: onSuccess,
onError: onError,
);
},
child: Container(
padding: EdgeInsets.all(16.h),
decoration: BoxDecoration(
color: AppColors.whiteColor,
border: Border.all(color: AppColors.borderOnlyColor),
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
children: [
Container(
padding: EdgeInsets.all(12.h),
decoration: BoxDecoration(
color: AppColors.primaryRedColor.withAlpha(26),
borderRadius: BorderRadius.circular(8.r),
),
child: Icon(
icon,
color: AppColors.primaryRedColor,
size: 24.h,
),
),
SizedBox(width: 12.w),
Expanded(
child: Text(
"$hours ${hours == 1 ? 'Hour' : 'Hours'} Before Appointment",
style: TextStyle(
fontSize: 16.f,
fontWeight: FontWeight.w600,
color: AppColors.textColor,
),
),
),
Icon(
Icons.arrow_forward_ios,
size: 16.h,
color: AppColors.greyTextColor,
),
],
),
),
);
}
/// Creates reminder with specific hours before appointment
Future<void> _createReminderWithHours({
required int hours,
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
required ReminderType reminderType,
required String title,
required String description,
required String eventIdPrefix,
required DateTime endDate,
Function(bool)? onSuccess,
Function(String)? onError,
}) async {
try {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
// Convert hours to minutes
int reminderMinutes = hours * 60;
String eventTitle;
String eventDescription;
switch (reminderType) {
case ReminderType.appointment:
eventTitle = "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}";
eventDescription = "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} in ${patientAppointmentHistoryResponseModel.projectName}";
break;
case ReminderType.payment:
eventTitle = "Payment Due - $hours ${hours == 1 ? 'hour' : 'hours'} before Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}";
eventDescription = "Payment reminder for ${patientAppointmentHistoryResponseModel.doctorNameObj} at ${patientAppointmentHistoryResponseModel.projectName}";
break;
case ReminderType.checkIn:
eventTitle = "Check-In Now - $hours ${hours == 1 ? 'hour' : 'hours'} before Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}";
eventDescription = "Check-in reminder for appointment with ${patientAppointmentHistoryResponseModel.doctorNameObj} at ${patientAppointmentHistoryResponseModel.projectName}";
break;
}
bool isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title: eventTitle,
description: eventDescription,
scheduleDateTime: DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
eventId: "${eventIdPrefix}_${patientAppointmentHistoryResponseModel.appointmentNo}",
location: patientAppointmentHistoryResponseModel.projectName ?? '',
reminderMinutes: reminderMinutes,
);
setAppointmentReminder(isEventAddedOrRemoved, patientAppointmentHistoryResponseModel);
if (onSuccess != null) {
onSuccess(isEventAddedOrRemoved);
}
} catch (e) {
if (onError != null) {
onError(e.toString());
@ -1165,16 +1461,19 @@ class MyAppointmentsViewModel extends ChangeNotifier {
/// Deletes the reminder for the appointment
/// Removes the calendar event associated with the appointment
/// [reminderType] specifies the type of reminder to delete (appointment, payment, or check-in)
Future<void> deleteReminder({
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
ReminderType reminderType = ReminderType.appointment,
Function(bool)? onSuccess,
Function(String)? onError,
}) async {
try {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
String eventIdPrefix = reminderType.eventIdPrefix;
bool isEventRemoved = await calender.checkAndRemove(
id: "${patientAppointmentHistoryResponseModel.appointmentNo}",
id: "${eventIdPrefix}_${patientAppointmentHistoryResponseModel.appointmentNo}",
);
// Update the reminder status (inverted because we're removing)
@ -1192,10 +1491,12 @@ class MyAppointmentsViewModel extends ChangeNotifier {
/// Toggle reminder for an appointment
/// Creates or deletes reminder based on the current state
/// [reminderType] specifies the type of reminder (appointment, payment, or check-in)
Future<void> toggleReminder({
required BuildContext context,
required bool shouldCreateReminder,
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
required ReminderType reminderType ,
Function(bool)? onSuccess,
Function(String)? onError,
}) async {
@ -1203,12 +1504,14 @@ class MyAppointmentsViewModel extends ChangeNotifier {
await createReminder(
context: context,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
reminderType: reminderType,
onSuccess: onSuccess,
onError: onError,
);
} else {
await deleteReminder(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
reminderType: reminderType,
onSuccess: onSuccess,
onError: onError,
);

@ -2893,14 +2893,14 @@ static const Map<String,dynamic> _en_US = {
"monitorCholesterolLevels": "Monitor cholesterol levels, assess heart health risks, and take proactive steps for well-being.",
"triglyceridesFatBlood": "Triglycerides Fat Blood",
"understandTriglyceridesImpact": "Understand triglycerides' impact on heart health with personalized insights and expert recommendations.",
"bmiCalculator": "BMI\nCalculator",
"caloriesCalculator": "Calories\nCalculator",
"bmrCalculator": "BMR\nCalculator",
"idealBodyWeight": "Ideal Body\nWeight",
"bodyFatCalculator": "Body Fat\nCalculator",
"carbsProteinFat": "Carbs\nProtein & Fat",
"ovulationPeriod": "Ovulation\nPeriod",
"deliveryDueDate": "Delivery\nDue Date",
"bmiCalculator": "BMI Calculator",
"caloriesCalculator": "Calories Calculator",
"bmrCalculator": "BMR Calculator",
"idealBodyWeight": "Ideal Body Weight",
"bodyFatCalculator": "Body Fat Calculator",
"carbsProteinFat": "Carbs Protein & Fat",
"ovulationPeriod": "Ovulation Period",
"deliveryDueDate": "Delivery Due Date",
"low": "Low",
"preDiabetic": "Pre-diabetic",
"high": "High",

@ -1176,13 +1176,21 @@ abstract class LocaleKeys {
static const triglyceridesFatBlood = 'triglyceridesFatBlood';
static const understandTriglyceridesImpact = 'understandTriglyceridesImpact';
static const bmiCalculator = 'bmiCalculator';
static const bmiCalculatorDesc = 'bmiCalculatorDesc';
static const caloriesCalculator = 'caloriesCalculator';
static const caloriesCalculatorDesc = 'caloriesCalculatorDesc';
static const bmrCalculator = 'bmrCalculator';
static const bmrCalculatorDesc = 'bmrCalculatorDesc';
static const idealBodyWeight = 'idealBodyWeight';
static const idealBodyWeightDesc = 'idealBodyWeightDesc';
static const bodyFatCalculator = 'bodyFatCalculator';
static const bodyFatCalculatorDesc = 'bodyFatCalculatorDesc';
static const carbsProteinFat = 'carbsProteinFat';
static const carbsProteinFatDesc = 'carbsProteinFatDesc';
static const ovulationPeriod = 'ovulationPeriod';
static const ovulationPeriodDesc = 'ovulationPeriodDesc';
static const deliveryDueDate = 'deliveryDueDate';
static const deliveryDueDateDesc = 'deliveryDueDateDesc';
static const low = 'low';
static const preDiabetic = 'preDiabetic';
static const high = 'high';

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -7,6 +8,7 @@ import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/calender_utils_new.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/penguin_method_channel.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
@ -32,13 +34,11 @@ import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointmen
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_rating_widget.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/ask_doctor/ask_doctor_page.dart';
import 'package:hmg_patient_app_new/presentation/ask_doctor/doctor_response_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/bell_switch.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.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/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -95,18 +95,54 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
} else {
isAppointmentWithin4Hours = true;
}
// Check if reminder exists in calendar and update the flag
await _checkAndUpdateReminderStatus();
}
});
// Initialize countdown timer for payment
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 ||
widget.patientAppointmentHistoryResponseModel.nextAction == 20) {
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20) {
_startCountdownTimer();
}
super.initState();
}
/// Checks if a reminder exists in the calendar for this appointment
/// and updates the hasReminder flag accordingly
Future<void> _checkAndUpdateReminderStatus() async {
try {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
// Check if reminder exists for this appointment
bool reminderExists = await calender.checkIfEventExist(
widget.patientAppointmentHistoryResponseModel.appointmentNo.toString() ?? "",
);
// Update the flag if it's different from current state
if (mounted && widget.patientAppointmentHistoryResponseModel.hasReminder != reminderExists) {
setState(() {
widget.patientAppointmentHistoryResponseModel.hasReminder = reminderExists;
});
// Also update in view model to keep data consistent
myAppointmentsViewModel.setAppointmentReminder(reminderExists, widget.patientAppointmentHistoryResponseModel);
}
debugPrint("Reminder status for appointment ${widget.patientAppointmentHistoryResponseModel.appointmentNo}: $reminderExists");
setState(() {});
} catch (e) {
debugPrint("Error checking reminder status: $e");
// If there's an error, default to false
if (mounted) {
setState(() {
widget.patientAppointmentHistoryResponseModel.hasReminder = false;
});
}
}
}
void _startCountdownTimer() {
final appointmentDate = DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate);
_updateTimeRemaining();
@ -327,7 +363,58 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
onRescheduleTap: () async {
openDoctorScheduleCalendar();
},
timerWidget: Column(
children: [
SizedBox(
height: 16.w,
),
Divider(
height: 1,
color: AppColors.dividerColor,
),
SizedBox(
height: 16.w,
),
Directionality(
textDirection: ui.TextDirection.ltr,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00',
LocaleKeys.days.tr(context: context),
),
),
_buildTimeSeparator(),
Expanded(
child: _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00',
LocaleKeys.hours.tr(context: context),
),
),
_buildTimeSeparator(),
Expanded(
child: _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.minutes.tr(context: context),
),
),
_buildTimeSeparator(),
Expanded(
child: _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.seconds.tr(context: context),
),
),
],
),
),
],
),
),
SizedBox(height: 16.h),
!AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
? Column(
@ -514,47 +601,118 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
],
),
const Spacer(),
Switch(
activeThumbColor: AppColors.successColor,
// activeTrackColor: AppColors.successColor.withValues(alpha: .15),
value: widget.patientAppointmentHistoryResponseModel.hasReminder!,
BellAnimatedSwitch(
initialValue: widget.patientAppointmentHistoryResponseModel.hasReminder ?? false,
activeColor: AppColors.successColor.withOpacity(0.2),
inactiveColor: AppColors.lightGrayBGColor,
activeCircleColor: AppColors.successColor,
inactiveCircleColor: AppColors.greyTextColor,
activeIconColor: AppColors.bgGreenColor,
inactiveIconColor: AppColors.greyTextColor,
activeIcon: Utils.buildSvgWithAssets(icon: AppAssets.bell, iconColor: AppColors.whiteColor, width: 15.w, height: 15.h),
inactiveIcon: Utils.buildSvgWithAssets(icon: AppAssets.bell, iconColor: AppColors.whiteColor, width: 15.w, height: 15.h),
onChanged: (newValue) async {
await myAppointmentsViewModel.toggleReminder(
context: context,
shouldCreateReminder: newValue,
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (result) {
showCommonBottomSheet(
context,
child: Utils.getSuccessWidget(
loadingText: newValue ? LocaleKeys.reminderSuccess.tr(context: context) : LocaleKeys.reminderCancelSuccess.tr(context: context),
),
callBackFunc: (str) {},
title: "",
isCloseButtonVisible: false,
isDismissible: true,
isFullScreen: false,
isAutoDismiss: true,
height: ResponsiveExtension.screenHeight * 0.3,
);
},
onError: (error) {
setState(() {
// Revert the switch if there was an error
widget.patientAppointmentHistoryResponseModel.hasReminder = !newValue;
});
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.notice.tr(context: context),
child: Utils.getErrorWidget(loadingText: error),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
CalenderUtilsNew calender = CalenderUtilsNew.instance;
bool isEventAddedOrRemoved = false;
if (newValue == true) {
DateTime startDate = DateTime.now();
DateTime endDate = DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate);
BottomSheetUtils().showReminderBottomSheet(
context,
endDate,
widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "",
"${widget.patientAppointmentHistoryResponseModel.appointmentNo}" ?? "",
"",
"",
title: "Appointment with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}",
description:
"${widget.patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${widget.patientAppointmentHistoryResponseModel.appointmentDate}",
onSuccess: () {
setState(() {
myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel);
});
},
isMultiAllowed: true,
onMultiDateSuccess: (int selectedIndex) async {
isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title:
"Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
description:
"Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} in ${widget.patientAppointmentHistoryResponseModel.projectName}",
scheduleDateTime: DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate),
eventId: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
location: '',
reminderMinutes: selectedIndex);
setState(() {
myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
});
},
);
} else {
isEventAddedOrRemoved = await calender.checkAndRemove(
id: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
);
setState(() {
myAppointmentsViewModel.setAppointmentReminder(!isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
});
}
},
),
)
// Switch(
// activeThumbColor: AppColors.successColor,
// // activeTrackColor: AppColors.successColor.withValues(alpha: .15),
// value: widget.patientAppointmentHistoryResponseModel.hasReminder!,
// onChanged: (newValue) async {
// CalenderUtilsNew calender = CalenderUtilsNew.instance;
// bool isEventAddedOrRemoved = false;
// if(newValue == true){
// DateTime startDate = DateTime.now();
// DateTime endDate = DateUtil.convertStringToDate(widget
// .patientAppointmentHistoryResponseModel.appointmentDate);
// BottomSheetUtils().showReminderBottomSheet(
// context,
// endDate,
// widget.patientAppointmentHistoryResponseModel.doctorNameObj??"",
// "${widget.patientAppointmentHistoryResponseModel.appointmentNo}"??"",
// "",
// "",
// title: "Appointment with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}",
// description:
// "${widget.patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${widget.patientAppointmentHistoryResponseModel.appointmentDate}",
// onSuccess: () {
// setState(() {
// myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel);
// });
// },
// isMultiAllowed: true,
// onMultiDateSuccess: (int selectedIndex) async {
// isEventAddedOrRemoved = await calender.createOrUpdateEvent(
// title:
// "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
// description:
// "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} in ${widget.patientAppointmentHistoryResponseModel.projectName}",
// scheduleDateTime: DateUtil.convertStringToDate(widget
// .patientAppointmentHistoryResponseModel.appointmentDate),
// eventId: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
// location: '',
// reminderMinutes: selectedIndex
// );
// setState(() {
// myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
// });
// },
// );
// }else {
// isEventAddedOrRemoved = await calender.checkAndRemove( id:"${widget.patientAppointmentHistoryResponseModel.appointmentNo}", );
// setState(() {
// myAppointmentsViewModel.setAppointmentReminder(!isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
// });
// }
//
//
// },
// ),
],
).paddingSymmetrical(16.h, 16.h),
),
@ -1234,39 +1392,42 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
children: [
// Message text
LocaleKeys.upcomingPaymentPending.tr(context: context).toText14(
color: AppColors.textColor,
isCenter: true,
),
SizedBox(height: 24.h),
// Countdown Timer - DD : HH : MM : SS format with labels
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Days
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00',
LocaleKeys.days.tr(context: context),
),
_buildTimeSeparator(),
// Hours
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00',
LocaleKeys.hours.tr(context: context),
),
_buildTimeSeparator(),
// Minutes
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.minutes.tr(context: context),
),
_buildTimeSeparator(),
// Seconds
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.seconds.tr(context: context),
color: AppColors.textColor,
isCenter: true,
),
],
SizedBox(height: 24.h),
// Countdown Timer - DD : HH : MM : SS format with labels - Always LTR
Directionality(
textDirection: ui.TextDirection.ltr,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Days
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00',
LocaleKeys.days.tr(context: context),
),
_buildTimeSeparator(),
// Hours
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00',
LocaleKeys.hours.tr(context: context),
),
_buildTimeSeparator(),
// Minutes
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.minutes.tr(context: context),
),
_buildTimeSeparator(),
// Seconds
_buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.seconds.tr(context: context),
),
],
),
),
SizedBox(height: 24.h),
// Green Acknowledge button with checkmark icon

@ -24,7 +24,13 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class AppointmentDoctorCard extends StatelessWidget {
const AppointmentDoctorCard(
{super.key, required this.patientAppointmentHistoryResponseModel, required this.onRescheduleTap, required this.onCancelTap, required this.onAskDoctorTap, this.renderWidgetForERDisplay = false});
{super.key,
required this.patientAppointmentHistoryResponseModel,
required this.onRescheduleTap,
required this.onCancelTap,
required this.onAskDoctorTap,
this.renderWidgetForERDisplay = false,
this.timerWidget});
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
final VoidCallback onRescheduleTap;
@ -32,6 +38,8 @@ class AppointmentDoctorCard extends StatelessWidget {
final VoidCallback onAskDoctorTap;
final bool renderWidgetForERDisplay;
final Widget? timerWidget;
@override
Widget build(BuildContext context) {
return Container(
@ -146,39 +154,39 @@ class AppointmentDoctorCard extends StatelessWidget {
? SizedBox.shrink()
: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async {
DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel();
selectedDoctor.doctorID = patientAppointmentHistoryResponseModel.doctorID;
selectedDoctor.doctorImageURL = patientAppointmentHistoryResponseModel.doctorImageURL;
selectedDoctor.name = patientAppointmentHistoryResponseModel.doctorNameObj;
selectedDoctor.doctorTitle = patientAppointmentHistoryResponseModel.doctorTitle;
selectedDoctor.nationalityFlagURL = "";
selectedDoctor.speciality = patientAppointmentHistoryResponseModel.doctorSpeciality;
selectedDoctor.clinicName = patientAppointmentHistoryResponseModel.clinicName;
selectedDoctor.projectName = patientAppointmentHistoryResponseModel.projectName;
selectedDoctor.clinicID = patientAppointmentHistoryResponseModel.clinicID;
selectedDoctor.projectID = patientAppointmentHistoryResponseModel.projectID;
selectedDoctor.doctorID = patientAppointmentHistoryResponseModel.doctorID;
selectedDoctor.doctorImageURL = patientAppointmentHistoryResponseModel.doctorImageURL;
selectedDoctor.name = patientAppointmentHistoryResponseModel.doctorNameObj;
selectedDoctor.doctorTitle = patientAppointmentHistoryResponseModel.doctorTitle;
selectedDoctor.nationalityFlagURL = "";
selectedDoctor.speciality = patientAppointmentHistoryResponseModel.doctorSpeciality;
selectedDoctor.clinicName = patientAppointmentHistoryResponseModel.clinicName;
selectedDoctor.projectName = patientAppointmentHistoryResponseModel.projectName;
selectedDoctor.clinicID = patientAppointmentHistoryResponseModel.clinicID;
selectedDoctor.projectID = patientAppointmentHistoryResponseModel.projectID;
getIt.get<BookAppointmentsViewModel>().setSelectedDoctor(selectedDoctor);
LoaderBottomSheet.showLoader();
await getIt.get<BookAppointmentsViewModel>().getDoctorProfile(onSuccess: (dynamic respData) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorProfilePage(
isDoctorAllowedToBook: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false),
),
),
);
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
})
getIt.get<BookAppointmentsViewModel>().setSelectedDoctor(selectedDoctor);
LoaderBottomSheet.showLoader();
await getIt.get<BookAppointmentsViewModel>().getDoctorProfile(onSuccess: (dynamic respData) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorProfilePage(
isDoctorAllowedToBook: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false),
),
),
);
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
})
],
),
SizedBox(height: 8.h),
@ -188,6 +196,8 @@ class AppointmentDoctorCard extends StatelessWidget {
AppointmentType.isArrived(patientAppointmentHistoryResponseModel),
),
),
if (timerWidget != null)
timerWidget ?? SizedBox()
],
),
),
@ -215,26 +225,26 @@ class AppointmentDoctorCard extends StatelessWidget {
iconColor: AppColors.primaryRedColor,
)
:
// !patientAppointmentHistoryResponseModel.isLiveCareAppointment!
// ? CustomButton(
// text: LocaleKeys.rebookSameDoctor.tr(),
// onPressed: () {
// onRescheduleTap();
// },
// backgroundColor: AppColors.greyColor,
// borderColor: AppColors.greyColor,
// textColor: AppColors.blackColor,
// fontSize: 12.f,
// isBold: true,
// borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0),
// height: 40.h,
// icon: AppAssets.rebook_appointment_icon,
// iconColor: AppColors.blackColor,
// iconSize: 14.h,
// )
// :
SizedBox.shrink();
// !patientAppointmentHistoryResponseModel.isLiveCareAppointment!
// ? CustomButton(
// text: LocaleKeys.rebookSameDoctor.tr(),
// onPressed: () {
// onRescheduleTap();
// },
// backgroundColor: AppColors.greyColor,
// borderColor: AppColors.greyColor,
// textColor: AppColors.blackColor,
// fontSize: 12.f,
// isBold: true,
// borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0),
// height: 40.h,
// icon: AppAssets.rebook_appointment_icon,
// iconColor: AppColors.blackColor,
// iconSize: 14.h,
// )
// :
SizedBox.shrink();
} else {
return patientAppointmentHistoryResponseModel.isLiveCareAppointment!
? CustomButton(

@ -321,8 +321,8 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
void initiateBookAppointment() async {
// LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: bookAppointmentsViewModel.isPatientRescheduleAppointment ? LocaleKeys.reschedulingAppo.tr(context: context) : LocaleKeys.bookingYourAppointment.tr(context: context));
// LoaderBottomSheet.showLoader(loadingText: bookAppointmentsViewModel.isPatientRescheduleAppointment ? LocaleKeys.reschedulingAppo.tr(context: context) : LocaleKeys.bookingYourAppointment.tr(context: context));
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
LoaderBottomSheet.showLoader(
loadingText: bookAppointmentsViewModel.isPatientRescheduleAppointment ? LocaleKeys.reschedulingAppo.tr(context: context) : LocaleKeys.bookingYourAppointment.tr(context: context));
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
if (bookAppointmentsViewModel.isLiveCareSchedule) {
@ -365,47 +365,10 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
}, onSuccess: (apiResp) async {
LoaderBottomSheet.hideLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()).paddingSymmetrical(0.h, 24.h), callBackFunc: () async {
showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()).paddingSymmetrical(0.h, 24.h), callBackFunc: () {
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
bookAppointmentsViewModel.setIsPatientRescheduleAppointment(false);
bool newValue = true;
await myAppointmentsViewModel.toggleReminder(
context: context,
shouldCreateReminder: newValue,
patientAppointmentHistoryResponseModel: apiResp.patientAppointmentHistoryResponseModel,
onSuccess: (result) {
showCommonBottomSheet(
context,
child: Utils.getSuccessWidget(
loadingText: newValue ? LocaleKeys.reminderSuccess.tr(context: context) : LocaleKeys.reminderCancelSuccess.tr(context: context),
),
callBackFunc: (str) {
Navigator.pushAndRemoveUntil(context, CustomPageRoute(page: LandingNavigation()), (r) => false);
},
title: "",
isCloseButtonVisible: false,
isDismissible: true,
isFullScreen: false,
isAutoDismiss: true,
height: ResponsiveExtension.screenHeight * 0.3,
);
},
onError: (error) {
setState(() {
apiResp.patientAppointmentHistoryResponseModel.hasReminder = !newValue;
});
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.notice.tr(context: context),
child: Utils.getErrorWidget(loadingText: error),
callBackFunc: () {
Navigator.pushAndRemoveUntil(context, CustomPageRoute(page: LandingNavigation()), (r) => false);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
Navigator.pushAndRemoveUntil(context, CustomPageRoute(page: LandingNavigation()), (r) => false);
}, isFullScreen: false, isCloseButtonVisible: false, isAutoDismiss: true);
});
});

@ -0,0 +1,441 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/features/my_appointments/models/reminder_type.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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
enum ReminderBottomSheetStep {
success,
reminderConfirmation,
reminderTypeSelection,
creatingReminder,
reminderSuccess,
reminderError,
}
class AppointmentSuccessReminderBottomSheet extends StatefulWidget {
final PatientAppointmentHistoryResponseModel appointmentModel;
final MyAppointmentsViewModel myAppointmentsViewModel;
final VoidCallback onComplete;
const AppointmentSuccessReminderBottomSheet({
Key? key,
required this.appointmentModel,
required this.myAppointmentsViewModel,
required this.onComplete,
}) : super(key: key);
@override
State<AppointmentSuccessReminderBottomSheet> createState() => _AppointmentSuccessReminderBottomSheetState();
}
class _AppointmentSuccessReminderBottomSheetState extends State<AppointmentSuccessReminderBottomSheet> {
ReminderBottomSheetStep currentStep = ReminderBottomSheetStep.success;
ReminderType? selectedReminderType;
String errorMessage = '';
bool isProcessing = false;
@override
void initState() {
super.initState();
// Auto-progress to reminder confirmation after showing success
Future.delayed(Duration(milliseconds: 2000), () {
if (mounted) {
setState(() {
currentStep = ReminderBottomSheetStep.reminderConfirmation;
});
}
});
}
void _handleNoReminder() {
Navigator.of(context).pop();
widget.onComplete();
}
void _handleYesReminder() {
setState(() {
currentStep = ReminderBottomSheetStep.reminderTypeSelection;
});
}
void _selectReminderType(ReminderType type) {
setState(() {
selectedReminderType = type;
});
}
Future<void> _createReminder() async {
if (selectedReminderType == null) return;
setState(() {
currentStep = ReminderBottomSheetStep.creatingReminder;
isProcessing = true;
});
await widget.myAppointmentsViewModel.toggleReminder(
context: context,
shouldCreateReminder: true,
reminderType: selectedReminderType!,
patientAppointmentHistoryResponseModel: widget.appointmentModel,
onSuccess: (result) {
if (mounted) {
setState(() {
currentStep = ReminderBottomSheetStep.reminderSuccess;
isProcessing = false;
});
// Auto-close after showing success
Future.delayed(Duration(milliseconds: 2000), () {
if (mounted) {
Navigator.of(context).pop();
widget.onComplete();
}
});
}
},
onError: (error) {
if (mounted) {
setState(() {
currentStep = ReminderBottomSheetStep.reminderError;
errorMessage = error;
isProcessing = false;
});
}
},
);
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: BorderRadius.vertical(top: Radius.circular(24.r)),
),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.h),
child: AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: _buildStepContent(),
),
);
}
Widget _buildStepContent() {
switch (currentStep) {
case ReminderBottomSheetStep.success:
return _buildSuccessStep();
case ReminderBottomSheetStep.reminderConfirmation:
return _buildReminderConfirmationStep();
case ReminderBottomSheetStep.reminderTypeSelection:
return _buildReminderTypeSelectionStep();
case ReminderBottomSheetStep.creatingReminder:
return _buildCreatingReminderStep();
case ReminderBottomSheetStep.reminderSuccess:
return _buildReminderSuccessStep();
case ReminderBottomSheetStep.reminderError:
return _buildReminderErrorStep();
}
}
Widget _buildSuccessStep() {
return Column(
key: ValueKey('success'),
mainAxisSize: MainAxisSize.min,
children: [
Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr(context: context)),
SizedBox(height: 16.h),
Center(
child: "Your appointment has been booked successfully!".toText14(
color: AppColors.greyTextColor,
),
),
],
);
}
Widget _buildReminderConfirmationStep() {
return Column(
key: ValueKey('confirmation'),
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.notifications_active_outlined,
size: 56.h,
color: AppColors.primaryRedColor,
),
SizedBox(height: 16.h),
Center(child: "Add Reminder?".toText20(isBold: true)),
SizedBox(height: 12.h),
Center(
child: "Would you like to add a reminder for this appointment?".toText14(
color: AppColors.greyTextColor,
),
),
SizedBox(height: 24.h),
Row(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.cancel.tr(context: context),
onPressed: _handleNoReminder,
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.greyTextColor,
textColor: AppColors.greyTextColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12,
height: 48.h,
),
),
SizedBox(width: 12.w),
Expanded(
child: CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: _handleYesReminder,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12,
height: 48.h,
),
),
],
),
],
);
}
Widget _buildReminderTypeSelectionStep() {
return Column(
key: ValueKey('type_selection'),
mainAxisSize: MainAxisSize.min,
children: [
Center(child: "Select Reminder Type".toText20(isBold: true)),
SizedBox(height: 8.h),
Center(
child: "Choose what type of reminder you want to set".toText14(
color: AppColors.greyTextColor,
),
),
SizedBox(height: 24.h),
_buildReminderTypeCard(
type: ReminderType.appointment,
icon: Icons.event_outlined,
title: "Appointment Reminder",
description: "Get reminded about your upcoming appointment",
),
SizedBox(height: 12.h),
_buildReminderTypeCard(
type: ReminderType.payment,
icon: Icons.payment_outlined,
title: "Payment Reminder",
description: "Get reminded about payment for this appointment",
),
SizedBox(height: 12.h),
_buildReminderTypeCard(
type: ReminderType.checkIn,
icon: Icons.check_circle_outline,
title: "Check-In Reminder",
description: "Get reminded to check in for your appointment",
),
SizedBox(height: 24.h),
Row(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.cancel.tr(context: context),
onPressed: () {
setState(() {
currentStep = ReminderBottomSheetStep.reminderConfirmation;
selectedReminderType = null;
});
},
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.greyTextColor,
textColor: AppColors.greyTextColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12,
height: 48.h,
),
),
SizedBox(width: 12.w),
Expanded(
child: CustomButton(
text: "Continue",
onPressed: selectedReminderType != null ? _createReminder : null,
backgroundColor: selectedReminderType != null ? AppColors.primaryRedColor : AppColors.greyTextColor.withAlpha(76),
borderColor: selectedReminderType != null ? AppColors.primaryRedColor : AppColors.greyTextColor.withAlpha(76),
textColor: Colors.white,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12,
height: 48.h,
),
),
],
),
],
);
}
Widget _buildReminderTypeCard({
required ReminderType type,
required IconData icon,
required String title,
required String description,
}) {
final isSelected = selectedReminderType == type;
return GestureDetector(
onTap: () => _selectReminderType(type),
child: Container(
padding: EdgeInsets.all(16.h),
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryRedColor.withAlpha(26) : AppColors.scaffoldBgColor,
border: Border.all(
color: isSelected ? AppColors.primaryRedColor : AppColors.borderOnlyColor,
width: isSelected ? 2 : 1,
),
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
children: [
Container(
padding: EdgeInsets.all(12.h),
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryRedColor : AppColors.greyTextColor.withAlpha(26),
borderRadius: BorderRadius.circular(8.r),
),
child: Icon(
icon,
color: isSelected ? Colors.white : AppColors.greyTextColor,
size: 24.h,
),
),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText16(
isBold: true,
color: isSelected ? AppColors.primaryRedColor : AppColors.textColor,
),
SizedBox(height: 4.h),
description.toText12(
color: AppColors.greyTextColor,
),
],
),
),
if (isSelected)
Icon(
Icons.check_circle,
color: AppColors.primaryRedColor,
size: 24.h,
),
],
),
),
);
}
Widget _buildCreatingReminderStep() {
return Column(
key: ValueKey('creating'),
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(color: AppColors.primaryRedColor),
SizedBox(height: 24.h),
Center(
child: "Creating your reminder...".toText16(
isBold: true,
),
),
SizedBox(height: 8.h),
Center(
child: "Please wait while we set up your reminder".toText14(
color: AppColors.greyTextColor,
),
),
],
);
}
Widget _buildReminderSuccessStep() {
return Column(
key: ValueKey('reminder_success'),
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.check_circle,
size: 64.h,
color: AppColors.successColor,
),
SizedBox(height: 16.h),
Center(
child: LocaleKeys.reminderSuccess.tr(context: context).toText20(
isBold: true,
),
),
SizedBox(height: 8.h),
Center(
child: "Your ${selectedReminderType?.displayName ?? 'reminder'} has been set successfully!".toText14(
color: AppColors.greyTextColor,
),
),
],
);
}
Widget _buildReminderErrorStep() {
return Column(
key: ValueKey('error'),
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.error_outline,
size: 64.h,
color: AppColors.primaryRedColor,
),
SizedBox(height: 16.h),
Center(
child: "Error".toText20(
isBold: true,
color: AppColors.primaryRedColor,
),
),
SizedBox(height: 8.h),
Center(
child: errorMessage.toText14(
color: AppColors.greyTextColor,
),
),
SizedBox(height: 24.h),
CustomButton(
text: "Close",
onPressed: () {
Navigator.of(context).pop();
widget.onComplete();
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12,
height: 48.h,
),
],
);
}
}

@ -0,0 +1,178 @@
import 'package:flutter/material.dart';
class BellAnimatedSwitch extends StatefulWidget {
final bool initialValue;
final ValueChanged<bool>? onChanged;
final Color? activeColor;
final Color? inactiveColor;
final Color? activeIconColor;
final Color? inactiveIconColor;
final Color? activeCircleColor;
final Color? inactiveCircleColor;
final Widget? activeIcon;
final Widget? inactiveIcon;
final double width;
final double height;
final Duration animationDuration;
const BellAnimatedSwitch({
super.key,
this.initialValue = false,
this.onChanged,
this.activeColor,
this.inactiveColor,
this.activeIconColor,
this.inactiveIconColor,
this.activeCircleColor,
this.inactiveCircleColor,
this.activeIcon,
this.inactiveIcon,
this.width = 70,
this.height = 40,
this.animationDuration = const Duration(milliseconds: 300),
});
@override
State<BellAnimatedSwitch> createState() => _BellAnimatedSwitchState();
}
class _BellAnimatedSwitchState extends State<BellAnimatedSwitch> with SingleTickerProviderStateMixin {
late bool _isActive;
late AnimationController _animationController;
late Animation<Alignment> _circleAlignment;
late Animation<double> _scaleAnimation;
@override
void initState() {
super.initState();
_isActive = widget.initialValue;
_animationController = AnimationController(
duration: widget.animationDuration,
vsync: this,
);
// Animation for the circle position (left/right)
_circleAlignment = AlignmentTween(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
);
// Scale animation for tap feedback
_scaleAnimation = Tween<double>(begin: 1.0, end: 0.9).animate(
CurvedAnimation(
parent: _animationController,
curve: const Interval(0.0, 0.5, curve: Curves.easeOut),
),
);
if (_isActive) {
_animationController.value = 1.0;
}
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _toggle() {
setState(() {
_isActive = !_isActive;
if (_isActive) {
_animationController.forward();
} else {
_animationController.reverse();
}
widget.onChanged?.call(_isActive);
});
}
Color _getBackgroundColor() {
if (_isActive) {
return widget.activeColor ?? Colors.green.shade400;
}
return widget.inactiveColor ?? Colors.grey.shade300;
}
Color _getCircleColor() {
if (_isActive) {
return widget.activeCircleColor ?? Colors.white;
}
return widget.inactiveCircleColor ?? Colors.white;
}
Widget _getIcon() {
if (_isActive) {
return widget.activeIcon ?? Icon(
Icons.check,
size: 18,
color: widget.activeIconColor ?? Colors.green.shade400,
);
}
return widget.inactiveIcon ?? Icon(
Icons.close,
size: 18,
color: widget.inactiveIconColor ?? Colors.grey.shade600,
);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _toggle,
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Transform.scale(
scale: _scaleAnimation.value,
child: Container(
width: widget.width,
height: widget.height,
decoration: BoxDecoration(
color: _getBackgroundColor(),
borderRadius: BorderRadius.circular(widget.height / 2),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withAlpha(26),
// blurRadius: 4,
// offset: const Offset(0, 2),
// ),
// ],
),
child: Stack(
children: [
// Animated circle with icon inside
Align(
alignment: _circleAlignment.value,
child: Container(
margin: const EdgeInsets.all(4),
width: widget.height - 8,
height: widget.height - 8,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _getCircleColor(),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(51),
blurRadius: 2,
offset: const Offset(0, 1),
),
],
),
child: Center(
child: _getIcon(),
),
),
),
],
),
),
);
},
),
);
}
}

@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts
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/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/expandable_list_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class HealthCalculatorsPage extends StatefulWidget {
@ -37,73 +38,89 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
return CollapsingListView(
title: widget.type == HealthCalConEnum.calculator ? LocaleKeys.healthCalculators.tr(context: context) : LocaleKeys.healthConverters.tr(),
child: widget.type == HealthCalConEnum.calculator
? Column(
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r),
child: Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.general_health, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
SizedBox(width: 12.w),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.generalHealth.tr().toText16(isBold: true),
LocaleKeys.relatedToBMICalories.tr().toText12(isBold: true, color: Color(0xFF8F9AA3))
],
),
),
SizedBox(
width: 12.w,
),
Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor)),
],
).paddingAll(16.w))
.onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectCalculator.tr(),
message: "",
child: showCalculatorsItems(type: HealthCalculatorEnum.general),
onOkPressed: () {},
);
}),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r),
child: Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.women_health, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
SizedBox(width: 12.w),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.womensHealth.tr().toText16(isBold: true),
LocaleKeys.relatedToPeriodsOvulation.tr().toText12(isBold: true, color: Color(0xFF8F9AA3))
],
),
),
SizedBox(width: 12.w),
Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor)),
],
).paddingAll(16.w))
.onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectCalculator.tr(),
message: "",
child: showCalculatorsItems(type: HealthCalculatorEnum.women),
onOkPressed: () {},
);
}),
? CustomExpandableList(
expansionMode: ExpansionMode.exactlyOne,
dividerColor: AppColors.dividerColor,
itemPadding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 14.h),
items: [
ExpandableListItem(
title: LocaleKeys.womensHealth.tr(context: context).toText18(isBold: true),
expandedBackgroundColor: Colors.transparent,
initiallyExpanded: true,
children: [showCalculatorsItems(type: HealthCalculatorEnum.women)],
),
ExpandableListItem(
title: LocaleKeys.generalHealth.tr(context: context).toText18(isBold: true),
expandedBackgroundColor: Colors.transparent,
initiallyExpanded: true,
children: [showCalculatorsItems(type: HealthCalculatorEnum.general)],
),
],
).paddingSymmetrical(20.w, 24.h)
theme: ExpandableListTheme.custom(
defaultTrailingIcon: Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w, iconColor: AppColors.textColor),
),
).paddingSymmetrical(16.w, 0.0)
// ? Column(
// children: [
// Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r),
// child: Row(
// children: [
// Utils.buildSvgWithAssets(icon: AppAssets.general_health, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
// SizedBox(width: 12.w),
// Flexible(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.center,
// children: [LocaleKeys.generalHealth.tr().toText16(isBold: true), LocaleKeys.relatedToBMICalories.tr().toText12(isBold: true, color: Color(0xFF8F9AA3))],
// ),
// ),
// SizedBox(
// width: 12.w,
// ),
// Transform.flip(
// flipX: getIt.get<AppState>().isArabic(),
// child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor)),
// ],
// ).paddingAll(16.w))
// .onPress(() {
// dialogService.showFamilyBottomSheetWithoutHWithChild(
// label: LocaleKeys.selectCalculator.tr(),
// message: "",
// child: showCalculatorsItems(type: HealthCalculatorEnum.general),
// onOkPressed: () {},
// );
// }),
// SizedBox(height: 16.h),
// Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r),
// child: Row(
// children: [
// Utils.buildSvgWithAssets(icon: AppAssets.women_health, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
// SizedBox(width: 12.w),
// Flexible(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.center,
// children: [LocaleKeys.womensHealth.tr().toText16(isBold: true), LocaleKeys.relatedToPeriodsOvulation.tr().toText12(isBold: true, color: Color(0xFF8F9AA3))],
// ),
// ),
// SizedBox(width: 12.w),
// Transform.flip(
// flipX: getIt.get<AppState>().isArabic(),
// child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor)),
// ],
// ).paddingAll(16.w))
// .onPress(() {
// dialogService.showFamilyBottomSheetWithoutHWithChild(
// label: LocaleKeys.selectCalculator.tr(),
// message: "",
// child: showCalculatorsItems(type: HealthCalculatorEnum.women),
// onOkPressed: () {},
// );
// }),
// ],
// ).paddingSymmetrical(20.w, 24.h)
: Column(
children: [
Container(
@ -151,11 +168,7 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.bloodCholesterol.tr().toText16(isBold: true),
LocaleKeys.monitorCholesterolLevels.tr()
.toText12(isBold: true, color: Color(0xFF8F9AA3))
],
children: [LocaleKeys.bloodCholesterol.tr().toText16(isBold: true), LocaleKeys.monitorCholesterolLevels.tr().toText12(isBold: true, color: Color(0xFF8F9AA3))],
),
),
SizedBox(width: 12.w),
@ -183,8 +196,7 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.triglyceridesFatBlood.tr().toText16(isBold: true),
LocaleKeys.understandTriglyceridesImpact.tr()
.toText12(isBold: true, color: Color(0xFF8F9AA3))
LocaleKeys.understandTriglyceridesImpact.tr().toText12(isBold: true, color: Color(0xFF8F9AA3))
],
),
),
@ -204,49 +216,104 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
}
Widget showCalculatorsItems({required HealthCalculatorEnum type}) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 4 icons per row
crossAxisSpacing: 16.w,
mainAxisSpacing: 16.w,
childAspectRatio: 0.85),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: type == HealthCalculatorEnum.general ? generalHealthServices.length : womenHealthServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
return HealthCard(
icon: type == HealthCalculatorEnum.general ? generalHealthServices[index].icon : womenHealthServices[index].icon,
labelText: type == HealthCalculatorEnum.general ? generalHealthServices[index].title : womenHealthServices[index].title,
onTap: () {
Navigator.pop(context);
Navigator.of(context).push(
CustomPageRoute(
page: HealthCalculatorDetailedPage(
calculatorType: type == HealthCalculatorEnum.general ? generalHealthServices[index].type : womenHealthServices[index].type,
clinicID: type == HealthCalculatorEnum.general ? generalHealthServices[index].clinicID : womenHealthServices[index].clinicID,
calculationID: type == HealthCalculatorEnum.general ? generalHealthServices[index].calculationID : womenHealthServices[index].calculationID,
return ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: type == HealthCalculatorEnum.general ? generalHealthServices.length : womenHealthServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
return HealthCard(
icon: type == HealthCalculatorEnum.general ? generalHealthServices[index].icon : womenHealthServices[index].icon,
labelText: type == HealthCalculatorEnum.general ? generalHealthServices[index].title : womenHealthServices[index].title,
subtitle: type == HealthCalculatorEnum.general ? generalHealthServices[index].subTitle ?? "" : womenHealthServices[index].subTitle ?? "",
iconColor: type == HealthCalculatorEnum.general ? generalHealthServices[index].iconColor : womenHealthServices[index].iconColor,
iconBgColor: type == HealthCalculatorEnum.general ? generalHealthServices[index].bgColor : womenHealthServices[index].bgColor,
onTap: () {
Navigator.of(context).push(
CustomPageRoute(
page: HealthCalculatorDetailedPage(
calculatorType: type == HealthCalculatorEnum.general ? generalHealthServices[index].type : womenHealthServices[index].type,
clinicID: type == HealthCalculatorEnum.general ? generalHealthServices[index].clinicID : womenHealthServices[index].clinicID,
calculationID: type == HealthCalculatorEnum.general ? generalHealthServices[index].calculationID : womenHealthServices[index].calculationID,
),
),
),
);
},
);
},
);
);
},
);
},
separatorBuilder: (BuildContext context, int index) {
return SizedBox(height: 16.h);
});
}
final List<HealthComponentModel> generalHealthServices = [
HealthComponentModel(title: LocaleKeys.bmiCalculator.tr(), icon: AppAssets.bmi, type: HealthCalculatorsTypeEnum.bmi, clinicID: 108, calculationID: null),
HealthComponentModel(title: LocaleKeys.caloriesCalculator.tr(), icon: AppAssets.calories, type: HealthCalculatorsTypeEnum.calories, clinicID: null, calculationID: 2),
HealthComponentModel(title: LocaleKeys.bmrCalculator.tr(), icon: AppAssets.bmr, type: HealthCalculatorsTypeEnum.bmr, clinicID: null, calculationID: 3),
HealthComponentModel(title: LocaleKeys.idealBodyWeight.tr(), icon: AppAssets.ibw, type: HealthCalculatorsTypeEnum.idealBodyWeight, clinicID: null, calculationID: 4),
HealthComponentModel(title: LocaleKeys.bodyFatCalculator.tr(), icon: AppAssets.ibw, type: HealthCalculatorsTypeEnum.bodyFat, clinicID: null, calculationID: 5),
HealthComponentModel(title: LocaleKeys.carbsProteinFat.tr(), icon: AppAssets.ibw, type: HealthCalculatorsTypeEnum.crabsProteinFat, clinicID: null, calculationID: 11),
HealthComponentModel(
title: LocaleKeys.bmiCalculator.tr(),
subTitle: LocaleKeys.bmiCalculatorDesc.tr(),
icon: AppAssets.bmicalc,
type: HealthCalculatorsTypeEnum.bmi,
clinicID: 108,
bgColor: AppColors.bmiCalculatorColor,
calculationID: null),
HealthComponentModel(
title: LocaleKeys.caloriesCalculator.tr(),
subTitle: LocaleKeys.caloriesCalculatorDesc.tr(),
icon: AppAssets.bmicalc,
type: HealthCalculatorsTypeEnum.calories,
clinicID: null,
bgColor: AppColors.caloriesCalculatorColor,
calculationID: 2),
HealthComponentModel(
title: LocaleKeys.bmrCalculator.tr(),
subTitle: LocaleKeys.bmrCalculatorDesc.tr(),
icon: AppAssets.bmrcalc,
type: HealthCalculatorsTypeEnum.bmr,
clinicID: null,
bgColor: AppColors.bmrCalculatorColor,
calculationID: 3),
HealthComponentModel(
title: LocaleKeys.idealBodyWeight.tr(),
subTitle: LocaleKeys.idealBodyWeightDesc.tr(),
icon: AppAssets.idealbodyweightcacl,
type: HealthCalculatorsTypeEnum.idealBodyWeight,
bgColor: AppColors.idealBodyWeightColor,
clinicID: null,
calculationID: 4),
HealthComponentModel(
title: LocaleKeys.bodyFatCalculator.tr(),
subTitle: LocaleKeys.bodyFatCalculatorDesc.tr(),
icon: AppAssets.bodyfatcalc,
type: HealthCalculatorsTypeEnum.bodyFat,
clinicID: null,
bgColor: AppColors.bodyFatCalculatorColor,
calculationID: 5),
HealthComponentModel(
title: LocaleKeys.carbsProteinFat.tr(),
subTitle: LocaleKeys.carbsProteinFatDesc.tr(),
icon: AppAssets.bmicalc,
type: HealthCalculatorsTypeEnum.crabsProteinFat,
clinicID: null,
bgColor: AppColors.carbsProteinFatColor,
calculationID: 11),
];
final List<HealthComponentModel> womenHealthServices = [
HealthComponentModel(title: LocaleKeys.ovulationPeriod.tr(), icon: AppAssets.locate_me, type: HealthCalculatorsTypeEnum.ovulation, clinicID: null, calculationID: 6 ),
HealthComponentModel(title: LocaleKeys.deliveryDueDate.tr(), icon: AppAssets.activeCheck, type: HealthCalculatorsTypeEnum.deliveryDueDate, clinicID: null, calculationID: 6),
HealthComponentModel(
title: LocaleKeys.ovulationPeriod.tr(),
subTitle: LocaleKeys.ovulationPeriodDesc.tr(),
icon: AppAssets.ovluationperiod,
type: HealthCalculatorsTypeEnum.ovulation,
clinicID: null,
calculationID: 6,
bgColor: AppColors.ovulationPeriodColor),
HealthComponentModel(
title: LocaleKeys.deliveryDueDate.tr(),
subTitle: LocaleKeys.deliveryDueDateDesc.tr(),
icon: AppAssets.duedatecalc,
type: HealthCalculatorsTypeEnum.deliveryDueDate,
clinicID: null,
bgColor: AppColors.deliveryDueDateColor,
calculationID: 6),
];
}

@ -1,4 +1,7 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -9,41 +12,55 @@ class HealthCard extends StatelessWidget {
const HealthCard({
super.key,
required this.icon,
this.iconColor,
this.iconBgColor,
required this.labelText,
required this.subtitle,
this.onTap,
});
final String icon;
final Color? iconColor;
final Color? iconBgColor;
final String labelText;
final String subtitle;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r, hasShadow: false),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(
icon: icon,
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: iconBgColor ?? Colors.transparent, borderRadius: 10.r),
height: 40.w,
width: 40.w,
height: 40.h,
fit: BoxFit.cover,
).toShimmer2(isShow: false, radius: 12.r),
SizedBox(height: 14.h),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Flexible(
child: labelText.toText12(
isBold: true,
maxLine: 2,
)),
],
child: Utils.buildSvgWithAssets(icon: icon, fit: BoxFit.none, height: 22.w, width: 22.w, iconColor: iconColor),
),
SizedBox(width: 12.h),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
labelText.toText16(weight: FontWeight.w600),
],
),
SizedBox(height: 4.h),
subtitle.toText12(maxLine: 2, color: AppColors.greyTextColor),
],
),
),
SizedBox(width: 2.h),
Transform.flip(
flipX: appState.getLanguageCode() == "ar",
child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.cover, iconColor: AppColors.textColor),
),
],
).paddingAll(16.w).onPress(() {

@ -90,6 +90,16 @@ class AppColors {
static Color get myChildVaccineCardColor => isDarkMode ? dark.myChildVaccineCardColor : const Color(0xFFFF2D78);
static Color get bookAppointment => isDarkMode ? dark.bookAppointment : const Color(0xFF415364);
// Health Calculators Colors
static Color get bmiCalculatorColor => isDarkMode ? dark.bmiCalculatorColor : const Color(0xFFF43333);
static Color get caloriesCalculatorColor => isDarkMode ? dark.caloriesCalculatorColor : const Color(0xFF0B85F7);
static Color get bmrCalculatorColor => isDarkMode ? dark.bmrCalculatorColor : const Color(0xFF18C273);
static Color get idealBodyWeightColor => isDarkMode ? dark.idealBodyWeightColor : const Color(0xFFFF8012);
static Color get bodyFatCalculatorColor => isDarkMode ? dark.bodyFatCalculatorColor : const Color(0xFFFF5662);
static Color get carbsProteinFatColor => isDarkMode ? dark.carbsProteinFatColor : const Color(0xFF18C273);
static Color get ovulationPeriodColor => isDarkMode ? dark.ovulationPeriodColor : const Color(0xFFFF47A9);
static Color get deliveryDueDateColor => isDarkMode ? dark.deliveryDueDateColor : const Color(0xFFFF2D78);
// Water Monitor
static Color get blueColor => isDarkMode ? dark.blueColor : const Color(0xFF4EB5FF);
static Color get blueGradientColorOne => isDarkMode ? dark.blueGradientColorOne : const Color(0xFFF1F7FD);
@ -217,6 +227,16 @@ class AppColorsDark {
Color get myChildVaccineCardColor => const Color(0xFFFF2D78);
Color get bookAppointment => const Color(0xFF415364);
// Health Calculators
Color get bmiCalculatorColor => const Color(0xFFF43333);
Color get caloriesCalculatorColor => const Color(0xFF0B85F7);
Color get bmrCalculatorColor => const Color(0xFF18C273);
Color get idealBodyWeightColor => const Color(0xFFFF8012);
Color get bodyFatCalculatorColor => const Color(0xFFFF5662);
Color get carbsProteinFatColor => const Color(0xFF18C273);
Color get ovulationPeriodColor => const Color(0xFFFF47A9);
Color get deliveryDueDateColor => const Color(0xFFFF2D78);
// Water Monitor
Color get blueColor => const Color(0xFF4EB5FF);
Color get blueGradientColorOne => const Color(0xFF101C2A);

@ -20,7 +20,12 @@ class BottomSheetUtils {
showReminderBottomSheet(BuildContext context, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted,
{required Function() onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool isMultiAllowed = false}) async {
if (Platform.isAndroid) {
if (await PermissionService.isCalendarPermissionEnabled()) {
bool hasPermission = await PermissionService.isCalendarPermissionEnabled();
if (!hasPermission) {
PermissionStatus status = await Permission.calendarFullAccess.request();
hasPermission = status.isGranted;
}
if (hasPermission) {
_showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
} else {

Loading…
Cancel
Save