Smartwatch integration started

pull/116/head
haroon amjad 3 months ago
parent ff98262cf7
commit d202aa8423

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@ -0,0 +1,5 @@
<svg width="35" height="36" viewBox="0 0 35 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.7655 2.68793e-05C22.4959 -0.000446999 20.3022 0.831603 18.5867 2.3436C16.8712 3.8556 15.7488 5.94619 15.4254 8.23203C15.4016 8.40311 15.4144 8.5774 15.4629 8.74298C15.5115 8.90856 15.5945 9.06152 15.7065 9.19141C15.8185 9.32131 15.9567 9.42506 16.1117 9.49558C16.2667 9.56611 16.4349 9.60173 16.6047 9.60003C16.8891 9.6033 17.1651 9.50187 17.3818 9.31443C17.5985 9.127 17.7414 8.86617 17.784 8.58003C18.0405 6.6832 19.027 4.96773 20.5265 3.81101C22.026 2.65428 23.9156 2.15105 25.7797 2.41203C27.6439 2.673 29.3298 3.6768 30.4665 5.20259C31.6033 6.72839 32.0979 8.6512 31.8414 10.548C31.573 12.3164 30.6823 13.9254 29.3352 15.0755C27.988 16.2256 26.276 16.8385 24.5179 16.8H1.17931C0.866538 16.8 0.566576 16.9265 0.345412 17.1515C0.124248 17.3765 0 17.6818 0 18C0 18.3183 0.124248 18.6235 0.345412 18.8486C0.566576 19.0736 0.866538 19.2 1.17931 19.2H24.4353C26.8716 19.2402 29.2327 18.3408 31.044 16.6824C32.8554 15.024 33.9829 12.7296 34.2 10.26C34.2891 8.94494 34.111 7.62528 33.6769 6.38328C33.2429 5.14127 32.562 4.00355 31.6769 3.04099C30.7918 2.07843 29.7214 1.31167 28.5323 0.788485C27.3432 0.265302 26.061 -0.00309236 24.7655 2.68793e-05Z" fill="#3B355A"/>
<path d="M19.8006 21.5996H1.17931C0.866538 21.5996 0.566576 21.726 0.345412 21.9511C0.124248 22.1761 0 22.4814 0 22.7996C0 23.1179 0.124248 23.4231 0.345412 23.6481C0.566576 23.8732 0.866538 23.9996 1.17931 23.9996H19.8006C20.5146 23.9992 21.2194 24.1638 21.8618 24.4809C22.5041 24.7979 23.0674 25.2592 23.5091 25.83C23.9509 26.4008 24.2595 27.0662 24.4117 27.776C24.564 28.4858 24.5559 29.2215 24.3881 29.9276C24.1363 30.985 23.5389 31.924 22.6939 32.5907C21.8488 33.2573 20.8062 33.612 19.7371 33.5967C18.6679 33.5814 17.6356 33.1969 16.8093 32.5062C15.9831 31.8156 15.4119 30.8598 15.1895 29.7956C15.1418 29.5139 14.9968 29.2587 14.7805 29.0761C14.5643 28.8935 14.2912 28.7955 14.0102 28.7996C13.8393 28.7976 13.6699 28.8335 13.514 28.9047C13.358 28.976 13.2191 29.0809 13.1069 29.2121C12.9948 29.3434 12.912 29.4979 12.8643 29.665C12.8166 29.832 12.8052 30.0076 12.8309 30.1796C13.0878 31.5182 13.7131 32.755 14.6339 33.746C15.5547 34.7371 16.7332 35.4416 18.0323 35.7776C19.3313 36.1137 20.6974 36.0673 21.9716 35.644C23.2457 35.2208 24.3756 34.438 25.2295 33.3867C26.0834 32.3355 26.6264 31.0591 26.7951 29.7061C26.9639 28.3531 26.7515 26.9791 26.1827 25.7441C25.6139 24.5092 24.7121 23.464 23.5822 22.7303C22.4524 21.9965 21.141 21.6044 19.8006 21.5996Z" fill="#3B355A"/>
<path d="M7.77155 11.8205H1.27355C0.960777 11.8205 0.660814 11.947 0.439651 12.172C0.218487 12.3971 0.0942383 12.7023 0.0942383 13.0205C0.0942383 13.3388 0.218487 13.644 0.439651 13.8691C0.660814 14.0941 0.960777 14.2205 1.27355 14.2205H7.71259C9.06084 14.2431 10.3698 13.7583 11.3884 12.8592C12.407 11.9601 13.0634 10.7099 13.2318 9.34854C13.3614 8.0124 12.9972 6.67504 12.2103 5.59734C11.4233 4.51964 10.27 3.7789 8.97535 3.51963C7.68071 3.26035 6.33757 3.50113 5.20795 4.195C4.07832 4.88887 3.24325 5.98606 2.86562 7.27253C2.81077 7.45608 2.79996 7.65032 2.83411 7.83899C2.86825 8.02765 2.94635 8.20524 3.06186 8.35686C3.17737 8.50848 3.32691 8.62971 3.49796 8.71038C3.66901 8.79106 3.85658 8.82883 4.04493 8.82054C4.31433 8.82852 4.57828 8.74238 4.79286 8.57644C5.00743 8.4105 5.15967 8.17479 5.22424 7.90854C5.44561 7.20326 5.91546 6.60618 6.54341 6.23217C7.17136 5.85817 7.91304 5.73365 8.62578 5.88257C9.33852 6.03149 9.97197 6.44333 10.4043 7.03887C10.8366 7.6344 11.0372 8.37156 10.9675 9.10854C10.865 9.88557 10.4799 10.5952 9.88817 11.0974C9.29645 11.5995 8.54118 11.8575 7.77155 11.8205Z" fill="#3B355A"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -0,0 +1,3 @@
<svg width="30" height="41" viewBox="0 0 30 41" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M29.943 24.2303L29.9145 23.8321C29.4563 17.7622 26.6788 13.9572 24.2285 10.601C21.9596 7.49317 20 4.80939 20 0.849479C20 0.531496 19.825 0.24086 19.5475 0.0950652C19.2691 -0.0515247 18.9347 -0.027517 18.6816 0.159695C15.0016 2.83933 11.9312 7.35572 10.8586 11.665C10.114 14.6652 10.0155 18.0379 10.0016 20.2655C6.6032 19.5268 5.83336 14.3538 5.82523 14.2975C5.78695 14.0292 5.62586 13.7957 5.39148 13.6681C5.15469 13.5423 4.87633 13.5332 4.63625 13.6541C4.45805 13.7418 0.262031 15.9114 0.0178903 24.5748C0.000780959 24.863 0 25.1511 0 25.4401C0 33.8559 6.7293 40.7033 15 40.7033C23.2707 40.7033 30 33.8559 30 25.4401C30 25.0178 29.9716 24.6237 29.943 24.2303ZM15 39.0074C12.2428 39.0074 10 36.5762 10 33.5876C10 33.4858 9.99922 33.3831 10.0065 33.2572C10.0398 31.9969 10.2751 31.1365 10.533 30.5643C11.0165 31.621 11.8815 32.5922 13.2845 32.5922C13.7452 32.5922 14.1179 32.213 14.1179 31.7443C14.1179 30.5369 14.1423 29.1441 14.4377 27.887C14.7006 26.7716 15.3288 25.5866 16.1248 24.636C16.4788 25.8698 17.1689 26.8685 17.8427 27.8432C18.8071 29.2377 19.804 30.6793 19.979 33.1379C19.9895 33.2836 20.0002 33.4302 20.0002 33.5875C20 36.5762 17.7572 39.0074 15 39.0074ZM20.2666 37.8994C21.1316 36.6991 21.6667 35.2154 21.6667 33.5876C21.6667 33.3881 21.6545 33.2025 21.6301 32.8556C21.4323 30.0873 20.2498 28.3765 19.2058 26.867C18.3163 25.5818 17.5489 24.4714 17.5489 22.8963C17.5489 22.5742 17.3698 22.2802 17.0866 22.137C16.8051 21.9928 16.4649 22.0252 16.2134 22.2198C14.6152 23.4486 13.2821 25.5172 12.8166 27.4922C12.579 28.505 12.496 29.6005 12.4667 30.5014C11.8889 29.8688 11.7098 28.6962 11.7083 28.6805C11.6709 28.4081 11.5065 28.1704 11.2664 28.0437C11.028 27.9179 10.7423 27.9146 10.5023 28.0404C10.2923 28.1497 8.44742 29.2262 8.34164 33.1861C8.3343 33.3203 8.33352 33.4544 8.33352 33.5877C8.33352 35.2155 8.86867 36.6992 9.73367 37.8995C4.9943 35.8171 1.66687 31.0181 1.66687 25.4403C1.66687 25.186 1.66609 24.9327 1.68312 24.6502C1.82633 19.5674 3.42469 17.0468 4.46797 15.9347C5.19547 18.5846 7.10141 22.0484 10.8335 22.0484C11.2941 22.0484 11.6669 21.6691 11.6669 21.2004C11.6669 18.3626 11.7295 15.0834 12.475 12.0808C13.3213 8.679 15.6398 5.00567 18.4385 2.51897C18.9032 6.15096 20.8473 8.81406 22.8909 11.6121C25.3201 14.9393 27.8315 18.3799 28.2522 23.9513L28.2807 24.357C28.3067 24.7098 28.3336 25.0618 28.3336 25.4402C28.3334 31.0181 25.0059 35.8171 20.2666 37.8994Z" fill="#D59E95"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -0,0 +1,3 @@
<svg width="27" height="35" viewBox="0 0 27 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.7188 6.51163C19.575 6.51163 21.0938 5.04651 21.0938 3.25581C21.0938 1.46512 19.575 0 17.7188 0C15.8625 0 14.3438 1.46512 14.3438 3.25581C14.3438 5.04651 15.8625 6.51163 17.7188 6.51163ZM12.3188 26.0465L13.3312 21.9767L16.875 25.2326V33.3721C16.875 34.186 17.55 35 18.5625 35C19.575 35 20.25 34.186 20.25 33.3721V24.2558C20.25 23.2791 19.9125 22.4651 19.2375 21.9767L16.7062 19.6977L17.7188 14.814C19.575 16.7674 22.1062 18.2326 25.1437 18.7209C26.1562 18.8837 27 18.0698 27 17.093C27 16.2791 26.325 15.6279 25.4813 15.4651C22.95 14.9767 20.7563 13.6744 19.7437 11.7209L18.0562 9.11628C17.3813 8.13953 16.3687 7.48837 15.1875 7.48837C14.6812 7.48837 14.3438 7.65116 13.8375 7.65116L7.0875 10.4186C5.7375 10.7442 5.0625 11.8837 5.0625 13.186V17.093C5.0625 18.0698 5.7375 18.7209 6.75 18.7209C7.7625 18.7209 8.4375 18.0698 8.4375 17.093V13.186L11.475 12.0465L8.775 25.2326L2.025 23.9302C1.18125 23.7674 0.16875 24.2558 0 25.2326C0 26.0465 0.50625 26.8605 1.35 27.186L8.4375 28.4884C10.125 28.814 11.9813 27.6744 12.3188 26.0465Z" fill="#6A46F5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

@ -0,0 +1,3 @@
<svg width="29" height="25" viewBox="0 0 29 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5 25C14.3533 25 14.2066 24.9622 14.0752 24.8866C13.9325 24.8045 10.5414 22.8419 7.10161 19.8848C5.06289 18.1322 3.4355 16.3939 2.26474 14.7182C0.749726 12.5499 -0.0121446 10.4643 0.000146364 8.51917C0.014533 6.2558 0.827833 4.12725 2.2904 2.52556C3.77767 0.89688 5.76246 0 7.87928 0C10.5922 0 13.0725 1.51475 14.5 3.91429C15.9275 1.5148 18.4079 0 21.1208 0C23.1207 0 25.0287 0.809258 26.4937 2.27873C28.1013 3.89131 29.0148 6.16982 28.9998 8.5299C28.9875 10.4716 28.2113 12.5541 26.693 14.7194C25.5186 16.3942 23.8935 18.1318 21.8627 19.8838C18.4355 22.8407 15.0688 24.8032 14.9271 24.8853C14.7951 24.9617 14.6475 25 14.5 25Z" fill="#6A46F5"/>
</svg>

After

Width:  |  Height:  |  Size: 764 B

@ -0,0 +1,4 @@
<svg width="23" height="36" viewBox="0 0 23 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5555 6.567C15.3689 6.567 16.839 5.09693 16.839 3.2835C16.839 1.47007 15.3689 0 13.5555 0C11.742 0 10.272 1.47007 10.272 3.2835C10.272 5.09693 11.742 6.567 13.5555 6.567Z" fill="#3263B8"/>
<path d="M21.8875 16.0899L17.66 14.6945C17.66 14.6945 15.3205 9.27668 15.2384 9.11251C14.6638 8.08642 13.5967 7.38867 12.3654 7.38867C11.8728 7.38867 11.3803 7.5118 10.9699 7.71702L5.22376 9.97443C4.81332 10.1386 4.48497 10.467 4.3208 10.8774L2.26861 15.8026C1.94026 16.6235 2.30966 17.6086 3.17157 17.9369C3.37679 18.019 3.58201 18.06 3.78723 18.06C4.44393 18.06 5.05959 17.6907 5.30585 17.034L6.98864 12.7654L8.71248 12.1087L5.88046 25.9404L0.380599 32.6306C-0.194014 33.3283 -0.111926 34.3544 0.585818 34.929C0.873124 35.1753 1.24252 35.2984 1.61191 35.2984C2.10444 35.2984 2.55592 35.0932 2.88427 34.6828L8.63039 27.7053C8.79457 27.5001 8.9177 27.2538 8.95874 27.0076L9.94379 22.2465L14.3765 25.4479V33.6567C14.3765 34.5596 15.1153 35.2984 16.0183 35.2984C16.9212 35.2984 17.66 34.5596 17.66 33.6567V24.627C17.66 24.0935 17.4138 23.601 17.0033 23.3136L13.0221 20.3995L14.1303 14.8586L14.9101 16.6646C15.1153 17.075 15.4437 17.4033 15.8951 17.5675L20.8204 19.2093C20.9846 19.2503 21.1487 19.2914 21.354 19.2914C22.0517 19.2914 22.6674 18.8399 22.9136 18.1832C23.2009 17.3213 22.7494 16.3773 21.8875 16.0899Z" fill="#3263B8"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.48916 2.45087C5.77706 2.18304 6.22294 2.18304 6.51084 2.45087L6.51224 2.45218L6.51473 2.4545L6.52292 2.46219L6.55163 2.48944C6.57607 2.51278 6.6109 2.54636 6.65464 2.58935C6.74206 2.67527 6.86535 2.79908 7.01259 2.95413C7.30624 3.26334 7.6993 3.70117 8.09421 4.21395C8.48746 4.72459 8.89375 5.32393 9.20436 5.95598C9.51149 6.58095 9.75 7.28776 9.75 8C9.75 9.28885 9.3037 10.2635 8.54571 10.902C7.80987 11.5219 6.86965 11.75 6 11.75C5.13035 11.75 4.19013 11.5219 3.45429 10.902C2.6963 10.2635 2.25 9.28885 2.25 8C2.25 7.28776 2.48851 6.58095 2.79564 5.95598C3.10625 5.32393 3.51254 4.72459 3.90579 4.21395C4.3007 3.70117 4.69376 3.26334 4.98741 2.95413C5.13465 2.79908 5.25794 2.67527 5.34536 2.58935C5.3891 2.54636 5.42393 2.51278 5.44837 2.48944L5.47708 2.46219L5.48527 2.4545L5.48776 2.45218L5.48916 2.45087Z" fill="#0B85F7"/>
<path d="M17.4892 2.45087C17.7771 2.18304 18.2229 2.18304 18.5108 2.45087L18.5147 2.4545L18.5229 2.46219L18.5516 2.48944C18.5761 2.51278 18.6109 2.54636 18.6546 2.58935C18.7421 2.67527 18.8654 2.79908 19.0126 2.95413C19.3062 3.26334 19.6993 3.70117 20.0942 4.21395C20.4875 4.72459 20.8937 5.32393 21.2044 5.95598C21.5115 6.58095 21.75 7.28776 21.75 8C21.75 9.28885 21.3037 10.2635 20.5457 10.902C19.8099 11.5219 18.8697 11.75 18 11.75C17.1304 11.75 16.1901 11.5219 15.4543 10.902C14.6963 10.2635 14.25 9.28885 14.25 8C14.25 7.28776 14.4885 6.58095 14.7956 5.95598C15.1063 5.32393 15.5125 4.72459 15.9058 4.21395C16.3007 3.70117 16.6938 3.26334 16.9874 2.95413C17.1346 2.79908 17.2579 2.67527 17.3454 2.58935C17.3891 2.54636 17.4239 2.51278 17.4484 2.48944L17.4771 2.46219L17.4853 2.4545L17.4878 2.45218L17.4892 2.45087Z" fill="#0B85F7"/>
<path d="M11.4892 12.4509C11.7771 12.183 12.2229 12.183 12.5108 12.4509L12.5122 12.4522L12.5147 12.4545L12.5229 12.4622L12.5516 12.4894C12.5761 12.5128 12.6109 12.5464 12.6546 12.5893C12.7421 12.6753 12.8654 12.7991 13.0126 12.9541C13.3062 13.2633 13.6993 13.7012 14.0942 14.214C14.4875 14.7246 14.8937 15.3239 15.2044 15.956C15.5115 16.5809 15.75 17.2878 15.75 18C15.75 19.2888 15.3037 20.2635 14.5457 20.902C13.8099 21.5219 12.8697 21.75 12 21.75C11.1303 21.75 10.1901 21.5219 9.45429 20.902C8.6963 20.2635 8.25 19.2888 8.25 18C8.25 17.2878 8.48851 16.5809 8.79564 15.956C9.10625 15.3239 9.51254 14.7246 9.90579 14.214C10.3007 13.7012 10.6938 13.2633 10.9874 12.9541C11.1346 12.7991 11.2579 12.6753 11.3454 12.5893C11.3891 12.5464 11.4239 12.5128 11.4484 12.4894L11.4771 12.4622L11.4853 12.4545L11.4878 12.4522L11.4892 12.4509Z" fill="#0B85F7"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 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="M12.052 1.75H11.948C9.75288 1.74999 8.03639 1.74998 6.69787 1.91195C5.33462 2.0769 4.24953 2.42064 3.38952 3.19465C2.5182 3.97883 2.12077 4.98563 1.93214 6.24835C1.74997 7.46783 1.74998 9.02533 1.75 10.9878L1.75 13.0122C1.74998 14.9746 1.74997 16.5322 1.93214 17.7516C2.12077 19.0144 2.5182 20.0212 3.38952 20.8054C4.24953 21.5794 5.33462 21.9231 6.69787 22.0881C8.03639 22.25 9.75287 22.25 11.948 22.25H12.052C14.2471 22.25 15.9636 22.25 17.3021 22.0881C18.6654 21.9231 19.7505 21.5794 20.6105 20.8054C21.4818 20.0212 21.8792 19.0144 22.0679 17.7516C22.25 16.5322 22.25 14.9747 22.25 13.0123V10.9877C22.25 9.02532 22.25 7.46783 22.0679 6.24835C21.8792 4.98563 21.4818 3.97883 20.6105 3.19465C19.7505 2.42064 18.6654 2.0769 17.3021 1.91195C15.9636 1.74998 14.2471 1.74999 12.052 1.75ZM16.75 6C16.75 5.58579 16.4142 5.25 16 5.25C15.5858 5.25 15.25 5.58579 15.25 6V7.25L14 7.25C13.5858 7.25 13.25 7.58579 13.25 8C13.25 8.41421 13.5858 8.75 14 8.75H15.25V10C15.25 10.4142 15.5858 10.75 16 10.75C16.4142 10.75 16.75 10.4142 16.75 10V8.75H18C18.4142 8.75 18.75 8.41421 18.75 8C18.75 7.58579 18.4142 7.25 18 7.25H16.75V6ZM13.25 17.5C13.25 17.0858 13.5858 16.75 14 16.75H18C18.4142 16.75 18.75 17.0858 18.75 17.5C18.75 17.9142 18.4142 18.25 18 18.25H14C13.5858 18.25 13.25 17.9142 13.25 17.5ZM14 13.75C13.5858 13.75 13.25 14.0858 13.25 14.5C13.25 14.9142 13.5858 15.25 14 15.25H18C18.4142 15.25 18.75 14.9142 18.75 14.5C18.75 14.0858 18.4142 13.75 18 13.75H14ZM10.5303 13.4697C10.8232 13.7626 10.8232 14.2374 10.5303 14.5303L9.31066 15.75L10.5303 16.9697C10.8232 17.2626 10.8232 17.7374 10.5303 18.0303C10.2374 18.3232 9.76256 18.3232 9.46967 18.0303L8.25 16.8107L7.03033 18.0303C6.73744 18.3232 6.26256 18.3232 5.96967 18.0303C5.67678 17.7374 5.67678 17.2626 5.96967 16.9697L7.18934 15.75L5.96967 14.5303C5.67678 14.2374 5.67678 13.7626 5.96967 13.4697C6.26256 13.1768 6.73744 13.1768 7.03033 13.4697L8.25 14.6893L9.46967 13.4697C9.76256 13.1768 10.2374 13.1768 10.5303 13.4697ZM6 7.25C5.58579 7.25 5.25 7.58579 5.25 8C5.25 8.41421 5.58579 8.75 6 8.75L10 8.75C10.4142 8.75 10.75 8.41421 10.75 8C10.75 7.58579 10.4142 7.25 10 7.25L6 7.25Z" fill="#18C273"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 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="M10.2215 4.19823C10.7926 4.06863 11.3878 4 12.0002 4C16.4185 4 20.0002 7.58172 20.0002 12C20.0002 14.0411 19.2363 15.904 17.9769 17.3181V16C17.9769 15.4477 17.5292 15 16.9769 15C16.4246 15 15.9769 15.4477 15.9769 16V19.5C15.9769 20.0523 16.4246 20.5 16.9769 20.5H20.5002C21.0525 20.5 21.5002 20.0523 21.5002 19.5C21.5002 18.9477 21.0525 18.5 20.5002 18.5H19.5996C21.0955 16.7526 22.0002 14.482 22.0002 12C22.0002 6.47715 17.5231 2 12.0002 2C11.2379 2 10.4943 2.08549 9.77893 2.24781C9.24034 2.37002 8.9028 2.90571 9.02501 3.4443C9.14722 3.9829 9.68291 4.32044 10.2215 4.19823Z" fill="#ED1C2B"/>
<path d="M3.5 3.51562C2.94772 3.51562 2.5 3.96334 2.5 4.51562C2.5 5.06791 2.94772 5.51562 3.5 5.51562H4.3873C2.89933 7.26098 2 9.5254 2 12.0001C2 17.5229 6.47715 22.0001 12 22.0001C12.7623 22.0001 13.5059 21.9146 14.2213 21.7523C14.7599 21.6301 15.0974 21.0944 14.9752 20.5558C14.853 20.0172 14.3173 19.6796 13.7787 19.8019C13.2076 19.9314 12.6124 20.0001 12 20.0001C7.58172 20.0001 4 16.4184 4 12.0001C4 9.97161 4.75451 8.11915 6 6.70824L6 8.00008C6 8.55236 6.44772 9.00008 7 9.00008C7.55228 9.00008 8 8.55236 8 8.00008L8 4.51562C8 3.96334 7.55228 3.51562 7 3.51562L3.5 3.51562Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 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="M13.7261 1.30124C13.2614 1.24995 12.6972 1.24998 12.0513 1.25001L11.9543 1.25001C11.3136 1.24992 10.74 1.24984 10.2743 1.30124C9.77418 1.35644 9.2886 1.47932 8.84157 1.79219C8.32719 2.15219 7.98746 2.67118 7.77073 3.256C7.60828 3.69434 7.47147 4.24173 7.31484 4.86839L7.07918 5.81104C7.53006 5.57385 8.04089 5.4428 8.60822 5.36652C7.70812 5.48754 6.95027 5.74644 6.34835 6.34835C5.74644 6.95027 5.48754 7.70814 5.36653 8.60825C5.24997 9.47521 5.24998 10.5775 5.25 11.9451V12.0549C5.24998 13.4224 5.24997 14.5248 5.36653 15.3918C5.48754 16.2919 5.74644 17.0497 6.34835 17.6517C6.57086 17.8742 6.81467 18.0498 7.0791 18.1889L7.31487 19.132C7.47149 19.7586 7.6083 20.306 7.77073 20.7443C7.98746 21.3291 8.32719 21.8481 8.84157 22.2081C9.2886 22.5209 9.77418 22.6438 10.2743 22.699C10.739 22.7503 11.3032 22.7503 11.9491 22.7503H12.0513C12.6972 22.7503 13.2614 22.7503 13.7261 22.699C14.2262 22.6438 14.7118 22.5209 15.1589 22.2081C15.6732 21.8481 16.013 21.3291 16.2297 20.7443C16.3921 20.306 16.5289 19.7586 16.6855 19.132L16.9214 18.1887C17.1856 18.0496 17.4293 17.874 17.6517 17.6517C18.2536 17.0497 18.5125 16.2919 18.6335 15.3918C18.75 14.5248 18.75 13.4225 18.75 12.0549V11.9451C18.75 10.5776 18.75 9.47521 18.6335 8.60825C18.5125 7.70814 18.2536 6.95027 17.6517 6.34835C17.4293 6.12596 17.1856 5.9504 16.9213 5.81131L16.6853 4.86739C16.5288 4.24115 16.3921 3.69411 16.2297 3.256C16.013 2.67118 15.6732 2.15219 15.1589 1.79219C14.7118 1.47932 14.2262 1.35644 13.7261 1.30124ZM14.7323 5.30154C14.5739 4.66885 14.4679 4.25742 14.3543 3.951C14.211 3.5642 14.1259 3.50722 14.0377 3.44819C14.0292 3.4425 14.0207 3.43677 14.0121 3.43074C13.9426 3.38216 13.8252 3.32432 13.5067 3.28916C13.1648 3.25143 12.7121 3.25002 12.0002 3.25002C11.2883 3.25002 10.8356 3.25143 10.4938 3.28916C10.1752 3.32432 10.0578 3.38216 9.98837 3.43074C9.97975 3.43677 9.97122 3.44248 9.96272 3.44818C9.87454 3.50722 9.78944 3.5642 9.64609 3.951C9.53254 4.25741 9.42652 4.66884 9.26813 5.3015C10.0153 5.24997 10.9032 5.24999 11.9451 5.25H12.0549C13.0969 5.24999 13.985 5.24997 14.7323 5.30154ZM8.60823 18.6335C8.60822 18.6335 8.60823 18.6335 8.60823 18.6335V18.6335ZM9.26806 18.6985C9.42649 19.3313 9.53252 19.7428 9.64609 20.0493C9.78944 20.4361 9.87453 20.493 9.9627 20.5521C9.97114 20.5577 9.97981 20.5635 9.98836 20.5695C10.0578 20.6181 10.1752 20.6759 10.4938 20.7111C10.8356 20.7488 11.2883 20.7503 12.0002 20.7503C12.7121 20.7503 13.1648 20.7488 13.5067 20.7111C13.8252 20.6759 13.9426 20.6181 14.0121 20.5695L14.0251 20.5606L14.0377 20.5521C14.1259 20.493 14.211 20.4361 14.3543 20.0493C14.4679 19.7428 14.5739 19.3313 14.7324 18.6985C13.9851 18.75 13.097 18.75 12.0549 18.75M12 9C12.5523 9 13 9.44772 13 10L13 11.5893L13.7053 12.2911C14.0968 12.6807 14.0984 13.3138 13.7089 13.7053C13.3193 14.0968 12.6862 14.0984 12.2947 13.7089L11.2947 12.7139C11.1061 12.5262 11 12.2711 11 12.005L11 10C11 9.44772 11.4477 9 12 9Z" fill="#FFB027"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

@ -71,6 +71,8 @@
<string>This app requires contacts access to show incoming virtual consultation request.</string>
<key>NSFaceIDUsageDescription</key>
<string>This app requires Face ID to allow biometric authentication for app login.</string>
<key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
<string>This App need access to HealthKit to read heart rate &amp; other data from your smart watch.</string>
<key>NSHealthShareUsageDescription</key>
<string>This App need access to HealthKit to read heart rate &amp; other data from your smart watch.</string>
<key>NSHealthUpdateUsageDescription</key>

@ -4,6 +4,14 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.healthkit</key>
<true/>
<key>com.apple.developer.healthkit.access</key>
<array>
<string>health-records</string>
</array>
<key>com.apple.developer.healthkit.background-delivery</key>
<true/>
<key>com.apple.developer.in-app-payments</key>
<array>
<string>merchant.com.hmgwebservices</string>

@ -202,6 +202,10 @@ class AppAssets {
static const String insurance_approval_icon = '$svgBasePath/insurance_approval_icon.svg';
static const String invoices_list_icon = '$svgBasePath/invoices_list_icon.svg';
static const String ancillary_orders_list_icon = '$svgBasePath/ancillary_orders_list_icon.svg';
static const String daily_water_monitor_icon = '$svgBasePath/daily_water_monitor.svg';
static const String health_calculators_services_icon = '$svgBasePath/health_calculators_services_icon.svg';
static const String health_converters_icon = '$svgBasePath/health_converters_icon.svg';
static const String smartwatch_icon = '$svgBasePath/smartwatch_icon.svg';
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';

@ -39,6 +39,7 @@ import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_mo
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_repo.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_repo.dart';
@ -232,6 +233,10 @@ class AppDependencies {
() => BloodDonationViewModel(bloodDonationRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt()),
);
getIt.registerLazySingleton<HealthProvider>(
() => HealthProvider(),
);
// Screen-specific VMs Factory
// getIt.registerFactory<BookAppointmentsViewModel>(
// () => BookAppointmentsViewModel(

@ -0,0 +1,85 @@
import 'package:flutter/foundation.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_service.dart';
class HealthProvider with ChangeNotifier {
final HealthService _healthService = HealthService();
Map<HealthDataType, List<HealthDataPoint>> healthData = {};
bool isLoading = false;
String? error;
String selectedTimeRange = '7D';
int selectedTabIndex = 0;
void onTabChanged(int index) {
selectedTabIndex = index;
notifyListeners();
}
Future<void> fetchHealthData() async {
isLoading = true;
error = null;
notifyListeners();
healthData.clear();
try {
final authorized = await _healthService.requestAuthorization();
if (!authorized) {
error = 'Health data access not authorized';
isLoading = false;
notifyListeners();
return;
}
final startTime = _getStartDate();
final endTime = DateTime.now();
healthData = await _healthService.getAllHealthData(startTime, endTime);
isLoading = false;
notifyListeners();
} catch (e) {
error = 'Error fetching health data: $e';
isLoading = false;
notifyListeners();
}
}
Future<void> refreshMetric(HealthDataType type) async {
try {
final startTime = _getStartDate();
final endTime = DateTime.now();
final data = await _healthService.getSpecificHealthData(
type,
startTime,
endTime,
);
healthData[type] = data;
notifyListeners();
} catch (e) {
print('Error refreshing metric $type: $e');
}
}
void updateTimeRange(String range) {
selectedTimeRange = range;
fetchHealthData();
}
DateTime _getStartDate() {
switch (selectedTimeRange) {
case '1D':
return DateTime.now().subtract(const Duration(days: 1));
case '7D':
return DateTime.now().subtract(const Duration(days: 7));
case '1M':
return DateTime.now().subtract(const Duration(days: 30));
case '3M':
return DateTime.now().subtract(const Duration(days: 90));
case '1Y':
return DateTime.now().subtract(const Duration(days: 365));
default:
return DateTime.now().subtract(const Duration(days: 7));
}
}
}

@ -0,0 +1,166 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:health/health.dart';
import 'package:permission_handler/permission_handler.dart';
import 'health_utils.dart';
class HealthService {
static final HealthService _instance = HealthService._internal();
factory HealthService() => _instance;
HealthService._internal();
final Health health = Health();
final List<HealthDataType> _healthMetrics = [
HealthDataType.HEART_RATE,
// HealthDataType.STEPS,
// HealthDataType.BLOOD_OXYGEN,
// HealthDataType.BLOOD_PRESSURE_SYSTOLIC,
// HealthDataType.BLOOD_PRESSURE_DIASTOLIC,
// HealthDataType.BODY_TEMPERATURE,
// HealthDataType.DISTANCE_WALKING_RUNNING,
// HealthDataType.ACTIVE_ENERGY_BURNED,
];
final List<HealthDataType> _healthMetricsAndroid = [
HealthDataType.HEART_RATE,
HealthDataType.STEPS,
HealthDataType.BLOOD_OXYGEN,
// HealthDataType.BLOOD_PRESSURE_SYSTOLIC,
// HealthDataType.BLOOD_PRESSURE_DIASTOLIC,
// HealthDataType.BODY_TEMPERATURE,
HealthDataType.DISTANCE_DELTA,
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.BASAL_ENERGY_BURNED,
HealthDataType.TOTAL_CALORIES_BURNED
];
final List<HealthDataType> _healthPermissions = [
HealthDataType.HEART_RATE,
HealthDataType.STEPS,
HealthDataType.BLOOD_OXYGEN,
// HealthDataType.BLOOD_PRESSURE_SYSTOLIC,
// HealthDataType.BLOOD_PRESSURE_DIASTOLIC,
// HealthDataType.BODY_TEMPERATURE,
Platform.isAndroid ? HealthDataType.DISTANCE_DELTA : HealthDataType.DISTANCE_WALKING_RUNNING,
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.BASAL_ENERGY_BURNED,
HealthDataType.TOTAL_CALORIES_BURNED
];
final List<HealthDataType> _healthMetricsCumulative = [
HealthDataType.BLOOD_OXYGEN,
HealthDataType.STEPS,
Platform.isAndroid ? HealthDataType.DISTANCE_DELTA : HealthDataType.DISTANCE_WALKING_RUNNING,
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.BASAL_ENERGY_BURNED,
HealthDataType.TOTAL_CALORIES_BURNED
];
Future<bool> requestAuthorization() async {
try {
final types = (Platform.isAndroid) ? dataTypesAndroid : _healthPermissions;
final granted = await health.requestAuthorization(types);
await Permission.activityRecognition.request();
await Permission.location.request();
// request access to read historic data
await Health().requestHealthDataHistoryAuthorization();
// await authorize();
return granted;
} catch (e) {
print('Authorization error: $e');
return false;
}
}
Future<Map<HealthDataType, List<HealthDataPoint>>> getAllHealthData(
DateTime startTime,
DateTime endTime,
) async {
final Map<HealthDataType, List<HealthDataPoint>> allData = {};
try {
for (var type in _healthMetricsCumulative) {
try {
final data = await health.getHealthIntervalDataFromTypes(
startDate: startTime,
endDate: endTime,
types: [type],
interval: 86400,
);
if (type == HealthDataType.BLOOD_OXYGEN) {
for (var point in data) {
if (point.value is NumericHealthValue) {
final numericValue = (point.value as NumericHealthValue).numericValue;
point.value = NumericHealthValue(
numericValue: numericValue * 100,
);
}
}
}
if (type == HealthDataType.DISTANCE_WALKING_RUNNING) {
for (var point in data) {
if (point.value is NumericHealthValue) {
final numericValue = (point.value as NumericHealthValue).numericValue;
point.value = NumericHealthValue(
numericValue: numericValue / 1000,
);
}
}
}
allData[type] = data;
} catch (e) {
print('Error fetching $type: $e');
allData[type] = [];
}
}
for (var type in Platform.isIOS ? _healthMetrics : _healthMetricsAndroid) {
try {
final data = await health.getHealthDataFromTypes(
startTime: startTime,
endTime: endTime,
types: [type],
// includeManualEntry: false
// interval: 86400,
);
allData[type] = data;
} catch (e) {
print('Error fetching $type: $e');
allData[type] = [];
}
}
} catch (e) {
print('Error fetching health data: $e');
}
return allData;
}
Future<List<HealthDataPoint>> getSpecificHealthData(
HealthDataType type,
DateTime startTime,
DateTime endTime,
) async {
try {
final data = await health.getHealthDataFromTypes(
startTime: startTime,
endTime: endTime,
types: [type],
);
return data;
} catch (e) {
print('Error fetching $type: $e');
return [];
}
}
}

@ -0,0 +1,109 @@
import 'package:health/health.dart';
/// Data types available on iOS via Apple Health.
const List<HealthDataType> dataTypesIOS = [
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.APPLE_STAND_TIME,
HealthDataType.APPLE_STAND_HOUR,
HealthDataType.APPLE_MOVE_TIME,
HealthDataType.AUDIOGRAM,
HealthDataType.BASAL_ENERGY_BURNED,
HealthDataType.BLOOD_GLUCOSE,
HealthDataType.BLOOD_OXYGEN,
HealthDataType.BLOOD_PRESSURE_DIASTOLIC,
HealthDataType.BLOOD_PRESSURE_SYSTOLIC,
HealthDataType.BODY_FAT_PERCENTAGE,
HealthDataType.BODY_MASS_INDEX,
HealthDataType.BODY_TEMPERATURE,
HealthDataType.DIETARY_CARBS_CONSUMED,
HealthDataType.DIETARY_CAFFEINE,
HealthDataType.DIETARY_ENERGY_CONSUMED,
HealthDataType.DIETARY_FATS_CONSUMED,
HealthDataType.DIETARY_PROTEIN_CONSUMED,
HealthDataType.ELECTRODERMAL_ACTIVITY,
HealthDataType.FORCED_EXPIRATORY_VOLUME,
HealthDataType.HEART_RATE,
HealthDataType.HEART_RATE_VARIABILITY_SDNN,
HealthDataType.HEIGHT,
HealthDataType.INSULIN_DELIVERY,
HealthDataType.RESPIRATORY_RATE,
HealthDataType.PERIPHERAL_PERFUSION_INDEX,
HealthDataType.STEPS,
HealthDataType.WAIST_CIRCUMFERENCE,
HealthDataType.WEIGHT,
HealthDataType.FLIGHTS_CLIMBED,
HealthDataType.DISTANCE_WALKING_RUNNING,
HealthDataType.WALKING_SPEED,
HealthDataType.MINDFULNESS,
HealthDataType.SLEEP_AWAKE,
HealthDataType.SLEEP_ASLEEP,
HealthDataType.SLEEP_IN_BED,
HealthDataType.SLEEP_LIGHT,
HealthDataType.SLEEP_DEEP,
HealthDataType.SLEEP_REM,
HealthDataType.WATER,
HealthDataType.EXERCISE_TIME,
HealthDataType.WORKOUT,
HealthDataType.HEADACHE_NOT_PRESENT,
HealthDataType.HEADACHE_MILD,
HealthDataType.HEADACHE_MODERATE,
HealthDataType.HEADACHE_SEVERE,
HealthDataType.HEADACHE_UNSPECIFIED,
HealthDataType.LEAN_BODY_MASS,
// note that a phone cannot write these ECG-based types - only read them
// HealthDataType.ELECTROCARDIOGRAM,
// HealthDataType.HIGH_HEART_RATE_EVENT,
// HealthDataType.IRREGULAR_HEART_RATE_EVENT,
// HealthDataType.LOW_HEART_RATE_EVENT,
// HealthDataType.RESTING_HEART_RATE,
// HealthDataType.WALKING_HEART_RATE,
// HealthDataType.ATRIAL_FIBRILLATION_BURDEN,
HealthDataType.NUTRITION,
HealthDataType.GENDER,
HealthDataType.BLOOD_TYPE,
HealthDataType.BIRTH_DATE,
HealthDataType.MENSTRUATION_FLOW,
HealthDataType.WATER_TEMPERATURE,
HealthDataType.UNDERWATER_DEPTH,
HealthDataType.UV_INDEX,
];
/// Data types available on Android via the Google Health Connect API.
const List<HealthDataType> dataTypesAndroid = [
HealthDataType.ACTIVE_ENERGY_BURNED,
// HealthDataType.BASAL_ENERGY_BURNED,
// HealthDataType.BLOOD_GLUCOSE,
HealthDataType.BLOOD_OXYGEN,
// HealthDataType.BLOOD_PRESSURE_DIASTOLIC,
// HealthDataType.BLOOD_PRESSURE_SYSTOLIC,
// HealthDataType.BODY_FAT_PERCENTAGE,
// HealthDataType.HEIGHT,
// HealthDataType.WEIGHT,
// HealthDataType.LEAN_BODY_MASS,
// HealthDataType.BODY_MASS_INDEX,
// HealthDataType.BODY_TEMPERATURE,
HealthDataType.HEART_RATE,
// HealthDataType.HEART_RATE_VARIABILITY_RMSSD,
HealthDataType.STEPS,
HealthDataType.DISTANCE_DELTA,
// HealthDataType.SPEED,
HealthDataType.RESPIRATORY_RATE,
// HealthDataType.SLEEP_ASLEEP,
// HealthDataType.SLEEP_AWAKE_IN_BED,
// HealthDataType.SLEEP_AWAKE,
// HealthDataType.SLEEP_DEEP,
// HealthDataType.SLEEP_LIGHT,
// HealthDataType.SLEEP_OUT_OF_BED,
// HealthDataType.SLEEP_REM,
// HealthDataType.SLEEP_UNKNOWN,
// HealthDataType.SLEEP_SESSION,
// HealthDataType.WATER,
// HealthDataType.WORKOUT,
HealthDataType.RESTING_HEART_RATE,
// HealthDataType.FLIGHTS_CLIMBED,
// HealthDataType.NUTRITION,
HealthDataType.TOTAL_CALORIES_BURNED,
// HealthDataType.MENSTRUATION_FLOW,
];

@ -28,6 +28,7 @@ import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
@ -153,6 +154,9 @@ void main() async {
),
ChangeNotifierProvider<BloodDonationViewModel>(
create: (_) => getIt.get<BloodDonationViewModel>(),
),
ChangeNotifierProvider<HealthProvider>(
create: (_) => getIt.get<HealthProvider>(),
)
], child: MyApp()),
),

@ -118,6 +118,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
: myAppointmentsVM.patientMyDoctorsList.isEmpty
? SizedBox()
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (appState.isAuthenticated) ...[],
"Recent Visits".needTranslation.toText18(isBold: true).paddingSymmetrical(24.w, 0.h),

@ -120,6 +120,45 @@ class ServicesPage extends StatelessWidget {
// )
];
late final List<HmgServicesComponentModel> hmgHealthToolServices = [
HmgServicesComponentModel(
11,
"Daily Water Monitor".needTranslation,
"".needTranslation,
AppAssets.daily_water_monitor_icon,
bgColor: AppColors.whiteColor,
true,
route: AppRoutes.eReferralPage,
),
HmgServicesComponentModel(
11,
"Health\nCalculators".needTranslation,
"".needTranslation,
AppAssets.health_calculators_services_icon,
bgColor: AppColors.whiteColor,
true,
route: AppRoutes.eReferralPage,
),
HmgServicesComponentModel(
5,
"Health\nConverters".needTranslation,
"".needTranslation,
AppAssets.health_converters_icon,
bgColor: AppColors.whiteColor,
true,
route: AppRoutes.comprehensiveCheckupPage,
),
HmgServicesComponentModel(
11,
"Smart\nWatches".needTranslation,
"".needTranslation,
AppAssets.smartwatch_icon,
bgColor: AppColors.whiteColor,
true,
route: AppRoutes.smartWatches,
),
];
@override
Widget build(BuildContext context) {
bloodDonationViewModel = Provider.of<BloodDonationViewModel>(context);
@ -149,7 +188,7 @@ class ServicesPage extends StatelessWidget {
itemCount: hmgServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
return ServiceGridViewItem(hmgServices[index], index, false);
return ServiceGridViewItem(hmgServices[index], index, false, isHealthToolIcon: false);
},
),
SizedBox(height: 24.h),
@ -298,6 +337,29 @@ class ServicesPage extends StatelessWidget {
],
),
SizedBox(height: 24.h),
"Health Tools".needTranslation.toText18(isBold: true),
SizedBox(height: 16.h),
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4, // 4 icons per row
crossAxisSpacing: 12.w,
mainAxisSpacing: 18.h,
childAspectRatio: 0.8,
),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: hmgHealthToolServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
return ServiceGridViewItem(
hmgHealthToolServices[index],
index,
false,
isHealthToolIcon: true,
);
},
),
SizedBox(height: 24.h),
"Support Services".needTranslation.toText18(isBold: true),
SizedBox(height: 16.h),
Column(

@ -13,8 +13,10 @@ class ServiceGridViewItem extends StatelessWidget {
final int index;
final bool isHomePage;
final bool isLocked;
final bool isHealthToolIcon;
final Function? onTap;
const ServiceGridViewItem(this.hmgServiceComponentModel, this.index, this.isHomePage, {super.key, this.isLocked = false, this.onTap});
const ServiceGridViewItem(this.hmgServiceComponentModel, this.index, this.isHomePage, {super.key, this.isLocked = false, this.onTap, this.isHealthToolIcon = false});
@override
Widget build(BuildContext context) {
@ -42,7 +44,7 @@ class ServiceGridViewItem extends StatelessWidget {
padding: EdgeInsets.all(12.h),
child: Utils.buildSvgWithAssets(
icon: hmgServiceComponentModel.icon,
iconColor: AppColors.whiteColor,
iconColor: isHealthToolIcon ? null : AppColors.whiteColor,
fit: BoxFit.contain,
),
),

@ -0,0 +1,422 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/widgets/health_metric.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/widgets/health_metric_card.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/custom_tab_bar.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import 'package:health/health.dart';
import 'package:intl/intl.dart';
class HealthDashboard extends StatefulWidget {
const HealthDashboard({Key? key}) : super(key: key);
@override
_HealthDashboardState createState() => _HealthDashboardState();
}
class _HealthDashboardState extends State<HealthDashboard> with SingleTickerProviderStateMixin {
late TabController _tabController;
final dateFormat = DateFormat('MMM dd, yyyy');
final timeFormat = DateFormat('hh:mm a');
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
Future.microtask(
() async {
await Health().configure();
context.read<HealthProvider>().fetchHealthData();
},
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<HealthProvider>(
builder: (context, healthProvider, child) {
return SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 96.h),
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [
CustomTabBarModel(null, "Overview".needTranslation),
CustomTabBarModel(null, "Details".needTranslation),
],
onTabChange: (index) {
healthProvider.onTabChanged(index);
},
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
getSelectedTabData(healthProvider.selectedTabIndex, healthProvider).paddingSymmetrical(24.w, 0),
],
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<HealthProvider>().fetchHealthData(),
tooltip: 'Refresh health data',
child: Icon(Icons.refresh),
),
);
}
Widget getSelectedTabData(int index, HealthProvider healthProvider) {
switch (index) {
case 0:
return _buildOverviewTab(healthProvider);
case 1:
return _buildDetailsTab(healthProvider);
default:
SizedBox.shrink();
}
return Container();
}
Widget _buildOverviewTab(HealthProvider healthProvider) {
if (healthProvider.isLoading) {
return _buildLoadingState();
}
if (healthProvider.error != null) {
return _buildErrorState(healthProvider.error!);
}
return CustomScrollView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: _buildTimeRangeSelector(healthProvider),
),
SliverPadding(
padding: EdgeInsets.symmetric(vertical: 12.w),
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: 0.62,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
final metric = HealthMetrics.metrics[index];
return HealthMetricCard(
metric: metric,
data: healthProvider.healthData[metric.type] ?? [],
onTap: () => _showMetricDetails(context, metric, healthProvider),
);
},
childCount: HealthMetrics.metrics.length,
),
),
),
],
);
}
Widget _buildDetailsTab(HealthProvider healthProvider) {
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: HealthMetrics.metrics.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final metric = HealthMetrics.metrics[index];
final data = healthProvider.healthData[metric.type] ?? [];
return Card(
color: AppColors.whiteColor,
margin: EdgeInsets.only(bottom: 16),
child: ExpansionTile(
leading: Icon(
metric.icon,
color: metric.color,
size: 32.h,
),
// title: Text(metric.name),
title: (getIt.get<AppState>().isArabic() ? metric.nameAr : metric.nameEn).toText14(isBold: true),
subtitle: Text(
data.isEmpty ? LocaleKeys.noDataAvailable.tr(context: context) : '${_getValueAsDouble(data.last.value, metric.type).toStringAsFixed(1)} ${metric.unit}',
),
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
metric.description.toText13(),
SizedBox(height: 16.h),
if (data.isNotEmpty) ...[
Text(
'History',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 8),
...data.reversed
.take(5)
.map((point) => Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
dateFormat.format(point.dateFrom),
style: TextStyle(color: Colors.grey[600]),
),
Text(
'${_getValueAsDouble(point.value, metric.type).toStringAsFixed(1)} ${metric.unit}',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
))
.toList(),
],
],
),
),
],
),
);
},
);
}
Widget _buildTimeRangeSelector(HealthProvider provider) {
return Container(
height: 40,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
for (final range in ['1D', '7D', '1M', '3M', '1Y'])
Padding(
padding: const EdgeInsets.only(right: 8),
child: ChoiceChip(
label: Text(range),
labelStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
checkmarkColor: AppColors.primaryRedColor,
selected: provider.selectedTimeRange == range,
selectedColor: AppColors.secondaryLightRedColor,
onSelected: (selected) {
if (selected) {
provider.updateTimeRange(range);
}
},
),
),
],
),
);
}
Widget _buildLoadingState() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Loading health data...'),
],
),
);
}
Widget _buildErrorState(String error) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
size: 48,
color: Colors.red,
),
SizedBox(height: 16),
Text(
'Error loading health data',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
error,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey[600]),
),
SizedBox(height: 24),
ElevatedButton(
onPressed: () => context.read<HealthProvider>().fetchHealthData(),
child: Text('Try Again'),
),
],
),
);
}
void _showMetricDetails(
BuildContext context,
HealthMetricInfo metric,
HealthProvider provider,
) {
final data = provider.healthData[metric.type] ?? [];
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) => DraggableScrollableSheet(
initialChildSize: 0.7,
minChildSize: 0.5,
maxChildSize: 0.95,
expand: false,
builder: (context, scrollController) => Container(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
width: 40,
height: 4,
margin: EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(2),
),
),
),
Row(
children: [
Icon(metric.icon, color: metric.color, size: 30),
SizedBox(width: 16),
(getIt.get<AppState>().isArabic() ? metric.nameAr : metric.nameEn).toText24(isBold: true),
// Text(
// metric.name,
// style: TextStyle(
// fontSize: 24,
// fontWeight: FontWeight.bold,
// ),
// ),
],
),
SizedBox(height: 16),
Text(
metric.description,
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
),
SizedBox(height: 24),
Text(
'Healthy Range',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
'${metric.minHealthyValue} - ${metric.maxHealthyValue} ${metric.unit}'.toText16(isBold: true, color: AppColors.primaryRedColor),
// Text(
// '${metric.minHealthyValue} - ${metric.maxHealthyValue} ${metric.unit}',
// style: TextStyle(
// color: mainPurple,
// fontSize: 16,
// ),
// ),
SizedBox(height: 24),
if (data.isNotEmpty) ...[
Text(
'History',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
Expanded(
child: ListView.builder(
controller: scrollController,
itemCount: data.length,
itemBuilder: (context, index) {
final point = data[data.length - 1 - index];
final value = _getValueAsDouble(point.value, metric.type);
return Card(
child: ListTile(
title: Text(
'${value.toStringAsFixed(1)} ${metric.unit}',
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(
// dateFormat.format(point.dateFrom),
Utils.getMonthDayYearDateFormatted(point.dateFrom)
// dateFormat.format(point.dateFrom),
),
trailing: Icon(
value >= metric.minHealthyValue && value <= metric.maxHealthyValue ? Icons.check_circle : Icons.warning,
color: value >= metric.minHealthyValue && value <= metric.maxHealthyValue ? AppColors.textColor : Colors.orange,
),
),
);
},
),
),
] else
Center(
child: Text(
'No data available',
style: TextStyle(color: Colors.grey[600]),
),
),
],
),
),
),
);
}
// Add this helper method to the _HealthDashboardState class
double _getValueAsDouble(HealthValue value, HealthDataType type) {
if (value is NumericHealthValue) {
// if(type == HealthDataType.BLOOD_OXYGEN) {
// return (value.numericValue.toDouble() * 100);
// } else {
return value.numericValue.toDouble();
// }
}
return 0.0;
}
}

@ -0,0 +1,464 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/health_dashboard/health_dashboard.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class SmartwatchInstructionsPage extends StatelessWidget {
const SmartwatchInstructionsPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.smartWatches.tr(),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h),
child: SingleChildScrollView(
child: Platform.isIOS ? getIOSInstructionsUI(context) : getAndroidInstructionsUI(context),
),
),
),
);
}
Widget getAndroidInstructionsUI(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Supported Smart Watches".needTranslation.toText20(isBold: true),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/galaxy_watch_ultra.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Galaxy Watch Ultra", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Galaxy Watch 8 Classic", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
],
),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/galaxy_watch_8.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Galaxy Watch 8", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/galaxy_watch_7_classic.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Galaxy Watch 7 Classic", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/galaxy_watch_7.webp", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Galaxy Watch 7", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/galaxy_fit_3.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Galaxy Fit3", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
],
),
),
SizedBox(height: 12),
"Please make sure that your Samsung Watch is connected to your Phone, is actively synced & updated.".needTranslation.toText14(isBold: true),
SizedBox(height: 12),
"Before syncing data, please make sure that you have followed the instructions properly.".needTranslation.toText14(isBold: true),
SizedBox(height: 12),
InkWell(
onTap: () {
showInstructionsDialog(context);
},
child: "View watch instructions".needTranslation.toText12(isBold: true, color: AppColors.textColor, isUnderLine: true)),
SizedBox(
height: 130.h,
),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
await Health().getHealthConnectSdkStatus().then((val) {
print('Health Connect SDK Status: $val');
if (val == HealthConnectSdkStatus.sdkAvailable) {
// Navigator.of(context).push(
// FadePage(
// page: HealthDashboard(), // Replace with the actual vital signs page
// // page: HealthApp(), // Replace with the actual vital signs page
// ),
// );
} else {
// Utils.showAppDialog(context, LocaleKeys.error.tr(context: context), LocaleKeys.healthConnectNotInstalled.tr(), () {
// Navigator.pop(context);
// Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata");
// launchUrl(uri, mode: LaunchMode.externalApplication);
// });
// return;
}
});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
),
// DefaultButton(
// LocaleKeys.confirm.tr(context: context),
// () async {
// await Health().getHealthConnectSdkStatus().then((val) {
// print('Health Connect SDK Status: $val');
// if (val == HealthConnectSdkStatus.sdkAvailable) {
// Navigator.of(context).push(
// FadePage(
// page: HealthDashboard(), // Replace with the actual vital signs page
// // page: HealthApp(), // Replace with the actual vital signs page
// ),
// );
// } else {
// Utils.showAppDialog(context, LocaleKeys.error.tr(context: context), LocaleKeys.healthConnectNotInstalled.tr(), () {
// Navigator.pop(context);
// Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata");
// launchUrl(uri, mode: LaunchMode.externalApplication);
// });
// return;
// }
// });
// },
// )
],
);
}
Widget getIOSInstructionsUI(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Supported Smart Watches".needTranslation.toText20(isBold: true),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/apple-watch-1.jpeg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Apple Watch Series 5", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/apple-watch-2.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Apple Watch Series 6", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
],
),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/apple-watch-3.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Apple Watch Series 7", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/apple-watch-4.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Apple Watch Series 8", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/apple-watch-5.jpg", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Apple Watch Series 9", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 15.0),
child: Row(
children: [
Image.asset("assets/images/png/smartwatches/Apple-Watch-6.png", width: 70.0, height: 70.0),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.21,
child: Text("Apple Watch Series 10", overflow: TextOverflow.clip, style: TextStyle(fontSize: 12.0)),
),
)
],
),
),
),
],
),
),
SizedBox(height: 12),
"Please make sure that your Apple Watch is connected to your iPhone, is actively synced & updated.".toText14(isBold: true),
SizedBox(height: 12),
"Before syncing data, please make sure that you have followed the instructions properly.".toText14(isBold: true),
SizedBox(height: 12),
InkWell(
onTap: () {
showInstructionsDialog(context);
},
child: "View watch instructions".toText12(isBold: true, color: AppColors.textColor, isUnderLine: true),
),
SizedBox(
height: 130.h,
),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).push(
CustomPageRoute(
page: HealthDashboard(),
),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
),
],
);
}
showInstructionsDialog(BuildContext context) {
showGeneralDialog(
barrierColor: Colors.black.withOpacity(0.5),
transitionBuilder: (context, a1, a2, widget) {
final curvedValue = Curves.easeInOutBack.transform(a1.value) - 1.0;
return Transform(
transform: Matrix4.translationValues(0.0, curvedValue * 200, 0.0),
child: Opacity(
opacity: a1.value,
child: Dialog(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 350.0,
padding: EdgeInsets.all(21),
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"SmartWatch Tracker".toText18(),
IconButton(
icon: Icon(
Icons.close,
color: Color(0xff2E303A),
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(Platform.isIOS
? "Make sure that you have installed 'Health' App & 'Watch' App from Apple Store."
: "Please make sure that your Samsung Watch is connected to your Phone, is actively synced & updated.")
.needTranslation
.toText14(),
SizedBox(height: 12),
],
)
],
),
),
],
),
),
),
);
},
transitionDuration: Duration(milliseconds: 500),
barrierDismissible: true,
barrierLabel: '',
context: context,
pageBuilder: (context, animation1, animation2) {
return SizedBox();
//Chanbged By Aamir
});
}
}

@ -0,0 +1,87 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
class HealthChart extends StatelessWidget {
final List<FlSpot> spots;
final String title;
final Color gradientColor;
const HealthChart({
Key? key,
required this.spots,
required this.title,
required this.gradientColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 200,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(0, 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Expanded(
child: LineChart(
LineChartData(
gridData: FlGridData(show: false),
titlesData: FlTitlesData(show: false),
borderData: FlBorderData(show: false),
minX: 0,
maxX: spots.length.toDouble() - 1,
minY: spots.map((e) => e.y).reduce((a, b) => a < b ? a : b),
maxY: spots.map((e) => e.y).reduce((a, b) => a > b ? a : b),
lineBarsData: [
LineChartBarData(
spots: spots,
isCurved: true,
gradient: LinearGradient(
colors: [
gradientColor.withOpacity(0.5),
gradientColor,
],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(show: false),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
gradientColor.withOpacity(0.1),
gradientColor.withOpacity(0.2),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
],
),
),
),
],
),
);
}
}

@ -0,0 +1,97 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class HealthMetricInfo {
final HealthDataType type;
final String nameEn;
final String nameAr;
final String unit;
final Color color;
final IconData icon;
final String description;
final double minHealthyValue;
final double maxHealthyValue;
final String svgIcon;
const HealthMetricInfo(
{required this.type,
required this.nameEn,
required this.nameAr,
required this.unit,
required this.color,
required this.icon,
required this.description,
required this.minHealthyValue,
required this.maxHealthyValue,
required this.svgIcon});
}
class HealthMetrics {
static final metrics = [
HealthMetricInfo(
type: HealthDataType.HEART_RATE,
nameEn: "Heart Rate",
nameAr: "معدل النبض",
unit: 'BPM',
color: AppColors.primaryRedColor,
icon: Icons.favorite,
description: "Your heart rate indicates how many times your heart beats per minute".needTranslation,
minHealthyValue: 60,
maxHealthyValue: 100,
svgIcon: "assets/images/smartwatches/heartrate_icon.svg"),
HealthMetricInfo(
type: HealthDataType.BLOOD_OXYGEN,
nameEn: "Blood Oxygen",
nameAr: "أكسجين الدم",
unit: '%',
// color: Colors.blue,
color: Color(0xff3A3558),
icon: Icons.air,
description: "Blood oxygen level indicates how much oxygen your red blood cells are carrying".needTranslation,
minHealthyValue: 95,
maxHealthyValue: 100,
svgIcon: "assets/images/smartwatches/bloodoxygen_icon.svg"),
HealthMetricInfo(
type: HealthDataType.STEPS,
nameEn: "Steps",
nameAr: "خطوات",
unit: 'steps',
// color: Colors.green,
color: Color(0xff3263B8),
icon: Icons.directions_walk,
description: "Number of steps taken throughout the day".needTranslation,
minHealthyValue: 7000,
maxHealthyValue: 15000,
svgIcon: "assets/images/smartwatches/steps_icon.svg"),
HealthMetricInfo(
type: Platform.isIOS ? HealthDataType.ACTIVE_ENERGY_BURNED : HealthDataType.TOTAL_CALORIES_BURNED,
nameEn: "Active Calories",
nameAr: "السعرات الحرارية النشطة",
unit: 'kcal',
color: Color(0xffD59E95),
icon: Icons.local_fire_department,
description: "Calories burned during physical activity".needTranslation,
minHealthyValue: 300,
maxHealthyValue: 1000,
svgIcon: "assets/images/smartwatches/calories_icon.svg"),
HealthMetricInfo(
type: Platform.isIOS ? HealthDataType.DISTANCE_WALKING_RUNNING : HealthDataType.DISTANCE_DELTA,
nameEn: "Distance Covered",
nameAr: "المسافة المغطاة",
unit: 'KMs',
// color: mainPurple,
color: Color(0xff6A46F5),
icon: Icons.directions_run,
description: "Distance covered throughout the day".needTranslation,
minHealthyValue: 3,
maxHealthyValue: 10,
svgIcon: "assets/images/smartwatches/distance_icon.svg"),
// Add more metrics as needed
];
}

@ -0,0 +1,151 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:health/health.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/widgets/health_metric.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class HealthMetricCard extends StatelessWidget {
final HealthMetricInfo metric;
final List<HealthDataPoint> data;
final VoidCallback onTap;
const HealthMetricCard({
Key? key,
required this.metric,
required this.data,
required this.onTap,
}) : super(key: key);
// Helper method to convert HealthValue to double
double _getValueAsDouble(HealthValue value, HealthDataType type) {
if (value is NumericHealthValue) {
return value.numericValue.toDouble();
}
return 0.0;
}
@override
Widget build(BuildContext context) {
final latestValue = data.isNotEmpty ? _getValueAsDouble(data.last.value, data.last.type) : 0.0;
final isHealthy = latestValue >= metric.minHealthyValue && latestValue <= metric.maxHealthyValue;
return Card(
color: AppColors.whiteColor,
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(20),
child: Container(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
metric.svgIcon,
height: 30.h,
width: 30.h,
fit: BoxFit.contain,
// color: color,
),
// Icon(
// metric.icon,
// color: metric.color,
// size: 30,
// ),
if (data.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: isHealthy ? Colors.green[100] : Color(0xffD7D2F3),
borderRadius: BorderRadius.circular(12),
),
child: Text(
isHealthy ? "Healthy".needTranslation : 'Warning'.needTranslation,
style: TextStyle(
color: isHealthy ? Colors.green[700] : AppColors.blackColor,
fontWeight: FontWeight.bold,
),
),
),
],
),
const SizedBox(height: 16),
(getIt.get<AppState>().isArabic() ? metric.nameAr : metric.nameEn).toText18(isBold: true, maxlines: 1),
// Text(
// metric.name,
// style: const TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// ),
// ),
const SizedBox(height: 8),
Text(
data.isEmpty ? LocaleKeys.noDataAvailable.tr(context: context) : '${latestValue.toStringAsFixed(metric.type == HealthDataType.STEPS ? 0 : 1)} ${metric.unit}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: metric.color,
),
),
if (data.isNotEmpty) ...[
const SizedBox(height: 16),
SizedBox(
height: 100,
child: LineChart(
LineChartData(
gridData: FlGridData(show: false),
titlesData: FlTitlesData(show: false),
borderData: FlBorderData(show: false),
lineBarsData: [
LineChartBarData(
spots: _convertToSpots(data),
isCurved: true,
color: metric.color,
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(show: false),
belowBarData: BarAreaData(
show: true,
color: metric.color.withOpacity(0.1),
),
),
],
),
),
),
],
],
),
),
),
);
}
List<FlSpot> _convertToSpots(List<HealthDataPoint> data) {
if (data.isEmpty) return [];
return List.generate(
data.length,
(index) => FlSpot(
index.toDouble(),
_getValueAsDouble(data[index].value, data[index].type),
),
);
}
}

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/presentation/e_referral/new_e_referral.dart'
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_procedures_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/smartwatch_instructions_page.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/organ_selector_screen.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/possible_conditions_screen.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/risk_factors_screen.dart';
@ -32,6 +33,7 @@ class AppRoutes {
static const String homeHealthCarePage = '/homeHealthCarePage';
static const String zoomCallPage = '/zoomCallPage';
static const String bloodDonationPage = '/bloodDonationPage';
static const String smartWatches = '/smartWatches';
//appointments
static const String bookAppointmentPage = '/bookAppointmentPage';
@ -69,6 +71,7 @@ class AppRoutes {
bookAppointmentPage: (context) => BookAppointmentPage(),
userInfoSelection: (context) => UserInfoSelectionScreen(),
userInfoFlowManager: (context) => UserInfoFlowManager(),
smartWatches: (context) => SmartwatchInstructionsPage(),
//
};

@ -114,6 +114,7 @@ flutter:
- assets/images/svg/
- assets/images/png/
- assets/images/png/zoom/
- assets/images/png/smartwatches/
- assets/animations/
- assets/animations/lottie/

Loading…
Cancel
Save